Bläddra i källkod

对话接口联调,流式接收

htc 1 vecka sedan
förälder
incheckning
5a04c43a46
2 ändrade filer med 115 tillägg och 32 borttagningar
  1. 105 22
      pages/dialog.vue
  2. 10 10
      pages/login.vue

+ 105 - 22
pages/dialog.vue

@@ -6,7 +6,7 @@
 				<image src="@/static/new_dialog.png" style="width: 42rpx;height: 42rpx;margin-left: 40rpx;" @tap="startNewDialog"></image>
 			</view>
 		</u-navbar>
-		<div class="dialogs container" ref="myContainer">
+		<div class="dialogs container" ref="messageContainer">
 			<div class="d_answer init">
 				<div class="da_top adfac">
 					<image src="@/static/logo.png"></image>
@@ -43,7 +43,7 @@
 		</div>
 		<div class="ask adfacjb">
 			<div class="a_l">
-				<input type="text" v-model="question" placeholder="请输入您的问题" @confirm="sendQuestion">
+				<input type="text" v-model="question" placeholder="请输入您的问题" @confirm="sendQuestion" ref="questionInp">
 			</div>
 			<image class="a_r" src="@/static/send.png" @tap="sendQuestion"></image>
 		</div>
@@ -73,12 +73,19 @@
 
 <script>
 	var timer = null;
+	let requestTask = null;
+	import { BaseApi } from '../http/baseApi.js'
 	import Tabbar from '@/components/CusTabbar/index.vue'
 	export default {
 		components:{ Tabbar },
 		data(){
 			return {
+				retryCount: 3, // 最大重试次数
+				currentRetry: 0, // 当前重试次数
+				isRequesting: false, // 请求状态锁
 				question:'',
+				streamingResponse:'',
+				receivedData:'',
 				dialogList:[],
 				windex:0,
 				commentShow:false,
@@ -111,23 +118,107 @@
 				clearInterval(timer)
 				this.dialogList = [];
 				this.question = '';
+				this.streamingResponse = '';
 			},
 			historyClose(){
 				this.historyShow = false;
 			},
+			// 封装带重试机制的请求方法
+			async sendRequestWithRetry() {
+				if (this.isRequesting) return;
+				this.isRequesting = true;
+				this.currentRetry = 0;
+				try {
+					await this._executeRequest();
+				} catch (error) {
+					  console.error('最终请求失败:', error);
+					  this.$showToast('请求失败,请稍后重试')
+				} finally {
+					this.isRequesting = false;
+				}
+			},
+			// 实际执行请求的方法
+			_executeRequest() {
+			    return new Promise((resolve, reject) => {
+					requestTask = uni.request({
+						url: `${BaseApi}/core/chat/streamingMessage`,
+						method: 'POST',
+						timeout: 10000,
+						data:{ 
+							query: this.question,
+							timestamp:Date.now()
+						},
+						header: {
+						  'Content-Type': 'application/json',
+						  'token': uni.getStorageSync('token') || ''
+						},
+						enableChunked: true, // 启用流式接收
+						responseType:'text',
+						success: (res) => {
+							if (res.statusCode === 200) {
+								this._handleSuccess(res.data);
+								resolve();
+							} else {
+								this._handleError(`状态码异常: ${res.statusCode}`, resolve, reject);
+							}
+						},
+						fail: (err) => {
+							this._handleError(err.errMsg, resolve, reject);
+						}
+					});
+					
+					requestTask.onChunkReceived(async (res) => {
+						const uint8Array = new Uint8Array(res.data);
+						const decoder = new TextDecoder("utf-8");
+						const decodedString = decoder.decode(uint8Array);
+						let newtext = decodedString.replaceAll('data:','')
+						newtext = newtext.replace(/\s+/g,'');
+						if(newtext){
+							let answer = this.dialogList[this.dialogList.length-1].answer+newtext;
+							this.$set(this.dialogList[this.dialogList.length-1],'answer',answer);
+							uni.pageScrollTo({
+							    scrollTop: 99999,
+							    duration: 300
+							});
+						}
+					});
+			    });
+			},
+			// 成功处理
+			_handleSuccess(data) {
+			    if (data) {
+			      this.streamingResponse += data;
+				  console.log(this.streamingResponse,'streamingResponse');
+			    }
+			    this.currentRetry = 0; // 重置重试计数器
+			},
+			// 错误处理
+			_handleError(errorMsg, resolve, reject) {
+			    console.error(`请求失败 (${this.currentRetry}/${this.retryCount}):`, errorMsg);
+			    if (this._shouldRetry(errorMsg)) {
+					this.currentRetry++;
+					setTimeout(() => {
+						this._executeRequest().then(resolve).catch(reject);
+					}, this._getRetryDelay());
+			    } else {
+					reject(errorMsg);
+			    }
+			},
+			// 判断是否需要重试
+			_shouldRetry(errorMsg) {
+			    const retryableErrors = [
+					'timeout', 
+					'request:fail', 
+					'Network Error'
+			    ];
+			    return this.currentRetry < this.retryCount && retryableErrors.some(e => errorMsg.includes(e));
+			},
+			// 获取指数退避延迟时间
+			_getRetryDelay() {
+			    return Math.min(1000 * Math.pow(2, this.currentRetry), 10000);
+			},
 			sendQuestion(){
 				if(!this.question) return this.$showToast('请输入问题');
-				let answer = `<div style="font-size: 30rpx;color: #252525;line-height: 54rpx;">
-								你好!请问你是想了解教练的相关信息,还是需要运动、健身或其他方面的指导呢?
-								无论是健身计划、技巧提升,还是职业教练的选择,我都可以为你提供建议。请告诉我你的具体需求,我会尽力帮助你!
-								<br><br>
-								例如:
-								<br><br>
-								<b>·健身教练:</b>想要制定增肌/减脂计划?<br>
-								<b>运动技巧:</b>想提升某项运动(如游泳、跑步)的水平?<br>
-								<b>职业教练:</b>如何考取教练资格证或选择靠谱的教练?<br>
-								期待你的详细需求!
-							</div>`;
 				let qa = {
 					question:JSON.parse(JSON.stringify(this.question)),
 					answer:'',
@@ -137,16 +228,8 @@
 					share:false,
 				}
 				this.dialogList = [...this.dialogList,...[qa]];
+				this.sendRequestWithRetry();
 				this.question = '';
-				timer = setInterval(()=>{
-					if(this.windex<answer.length){
-						this.windex+=1;
-						this.$set(this.dialogList[this.dialogList.length-1],'answer',answer.substring(0,this.windex));
-					}else{
-						this.windex = 0;
-						clearInterval(timer)
-					} 
-				},50)
 			},
 			toCopy(item,index){
 				this.$set(this.dialogList[index],'copy',!this.dialogList[index].copy);

+ 10 - 10
pages/login.vue

@@ -34,16 +34,16 @@
 		},
 		methods:{
 			decryptPhoneNumber(e){
+				if(uni.getStorageSync('token')){
+					uni.reLaunch({
+						url:'/pages/dialog'
+					})
+					return
+				}
 				if(e.detail.code) this.wxLogin(e.detail.code);
 			},
 			wxLogin(code){
-				uni.showLoading({ title:'登录中' });
-				this.$showToast('登录成功');
-				setTimeout(()=>{
-					uni.reLaunch({ url:'/pages/dialog' })
-				},1500)
-				
-				return
+				uni.showLoading({ title:'登录中' });
 				let that = this;
 				wx.login({
 					success(res){
@@ -57,10 +57,10 @@
 									id:res.data.data.id,
 									gender:res.data.data.gender,
 									realName:res.data.data.realName,
-									email:res.data.data.email,
+									mobile:res.data.data.mobile,
 									headUrl:res.data.data.headUrl,
-									roleCodes:res.data.data.roleCodes,
-									status:res.data.data.status
+									teamId:res.data.data.teamId,
+									enterpriseId:res.data.data.enterpriseId
 								}));
 								
 								uni.hideLoading();