一些操作
This commit is contained in:
+4
-1
@@ -17,4 +17,7 @@ VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
|
||||
# 王洋洋
|
||||
#VITE_APP_BASE_H5_API_Url = 'http://25.64.16.140:9604'
|
||||
VITE_APP_BASE_H5_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
VITE_APP_BASE_H5_API_Url = 'https://aitstest.jlbank.com.cn:7001'
|
||||
#岳世凯
|
||||
#VITE_APP_BASE_H5_API_Url = 'http://25.64.16.141:9701'
|
||||
|
||||
|
||||
@@ -31,3 +31,19 @@ export const deleteTraPersonalCollectionById = (data) => {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
||||
/*
|
||||
新增任务收藏
|
||||
入参:
|
||||
collectTyp 收藏类型 必须 String 01--课程,02--任务
|
||||
collectBusId 收藏业务ID 必须 String
|
||||
**/
|
||||
export const insertTraPersonalCollectionTask = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPersonalCollection/insertTraPersonalCollectionTask',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
import request from '@/api/request'
|
||||
const base_url = '/trastudy'
|
||||
|
||||
// 查询所有、未完成、已完成的任务(分页)
|
||||
export const queryAllTraTaskInfoByUserId = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traTaskInfo/queryAllTraTaskInfoByUserId',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
import request from '@/api/request'
|
||||
const base_url = '/trastudy'
|
||||
|
||||
// 查询当前用户的所有消息通知 (分页)
|
||||
export const queryTraPersonalMessageNoticePaging = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPersonalMessageNotice/queryTraPersonalMessageNoticePaging',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 读取单一消息
|
||||
export const readNotice = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPersonalMessageNotice/readNotice',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 一键读取所有消息(不展示)
|
||||
export const oneTimeRead = (data) => {
|
||||
return request({
|
||||
url: base_url + '/traPersonalMessageNotice/oneTimeRead',
|
||||
method: 'post',
|
||||
toastErrors: true,
|
||||
data
|
||||
});
|
||||
};
|
||||
@@ -25,7 +25,6 @@
|
||||
<view class="option_div">
|
||||
<questionVue @changePlay="changePlay" :dataInfo="talkingInfo" :activeVoiceId="questionValue"></questionVue>
|
||||
</view>
|
||||
|
||||
</view>
|
||||
</template>
|
||||
<script setup>
|
||||
@@ -69,7 +68,7 @@
|
||||
const emit = defineEmits(['subject_click'])
|
||||
const talkingInfo = ref({
|
||||
id: '3',
|
||||
intrctWay: "",
|
||||
intrctWay: "02",
|
||||
intrctContent: "中的i id一二三。",
|
||||
talkingText: '中的i id一二三。',
|
||||
talkingVoice: ''
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<view class="talking-info" v-if="dataInfo.intrctWay === '02'">
|
||||
<view :class="['talking-gif', !voiceLoading&&(props.activeVoiceId === dataInfo.id) ? 'is-play' : '']">
|
||||
<CommonLoading color="#fff" v-show="voiceLoading"/>
|
||||
<view class="talking-info" v-if="intrctWay === '02'">
|
||||
<view :class="['talking-gif', (props.activeVoiceId === dataInfo.id) ? 'is-play' : '']">
|
||||
<CommonLoading color="#fff" v-show="voiceLoading" />
|
||||
</view>
|
||||
<view class="right-time">{{voiceTime}}</view>
|
||||
<view class="talking-cont">
|
||||
@@ -9,141 +9,151 @@
|
||||
{{ showContent }}
|
||||
</text>
|
||||
<view class="talking-text translate-text" v-if="translateLoading">
|
||||
<CommonLoading color="#fff"/>
|
||||
<CommonLoading color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
<view class="btns-cont">
|
||||
<view class="play-btn">
|
||||
<image class="icon"
|
||||
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="!voiceLoading&&(props.activeVoiceId === dataInfo.id)"
|
||||
@click.stop="pauseVoice"
|
||||
src="@/static/images/course/stop-blue.png"
|
||||
style="width: 100%;height: 100%;"
|
||||
></image>
|
||||
<!-- <view class="icon text-btn" v-if="type === 1" @click.stop="translateVoice(dataInfo)">文</view> -->
|
||||
<image class="icon" v-show="!(props.activeVoiceId === dataInfo.id)" @click="playVoice"
|
||||
src="@/static/images/course/play-blue.png" style="width: 100%;height: 100%;"></image>
|
||||
<image class="icon" v-show="props.activeVoiceId === dataInfo.id"
|
||||
@click.stop="pauseVoice" src="@/static/images/course/stop-blue.png"
|
||||
style="width: 100%;height: 100%;"></image>
|
||||
<!-- <view class="icon text-btn" v-if="type === 1" @click.stop="translateVoice(dataInfo)">文</view> -->
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="talking-info talking-info-text" v-else-if="dataInfo.intrctWay === '01'">
|
||||
<!-- 01纯文字 -->
|
||||
<view class="talking-info talking-info-text" v-else-if="intrctWay === '01'">
|
||||
<view class="talking-cont">
|
||||
<text :class="['talking-text translate-text loading']">
|
||||
{{ showContent }}
|
||||
</text>
|
||||
</view>
|
||||
</view>
|
||||
<view class="talking-info talking-info-loading" v-else>
|
||||
<view class="talking-info talking-info-loading" v-else>
|
||||
<view :class="['talking-gif']">
|
||||
<CommonLoading color="#fff"/>
|
||||
<CommonLoading color="#fff" />
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, unref, ref, toRefs, watch, onMounted } from "vue"
|
||||
import { onUnload } from '@dcloudio/uni-app';
|
||||
const props = defineProps({
|
||||
import {
|
||||
computed,
|
||||
unref,
|
||||
ref,
|
||||
toRefs,
|
||||
watch,
|
||||
onMounted
|
||||
} from "vue"
|
||||
import {
|
||||
onUnload
|
||||
} from '@dcloudio/uni-app';
|
||||
const props = defineProps({
|
||||
dataInfo: {
|
||||
default: () => ({}),
|
||||
type: Object
|
||||
},
|
||||
activeVoiceId:{
|
||||
default:'',
|
||||
activeVoiceId: {
|
||||
default: '',
|
||||
type: String
|
||||
},
|
||||
})
|
||||
const { activeVoiceId, dataInfo } = toRefs(props)
|
||||
const {
|
||||
activeVoiceId,
|
||||
dataInfo
|
||||
} = toRefs(props)
|
||||
|
||||
const intrctWay = ref('02')
|
||||
const emit = defineEmits(['changePlay'])
|
||||
watch(() => props.dataInfo, () => {},{deep: true,immediate: true})
|
||||
watch(() => props.dataInfo, () => {}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
// 声音播放初始化
|
||||
const talkVoiceObj = ref(null)
|
||||
|
||||
|
||||
const isPlaying = ref(false)
|
||||
const voiceLoading = ref(false)
|
||||
const translateLoading = ref(false)
|
||||
|
||||
|
||||
const voiceTime = ref('')
|
||||
const itemVoice = ref('')
|
||||
const showContent = computed(()=>{
|
||||
const showContent = computed(() => {
|
||||
return dataInfo.value.talkingText || ''
|
||||
})
|
||||
onMounted(()=>{
|
||||
onMounted(() => {
|
||||
initVoice()
|
||||
})
|
||||
onUnload(()=>{
|
||||
onUnload(() => {
|
||||
pauseVoice()
|
||||
})
|
||||
watch(() => props.dataInfo.talkingVoice,(val)=>{
|
||||
if(val){
|
||||
watch(() => props.dataInfo.talkingVoice, (val) => {
|
||||
if (val) {
|
||||
initVoice()
|
||||
}
|
||||
},{
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
const pauseVoice = () => {
|
||||
if(!talkVoiceObj.value) return
|
||||
if (!talkVoiceObj.value) return
|
||||
talkVoiceObj.value.pause()
|
||||
isPlaying.value = false
|
||||
emit('changePlay', '')
|
||||
}
|
||||
const playVoice = () =>{
|
||||
const playVoice = () => {
|
||||
emit('changePlay', unref(dataInfo)?.id)
|
||||
if(talkVoiceObj.value && talkVoiceObj.value.src) {
|
||||
talkVoiceObj.value.play()
|
||||
if (talkVoiceObj.value && talkVoiceObj.value.src) {
|
||||
talkVoiceObj.value.play()
|
||||
return
|
||||
}else{
|
||||
} else {
|
||||
talkVoiceObj.value.src = ''
|
||||
if(unref(dataInfo).talkingVoice){
|
||||
setTimeout(()=>{
|
||||
if (unref(dataInfo).talkingVoice) {
|
||||
setTimeout(() => {
|
||||
talkVoiceObj.value.src = unref(dataInfo).talkingVoice
|
||||
talkVoiceObj.value.play()
|
||||
isPlaying.value = true
|
||||
},100)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
const initVoice = () => {
|
||||
talkVoiceObj.value = uni.createInnerAudioContext()
|
||||
talkVoiceObj.value.onEnded(()=>{
|
||||
talkVoiceObj.value.onEnded(() => {
|
||||
emit('changePlay', '')
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
talkVoiceObj.value.onError(()=>{
|
||||
talkVoiceObj.value.onError(() => {
|
||||
talkVoiceObj.value.src = ''
|
||||
})
|
||||
if(unref(dataInfo).intrctWay === '02'){
|
||||
if (unref(dataInfo).intrctWay === '02') {
|
||||
itemVoice.value = unref(dataInfo).talkingVoice
|
||||
talkVoiceObj.value.src = itemVoice.value
|
||||
console.log(talkVoiceObj.value.src,1111)
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
setVoiceTime(0)
|
||||
},100)
|
||||
}, 100)
|
||||
}
|
||||
}
|
||||
const setVoiceTime = (sum) => {
|
||||
sum += 1
|
||||
if(Math.ceil(talkVoiceObj.value.duration)>0){
|
||||
voiceTime.value = (Math.ceil(talkVoiceObj.value.duration) || 1 ) + 's'
|
||||
}else{
|
||||
if(sum === 20) {
|
||||
if (Math.ceil(talkVoiceObj.value.duration) > 0) {
|
||||
voiceTime.value = (Math.ceil(talkVoiceObj.value.duration) || 1) + 's'
|
||||
} else {
|
||||
if (sum === 20) {
|
||||
voiceTime.value = 0 + 's'
|
||||
return
|
||||
}
|
||||
setTimeout(()=>{
|
||||
setTimeout(() => {
|
||||
setVoiceTime(sum)
|
||||
},200)
|
||||
}, 200)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
.talking-info{
|
||||
.talking-info {
|
||||
padding: 20rpx;
|
||||
border-radius: 15rpx;
|
||||
background-color: #06f;
|
||||
@@ -152,18 +162,21 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
color: #fff;
|
||||
width: 100%;
|
||||
float: right;
|
||||
.talking-gif{
|
||||
|
||||
.talking-gif {
|
||||
width: 200rpx;
|
||||
height: 38rpx;
|
||||
background: url(@/static/images/course/voice-gray.png) no-repeat;
|
||||
background-size: contain;
|
||||
padding-left: 168rpx;
|
||||
&.is-play{
|
||||
|
||||
&.is-play {
|
||||
background: url(@/static/images/course/voice-white.gif) no-repeat;
|
||||
background-size: contain;
|
||||
}
|
||||
}
|
||||
.right-time{
|
||||
|
||||
.right-time {
|
||||
position: absolute;
|
||||
right: 20rpx;
|
||||
top: 20rpx;
|
||||
@@ -171,37 +184,45 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
height: 38rpx;
|
||||
line-height: 38rpx;
|
||||
}
|
||||
&.talking-info-loading{
|
||||
|
||||
&.talking-info-loading {
|
||||
padding-bottom: 20rpx;
|
||||
}
|
||||
&.talking-info-text{
|
||||
|
||||
&.talking-info-text {
|
||||
padding-bottom: 20rpx;
|
||||
width: auto;
|
||||
float: right;
|
||||
.talking-cont{
|
||||
|
||||
.talking-cont {
|
||||
margin-top: 0rpx;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
.talking-cont{
|
||||
|
||||
.talking-cont {
|
||||
margin-top: 16rpx;
|
||||
overflow: hidden;
|
||||
.talking-text{
|
||||
|
||||
.talking-text {
|
||||
font-size: 28rpx;
|
||||
line-height: 48rpx;
|
||||
margin-bottom: 20rpx;
|
||||
word-break: break-all;
|
||||
white-space: pre-line;
|
||||
overflow: hidden;
|
||||
&.translate-text{
|
||||
|
||||
&.translate-text {
|
||||
min-height: 48rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
.btns-cont{
|
||||
|
||||
.btns-cont {
|
||||
overflow: hidden;
|
||||
border-top: 3rpx solid #eee;
|
||||
.replay-btn{
|
||||
|
||||
.replay-btn {
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
@@ -209,7 +230,8 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.play-btn{
|
||||
|
||||
.play-btn {
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
@@ -217,7 +239,8 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
margin-right: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.text-btn{
|
||||
|
||||
.text-btn {
|
||||
float: left;
|
||||
width: 46rpx;
|
||||
height: 46rpx;
|
||||
@@ -232,7 +255,8 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
font-weight: bold;
|
||||
border-radius: 20rpx;
|
||||
}
|
||||
.text-right-btn{
|
||||
|
||||
.text-right-btn {
|
||||
float: right;
|
||||
padding: 0 10rpx;
|
||||
height: 46rpx;
|
||||
@@ -242,7 +266,8 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
margin-left: 16rpx;
|
||||
margin-top: 25rpx;
|
||||
}
|
||||
.next-btn{
|
||||
|
||||
.next-btn {
|
||||
float: right;
|
||||
padding: 0 60rpx 0 20rpx;
|
||||
height: 62rpx;
|
||||
@@ -253,7 +278,8 @@ import { onUnload } from '@dcloudio/uni-app';
|
||||
border-radius: 8rpx;
|
||||
margin-top: 16rpx;
|
||||
position: relative;
|
||||
.icon-iamge{
|
||||
|
||||
.icon-iamge {
|
||||
width: 25rpx;
|
||||
height: 25rpx;
|
||||
position: absolute;
|
||||
|
||||
@@ -0,0 +1,412 @@
|
||||
<template>
|
||||
<view class="talk-btns">
|
||||
<uv-button class="touch-btn" @touchstart="startRecord" @touchend="stopRecord" @touchmove="handleMove"
|
||||
v-if="!keyboardIsShow" :customStyle="{height:'92rpx'}">按住说话
|
||||
</uv-button>
|
||||
<view class="touch-btn" v-if="keyboardIsShow">
|
||||
<uv-input class="input-box" ref="inputRef" v-model="inputText" :maxlength="props.textValueLength"
|
||||
:adjustPosition="false" placeholderStyle='color:#999999;font-size:26rpx' placeholder="请输入文字">
|
||||
</uv-input>
|
||||
</view>
|
||||
<view class="talk-btn-box">
|
||||
<image class="talk-btn-icon" v-show="!keyboardIsShow" src="@/static/images/course/jianpan.png" mode=""
|
||||
@click="changeBtn"></image>
|
||||
<image class="talk-btn-icon" v-show="keyboardIsShow && !inputText" src="@/static/images/course/record.png"
|
||||
mode="" @click="changeBtn"></image>
|
||||
|
||||
<image class="talk-btn-icon" v-show="keyboardIsShow && !!inputText" src="@/static/images/course/send.png"
|
||||
mode="" @click.stop="showKeyboard"></image>
|
||||
</view>
|
||||
|
||||
<uni-popup ref="popupRef" class="popup">
|
||||
<view class="overlay-box">
|
||||
<view class="circle-bg-box">
|
||||
<view class="icon-box">
|
||||
<image src="@/static/images/course/talk-icon.png"></image>
|
||||
</view>
|
||||
</view>
|
||||
<view class="tips-box">松开发送</view>
|
||||
<view class="btns-box">
|
||||
<view :class="['close-btn',isOut?'is-out':'']" id="circleBox">取消
|
||||
<image class="btn-box" v-if="!isOut" src="@/static/images/course/close.png" mode=""></image>
|
||||
<image class="btn-box" v-else src="@/static/images/course/close-active.png" mode=""></image>
|
||||
</view>
|
||||
</view>
|
||||
<view :class="['talk-dialog',isOut?'is-out':'']">
|
||||
<image src="@/static/images/course/voice-white.gif" mode="" class="gif-box"></image>
|
||||
</view>
|
||||
</view>
|
||||
</uni-popup>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
toRefs,
|
||||
ref,
|
||||
computed,
|
||||
unref,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
nextTick,
|
||||
watch,
|
||||
reactive
|
||||
} from 'vue';
|
||||
import common from '@/common/common';
|
||||
import permission from '@/common/permission.js'
|
||||
import {
|
||||
getPhoneEnvBool
|
||||
} from '@/common/common.js'
|
||||
|
||||
const emit = defineEmits(['submit'])
|
||||
const props = defineProps({
|
||||
isDisabled: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
isLoading: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
loadingText: {
|
||||
default: '发送回答中,请稍后再试!',
|
||||
type: String
|
||||
},
|
||||
canAnswer: {
|
||||
default: true,
|
||||
type: Boolean
|
||||
},
|
||||
canAnswerText: {
|
||||
default: '当前状态不能发送内容!',
|
||||
type: String
|
||||
},
|
||||
textValueLength: {
|
||||
type: Number,
|
||||
default: 500
|
||||
},
|
||||
minRecordDuration: { // 最小录音间隔
|
||||
type: Number,
|
||||
default: 1000
|
||||
},
|
||||
|
||||
})
|
||||
const {
|
||||
isDisabled,
|
||||
} = toRefs(props)
|
||||
|
||||
|
||||
|
||||
// 键盘还是语音
|
||||
const keyboardIsShow = ref(false)
|
||||
const popupRef = ref(null)
|
||||
|
||||
watch(() => props.isLoading, () => {}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
watch(() => props.canAnswer, () => {}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
|
||||
watch(() => props.isDisabled, (val) => {
|
||||
if (val) {
|
||||
keyboardIsShow.value = false
|
||||
}
|
||||
}, {
|
||||
deep: true,
|
||||
immediate: true
|
||||
})
|
||||
|
||||
const inputText = ref('')
|
||||
let startTime = 0;
|
||||
|
||||
// not_started 未开始, preparing 准备中, in_recording 录音中,ending 结束中
|
||||
const recordingStatus = ref('not_started')
|
||||
// 获取全局唯一的录音管理器 recorderManager
|
||||
const recorderManager = uni.getRecorderManager();
|
||||
// const innerAudioContext = uni.createInnerAudioContext();
|
||||
const startTimer = ref(null); // 延迟启动的定时器ID
|
||||
const startFlag = ref(1)
|
||||
const startRecord = (obj) => { // 开始录音
|
||||
console.log('开始录音', recordingStatus.value);
|
||||
if (recordingStatus.value !== 'not_started') return;
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
startTimer.value = setTimeout(() => {
|
||||
console.log('延迟开始');
|
||||
recordingStatus.value = 'preparing'
|
||||
isMoving.value = true
|
||||
recorderManager.start();
|
||||
}, 80);
|
||||
}
|
||||
// 结束录音
|
||||
const stopRecord = (obj) => {
|
||||
console.log('结束录音', obj);
|
||||
if (startTimer.value) {
|
||||
clearTimeout(startTimer.value);
|
||||
startTimer.value = null;
|
||||
}
|
||||
recorderManager.stop();
|
||||
popupRef.value.close()
|
||||
nextTick(() => {
|
||||
setTimeout(() => {
|
||||
recordingStatus.value = 'not_started'
|
||||
}, 300)
|
||||
})
|
||||
}
|
||||
onMounted(async () => {
|
||||
recorderManager.onStop(function(res) {
|
||||
console.log('recorder stop' + JSON.stringify(res));
|
||||
console.log('录音文件临时位置', res.tempFilePath);
|
||||
if (isOut) return; // 被划掉的语音
|
||||
const endTime = Date.now();
|
||||
const recordDuration = (endTime - startTime);
|
||||
if (props.minRecordDuration > recordDuration) {
|
||||
return common.msg('说话时间太短,没有听清!')
|
||||
}
|
||||
console.log('录音结束,时长:', recordDuration, '秒');
|
||||
emit('submit', 'voice', res.tempFilePath)
|
||||
});
|
||||
recorderManager.onStart(function(res) {
|
||||
// 检测是否已经抬手结束了
|
||||
console.log('检测是否已经抬手结束了', recordingStatus.value);
|
||||
if (recordingStatus.value !== 'preparing') {
|
||||
|
||||
stopRecord()
|
||||
}
|
||||
startTime = Date.now();
|
||||
popupRef.value.open()
|
||||
recordingStatus.value = 'in_recording'
|
||||
});
|
||||
})
|
||||
|
||||
const touchY = ref(0)
|
||||
const windowInfo = uni.getWindowInfo()
|
||||
|
||||
// 安全区域信息
|
||||
const safeArea = windowInfo.safeArea;
|
||||
|
||||
// 计算是否超出按下盒子位置
|
||||
const isOut = computed(() => {
|
||||
const btnHeight = windowInfo.screenWidth / 750 * 234;
|
||||
return touchY.value < safeArea.bottom - btnHeight;
|
||||
});
|
||||
const activeNum = ref(1)
|
||||
|
||||
const isMoving = ref(false)
|
||||
|
||||
const handleMove = (obj) => {
|
||||
touchY.value = obj.changedTouches[0].pageY
|
||||
}
|
||||
// 发送文本
|
||||
const showKeyboard = () => {
|
||||
if (keyboardIsShow.value) {
|
||||
const inputTextTram = inputText.value.trim()
|
||||
if (inputTextTram) {
|
||||
emit('submit', 'text', inputTextTram)
|
||||
} else {
|
||||
common.msg("不能发送空白消息!")
|
||||
}
|
||||
} else {
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
}
|
||||
|
||||
}
|
||||
// 切换键盘语音
|
||||
const changeBtn = () => {
|
||||
if (props.isDisabled) return
|
||||
keyboardIsShow.value = !keyboardIsShow.value
|
||||
inputText.value = ''
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.talk-btns {
|
||||
height: 150rpx;
|
||||
background-color: #fff;
|
||||
padding: 25rpx 30rpx 0;
|
||||
position: relative;
|
||||
|
||||
.touch-btn {
|
||||
height: 92rpx;
|
||||
box-shadow: 0 8rpx 20rpx 0 rgba(0, 0, 0, .06);
|
||||
text-align: center;
|
||||
line-height: 92rpx;
|
||||
color: #000;
|
||||
font-weight: 400;
|
||||
position: relative;
|
||||
|
||||
.input-box {
|
||||
width: 100%;
|
||||
height: 92rpx;
|
||||
line-height: 92rpx;
|
||||
text-align: left;
|
||||
box-sizing: border-box;
|
||||
padding: 0 40rpx 0 40rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.talk-btn-box {
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 120rpx;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
||||
.talk-btn-icon {
|
||||
width: 40rpx;
|
||||
height: 40rpx;
|
||||
position: absolute;
|
||||
right: 60rpx;
|
||||
top: 50%;
|
||||
margin-top: -20rpx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.overlay-box {
|
||||
display: flex;
|
||||
flex-direction: column-reverse;
|
||||
// justify-content: flex-end;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-color: rgba(0, 0, 0, 0.9);
|
||||
|
||||
.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;
|
||||
border-radius: 32rpx;
|
||||
position: relative;
|
||||
|
||||
&.is-out {
|
||||
background-color: #ff3e49;
|
||||
|
||||
&::after {
|
||||
background-color: #ff3e49;
|
||||
}
|
||||
}
|
||||
|
||||
.gif-box {
|
||||
position: absolute;
|
||||
width: 200rpx;
|
||||
height: 80rpx;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
width: 44rpx;
|
||||
height: 44rpx;
|
||||
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
||||
background-color: #06f;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
bottom: -22rpx;
|
||||
left: 50%;
|
||||
margin-left: -22rpx;
|
||||
}
|
||||
}
|
||||
|
||||
.white-bg-box {
|
||||
height: 365rpx;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
border-radius: 32rpx 32rpx 0 0;
|
||||
padding: 58rpx 36rpx;
|
||||
|
||||
.box-title {
|
||||
font-size: 32rpx;
|
||||
font-weight: bold;
|
||||
line-height: 46rpx;
|
||||
margin-bottom: 46rpx;
|
||||
}
|
||||
|
||||
.box-btns {
|
||||
height: 46rpx;
|
||||
line-height: 46rpx;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
color: #999;
|
||||
|
||||
.is-active {
|
||||
color: #06f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::v-deep .uv-input__content__field-wrapper__field {
|
||||
padding-right: 60rpx;
|
||||
}
|
||||
</style>
|
||||
@@ -15,40 +15,45 @@
|
||||
</view>
|
||||
<view class="title-num">
|
||||
<view class="num-item">
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/zhishidian.png"
|
||||
mode="heightFix"></image>
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/zhishidian.png" mode="heightFix"></image>
|
||||
<view class="mr-10">知识点</view>
|
||||
<view class="c-000">{{ form.pgrphNum || 0 }}</view>
|
||||
</view>
|
||||
<view class="num-item">
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/yixue.png" mode="heightFix">
|
||||
</image>
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/yixue.png" mode="heightFix"></image>
|
||||
<view class="mr-10">已学</view>
|
||||
<view class="c-000">{{ form.styParaGraphNum || 0 }}</view>
|
||||
</view>
|
||||
<view class="num-item examination">
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/charts.png" mode="heightFix">
|
||||
</image>
|
||||
<image class="title-icon" src="/src/static/images/courseDetail/charts.png" mode="heightFix"></image>
|
||||
<view>考试排行榜</view>
|
||||
<view class="back-icon"></view>
|
||||
</view>
|
||||
<view class="fl1">
|
||||
</view>
|
||||
<view class="num-item" @click="test=!test">
|
||||
<image v-show="test" class="collect-icon"
|
||||
src="/src/static/images/courseDetail/in_collect.png" mode="widthFix"></image>
|
||||
<image v-show="!test" class="collect-icon"
|
||||
src="/src/static/images/courseDetail/out_collect.png" mode="widthFix"></image>
|
||||
<view class="fl1"></view>
|
||||
<view class="num-item" @click="collect_click(form.collectId)">
|
||||
<image
|
||||
v-if="form.collectId"
|
||||
class="collect-icon"
|
||||
src="/src/static/images/courseDetail/out_collect.png"
|
||||
mode="widthFix"
|
||||
></image>
|
||||
<image v-else class="collect-icon" src="/src/static/images/courseDetail/in_collect.png" mode="widthFix"></image>
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
<view class="body-box">
|
||||
<uv-sticky :customNavHeight="statusBarHeight" id='tabsDiv' class="sticky">
|
||||
<uv-sticky :customNavHeight="statusBarHeight" id="tabsDiv" class="sticky">
|
||||
<view class="body-tab">
|
||||
<uv-tabs class="font_pf" :current="tabAct" :list="tabList" @change="tabSwitch"
|
||||
:scrollable="false" line-color="#0066FF"
|
||||
<uv-tabs
|
||||
class="font_pf"
|
||||
:current="tabAct"
|
||||
:list="tabList"
|
||||
@change="tabSwitch"
|
||||
:scrollable="false"
|
||||
line-color="#0066FF"
|
||||
:active-style="{ color: '#323E57', 'font-weight': 600, 'font-size': '30rpx' }"
|
||||
:inactive-style="{ color: '#666666', 'font-size': '30rpx' }"></uv-tabs>
|
||||
:inactive-style="{ color: '#666666', 'font-size': '30rpx' }"
|
||||
></uv-tabs>
|
||||
</view>
|
||||
</uv-sticky>
|
||||
<!-- <swiper class="body-swiper" @change="swiper_change" :current="tabAct"><swiper-item> -->
|
||||
@@ -61,66 +66,46 @@
|
||||
</view>
|
||||
<!--</swiper-item><swiper-item>-->
|
||||
<view class="evaluate" v-if="tabAct == 2 && form">
|
||||
<comment ref="commentRef" :crsNum="form.crsNum" :crsId="form.crsId" :imgId="form.imgId">
|
||||
</comment>
|
||||
<comment ref="commentRef" :crsNum="form.crsNum" :crsId="form.crsId" :imgId="form.imgId"></comment>
|
||||
</view>
|
||||
<!--</swiper-item></swiper>-->
|
||||
</view>
|
||||
</view>
|
||||
</scroll-view>
|
||||
<view class="btn-box btn-box-height font_pf">
|
||||
<template v-if="[0,1].includes(tabAct)">
|
||||
<uv-button type="primary"
|
||||
@click="common.navigateTo('/pages/course/study?crsNum='+crsNum+'&crsId='+form.crsId + '&imgId=' + form.imgId)">去学习</uv-button>
|
||||
<template v-if="[0, 1].includes(tabAct)">
|
||||
<uv-button type="primary" @click="common.navigateTo('/pages/course/study?crsNum=' + crsNum + '&crsId=' + form.crsId + '&imgId=' + form.imgId)">去学习</uv-button>
|
||||
<uv-button type="primary">去练习</uv-button>
|
||||
<uv-button type="primary" @click="goto_examination()">去考试</uv-button>
|
||||
</template>
|
||||
<template v-if="tabAct == 2">
|
||||
<uv-button type="primary" class="send_evaluate"
|
||||
@click="common.navigateTo('/pages/courseDetail/submit?crsNum='+crsNum+'&imgId='+form.imgId)">发布评价</uv-button>
|
||||
<uv-button type="primary" class="send_evaluate" @click="common.navigateTo('/pages/courseDetail/submit?crsNum=' + crsNum + '&imgId=' + form.imgId)">
|
||||
发布评价
|
||||
</uv-button>
|
||||
</template>
|
||||
</view>
|
||||
</view>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
reactive,
|
||||
ref,
|
||||
computed,
|
||||
onMounted
|
||||
} from 'vue';
|
||||
|
||||
import {
|
||||
onShow,
|
||||
onLoad,
|
||||
onUnload
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
getCourseDetailApi
|
||||
} from '@/api/courseDetail.js';
|
||||
import {
|
||||
startExamByCrs
|
||||
} from '@/api/examination.js'
|
||||
import { reactive, ref, computed, onMounted } from 'vue';
|
||||
import { onShow, onLoad, onUnload } from '@dcloudio/uni-app';
|
||||
import { getCourseDetailApi } from '@/api/courseDetail.js';
|
||||
import { startExamByCrs } from '@/api/examination.js';
|
||||
import { insertTraPersonalCollectionTask, deleteTraPersonalCollectionById } from '@/api/favorites.js';
|
||||
import common from '@/common/common';
|
||||
import introduceVue from './components/introduce.vue';
|
||||
import knowledge from './components/knowledge.vue';
|
||||
import comment from './components/comment.vue';
|
||||
const statusBarHeight = uni.getSystemInfoSync().statusBarHeight;
|
||||
// tab栏
|
||||
const tabList = ref([{
|
||||
name: '课程介绍'
|
||||
}, {
|
||||
name: '知识点'
|
||||
}, {
|
||||
name: '评价'
|
||||
}]);
|
||||
const tabList = ref([{ name: '课程介绍' }, { name: '知识点' }, { name: '评价' }]);
|
||||
|
||||
const test = ref(false);
|
||||
const commentRef = ref(null);
|
||||
const tabsDiv = ref(null);
|
||||
const form = ref({});
|
||||
const crsNum = ref('');
|
||||
const crsId = ref('');
|
||||
const tabAct = ref(0);
|
||||
const scrollTop = ref(0);
|
||||
const tabSwitch = (item) => {
|
||||
@@ -134,17 +119,14 @@
|
||||
};
|
||||
|
||||
const getData = async () => {
|
||||
const {
|
||||
body
|
||||
} = await getCourseDetailApi({
|
||||
crsNum: crsNum.value
|
||||
const { body } = await getCourseDetailApi({
|
||||
crsId: crsId.value
|
||||
});
|
||||
form.value = body;
|
||||
};
|
||||
const toStudyPrgh = (info) => {
|
||||
common.navigateTo('/pages/course/study?crsNum=' + crsNum.value + '&crsId=' + form.value.crsId + '&pgrphId=' +
|
||||
info.pgrphId + '&imgId=' + form.imgId)
|
||||
}
|
||||
common.navigateTo('/pages/course/study?crsNum=' + form.value.value + '&crsId=' + crsId.value + '&pgrphId=' + info.pgrphId + '&imgId=' + form.imgId);
|
||||
};
|
||||
|
||||
const bgOpacity = computed(() => {
|
||||
if (scrollTop.value <= 20) return `rgba(255,255,255,0)`;
|
||||
@@ -152,48 +134,65 @@
|
||||
return `rgba(255,255,255,${opacity})`;
|
||||
});
|
||||
// 子组件滑动开启状态
|
||||
const childScrollStatus = ref(false)
|
||||
const childScrollStatus = ref(false);
|
||||
const scroll_fun = (e) => {
|
||||
scrollTop.value = e.detail.scrollTop
|
||||
scrollTop.value = e.detail.scrollTop;
|
||||
// getElementPosition().then(res => {
|
||||
// childScrollStatus.value = statusBarHeight === res.top
|
||||
// })
|
||||
}
|
||||
};
|
||||
|
||||
const swiper_change = (res) => {
|
||||
tabAct.value = res.detail.current
|
||||
}
|
||||
tabAct.value = res.detail.current;
|
||||
};
|
||||
// 去考试
|
||||
const goto_examination = async () => {
|
||||
common.loading()
|
||||
|
||||
common.loading();
|
||||
startExamByCrs({
|
||||
// crsId : form.value.crsId
|
||||
crsId : 'CRS0250181220722025070408313900000018729'
|
||||
}).then(res => {
|
||||
setPageCache('examination', {...res.body, examId:detailData.examId})
|
||||
common.navigateTo('/pages/examination/index')
|
||||
}).finally(() => {
|
||||
common.hideLoading()
|
||||
crsId: 'CRS0250181220722025070408313900000018729'
|
||||
})
|
||||
}
|
||||
.then((res) => {
|
||||
setPageCache('examination', {
|
||||
...res.body,
|
||||
examId: detailData.examId
|
||||
});
|
||||
common.navigateTo('/pages/examination/index');
|
||||
})
|
||||
.finally(() => {
|
||||
common.hideLoading();
|
||||
});
|
||||
};
|
||||
|
||||
const collect_click = async (collectId) => {
|
||||
console.log(collectId);
|
||||
if (!collectId) {
|
||||
await insertTraPersonalCollectionTask({
|
||||
collectTyp: '01',
|
||||
collectBusId: crsId.value
|
||||
});
|
||||
} else {
|
||||
await deleteTraPersonalCollectionById({
|
||||
collectId: collectId
|
||||
});
|
||||
}
|
||||
};
|
||||
onMounted(async () => {
|
||||
uni.$on('refresh_comment_data', () => {
|
||||
console.log('发评论了刷新');
|
||||
commentRef.value?.getData('submit');
|
||||
tabAct.value = 2
|
||||
})
|
||||
})
|
||||
|
||||
tabAct.value = 2;
|
||||
});
|
||||
});
|
||||
|
||||
onLoad((params) => {
|
||||
crsNum.value = params.crsNum;
|
||||
crsId.value = params.crsId;
|
||||
});
|
||||
onShow(() => {
|
||||
getData();
|
||||
})
|
||||
});
|
||||
onUnload(() => {
|
||||
uni.$off('refresh_comment_data')
|
||||
uni.$off('refresh_comment_data');
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -227,8 +226,8 @@
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #FFFFFF;
|
||||
border-left: 4rpx solid #FFFFFF;
|
||||
border-top: 4rpx solid #ffffff;
|
||||
border-left: 4rpx solid #ffffff;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
}
|
||||
@@ -254,7 +253,6 @@
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
}
|
||||
|
||||
.body-head {
|
||||
@@ -273,7 +271,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.head-title {
|
||||
border-radius: 24rpx 24rpx 0rpx 0rpx;
|
||||
// height: 162rpx;
|
||||
@@ -307,7 +304,7 @@
|
||||
display: flex;
|
||||
|
||||
.examination {
|
||||
color: #0066FF;
|
||||
color: #0066ff;
|
||||
|
||||
.back-icon {
|
||||
position: relative;
|
||||
@@ -328,8 +325,8 @@
|
||||
left: 25%;
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
border-top: 4rpx solid #0066FF;
|
||||
border-left: 4rpx solid #0066FF;
|
||||
border-top: 4rpx solid #0066ff;
|
||||
border-left: 4rpx solid #0066ff;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
}
|
||||
@@ -342,7 +339,6 @@
|
||||
padding-right: 16rpx;
|
||||
padding-top: 20rpx;
|
||||
padding-bottom: 245rpx;
|
||||
|
||||
}
|
||||
|
||||
.body-tab {
|
||||
@@ -371,7 +367,7 @@
|
||||
padding-top: 37rpx;
|
||||
justify-content: space-around;
|
||||
background-color: #ffffff;
|
||||
border: 2rpx solid #E5E5E5;
|
||||
border: 2rpx solid #e5e5e5;
|
||||
z-index: 1000;
|
||||
|
||||
:deep(.uv-button-wrapper) {
|
||||
@@ -402,8 +398,6 @@
|
||||
height: 30rpx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.learn {
|
||||
color: #1dd17a;
|
||||
}
|
||||
@@ -416,4 +410,4 @@
|
||||
font-weight: 600;
|
||||
color: #000000;
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
<template>
|
||||
<view class="main_div max_page">
|
||||
<nav-bar :is_seat="true"></nav-bar>
|
||||
<view class="nav-div">
|
||||
<view class="title ellipsis-text">
|
||||
这里是练习名称
|
||||
</view>
|
||||
<view class="back_div"></view>
|
||||
</view>
|
||||
<view class="countdown-and-question-number-div">
|
||||
<view class="top">
|
||||
<view class="countdown">
|
||||
<text class="grey">答题进度</text> <text class="bold">2</text><text class="grey">/10</text>
|
||||
</view>
|
||||
<view class="question">
|
||||
<view class="grey">剩余时间</view>
|
||||
<uv-count-down :time="30 * 60 * 60 * 1000" format="HH:mm:ss"></uv-count-down>
|
||||
</view>
|
||||
</view>
|
||||
<view class="progress">
|
||||
<uv-line-progress :percentage="30" :showText="false" activeColor="#FFFFFF" inactiveColor="#89B8FF"
|
||||
:height="8"></uv-line-progress>
|
||||
</view>
|
||||
</view>
|
||||
<view class="scroll_div">
|
||||
<swiper class="swiper" :current="tabAct" :indicator-dots="false" :disable-touch="true">
|
||||
<swiper-item>
|
||||
<view class="content">
|
||||
<view class="expose_shadow"></view>
|
||||
<scroll-view :scroll-y="true" class="scroll-Y" :show-scrollbar="false" :refresher-threshold="0">
|
||||
<RadioSubject></RadioSubject>
|
||||
</scroll-view>
|
||||
</view>
|
||||
</swiper-item>
|
||||
</swiper>
|
||||
</view>
|
||||
</view>
|
||||
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import RadioSubject from '@/components/examination/radio-subject.vue'
|
||||
import {
|
||||
ref,
|
||||
computed,
|
||||
onMounted,
|
||||
nextTick,
|
||||
getCurrentInstance
|
||||
} from 'vue';
|
||||
const {
|
||||
proxy
|
||||
} = getCurrentInstance() // 获取当前组件实例
|
||||
// 用于存储尺寸信息的响应式变量
|
||||
const dimensions = ref({
|
||||
containerHeight: 0,
|
||||
contentHeight: 0
|
||||
});
|
||||
// 检查尺寸并更新
|
||||
const checkDimensions = async () => {
|
||||
await nextTick(); // 确保DOM已更新
|
||||
// 创建查询
|
||||
const query = uni.createSelectorQuery().in(proxy);
|
||||
// 添加内容高度查询
|
||||
query.select('.content').boundingClientRect(data => {
|
||||
dimensions.value.contentHeight = data?.height || 0;
|
||||
});
|
||||
// 添加容器高度查询(注意这里没有调用.exec())
|
||||
query.select('.scroll_div').boundingClientRect(data => {
|
||||
dimensions.value.containerHeight = data?.height || 0;
|
||||
});
|
||||
// 执行所有查询(只调用一次exec())
|
||||
query.exec();
|
||||
};
|
||||
|
||||
// 计算属性:判断是否需要开启滚动
|
||||
const isScrollable = computed(() => {
|
||||
return dimensions.value.contentHeight > dimensions.value.containerHeight - 20;
|
||||
});
|
||||
// 初始化时检查
|
||||
onMounted(() => {
|
||||
checkDimensions();
|
||||
// 监听窗口尺寸变化(可选)
|
||||
uni.onWindowResize(() => {
|
||||
checkDimensions();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
$bg-margin-left: 30rpx;
|
||||
|
||||
.scroll-Y {
|
||||
max-height: calc(100vh - var(--status-bar-height) - 70rpx - 70rpx - 40rpx - 64rpx - 68rpx - 60rpx);
|
||||
min-height: calc(100vh - var(--status-bar-height) - 70rpx - 70rpx - 40rpx - 64rpx - 68rpx - 60rpx - 380rpx);
|
||||
}
|
||||
|
||||
.content {
|
||||
position: relative;
|
||||
margin: 32rpx $bg-margin-left;
|
||||
border-radius: 16rpx;
|
||||
padding: 34rpx 30rpx 34rpx 36rpx;
|
||||
background-color: #fff;
|
||||
|
||||
.expose_shadow {
|
||||
margin-left: 36rpx;
|
||||
position: absolute;
|
||||
bottom: -26rpx;
|
||||
left: 0%;
|
||||
width: calc(100% - 66rpx);
|
||||
height: 28rpx;
|
||||
background-color: #FFFFFF;
|
||||
border-radius: 0 0 14rpx 14rpx;
|
||||
opacity: 0.4;
|
||||
z-index: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.countdown-and-question-number-div {
|
||||
margin: 20rpx $bg-margin-left;
|
||||
height: 70rpx;
|
||||
// background-color: red;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
z-index: 10;
|
||||
|
||||
.top {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
font-family: PingFangSC;
|
||||
font-size: 26rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: left;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.question {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
// background-color: red;
|
||||
width: 242rpx;
|
||||
color: red;
|
||||
|
||||
.grey {
|
||||
margin-right: 8rpx;
|
||||
}
|
||||
|
||||
:deep(.uv-count-down__text) {
|
||||
color: #FFFFFF !important;
|
||||
font-weight: 600;
|
||||
font-size: 26rpx !important;
|
||||
}
|
||||
}
|
||||
|
||||
.grey {
|
||||
color: #B6E2FF;
|
||||
}
|
||||
|
||||
.bold {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-div {
|
||||
position: relative;
|
||||
|
||||
.title {
|
||||
// padding-top:var(--status-bar-height);
|
||||
// padding: 0 30rpx;
|
||||
margin: 0 calc($bg-margin-left + 70rpx);
|
||||
height: 70rpx;
|
||||
font-family: PingFangSC;
|
||||
font-weight: 500;
|
||||
font-size: 34rpx;
|
||||
color: #FFFFFF;
|
||||
text-align: center;
|
||||
font-style: normal;
|
||||
line-height: 70rpx;
|
||||
|
||||
}
|
||||
|
||||
.back_div {
|
||||
position: absolute;
|
||||
right: $bg-margin-left;
|
||||
top: 0;
|
||||
width: 70rpx;
|
||||
height: 70rpx;
|
||||
// background-color: red;
|
||||
}
|
||||
}
|
||||
|
||||
.main_div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background: linear-gradient(to top, #3480FF, #0066FF);
|
||||
/* 确保背景占满整个视口高度 */
|
||||
min-height: 100vh;
|
||||
margin: 0;
|
||||
}
|
||||
</style>
|
||||
@@ -43,7 +43,7 @@
|
||||
</swiper>
|
||||
</view>
|
||||
|
||||
<view class="fixed-box font_pf">
|
||||
<view class="fixed-box font_pf" :style="{marginBottom:popup_input_bottom}">
|
||||
<view class="fixed-btn-box">
|
||||
<view class="sheet_button" @click="openSheet(true)">
|
||||
<image :src="examinationSheetIcon()" class="img"></image>
|
||||
@@ -60,13 +60,13 @@
|
||||
</view>
|
||||
</view>
|
||||
<view class="touch-btn-div" :class="{'show':showTouchBtn}">
|
||||
<TouchBtn class="talk-btns" @uploadVoice="uploadRecordNow" @submitAnswer="submitAnswerNow"
|
||||
:loadingText="sendLoadingText" :isLoading="!answerIsOver" :isDisabled="false" />
|
||||
<TouchBtn class="talk-btns" @submit="touchBtnSubmit"
|
||||
loadingText="问题回答中,请在问题回答结束后重试!" :isLoading="!answerIsOver" :isDisabled="false" />
|
||||
</view>
|
||||
</view>
|
||||
|
||||
<uni-popup ref="popupRef" class="popup">
|
||||
<view class="sheet_popup_div">
|
||||
<view class="sheet_popup_div" >
|
||||
<view class="title_div">
|
||||
<view class="text">
|
||||
答题卡
|
||||
@@ -107,7 +107,7 @@
|
||||
import Dialog from './components/dialog.vue'
|
||||
import RadioSubject from '@/components/examination/radio-subject.vue'
|
||||
import CharactersSubject from '@/components/examination/characters-subject.vue'
|
||||
import TouchBtn from '@/pages/course/components/touchBtn.vue'
|
||||
import TouchBtn from '@/components/examination/touchBtn.vue'
|
||||
import {
|
||||
ref,
|
||||
reactive,
|
||||
@@ -134,7 +134,7 @@
|
||||
queryPaperExamScore
|
||||
} from '@/api/examination.js'
|
||||
|
||||
const sendLoadingText = ref('问题回答中,请在问题回答结束后重试!')
|
||||
|
||||
const answerIsOver = ref(true)
|
||||
const feedbackRef = ref(null)
|
||||
const dialogRef = ref(null)
|
||||
@@ -149,9 +149,9 @@
|
||||
papersName: '', // 试卷名称
|
||||
}) // 试卷信息
|
||||
const topicList = reactive([]) // 问题列表
|
||||
|
||||
const popup_input_bottom = ref('0px')
|
||||
const questionNumber = ref(0) // 题号
|
||||
|
||||
const systemInfo = uni.getSystemInfoSync();
|
||||
const showTouchBtn = computed(() => {
|
||||
return topicList[questionNumber.value]['qnsTyp'] === 'ES'
|
||||
})
|
||||
@@ -207,53 +207,32 @@
|
||||
}
|
||||
|
||||
const voicePathValue = ref('')
|
||||
|
||||
// 录音按钮提交
|
||||
const touchBtnSubmit = (type, submitObj) => {
|
||||
if (type === 'voice') {
|
||||
uploadRecordNow(submitObj)
|
||||
}else if (type === 'text') {
|
||||
|
||||
}
|
||||
}
|
||||
// 发送语音
|
||||
const uploadRecordNow = (voicePath) => {
|
||||
//#ifdef APP-PLUS
|
||||
|
||||
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {}).then(res => {
|
||||
let _res = JSON.parse(res.data)
|
||||
voicePathValue.value = voicePath
|
||||
console.log('_res', _res, voicePath);
|
||||
|
||||
if (_res.rtnCode === '0000') {
|
||||
|
||||
// "chatId": "CHAT025018122068202508081537410000000000000000000000000000000088",
|
||||
// "fileId": "S3F0250181220722025080815374100000456565",
|
||||
// "ossFileAddr": "http://25.18.122.66::9786/traoss/show//S3F0250181220722025080815374100000456565",
|
||||
// "transContent": "下面那几个跟。"
|
||||
|
||||
// activeVoiceId.value =
|
||||
// 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
|
||||
// });
|
||||
// }
|
||||
} else {}
|
||||
|
||||
}
|
||||
}).catch(err => {
|
||||
// talkingList.value.pop()
|
||||
uni.showToast({
|
||||
title: '系统异常,请联系管理员',
|
||||
icon: "none",
|
||||
duration: 1000
|
||||
});
|
||||
})
|
||||
// #endif
|
||||
}
|
||||
// 发送文本
|
||||
const submitAnswerNow = (val, cb = null) => {
|
||||
@@ -277,6 +256,18 @@
|
||||
my_answer: [],
|
||||
backend_answer: [],
|
||||
})))
|
||||
// 安全区域底部到屏幕底部的高度(即底部安全区域高度)
|
||||
const safeAreaBottomHeight = systemInfo.screenHeight - systemInfo.safeArea.bottom;
|
||||
uni.onKeyboardHeightChange(res => {
|
||||
|
||||
let keyboardHeight = res.height;
|
||||
// 仅在iOS端补偿安全区域高度
|
||||
if (systemInfo.platform === 'ios') {
|
||||
keyboardHeight = Math.max(0, keyboardHeight - safeAreaBottomHeight); // 避免负数
|
||||
}
|
||||
popup_input_bottom.value = `${keyboardHeight}px`;
|
||||
console.log('端补偿安全区域高度', popup_input_bottom.value);
|
||||
});
|
||||
});
|
||||
|
||||
const result_click = ({
|
||||
@@ -366,7 +357,7 @@
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
console.log('answerDtoList', answerDtoList);
|
||||
dialogRef.value.close()
|
||||
common.loading('正在提交')
|
||||
@@ -382,7 +373,7 @@
|
||||
} else { // 不需要查分
|
||||
common.navigateBack()
|
||||
}
|
||||
|
||||
|
||||
// const execId = res.body.execId
|
||||
// let timer = setInterval(() => {
|
||||
// queryPaperExamScore({
|
||||
@@ -413,6 +404,7 @@
|
||||
padding: 0 38rpx;
|
||||
|
||||
.sheet_popup_div {
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #FFFFFF;
|
||||
@@ -535,7 +527,7 @@
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: 0 20rpx 20rpx 20rpx;
|
||||
|
||||
|
||||
.sheet_button {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
<view class="scroll-view-item" v-for="(item,index) in hot_class_list" :key="index">
|
||||
<view class="item_div">
|
||||
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
|
||||
<view class="item" @click="goto_course_detail(item.crsNum)">
|
||||
<view class="item" @click="goto_course_detail(item.crsId)">
|
||||
<view class="left">
|
||||
<image-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
|
||||
:isCache="true" :width="240" :height="240"></image-preview>
|
||||
@@ -164,7 +164,7 @@
|
||||
<view class="scroll-view-item" v-for="(item,index) in recommend_class_list" :key="index">
|
||||
<view class="item_div">
|
||||
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
|
||||
<view class="item" @click="goto_course_detail(item.crsNum)">
|
||||
<view class="item" @click="goto_course_detail(item.crsId)">
|
||||
<view class="left">
|
||||
<image-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
|
||||
:isCache="true" :width="240" :height="240"></image-preview>
|
||||
@@ -197,7 +197,7 @@
|
||||
<view class="scroll-view-item" v-for="(item,index) in new_class_list" :key="index">
|
||||
<view class="item_div">
|
||||
<uv-skeleton :loading="!item.crsNum" :rows="3" avatar avatar-shape="square" :title="false">
|
||||
<view class="item" @click="goto_course_detail(item.crsNum)">
|
||||
<view class="item" @click="goto_course_detail(item.crsId)">
|
||||
<view class="left">
|
||||
<image-preview class="img-box img" :imgId="item.imgId" mode="aspectFill"
|
||||
:isCache="true" :width="240" :height="240"></image-preview>
|
||||
@@ -389,8 +389,8 @@
|
||||
common.navigateTo('/pages/search/search')
|
||||
}
|
||||
// 进入课程详情页
|
||||
const goto_course_detail = (crsNum) => {
|
||||
common.navigateTo('/pages/courseDetail/index?crsNum=' + crsNum)
|
||||
const goto_course_detail = (crsId) => {
|
||||
common.navigateTo('/pages/courseDetail/index?crsId=' + crsId)
|
||||
}
|
||||
const scrolltolower = () => {
|
||||
common.navigateTo('/pages/index/dialog', {
|
||||
|
||||
@@ -16,10 +16,10 @@
|
||||
</view>
|
||||
<view class="right_div">
|
||||
<view class="title ellipsis-text">
|
||||
JBank银行服务礼仪与投诉...
|
||||
{{item.taskName}}
|
||||
</view>
|
||||
<view class="time_div">
|
||||
起止时间:<text class="blod_color">2025-05-13至2025-05-13</text>
|
||||
<view class="time_div" v-if="item.limitTyp==='02'">
|
||||
起止时间:<text class="blod_color">{{item.startTm?.substr(0, 10)}}至{{item.endTm?.substr(0, 10)}}</text>
|
||||
</view>
|
||||
<view class="people_progress_div">
|
||||
<view class="mr-10">
|
||||
@@ -49,8 +49,8 @@
|
||||
} from 'vue'
|
||||
|
||||
import {
|
||||
queryTraCrsBbsInfoByCrsId,
|
||||
} from '@/api/courseDetail.js';
|
||||
queryAllTraTaskInfoByUserId,
|
||||
} from '@/api/learningTasks.js';
|
||||
const getData = (from = '') => {
|
||||
if (from == 'first') {
|
||||
if (total.value !== -1) {
|
||||
@@ -66,8 +66,8 @@
|
||||
page.value++
|
||||
}
|
||||
setTimeout(() => {
|
||||
queryTraCrsBbsInfoByCrsId({
|
||||
crsId: 'CRS0250181220722025070408313900000018729',
|
||||
queryAllTraTaskInfoByUserId({
|
||||
state: '01',
|
||||
page: page.value,
|
||||
limit: limit
|
||||
}).then(res => {
|
||||
|
||||
@@ -15,36 +15,34 @@
|
||||
suffixIcon="search" :customStyle="customStyle" :suffixIconStyle="suffixIconStyle">
|
||||
</uv-input>
|
||||
</view>
|
||||
|
||||
<scroll-view ref="scrollRef" scroll-y="true" class="scroll-Y" :refresher-enabled="true"
|
||||
@refresherrefresh="onRefresh" @refresherrestore="triggered = 'restore'" :refresher-triggered="triggered"
|
||||
refresher-default-style="none">
|
||||
<!-- 主体 -->
|
||||
<view class="content">
|
||||
<view style="position: absolute;top: -90rpx;width: 100%;height: 90rpx;background-color: red;"> 下拉显示</view>
|
||||
<view style="position: absolute;top: -90rpx;width: 100%;height: 90rpx;"> </view>
|
||||
<uv-swipe-action>
|
||||
<uv-swipe-action-item :options="options" :threshold="40" :index="index"
|
||||
v-for="(index,item) in data_list">
|
||||
v-for="(item, index) in data_list">
|
||||
<view class="item">
|
||||
<view class="icon">
|
||||
<image class="img_100" :src="'/static/images/message_notification/type_1.png'"
|
||||
mode="widthFix"></image>
|
||||
<image class="img_100" :src="`@/static/images/messageNotification/type_${item.noticeTyp}.png`" mode="widthFix"></image>
|
||||
</view>
|
||||
<view class="right">
|
||||
<view class="top">
|
||||
<view class="title">
|
||||
新任务提醒
|
||||
{{item.noticeTitle}}
|
||||
</view>
|
||||
<view class="time">
|
||||
2025-05-05
|
||||
{{item.ctTime.substr(0, 16)}}
|
||||
</view>
|
||||
</view>
|
||||
<view class="bottom">
|
||||
<view class="note">
|
||||
您的学习任务
|
||||
<view class="note ellipsis-text">
|
||||
{{item.noticeContent}}
|
||||
</view>
|
||||
<view class="num_div">
|
||||
{{item}}
|
||||
|
||||
</view>
|
||||
</view>
|
||||
</view>
|
||||
@@ -70,8 +68,9 @@
|
||||
onLoad
|
||||
} from '@dcloudio/uni-app'
|
||||
import {
|
||||
queryTraCrsBbsInfoByCrsId
|
||||
} from '@/api/courseDetail.js';
|
||||
queryTraPersonalMessageNoticePaging
|
||||
} from '@/api/messageNotification.js';
|
||||
|
||||
const customStyle = {
|
||||
backgroundColor: "#ffffff",
|
||||
paddingLeft: "40rpx",
|
||||
@@ -135,8 +134,7 @@
|
||||
console.log(status.value, '阿斯顿撒');
|
||||
|
||||
setTimeout(() => {
|
||||
queryTraCrsBbsInfoByCrsId({
|
||||
crsId: 'CRS0250181220722025070408313900000018729',
|
||||
queryTraPersonalMessageNoticePaging({
|
||||
page: page.value,
|
||||
limit: limit
|
||||
}).then(res => {
|
||||
|
||||
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
Reference in New Issue
Block a user