This commit is contained in:
yanghang
2025-07-14 17:42:47 +08:00
parent 21f57b7d48
commit 7e8d6eaca4
26 changed files with 574 additions and 16 deletions
+5
View File
@@ -7,7 +7,12 @@ ENV = 'development'
# 苗扬
# VITE_APP_BASE_API_Url = 'http://25.64.16.133:9786'
# UAT
# VITE_APP_BASE_API_Url = 'http://25.18.122.78:9786'
# DEV
VITE_APP_BASE_API_Url = 'https://aitstest.jlbank.com.cn:7001'
# http://25.18.122.65:7001/download/dev-jax.apk
# app入口
#VITE_APP_BASE_API_Url = 'http://25.16.122.65:7001'
+1 -1
View File
@@ -1,7 +1,7 @@
<template>
<view class="course-item-box" @click="clickItem">
<view class="img-box-view">
<ImagePreview class="img-box" :imgId="itemInfo.imgId" :isCache="true"></ImagePreview>
<ImagePreview class="img-box" :imgId="itemInfo.imgId" :isCache="true" width="340" height="340"></ImagePreview>
<view class="item-grade">{{itemInfo.evalGrade}}</view>
</view>
<view class="cont-box">
@@ -34,7 +34,7 @@
default:50,
type:[String, Number]
},
isCache:{
isCache:{ // 获取缩略图
type: Boolean,
default: false
},
+33 -7
View File
@@ -2,7 +2,7 @@
<view class="talk-btns" ref="talkBtnRef">
<view
class="touch-btn"
@touchstart="showOverlayTalking"
@touchstart="getRecordPermission"
@touchend="hideOverlayTalking"
@touchmove="handleMove"
v-if="!keyboardIsShow"
@@ -42,12 +42,12 @@ import { toRefs, ref, computed, unref, onMounted, onUnmounted, nextTick } from '
import common from '../../../common/common';
const emit = defineEmits(['uploadVoice', 'submitAnswer','startRecord'])
const props = defineProps({
answerType:{
default: 0,
type: Number
isDisabled:{
default: Boolean,
type: true
}
})
const { answerType } = toRefs(props)
const { isDisabled } = toRefs(props)
const showTalkingModel = ref(false)
const keyboardIsShow = ref(false)
const answerValue = ref('')
@@ -96,10 +96,36 @@ const isOut = computed(() => {
})
const recNum = ref(1)
const activeNum = ref(1)
const getRecordPermission = (obj) => {
//#ifdef APP-PLUS
uni.getSetting({
success: (res) => {
if(!res.authSetting['scope.record']){
// 没有授权,请求授权
uni.authorize({
scope: 'scope.record',
success:() => {
showOverlayTalking(obj)
},
fail: () => {
common.msg('请设置开启录音权限!')
}
})
}else{
showOverlayTalking(obj)
}
}
})
// #endif
//#ifndef APP-PLUS
showOverlayTalking(obj)
// #endif
}
const showOverlayTalking = (obj) => {
recNum.value += 1
emit('startRecord')
if(answerType.value === 4){
if(!isDisabled.value){
showTalkingModel.value = true
touchX.value = obj.changedTouches[0].pageX
touchY.value = obj.changedTouches[0].pageY
@@ -142,7 +168,7 @@ const handleMove = (obj) => {
}
// 发送文本
const showKeyboard = () => {
if(answerType.value === 4){
if(!isDisabled.value){
if(keyboardIsShow.value){
if(answerValue.value){
emit(
+5 -3
View File
@@ -82,7 +82,7 @@
@uploadVoice="uploadRecordNow"
@submitAnswer="submitAnswerNow"
@startRecord="changePlayItemId('')"
:answerType="lastTalkingInfo.type||0"
:isDisabled="(lastTalkingInfo.type||0) !== 4"
/>
</view>
<uv-overlay :show="showSeekModel" opacity=".6" @click="showSeekModel = false">
@@ -355,7 +355,6 @@ const getQuestionInfoUnStudy = (pgrphId) => {
.then(res=>{
let _id = new Date().getTime() + 'id'
let _body = res.body || {}
console.log(_body.chatBody)
if(_body.chatBody && _body.chatBody?.stdyStat !== 'N'){
let _id = new Date().getTime() + 'id'
lastTalkingInfo.value = {
@@ -693,7 +692,7 @@ const finishQuestionNow = (data) => {
common.msg('提交答案失败!')
return
}
let _id1 = new Date().getTime() + 'id'
let _id1 = new Date().getTime() + '3d'
talkingList.value.push({
id: _id1,
talkingContent: '完成',
@@ -879,6 +878,9 @@ const chooseRateNow = (item) => {
text-align: left;
box-sizing: border-box;
padding:0 40rpx 0 40rpx;
::v-deep .uv-input__content{
padding-right: 50rpx;
}
}
}
.talk-btn-box{
+9
View File
@@ -0,0 +1,9 @@
<template>
<view>答案</view>
</template>
<script>
</script>
<style>
</style>
+157
View File
@@ -0,0 +1,157 @@
<template>
<view class="talking-info">
<view :class="['talking-gif', !voiceLoading ? 'is-play' : '']">
<CommonLoading color="#fff" v-show="voiceLoading"/>
</view>
<view class="right-time">{{voiceTime}}</view>
<view class="talking-cont">
<text :class="['talking-text translate-text loading']" v-show="!translateLoading">
{{ showContent }}
</text>
<view class="talking-text translate-text" v-if="translateLoading">
<CommonLoading color="#fff"/>
</view>
</view>
<view class="btns-cont">
<view class="play-btn">
<image class="icon"
src="@/static/images/course/play-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>
</template>
<script setup>
import { computed, ref, toRefs } from "vue"
const props = defineProps({
dataInfo: {
default: () => ({}),
type: Object
},
activeVoiceId:{
default:'',
type: String
},
})
const { activeVoiceId, dataInfo } = toRefs(props)
const voiceLoading = ref(false)
const translateLoading =ref(false)
const voiceTime = ref('')
const showContent = computed(()=>{
return '问题'
})
</script>
<style scoped lang="scss">
.talking-info{
padding: 20rpx;
border-radius: 15rpx;
background-color: #06f;
padding-bottom: 30rpx;
position: relative;
color: #fff;
.talking-gif{
width: 200rpx;
height: 38rpx;
background: url(@/static/images/course/voice-gray.png) no-repeat;
background-size: contain;
padding-left: 168rpx;
&.is-play{
background: url(@/static/images/course/voice-white.gif) no-repeat;
background-size: contain;
}
}
.right-time{
position: absolute;
right: 20rpx;
top: 20rpx;
font-size: 28rpx;
height: 38rpx;
line-height: 38rpx;
}
.talking-cont{
margin-top: 16rpx;
overflow: hidden;
.talking-text{
font-size: 28rpx;
line-height: 48rpx;
margin-bottom: 20rpx;
word-break: break-all;
white-space: pre-line;
overflow: hidden;
&.translate-text{
min-height: 48rpx;
}
}
}
.btns-cont{
overflow: hidden;
border-top: 3rpx solid #eee;
.replay-btn{
float: left;
width: 46rpx;
height: 46rpx;
overflow: hidden;
margin-right: 16rpx;
margin-top: 25rpx;
}
.play-btn{
float: left;
width: 46rpx;
height: 46rpx;
overflow: hidden;
margin-right: 16rpx;
margin-top: 25rpx;
}
.text-btn{
float: left;
width: 46rpx;
height: 46rpx;
overflow: hidden;
line-height: 46rpx;
text-align: center;
color: #fff;
margin-right: 16rpx;
margin-top: 25rpx;
background-color: #67A4ff;
font-size: 24rpx;
font-weight: bold;
border-radius: 20rpx;
}
.text-right-btn{
float: right;
padding: 0 10rpx;
height: 46rpx;
overflow: hidden;
line-height: 46rpx;
text-align: center;
margin-left: 16rpx;
margin-top: 25rpx;
}
.next-btn{
float: right;
padding: 0 60rpx 0 20rpx;
height: 62rpx;
line-height: 62rpx;
font-size: 30rpx;
background-color: #06f;
color: #fff;
border-radius: 8rpx;
margin-top: 16rpx;
position: relative;
.icon-iamge{
width: 25rpx;
height: 25rpx;
position: absolute;
right: 20rpx;
top: 50%;
margin-top: -12rpx;
}
}
}
}
</style>
@@ -0,0 +1,28 @@
<template>
<view class="talking-item">
<questionVue v-if="talkingType === 'question'"></questionVue>
<answerVue v-else-if="talkingType === 'answer'"></answerVue>
<view v-else></view>
</view>
</template>
<script setup>
import { toRefs } from 'vue'
import questionVue from './question.vue';
import answerVue from './answer.vue';
const props = defineProps({
talkingType:{
default:'question',
type: String
}
})
const { talkingType } = toRefs(props)
</script>
<style >
.talking-item{
&+.talking-item{
margin-top: 30rpx;
}
}
</style>
+333 -3
View File
@@ -1,12 +1,342 @@
<template>
<view>
<MarkdownPreview/>
<view class="index-dialog-page">
<!-- <MarkdownPreview/> -->
<view class="top-bg"></view>
<view class="bot-bg"></view>
<view class="index-dialog-body">
<view class="seek-setting">
设置
<image src="@/static/images/course/setting.png" alt="" class="image-icon"></image>
</view>
<view class="body-title">
<uv-icon class="arrow-icon" name="arrow-left" @click="common.navigateBack()"/>
AI问答
</view>
<view class="ai-info">
<image src="@/static/images/dialog/pet-3.png" alt="" class="image-pet-bg"></image>
<view class="ai-info-bg-box">
<view class="hello-text">Hi我是{{'李想'}}</view>
<view class="info-text">工作学习我都能帮你</view>
<view class="info-btn">试试他的能力</view>
</view>
</view>
<view class="questions-view">
<scroll-view :scroll-x="true" :show-scrollbar="false">
<view class="question-row">
<view class="question-item" v-for="item in Math.ceil(questionList.length/2)">{{questionList[item-1]}}</view>
</view>
<view class="question-row">
<view class="question-item" v-for="item in questionList.length - Math.ceil(questionList.length/2)">{{questionList[item + Math.ceil(questionList.length/2)-1]}}</view>
</view>
</scroll-view>
</view>
<view class="talking-list">
<scroll-view
class="talking-scroll-list"
:scroll-y="true"
:scroll-top="scrollTop"
:show-scrollbar="false"
:scroll-with-animation="true"
>
<TalkingItem
v-for="item in 12"
:talkingType="item%2===1?'question':'answer'"
>
</TalkingItem>
</scroll-view>
</view>
<view class="router-list">
<scroll-view class="" :scroll-x="true" :show-scrollbar="false">
<view class="btns-item" @click="routerTo('AI学')">
<image src="@/static/images/dialog/icons/study.png" alt="" class="image-icon"></image>
{{ 'AI学' }}
</view>
<view class="btns-item" @click="routerTo('AI练')">
<image src="@/static/images/dialog/icons/test.png" alt="" class="image-icon"></image>
{{ 'AI练' }}
</view>
<view class="btns-item" @click="routerTo('AI考')">
<image src="@/static/images/dialog/icons/exam.png" alt="" class="image-icon"></image>
{{ 'AI考' }}
</view>
<view class="btns-item" @click="routerTo('去PK')">
<image src="@/static/images/dialog/icons/PK.png" alt="" class="image-icon"></image>
{{ '去PK' }}
</view>
<view class="btns-item" @click="routerTo('任务')">
<image src="@/static/images/dialog/icons/task.png" alt="" class="image-icon"></image>
{{ '任务' }}
</view>
<view class="btns-item" @click="routerTo('错题')">
<image src="@/static/images/dialog/icons/wrong.png" alt="" class="image-icon"></image>
{{ '错题' }}
</view>
<view class="btns-item" @click="routerTo('分析')">
<image src="@/static/images/dialog/icons/static.png" alt="" class="image-icon"></image>
{{ '分析' }}
</view>
</scroll-view>
</view>
<TouchBtn
class="talk-btns"
@uploadVoice="uploadRecordNow"
@submitAnswer="submitAnswerNow"
@startRecord="startRecordCallback"
:isDisabled="false"
/>
</view>
</view>
</template>
<script setup>
import { ref } from 'vue'
import common from '@/common/common';
import TouchBtn from '@/pages/course/components/touchBtn.vue'
import MarkdownPreview from '@/components/markdown-preview/markdown-preview.vue';
import TalkingItem from './components/talking-item.vue';
const questionList = ref([
'对公小程序开户流程?',
'厅堂服务经理2025年管理办法?',
'厅堂服务经理2025年考核表单?',
'吉林银行重要空白凭证调微业务操作规程?',
'协助有权机关查询冻结扣划业务操作规程?',
'柜面个人账户操作规程?',
'久悬未取款账户如何办理销户?',
'境外来华人员个人账户业务开户如何办理?',
'营业机构日间管理风险防控要点有哪些?',
'现金管理平台柜面业务操作?'
])
const scrollBoxRef = ref()
const scrollTop = ref(99999)
const scrollToBottomNow = (time = 500) => {
nextTick(()=>{
setTimeout(() => {
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 routerTo = (type) => {
switch(type){
case 'AI学':
common.navigateTo('/pages/course/index')
break;
default:
common.msg('页面建设中,敬请期待!')
break;
}
}
const uploadRecordNow = (voicePath) => {
}
// 发送文本
const submitAnswerNow = (val, cb) => {
}
const startRecordCallback = () => {
// 开始录音回调
}
</script>
<style>
<style scoped lang="scss">
.index-dialog-page{
position: relative;
display: flex;
flex-direction: column;
height: 100vh;
.top-bg{
background: linear-gradient(16deg,rgba(234,246,255,0) 0%,#c3e6ff 100%);
height: 480rpx;
width: 100%;
}
.bot-bg{
// background-color: #F6F8FF;
background: linear-gradient(136deg,rgba(234,246,255,0) 0%,#c3e6ff 100%);
width: 100%;
flex: 1;
}
.index-dialog-body{
position: absolute;
overflow: hidden;
left:0;
top: 0;
height: 100%;
width: 100%;
padding: 0;
box-sizing: border-box;
// display: flex;
// flex-direction: column;
.body-title{
height: 140rpx;
text-align: center;
font-size: 33rpx;
padding-top: 70rpx;
line-height: 46rpx;
box-sizing: border-box;
font-weight: 500;
color:#000;
position: relative;
// margin-bottom: 23rpx;
.arrow-icon{
position: absolute;
left:36rpx;
top:80rpx;
color: #000;
}
}
.seek-setting{
position: absolute;
z-index: 3;
right: 45rpx;
top: 68rpx;
font-size: 26rpx;
width: 140rpx;
height: 52rpx;
padding: 10rpx 0;
overflow: hidden;
line-height: 32rpx;
text-align: right;
padding-right: 48rpx;
.image-icon{
width: 30rpx;
height: 32rpx;
position: absolute;
right: 0;
top: 10rpx;
}
}
.ai-info{
padding: 0 24rpx;
height: 250rpx;
overflow: hidden;
padding-top: 72rpx;
margin-bottom: 24rpx;
position: relative;
box-sizing: border-box;
.image-pet-bg{
position: absolute;
padding: 0 24rpx;
box-sizing: border-box;
width: 100%;
height: 100%;
left: 0;
top: 0;
z-index: 2;
}
.ai-info-bg-box{
position: absolute;
z-index: 3;
left: 0;
top: 68rpx;
width: 100%;
// background-color: #ccc;
padding: 0 64rpx;
height: 178rpx;
.hello-text{
height: 54rpx;
line-height: 44rpx;
font-size: 28rpx;
color: #666;
}
.info-text{
height: 44rpx;
line-height: 44rpx;
font-size: 32rpx;
color: #000;
font-weight: 600;
}
.info-btn{
width: 220rpx;
font-size: 29rpx;
height: 54rpx;
color: #fff;
background: linear-gradient(104deg, #5547f3 0%, #4e86f4 100%);
line-height: 54rpx;
text-align: center;
border-radius: 15rpx 15rpx 0 0;
position: absolute;
left: 64rpx;
bottom: 0;
}
}
}
.questions-view{
padding-left: 24rpx;
padding-right: 24rpx;
height: 184rpx;
box-sizing: border-box;
.question-row{
white-space: nowrap;
margin-bottom: 16rpx;
}
.question-item{
white-space: nowrap;
height: 76rpx;
line-height: 74rpx;
background-color: #fff;
border: 2rpx solid #e0dede;
padding: 0 16rpx;
border-radius: 11rpx;
margin-right: 16rpx;
display: inline-block;
&:last-child{
margin-right: 0;
}
}
}
.router-list{
height: 84rpx;
padding: 22rpx 30rpx 0;
background-color: #fff;
border-radius: 15rpx 15rpx 0 0;
white-space: nowrap;
box-sizing: border-box;
.btns-item{
display: inline-block;
box-sizing: border-box;
height: 62rpx;
border: 2rpx solid #e0dede;
border-radius: 15rpx;
margin-right: 16rpx;
padding: 0 20rpx 0 64rpx;
line-height: 58rpx;
font-size: 29rpx;
position: relative;
.image-icon{
position: absolute;
width: 31rpx;
height: 31rpx;
top:50%;
transform: translateY(-50%);
left: 24rpx;
}
&:last-child{
margin-right: 0;
}
}
}
.talking-list{
height: calc(100% - 834rpx);
padding: 12rpx 24rpx;
box-sizing: border-box;
.talking-scroll-list{
height: 100%;
}
}
}
}
</style>
+2 -1
View File
@@ -110,7 +110,8 @@ const login_fun = (): void => {
// this.$common.reLaunch('/pages/homepage/index');
// }, this.GLOBAL_TIMER_SUBMIT_DELAY_TIME);
socketStore.creatSocket();
// ws
// socketStore.creatSocket();
const pages = getCurrentPages();
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 212 KiB