Merge branch 'develop' of http://25.13.9.101:9000/K17_AITS/tra-app into develop
This commit is contained in:
@@ -72,6 +72,7 @@ export const commonUploadVoiceFile = (file, url, data = {}, fileKey='voice') =>
|
||||
};
|
||||
if (token)
|
||||
header['summary'] = token
|
||||
console.log(`${base_url}${url}`)
|
||||
return new Promise((resolve, reject) => {
|
||||
uni.uploadFile({
|
||||
url: `${base_url}${url}`,
|
||||
|
||||
@@ -35,6 +35,7 @@ export default class WebSocketUtil {
|
||||
*/
|
||||
init(flag = false) {
|
||||
if(flag) this.reconnectCount = 0
|
||||
this.isClose = false; // 手动关闭
|
||||
// 创建WebSocket连接
|
||||
this.socketTask = uni.connectSocket({
|
||||
url: this.url,
|
||||
|
||||
@@ -156,7 +156,7 @@
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
max-width: 100%;
|
||||
width: 100vw;
|
||||
max-height: 100%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
@@ -104,8 +104,8 @@
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
.overlay-box .video-cont-center{
|
||||
max-width: 100%;
|
||||
max-height: 80%;
|
||||
width: 100vw;
|
||||
max-height: 100%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
<template>
|
||||
<view class="chart-box" :style="allStyle">
|
||||
<view class="cont-box">
|
||||
<view v-for="width in 5" :class="'total-line total-line' + width"></view>
|
||||
<view v-for="width in 3" :class="`percent-${width * 25}`"></view>
|
||||
<view class="data-box">
|
||||
<view class="line-box">
|
||||
<view v-for="width in 3" :class="`percent-${width * 25}`"></view>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="title">
|
||||
<image class="title-icon" src="@/static/images/course/edit.png" alt=""> </image>
|
||||
改进建议:
|
||||
</view>
|
||||
<view class="total-score">
|
||||
<view class="score-num">{{ score }}</view>分
|
||||
<image class="total-score-icon" src="@/static/images/course/score.png" alt=""></image>
|
||||
</view>
|
||||
<view v-for="(item,index) in 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>
|
||||
<script>
|
||||
export default{
|
||||
props:{
|
||||
dataList:{
|
||||
default:() => [],
|
||||
type: Array
|
||||
},
|
||||
score:{
|
||||
default: 0,
|
||||
type: [Number,String]
|
||||
},
|
||||
size:{
|
||||
default: 262,
|
||||
type: [Number,String]
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
|
||||
}
|
||||
},
|
||||
computed:{
|
||||
dataValue(){
|
||||
return this.dataList.map(t=>t.anlyGrade)
|
||||
},
|
||||
chartWidth(){
|
||||
return this.size + 'rpx'
|
||||
},
|
||||
chartHeight(){
|
||||
return this.size + 'rpx'
|
||||
},
|
||||
scoreMargin1Y(){
|
||||
return '-' + (this.size/2 - 25) + 'rpx'
|
||||
},
|
||||
scoreMargin2X(){
|
||||
return `calc(-50% + ${this.size/2 + 60}rpx)`
|
||||
},
|
||||
scoreMargin2Y(){
|
||||
return `calc(-50% - ${this.size * .077}rpx)`
|
||||
},
|
||||
scoreMargin3X(){
|
||||
return `calc(-50% + ${this.size * .38}rpx)`
|
||||
},
|
||||
scoreMargin3Y(){
|
||||
return (this.size/2 + 20) + 'rpx'
|
||||
},
|
||||
scoreMargin4X(){
|
||||
return `calc(-50% - ${this.size * .38}rpx)`
|
||||
},
|
||||
scoreMargin4Y(){
|
||||
return this.scoreMargin3Y
|
||||
},
|
||||
scoreMargin5X(){
|
||||
return `calc(-50% - ${this.size /2 + 60}rpx)`
|
||||
},
|
||||
scoreMargin5Y(){
|
||||
return this.scoreMargin2Y
|
||||
},
|
||||
styleFive(){
|
||||
let base = 50
|
||||
let _tx = 50
|
||||
let _ty = 0
|
||||
let _rx = 50 + base*Math.cos(1/10 * Math.PI)
|
||||
let _ry = 50 - base*Math.sin(1/10 * Math.PI)
|
||||
let _bx = 50 + base*Math.sin(1/5 * Math.PI)
|
||||
let _by = 50 + base*Math.cos(1/5 * Math.PI)
|
||||
let _lx = 50 - base*Math.sin(1/5 * Math.PI)
|
||||
let _ly = 50 + base*Math.cos(1/5 * Math.PI)
|
||||
let _lxl = 50 - base*Math.cos(1/10 * Math.PI)
|
||||
let _lyl = 50 - base*Math.sin(1/10 * Math.PI)
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%, ${_lx}% ${_ly}%, ${_lxl}% ${_lyl}%)`
|
||||
},
|
||||
styleFiveResult(){
|
||||
let score = this.dataList
|
||||
if(score.length >= 5){
|
||||
let base = 50
|
||||
let _tx = 50
|
||||
let _ty = 50 - score[0] * 50 / 100
|
||||
let _rx = 50 + base*Math.cos(1/10 * Math.PI) / 100 * score[1]
|
||||
let _ry = 50 - base*Math.sin(1/10 * Math.PI) / 100 * score[1]
|
||||
let _bx = 50 + base*Math.sin(1/5 * Math.PI) / 100 * score[2]
|
||||
let _by = 50 + base*Math.cos(1/5 * Math.PI) / 100 * score[2]
|
||||
let _lx = 50 - base*Math.sin(1/5 * Math.PI) / 100 * score[3]
|
||||
let _ly = 50 + base*Math.cos(1/5 * Math.PI) / 100 * score[3]
|
||||
let _lxl = 50 - base*Math.cos(1/10 * Math.PI) / 100 * score[4]
|
||||
let _lyl = 50 - base*Math.sin(1/10 * Math.PI) / 100 * score[4]
|
||||
return `polygon(${_tx}% ${_ty}%, ${_rx}% ${_ry}%, ${_bx}% ${_by}%, ${_lx}% ${_ly}%, ${_lxl}% ${_lyl}%)`
|
||||
}else{
|
||||
return this.styleFive
|
||||
}
|
||||
},
|
||||
allStyle(){
|
||||
return {
|
||||
'--styleFive': this.styleFive,
|
||||
'--styleFiveResult': this.styleFiveResult,
|
||||
'--chartWidth': this.chartWidth,
|
||||
'--chartHeight': this.chartHeight,
|
||||
'--scoreMargin1Y': this.scoreMargin1Y,
|
||||
'--scoreMargin2X': this.scoreMargin2X,
|
||||
'--scoreMargin2Y': this.scoreMargin2Y,
|
||||
'--scoreMargin3X': this.scoreMargin3X,
|
||||
'--scoreMargin3Y': this.scoreMargin3Y,
|
||||
'--scoreMargin4X': this.scoreMargin4X,
|
||||
'--scoreMargin4Y': this.scoreMargin4Y,
|
||||
'--scoreMargin5X': this.scoreMargin5X,
|
||||
'--scoreMargin5Y': this.scoreMargin5Y
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.chart-box{
|
||||
width: 100%;
|
||||
height: 580rpx;
|
||||
background:linear-gradient( 270deg, #4a74ff 0%, #6fa7fe 100%);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
border-radius: 16rpx;
|
||||
margin-bottom: 20rpx;
|
||||
.cont-box{
|
||||
background-color: #87abfe;
|
||||
width: var(--chartWidth);
|
||||
height: var(--chartHeight);
|
||||
clip-path: var(--styleFive);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
margin-top: 25rpx;
|
||||
|
||||
.total-line{
|
||||
width: 57.7%;
|
||||
height: 3rpx;
|
||||
background-color: rgba(255, 255, 255, .3);
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
z-index: 20;
|
||||
&.total-line1{
|
||||
top: 40.5%;
|
||||
left: 49.5%;
|
||||
transform: rotateZ(162deg);
|
||||
}
|
||||
&.total-line2{
|
||||
top: 40.5%;
|
||||
left:-6.5%;
|
||||
transform: rotateZ(18deg);
|
||||
}
|
||||
&.total-line3{
|
||||
top: 21.5%;
|
||||
left: 21%;
|
||||
transform: rotateZ(-90deg);
|
||||
}
|
||||
&.total-line4{
|
||||
top: 72.5%;
|
||||
left: 4.5%;
|
||||
transform: rotateZ(-54deg);
|
||||
}
|
||||
&.total-line5{
|
||||
top: 72.5%;
|
||||
left: 37.5%;
|
||||
transform: rotateZ(-126deg);
|
||||
}
|
||||
}
|
||||
@for $i from 1 through 3 {
|
||||
.percent-#{$i*25}{
|
||||
width: $i * 25%;
|
||||
height: $i * 25%;
|
||||
clip-path: var(--styleFive);
|
||||
background-color: rgba(255, 255, 255, .3);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: (4 - $i) * 2;
|
||||
&::before{
|
||||
content: '';
|
||||
display: block;
|
||||
width: calc(100% - 10rpx);
|
||||
height: calc(100% - 10rpx);
|
||||
background-color: #87abfe;
|
||||
clip-path: var(--styleFive);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
.data-box{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
clip-path: var(--styleFiveResult);
|
||||
position: absolute;
|
||||
background-color: #fff;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 12;
|
||||
overflow: hidden;
|
||||
.line-box{
|
||||
display: block;
|
||||
width: calc(100% - 24rpx);
|
||||
height: calc(100% - 24rpx);
|
||||
// background-color: #6691fe;
|
||||
background-color: #6691fe;
|
||||
clip-path: var(--styleFiveResult);
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 14;
|
||||
}
|
||||
|
||||
@for $i from 1 through 3 {
|
||||
.percent-#{$i*25}{
|
||||
background-color: rgba(255, 255, 255, .1);
|
||||
z-index: (4 - $i) * 2 + 10;
|
||||
&::before{
|
||||
background-color: #6692ff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.title{
|
||||
padding: 24rpx;
|
||||
line-height: 46rpx;
|
||||
font-size: 32rpx;
|
||||
color: #fff;
|
||||
.title-icon{
|
||||
width: 27rpx;
|
||||
height: 27rpx;
|
||||
}
|
||||
}
|
||||
.total-score{
|
||||
position: absolute;
|
||||
right: 30rpx;
|
||||
top:30rpx;
|
||||
width: 100rpx;
|
||||
height: 80rpx;
|
||||
line-height: 70rpx;
|
||||
font-size: 30rpx;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-shadow: 0 4px 12px rgba(0, 0, 0, .33);
|
||||
.score-num{
|
||||
display: inline-block;
|
||||
font-size: 60rpx;
|
||||
line-height: 70rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
.total-score-icon{
|
||||
width: 100%;
|
||||
height: 16rpx;
|
||||
position: absolute;
|
||||
bottom:0;
|
||||
left:0;
|
||||
}
|
||||
}
|
||||
.score-item{
|
||||
position: absolute;
|
||||
color: #fff;
|
||||
width: 120rpx;
|
||||
text-align: center;
|
||||
.score-item-name{
|
||||
font-size: 28rpx;
|
||||
line-height: 36rpx;
|
||||
margin-bottom: 4rpx;
|
||||
}
|
||||
.score-item-score{
|
||||
font-size: 38rpx;
|
||||
line-height: 46rpx;
|
||||
font-weight: bold;
|
||||
}
|
||||
&.score-item1{
|
||||
left: 50%;
|
||||
margin-left: -60rpx;
|
||||
bottom: 50%;
|
||||
transform: translateY(var(--scoreMargin1Y));
|
||||
}
|
||||
&.score-item2{
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(var(--scoreMargin2X), var(--scoreMargin2Y));
|
||||
}
|
||||
&.score-item3{
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(var(--scoreMargin3X), var(--scoreMargin3Y));
|
||||
}
|
||||
&.score-item4{
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(var(--scoreMargin4X), var(--scoreMargin3Y));
|
||||
}
|
||||
&.score-item5{
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(var(--scoreMargin5X), var(--scoreMargin2Y));
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -30,6 +30,7 @@
|
||||
<view v-if="type === 5 && !dataInfo.isLoading" style="padding-top: 16rpx;">
|
||||
<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"/>
|
||||
<ChartFive v-if="dataInfo.evalDimens.length === 5" :dataList="dataInfo.evalDimens" :score="dataInfo.intrctGrade"/>
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns-cont" v-show="!dataInfo.isLoading">
|
||||
@@ -151,7 +152,7 @@
|
||||
<view
|
||||
class="icon text-right-btn"
|
||||
@click.stop="withdraw"
|
||||
v-show="isLast"
|
||||
v-show="showWithdraw"
|
||||
>撤回
|
||||
<!-- v-show="showWithdraw" -->
|
||||
</view>
|
||||
@@ -189,6 +190,7 @@ import { downloadVoiceFile, uploadVoiceFile, getAudioByText } from "@/api/common
|
||||
import { studyParagraphOverApi, getAskAboutRawApi } from "@/api/study.js"
|
||||
import ChartFour from "./chartFour.vue"
|
||||
import ChartThree from "./chartThree.vue"
|
||||
import ChartFive from './chartFive.vue'
|
||||
import common from '@/common/common';
|
||||
import { getUserInfo } from '@/common/common';
|
||||
import { useStorageStore } from "@/store/storage.js"
|
||||
@@ -252,7 +254,7 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
const itemVoice = ref('')
|
||||
|
||||
const showWithdraw = computed(()=>{
|
||||
let _isMe = unref(lastQuestionInfo).qnsLogId === unref(dataInfo).qnsLogId
|
||||
let _isMe = unref(lastQuestionInfo).qstLogId === unref(dataInfo).qstLogId
|
||||
let _isQuestion = unref(lastQuestionInfo).isQuestion
|
||||
return _isMe && _isQuestion
|
||||
})
|
||||
@@ -365,13 +367,17 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
},100)
|
||||
}else{
|
||||
voiceLoading.value = true
|
||||
let _type = props.type == 2 ? 'ans' : props.type == 3 ? 'pgrh' : props.type == 4 ? 'qns' : ''
|
||||
let _readId = props.type == 2 ? unref(dataInfo)?.intrctId : props.type == 3 ? unref(dataInfo)?.pgrphId : props.type == 4 ? unref(dataInfo)?.qnsId : ''
|
||||
console.log(unref(dataInfo))
|
||||
let _params = {
|
||||
crsId: unref(dataInfo)?.crsId || '',
|
||||
pgrphId: unref(dataInfo)?.pgrphId || '',
|
||||
qnsId: unref(dataInfo)?.qnsId || '',
|
||||
readType: readType,
|
||||
readType: _type,// 2 文本回答 3, 段落信息 4 问题信息
|
||||
teachNo: unref(teacherInfo)?.teacherNo, // 必填
|
||||
content: _content
|
||||
readId: _readId
|
||||
// content: _content
|
||||
}
|
||||
|
||||
|
||||
@@ -386,19 +392,6 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
talkVoiceObj.value.src = url
|
||||
talkVoiceObj.value.play()
|
||||
}else{
|
||||
// getAudioByText(_params).then(res=>{
|
||||
// // uni.env.USER_DATA_PATH ||
|
||||
// let filePath = `${'/'}/${dataInfo.value.id}.mp3`
|
||||
// saveFile(res, filePath, () => {
|
||||
// voiceLoading.value = false
|
||||
// itemVoice.value = filePath
|
||||
// talkVoiceObj.value.src = filePath
|
||||
// talkVoiceObj.value.play()
|
||||
// storageStore.setStorage('audio', _url + _params.teachNo, itemVoice.value)
|
||||
// })
|
||||
// }).catch(err=>{
|
||||
// console.log(err)
|
||||
// })
|
||||
downloadVoiceFile(_url).then(res=>{
|
||||
if(res?.data){
|
||||
common.msg(res.data.message)
|
||||
@@ -522,7 +515,7 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border: 3rpx solid #fff;
|
||||
background-color: #ccc;
|
||||
background-color: #f1f1f1;
|
||||
overflow: hidden;
|
||||
border-radius: 10rpx;
|
||||
margin-right: 16rpx;
|
||||
@@ -698,7 +691,7 @@ const audioCacheObj = computed(() => storageStore.audioObj)
|
||||
width: 76rpx;
|
||||
height: 76rpx;
|
||||
border: 3rpx solid #fff;
|
||||
background-color: #ccc;
|
||||
background-color: #f1f1f1;
|
||||
overflow: hidden;
|
||||
border-radius: 10rpx;
|
||||
margin-left: 16rpx;
|
||||
|
||||
@@ -61,12 +61,23 @@ const props = defineProps({
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
canAnswer:{
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
canAnswerText:{
|
||||
default: '当前状态不能发送内容!',
|
||||
type: String
|
||||
},
|
||||
})
|
||||
const { isDisabled, onlyVoice } = toRefs(props)
|
||||
const isLoadingState = computed(() => props.isLoading)
|
||||
watch(()=>props.isLoading,()=>{},{
|
||||
deep:true,immediate:true
|
||||
})
|
||||
watch(()=>props.canAnswer,()=>{},{
|
||||
deep:true,immediate:true
|
||||
})
|
||||
watch(()=>props.onlyVoice,()=>{},{
|
||||
deep:true,immediate:true
|
||||
})
|
||||
@@ -87,11 +98,32 @@ const initRecord = () => {
|
||||
// stopRecord()
|
||||
unref(recordObjCom)?.onStop((res, duration)=>{
|
||||
audioPath.value = res.tempFilePath
|
||||
showTalkingModel.value = false
|
||||
if(startFlag.value !== 2){
|
||||
common.msg('说话时间太短,没有听清!')
|
||||
return
|
||||
}
|
||||
if(!isOut.value){
|
||||
emit('uploadVoice', audioPath.value)
|
||||
}
|
||||
})
|
||||
unref(recordObjCom).onStart(() => {
|
||||
startFlag.value = 1
|
||||
setTimeout(()=>{
|
||||
startFlag.value = 2
|
||||
},1000)
|
||||
let _recordPerm = uni.getAppAuthorizeSetting()
|
||||
let _state = _recordPerm.microphoneAuthorized
|
||||
if(_state === 'authorized'){
|
||||
showTalkingModel.value = true
|
||||
}
|
||||
})
|
||||
}
|
||||
const startFlag = ref(1)
|
||||
const startRecord = () => {
|
||||
unref(recordObjCom).start({format:'mp3'})
|
||||
}
|
||||
|
||||
const stopRecord = () => {
|
||||
if(unref(recordObjCom).stop){
|
||||
unref(recordObjCom)?.stop?.()
|
||||
@@ -120,17 +152,20 @@ onMounted(async ()=>{
|
||||
})
|
||||
}
|
||||
}else{
|
||||
let _recordPerm = permission.judgeIosPermission('record')
|
||||
if(!_recordPerm){
|
||||
let _recordPerm = uni.getAppAuthorizeSetting()
|
||||
let _state = _recordPerm.microphoneAuthorized
|
||||
if(_state === 'denied'){
|
||||
common.show('提示信息', '当前页面需要使用的录音权限,是否前往开启?',true, '取消','确定').then((res) => {
|
||||
if(res) {
|
||||
// 去开启权限
|
||||
permission.gotoAppPermissionSetting()
|
||||
uni.openAppAuthorizeSetting()
|
||||
}else{
|
||||
// 取消
|
||||
common.navigateBack()
|
||||
}
|
||||
})
|
||||
}else if(_state === 'not determined'){
|
||||
// startRecord()
|
||||
}
|
||||
}
|
||||
// #endif
|
||||
@@ -154,21 +189,10 @@ const outScreen = computed(()=>{
|
||||
const recNum = ref(1)
|
||||
const activeNum = ref(1)
|
||||
|
||||
const getRecordPermission = async (obj) => {
|
||||
//#ifdef APP-PLUS
|
||||
// 安卓端
|
||||
// let _recordPerm = await permission.requestAndroidPermission('android.permission.RECORD_AUDIO')
|
||||
// if(_recordPerm !== 1){
|
||||
// permission.gotoAppPermissionSetting()
|
||||
// return
|
||||
// }
|
||||
showOverlayTalking(obj)
|
||||
// #endif
|
||||
//#ifndef APP-PLUS
|
||||
// pc端
|
||||
showOverlayTalking(obj)
|
||||
// #endif
|
||||
const getRecordPermission = (obj) => {
|
||||
showOverlayTalking(obj)
|
||||
}
|
||||
const isMoving = ref(false)
|
||||
const showOverlayTalking = (obj) => {
|
||||
if(isLoadingState.value){
|
||||
uni.showToast({
|
||||
@@ -178,10 +202,18 @@ const showOverlayTalking = (obj) => {
|
||||
})
|
||||
return
|
||||
}
|
||||
if(!props.canAnswer){
|
||||
uni.showToast({
|
||||
title: props.canAnswerText,
|
||||
icon: "none",
|
||||
duration:1000
|
||||
})
|
||||
return
|
||||
}
|
||||
isMoving.value = true
|
||||
emit('startRecord')
|
||||
recNum.value += 1
|
||||
if(!isDisabled.value){
|
||||
showTalkingModel.value = true
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
baseY.value = obj.currentTarget.offsetTop
|
||||
@@ -201,29 +233,20 @@ const showOverlayTalking = (obj) => {
|
||||
}
|
||||
}
|
||||
const hideOverlayTalking = (obj) => {
|
||||
isMoving.value = false
|
||||
if(!showTalkingModel.value) return
|
||||
if(activeNum.value + 1 === recNum.value){
|
||||
showTalkingModel.value = false
|
||||
//#ifdef APP-PLUS
|
||||
stopRecord()
|
||||
// #endif
|
||||
if(!isOut.value){
|
||||
setTimeout(()=>{
|
||||
emit('uploadVoice', audioPath.value)
|
||||
},1000)
|
||||
}
|
||||
}else{
|
||||
showTalkingModel.value = false
|
||||
common.msg('录音失败,请重试!')
|
||||
}
|
||||
activeNum.value = recNum.value
|
||||
//#ifdef APP-PLUS
|
||||
stopRecord()
|
||||
// #endif
|
||||
}
|
||||
|
||||
const handleMove = (obj) => {
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
if(outScreen.value){
|
||||
hideOverlayTalking(obj)
|
||||
if(isMoving.value){
|
||||
touchX.value = obj.changedTouches[0].pageX
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
if(outScreen.value){
|
||||
hideOverlayTalking(obj)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 发送文本
|
||||
|
||||
+26
-25
@@ -85,6 +85,8 @@
|
||||
@startRecord="changePlayItemId('')"
|
||||
:isLoading="isUploadingVoice"
|
||||
:onlyVoice="answerOnlyVoice"
|
||||
:canAnswer="testAnswer"
|
||||
:canAnswerText="'每个问题最多连续发送五次答案!'"
|
||||
:isDisabled="((lastTalkingInfo.type||0) !== 4)"
|
||||
/>
|
||||
</view>
|
||||
@@ -177,7 +179,6 @@ const isUploadingVoice = ref(false)
|
||||
// 初始化数据
|
||||
const getData = async (flag) => {
|
||||
try{
|
||||
initsocketTask()
|
||||
const { body } = await getCourseStudyInfoApi({crsId: crsId.value})
|
||||
teacherList.value = body.teacheList.map(t=>({
|
||||
...t,
|
||||
@@ -445,7 +446,7 @@ const getQuestionInfoUnStudy = (pgrphId) => {
|
||||
id: _id,
|
||||
isQuestion: true
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||||
qstLogId.value = _body.chatBody?.qstLogId
|
||||
scrollToBottomNow()
|
||||
}else{
|
||||
@@ -548,7 +549,8 @@ const nextQuestionSuccess = (info, type='next') => {
|
||||
isQuestion: true
|
||||
}
|
||||
talkingList.value.push(lastTalkingInfo.value)
|
||||
qstLogId.value = _body.chatBody.qstLogId
|
||||
logId.value = _body.chatBody.logId
|
||||
qstLogId.value = _body.chatBody.qstLogId || qstLogId.value
|
||||
scrollToBottomNow()
|
||||
})
|
||||
}
|
||||
@@ -581,18 +583,18 @@ const logId = ref('')
|
||||
// ws 初始化逻辑
|
||||
const initsocketTask = () => {
|
||||
socketStore.creatSocket()
|
||||
unref(SocketObj).on('open', (res)=>{
|
||||
if(startPgrphId.value){
|
||||
sendMessage({
|
||||
"commond" : 'STDY',
|
||||
"body" : {
|
||||
crsId: crsId.value,
|
||||
teacherNo: choiceTeacher.value
|
||||
}
|
||||
})
|
||||
step.value = 2
|
||||
}
|
||||
})
|
||||
// unref(SocketObj).on('open', (res)=>{
|
||||
// if(startPgrphId.value){
|
||||
// sendMessage({
|
||||
// "commond" : 'STDY',
|
||||
// "body" : {
|
||||
// crsId: crsId.value,
|
||||
// teacherNo: choiceTeacher.value
|
||||
// }
|
||||
// })
|
||||
// step.value = 2
|
||||
// }
|
||||
// })
|
||||
unref(SocketObj).on('message', (res)=>{
|
||||
const { rtnCode, body, commond } = JSON.parse(res.data)
|
||||
if(rtnCode === '0000'){
|
||||
@@ -611,10 +613,7 @@ const initsocketTask = () => {
|
||||
})
|
||||
}
|
||||
const reconnect = ()=> {
|
||||
if(reconnectTimer || isManualClose.value) return
|
||||
reconnectTimer = setTimeout(()=>{
|
||||
initsocketTask()
|
||||
},3000)
|
||||
initsocketTask()
|
||||
}
|
||||
const sendMessage = (data) => {
|
||||
unref(SocketObj).send(data)
|
||||
@@ -623,6 +622,7 @@ const sendMessage = (data) => {
|
||||
const startPgrphId = ref('')
|
||||
const imageId = ref('')
|
||||
onLoad((params) => {
|
||||
watchFlag.value = 1
|
||||
crsId.value = params.crsId||'';
|
||||
crsNum.value = params.crsNum||'';
|
||||
imageId.value = params.imgId || ''
|
||||
@@ -632,21 +632,21 @@ onLoad((params) => {
|
||||
const showTalkingModel = ref(false)
|
||||
// 录音
|
||||
onMounted(()=>{
|
||||
initsocketTask()
|
||||
getData('1');
|
||||
console.log('onMounted')
|
||||
})
|
||||
onHide(()=>{
|
||||
if(watchFlag.value === 1) return
|
||||
changePlayItemId('')
|
||||
socketStore.closeSocket()
|
||||
common.show('提示信息', '检测到您已离开,即将退出学习页面。',false, '','确认').then((res) => {
|
||||
common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`)
|
||||
}).finally(() => {})
|
||||
// common.show('提示信息', '检测到您已离开,即将退出学习页面。',false, '','确认').then((res) => {
|
||||
// common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`)
|
||||
// }).finally(() => {})
|
||||
})
|
||||
onShow(()=>{
|
||||
console.log('onShow')
|
||||
if(watchFlag.value === 1) return
|
||||
getData('1');
|
||||
// getData('2');
|
||||
initsocketTask()
|
||||
})
|
||||
const watchFlag = ref(1)
|
||||
onUnload(()=>{
|
||||
@@ -786,6 +786,7 @@ const submitAnswerNow = (val, cb) => {
|
||||
talkingVoice: '',
|
||||
type: 2,
|
||||
userInfo: {...choiceTeacherInfo.value},
|
||||
qstLogId: qstLogId.value,
|
||||
id: _id
|
||||
})
|
||||
scrollToBottomNow()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<view class="talking-info" v-if="dataInfo.intrctWay === '02'">
|
||||
<view :class="['talking-gif', !voiceLoading ? 'is-play' : '']">
|
||||
<view :class="['talking-gif', !voiceLoading&&(props.activeVoiceId === dataInfo.id) ? 'is-play' : '']">
|
||||
<CommonLoading color="#fff" v-show="voiceLoading"/>
|
||||
</view>
|
||||
<view class="right-time">{{voiceTime}}</view>
|
||||
@@ -15,13 +15,13 @@
|
||||
<view class="btns-cont">
|
||||
<view class="play-btn">
|
||||
<image class="icon"
|
||||
v-show="!isPlaying"
|
||||
v-show="!(!voiceLoading&&(props.activeVoiceId === dataInfo.id))"
|
||||
@click="playVoice"
|
||||
src="@/static/images/course/play-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
<image class="icon"
|
||||
v-show="isPlaying"
|
||||
v-show="!voiceLoading&&(props.activeVoiceId === dataInfo.id)"
|
||||
@click.stop="pauseVoice"
|
||||
src="@/static/images/course/stop-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
@@ -45,7 +45,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, unref, ref, toRefs, watch, onMounted } from "vue"
|
||||
import { computed, unref, ref, toRefs, watch, onMounted } from "vue"
|
||||
import { onUnload } from '@dcloudio/uni-app';
|
||||
const props = defineProps({
|
||||
dataInfo: {
|
||||
@@ -63,6 +63,7 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
// 声音播放初始化
|
||||
const talkVoiceObj = ref(null)
|
||||
|
||||
const isPlaying = ref(false)
|
||||
const voiceLoading = ref(false)
|
||||
const translateLoading = ref(false)
|
||||
|
||||
@@ -77,35 +78,46 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
onUnload(()=>{
|
||||
pauseVoice()
|
||||
})
|
||||
watch(() => props.dataInfo.talkingVoice,(val)=>{
|
||||
if(val){
|
||||
initVoice()
|
||||
}
|
||||
},{
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
const pauseVoice = () => {
|
||||
if(!talkVoiceObj.value) return
|
||||
talkVoiceObj.value.pause()
|
||||
isPlaying.value = false
|
||||
emit('changePlay', '')
|
||||
}
|
||||
const playVoice = () =>{
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
if(talkVoiceObj.value.src && talkVoiceObj.value.src === itemVoice.value) {
|
||||
if(talkVoiceObj.value && talkVoiceObj.value.src) {
|
||||
talkVoiceObj.value.play()
|
||||
return
|
||||
}
|
||||
talkVoiceObj.value.src = ''
|
||||
if(itemVoice.value){
|
||||
setTimeout(()=>{
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
talkVoiceObj.value.play()
|
||||
},100)
|
||||
}else{
|
||||
talkVoiceObj.value.src = ''
|
||||
if(unref(dataInfo).talkingVoice){
|
||||
setTimeout(()=>{
|
||||
talkVoiceObj.value.src = unref(dataInfo).talkingVoice
|
||||
talkVoiceObj.value.play()
|
||||
isPlaying.value = true
|
||||
},100)
|
||||
}
|
||||
}
|
||||
}
|
||||
const initVoice = () => {
|
||||
if(unref(dataInfo).talkingVoice){
|
||||
talkVoiceObj.value = uni.createInnerAudioContext()
|
||||
talkVoiceObj.value.onEnded(()=>{
|
||||
emit('changePlay', '')
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
talkVoiceObj.value.onError(()=>{
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
talkVoiceObj.value = uni.createInnerAudioContext()
|
||||
talkVoiceObj.value.onEnded(()=>{
|
||||
emit('changePlay', '')
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
talkVoiceObj.value.onError(()=>{
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
if(unref(dataInfo).intrctWay === '02'){
|
||||
itemVoice.value = unref(dataInfo).talkingVoice
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
setTimeout(()=>{
|
||||
@@ -158,6 +170,9 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
height: 38rpx;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
&.talking-info-loading{
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
&.talking-info-text{
|
||||
padding-bottom: 20rpx;
|
||||
width: auto;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
v-if="talkingType === 'question'"
|
||||
@changePlay="changePlay"
|
||||
:dataInfo="talkingInfo"
|
||||
:activeVoiceId="activeVoiceId"
|
||||
></questionVue>
|
||||
<answerVue
|
||||
v-else-if="talkingType === 'answer'"
|
||||
@@ -28,8 +29,13 @@
|
||||
talkingInfo:{
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
activeVoiceId:{
|
||||
default:'',
|
||||
type: String
|
||||
}
|
||||
})
|
||||
watch(() => props.activeVoiceId, () => {},{deep: true,immediate: true})
|
||||
watch(() => props.talkingInfo, () => {},{deep: true,immediate: true})
|
||||
const { talkingType } = toRefs(props)
|
||||
const handleEvents = (type) => {
|
||||
|
||||
+83
-44
@@ -13,9 +13,11 @@
|
||||
AI问答
|
||||
</view>
|
||||
<view class="ai-info">
|
||||
<image src="@/static/images/dialog/pet-3.png" alt="" class="image-pet-bg"></image>
|
||||
<view class="ai-info-bg-box">
|
||||
<view class="hello-text">Hi,我是{{'李想'}}</view>
|
||||
<!-- <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="userInfo.mascotInfo?.imgAddr ||''" alt="" class="image-pet"></image>
|
||||
<view class="ai-info-bg-box">
|
||||
<view class="hello-text">Hi,我是{{ userInfo.mascotInfo?.mascotName || ''}}</view>
|
||||
<view class="info-text">工作学习,我都能帮你!</view>
|
||||
<view class="info-btn">试试他的能力</view>
|
||||
</view>
|
||||
@@ -50,6 +52,7 @@
|
||||
v-for="item in talkingList"
|
||||
:talkingType="item.type"
|
||||
:talkingInfo="item"
|
||||
:activeVoiceId="activeVoiceTalkingItemId"
|
||||
@handleEvents="talkItemEvents"
|
||||
>
|
||||
</TalkingItem>
|
||||
@@ -101,7 +104,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, unref, onMounted, watch, nextTick } from 'vue'
|
||||
import { ref, unref, onMounted, watch, nextTick, computed } from 'vue'
|
||||
import common from '@/common/common';
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue'
|
||||
import TalkingItem from './components/talking-item.vue';
|
||||
@@ -110,12 +113,14 @@
|
||||
import { storeToRefs } from 'pinia'
|
||||
import { onLoad, onShow, onUnload, onHide } from '@dcloudio/uni-app';
|
||||
import { get_base_url, goto_login_fun } from '@/api/request'
|
||||
import {
|
||||
commonUploadVoiceFile
|
||||
} from "@/api/common.js"
|
||||
import { getUserInfo } from '@/common/common';
|
||||
import {
|
||||
commonUploadVoiceFile
|
||||
} from "@/api/common.js"
|
||||
|
||||
const socketStore = useSocketStore()
|
||||
const { SocketObj } = storeToRefs(socketStore)
|
||||
const userInfo = computed(() => getUserInfo())
|
||||
|
||||
const questionList = ref([
|
||||
'对公小程序开户流程?',
|
||||
@@ -139,31 +144,33 @@ import {
|
||||
},time)
|
||||
})
|
||||
}
|
||||
|
||||
const activeVoiceTalkingItemId = ref('')
|
||||
// ws 初始化逻辑
|
||||
const reconnectTimer = null // 重连timer
|
||||
const isManualClose = ref(false) // 是否手动关闭
|
||||
const reqBatch = ref('')
|
||||
const seqNo = ref('')
|
||||
const mascotId = ref('Tst00001')
|
||||
const mascotId = computed(() => {
|
||||
return unref(userInfo).mascotInfo?.mascotId || 'Tst00001'
|
||||
})
|
||||
const answerText = ref('')
|
||||
const answerIsOver = ref(true)
|
||||
const talkingList = ref([])
|
||||
|
||||
const initsocketTask = () => {
|
||||
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('open', (res)=>{
|
||||
// if(!answerIsOver.value){
|
||||
// sendMessage({
|
||||
// "commond" : 'ASK-RE-START',
|
||||
// "body" : {
|
||||
// reqBatch: reqBatch.value,
|
||||
// seqNo: seqNo.value,
|
||||
// answerContent: answerText.value
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
// })
|
||||
unref(SocketObj).on('message', (res)=>{
|
||||
const { rtnCode, body, commond } = JSON.parse(res.data)
|
||||
let _id = new Date().getTime() + 'id'
|
||||
@@ -197,7 +204,8 @@ import {
|
||||
talkingText: body.intrctContent,
|
||||
isLoading: false,
|
||||
id: _id,
|
||||
...body
|
||||
...body,
|
||||
talkingVoice: askData.value.talkingVoice
|
||||
})
|
||||
return
|
||||
}
|
||||
@@ -246,6 +254,7 @@ import {
|
||||
|
||||
if(commond === 'ASK-ERR'){
|
||||
console.log('提问失败,系统异常!')
|
||||
console.log('body')
|
||||
return
|
||||
}
|
||||
}else{
|
||||
@@ -313,6 +322,7 @@ import {
|
||||
break;
|
||||
case 'changePlay':
|
||||
console.log('播放/暂停')
|
||||
activeVoiceTalkingItemId.value = id
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -349,21 +359,31 @@ import {
|
||||
isLoading: true
|
||||
})
|
||||
scrollToBottomNow()
|
||||
console.log(voicePath,111111111)
|
||||
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {}).then(res=>{
|
||||
let _res = JSON.parse(res.data)
|
||||
if(_res.rtnCode === '0000'){
|
||||
askData.value = {
|
||||
reqBatch: reqBatch.value,
|
||||
intrctWay: '02',//01-文本;02-语音;03-图片
|
||||
intrctContent: _res.body.transContent,
|
||||
bucketKey: _res.body.fileId,
|
||||
ossFileAddr: _res.body.ossFileAddr,
|
||||
talkingVoice: voicePath
|
||||
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
|
||||
});
|
||||
}
|
||||
sendMessage({
|
||||
"commond" : 'ASK',
|
||||
"body": askData.value
|
||||
})
|
||||
}else{}
|
||||
}).catch(err=>{
|
||||
talkingList.value.pop()
|
||||
@@ -414,14 +434,25 @@ import {
|
||||
})
|
||||
onShow(()=>{
|
||||
if(watchFlag.value === 1) return
|
||||
socketStore?.createSocket?.()
|
||||
sendMessage({
|
||||
"commond" : 'ASK-START',
|
||||
"body" : {
|
||||
mascotId: mascotId.value,
|
||||
deviceImei: ''
|
||||
}
|
||||
})
|
||||
socketStore?.createSocket()
|
||||
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: ''
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
onUnload(()=>{
|
||||
watchFlag.value = 1
|
||||
@@ -514,14 +545,22 @@ import {
|
||||
margin-bottom: 24rpx;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
.image-pet{
|
||||
width: 230rpx;
|
||||
height: 235rpx;
|
||||
position: absolute;
|
||||
right: 24rpx;
|
||||
top: 15rpx;
|
||||
z-index: 2;
|
||||
}
|
||||
.image-pet-bg{
|
||||
position: absolute;
|
||||
padding: 0 24rpx;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
height: 230rpx;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
.ai-info-bg-box{
|
||||
@@ -556,7 +595,7 @@ import {
|
||||
text-align: center;
|
||||
border-radius: 15rpx 15rpx 0 0;
|
||||
position: absolute;
|
||||
left: 64rpx;
|
||||
left: 68rpx;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 344 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
Reference in New Issue
Block a user