Merge branch 'sit' into 'uat'

Sit

See merge request K17_AITS/tra-app!37
This commit is contained in:
田岩
2025-07-17 17:13:57 +08:00
26 changed files with 211 additions and 40 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -20,7 +20,7 @@ android {
config {
keyAlias 'ai_jlyh_app'
keyPassword 'Kup9dayLY#*'
storeFile file('ai_jlyh_app.jks')
storeFile file('ai_jlyh_app.keystore')
storePassword 'Kup9dayLY#*'
v1SigningEnabled true
v2SigningEnabled true
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2
View File
@@ -0,0 +1,2 @@
包名:cn.com.jlbank.ai
证书密码:Kup9dayLY#*
+9
View File
@@ -0,0 +1,9 @@
# 先生成p12文件
keytool -importkeystore -srckeystore ai_jlyh_app.jks -srcstoretype JKS -deststoretype PKCS12 -destkeystore ai_jlyh_app.p12
# 用p12生成keystore
keytool -v -importkeystore -srckeystore ai_jlyh_app.p12 -srcstoretype PKCS12 -destkeystore ai_jlyh_app.keystore -deststoretype JKS
# 迁移到行业标准格式 PKCS12
keytool -importkeystore -srckeystore ai_jlyh_app.keystore -destkeystore ai_jlyh_app.keystore -deststoretype pkcs12
keytool -v -list -keystore ai_jlyh_app.keystore
+32
View File
@@ -157,6 +157,38 @@ export function downloadVoiceFile(url) {
});
});
}
export function getAudioByText(data) {
const token = getToken();
const header = {
"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
};
if (token)
header['summary'] = token
let baseUrl = get_base_url();
return new Promise((resolve, reject) => {
uni.request({
url: `${baseUrl}/trastudy/traStdyInfo/readContent`,
header,
method:"POST",
data,
responseType: "arraybuffer",
success(result) {
if(result.statusCode === 200){
resolve(result.data)
}else{
reject(new Error(result))
}
},
fail(error) {
reject(new Error(error));
}
});
});
}
// 对象存储预览 /traoss/tras3/show/{文件ID}
export function previewFile(id, responseType = 'arraybuffer') {
const token = getToken();
+3
View File
@@ -155,6 +155,9 @@ export default class WebSocketUtil {
} else {
console.error('WebSocket连接未打开,无法发送消息');
this.triggerEvent('error', new Error('WebSocket连接未打开'));
setTimeout(()=>{
this.send(message)
},500)
}
return this;
}
@@ -5,10 +5,7 @@
</template>
<script>
// import {Marked} from 'marked';
import MarkdownIt from 'markdown-it';
// import markdownItAttrs from 'markdown-it-attrs'
// import markdownItHighlight from 'markdown-it-highlightjs'
export default {
name:"markdown-preview",
props: {
@@ -49,10 +46,7 @@
linkify: true,
typographer: true
})
// this.mdObj.use(markdownItAttrs)
// this.mdObj.use(markdownItHighlight)
this.contentHtml = this.parseContent(this.mdString)
console.log(this.contentHtml)
}
}
</script>
+1 -1
View File
@@ -14,7 +14,7 @@
</view>
<view class="total-score">
<view class="score-num">{{props.score}}</view>
<img class="total-score-icon" src="@/static/images/course/score.png" alt="" />
<image class="total-score-icon" src="@/static/images/course/score.png" alt=""></image>
</view>
<view v-for="item,index in props.dataList" :class="['score-item', 'score-item'+(index+1)]">
<view class="score-item-name">{{ item.gradeDimensName }}</view>
+1 -1
View File
@@ -17,7 +17,7 @@
</view>
<view class="total-score">
<view class="score-num">{{props.score}}</view>
<img class="total-score-icon" src="@/static/images/course/score.png" alt="" />
<image class="total-score-icon" src="@/static/images/course/score.png" alt="" ></image>
</view>
<view v-for="item,index in props.dataList" :class="['score-item', 'score-item'+(index+1)]">
<view class="score-item-name">{{ item.gradeDimensName }}</view>
+29 -1
View File
@@ -185,7 +185,7 @@
import { watch, unref, ref, toRefs, computed, nextTick,onMounted } from 'vue'
import ImagePreview from '@/components/image-preview/image-preview.vue'
import VideoPreview from '@/components/image-preview/video-preview.vue'
import { downloadVoiceFile, uploadVoiceFile, } from "@/api/common.js"
import { downloadVoiceFile, uploadVoiceFile, getAudioByText } from "@/api/common.js"
import { studyParagraphOverApi, getAskAboutRawApi } from "@/api/study.js"
import ChartFour from "./chartFour.vue"
import ChartThree from "./chartThree.vue"
@@ -373,6 +373,8 @@ const audioCacheObj = computed(() => storageStore.audioObj)
teachNo: unref(teacherInfo)?.teacherNo, // 必填
content: _content
}
let _url = '/trastudy/traStdyInfo/readContent?' + Object.keys(_params).map(t=>{
return encodeURIComponent(t) + '=' + encodeURIComponent(_params[t])
}).join('&')
@@ -384,6 +386,19 @@ const audioCacheObj = computed(() => storageStore.audioObj)
talkVoiceObj.value.src = url
talkVoiceObj.value.play()
}else{
// getAudioByText(_params).then(res=>{
// // uni.env.USER_DATA_PATH ||
// let filePath = `${'/'}/${dataInfo.value.id}.mp3`
// saveFile(res, filePath, () => {
// voiceLoading.value = false
// itemVoice.value = filePath
// talkVoiceObj.value.src = filePath
// talkVoiceObj.value.play()
// storageStore.setStorage('audio', _url + _params.teachNo, itemVoice.value)
// })
// }).catch(err=>{
// console.log(err)
// })
downloadVoiceFile(_url).then(res=>{
if(res?.data){
common.msg(res.data.message)
@@ -401,6 +416,19 @@ const audioCacheObj = computed(() => storageStore.audioObj)
})
}
}
const saveFile = (buffer,filePath, cb = ()=>{}) => {
let fileManager = uni.getFileSystemManager()
fileManager.writeFile({
filePath: filePath,
data: buffer,
encoding: 'binary',
success: cb,
file: ()=>{
voiceLoading.value = false
console.log('文件保存失败!')
}
})
}
const initVoice = (readType = 'qns', item, isplay=false) => {
if(unref(dataInfo).talkingVoice){
itemVoice.value = unref(dataInfo).talkingVoice
+24 -17
View File
@@ -176,13 +176,8 @@ const flagVal = ref('1')
const isUploadingVoice = ref(false)
// 初始化数据
const getData = async (flag) => {
// if(flag === flagVal.value){
// flagVal.value = '2'
// }else{
// return
// }
try{
await initsocketTask()
initsocketTask()
const { body } = await getCourseStudyInfoApi({crsId: crsId.value})
teacherList.value = body.teacheList.map(t=>({
...t,
@@ -192,8 +187,8 @@ const getData = async (flag) => {
if(body.stdyProgressFlag === 'N'){
step.value = 1
}else{
choiceTeacher.value = body.choiceTeacher
if(startPgrphId.value){
choiceTeacher.value = body.choiceTeacher
sendMessage({
"commond" : 'STDY',
"body" : {
@@ -201,7 +196,6 @@ const getData = async (flag) => {
teacherNo: choiceTeacher.value
}
})
step.value = 2
return
}
common.show('提示', '系统检测到您已存在学习记录,要继续学习吗?',true, '重新学习','继续学习').then((res) => {
@@ -209,7 +203,6 @@ const getData = async (flag) => {
// 继续学习 获取学习历史接口
// 滚动到最下面
scrollToBottomNow()
choiceTeacher.value = body.choiceTeacher
sendMessage({
"commond" : 'STDY',
"body" : {
@@ -374,7 +367,6 @@ const getGraphInfoUnStudy = (flag = 0) => {
if(!_body.chatBody) {
return
}
console.log('prgh', _body)
if(Number(_body.bodyTyp) === 7){
common.show('恭喜你已学完全部知识点', '有什么心得跟我们分享吗?',true, '取消','去评论').then((res) => {
if(res) {
@@ -587,8 +579,20 @@ const stdyId = ref('')
const stdyBatch = ref('')
const logId = ref('')
// ws 初始化逻辑
const initsocketTask = async () => {
await socketStore.creatSocket()
const initsocketTask = () => {
socketStore.creatSocket()
unref(SocketObj).on('open', (res)=>{
if(startPgrphId.value){
sendMessage({
"commond" : 'STDY',
"body" : {
crsId: crsId.value,
teacherNo: choiceTeacher.value
}
})
step.value = 2
}
})
unref(SocketObj).on('message', (res)=>{
const { rtnCode, body, commond } = JSON.parse(res.data)
if(rtnCode === '0000'){
@@ -597,6 +601,7 @@ const initsocketTask = async () => {
stdyBatch.value = body.stdyBatch || ''
logId.value = body.logId || ''
getGraphInfoUnStudy(1)
step.value = 2
}
}else{
// if(['0005', 'QQ0005'].includes(res.rtnCode)) {
@@ -622,13 +627,14 @@ onLoad((params) => {
crsNum.value = params.crsNum||'';
imageId.value = params.imgId || ''
startPgrphId.value = params.pgrphId||'';
getData('1');
console.log('onLoad')
});
const showTalkingModel = ref(false)
// 录音
// onMounted(()=>{
// getData('1');
// })
onMounted(()=>{
getData('1');
console.log('onMounted')
})
onHide(()=>{
if(watchFlag.value === 1) return
changePlayItemId('')
@@ -638,8 +644,9 @@ onHide(()=>{
}).finally(() => {})
})
onShow(()=>{
console.log('onShow')
if(watchFlag.value === 1) return
socketStore.createSocket()
getData('1');
})
const watchFlag = ref(1)
onUnload(()=>{
+74 -6
View File
@@ -15,9 +15,17 @@
<view class="btns-cont">
<view class="play-btn">
<image class="icon"
v-show="!isPlaying"
@click="playVoice"
src="@/static/images/course/play-blue.png"
style="width: 100%;height: 100%;"
></image>
<image class="icon"
v-show="isPlaying"
@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>
@@ -29,17 +37,16 @@
</text>
</view>
</view>
<view class="talking-info talking-info-text" v-else>
<view class="talking-cont">
<view class="talking-text translate-text" v-if="translateLoading">
<CommonLoading color="#fff"/>
</view>
<view class="talking-info talking-info-loading" v-else>
<view :class="['talking-gif']">
<CommonLoading color="#fff"/>
</view>
</view>
</template>
<script setup>
import { computed, ref, toRefs, watch } from "vue"
import { computed, unref, ref, toRefs, watch, onMounted } from "vue"
import { onUnload } from '@dcloudio/uni-app';
const props = defineProps({
dataInfo: {
default: () => ({}),
@@ -51,14 +58,75 @@
},
})
const { activeVoiceId, dataInfo } = toRefs(props)
const emit = defineEmits(['changePlay'])
watch(() => props.dataInfo, () => {},{deep: true,immediate: true})
// 声音播放初始化
const talkVoiceObj = ref(null)
const voiceLoading = ref(false)
const translateLoading = ref(false)
const voiceTime = ref('')
const itemVoice = ref('')
const showContent = computed(()=>{
return dataInfo.value.talkingText || ''
})
onMounted(()=>{
initVoice()
})
onUnload(()=>{
pauseVoice()
})
const pauseVoice = () => {
if(!talkVoiceObj.value) return
talkVoiceObj.value.pause()
emit('changePlay', '')
}
const playVoice = () =>{
emit('changePlay', unref(dataInfo)?.id)
if(talkVoiceObj.value.src && talkVoiceObj.value.src === itemVoice.value) {
talkVoiceObj.value.play()
return
}
talkVoiceObj.value.src = ''
if(itemVoice.value){
setTimeout(()=>{
talkVoiceObj.value.src = itemVoice.value
talkVoiceObj.value.play()
},100)
}
}
const initVoice = () => {
if(unref(dataInfo).talkingVoice){
talkVoiceObj.value = uni.createInnerAudioContext()
talkVoiceObj.value.onEnded(()=>{
emit('changePlay', '')
talkVoiceObj.value.src = ''
})
talkVoiceObj.value.onError(()=>{
talkVoiceObj.value.src = ''
})
itemVoice.value = unref(dataInfo).talkingVoice
talkVoiceObj.value.src = itemVoice.value
setTimeout(()=>{
setVoiceTime(0)
},100)
}
}
const setVoiceTime = (sum) => {
sum += 1
if(talkVoiceObj.value.duration){
voiceTime.value = ( Math.ceil(talkVoiceObj.value.duration) || 0 ) + 's'
}else{
if(sum === 10) {
voiceTime.value = 0 + 's'
return
}
setTimeout(()=>{
setVoiceTime(sum)
},200)
}
}
</script>
<style scoped lang="scss">
+8 -1
View File
@@ -1,6 +1,10 @@
<template>
<view class="talking-item">
<questionVue v-if="talkingType === 'question'" :dataInfo="talkingInfo"></questionVue>
<questionVue
v-if="talkingType === 'question'"
@changePlay="changePlay"
:dataInfo="talkingInfo"
></questionVue>
<answerVue
v-else-if="talkingType === 'answer'"
:dataInfo="props.talkingInfo"
@@ -31,6 +35,9 @@
const handleEvents = (type) => {
emit('handleEvents', type, props.talkingInfo)
}
const changePlay = (id) => {
emit('handleEvents', 'changePlay', props.talkingInfo, id)
}
</script>
<style >
+27 -6
View File
@@ -166,6 +166,7 @@ import {
})
unref(SocketObj).on('message', (res)=>{
const { rtnCode, body, commond } = JSON.parse(res.data)
let _id = new Date().getTime() + 'id'
if(rtnCode === '0000'){
if(commond === 'ASK-OPEN'){
// console.log('链接成功!')
@@ -185,12 +186,17 @@ import {
}
if(commond === 'ASK'){
console.log('发送问题成功!')
if((talkingList.value.length > 0) && talkingList.value[talkingList.value.length-1].isLoading){
talkingList.value.pop()
}
seqNo.value = body.seqNo
touchBtnCallBack.value && touchBtnCallBack.value()
touchBtnCallBack.value = null
talkingList.value.push({
type: 'question',
talkingText: body.intrctContent,
isLoading: false,
id: _id,
...body
})
return
@@ -204,19 +210,22 @@ import {
return
}
if(commond === 'ASK-ANSWER'){
console.log('开始回答!')
if(body.event === 'start'){
console.log('开始回答!')
answerIsOver.value = false
answerText.value = ''
talkingList.value.push({
type: 'answer',
talkingText: answerText.value,
isLoading: false,
id: _id,
...body
})
}else if(body.event === 'token'){
answerIsOver.value = false
answerText.value += body.data
}else if(body.event === 'end'){
console.log('完成回答!')
answerIsOver.value = true
}
return
@@ -236,7 +245,7 @@ import {
}
if(commond === 'ASK-ERR'){
console.log('操作异常!')
console.log('提问失败,系统异常!')
return
}
}else{
@@ -270,7 +279,7 @@ import {
}
const stopAnswerCallBack = ref(null)
const talkItemEvents = (type, data) => {
const talkItemEvents = (type, data, id = '') => {
switch (type){
case 'reAnswer':
console.log('重新获取数据')
@@ -302,6 +311,9 @@ import {
}
})
break;
case 'changePlay':
console.log('播放/暂停')
break;
default:
break;
}
@@ -333,7 +345,8 @@ import {
//#ifdef APP-PLUS
talkingList.value.push({
type: 'question',
talkingText: ''
talkingText: '',
isLoading: true
})
scrollToBottomNow()
commonUploadVoiceFile(voicePath, '/traask/traAskchat/voiceTrans', {}).then(res=>{
@@ -345,7 +358,7 @@ import {
intrctContent: _res.body.transContent,
bucketKey: _res.body.fileId,
ossFileAddr: _res.body.ossFileAddr,
voicePath: voicePath
talkingVoice: voicePath
}
sendMessage({
"commond" : 'ASK',
@@ -401,9 +414,17 @@ import {
})
onShow(()=>{
if(watchFlag.value === 1) return
socketStore?.createSocket()
socketStore?.createSocket?.()
sendMessage({
"commond" : 'ASK-START',
"body" : {
mascotId: mascotId.value,
deviceImei: ''
}
})
})
onUnload(()=>{
watchFlag.value = 1
socketStore?.closeSocket()
})
</script>