1554 lines
43 KiB
Vue
1554 lines
43 KiB
Vue
<template>
|
||
<view class="course-study max_page">
|
||
<view class="top-bg"></view>
|
||
<view class="bot-bg"></view>
|
||
<view class="course-study-body" v-show="step === 1">
|
||
<view class="seek-setting">
|
||
<view class="inline-block" @click="showChangeSeekModelNow">{{ chooseRate }}倍</view>
|
||
<!-- <image src="@/static/images/course/setting.png" alt="" class="image-icon" @click.stop="showChangeBgModelNow"></image> -->
|
||
</view>
|
||
<view class="body-title">
|
||
<uv-icon class="arrow-icon" name="arrow-left" @click="backRouter()" />
|
||
语言选择,开启学习之旅
|
||
</view>
|
||
<view class="voice-list">
|
||
<uv-radio-group v-model="choiceTeacher">
|
||
<view class="voice-item" v-for="item in teacherList" :key="item.teacherNo" @click="choiceTeacher = item.teacherNo">
|
||
<view class="avatar-box">
|
||
<ImagePreview class="img-box" :src="item.imgAddr" :isCache="true" :width="120" :height="160"> </ImagePreview>
|
||
</view>
|
||
<view class="right-cont">
|
||
<view class="right-name">{{ item.teacherName }}</view>
|
||
<view class="right-desc">描述:{{ item.voiceDesc || '--' }}</view>
|
||
<view class="audio-box">
|
||
<view :class="['talking-gif', activeVoiceTeachNo === item.teacherNo && !loadingTeacherVoice ? 'is-play' : '']"> </view>
|
||
<CommonLoading color="#06f" v-show="activeVoiceTeachNo === item.teacherNo && loadingTeacherVoice" style="float: left" />
|
||
<view class="play-btn" @click="playTeacherVoice(item)">
|
||
<image class="icon" v-if="activeVoiceTeachNo !== item.teacherNo" src="@/static/images/course/play-blue.png" style="width: 100%; height: 100%"></image>
|
||
<image class="icon" v-else src="@/static/images/course/stop-blue.png" style="width: 100%; height: 100%"></image>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
<uv-radio :name="item.teacherNo" class="radio-box" @click.stop />
|
||
</view>
|
||
</uv-radio-group>
|
||
</view>
|
||
<view class="start-btns" @click="nextStep"> 开启学习之旅 </view>
|
||
</view>
|
||
<view :class="['course-study-body', !IsAndEnv ? 'isIos' : 'isAnd']" v-show="step === 2">
|
||
<view class="seek-setting">
|
||
<view class="inline-block" @click="showChangeSeekModelNow">{{ chooseRate }}倍</view>
|
||
<view class="image-icon" @click="showChangeBgModelNow">
|
||
<image src="@/static/images/course/setting.png" alt="" class="image-icon-img"></image>
|
||
</view>
|
||
</view>
|
||
<view class="body-title" @click="scrollToBottomNow">
|
||
<uv-icon class="arrow-icon" name="arrow-left" @click="backRouter()" />
|
||
课程学习
|
||
</view>
|
||
<view class="study-num">
|
||
<view class="color-blue">{{ showOrder }}</view> / {{ pgrphNum }}
|
||
</view>
|
||
<scroll-view class="talking-list" :scroll-y="true" :scroll-top="scrollTop" :show-scrollbar="false" :scroll-with-animation="true">
|
||
<!-- <view class="talking-list-cont" id="scroll-box" ref="scrollBoxRef"> -->
|
||
<TalkingItem
|
||
class="talking-item"
|
||
v-for="(item, index) in talkingList"
|
||
:key="'item' + item.id"
|
||
:type="item.type"
|
||
:dataInfo="item"
|
||
:activeVoiceId="activeVoiceTalkingItemId"
|
||
:isPlaying="activeVoiceTalkingItemId === item.id"
|
||
:voiceRate="chooseRate"
|
||
:lastQuestionInfo="lastTalkingInfo"
|
||
:teacherInfo="choiceTeacherInfo"
|
||
@changePlay="changePlayItemId"
|
||
@nextQuestion="nextQuestionSuccess"
|
||
@withdraw="withdrawNow"
|
||
@answerQuestion="answerQuestionNow"
|
||
@finishQuestion="finishQuestionNow"
|
||
:id="'item' + item.id"
|
||
:isLast="talkingList.length === index + 1"></TalkingItem>
|
||
<!-- <video v-if="videoUrlShow" :src="videoUrlShow" controls></video> -->
|
||
<!-- </view> -->
|
||
</scroll-view>
|
||
<TouchBtn
|
||
class="talk-btns"
|
||
@uploadVoice="uploadRecordNow"
|
||
@submitAnswer="submitAnswerNow"
|
||
@startRecord="changePlayItemId('')"
|
||
:isLoading="isUploadingVoice"
|
||
:onlyVoice="answerOnlyVoice"
|
||
:canAnswer="testAnswer"
|
||
:adjustPosition="true"
|
||
:canAnswerText="canAnswerText"
|
||
:isDisabled="(lastTalkingInfo.type || 0) !== 4 || ['SN','MU','JD'].includes(lastTalkingInfo.qnsTyp)"/>
|
||
</view>
|
||
<uv-overlay :show="showSeekModel" opacity=".6" @click="showSeekModel = false">
|
||
<view class="overlay-box">
|
||
<view class="white-bg-box">
|
||
<view class="box-title">倍速</view>
|
||
<view class="box-btns">
|
||
<view v-for="item in rateList" :class="{ 'is-active': item === chooseRate }" @click="chooseRateNow(item)">
|
||
{{ item }}
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</uv-overlay>
|
||
<uv-overlay :show="showBgModel" opacity=".6" @click="showBgModel = false">
|
||
<view class="overlay-box">
|
||
<view class="white-bg-box-setting white-bg-box">
|
||
<view class="box-title">设置 </view>
|
||
<view class="box-items" @click.stop>
|
||
<view class="box-item">
|
||
<view class="box-item-title">音色</view>
|
||
<uv-radio-group v-model="choiceTeacher" class="box-item-cont">
|
||
<view class="overlay-voice-item" v-for="item in teacherList" :key="item.teacherNo" @click="changeTeacherVoiceNow(item)">
|
||
<view class="overlay-avatar-box">
|
||
<ImagePreview class="overlay-img-box" :src="item.imgAddr" :isCache="true" :width="120" :height="160"></ImagePreview>
|
||
</view>
|
||
<view class="overlay-teacher-name">{{ item.teacherName }}</view>
|
||
<uv-radio :name="item.teacherNo" class="overlay-radio-box" @click.stop />
|
||
</view>
|
||
</uv-radio-group>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</uv-overlay>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { reactive, ref, computed, unref, onMounted, onUnmounted, getCurrentInstance, nextTick } from 'vue'
|
||
import { onLoad, onShow, onUnload, onHide } from '@dcloudio/uni-app'
|
||
import { previewFile, downloadFile, commonUploadVoiceFile, downloadVoiceFile, uploadVoiceFile } from '@/api/common.js'
|
||
import { getToken, getPhoneEnvBool } from '@/common/common.js'
|
||
import { get_base_url, goto_login_fun } from '@/api/request'
|
||
import { getCourseStudyInfoApi, afreshStudyCourseApi, queryQuestionEvalateApi, textChartApi, setStudyTeacherApi, textChartPreviewApi, previewAfreshStudyCourse } 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'
|
||
import { storeToRefs } from 'pinia'
|
||
|
||
const socketStore = useSocketStore()
|
||
const storageStore = useStorageStore()
|
||
const { SocketObj } = storeToRefs(socketStore)
|
||
const audioCacheObj = computed(() => storageStore.audioObj)
|
||
|
||
const { proxy } = getCurrentInstance()
|
||
const crsNum = ref('')
|
||
const crsId = ref('')
|
||
const step = ref(0)
|
||
const teacherList = ref([])
|
||
const choiceTeacher = ref('')
|
||
const videoUrlShow = ref('')
|
||
const talkingList = ref([])
|
||
const activeVoiceTalkingItemId = ref('')
|
||
const answerValue = ref('')
|
||
const inputRef = ref('')
|
||
const flagVal = ref('1')
|
||
const isUploadingVoice = ref(false)
|
||
const isPreview = ref(false)
|
||
const IsAndEnv = ref(getPhoneEnvBool('AND'))
|
||
|
||
const ajaxApi = computed(() => (isPreview.value ? textChartPreviewApi : textChartApi))
|
||
|
||
const { statusBarHeight } = uni.getWindowInfo()
|
||
|
||
const pageTopPadding = computed(() => statusBarHeight + 'px')
|
||
|
||
const isContinue = ref('N')
|
||
// 初始化数据
|
||
const getData = async flag => {
|
||
isContinue.value = "N"
|
||
try {
|
||
const { body } = await getCourseStudyInfoApi({
|
||
crsId: crsId.value
|
||
})
|
||
teacherList.value = body.teacheList.map(t => ({
|
||
...t,
|
||
voicePath: '',
|
||
voiceObj: null
|
||
}))
|
||
if (isPreview.value) {
|
||
resStartStudyNow(body.teacheList)
|
||
} else {
|
||
if(body.isStdyFinish === 'Y'){
|
||
// 重新学习
|
||
resStartStudyNow(body.teacheList)
|
||
return
|
||
}
|
||
if (body.stdyProgressFlag === 'N') {
|
||
step.value = 1
|
||
} else {
|
||
choiceTeacher.value = body.choiceTeacher
|
||
if (startPgrphId.value) {
|
||
sendMessage({
|
||
commond: 'STDY',
|
||
body: {
|
||
crsId: crsId.value,
|
||
teacherNo: choiceTeacher.value,
|
||
studyType: isPreview.value ? 'P' : 'S',
|
||
isContinue: isContinue.value
|
||
}
|
||
})
|
||
return
|
||
}
|
||
common
|
||
.show('提示', '系统检测到您已存在学习记录,要继续学习吗?', true, '重新学习', '继续学习')
|
||
.then(res => {
|
||
if (res) {
|
||
// 继续学习 , 获取学习历史接口
|
||
// 滚动到最下面
|
||
scrollToBottomNow()
|
||
isContinue.value = "Y"
|
||
sendMessage({
|
||
commond: 'STDY',
|
||
body: {
|
||
crsId: crsId.value,
|
||
teacherNo: choiceTeacher.value,
|
||
studyType: isPreview.value ? 'P' : 'S',
|
||
isContinue: isContinue.value
|
||
}
|
||
})
|
||
step.value = 2
|
||
} else {
|
||
// 重新学习
|
||
resStartStudyNow(body.teacheList)
|
||
}
|
||
})
|
||
.finally(() => {})
|
||
}
|
||
}
|
||
} catch {
|
||
} finally {
|
||
watchFlag.value += 1
|
||
}
|
||
}
|
||
// 重新学习
|
||
const resStartStudyNow = ($list = []) => {
|
||
let _ajax = isPreview.value ? previewAfreshStudyCourse : afreshStudyCourseApi
|
||
console.log(_ajax)
|
||
_ajax({
|
||
crsId: crsId.value
|
||
})
|
||
.then(res => {
|
||
step.value = 1
|
||
teacherList.value = $list.map(t => ({
|
||
...t,
|
||
voicePath: '',
|
||
voiceObj: null
|
||
}))
|
||
})
|
||
.catch(e => {
|
||
step.value = 1
|
||
teacherList.value = $list.map(t => ({
|
||
...t,
|
||
voicePath: '',
|
||
voiceObj: null
|
||
}))
|
||
})
|
||
}
|
||
|
||
const showChangeSeekModelNow = () => {
|
||
// changePlayItemId()
|
||
showSeekModel.value = true
|
||
}
|
||
const showBgModel = ref(false)
|
||
const showChangeBgModelNow = () => {
|
||
changePlayItemId()
|
||
showBgModel.value = true
|
||
}
|
||
// 关闭播放状态
|
||
const changePlayItemId = (id = '') => {
|
||
activeVoiceTalkingItemId.value = id
|
||
// if(activeVoiceTalkingItemId.value === id){
|
||
// activeVoiceTalkingItemId.value = ''
|
||
// }else{
|
||
// activeVoiceTalkingItemId.value = id
|
||
// }
|
||
}
|
||
// 选择的教师对象信息
|
||
const choiceTeacherInfo = computed(() => {
|
||
return teacherList.value.find(t => t.teacherNo === choiceTeacher.value)
|
||
})
|
||
|
||
const changeTeacherVoiceNow = async item => {
|
||
if (item.teacherNo === choiceTeacher.value) return
|
||
try {
|
||
const res = await setStudyTeacherApi({
|
||
stdyId: stdyId.value,
|
||
teacherNo: item.teacherNo
|
||
})
|
||
if (res.rtnCode === '0000') {
|
||
choiceTeacher.value = item.teacherNo
|
||
showBgModel.value = false
|
||
}
|
||
} catch {
|
||
} finally {
|
||
}
|
||
}
|
||
|
||
// 选择教师语音对象
|
||
const activeVoiceTeachNo = ref('')
|
||
let teacherVoiceObj = uni.createInnerAudioContext()
|
||
|
||
teacherVoiceObj.onEnded(() => {
|
||
activeVoiceTeachNo.value = ''
|
||
teacherVoiceObj.src = ''
|
||
})
|
||
const loadingTeacherVoice = ref(false)
|
||
const playTeacherVoice = item => {
|
||
teacherVoiceObj.stop()
|
||
teacherVoiceObj.src = ''
|
||
let _isStop = item.teacherNo === activeVoiceTeachNo.value
|
||
activeVoiceTeachNo.value = _isStop ? '' : item.teacherNo
|
||
if (_isStop) return
|
||
if (item.voicePath) {
|
||
teacherVoiceObj.src = item.voicePath
|
||
teacherVoiceObj.play()
|
||
} else {
|
||
loadingTeacherVoice.value = true
|
||
storageStore.getStorageById('audio', item.teacherNo, url => {
|
||
if (url) {
|
||
teacherVoiceObj.src = url
|
||
teacherVoiceObj.play()
|
||
loadingTeacherVoice.value = false
|
||
} else {
|
||
downloadVoiceFile('/trastudy/traStdyInfo/trialListening?teachNo=' + item.teacherNo).then(res => {
|
||
loadingTeacherVoice.value = false
|
||
item.voicePath = res.tempFilePath
|
||
teacherVoiceObj.src = item.voicePath
|
||
teacherVoiceObj.play()
|
||
storageStore.setStorage('audio', item.teacherNo, item.voicePath)
|
||
})
|
||
}
|
||
})
|
||
}
|
||
}
|
||
var socketTask = null
|
||
const nextStep = () => {
|
||
if (choiceTeacher.value) {
|
||
teacherVoiceObj.destroy()
|
||
sendMessage({
|
||
commond: 'STDY',
|
||
body: {
|
||
crsId: crsId.value,
|
||
teacherNo: choiceTeacher.value,
|
||
studyType: isPreview.value ? 'P' : 'S',
|
||
isContinue: isContinue.value
|
||
}
|
||
})
|
||
step.value = 2
|
||
} else {
|
||
uni.showToast({
|
||
title: '请选择一位教师!',
|
||
icon: 'none',
|
||
duration: 1000
|
||
})
|
||
}
|
||
}
|
||
|
||
const pgrphNum = ref(1)
|
||
const showOrder = ref(0)
|
||
const isLastPgrph = ref(false)
|
||
const backRouter = () => {
|
||
// common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`)
|
||
// uni.$emit('refresh_course_list') // yh0903让去除
|
||
common.navigateBack()
|
||
}
|
||
|
||
const answerOnlyVoice = computed(() => {
|
||
return lastTalkingInfo.value.answerWay === 'V'
|
||
})
|
||
|
||
const canAnswerText = computed(() => {
|
||
return '每个问题最多连续发送五次答案!'
|
||
})
|
||
|
||
const oldStdyId = ref('')
|
||
// 获取段落
|
||
const getGraphInfoUnStudy = (flag = 0) => {
|
||
let _id = new Date().getTime() + 'id'
|
||
let _data = {
|
||
crsId: crsId.value,
|
||
stdyId: unref(stdyId),
|
||
stdyBatch: unref(stdyBatch),
|
||
oldStdyId: unref(oldStdyId),
|
||
isContinue: isContinue.value
|
||
}
|
||
if (flag === 1 && !!startPgrphId.value) {
|
||
_data.pgrphId = startPgrphId.value
|
||
}
|
||
unref(ajaxApi)({
|
||
processType: 'PRGH-STDY',
|
||
requestBody: JSON.stringify(_data)
|
||
}).then(res => {
|
||
let _body = res.body || {}
|
||
if (!_body.chatBody) {
|
||
return
|
||
}
|
||
if (Number(_body.bodyTyp) === 7) {
|
||
uni.$emit('refresh_course_list', crsId.value)
|
||
if (isPreview.value) {
|
||
common
|
||
.show('提示', '您已学完全部知识点', false)
|
||
.then(res => {
|
||
common.navigateBack()
|
||
// common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study&isPreview=true`)
|
||
})
|
||
.finally(() => {})
|
||
} else {
|
||
common
|
||
.show('恭喜你已学完全部知识点', '有什么心得跟我们分享吗?', true, '取消', '去评论')
|
||
.then(res => {
|
||
if (res) {
|
||
// 去评论
|
||
common.redirectTo(`/pages/courseDetail/submit?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study&imgId=${imageId.value}`)
|
||
} else {
|
||
// 取消
|
||
common.navigateBack()
|
||
// common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`)
|
||
}
|
||
})
|
||
.finally(() => {})
|
||
}
|
||
|
||
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
|
||
}
|
||
isLastPgrph.value = _body.chatBody.haveNext !== 'Y'
|
||
talkingList.value.push(lastTalkingInfo.value)
|
||
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 => {
|
||
console.log(pgrphId)
|
||
unref(ajaxApi)({
|
||
processType: 'QNS-ANSER',
|
||
requestBody: JSON.stringify({
|
||
crsId: crsId.value,
|
||
stdyId: unref(stdyId),
|
||
stdyBatch: unref(stdyBatch),
|
||
logId: unref(logId),
|
||
pgrphId: pgrphId
|
||
})
|
||
}).then(res => {
|
||
let _id = new Date().getTime() + 'id'
|
||
let _body = res.body || {}
|
||
console.log(_body)
|
||
if (_body.bodyTyp === '4') {
|
||
lastTalkingInfo.value = {
|
||
crsId: crsId.value,
|
||
stdyId: unref(stdyId),
|
||
stdyBatch: unref(stdyBatch),
|
||
logId: unref(logId),
|
||
pgrphId,
|
||
chatContent: _body.chatContent || '',
|
||
...(_body.chatBody || {}),
|
||
type: 4,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
id: _id,
|
||
isQuestion: true,
|
||
my_answer: [],
|
||
backend_answer: []
|
||
}
|
||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
qstLogId.value = _body.chatBody?.qstLogId
|
||
scrollToBottomNow(800)
|
||
} else {
|
||
// getGraphInfoUnStudy()
|
||
lastTalkingInfo.value = {
|
||
crsId: crsId.value,
|
||
stdyId: unref(stdyId),
|
||
stdyBatch: unref(stdyBatch),
|
||
logId: unref(logId),
|
||
chatContent: _body.chatContent || '',
|
||
stdyStat: _body.chatBody.stdyStat,
|
||
type: 9,
|
||
pgrphId,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
id: _id
|
||
}
|
||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
}
|
||
})
|
||
}
|
||
|
||
// 继续 执行方法
|
||
const nextQuestionSuccess = (info, type = 'next') => {
|
||
console.log(info)
|
||
let _id = new Date().getTime() + 'id'
|
||
if (type === 'next') {
|
||
talkingList.value.push({
|
||
crsId: info.crsId,
|
||
pgrphId: info.pgrphId,
|
||
talkingContent: '继续',
|
||
type: 0,
|
||
id: _id
|
||
})
|
||
scrollToBottomNow()
|
||
getQuestionInfoUnStudy(info.pgrphId)
|
||
} else if (type === 'overGraph') {
|
||
unref(ajaxApi)({
|
||
processType: 'PRGH-OVER',
|
||
requestBody: JSON.stringify({
|
||
stdyId: unref(stdyId),
|
||
pgrphId: info?.pgrphId,
|
||
logId: info?.logId,
|
||
oldStdyId: unref(oldStdyId),
|
||
isContinue: isContinue.value
|
||
})
|
||
}).then(res => {
|
||
talkingList.value.push({
|
||
crsId: info.crsId,
|
||
pgrphId: info.pgrphId,
|
||
talkingContent: '继续',
|
||
type: 0,
|
||
id: _id
|
||
})
|
||
scrollToBottomNow()
|
||
getQuestionInfoUnStudy(info.pgrphId)
|
||
})
|
||
} else if (type === 'nextGraph') {
|
||
talkingList.value.push({
|
||
crsId: info.crsId,
|
||
pgrphId: info.pgrphId,
|
||
talkingContent: '继续学',
|
||
type: 0,
|
||
id: _id
|
||
})
|
||
// 下个段落
|
||
getGraphInfoUnStudy()
|
||
} else if (type === 'reStart') {
|
||
talkingList.value.push({
|
||
crsId: info.crsId,
|
||
pgrphId: info.pgrphId,
|
||
talkingContent: '重新答',
|
||
type: 0,
|
||
id: _id
|
||
})
|
||
// 重新回答
|
||
unref(ajaxApi)({
|
||
processType: 'NEW-ANSER', //NEW-KNOW
|
||
requestBody: JSON.stringify({
|
||
stdyId: unref(stdyId),
|
||
qnsId: info.qnsId
|
||
})
|
||
}).then(res => {
|
||
let _body = res.body || {}
|
||
if (!_body.chatBody) {
|
||
return
|
||
}
|
||
lastTalkingInfo.value = {
|
||
crsId: info.crsId,
|
||
qstLogId: _body.chatBody,
|
||
chatContent: _body.chatContent,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
..._body.chatBody,
|
||
pgrphId: info.pgrphId,
|
||
type: Number(_body.bodyTyp) || 0,
|
||
id: _id,
|
||
isQuestion: true,
|
||
my_answer: [],
|
||
backend_answer: []
|
||
}
|
||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
qstLogId.value = _body.chatBody.qstLogId
|
||
scrollToBottomNow()
|
||
})
|
||
} else if (type === 'reStartPrgh') {
|
||
talkingList.value.push({
|
||
crsId: info.crsId,
|
||
pgrphId: info.pgrphId,
|
||
talkingContent: '重新学',
|
||
type: 0,
|
||
id: _id
|
||
})
|
||
console.log(unref(logId))
|
||
unref(ajaxApi)({
|
||
processType: 'NEW-KNOW',
|
||
requestBody: JSON.stringify({
|
||
logId: unref(logId),
|
||
pgrphId: info.pgrphId,
|
||
stdyId: unref(stdyId)
|
||
})
|
||
}).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(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
logId.value = _body.chatBody.logId
|
||
qstLogId.value = _body.chatBody.qstLogId || qstLogId.value
|
||
scrollToBottomNow()
|
||
})
|
||
}
|
||
}
|
||
const scrollBoxRef = ref()
|
||
const scrollTop = ref(99999)
|
||
const scrollToBottomNow = (time = 500) => {
|
||
nextTick(() => {
|
||
setTimeout(() => {
|
||
scrollTop.value += 1
|
||
scrollTop.value += 1
|
||
let _arr = talkingList.value || []
|
||
if (_arr.length && _arr.length > 0) {
|
||
let _last = talkingList.value[talkingList.value.length - 1]
|
||
uni.pageScrollTo({
|
||
selector: '#item' + _last.id,
|
||
duration: 300
|
||
})
|
||
}
|
||
}, time)
|
||
})
|
||
}
|
||
|
||
const reconnectTimer = null // 重连timer
|
||
const isManualClose = ref(false) // 是否手动关闭
|
||
|
||
const stdyId = ref('')
|
||
const stdyBatch = ref('')
|
||
const logId = ref('')
|
||
// ws 初始化逻辑
|
||
const initsocketTask = () => {
|
||
socketStore.creatSocket()
|
||
unref(SocketObj).on('message', res => {
|
||
const { rtnCode, body, commond } = JSON.parse(res.data)
|
||
if (rtnCode === '0000') {
|
||
if (commond === 'STDYBTH' && !stdyId.value) {
|
||
stdyId.value = body.stdyId || ''
|
||
stdyBatch.value = body.stdyBatch || ''
|
||
oldStdyId.value = body.oldStdyId || ''
|
||
logId.value = body.logId || ''
|
||
getGraphInfoUnStudy(1)
|
||
step.value = 2
|
||
}
|
||
} else {
|
||
// if(['0005', 'QQ0005'].includes(res.rtnCode)) {
|
||
// goto_login_fun();
|
||
// }
|
||
}
|
||
})
|
||
}
|
||
const reconnect = () => {
|
||
initsocketTask()
|
||
}
|
||
const sendMessage = data => {
|
||
unref(SocketObj).send(data)
|
||
}
|
||
// ws 结束
|
||
const startPgrphId = ref('')
|
||
const imageId = ref('')
|
||
onLoad(params => {
|
||
changeAppHeightBottom()
|
||
watchFlag.value = 1
|
||
isPreview.value = params.isPreview === 'preview'
|
||
crsId.value = params.crsId || ''
|
||
crsNum.value = params.crsNum || ''
|
||
imageId.value = params.imgId || ''
|
||
startPgrphId.value = params.pgrphId || ''
|
||
})
|
||
const showTalkingModel = ref(false)
|
||
// 录音
|
||
onMounted(() => {
|
||
initsocketTask()
|
||
getData('1')
|
||
})
|
||
const keyboardHeight = ref('0px')
|
||
const setHeight = res => {
|
||
keyboardHeight.value = res.height + 'px'
|
||
// scrollToBottomNow()
|
||
}
|
||
|
||
const keyBoardIsHide = computed(() => {
|
||
return parseInt(keyboardHeight.value) == 0
|
||
})
|
||
const bottomHeight = ref('0px')
|
||
const totalBotHeight = computed(() => {
|
||
return keyBoardIsHide.value ? 0 + 'px' : parseInt(keyboardHeight.value) - parseInt(bottomHeight.value) + 'px'
|
||
})
|
||
const changeAppHeightBottom = height => {
|
||
//#ifdef APP-PLUS
|
||
// 获取系统信息
|
||
const systemInfo = uni.getSystemInfoSync()
|
||
// 计算安全区域底部高度
|
||
bottomHeight.value = systemInfo.screenHeight - systemInfo.safeArea.bottom + 'px'
|
||
// #endif
|
||
}
|
||
onHide(() => {
|
||
//#ifdef APP-PLUS
|
||
uni.offKeyboardHeightChange(setHeight)
|
||
// #endif
|
||
// 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(() => {})
|
||
})
|
||
onShow(() => {
|
||
//#ifdef APP-PLUS
|
||
uni.onKeyboardHeightChange(setHeight)
|
||
// #endif
|
||
if (watchFlag.value === 1) return
|
||
// getData('2');
|
||
initsocketTask()
|
||
})
|
||
const watchFlag = ref(1)
|
||
onUnload(() => {
|
||
changePlayItemId()
|
||
teacherVoiceObj?.stop?.()
|
||
teacherVoiceObj.src = ''
|
||
socketStore.closeSocket()
|
||
})
|
||
const testAnswer = computed(() => {
|
||
if (talkingList.value.length < 5) return true
|
||
let _arr = talkingList.value.slice(-5)
|
||
let _num = _arr.map(t => [1, 2, 6].indexOf(Number(t.type)) >= 0).filter(t => !!t)
|
||
return _num.length < 5
|
||
})
|
||
const uploadRecordNow = voicePath => {
|
||
if (!testAnswer.value) {
|
||
common.msg('每个问题最多连续发送五次答案!')
|
||
return
|
||
}
|
||
isUploadingVoice.value = true
|
||
let _data = {
|
||
stdyId: unref(stdyId),
|
||
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
|
||
asrStartTm: unref(lastTalkingInfo).asrStartTm
|
||
}
|
||
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
|
||
})
|
||
setIsUploadingVoice()
|
||
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()
|
||
let _path = isPreview.value ? '/trastudy/traStdychat/previewVoiceChart' : '/trastudy/traStdychat/voiceChart'
|
||
commonUploadVoiceFile(voicePath, _path, {
|
||
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: _data.pgrphId,
|
||
qstLogId: _data.qstLogId,
|
||
qnsId: _data.qnsId,
|
||
talkingContent: '',
|
||
talkingVoice: voicePath,
|
||
recordId: _res.body.chatBody.recordId,
|
||
asrStartTm: unref(lastTalkingInfo).asrStartTm,
|
||
stdyPgrphId: _res.body.chatBody.stdyPgrphId,
|
||
type: 1,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
id: _id
|
||
}
|
||
} else {
|
||
return t
|
||
}
|
||
})
|
||
console.log(11111, _res.body.chatBody)
|
||
scrollToBottomNow()
|
||
} else {
|
||
}
|
||
setIsUploadingVoice()
|
||
})
|
||
.catch(err => {
|
||
console.log('err', err)
|
||
setIsUploadingVoice()
|
||
talkingList.value = talkingList.value.filter(t => t.id !== _id)
|
||
uni.showToast({
|
||
title: err.message || '系统异常,请联系管理员',
|
||
icon: 'none',
|
||
duration: 1000
|
||
})
|
||
})
|
||
// #endif
|
||
}
|
||
const setIsUploadingVoice = (flag = false) => {
|
||
if (flag) {
|
||
isUploadingVoice.value = true
|
||
} else {
|
||
setTimeout(() => {
|
||
isUploadingVoice.value = false
|
||
}, 100)
|
||
}
|
||
}
|
||
// 发送文本
|
||
const submitAnswerNow = (val, cb) => {
|
||
if (!testAnswer.value) {
|
||
common.msg('每个问题最多连续发送五次答案!')
|
||
return
|
||
}
|
||
isUploadingVoice.value = true
|
||
let _data = {
|
||
stdyId: unref(stdyId),
|
||
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
|
||
asrStartTm: unref(lastTalkingInfo).asrStartTm
|
||
}
|
||
unref(ajaxApi)({
|
||
processType: 'ANSER-TEXT',
|
||
requestBody: JSON.stringify(_data)
|
||
})
|
||
.then(res => {
|
||
setIsUploadingVoice()
|
||
let _id = new Date().getTime() + 'id'
|
||
let _body = res.body || {}
|
||
if (!_body.chatBody) {
|
||
return
|
||
}
|
||
talkingList.value.push({
|
||
..._data,
|
||
chatContent: _body.chatContent,
|
||
recordId: _body.chatBody.recordId,
|
||
stdyPgrphId: _body.chatBody.stdyPgrphId,
|
||
talkingContent: val,
|
||
talkingVoice: '',
|
||
type: 2,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
qstLogId: qstLogId.value,
|
||
id: _id
|
||
})
|
||
scrollToBottomNow()
|
||
cb && cb()
|
||
})
|
||
.catch(() => {
|
||
setIsUploadingVoice()
|
||
})
|
||
}
|
||
// 撤回
|
||
const withdrawNow = data => {
|
||
unref(ajaxApi)({
|
||
processType: 'ANSER-WITHDRAW',
|
||
requestBody: JSON.stringify({
|
||
recordId: data.recordId
|
||
})
|
||
}).then(res => {
|
||
// 删除撤回的数据item
|
||
common.msg('撤回成功!')
|
||
talkingList.value = talkingList.value.filter(t => t.recordId !== data.recordId)
|
||
})
|
||
}
|
||
const loadingExecLogId = ref('')
|
||
const answerQuestionNow = data => {
|
||
let _data = {
|
||
stdyId: unref(stdyId),
|
||
qnsId: data.qnsId, // 问题ID 必输项:true 类型:String
|
||
pgrphId: data.pgrphId, // 段落ID 必输项:true 类型:String
|
||
crsId: crsId.value, // 课程ID 必输项:true 类型:String
|
||
stdyBatch: stdyBatch.value, // 学习批次 必输项:true 类型:String
|
||
ansterContent: data.answer.join(','), // 回答文本内容 必输项:false 类型:String
|
||
asrStartTm: data.asrStartTm
|
||
}
|
||
// 发出答案
|
||
let _answer = data.answerItems.map(t => t.itemNo).join(',')
|
||
let _id1 = new Date().getTime() + '3d'
|
||
talkingList.value.push({
|
||
id: _id1,
|
||
talkingContent: _answer,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
type: 0
|
||
})
|
||
scrollToBottomNow(0)
|
||
unref(ajaxApi)({
|
||
processType: 'ANSER-CHOICE',
|
||
requestBody: JSON.stringify(_data)
|
||
}).then(res => {
|
||
let _id = new Date().getTime() + 'id'
|
||
let _body = res.body
|
||
lastTalkingInfo.value = {
|
||
crsId: crsId.value,
|
||
stdyId: unref(stdyId),
|
||
stdyBatch: unref(stdyBatch),
|
||
logId: unref(logId),
|
||
pgrphId: data.pgrphId,
|
||
qnsId: data.qnsId,
|
||
chatContent: _body.chatContent || '',
|
||
...(_body.chatBody || {}),
|
||
type: Number(_body.bodyTyp || 8),
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
id: _id,
|
||
isQuestion: true,
|
||
my_answer: [],
|
||
backend_answer: []
|
||
}
|
||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
scrollToBottomNow()
|
||
})
|
||
}
|
||
// 完成
|
||
const finishQuestionNow = data => {
|
||
unref(ajaxApi)({
|
||
processType: 'ANSER-OVER',
|
||
requestBody: JSON.stringify({
|
||
qnsId: data.qnsId,
|
||
stdyPgrphId: data.stdyPgrphId,
|
||
asrStartTm: data.asrStartTm
|
||
})
|
||
})
|
||
.then(res => {
|
||
// common.msg('完成成功,开始获取评分维度数据!')
|
||
let _state = res.body.chatBody.isWait
|
||
if (_state !== 'Y') {
|
||
common.msg('提交答案失败!')
|
||
return
|
||
}
|
||
let _id1 = new Date().getTime() + '3d'
|
||
talkingList.value.push({
|
||
id: _id1,
|
||
talkingContent: '完成',
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
type: 0
|
||
})
|
||
loadingExecLogId.value = res.body.chatBody.execLogId
|
||
qstLogId.value = loadingExecLogId.value
|
||
let _id = new Date().getTime() + 'id'
|
||
lastTalkingInfo.value = {
|
||
isLoading: true,
|
||
id: _id,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
type: 5
|
||
}
|
||
talkingList.value.push(JSON.parse(JSON.stringify(lastTalkingInfo.value)))
|
||
scrollToBottomNow(0)
|
||
getQuestionEvalateRequest(_id, data, 1)
|
||
})
|
||
.catch(err => {
|
||
console.log(err)
|
||
})
|
||
}
|
||
// 查询问题回答评分
|
||
const getQuestionEvalateRequest = (id, data, num) => {
|
||
if (loadingExecLogId.value) {
|
||
unref(ajaxApi)({
|
||
processType: 'ANSER-RESULT',
|
||
requestBody: JSON.stringify({
|
||
execLogId: loadingExecLogId.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: loadingExecLogId.value,
|
||
id,
|
||
userInfo: {
|
||
...choiceTeacherInfo.value
|
||
},
|
||
evalDimens: (_body.chatBody.essayEvalVo || []).map(t => ({
|
||
...t,
|
||
gradeDimensName: t.gradeDimens
|
||
})),
|
||
type: 5
|
||
}
|
||
return lastTalkingInfo.value
|
||
} else {
|
||
return t
|
||
}
|
||
})
|
||
scrollToBottomNow()
|
||
} else {
|
||
// 1分钟之后取消获取报错
|
||
if (num === 30) {
|
||
common.msg('获取评分数据失败,请重新提交获取!')
|
||
talkingList.value.pop() //删除loading会话
|
||
talkingList.value.pop() //删除完成会话
|
||
return
|
||
}
|
||
setTimeout(() => {
|
||
getQuestionEvalateRequest(id, data, num + 1)
|
||
}, 2 * 1000)
|
||
}
|
||
})
|
||
}
|
||
}
|
||
|
||
const showSeekModel = ref(false)
|
||
const rateList = ref(['0.5', '0.8', '1.0', '1.5', '2.0'])
|
||
const chooseRate = ref('1.0')
|
||
const chooseRateNow = item => {
|
||
chooseRate.value = item
|
||
showSeekModel.value = false
|
||
teacherVoiceObj.playbackRate = Number(item)
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.course-study {
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
height: 100vh;
|
||
overflow: hidden;
|
||
bottom: 0;
|
||
|
||
.top-bg {
|
||
background: linear-gradient(16deg, rgba(234, 246, 255, 0) 0%, #e6eafd 100%);
|
||
height: 480rpx;
|
||
width: 750rpx;
|
||
}
|
||
|
||
.bot-bg {
|
||
// background-color: #F6F8FF;
|
||
background: linear-gradient(136deg, rgba(234, 246, 255, 0) 0%, #e6eafd 100%);
|
||
width: 750rpx;
|
||
flex: 1;
|
||
}
|
||
|
||
.seek-setting {
|
||
position: absolute;
|
||
z-index: 3;
|
||
right: 35rpx;
|
||
top: calc(v-bind(pageTopPadding) - 12rpx);
|
||
font-size: 26rpx;
|
||
width: 140rpx;
|
||
height: 92rpx;
|
||
padding: 30rpx 0;
|
||
overflow: hidden;
|
||
line-height: 32rpx;
|
||
text-align: right;
|
||
padding-right: 68rpx;
|
||
|
||
.image-icon {
|
||
width: 30rpx;
|
||
height: 32rpx;
|
||
position: absolute;
|
||
right: 10rpx;
|
||
top: 30rpx;
|
||
|
||
.image-icon-img {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
}
|
||
|
||
.course-study-body {
|
||
position: fixed;
|
||
overflow: hidden;
|
||
left: 0;
|
||
bottom: 0;
|
||
height: 100%;
|
||
// height: calc(100% - v-bind(totalBotHeight));
|
||
width: 100%;
|
||
padding: 0 0rpx;
|
||
box-sizing: border-box;
|
||
display: flex;
|
||
flex-direction: column;
|
||
padding-top: v-bind(pageTopPadding);
|
||
&.isAnd {
|
||
height: calc(100% - v-bind(totalBotHeight));
|
||
}
|
||
.body-title {
|
||
height: 90rpx;
|
||
text-align: center;
|
||
font-size: 33rpx;
|
||
padding-top: 10rpx;
|
||
line-height: 46rpx;
|
||
box-sizing: border-box;
|
||
font-weight: 500;
|
||
color: #000;
|
||
position: sticky;
|
||
top: 0;
|
||
|
||
// margin-bottom: 23rpx;
|
||
.arrow-icon {
|
||
position: absolute;
|
||
left: 21rpx;
|
||
top: 5rpx;
|
||
color: #000;
|
||
padding: 15rpx;
|
||
// background-color: red;
|
||
}
|
||
}
|
||
|
||
.study-num {
|
||
height: 36rpx;
|
||
line-height: 36rpx;
|
||
text-align: center;
|
||
padding-top: 20rpx;
|
||
padding-bottom: 10rpx;
|
||
box-sizing: content-box;
|
||
background: url(@/static/images/course/study-bg.png) no-repeat;
|
||
border-radius: 30rpx 30rpx 0 0;
|
||
|
||
.color-blue {
|
||
color: #06f;
|
||
display: inline;
|
||
}
|
||
}
|
||
|
||
.talking-list {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 10rpx 30rpx;
|
||
background: url(@/static/images/course/study-bg.png) no-repeat;
|
||
background-size: cover;
|
||
background-position: center bottom;
|
||
box-sizing: border-box;
|
||
width: 100%;
|
||
|
||
.talking-list-cont {
|
||
padding: 0;
|
||
}
|
||
|
||
.talking-item {
|
||
margin-bottom: 46rpx;
|
||
}
|
||
}
|
||
|
||
.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, 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;
|
||
|
||
::v-deep .uv-input__content {
|
||
padding-right: 50rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
}
|
||
|
||
.voice-list {
|
||
flex: 1;
|
||
overflow-y: auto;
|
||
padding: 10rpx 40rpx;
|
||
|
||
.voice-item {
|
||
min-height: 246rpx;
|
||
width: 100%;
|
||
overflow: hidden;
|
||
background-color: #fff;
|
||
border-radius: 16rpx;
|
||
display: flex;
|
||
padding: 25rpx;
|
||
position: relative;
|
||
|
||
&:not(:last-child) {
|
||
margin-bottom: 30rpx;
|
||
}
|
||
|
||
.avatar-box {
|
||
width: 160rpx;
|
||
height: 207rpx;
|
||
margin-right: 20rpx;
|
||
border-radius: 16rpx;
|
||
overflow: hidden;
|
||
background-color: #ccc;
|
||
|
||
.img-box {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.right-cont {
|
||
flex: 1;
|
||
|
||
.right-name {
|
||
width: 380rpx;
|
||
line-height: 40rpx;
|
||
font-size: 28rpx;
|
||
font-weight: 500;
|
||
margin-bottom: 25rpx;
|
||
word-break: break-all;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.right-desc {
|
||
width: 380rpx;
|
||
line-height: 38rpx;
|
||
font-size: 25rpx;
|
||
color: #999;
|
||
margin-bottom: 12rpx;
|
||
word-break: break-all;
|
||
white-space: nowrap;
|
||
text-overflow: ellipsis;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.audio-box {
|
||
width: 90%;
|
||
height: 70rpx;
|
||
line-height: 70rpx;
|
||
background-color: #eaf2ff;
|
||
padding: 15rpx 25rpx;
|
||
overflow: hidden;
|
||
|
||
.talking-gif {
|
||
width: 140rpx;
|
||
height: 40rpx;
|
||
margin-right: 20rpx;
|
||
// background-color: #ccc;
|
||
background: url(@/static/images/course/voice-gray.png) no-repeat;
|
||
background-size: 100%;
|
||
box-sizing: border-box;
|
||
float: left;
|
||
|
||
&.is-play {
|
||
background: url(@/static/images/course/voice-gif.gif) no-repeat;
|
||
background-size: 100%;
|
||
}
|
||
}
|
||
|
||
.talking-time {
|
||
float: right;
|
||
text-align: right;
|
||
line-height: 40rpx;
|
||
font-size: 23rpx;
|
||
color: #b1bbd3;
|
||
}
|
||
|
||
.play-btn {
|
||
float: right;
|
||
width: 35rpx;
|
||
height: 40rpx;
|
||
padding-top: 2rpx;
|
||
line-height: 35rpx;
|
||
margin-left: 20rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.radio-box {
|
||
position: absolute;
|
||
right: 20rpx;
|
||
top: 20rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.start-btns {
|
||
margin: 20rpx 30rpx 30rpx;
|
||
height: 80rpx;
|
||
width: calc(100% - 60rpx);
|
||
background-color: #06f;
|
||
color: #fff;
|
||
text-align: center;
|
||
line-height: 80rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.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;
|
||
|
||
&.white-bg-box-setting {
|
||
height: auto;
|
||
min-height: 400rpx;
|
||
}
|
||
|
||
.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;
|
||
}
|
||
}
|
||
|
||
.box-items {
|
||
.box-item {
|
||
margin-bottom: 20rpx;
|
||
overflow: hidden;
|
||
|
||
.box-item-title {
|
||
width: 81rpx;
|
||
height: 100%;
|
||
float: left;
|
||
overflow: hidden;
|
||
color: #666;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.box-item-cont {
|
||
display: block;
|
||
float: left;
|
||
width: calc(100% - 86rpx);
|
||
overflow: hidden;
|
||
padding-left: 5rpx;
|
||
padding-top: 5rpx;
|
||
|
||
.overlay-voice-item {
|
||
width: 123rpx;
|
||
float: left;
|
||
position: relative;
|
||
margin-bottom: 30rpx;
|
||
|
||
&:not(:nth-child(3n)) {
|
||
margin-right: 100rpx;
|
||
}
|
||
|
||
.overlay-avatar-box {
|
||
width: 123rpx;
|
||
height: 123rpx;
|
||
border-radius: 50%;
|
||
overflow: hidden;
|
||
box-shadow: 1rpx 0rpx 5rpx #ccc;
|
||
|
||
.overlay-img-box {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.overlay-teacher-name {
|
||
width: 123rpx;
|
||
text-align: center;
|
||
height: 58rpx;
|
||
line-height: 58rpx;
|
||
font-size: 28rpx;
|
||
}
|
||
|
||
.overlay-radio-box {
|
||
position: absolute;
|
||
left: 100rpx;
|
||
top: 5rpx;
|
||
pointer-events: none;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
</style>
|