diff --git a/.env.development b/.env.development index 4750d846..a61765ea 100644 --- a/.env.development +++ b/.env.development @@ -2,10 +2,6 @@ ENV = 'development' # 'development' -VITE_APP_ENV = 'AND' - -# base api - # 苗扬 # VITE_APP_BASE_API_Url = 'http://25.64.16.133:9786' @@ -16,6 +12,7 @@ VITE_APP_ENV = 'AND' VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001' + # app入口 #VITE_APP_BASE_API_Url = 'http://25.16.122.65:7001' #VITE_APP_BASE_API_Url = 'http://25.16.122.91:9786' diff --git a/.env.production b/.env.production index c5649d8c..22641718 100644 --- a/.env.production +++ b/.env.production @@ -1,8 +1,5 @@ # 生产环境 ENV = 'production' -VITE_APP_ENV = 'AND' - # base api - VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001' diff --git a/.env.sit b/.env.sit index 4b66d147..9623af29 100644 --- a/.env.sit +++ b/.env.sit @@ -1,8 +1,6 @@ # SIT环境 ENV = 'sit' -VITE_APP_ENV = 'AND' # base api - VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002' diff --git a/.env.sit-ios b/.env.sit-ios deleted file mode 100644 index 2bd04f76..00000000 --- a/.env.sit-ios +++ /dev/null @@ -1,8 +0,0 @@ -# SIT环境 -ENV = 'sit' - -VITE_APP_ENV = 'IOS' - -# base api - -VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7002' diff --git a/.env.uat b/.env.uat index b953bca8..c0c4b2ff 100644 --- a/.env.uat +++ b/.env.uat @@ -1,8 +1,5 @@ # UAT环境 ENV = 'uat' -VITE_APP_ENV = 'AND' - # base api - VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7003' diff --git a/.env.uat-ios b/.env.uat-ios deleted file mode 100644 index cbf3ee5a..00000000 --- a/.env.uat-ios +++ /dev/null @@ -1,8 +0,0 @@ -# UAT环境 -ENV = 'uat' - -VITE_APP_ENV = 'IOS' - -# base api - -VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7003' diff --git a/README.en.md b/README.en.md index 85462a72..53639d47 100644 --- a/README.en.md +++ b/README.en.md @@ -2,4 +2,5 @@ npm install --registry=http://25.12.10.69:8081/repository/aliyun-npm/ npm 淘宝源下载 :npm config set registry https://registry.npmmirror.com -npm config set registry http://25.12.10.69:8081/repository/aliyun-npm/ \ No newline at end of file +npm config set registry http://25.12.10.69:8081/repository/aliyun-npm/ + diff --git a/src/api/common.js b/src/api/common.js index baf0375f..61154a68 100644 --- a/src/api/common.js +++ b/src/api/common.js @@ -144,7 +144,7 @@ export function downloadVoiceFile(url) { let baseUrl = get_base_url(); return new Promise((resolve, reject) => { uni.downloadFile({ - url: `${baseUrl}${url}`, + url: `${baseUrl}${url}`, header, success(result) { console.log(result) diff --git a/src/api/socket.js b/src/api/socket.js index 51737370..454df64a 100644 --- a/src/api/socket.js +++ b/src/api/socket.js @@ -63,7 +63,7 @@ export default class WebSocketUtil { this.socketTask.onMessage((res) => { if(res.data){ const { rtnCode } = JSON.parse(res.data) - console.log('收到WebSocket消息', JSON.parse(res.data) ); + // console.log('收到WebSocket消息', JSON.parse(res.data) ); if(['0005', 'QQ0005'].includes(rtnCode)) { clearInterval(this.reconnectTimer); this.reconnectTimer = null diff --git a/src/api/study.js b/src/api/study.js index df818e4e..ef123a57 100644 --- a/src/api/study.js +++ b/src/api/study.js @@ -156,4 +156,14 @@ export const textChartApi = (data) => { toastErrors: true, data }); +}; + +// 设置学习顾问音色/traStdyTeacher/setStudyTeacher +export const setStudyTeacherApi = (data) => { + return request({ + url: base_url + '/traStdyTeacher/setStudyTeacher', + method: 'post', + toastErrors: true, + data + }); }; \ No newline at end of file diff --git a/src/common/common.js b/src/common/common.js index 582e668e..0ac01c68 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -1,6 +1,4 @@ -const _ENV = import.meta.env - function msg(title, duration = 1000) { uni.showToast({ title: title, @@ -116,7 +114,25 @@ export const getUserInfo = (key = '') => { const userInfo = uni.getStorageSync('userInfo') return '' === key ? userInfo : userInfo[key]; } -export const getPhoneEnvBool = (flag) => _ENV.VITE_APP_ENV === flag +/** + * 判断当前运行平台是否匹配指定标识 + * @param {string} flag - 平台标识:'IOS' 表示苹果iOS平台,'AND' 表示安卓平台 + * @returns {boolean} 如果当前平台匹配指定标识返回true,否则返回false + */ +export const getPhoneEnvBool = (flag) => { + // 获取当前设备的平台信息 + + const { platform } = uni.getSystemInfoSync(); + + // 平台与标识的映射关系 + const platformMap = { + ios: 'IOS', + android: 'AND', + }; + + // 根据当前平台返回匹配结果 + return platformMap[platform] === flag; +}; // 将对象和字符串相互转换 diff --git a/src/common/dialogMessage.js b/src/common/dialogMessage.js new file mode 100644 index 00000000..522b4708 --- /dev/null +++ b/src/common/dialogMessage.js @@ -0,0 +1,223 @@ +export default function showDialog(options) { + const view = new plus.nativeObj.View('customModal', { + top: '0', + left: '0', + height: '100%', + width: '100%', + backgroundColor: 'rgba(0,0,0,0.5)', + position: 'fixed' + }); + + const screenWidth = plus.screen.resolutionWidth; + const screenHeight = plus.screen.resolutionHeight; + const borderRadius = 10; + const contentPadding = 20; // 内容左右内边距 + const lineHeight = 24; // 单行文本行高 + const maxLines = 2; // 最大行数 + const fontSize = 16; // 字体大小 + + // 判断内容和标题是否存在 + const hasContent = options.content && options.content.trim() !== ''; + const hasTitle = options.title && options.title.trim() !== ''; + + // 弹窗宽度计算 + const modalWidth = Math.min(0.8 * screenWidth, 500); + const modalLeft = (screenWidth - modalWidth) / 2; + + // 内容区域可用宽度 + const contentAvailableWidth = modalWidth - 2 * contentPadding - 10; + + // 动态计算各部分高度 + const titleHeight = hasTitle ? 30 : 0; + const titleToContentSpacing = (hasTitle && hasContent) ? 10 : 0; + const contentHeight = hasContent ? (lineHeight * maxLines) : 0; + const contentToBtnSpacing = 10; + const btnHeight = 50; + + // 弹窗总高度 + let modalHeight = contentPadding + titleHeight + titleToContentSpacing + contentHeight + contentToBtnSpacing + btnHeight; + modalHeight = options.showCancel ? Math.min(modalHeight, 300) : Math.min(modalHeight, 250); + + // 位置计算 + const modalTop = (screenHeight - modalHeight) / 2; + const contentAreaTop = modalTop + contentPadding; + const titleTop = hasTitle ? contentAreaTop : 0; + + // Fix: Calculate contentTop properly when there's no content + let contentTop; + if (hasContent) { + contentTop = hasTitle ? (titleTop + titleHeight + titleToContentSpacing) : contentAreaTop; + } else { + contentTop = hasTitle ? (titleTop + titleHeight) : contentAreaTop; + } + + const btnTop = hasContent + ? (contentTop + contentHeight + contentToBtnSpacing) + : (hasTitle + ? (titleTop + titleHeight + contentToBtnSpacing) + : (contentAreaTop + (modalHeight - btnHeight - contentPadding))); // 既无标题也无内容时 + + // 绘制弹窗背景 + view.draw([{ + tag: 'rect', + id: 'bg', + position: { top: modalTop + 'px', left: modalLeft + 'px', width: modalWidth + 'px', height: modalHeight + 'px' }, + rectStyles: { color: '#fff', radius: borderRadius + 'px' } + }]); + + // 绘制标题和内容 + const elements = []; + + // 标题(仅当存在时) + if (hasTitle) { + elements.push({ + tag: 'font', + id: 'title', + text: options.title, + position: { top: titleTop + 'px', left: modalLeft + 'px', width: modalWidth + 'px', height: titleHeight + 'px' }, + textStyles: { + color: '#000', + size: '20px', + align: 'center', + fontWeight: 'bold', + verticalAlign: 'middle' + } + }); + } + if (hasContent) { + const text = options.content; + const maxLines = 2; // 最大显示行数 + const lineHeightPx = lineHeight; + const leftPos = modalLeft + contentPadding; + const textWidth = contentAvailableWidth; + const fontSizePx = fontSize; + + // 按 \n 分割段落 + const paragraphs = text.split('\n'); + let lines = []; + + // 遍历每个段落,计算换行 + for (let para of paragraphs) { + if (lines.length >= maxLines) break; + + // 估算每行能容纳的字符数(中文按 1.2 倍宽度计算) + const avgCharWidth = fontSizePx * (isChinese(para) ? 1.2 : 0.6); + const maxCharsPerLine = Math.floor(textWidth / avgCharWidth); + + let currentLine = ''; + for (let i = 0; i < para.length; i++) { + const char = para[i]; + currentLine += char; + + // 如果当前行字符数超过限制,换行 + if (currentLine.length >= maxCharsPerLine) { + lines.push(currentLine); + currentLine = ''; + + if (lines.length >= maxLines) break; + } + } + + // 添加剩余部分 + if (currentLine && lines.length < maxLines) { + lines.push(currentLine); + } + } + + // 如果超出最大行数,最后一行加 "..." + if (lines.length > maxLines) { + lines = lines.slice(0, maxLines); + const lastLine = lines[maxLines - 1]; + lines[maxLines - 1] = lastLine.substring(0, lastLine.length - 3) + '...'; + } + + // 绘制每一行文本(确保行高正确) + lines.forEach((line, index) => { + const topPos = contentTop + index * lineHeightPx; + + elements.push({ + tag: 'font', + id: 'content_line_' + index, + text: line, + position: { + top: topPos + 'px', + left: leftPos + 'px', + width: textWidth + 'px', + height: lineHeightPx + 'px' + }, + textStyles: { + color: '#666', + size: fontSizePx + 'px', + align: 'center', + verticalAlign: 'top', + lineHeight: lineHeightPx + 'px' + } + }); + }); + } + + // 判断是否主要是中文 + function isChinese(text) { + return /[\u4e00-\u9fa5]/.test(text); + } + + // 分割线 + elements.push({ + tag: 'rect', + id: 'divider', + position: { top: btnTop + 'px', left: modalLeft + 'px', width: modalWidth + 'px', height: '1px' }, + rectStyles: { color: '#b3b3b3' } + }); + + view.draw(elements); + + // 绘制按钮(不变) + if (options.showCancel) { + const btnWidth = Math.floor((modalWidth - 2 * borderRadius) / 2); + view.draw([ + { tag: 'rect', id: 'cancelBtn', position: { top: (btnTop + 2) + 'px', left: (modalLeft + borderRadius) + 'px', width: btnWidth + 'px', height: (btnHeight - 3) + 'px' }, rectStyles: { color: '#fff' } }, + { tag: 'font', id: 'cancelText', text: options.cancelText || '取消', position: { top: btnTop + 'px', left: (modalLeft + borderRadius) + 'px', width: btnWidth + 'px', height: btnHeight + 'px' }, textStyles: { color: '#007AFF', size: '16px', align: 'center', verticalAlign: 'middle' } }, + { tag: 'rect', id: 'btnDivider', position: { top: btnTop + 'px', left: (modalLeft + borderRadius + btnWidth) + 'px', width: '1px', height: btnHeight + 'px' }, rectStyles: { color: '#b3b3b3' } }, + { tag: 'rect', id: 'confirmBtn', position: { top: (btnTop + 2) + 'px', left: (modalLeft + borderRadius + btnWidth + 1) + 'px', width: btnWidth + 'px', height: (btnHeight - 3) + 'px' }, rectStyles: { color: '#fff' } }, + { tag: 'font', id: 'confirmText', text: options.confirmText || '确定', position: { top: btnTop + 'px', left: (modalLeft + borderRadius + btnWidth + 1) + 'px', width: btnWidth + 'px', height: btnHeight + 'px' }, textStyles: { color: '#007AFF', size: '16px', align: 'center', verticalAlign: 'middle' } } + ]); + } else { + view.draw([ + { tag: 'rect', id: 'confirmBtn', position: { top: (btnTop + 2) + 'px', left: (modalLeft + borderRadius) + 'px', width: (modalWidth - 2 * borderRadius) + 'px', height: (btnHeight - 3) + 'px' }, rectStyles: { color: '#fff' } }, + { tag: 'font', id: 'confirmText', text: options.confirmText || '确定', position: { top: btnTop + 'px', left: (modalLeft + borderRadius) + 'px', width: (modalWidth - 2 * borderRadius) + 'px', height: btnHeight + 'px' }, textStyles: { color: '#007AFF', size: '16px', align: 'center', verticalAlign: 'middle' } } + ]); + } + + // 点击事件(不变) + view.addEventListener("click", function(e) { + const x = e.clientX; + const y = e.clientY; + if (options.showCancel) { + const btnWidth = Math.floor((modalWidth - 2 * borderRadius) / 2); + const cancelBtnLeft = modalLeft + borderRadius; + if (y > btnTop && y < btnTop + btnHeight) { + if (x >= cancelBtnLeft && x < cancelBtnLeft + btnWidth) { + options.cancel?.(); + view.close(); + } else if (x >= cancelBtnLeft + btnWidth + 1 && x < cancelBtnLeft + 2 * btnWidth + 1) { + options.success?.({ confirm: true }); + view.close(); + } + } + } else { + const btnLeft = modalLeft + borderRadius; + if (y > btnTop && y < btnTop + btnHeight && x >= btnLeft && x < btnLeft + (modalWidth - 2 * borderRadius)) { + options.success?.({ confirm: true }); + view.close(); + } + } + }, false); + + view.show(); + + return { + close: () => { + view.close(); + } + }; +} \ No newline at end of file diff --git a/src/components/image-preview/image-preview.vue b/src/components/image-preview/image-preview.vue index 8e766627..f368c93f 100644 --- a/src/components/image-preview/image-preview.vue +++ b/src/components/image-preview/image-preview.vue @@ -40,7 +40,7 @@ }, mode:{ type: String, - default: 'widthFix' + default: 'aspectFit' }, previewDetail: { default: '', diff --git a/src/pages/course/components/talkingItem.vue b/src/pages/course/components/talkingItem.vue index 43b5ec4e..b2d61564 100644 --- a/src/pages/course/components/talkingItem.vue +++ b/src/pages/course/components/talkingItem.vue @@ -3,11 +3,11 @@ - + - {{ dataInfo?.userInfo?.teacherName }} - {{dataInfo?.userInfo?.teacherDesc}} + {{ teacherInfo?.teacherName }} + {{teacherInfo?.teacherDesc}} @@ -88,11 +88,11 @@ @@ -205,6 +205,10 @@ const audioCacheObj = computed(() => storageStore.audioObj) default: () => ({}), type: Object }, + teacherInfo: { + default: () => ({}), + type: Object + }, activeVoiceId:{ default:'', type: String @@ -239,12 +243,13 @@ const audioCacheObj = computed(() => storageStore.audioObj) } }) - const { type, dataInfo, activeVoiceId, isPlaying, isLast, lastQuestionInfo} = toRefs(props) + const { type, dataInfo, activeVoiceId, isPlaying, isLast, lastQuestionInfo, teacherInfo} = 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 itemVoice = ref('') const showWithdraw = computed(()=>{ let _isMe = unref(lastQuestionInfo).qnsLogId === unref(dataInfo).qnsLogId @@ -253,6 +258,13 @@ const audioCacheObj = computed(() => storageStore.audioObj) }) const voiceLoading = ref(false) + watch(() => props.teacherInfo,(val) => { + itemVoice.value = '' + talkVoiceObj.value.src = '' + },{ + deep: true, + immediate: true + }) watch(() => props.isPlaying,(val) => { if(!val){ talkVoiceObj.value?.pause() @@ -311,7 +323,6 @@ const audioCacheObj = computed(() => storageStore.audioObj) talkVoiceObj.value.src = '' }) talkVoiceObj.value.onError(()=>{ - emit('changePlay', '') talkVoiceObj.value.src = '' }) const pauseVoice = () => { @@ -333,19 +344,20 @@ const audioCacheObj = computed(() => storageStore.audioObj) playVoice() } } - const itemVoice = ref('') const playVoice = (readType = 'pgth') =>{ let _content = showContent.value if(!_content){ common.msg('没有可以播放的文字信息!') return } + emit('changePlay', unref(dataInfo)?.id) // readType 阅读内容类型pgrh段落/qns问题 - emit('changePlay', unref(dataInfo)?.id) if(talkVoiceObj.value.src && talkVoiceObj.value.src === itemVoice.value) { + emit('changePlay', unref(dataInfo)?.id) talkVoiceObj.value.play() return } + talkVoiceObj.value.src = '' if(itemVoice.value){ setTimeout(()=>{ talkVoiceObj.value.src = itemVoice.value @@ -358,14 +370,14 @@ const audioCacheObj = computed(() => storageStore.audioObj) pgrphId: unref(dataInfo)?.pgrphId || '', qnsId: unref(dataInfo)?.qnsId || '', readType: readType, - teachNo: unref(dataInfo)?.userInfo?.teacherNo, // 必填 + teachNo: unref(teacherInfo)?.teacherNo, // 必填 content: _content } let _url = '/trastudy/traStdyInfo/readContent?' + Object.keys(_params).map(t=>{ return encodeURIComponent(t) + '=' + encodeURIComponent(_params[t]) }).join('&') - storageStore.getStorageById('audio', _url, (url)=>{ + storageStore.getStorageById('audio', _url + _params.teachNo, (url)=>{ if(url){ voiceLoading.value = false itemVoice.value = url @@ -381,7 +393,7 @@ const audioCacheObj = computed(() => storageStore.audioObj) itemVoice.value = res.tempFilePath talkVoiceObj.value.src = res.tempFilePath talkVoiceObj.value.play() - storageStore.setStorage('audio', _url, itemVoice.value) + storageStore.setStorage('audio', _url + _params.teachNo, itemVoice.value) }).catch((err)=>{ voiceLoading.value = false }) diff --git a/src/pages/course/components/touchBtn.vue b/src/pages/course/components/touchBtn.vue index 2aa9db6b..9818ec00 100644 --- a/src/pages/course/components/touchBtn.vue +++ b/src/pages/course/components/touchBtn.vue @@ -13,7 +13,7 @@ placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入答案"> - + @@ -46,19 +46,30 @@ const proxy = getCurrentInstance() const emit = defineEmits(['uploadVoice', 'submitAnswer','startRecord']) const props = defineProps({ isDisabled:{ - default: Boolean, - type: true + default: true, + type: Boolean }, isLoading:{ + default: false, + type: Boolean + }, + loadingText:{ + default: '发送回答中,请稍后再试!', + type: String + }, + onlyVoice:{ default: false, type: Boolean - } + }, }) -const { isDisabled } = toRefs(props) +const { isDisabled, onlyVoice } = toRefs(props) const isLoadingState = computed(() => props.isLoading) watch(()=>props.isLoading,()=>{},{ deep:true,immediate:true }) +watch(()=>props.onlyVoice,()=>{},{ + deep:true,immediate:true +}) const showTalkingModel = ref(false) const keyboardIsShow = ref(false) const answerValue = ref('') @@ -161,7 +172,7 @@ const getRecordPermission = async (obj) => { const showOverlayTalking = (obj) => { if(isLoadingState.value){ uni.showToast({ - title: '发送回答中,请稍后再试!', + title: props.loadingText, icon: "none", duration:1000 }) @@ -181,6 +192,7 @@ const showOverlayTalking = (obj) => { hideOverlayTalking() },59 * 1010) }else{ + showTalkingModel.value = false uni.showToast({ title: '暂无问题需要回答!', icon: "none", @@ -216,6 +228,14 @@ const handleMove = (obj) => { } // 发送文本 const showKeyboard = () => { + if(isLoadingState.value){ + uni.showToast({ + title: props.loadingText, + icon: "none", + duration:1000 + }) + return + } if(!isDisabled.value){ if(keyboardIsShow.value){ if(answerValue.value){ @@ -235,7 +255,7 @@ const showKeyboard = () => { } }else{ uni.showToast({ - title: '请先获取问题信息!', + title: '暂无问题需要回答!', icon: "none", duration:1000 }) diff --git a/src/pages/course/study.vue b/src/pages/course/study.vue index c9c8a447..7ae7e1d7 100644 --- a/src/pages/course/study.vue +++ b/src/pages/course/study.vue @@ -5,7 +5,7 @@ {{chooseRate}}倍 - + @@ -67,6 +67,7 @@ :isPlaying="activeVoiceTalkingItemId === item.id" :voiceRate="chooseRate" :lastQuestionInfo="lastTalkingInfo" + :teacherInfo="choiceTeacherInfo" @changePlay="changePlayItemId" @nextQuestion="nextQuestionSuccess" @withdraw="withdrawNow" @@ -83,6 +84,7 @@ @submitAnswer="submitAnswerNow" @startRecord="changePlayItemId('')" :isLoading="isUploadingVoice" + :onlyVoice="answerOnlyVoice" :isDisabled="((lastTalkingInfo.type||0) !== 4)" /> @@ -103,15 +105,22 @@ - + 设置 - - {{item}} + + + 音色 + + + + + + {{item.teacherName}} + + + + @@ -135,7 +144,8 @@ import { getCourseStudyInfoApi, afreshStudyCourseApi, queryQuestionEvalateApi, - textChartApi + textChartApi, + setStudyTeacherApi } from "@/api/study.js" import common from '@/common/common'; import TalkingItem from '@/pages/course/components/talkingItem.vue' @@ -172,8 +182,8 @@ const getData = async (flag) => { // return // } try{ + await initsocketTask() const { body } = await getCourseStudyInfoApi({crsId: crsId.value}) - initsocketTask() teacherList.value = body.teacheList.map(t=>({ ...t, voicePath: '', @@ -183,7 +193,6 @@ const getData = async (flag) => { step.value = 1 }else{ if(startPgrphId.value){ - scrollToBottomNow() choiceTeacher.value = body.choiceTeacher sendMessage({ "commond" : 'STDY', @@ -244,20 +253,38 @@ const showChangeSeekModelNow = () => { } const showBgModel = ref(false) const showChangeBgModelNow = () => { + changePlayItemId() showBgModel.value = true } // 关闭播放状态 const changePlayItemId = (id = '') => { - if(activeVoiceTalkingItemId.value === id){ - activeVoiceTalkingItemId.value = '' - }else{ - activeVoiceTalkingItemId.value = 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 + }) + console.log(res) + if(res.rtnCode === '0000'){ + choiceTeacher.value = item.teacherNo + showBgModel.value = false + } + }catch{} finally{} +} + // 选择教师语音对象 const activeVoiceTeachNo = ref('') let teacherVoiceObj = uni.createInnerAudioContext() @@ -322,6 +349,11 @@ const isLastPgrph = ref(false) const backRouter = ()=>{ common.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`) } + +const answerOnlyVoice = computed(()=>{ + return lastTalkingInfo.value.answerWay === 'V' +}) + // 获取段落 const getGraphInfoUnStudy = (flag = 0) => { console.log(isLastPgrph.value) @@ -342,6 +374,7 @@ const getGraphInfoUnStudy = (flag = 0) => { if(!_body.chatBody) { return } + console.log('prgh', _body) if(Number(_body.bodyTyp) === 7){ common.show('恭喜你已学完全部知识点', '有什么心得跟我们分享吗?',true, '取消','去评论').then((res) => { if(res) { @@ -392,6 +425,18 @@ const getQuestionInfoUnStudy = (pgrphId) => { let _id = new Date().getTime() + 'id' let _body = res.body || {} console.log(_body) + if(Number(_body.bodyTyp) === 7){ + 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.redirectTo(`/pages/courseDetail/index?crsId=${crsId.value}&crsNum=${crsNum.value}&from=study`) + } + }).finally(() => {}) + return + } if(_body.chatBody && _body.chatBody?.stdyStat !== 'N'){ let _id = new Date().getTime() + 'id' lastTalkingInfo.value = { @@ -452,7 +497,7 @@ const nextQuestionSuccess = (info, type='next') => { talkingList.value.push({ crsId: info.crsId, pgrphId: info.pgrphId, - talkingContent: '重新学', + talkingContent: '重新答', type: 0, id: _id }) @@ -542,8 +587,8 @@ const stdyId = ref('') const stdyBatch = ref('') const logId = ref('') // ws 初始化逻辑 -const initsocketTask = () => { - socketStore.creatSocket() +const initsocketTask = async () => { + await socketStore.creatSocket() unref(SocketObj).on('message', (res)=>{ const { rtnCode, body, commond } = JSON.parse(res.data) if(rtnCode === '0000'){ @@ -554,9 +599,9 @@ const initsocketTask = () => { getGraphInfoUnStudy(1) } }else{ - if(['0005', 'QQ0005'].includes(res.rtnCode)) { - goto_login_fun(); - } + // if(['0005', 'QQ0005'].includes(res.rtnCode)) { + // goto_login_fun(); + // } } }) } @@ -790,11 +835,11 @@ const finishQuestionNow = (data) => { } talkingList.value.push(lastTalkingInfo.value) scrollToBottomNow(0) - getQuestionEvalateRequest(_id,data) + getQuestionEvalateRequest(_id, data, 1) }) } // 查询问题回答评分 -const getQuestionEvalateRequest = (id, data) => { +const getQuestionEvalateRequest = (id, data, num) => { if(loadingQstLogId.value){ textChartApi({ processType: 'ANSER-RESULT', @@ -825,8 +870,15 @@ const getQuestionEvalateRequest = (id, data) => { }) scrollToBottomNow() }else{ + // 1分钟之后取消获取报错 + if(num === 30){ + common.msg('获取评分数据失败,请重新提交获取!') + talkingList.value.pop()//删除loading会话 + talkingList.value.pop()//删除完成会话 + return + } setTimeout(()=>{ - getQuestionEvalateRequest(id, data) + getQuestionEvalateRequest(id, data, num+1) }, 2 * 1000) } }) @@ -1162,6 +1214,10 @@ const chooseRateNow = (item) => { 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; @@ -1178,6 +1234,55 @@ const chooseRateNow = (item) => { color: #06f; } } + .box-items{ + .box-item{ + margin-bottom: 20rpx; + overflow: hidden; + .box-item-title{ + width: 86rpx; + height: 100%; + float: left; + overflow: hidden; + color: #666; + font-size: 28rpx; + } + .box-item-cont{ + display: block; + float: left; + width: calc(100% - 86rpx); + overflow: hidden; + .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-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; + } + } + } + } + } } } diff --git a/src/pages/index/components/answer.vue b/src/pages/index/components/answer.vue index 954c4b33..218f7494 100644 --- a/src/pages/index/components/answer.vue +++ b/src/pages/index/components/answer.vue @@ -1,55 +1,66 @@ \ No newline at end of file diff --git a/src/pages/index/components/question.vue b/src/pages/index/components/question.vue index d26b6d27..d8cb585e 100644 --- a/src/pages/index/components/question.vue +++ b/src/pages/index/components/question.vue @@ -1,5 +1,5 @@ @@ -54,6 +69,8 @@ padding-bottom: 30rpx; position: relative; color: #fff; + width: 100%; + float: right; .talking-gif{ width: 200rpx; height: 38rpx; @@ -73,6 +90,15 @@ height: 38rpx; line-height: 38rpx; } + &.talking-info-text{ + padding-bottom: 20rpx; + width: auto; + float: right; + .talking-cont{ + margin-top: 0rpx; + } + + } .talking-cont{ margin-top: 16rpx; overflow: hidden; diff --git a/src/pages/index/components/talking-item.vue b/src/pages/index/components/talking-item.vue index 690aa092..fcff5288 100644 --- a/src/pages/index/components/talking-item.vue +++ b/src/pages/index/components/talking-item.vue @@ -1,26 +1,41 @@