Merge branch 'develop' of http://25.13.9.101:9000/K17_AITS/tra-app into develop
This commit is contained in:
+1
-1
@@ -11,7 +11,7 @@ VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
# http://25.18.122.65:7001/download/dev-jax.apk
|
||||
# app入口
|
||||
#VITE_APP_BASE_API_Url = 'http://25.18.122.65:7001'
|
||||
#VITE_APP_BASE_API_Url = 'http://25.16.122.65:7001'
|
||||
#VITE_APP_BASE_API_Url = 'http://25.18.122.91:9786'
|
||||
#VITE_APP_BASE_API_Url = 'http://25.18.122.66:9786'
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -3,4 +3,4 @@ ENV = 'production'
|
||||
|
||||
# base api
|
||||
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002'
|
||||
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -6,5 +6,5 @@
|
||||
# header note.
|
||||
#Thu Jul 03 09:46:08 CST 2025
|
||||
|
||||
#sdk.dir=C\:\\Users\\ty\\AppData\\Local\\Android\\Sdk
|
||||
sdk.dir=/data/jenkins/agent/workspace/tra-app-build-test/android-sdk
|
||||
sdk.dir=C\:\\Users\\ty\\AppData\\Local\\Android\\Sdk
|
||||
#sdk.dir=/data/jenkins/agent/workspace/tra-app-build-test/android-sdk
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -7,8 +7,8 @@
|
||||
"id": "__UNI__EDE0E52",
|
||||
"name": "tra-app",
|
||||
"version": {
|
||||
"name": "1.0.0",
|
||||
"code": "100"
|
||||
"name": "0.0.3",
|
||||
"code": 3
|
||||
},
|
||||
"description": "",
|
||||
"developer": {
|
||||
|
||||
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
@charset "UTF-8";.main_div[data-v-e9416fd9]{margin:20% auto 0;display:flex;justify-content:center;font-weight:600}
|
||||
@charset "UTF-8";.main_div[data-v-e5b805df]{margin:20% auto 0;display:flex;justify-content:center;font-weight:600}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,88 @@
|
||||
|
||||
import { getToken } from '@/common/common.js'
|
||||
import { get_base_url } from '@/api/request'
|
||||
|
||||
const base_url = get_base_url();
|
||||
const token = getToken();
|
||||
// 基础配置
|
||||
const baseConfig = {
|
||||
enableChunked: true, // 必须开启分块传输
|
||||
responseType: 'arraybuffer', // 微信小程序需用arraybuffer
|
||||
timeout: 30000 // 超时时间延长
|
||||
}
|
||||
|
||||
// 流式请求核心实现
|
||||
function streamRequest(options) {
|
||||
const {
|
||||
url,
|
||||
method = 'GET',
|
||||
data,
|
||||
headers = {},
|
||||
onChunk,
|
||||
onComplete,
|
||||
onError
|
||||
} = options
|
||||
|
||||
headers['Accept'] = 'text/event-stream'
|
||||
headers['Content-Type'] = 'application/json;charset=UTF-8'
|
||||
headers['summary'] = token
|
||||
|
||||
// 创建请求任务
|
||||
const requestTask = uni.request({
|
||||
url,
|
||||
method,
|
||||
data,
|
||||
header: headers,
|
||||
...baseConfig,
|
||||
success: (res) => {
|
||||
onComplete?.(res)
|
||||
},
|
||||
fail: (err) => {
|
||||
onError?.(err)
|
||||
}
|
||||
})
|
||||
console.log(requestTask)
|
||||
// 流式数据处理器
|
||||
let bufferCache = ''
|
||||
requestTask.onChunkReceived((res) => {
|
||||
try {
|
||||
// ArrayBuffer转字符串(兼容多平台)
|
||||
const uint8Array = new Uint8Array(res.data)
|
||||
const chunkText = bufferCache +
|
||||
String.fromCharCode.apply(null, uint8Array)
|
||||
|
||||
// 处理SSE格式数据(data:开头)
|
||||
const events = chunkText.split('\n\n')
|
||||
bufferCache = events.pop() || '' // 缓存不完整数据
|
||||
|
||||
events.forEach(event => {
|
||||
if (event.startsWith('data:')) {
|
||||
onChunk?.(event.substring(5).trim())
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
onError?.(e)
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
abort: () => requestTask.abort()
|
||||
}
|
||||
}
|
||||
|
||||
// 使用示例
|
||||
export const demoUsage = (data) => {
|
||||
const controller = streamRequest({
|
||||
url: `${base_url}/trastudy/intgask/askAbout`,
|
||||
data: data,
|
||||
onChunk: (chunk) => {
|
||||
console.log('收到数据块:', chunk)
|
||||
// 实时更新UI逻辑
|
||||
},
|
||||
onComplete: () => console.log('传输完成'),
|
||||
onError: (err) => console.error('错误:', err)
|
||||
})
|
||||
|
||||
// 需要中断时调用
|
||||
// controller.abort()
|
||||
}
|
||||
@@ -93,6 +93,7 @@ export const commonUploadVoiceFile = (file, url, data = {}, fileKey='voice') =>
|
||||
}
|
||||
},
|
||||
fail(error) {
|
||||
console.log(error)
|
||||
reject(new Error('Upload failed'));
|
||||
}
|
||||
});
|
||||
|
||||
+6
-1
@@ -63,11 +63,16 @@ export default class WebSocketUtil {
|
||||
if(res.data){
|
||||
const { rtnCode } = JSON.parse(res.data)
|
||||
console.log('收到WebSocket消息', JSON.parse(res.data) );
|
||||
if(['0005', 'QQ0005'].includes(res.rtnCode)) {
|
||||
if(['0005', 'QQ0005'].includes(rtnCode)) {
|
||||
clearInterval(this.reconnectTimer);
|
||||
this.reconnectTimer = null
|
||||
this.close()
|
||||
goto_login_fun();
|
||||
return
|
||||
}
|
||||
}else{
|
||||
clearInterval(this.reconnectTimer); // 清除重连计时器
|
||||
this.reconnectTimer = null
|
||||
goto_login_fun();
|
||||
return
|
||||
}
|
||||
|
||||
+35
-21
@@ -1,5 +1,6 @@
|
||||
import request from '@/api/request'
|
||||
|
||||
import { getToken } from '@/common/common.js'
|
||||
import { get_base_url } from '@/api/request'
|
||||
const base_url = '/trastudy'
|
||||
|
||||
// 获取课程学习信息接口
|
||||
@@ -31,6 +32,15 @@ export const deleteTraStdyInfoByIdApi = (data) => {
|
||||
});
|
||||
};
|
||||
|
||||
// 重新学习
|
||||
export const afreshStudyCourseApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traStdyInfo/afreshStudyCourse',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
// 学习段落完成
|
||||
export const studyParagraphOverApi = (data) => {
|
||||
return request({
|
||||
@@ -94,6 +104,17 @@ export const waitMakeEvaluateApi = (data) => {
|
||||
data
|
||||
});
|
||||
};
|
||||
// 查询问题评价
|
||||
// /traStdyInfo/queryQuestionEvalate
|
||||
export const queryQuestionEvalateApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traStdyInfo/queryQuestionEvalate',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// /trastudy/intgask/askAbout
|
||||
// 流式获取文本
|
||||
@@ -111,35 +132,28 @@ export const getAskAboutRawApi = (data) => {
|
||||
// toastErrors: false,
|
||||
// data
|
||||
// });
|
||||
return new Promise((resolve, reject) => {
|
||||
request({
|
||||
return request({
|
||||
url: base_url + '/intgask/askAbout',
|
||||
header: {
|
||||
'Accept':'text/event-stream',
|
||||
'content-type': 'application/json; charset=UTF-8',
|
||||
'content-type': 'text/event-stream; charset=UTF-8',
|
||||
},
|
||||
responseType: 'arrayBuffer',
|
||||
method: 'get',
|
||||
isStream: true,
|
||||
timeout: 30000,
|
||||
toastErrors: false,
|
||||
data
|
||||
}).then(res=>{
|
||||
console.log(res.data)
|
||||
let _str = `[${ res.data.split('}{').join('},{')}]`
|
||||
console.log(JSON.parse(_str))
|
||||
|
||||
})
|
||||
};
|
||||
|
||||
|
||||
// 学习 对话
|
||||
export const textChartApi = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traStdychat/textChart',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
// return request({
|
||||
// url: base_url + '/intgask/askAbout',
|
||||
// header: {
|
||||
// 'Accept':'text/event-stream',
|
||||
// 'content-type': 'application/json; charset=UTF-8',
|
||||
// },
|
||||
// method: 'get',
|
||||
// isStream: true,
|
||||
// timeout: 30000,
|
||||
// toastErrors: false,
|
||||
// data
|
||||
// });
|
||||
};
|
||||
@@ -9,16 +9,16 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="title">
|
||||
<img class="title-icon" src="@/static/images/course/edit.png" alt="" />
|
||||
<image class="title-icon" src="@/static/images/course/edit.png" alt=""> </image>
|
||||
改进建议:
|
||||
</view>
|
||||
<view class="total-score">
|
||||
<view class="score-num">57</view>分
|
||||
<view class="score-num">{{props.score}}</view>分
|
||||
<img class="total-score-icon" src="@/static/images/course/score.png" alt="" />
|
||||
</view>
|
||||
<view v-for="item,index in 4" :class="['score-item', 'score-item'+(index + 1)]">
|
||||
<view class="score-item-name">词命中率</view>
|
||||
<view class="score-item-score">98</view>
|
||||
<view v-for="item,index in props.dataList" :class="['score-item', 'score-item'+(index+1)]">
|
||||
<view class="score-item-name">{{ item.gradeDimensName }}</view>
|
||||
<view class="score-item-score">{{ item.anlyGrade }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -26,15 +26,22 @@
|
||||
<script setup>
|
||||
import { ref, computed} from "vue"
|
||||
const props = defineProps({
|
||||
data:{
|
||||
default:() => [60,70,80,90],
|
||||
dataList:{
|
||||
default:() => [],
|
||||
type: Array
|
||||
},
|
||||
score:{
|
||||
default: 0,
|
||||
type: [Number,String]
|
||||
},
|
||||
size:{
|
||||
default: 262,
|
||||
type: [Number,String]
|
||||
}
|
||||
})
|
||||
const dataValue = computed(() => {
|
||||
return props.dataList.map(t=>t.anlyGrade)
|
||||
})
|
||||
const chartWidth = computed(() => props.size + 'rpx')
|
||||
const chartHeight = computed(() => props.size + 'rpx')
|
||||
const scoreMarginX = computed(() => {
|
||||
@@ -51,16 +58,20 @@
|
||||
})
|
||||
const styleFour = ref('polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%)')
|
||||
const styleFourResult = computed(()=>{
|
||||
let score = props.data
|
||||
let _tx = 50
|
||||
let _ty = 50 - Math.floor((score[0]/100)*50)
|
||||
let _rx = 50 + Math.floor((score[1]/100)*50)
|
||||
let _ry = 50
|
||||
let _bx = 50
|
||||
let _by = 50 + Math.floor((score[2]/100)*50)
|
||||
let _lx = 50 - Math.floor((score[3]/100)*50)
|
||||
let _ly = 50
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%, ${_lx}% ${_ly}%)`
|
||||
let score = dataValue.value
|
||||
if(score.length>=4){
|
||||
let _tx = 50
|
||||
let _ty = 50 - Math.floor((score[0]/100)*50)
|
||||
let _rx = 50 + Math.floor((score[1]/100)*50)
|
||||
let _ry = 50
|
||||
let _bx = 50
|
||||
let _by = 50 + Math.floor((score[2]/100)*50)
|
||||
let _lx = 50 - Math.floor((score[3]/100)*50)
|
||||
let _ly = 50
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%, ${_lx}% ${_ly}%)`
|
||||
}else{
|
||||
return `polygon(${0}% ${50}%, ${50}% ${100}%, ${100}% ${50}%, ${50}% ${0}%)`
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -225,9 +236,9 @@
|
||||
transform: translateY(v-bind(scoreMarginAbsY));
|
||||
}
|
||||
&.score-item2{
|
||||
left: 0%;
|
||||
right: 0%;
|
||||
top: 50%;
|
||||
transform: translate(calc(v-bind(scoreMarginX) - 60rpx), calc(-50% + 25rpx));
|
||||
transform: translate(calc(v-bind(scoreMarginAbsX) + 60rpx), calc(-50% + 25rpx));
|
||||
}
|
||||
&.score-item3{
|
||||
left: 50%;
|
||||
@@ -236,9 +247,9 @@
|
||||
transform: translateY(v-bind(scoreMarginY));
|
||||
}
|
||||
&.score-item4{
|
||||
right: 0%;
|
||||
left: 0%;
|
||||
top: 50%;
|
||||
transform: translate(calc(v-bind(scoreMarginAbsX) + 60rpx), calc(-50% + 25rpx));
|
||||
transform: translate(calc(v-bind(scoreMarginX) - 60rpx), calc(-50% + 25rpx));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,16 +12,16 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="title">
|
||||
<img class="title-icon" src="@/static/images/course/edit.png" alt="" />
|
||||
<image class="title-icon" src="@/static/images/course/edit.png" alt=""> </image>
|
||||
改进建议:
|
||||
</view>
|
||||
<view class="total-score">
|
||||
<view class="score-num">57</view>分
|
||||
<view class="score-num">{{props.score}}</view>分
|
||||
<img class="total-score-icon" src="@/static/images/course/score.png" alt="" />
|
||||
</view>
|
||||
<view v-for="item,index in 3" :class="['score-item', 'score-item'+(index + 1)]">
|
||||
<view class="score-item-name">词命中率</view>
|
||||
<view class="score-item-score">98</view>
|
||||
<view v-for="item,index in props.dataList" :class="['score-item', 'score-item'+(index+1)]">
|
||||
<view class="score-item-name">{{ item.gradeDimensName }}</view>
|
||||
<view class="score-item-score">{{ item.anlyGrade }}</view>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
@@ -29,15 +29,22 @@
|
||||
<script setup>
|
||||
import { ref, computed} from "vue"
|
||||
const props = defineProps({
|
||||
data:{
|
||||
default:() => [60,70,80,90],
|
||||
dataList:{
|
||||
default:() => [],
|
||||
type: Array
|
||||
},
|
||||
score:{
|
||||
default: 0,
|
||||
type: [Number,String]
|
||||
},
|
||||
size:{
|
||||
default: 262,
|
||||
type: [Number,String]
|
||||
}
|
||||
})
|
||||
const dataValue = computed(() => {
|
||||
return props.dataList.map(t=>t.anlyGrade)
|
||||
})
|
||||
let _scale = .9
|
||||
const chartWidth = computed(() => props.size / _scale + 'rpx')
|
||||
const chartHeight = computed(() => props.size / _scale + 'rpx')
|
||||
@@ -49,8 +56,8 @@
|
||||
return '-' + (props.size/2 - 40) + 'rpx'
|
||||
})
|
||||
const scoreMarginPercentY = computed(() => {
|
||||
let score = props.data
|
||||
return setPercent(score[2], Math.round(100 * 1.732 / 6 * _scale * 100)/100) + '%'
|
||||
let score = dataValue.value
|
||||
return setPercent(80, Math.round(100 * 1.732 / 6 * _scale * 100)/100) + '%'
|
||||
})
|
||||
|
||||
|
||||
@@ -66,14 +73,19 @@
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%)`
|
||||
})
|
||||
const styleFourResult = computed(()=>{
|
||||
let score = props.data
|
||||
let _tx = 50
|
||||
let _ty = 50 - setPercent(score[0], Math.round(100 * 1.732 / 3 * _scale * 100)/100)
|
||||
let _rx = 50 + setPercent(score[1], Math.round(50 *_scale * 100)/100)
|
||||
let _ry = 50 + setPercent(score[1], Math.round(100 * 1.732 / 6 * _scale * 100)/100)
|
||||
let _bx = 50 - setPercent(score[2], Math.round(50 *_scale * 100)/100)
|
||||
let _by = 50 + setPercent(score[2], Math.round(100 * 1.732 / 6 * _scale * 100)/100)
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%)`
|
||||
let score = dataValue.value
|
||||
|
||||
if(score.length >= 3){
|
||||
let _tx = 50
|
||||
let _ty = 50 - setPercent(score[0], Math.round(100 * 1.732 / 3 * _scale * 100)/100)
|
||||
let _rx = 50 + setPercent(score[1], Math.round(50 *_scale * 100)/100)
|
||||
let _ry = 50 + setPercent(score[1], Math.round(100 * 1.732 / 6 * _scale * 100)/100)
|
||||
let _bx = 50 - setPercent(score[2], Math.round(50 *_scale * 100)/100)
|
||||
let _by = 50 + setPercent(score[2], Math.round(100 * 1.732 / 6 * _scale * 100)/100)
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%)`
|
||||
}else{
|
||||
return styleFour.value
|
||||
}
|
||||
})
|
||||
const setPercent = (precent, show) => {
|
||||
return Math.floor((precent/100) * show)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!-- type: 3, 段落信息 4 问题信息 5 统计信息 1,语音回答 , 2 文本回答 ,0,纯文本信息 不翻译 6: 发送loading状态-->
|
||||
<!-- type: 0,纯文本信息不翻译 1,语音回答 , 2 文本回答 3, 段落信息 4 问题信息 5 统计信息 6: 发送loading状态 -->
|
||||
<template>
|
||||
<view class="ai-answer" v-if="[3,4,5].indexOf(type) >= 0">
|
||||
<view class="user-info">
|
||||
@@ -11,24 +11,25 @@
|
||||
</view>
|
||||
</view>
|
||||
<view :class="['talking-info', [4].indexOf(type) >= 0 ? 'talking-info-less':''] ">
|
||||
<view :class="['talking-gif', !voiceLoading && (activeVoiceId === dataInfo.id)?'is-play':'']">
|
||||
<view :class="['talking-gif', !voiceLoading && (activeVoiceId === dataInfo.id)?'is-play':'']" v-if="type !== 5">
|
||||
<CommonLoading color="#06f" v-show="voiceLoading"/>
|
||||
</view>
|
||||
<view class="talking-cont">
|
||||
<view class="talking-text" v-if="[3, 5, 6].indexOf(type) >= 0">
|
||||
{{ dataInfo.pgrphContent }}
|
||||
</view>
|
||||
<view class="talking-text" v-if="[4].indexOf(type) >= 0">
|
||||
请您思考并作答:<br>
|
||||
{{ dataInfo.qnsContent }}
|
||||
</view>
|
||||
<view v-show="type === 3">
|
||||
<CommonLoading color="#06f" v-show="dataInfo.isLoading"/>
|
||||
<text class="talking-text" v-if="[3, 5, 6].indexOf(type) >= 0 && !dataInfo.isLoading">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<text class="talking-text" v-if="[4].indexOf(type) >= 0">
|
||||
<!-- 请您思考并作答:<br> -->
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<view v-if="type === 3">
|
||||
<ImagePreview class="cont-img-box" v-if="(dataInfo.imageAddrs||[]).length>0" :imgId="dataInfo.imageAddrs[0]"></ImagePreview>
|
||||
<VideoPreview class="cont-img-box" v-if="(dataInfo.vidoAddrs||[]).length>0" :imgId="dataInfo.vidoAddrs[0]"></VideoPreview>
|
||||
</view>
|
||||
<view v-show="type === 5">
|
||||
<ChartFour/>
|
||||
<ChartThree/>
|
||||
<view v-if="type === 5 && !dataInfo.isLoading">
|
||||
<ChartFour v-if="dataInfo.evalDimens.length === 4" :dataList="dataInfo.evalDimens" :score="dataInfo.intrctGrade"/>
|
||||
<ChartThree v-if="dataInfo.evalDimens.length === 3" :dataList="dataInfo.evalDimens" :score="dataInfo.intrctGrade"/>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="talking-cont">
|
||||
@@ -36,16 +37,16 @@
|
||||
阿列克山大是快乐的你艾德卡省的mask安东拉森扣篮大赛了快递那里是啊克里斯蒂娜老师的阿萨是看,
|
||||
</view>
|
||||
</view> -->
|
||||
<view class="btns-cont">
|
||||
<view class="replay-btn" @click="restartPlay">
|
||||
<view class="btns-cont" v-show="!dataInfo.isLoading">
|
||||
<view class="replay-btn" @click.stop="restartPlay" v-if="!([5].indexOf(type) >= 0)">
|
||||
<image class="icon" src="@/static/images/course/replay.png" style="width: 100%;height: 100%;"></image>
|
||||
</view>
|
||||
<view class="play-btn">
|
||||
<view class="play-btn" v-if="!([5].indexOf(type) >= 0)">
|
||||
<image
|
||||
class="icon"
|
||||
src="@/static/images/course/play.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
@click="playVoice()"
|
||||
@click.stop="playVoice()"
|
||||
v-show="!isPlaying"
|
||||
></image>
|
||||
<image
|
||||
@@ -53,12 +54,27 @@
|
||||
v-show="isPlaying"
|
||||
src="@/static/images/course/pause.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
@click="pauseVoice"
|
||||
@click.stop="pauseVoice"
|
||||
></image>
|
||||
</view>
|
||||
<!-- <view class="next-learn-btn">继续学<image class="icon icon-iamge" src="@/static/images/course/goon.png" ></image></view>
|
||||
<view class="replay-study-btn"><image class="icon icon-iamge" src="@/static/images/course/restudy.png" ></image></view> -->
|
||||
<view class="next-btn" @click="goOnGetQues" v-if="showNextBtn && [3, 5, 6].indexOf(type) >= 0 && isLast">继续
|
||||
<view
|
||||
class="next-learn-btn"
|
||||
v-if="showNextBtn && [5].indexOf(type) >= 0 && isLast"
|
||||
@click.stop="goOnGetQues"
|
||||
>
|
||||
继续学
|
||||
<image class="icon icon-iamge" src="@/static/images/course/goon.png" ></image>
|
||||
</view>
|
||||
<view
|
||||
class="next-learn-btn restart"
|
||||
v-if="showNextBtn && [5].indexOf(type) >= 0 && isLast"
|
||||
@click.stop="goOnRestart"
|
||||
>
|
||||
重新学
|
||||
<image class="icon icon-iamge" src="@/static/images/course/restart.png" ></image>
|
||||
</view>
|
||||
<!-- <view class="replay-study-btn" v-if="showNextBtn && [5].indexOf(type) >= 0 && isLast"><image class="icon icon-iamge" src="@/static/images/course/restudy.png" ></image></view> -->
|
||||
<view class="next-btn" @click.stop="goOnGetQues" v-if="showNextBtn && [3, 6].indexOf(type) >= 0 && isLast">继续
|
||||
<image class="icon icon-iamge" src="@/static/images/course/goon.png" ></image></view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -66,8 +82,9 @@
|
||||
<view class="user-answer" v-else-if="[1, 2].indexOf(type) >= 0">
|
||||
<view class="user-info">
|
||||
<view class="avatar-box">
|
||||
<!-- <ImagePreview class="img-box" :imgId="''"></ImagePreview> -->
|
||||
<img class="img-box" :src="userInfo.imagePath" alt="" fit="contain" style="width: 100%; height: 100%;"/>
|
||||
<image v-if="userInfo.imagePath" class="img-box" :src="userInfo.imagePath" style="width: 100%; height: 100%;"></image>
|
||||
<ImagePreview v-else-if="userInfo.imageAddr" class="img-box" :src="userInfo.imageAddr" style="width: 100%; height: 100%;"></ImagePreview>
|
||||
<image v-else class="img-box" src="/static/images/me/default_user_avatar.png" style="width: 100%; height: 100%;"></image>
|
||||
</view>
|
||||
<view class="ai-name">
|
||||
{{ userInfo.userName }}
|
||||
@@ -75,54 +92,58 @@
|
||||
</view>
|
||||
|
||||
<view class="talking-info">
|
||||
<view :class="['talking-gif', !voiceLoading && (activeVoiceId === dataInfo.id) ? 'is-play' : '']">
|
||||
<CommonLoading color="#fff" v-show="voiceLoading"/>
|
||||
<view :class="['talking-gif', !voiceLoading && (activeVoiceId === dataInfo.id) ? 'is-play' : '']">
|
||||
<CommonLoading color="#fff" v-show="voiceLoading || dataInfo.isLoading"/>
|
||||
</view>
|
||||
<view class="talking-cont">
|
||||
<view class="talking-text">
|
||||
<CommonLoading color="#fff" v-show="translateLoading"/>
|
||||
{{ dataInfo.talkingContent }}
|
||||
<view class="talking-cont" v-show="!dataInfo.isLoading">
|
||||
<text :class="['talking-text translate-text loading']" v-show="!translateLoading">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<view class="talking-text translate-text" v-if="translateLoading">
|
||||
<CommonLoading color="#fff"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns-cont">
|
||||
<view class="btns-cont" v-show="!dataInfo.isLoading">
|
||||
<!-- <view class="replay-btn">
|
||||
<image class="icon" src="@/static/images/course/replay.png" style="width: 100%;height: 100%;"></image>
|
||||
</view> -->
|
||||
<view class="play-btn">
|
||||
<image class="icon"
|
||||
@click="playQnsVoice('qns', dataInfo)"
|
||||
@click.stop="playQnsVoice('qns', dataInfo)"
|
||||
v-show="!isPlaying"
|
||||
src="@/static/images/course/play-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
<image class="icon"
|
||||
v-show="isPlaying"
|
||||
@click="pauseVoice"
|
||||
@click.stop="pauseVoice"
|
||||
src="@/static/images/course/stop-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
</view>
|
||||
<view class="icon text-btn" v-if="type === 1" @click="translateVoice(dataInfo)">文</view>
|
||||
<view class="icon text-right-btn" @click="finishQuestion(dataInfo)" v-if="isLast">完成</view>
|
||||
<view class="icon text-right-btn" @click="withdraw(dataInfo)">撤回</view>
|
||||
<view class="icon text-btn" v-if="type === 1" @click.stop="translateVoice(dataInfo)">文</view>
|
||||
<view class="icon text-right-btn" @click.stop="finishQuestion(dataInfo)" v-if="isLast">完成</view>
|
||||
<view class="icon text-right-btn" @click.stop="withdraw(dataInfo)" v-show="showWithdraw">撤回
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="user-answer" v-else-if="[0, 6].indexOf(type) >= 0">
|
||||
<view class="user-info">
|
||||
<view class="avatar-box">
|
||||
<!-- <ImagePreview class="img-box" :imgId="''"></ImagePreview> -->
|
||||
<img class="img-box" :src="userInfo.imagePath" alt="" fit="contain" style="width: 100%; height: 100%;"/>
|
||||
<image v-if="userInfo.imagePath" class="img-box" :src="userInfo.imagePath" style="width: 100%; height: 100%;"></image>
|
||||
<ImagePreview v-else-if="userInfo.imageAddr" class="img-box" :src="userInfo.imageAddr" style="width: 100%; height: 100%;"></ImagePreview>
|
||||
<image v-else class="img-box" src="/static/images/me/default_user_avatar.png" style="width: 100%; height: 100%;"></image>
|
||||
</view>
|
||||
<view class="ai-name">
|
||||
{{ userInfo.userName }}
|
||||
</view>
|
||||
</view>
|
||||
<view class="talking-info-less">
|
||||
<view class="talking-text" v-if="type === 0">
|
||||
{{ dataInfo.talkingContent }}
|
||||
</view>
|
||||
<view class="talking-text" v-if="type === 6">
|
||||
<text class="talking-text" v-if="type === 0">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<view class="talking-text loading" v-if="type === 6">
|
||||
<CommonLoading color="#fff"/>
|
||||
</view>
|
||||
</view>
|
||||
@@ -141,10 +162,11 @@ import ChartThree from "./chartThree.vue"
|
||||
import common from '@/common/common';
|
||||
import { getUserInfo } from '@/common/common';
|
||||
import { useStorageStore } from "@/store/storage.js"
|
||||
import { demoUsage } from "@/api/arraybuffer.js"
|
||||
import { onUnload } from '@dcloudio/uni-app'
|
||||
|
||||
const storageStore = useStorageStore()
|
||||
const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
|
||||
const props = defineProps({
|
||||
type:{
|
||||
default: 0,// 1: userAnswer 0: AIAnswer
|
||||
@@ -174,18 +196,28 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
lastQuestionInfo: {
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
})
|
||||
const { type, dataInfo, activeVoiceId, isPlaying, isLast} = toRefs(props)
|
||||
const { type, dataInfo, activeVoiceId, isPlaying, isLast, lastQuestionInfo} = toRefs(props)
|
||||
const emit = defineEmits(['changePlay', 'nextQuestion', 'withdraw', 'finishQuestion'])
|
||||
// 声音播放初始化
|
||||
const talkVoiceObj = ref(uni.createInnerAudioContext())
|
||||
talkVoiceObj.value.playbackRate = Number(props.voiceRate)
|
||||
const userInfo = computed(() => getUserInfo())
|
||||
|
||||
const showWithdraw = computed(()=>{
|
||||
let _isMe = unref(lastQuestionInfo).qnsLogId === unref(dataInfo).qnsLogId
|
||||
let _isQuestion = unref(lastQuestionInfo).isQuestion
|
||||
return _isMe && _isQuestion
|
||||
})
|
||||
|
||||
const voiceLoading = ref(false)
|
||||
watch(() => props.isPlaying,(val) => {
|
||||
if(!val){
|
||||
talkVoiceObj.value?.stop()
|
||||
talkVoiceObj.value?.pause()
|
||||
}
|
||||
},{
|
||||
deep: true,
|
||||
@@ -197,24 +229,43 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(()=>props.lastTalkingInfo,()=>{},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(() => props.dataInfo,()=>{},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
|
||||
const transformContent = ref('')
|
||||
const showContentBase = computed(() => {
|
||||
if(props.isTransform){
|
||||
return transformContent.value
|
||||
}else{
|
||||
if(props.type === 1) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
else if(props.type === 2) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
else if(props.type === 3) return unref(dataInfo)?.chatContent || unref(dataInfo)?.pgrphContent
|
||||
else if(props.type === 4) return unref(dataInfo)?.chatContent || unref(dataInfo)?.qnsContent
|
||||
else if(props.type === 5) return unref(dataInfo)?.chatContent || unref(dataInfo)?.evalContent
|
||||
else if(props.type === 0) return unref(dataInfo)?.chatContent || unref(dataInfo)?.talkingContent
|
||||
}
|
||||
})
|
||||
const showContent = computed(() => {
|
||||
return props.isTransform
|
||||
? transformContent.value
|
||||
: unref(dataInfo)?.pgrphContent || unref(dataInfo)?.qnsContent || unref(dataInfo)?.talkingContent || ''
|
||||
let _str = showContentBase.value || ''
|
||||
return _str.replace(/\/n/g,"\n")
|
||||
})
|
||||
|
||||
onMounted(()=>{
|
||||
// getAskAboutRawApi({
|
||||
// question: unref(dataInfo)?.pgrphContent,
|
||||
// streaming: true
|
||||
// }).then(res=>{
|
||||
// console.log(res)
|
||||
// })
|
||||
if(props.isTransform){}
|
||||
// demoUsage({
|
||||
// question: unref(dataInfo)?.pgrphContent,
|
||||
// streaming: true
|
||||
// })
|
||||
// if(props.isTransform){}
|
||||
})
|
||||
onUnload(()=>{
|
||||
pauseVoice()
|
||||
})
|
||||
|
||||
talkVoiceObj.value.onEnded(()=>{
|
||||
emit('changePlay', '')
|
||||
talkVoiceObj.value.src = ''
|
||||
@@ -242,13 +293,17 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
}
|
||||
const itemVoice = ref('')
|
||||
const playVoice = (readType = 'pgth') =>{
|
||||
let _content = unref(dataInfo)?.pgrphContent || unref(dataInfo)?.qnsContent || unref(dataInfo)?.talkingContent || ''
|
||||
let _content = showContent.value
|
||||
if(!_content){
|
||||
common.msg('没有可以播放的文字信息!')
|
||||
return
|
||||
}
|
||||
// readType 阅读内容类型pgrh段落/qns问题
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
if(talkVoiceObj.value.src === itemVoice.value) {
|
||||
talkVoiceObj.value.play()
|
||||
return
|
||||
}
|
||||
if(itemVoice.value){
|
||||
setTimeout(()=>{
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
@@ -276,7 +331,6 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
talkVoiceObj.value.play()
|
||||
}else{
|
||||
downloadVoiceFile(_url).then(res=>{
|
||||
console.log(res)
|
||||
if(res?.data){
|
||||
common.msg(res.data.message)
|
||||
return
|
||||
@@ -291,23 +345,6 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
})
|
||||
}
|
||||
})
|
||||
// let _cache = audioCacheObj.value[_url]
|
||||
// if(_cache){
|
||||
// voiceLoading.value = false
|
||||
// itemVoice.value = _cache
|
||||
// talkVoiceObj.value.src = _cache
|
||||
// talkVoiceObj.value.play()
|
||||
// return
|
||||
// }
|
||||
// downloadVoiceFile(_url).then(res=>{
|
||||
// voiceLoading.value = false
|
||||
// itemVoice.value = res.tempFilePath
|
||||
// talkVoiceObj.value.src = res.tempFilePath
|
||||
// talkVoiceObj.value.play()
|
||||
// storageStore.setStorage('audio', _url, itemVoice.value)
|
||||
// }).catch((err)=>{
|
||||
// voiceLoading.value = false
|
||||
// })
|
||||
}
|
||||
}
|
||||
const playQnsVoice = (readType = 'qns', item) =>{
|
||||
@@ -331,7 +368,7 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
translateLoading.value = true
|
||||
uploadVoiceFile(item.talkingVoice,{}).then(res=>{
|
||||
let _data = JSON.parse(res.data)
|
||||
item.talkingContent = _data.body
|
||||
item.talkingContent = _data.body.text
|
||||
translateLoading.value = false
|
||||
}).catch(()=>{
|
||||
translateLoading.value = false
|
||||
@@ -339,13 +376,21 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
}
|
||||
const showNextBtn = ref(true)
|
||||
const goOnGetQues = () => {
|
||||
studyParagraphOverApi({
|
||||
pgrphId:unref(dataInfo)?.pgrphId,
|
||||
logId:unref(dataInfo)?.logId,
|
||||
}).then(res=>{
|
||||
showNextBtn.value = false
|
||||
if(props.type === 5){
|
||||
emit('nextQuestion', unref(dataInfo))
|
||||
})
|
||||
}else if(props.type === 3){
|
||||
// studyParagraphOverApi({
|
||||
// pgrphId:unref(dataInfo)?.pgrphId,
|
||||
// logId:unref(dataInfo)?.logId,
|
||||
// }).then(res=>{
|
||||
// showNextBtn.value = false
|
||||
// })
|
||||
emit('nextQuestion', unref(dataInfo), 'overGraph')
|
||||
}
|
||||
|
||||
}
|
||||
const goOnRestart = () => {
|
||||
emit('nextQuestion', unref(dataInfo), 'reStart')
|
||||
}
|
||||
// 撤回
|
||||
const withdraw = (data) => {
|
||||
@@ -395,16 +440,17 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
border-radius: 15rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
padding-bottom: 40rpx;
|
||||
&.talking-info-less{
|
||||
float: left;
|
||||
min-width: 400rpx;
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
.talking-gif{
|
||||
width: 200rpx;
|
||||
height: 38rpx;
|
||||
background: url(@/static/images/course/voice-gray.png) no-repeat;
|
||||
background-size: contain;
|
||||
margin-bottom: 16rpx;
|
||||
padding-left: 168rpx;
|
||||
&.is-play{
|
||||
background: url(@/static/images/course/voice-gif.gif) no-repeat;
|
||||
@@ -412,11 +458,19 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
}
|
||||
}
|
||||
.talking-cont{
|
||||
margin-top: 16rpx;
|
||||
overflow: hidden;
|
||||
min-height: 48rpx;
|
||||
.talking-text{
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
min-height: 48rpx;
|
||||
margin-bottom: 20rpx;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
&.loading{
|
||||
// min-height: 36px;
|
||||
}
|
||||
}
|
||||
.cont-img-box{
|
||||
width: 433rpx;
|
||||
@@ -458,6 +512,10 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
margin-top: 16rpx;
|
||||
margin-right: 16rpx;
|
||||
position: relative;
|
||||
&.restart{
|
||||
background-color: #eaf2ff;
|
||||
color: #06f;
|
||||
}
|
||||
.icon-iamge{
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
@@ -568,7 +626,6 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
height: 38rpx;
|
||||
background: url(@/static/images/course/voice-gray.png) no-repeat;
|
||||
background-size: contain;
|
||||
margin-bottom: 16rpx;
|
||||
padding-left: 168rpx;
|
||||
&.is-play{
|
||||
background: url(@/static/images/course/voice-white.gif) no-repeat;
|
||||
@@ -576,11 +633,18 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
}
|
||||
}
|
||||
.talking-cont{
|
||||
margin-top: 16rpx;
|
||||
overflow: hidden;
|
||||
.talking-text{
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
margin-bottom: 20rpx;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
overflow: hidden;
|
||||
&.translate-text{
|
||||
min-height: 48rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btns-cont{
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
<template>
|
||||
<view class="talk-btns" ref="talkBtnRef">
|
||||
<view
|
||||
class="touch-btn"
|
||||
@touchstart="showOverlayTalking"
|
||||
@touchend="hideOverlayTalking"
|
||||
@touchmove="handleMove"
|
||||
v-if="!keyboardIsShow"
|
||||
>按住说话
|
||||
</view>
|
||||
<view class="touch-btn" v-if="keyboardIsShow">
|
||||
<uv-input class="input-box" ref="inputRef" v-model.trim="answerValue" maxlength="1000"
|
||||
placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入答案">
|
||||
</uv-input>
|
||||
</view>
|
||||
<view class="talk-btn-box" @click.stop="showKeyboard">
|
||||
<image class="talk-btn-icon" v-show="!keyboardIsShow" src="/src/static/images/course/jianpan.png" mode=""></image>
|
||||
<image class="talk-btn-icon" v-show="keyboardIsShow" src="/src/static/images/course/send.png" mode=""></image>
|
||||
</view>
|
||||
<uv-overlay :show="showTalkingModel" opacity=".9" @click="showTalkingModel = false">
|
||||
<view class="overlay-box">
|
||||
<view class="circle-bg-box">
|
||||
<view class="icon-box">
|
||||
<image src="/src/static/images/course/talk-icon.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tips-box">松开发送</view>
|
||||
<view class="btns-box">
|
||||
<view :class="['close-btn',isOut?'is-out':'']" >取消
|
||||
<image class="btn-box" v-if="!isOut" src="/src/static/images/course/close.png" mode=""></image>
|
||||
<image class="btn-box" v-else src="/src/static/images/course/close-active.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
</uv-overlay>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { toRefs, ref, computed, unref, onMounted, onUnmounted, defineEmits, nextTick } from 'vue';
|
||||
const emit = defineEmits(['uploadVoice', 'submitAnswer','startRecord'])
|
||||
const props = defineProps({
|
||||
answerType:{
|
||||
default: 0,
|
||||
type: Number
|
||||
}
|
||||
})
|
||||
const { answerType } = toRefs(props)
|
||||
const showTalkingModel = ref(false)
|
||||
const keyboardIsShow = ref(false)
|
||||
const answerValue = ref('')
|
||||
const talkBtnRef = ref()
|
||||
// 录音
|
||||
const audioPath = ref('')
|
||||
const audioObj = uni.createInnerAudioContext()
|
||||
//#ifdef APP-PLUS
|
||||
// app端
|
||||
const recordObjCom = uni.getRecorderManager()
|
||||
const initRecord = () => {
|
||||
unref(recordObjCom)?.onStop((res, duration)=>{
|
||||
audioPath.value = res.tempFilePath
|
||||
})
|
||||
}
|
||||
const startRecord = () => {
|
||||
unref(recordObjCom).start({format:'mp3'})
|
||||
}
|
||||
const stopRecord = () => {
|
||||
unref(recordObjCom)?.stop?.()
|
||||
}
|
||||
// #endif
|
||||
//#ifndef APP-PLUS
|
||||
const recordObjCom = {}
|
||||
const initRecord = () => {}
|
||||
// #endif
|
||||
onMounted(()=>{
|
||||
initRecord?.()
|
||||
})
|
||||
// const playRecord = () => {
|
||||
// audioObj.src = audioPath.value
|
||||
// unref(audioObj).play()
|
||||
// }
|
||||
// 录音结束
|
||||
|
||||
// 记录 按下移动位置
|
||||
const touchX = ref(0)
|
||||
const touchY = ref(0)
|
||||
const baseY = ref(0)
|
||||
const windowInfo = uni.getWindowInfo()
|
||||
// 计算是否超出按下盒子位置
|
||||
const isOut = computed(() => {
|
||||
let _btnHeight = windowInfo.screenWidth/750 * 234
|
||||
let moveVal = (windowInfo.screenHeight - touchY.value) > _btnHeight
|
||||
return moveVal
|
||||
})
|
||||
const showOverlayTalking = (obj) => {
|
||||
emit('startRecord')
|
||||
if(answerType.value === 4){
|
||||
showTalkingModel.value = true
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
baseY.value = obj.currentTarget.offsetTop
|
||||
//#ifdef APP-PLUS
|
||||
startRecord()
|
||||
// #endif
|
||||
}else{
|
||||
uni.showToast({
|
||||
title: '请先获取问题信息!',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
})
|
||||
}
|
||||
}
|
||||
const hideOverlayTalking = (obj) => {
|
||||
showTalkingModel.value = false
|
||||
//#ifdef APP-PLUS
|
||||
stopRecord()
|
||||
// #endif
|
||||
if(!isOut.value){
|
||||
setTimeout(()=>{
|
||||
emit('uploadVoice', audioPath.value)
|
||||
},1000)
|
||||
}
|
||||
}
|
||||
|
||||
const handleMove = (obj) => {
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
}
|
||||
// 发送文本
|
||||
const showKeyboard = () => {
|
||||
if(answerType.value === 4){
|
||||
if(keyboardIsShow.value){
|
||||
if(answerValue.value){
|
||||
emit(
|
||||
'submitAnswer',
|
||||
answerValue.value,
|
||||
() => {
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
answerValue.value = ''
|
||||
}
|
||||
)
|
||||
}else{
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
}else{
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
}else{
|
||||
uni.showToast({
|
||||
title: '请先获取问题信息!',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
})
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.talk-btns{
|
||||
height: 150rpx;
|
||||
background-color: #fff;
|
||||
padding: 25rpx 30rpx 0;
|
||||
position: relative;
|
||||
.touch-btn{
|
||||
height: 92rpx;
|
||||
box-shadow: 0 8rpx 20rpx 0 rgba(0,0,0,.06);
|
||||
text-align: center;
|
||||
line-height: 92rpx;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
position: relative;
|
||||
.input-box{
|
||||
width: 100%;
|
||||
height: 92rpx;
|
||||
line-height: 92rpx;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
padding:0 40rpx 0 40rpx;
|
||||
}
|
||||
}
|
||||
.talk-btn-box{
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 120rpx;
|
||||
right: 0;
|
||||
top:0;
|
||||
.talk-btn-icon{
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
position: absolute;
|
||||
right: 60rpx;
|
||||
top: 50%;
|
||||
margin-top: -20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-box{
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
// justify-content: flex-end;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.circle-bg-box{
|
||||
height: 234rpx;
|
||||
background: url(@/static/images/course/talking.png) no-repeat;
|
||||
background-size: cover;
|
||||
position: relative;
|
||||
.icon-box{
|
||||
position: absolute;
|
||||
left:50%;
|
||||
top: 50%;
|
||||
margin-left: -17rpx;
|
||||
margin-top: -24rpx;
|
||||
width: 34rpx;
|
||||
height: 48rpx;
|
||||
image{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
.tips-box{
|
||||
height: 40rpx;
|
||||
line-height: 40rpx;
|
||||
color:#c0c0c0;
|
||||
text-align: center;
|
||||
margin: 12rpx 0 24rpx;
|
||||
}
|
||||
.btns-box{
|
||||
height: 270rpx;
|
||||
// padding: 0 120rpx;
|
||||
width: 154rpx;
|
||||
margin: 0 auto 100rpx;
|
||||
overflow: hidden;
|
||||
font-size: 28rpx;
|
||||
text-align: center;
|
||||
line-height: 116rpx;
|
||||
.close-btn{
|
||||
float: left;
|
||||
height: 100%;
|
||||
width: 154rpx;
|
||||
overflow: hidden;
|
||||
color:#999;
|
||||
&.is-out{
|
||||
color:#fff;
|
||||
}
|
||||
}
|
||||
.translate-btn{
|
||||
float: right;
|
||||
height: 100%;
|
||||
width: 154rpx;
|
||||
overflow: hidden;
|
||||
color:#999;
|
||||
}
|
||||
.btn-box{
|
||||
width: 100%;
|
||||
height: 154rpx;
|
||||
}
|
||||
}
|
||||
.talk-dialog{
|
||||
width: 506rpx;
|
||||
height: 234rpx;
|
||||
margin: 0 auto;
|
||||
background-color: #06f;
|
||||
}
|
||||
.white-bg-box{
|
||||
height: 365rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 58rpx 36rpx;
|
||||
.box-title{
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
.box-btns{
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
.is-active{
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
@@ -351,7 +351,7 @@ import { onMounted, ref, computed } from 'vue'
|
||||
.list-view{
|
||||
flex:1;
|
||||
overflow: hidden;
|
||||
margin-bottom: 80rpx;
|
||||
margin-bottom: 15rpx;
|
||||
background: #ffffff;
|
||||
border-radius: 23rpx;
|
||||
display: flex;
|
||||
@@ -469,14 +469,16 @@ import { onMounted, ref, computed } from 'vue'
|
||||
border-right: 2rpx solid #eee;
|
||||
overflow-y: auto;
|
||||
.type-item{
|
||||
height: 90rpx;
|
||||
line-height: 90rpx;
|
||||
font-size: 28rpx;
|
||||
min-height: 90rpx;
|
||||
line-height: 40rpx;
|
||||
font-size: 22rpx;
|
||||
box-sizing: border-box;
|
||||
padding: 0 18rpx;
|
||||
padding: 25rpx 18rpx;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
// text-overflow: ellipsis;
|
||||
word-break: break-all;
|
||||
text-align: center;
|
||||
white-space: pre-wrap;
|
||||
&.is-active{
|
||||
background-color: rgba(44,142,242,.1);
|
||||
color: #06f;
|
||||
|
||||
+339
-290
@@ -3,9 +3,9 @@
|
||||
<view class="top-bg"></view>
|
||||
<view class="bot-bg"></view>
|
||||
<view class="course-study-body" v-show="step === 1">
|
||||
<view class="seek-setting" @click="showSeekModel = true">
|
||||
<view class="seek-setting" @click="showChangeSeekModelNow">
|
||||
{{chooseRate}}倍
|
||||
<image src="@/static/images/course/setting.png" alt=""/>
|
||||
<image src="@/static/images/course/setting.png" alt="" class="image-icon"></image>
|
||||
</view>
|
||||
<view class="body-title">
|
||||
<uv-icon class="arrow-icon" name="arrow-left" @click="common.navigateBack()"/>
|
||||
@@ -36,14 +36,14 @@
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="course-study-body" v-show="step === 2" @click="playRecord">
|
||||
<view class="seek-setting" @click="showSeekModel = true">
|
||||
<view class="course-study-body" v-show="step === 2">
|
||||
<view class="seek-setting" @click="showChangeSeekModelNow">
|
||||
{{chooseRate}} 倍
|
||||
<img src="@/static/images/course/setting.png" alt="">
|
||||
<image src="@/static/images/course/setting.png" alt="" class="image-icon"></image>
|
||||
</view>
|
||||
<view class="body-title" @click="scrollToBottomNow">
|
||||
<uv-icon class="arrow-icon" name="arrow-left" @click="common.navigateBack()"/>
|
||||
课程学习{{scrollTop}}
|
||||
课程学习
|
||||
</view>
|
||||
<scroll-view
|
||||
class="talking-list"
|
||||
@@ -65,6 +65,7 @@
|
||||
:activeVoiceId="activeVoiceTalkingItemId"
|
||||
:isPlaying="activeVoiceTalkingItemId === item.id"
|
||||
:voiceRate="chooseRate"
|
||||
:lastQuestionInfo="lastTalkingInfo"
|
||||
@changePlay="changePlayItemId"
|
||||
@nextQuestion="nextQuestionSuccess"
|
||||
@withdraw="withdrawNow"
|
||||
@@ -75,45 +76,14 @@
|
||||
<!-- <video v-if="videoUrlShow" :src="videoUrlShow" controls></video> -->
|
||||
<!-- </view> -->
|
||||
</scroll-view>
|
||||
<view class="talk-btns">
|
||||
<view
|
||||
class="touch-btn"
|
||||
@touchstart="showOverlayTalking"
|
||||
@touchend="hideOverlayTalking"
|
||||
@touchmove="handleMove"
|
||||
v-if="!keyboardIsShow"
|
||||
>按住说话
|
||||
</view>
|
||||
<view class="touch-btn" v-if="keyboardIsShow">
|
||||
<uv-input class="input-box" ref="inputRef" v-model.trim="answerValue" maxlength="1000"
|
||||
placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入答案">
|
||||
</uv-input>
|
||||
</view>
|
||||
<view class="talk-btn-box" @click.stop="showKeyboard">
|
||||
<image class="talk-btn-icon" src="/src/static/images/course/jianpan.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<TouchBtn
|
||||
class="talk-btns"
|
||||
@uploadVoice="uploadRecordNow"
|
||||
@submitAnswer="submitAnswerNow"
|
||||
@startRecord="changePlayItemId('')"
|
||||
:answerType="lastTalkingInfo.type||0"
|
||||
/>
|
||||
</view>
|
||||
<uv-overlay :show="showTalkingModel" opacity=".9" @click="showTalkingModel = false">
|
||||
<view class="overlay-box">
|
||||
<view class="circle-bg-box">
|
||||
<view class="icon-box">
|
||||
<image src="/src/static/images/course/talk-icon.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tips-box">松开发送</view>
|
||||
<view class="btns-box">
|
||||
<view :class="['close-btn',isOut?'is-out':'']" >取消
|
||||
<image class="btn-box" v-if="!isOut" src="/src/static/images/course/close.png" mode=""></image>
|
||||
<image class="btn-box" v-else src="/src/static/images/course/close-active.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<!-- <view class="talk-dialog">
|
||||
<view class="voice-gif"></view>
|
||||
</view> -->
|
||||
</view>
|
||||
</uv-overlay>
|
||||
|
||||
<uv-overlay :show="showSeekModel" opacity=".6" @click="showSeekModel = false">
|
||||
<view class="overlay-box">
|
||||
<view class="white-bg-box">
|
||||
@@ -134,7 +104,7 @@
|
||||
|
||||
<script setup>
|
||||
import { reactive, ref, computed, unref, onMounted, onUnmounted, getCurrentInstance, nextTick } from 'vue';
|
||||
import { onLoad,onShow,onHide } from '@dcloudio/uni-app';
|
||||
import { onLoad,onShow, onUnload } from '@dcloudio/uni-app';
|
||||
import {
|
||||
previewFile,
|
||||
downloadFile,
|
||||
@@ -146,17 +116,14 @@ import { getToken } from '@/common/common.js'
|
||||
import { get_base_url, goto_login_fun } from '@/api/request'
|
||||
import {
|
||||
getCourseStudyInfoApi,
|
||||
queryTraStdyBatchWaitParagraphInfoApi,
|
||||
audioTranscriptionsApi,
|
||||
deleteTraStdyInfoByIdApi,
|
||||
queryTraStdyBatchWaitQuestionInfoApi,
|
||||
studyAnswerTextUpApi,
|
||||
withdrawalAnswerApi,
|
||||
waitMakeEvaluateApi
|
||||
afreshStudyCourseApi,
|
||||
queryQuestionEvalateApi,
|
||||
textChartApi
|
||||
} from "@/api/study.js"
|
||||
import common from '@/common/common';
|
||||
import TalkingItem from '@/pages/course/components/talkingItem.vue'
|
||||
import ImagePreview from '@/components/image-preview/image-preview.vue'
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue'
|
||||
|
||||
import { useSocketStore } from "@/store/socket.js"
|
||||
import { useStorageStore } from "@/store/storage.js"
|
||||
@@ -178,8 +145,14 @@ const talkingList = ref([])
|
||||
const activeVoiceTalkingItemId = ref('')
|
||||
const answerValue = ref('')
|
||||
const inputRef = ref('')
|
||||
const flagVal = ref('1')
|
||||
// 初始化数据
|
||||
const getData = async () => {
|
||||
const getData = async (flag) => {
|
||||
if(flag === flagVal.value){
|
||||
flagVal.value = '2'
|
||||
}else{
|
||||
return
|
||||
}
|
||||
try{
|
||||
const { body } = await getCourseStudyInfoApi({crsId: crsId.value})
|
||||
initsocketTask()
|
||||
@@ -206,10 +179,9 @@ const getData = async () => {
|
||||
})
|
||||
step.value = 2
|
||||
}else{
|
||||
// 重新开始
|
||||
// 删除学习信息
|
||||
deleteTraStdyInfoByIdApi({
|
||||
id:''
|
||||
// 重新学习
|
||||
afreshStudyCourseApi({
|
||||
crsId: crsId.value,
|
||||
}).then(res=>{
|
||||
step.value = 1
|
||||
teacherList.value = body.teacheList.map(t=>({
|
||||
@@ -231,13 +203,14 @@ const getData = async () => {
|
||||
}catch{
|
||||
|
||||
}
|
||||
// downloadFile('S3F0250640161332025061618052000000267276').then(res=>{
|
||||
// videoUrlShow.value = res.tempFilePath
|
||||
// })
|
||||
};
|
||||
|
||||
const showChangeSeekModelNow = () => {
|
||||
// changePlayItemId()
|
||||
showSeekModel.value = true
|
||||
}
|
||||
// 关闭播放状态
|
||||
const changePlayItemId = (id) => {
|
||||
const changePlayItemId = (id = '') => {
|
||||
if(activeVoiceTalkingItemId.value === id){
|
||||
activeVoiceTalkingItemId.value = ''
|
||||
}else{
|
||||
@@ -248,9 +221,9 @@ const changePlayItemId = (id) => {
|
||||
const choiceTeacherInfo = computed(()=>{
|
||||
return teacherList.value.find(t=> t.teacherNo === choiceTeacher.value)
|
||||
})
|
||||
|
||||
// 选择教师语音对象
|
||||
const activeVoiceTeachNo = ref('')
|
||||
const teacherVoiceObj = uni.createInnerAudioContext()
|
||||
let teacherVoiceObj = uni.createInnerAudioContext()
|
||||
|
||||
teacherVoiceObj.onEnded(()=>{
|
||||
activeVoiceTeachNo.value = ''
|
||||
@@ -306,67 +279,143 @@ const pgrphNum = ref(1)
|
||||
const showOrder = ref(0)
|
||||
// 获取段落
|
||||
const getGraphInfoUnStudy = () => {
|
||||
queryTraStdyBatchWaitParagraphInfoApi({
|
||||
crsId: crsId.value,
|
||||
stdyId: unref(stdyId),
|
||||
stdyBatch: unref(stdyBatch)
|
||||
|
||||
textChartApi({
|
||||
processType: 'PRGH-STDY',
|
||||
requestBody: JSON.stringify({
|
||||
crsId: crsId.value,
|
||||
stdyId: unref(stdyId),
|
||||
stdyBatch: unref(stdyBatch)
|
||||
})
|
||||
}).then(res=>{
|
||||
let _id = new Date().getTime() + 'id'
|
||||
lastTalkingInfo.value = {
|
||||
...res.body,
|
||||
type: 3,
|
||||
let _body = res.body|| {}
|
||||
if(!_body.chatBody) {
|
||||
return
|
||||
}
|
||||
lastTalkingInfo.value = {
|
||||
crsId: crsId.value,
|
||||
qstLogId: _body.chatBody,
|
||||
pgrphId: _body.pgrphId,
|
||||
logId:_body.chatBody.logId || '',
|
||||
chatContent: _body.chatContent,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
..._body.chatBody,
|
||||
type: Number(_body.bodyTyp) || 0,
|
||||
id: _id
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
|
||||
pgrphNum.value = res.body.pgrphNum
|
||||
showOrder.value = res.body.showOrder
|
||||
logId.value = res.body.logId || ''
|
||||
pgrphNum.value = _body.chatBody.pgrphNum
|
||||
showOrder.value = _body.chatBody.showOrder
|
||||
logId.value = _body.chatBody.logId || ''
|
||||
scrollToBottomNow()
|
||||
})
|
||||
// common.msg('您已学完当前课程的全部内容!')
|
||||
}
|
||||
const lastTalkingInfo = ref({})
|
||||
const qstLogId = ref('')
|
||||
// 获取问题
|
||||
const getQuestionInfoUnStudy = (pgrphId) => {
|
||||
queryTraStdyBatchWaitQuestionInfoApi({
|
||||
crsId: crsId.value,
|
||||
stdyId: unref(stdyId),
|
||||
stdyBatch: unref(stdyBatch),
|
||||
logId: unref(logId),
|
||||
pgrphId
|
||||
}).then(res=>{
|
||||
textChartApi({
|
||||
processType: 'QSN-ANSER',
|
||||
requestBody: JSON.stringify({
|
||||
crsId: crsId.value,
|
||||
stdyId: unref(stdyId),
|
||||
stdyBatch: unref(stdyBatch),
|
||||
logId: unref(logId),
|
||||
pgrphId
|
||||
})
|
||||
})
|
||||
.then(res=>{
|
||||
let _id = new Date().getTime() + 'id'
|
||||
lastTalkingInfo.value = {
|
||||
...res.body,
|
||||
type: 4,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
let _body = res.body || {}
|
||||
console.log(_body.chatBody)
|
||||
if(_body.chatBody && _body.chatBody?.stdyStat !== 'N'){
|
||||
let _id = new Date().getTime() + 'id'
|
||||
lastTalkingInfo.value = {
|
||||
crsId: crsId.value,
|
||||
stdyId: unref(stdyId),
|
||||
stdyBatch: unref(stdyBatch),
|
||||
logId: unref(logId),
|
||||
pgrphId,
|
||||
chatContent: _body.chatContent||'',
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
...(_body.chatBody||{}),
|
||||
type: 4,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id,
|
||||
isQuestion: true
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
qstLogId.value = _body.chatBody?.qstLogId
|
||||
scrollToBottomNow()
|
||||
}else{
|
||||
getGraphInfoUnStudy()
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
qstLogId.value = res.body.qstLogId
|
||||
scrollToBottomNow()
|
||||
})
|
||||
}
|
||||
|
||||
// 继续 执行方法
|
||||
const nextQuestionSuccess = (info) => {
|
||||
const nextQuestionSuccess = (info, type='next') => {
|
||||
let _id = new Date().getTime() + 'id'
|
||||
talkingList.value.push({
|
||||
crsId: info.crsId,
|
||||
pgrphId: info.pgrphId,
|
||||
talkingContent: '继续',
|
||||
type: 0,
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
// getGraphInfoUnStudy()
|
||||
getQuestionInfoUnStudy(info.pgrphId)
|
||||
if(type === 'next'){
|
||||
talkingList.value.push({
|
||||
crsId: info.crsId,
|
||||
pgrphId: info.pgrphId,
|
||||
talkingContent: '继续',
|
||||
type: 0,
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow(0)
|
||||
getQuestionInfoUnStudy(info.pgrphId)
|
||||
}else if( type === 'overGraph'){
|
||||
textChartApi({
|
||||
processType: 'PRGH-OVER',
|
||||
requestBody: JSON.stringify({
|
||||
pgrphId: info?.pgrphId,
|
||||
logId: info?.logId,
|
||||
})
|
||||
}).then(res=>{
|
||||
talkingList.value.push({
|
||||
crsId: info.crsId,
|
||||
pgrphId: info.pgrphId,
|
||||
talkingContent: '继续',
|
||||
type: 0,
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow(0)
|
||||
getQuestionInfoUnStudy(info.pgrphId)
|
||||
})
|
||||
}else if( type === 'reStart'){
|
||||
// 重新回答
|
||||
textChartApi({
|
||||
processType: 'NEW-ANSER',
|
||||
requestBody: info.qstLogId
|
||||
}).then(res=>{
|
||||
let _body = res.body|| {}
|
||||
if(!_body.chatBody) {
|
||||
return
|
||||
}
|
||||
lastTalkingInfo.value = {
|
||||
crsId: info.crsId,
|
||||
qstLogId: _body.chatBody,
|
||||
pgrphId: info.pgrphId,
|
||||
chatContent: _body.chatContent,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
..._body.chatBody,
|
||||
type: Number(_body.bodyTyp) || 0,
|
||||
id: _id,
|
||||
isQuestion: true
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
qstLogId.value = _body.chatBody.qstLogId
|
||||
scrollToBottomNow()
|
||||
})
|
||||
}
|
||||
}
|
||||
const scrollBoxRef = ref()
|
||||
const scrollTop = ref(99999)
|
||||
const scrollToBottomNow = () => {
|
||||
const scrollToBottomNow = (time = 500) => {
|
||||
nextTick(()=>{
|
||||
setTimeout(() => {
|
||||
scrollTop.value += 1
|
||||
@@ -379,7 +428,7 @@ const scrollToBottomNow = () => {
|
||||
duration: 300
|
||||
})
|
||||
}
|
||||
},200)
|
||||
},time)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -417,14 +466,6 @@ const reconnect = ()=> {
|
||||
const sendMessage = (data) => {
|
||||
unref(SocketObj).send(data)
|
||||
}
|
||||
const closeWebSocket = () => {
|
||||
isManualClose.value = true
|
||||
if(socketTask){
|
||||
// socketTask.close()
|
||||
socketTask = null
|
||||
uni.closeSocket({})
|
||||
}
|
||||
}
|
||||
// ws 结束
|
||||
|
||||
onLoad((params) => {
|
||||
@@ -433,211 +474,219 @@ onLoad((params) => {
|
||||
});
|
||||
const showTalkingModel = ref(false)
|
||||
// 录音
|
||||
const audioPath = ref('')
|
||||
const audioObj = uni.createInnerAudioContext()
|
||||
//#ifdef APP-PLUS
|
||||
// app端
|
||||
const recordObj = uni.getRecorderManager()
|
||||
const initRecord = () => {
|
||||
unref(recordObj)?.onStop((res, duration)=>{
|
||||
audioPath.value = res.tempFilePath
|
||||
})
|
||||
}
|
||||
const startRecord = () => {
|
||||
unref(recordObj).start({format:'mp3'})
|
||||
}
|
||||
const stopRecord = () => {
|
||||
unref(recordObj)?.stop?.()
|
||||
}
|
||||
// #endif
|
||||
//#ifndef APP-PLUS
|
||||
const recordObj = {}
|
||||
const initRecord = () => {}
|
||||
// #endif
|
||||
onMounted(()=>{
|
||||
getData();
|
||||
initRecord?.()
|
||||
getData('1');
|
||||
})
|
||||
onShow(()=>{
|
||||
// getData();
|
||||
getData('2');
|
||||
})
|
||||
// onHide(()=>{
|
||||
// teacherVoiceObj.stop()
|
||||
// teacherVoiceObj.src = ''
|
||||
// })
|
||||
onUnmounted(()=>{
|
||||
onUnload(()=>{
|
||||
changePlayItemId()
|
||||
teacherVoiceObj?.stop?.()
|
||||
teacherVoiceObj.src = ''
|
||||
})
|
||||
const playRecord = () => {
|
||||
audioObj.src = audioPath.value
|
||||
unref(audioObj).play()
|
||||
}
|
||||
// 录音结束
|
||||
|
||||
// 记录 按下移动位置
|
||||
const touchX = ref(0)
|
||||
const touchY = ref(0)
|
||||
const baseY = ref(0)
|
||||
const systemInfo = uni.getSystemInfoSync()
|
||||
const widowHeight = systemInfo.windowHeight
|
||||
// 计算是否超出按下盒子位置
|
||||
const isOut = computed(() => {
|
||||
let moveVal = (widowHeight - baseY.value)/140 * 234
|
||||
return (widowHeight - moveVal) > touchY.value
|
||||
})
|
||||
const showOverlayTalking = (obj) => {
|
||||
if(lastTalkingInfo.value.type === 4){
|
||||
//#ifdef APP-PLUS
|
||||
showTalkingModel.value = true
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
baseY.value = obj.currentTarget.offsetTop
|
||||
startRecord()
|
||||
// #endif
|
||||
}else{
|
||||
uni.showToast({
|
||||
title: '请先获取问题信息!',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
})
|
||||
}
|
||||
}
|
||||
const hideOverlayTalking = (obj) => {
|
||||
showTalkingModel.value = false
|
||||
//#ifdef APP-PLUS
|
||||
stopRecord()
|
||||
// #endif
|
||||
if(!isOut.value){
|
||||
setTimeout(()=>{
|
||||
let _data = {
|
||||
qnsId: unref(lastTalkingInfo).qnsId,// 问题ID 必输项:true 类型:String
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,// 段落ID 必输项:true 类型:String
|
||||
qstLogId: unref(qstLogId),// 段落ID 必输项:true 类型:String
|
||||
crsId: crsId.value,// 课程ID 必输项:true 类型:String
|
||||
stdyBatch: stdyBatch.value,// 学习批次 必输项:true 类型:String
|
||||
ansterContent: '',// 回答文本内容 必输项:false 类型:String
|
||||
}
|
||||
//#ifndef APP-PLUS
|
||||
// h5 假数据
|
||||
let _id = new Date().getTime() + 'id'
|
||||
talkingList.value.push({
|
||||
crsId: crsId.value,
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,
|
||||
qnsId: unref(lastTalkingInfo).qnsId,
|
||||
talkingContent: '',
|
||||
talkingVoice: audioPath.value,
|
||||
type: 1,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
// #endif
|
||||
//#ifdef APP-PLUS
|
||||
commonUploadVoiceFile(audioPath.value, '/trastudy/traStdyInfo/studyAnswerVoiceUp', _data).then(res=>{
|
||||
let _res = JSON.parse(res.data)
|
||||
if(_res.rtnCode === '0000'){
|
||||
let _id = new Date().getTime() + 'id'
|
||||
talkingList.value.push({
|
||||
crsId: crsId.value,
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,
|
||||
qnsId: unref(lastTalkingInfo).qnsId,
|
||||
talkingContent: '',
|
||||
talkingVoice: audioPath.value,
|
||||
intrctId: res.body||'',
|
||||
type: 1,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
}
|
||||
}).catch(err=>{
|
||||
uni.showToast({
|
||||
title: err||'系统异常,请联系管理员',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
});
|
||||
const uploadRecordNow = (voicePath) => {
|
||||
let _data = {
|
||||
qnsId: unref(lastTalkingInfo).qnsId,// 问题ID 必输项:true 类型:String
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,// 段落ID 必输项:true 类型:String
|
||||
qstLogId: unref(qstLogId),// 段落ID 必输项:true 类型:String
|
||||
crsId: crsId.value,// 课程ID 必输项:true 类型:String
|
||||
stdyBatch: stdyBatch.value,// 学习批次 必输项:true 类型:String
|
||||
ansterContent: '',// 回答文本内容 必输项:false 类型:String
|
||||
}
|
||||
let _id = new Date().getTime() + 'id'
|
||||
//#ifndef APP-PLUS
|
||||
// h5 假数据
|
||||
talkingList.value.push({
|
||||
crsId: crsId.value,
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,
|
||||
qnsId: unref(lastTalkingInfo).qnsId,
|
||||
talkingContent: '',
|
||||
talkingVoice: voicePath,
|
||||
type: 1,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
// #endif
|
||||
},1000)
|
||||
}
|
||||
}
|
||||
|
||||
const handleMove = (obj) => {
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
}
|
||||
|
||||
const keyboardIsShow = ref(false)
|
||||
// 发送文本
|
||||
const showKeyboard = () => {
|
||||
if(lastTalkingInfo.value.type === 4){
|
||||
if(keyboardIsShow.value){
|
||||
if(answerValue.value){
|
||||
let _data = {
|
||||
qnsId: unref(lastTalkingInfo).qnsId,// 问题ID 必输项:true 类型:String
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,// 段落ID 必输项:true 类型:String
|
||||
qstLogId: unref(qstLogId),// 段落ID 必输项:true 类型:String
|
||||
crsId: crsId.value,// 课程ID 必输项:true 类型:String
|
||||
stdyBatch: stdyBatch.value,// 学习批次 必输项:true 类型:String
|
||||
ansterContent: answerValue.value // 回答文本内容 必输项:false 类型:String
|
||||
}
|
||||
studyAnswerTextUpApi(_data).then(res=>{
|
||||
if(res.rtnCode === '0000'){
|
||||
let _id = new Date().getTime() + 'id'
|
||||
talkingList.value.push({
|
||||
scrollToBottomNow()
|
||||
// #endif
|
||||
//#ifdef APP-PLUS
|
||||
talkingList.value.push({
|
||||
crsId: crsId.value,
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,
|
||||
qnsId: unref(lastTalkingInfo).qnsId,
|
||||
talkingContent: '',
|
||||
talkingVoice: voicePath,
|
||||
intrctId: '',
|
||||
isLoading: true,
|
||||
type: 1,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
commonUploadVoiceFile(voicePath, '/trastudy/traStdychat/voiceChart', {
|
||||
processType: 'ANSER-VOICE',
|
||||
requestBody: JSON.stringify(_data)
|
||||
}).then(res=>{
|
||||
let _res = JSON.parse(res.data)
|
||||
console.log(_res)
|
||||
if(_res.rtnCode === '0000'){
|
||||
talkingList.value = talkingList.value.map(t=>{
|
||||
if(t.id === _id){
|
||||
return {
|
||||
crsId: crsId.value,
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,
|
||||
qstLogId: unref(lastTalkingInfo).qstLogId,
|
||||
qnsId: unref(lastTalkingInfo).qnsId,
|
||||
talkingContent: answerValue.value,
|
||||
talkingVoice: '',
|
||||
intrctId: res.body||'',
|
||||
type: 2,
|
||||
pgrphId: _data.pgrphId,
|
||||
qstLogId: _data.qstLogId,
|
||||
qnsId: _data.qnsId,
|
||||
talkingContent: '',
|
||||
talkingVoice: voicePath,
|
||||
intrctId: _res.chatBody,
|
||||
type: 1,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
answerValue.value = ''
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
}else{
|
||||
return t
|
||||
}
|
||||
})
|
||||
}else{
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
}else{
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
}else{
|
||||
uni.showToast({
|
||||
title: '请先获取问题信息!',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
scrollToBottomNow()
|
||||
}else{}
|
||||
}).catch(err=>{
|
||||
talkingList.value = talkingList.value.filter(t=>t.id !== _id)
|
||||
uni.showToast({
|
||||
title: '系统异常,请联系管理员',
|
||||
icon: "none",
|
||||
duration:1000
|
||||
});
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
// 发送文本
|
||||
const submitAnswerNow = (val, cb) => {
|
||||
let _data = {
|
||||
qnsId: unref(lastTalkingInfo).qnsId,// 问题ID 必输项:true 类型:String
|
||||
pgrphId: unref(lastTalkingInfo).pgrphId,// 段落ID 必输项:true 类型:String
|
||||
qstLogId: unref(qstLogId),// 段落ID 必输项:true 类型:String
|
||||
crsId: crsId.value,// 课程ID 必输项:true 类型:String
|
||||
stdyBatch: stdyBatch.value,// 学习批次 必输项:true 类型:String
|
||||
ansterContent: val // 回答文本内容 必输项:false 类型:String
|
||||
}
|
||||
textChartApi({
|
||||
processType: 'ANSER-TEXT',
|
||||
requestBody: JSON.stringify(_data)
|
||||
})
|
||||
.then(res=>{
|
||||
let _id = new Date().getTime() + 'id'
|
||||
let _body = res.body|| {}
|
||||
if(!_body.chatBody) {
|
||||
return
|
||||
}
|
||||
talkingList.value.push({
|
||||
..._data,
|
||||
chatContent: _body.chatContent,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
intrctId: _body.chatBody ||'',
|
||||
talkingContent: val,
|
||||
talkingVoice: '',
|
||||
type: 2,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
cb && cb()
|
||||
})
|
||||
}
|
||||
// 撤回
|
||||
const withdrawNow = (data) => {
|
||||
withdrawalAnswerApi({
|
||||
intrctId: data.intrctId
|
||||
}).then(res=> {
|
||||
textChartApi({
|
||||
processType: 'ANSER-WITHDRAW',
|
||||
requestBody: JSON.stringify({
|
||||
intrctId: data.intrctId
|
||||
})
|
||||
})
|
||||
.then(res=> {
|
||||
// 删除撤回的数据item
|
||||
common.msg('撤回成功!')
|
||||
talkingList.value = talkingList.value.filter(t => t.intrctId !== data.intrctId)
|
||||
})
|
||||
}
|
||||
const loadingQstLogId = ref('')
|
||||
// 完成
|
||||
const finishQuestionNow = (data) => {
|
||||
waitMakeEvaluateApi({
|
||||
qstLogId: data.qstLogId
|
||||
}).then(res=> {
|
||||
console.log(res.body.processStat)
|
||||
common.msg('完成成功,开始获取评分维度数据!')
|
||||
// qstLogId 问题日志ID String
|
||||
// qnsId 问题ID String
|
||||
// processStat 状态 String
|
||||
// message 处理消息 String
|
||||
let _id1 = new Date().getTime() + 'id'
|
||||
talkingList.value.push({
|
||||
id: _id1,
|
||||
talkingContent: '完成',
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
type: 0
|
||||
})
|
||||
// waitMakeEvaluateApi({
|
||||
// qstLogId: data.qstLogId
|
||||
// })
|
||||
|
||||
textChartApi({
|
||||
processType: 'ANSER-OVER',
|
||||
requestBody: JSON.stringify({
|
||||
qstLogId: data.qstLogId
|
||||
})
|
||||
})
|
||||
.then(res=> {
|
||||
// common.msg('完成成功,开始获取评分维度数据!')
|
||||
loadingQstLogId.value = res.body.chatBody.qstLogId
|
||||
qstLogId.value = loadingQstLogId.value
|
||||
let _id = new Date().getTime() + 'id'
|
||||
lastTalkingInfo.value = {
|
||||
isLoading: true,
|
||||
id: _id,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
type: 5
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
scrollToBottomNow(0)
|
||||
getQuestionEvalateRequest(_id,data)
|
||||
})
|
||||
}
|
||||
// 查询问题回答评分
|
||||
const getQuestionEvalateRequest = (id, data) => {
|
||||
if(loadingQstLogId.value){
|
||||
// queryQuestionEvalateApi({
|
||||
// qstLogId:loadingQstLogId.value
|
||||
// })
|
||||
|
||||
textChartApi({
|
||||
processType: 'ANSER-RESULT',
|
||||
requestBody: JSON.stringify({
|
||||
qstLogId:loadingQstLogId.value
|
||||
})
|
||||
})
|
||||
.then(res=>{
|
||||
let _body = res.body|| {}
|
||||
if(!_body.chatBody) {
|
||||
return
|
||||
}
|
||||
if(_body.chatBody && _body.chatBody.evalOver === 'Y'){
|
||||
talkingList.value = talkingList.value.map(t=>{
|
||||
if(t.id === id){
|
||||
lastTalkingInfo.value = {
|
||||
..._body.chatBody,
|
||||
pgrphId: data.pgrphId,
|
||||
qstLogId: loadingQstLogId.value,
|
||||
id,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
type: 5
|
||||
}
|
||||
return lastTalkingInfo.value
|
||||
}else{
|
||||
return t
|
||||
}
|
||||
})
|
||||
scrollToBottomNow()
|
||||
}else{
|
||||
setTimeout(()=>{
|
||||
getQuestionEvalateRequest(id, data)
|
||||
}, 2 * 1000)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const showSeekModel = ref(false)
|
||||
@@ -680,7 +729,7 @@ const chooseRateNow = (item) => {
|
||||
text-align: right;
|
||||
padding-right: 48rpx;
|
||||
|
||||
img{
|
||||
.image-icon{
|
||||
width: 30rpx;
|
||||
height: 32rpx;
|
||||
position: absolute;
|
||||
|
||||
Reference in New Issue
Block a user