当前位置:   article > 正文

uniapp renderjs使用 SSE方案_uniapp sse

uniapp sse

uniapp中renderjs使用主要解决在APP端无法使用web端的js问题
如果只开发web端就不用考虑renderjs 跨端app中可以使用,解决通信阻塞问题
这是一个在app端使用sse的方案
下面展示一些。

<template>
	<!-- #ifdef APP -->
	<page-meta :root-font-size="footSize" style="display: block;"></page-meta>
	<!-- #endif -->
	<view class="page-top">
		<!-- #ifdef APP -->
		<view class="status_bar">
			<view class="top_view"></view>
		</view>
		<!-- #endif -->
		<uni-nav-bar fixed class="nav-title" left-icon="back" :title="aiName" backgroundColor="#f8f8f8" @clickLeft="toPrev"></uni-nav-bar>
		<view class="cu-chat">
			<blockquote v-for="(item,index) in chatList" :key="item.id">
				<view class="cu-item" :class="{'self':item.self == 1}"  v-if="item.self == 1">
					<view class="main">
						<view class="content shadow">
							<text class="self-content">{{item.content}}</text>
						</view>
					</view>
					<view class="cu-avatar radius" :style="{'background-image': 'url('+item.avatarImg+')'}"></view>
				</view>
				<view class="cu-item" v-else>
					<view class="cu-avatar radius" :style="{'background-image': 'url('+item.avatarImg+')'}"></view>
					<view class="main">
						<view class="content shadow">
							<text class="self-content">{{item.content}}</text>
						</view>
						<view class="flex chat-tools" v-if="item.isEnd && !item.self">
							<view class="reloadContent cu-btn bg-blue sm" @click="reloadContent()" v-if="chatList.length == (index+1)">
								刷新
							</view>
							<view class="copyContent cu-btn bg-blue sm" @click="copyContentBtn(item.content)">
								复制
							</view>
						</view>
					</view>
				</view>
			</blockquote>	
		</view>
		<view class="cu-bar foot input">
			<input class="solid-bottom" :placeholder="placeholderStr"
			v-model="content"
				placeholder-class="input-placeholder" 
				:adjust-position="false" 
				:focus="false" 
				maxlength="2500" 
				cursor-spacing="10"></input>
			<button :prop="msg" :change:prop="renderScript.onChange" class="cu-btn bg-blue shadow" :disabled="ifSend" @click="sendMsg">发送</button>
		</view>
	</view>
</template>

<script>
	// import {BASE_URL} from '@/util/request.js'
	import {copyContent} from '@/util/tools.js'
	// import {EventSourcePolyfill} from 'event-source-polyfill'
	import avatarDef from '@/static/img/avatar_deft.png'
	import aislogo from '@/static/img/aislogo.png'
	export default {
		data() {
			return {
				footSize: this.$footFontSize,
				msg:{//监听msg中的变化去执行renderjs中的onchange方法
					userId:'',
					conversationId:'',
					renderContent:''
				},
				chatList:[],
				answerWords:[],
				eventSource:null,
				contentIdx:0,
				placeholderStr:'',
				aiLoadding:'',
				aiName:'',
				content:'',
				welcome:'',
				ifSend:false,
				conversationId:'',
				userId:'',
				quesId:'',
				quesIds:'',
				subjectId:'',
				planId:'',
				batchId:'',
				userPlanId:'',
				user:{
					nickName: '',
					avatar: avatarDef,
				},
				aiUser:{
					nickName: '',
					avatar: aislogo,
				}
			}
		},
		onLoad(options){
			this.quesId = options.quesID;
			this.quesIds = options.quesIds;
			this.subjectId = options.subjectId;
			this.planId = options.planId;
			this.batchId = options.batchId;
			this.userPlanId = options.userPlanId;
			let buffer = {
				quesId:this.quesId
			}
			var that = this;
			this.$myRequest({
				url:'/api/bot/conversation',
				method:'POST',
				data:{
					userPlanId:this.userPlanId,
					quesId:this.quesId,
					ran:Math.random()
				}
			}).then(res=>{
				that.welcome = res.data.welcome;
				that.conversationId = res.data.conversation_id;
				that.content = res.data.first_content;
				that.userId = res.data.userId;
				that.placeholderStr = res.data.placeholder;
				that.aiLoadding = res.data.aiLoadding;
				that.aiName = res.data.aiName;
				that.msg.userId = res.data.userId;
				that.msg.conversationId = res.data.conversation_id;
				that.msg.renderContent = res.data.first_content;
				that.firstChat();
			})
		},
		methods: {
			firstChat(){
				//首次进入在内容生成之前发送按钮不可使用
				this.ifSend = true;
				this.chatList.push({
					modelRole: this.aiUser.nickName,
					avatarImg: this.aiUser.avatar,
					self: 0,
					id: +new Date(),
					content: this.welcome,
					isEnd: false,
					isList:false
				})
				this.chatList.push({
					modelRole: this.user.nickName,
					avatarImg: this.user.avatar,
					self: 1,
					id: +new Date()+1,
					content: this.content,
					isEnd: false,
					isList:false
				})
				this.chatList.push({
					modelRole: this.aiUser.nickName,
					avatarImg: this.aiUser.avatar,
					self: 0,
					id: +new Date()+10,
					content: this.aiLoadding,
					isEnd: false,
					isList:false
				})
				this.content = '';
				this.scrollBottom(10000);
				//创建EventSource 并发起会话
				// this.eventSourceBox();
			},
			eventSourceBox(){
				let lastItem = this.chatList[this.chatList.length - 1];
				var that = this;
				const url = BASE_URL+"/stream-chat/chat.php?question="+encodeURIComponent(this.content.replace(/\+/g, '{[$add$]}'))+"&conversationId="+this.conversationId+"&userId="+this.userId;
				this.eventSource = new EventSourcePolyfill(url);
				this.eventSource.onopen = (event)=>{
					console.log("连接已建立");
				}
				this.content = '';
				lastItem.contentList = [];
				this.eventSource.onmessage = (event)=>{
					try {
						var result = JSON.parse(event.data);
						// console.log(result);
						if(result.time && result.content ){
							lastItem.isList = true;
							that.ifSend = true;//没有生成完毕禁止点击
							if(lastItem.content == this.aiLoadding){
								lastItem.content = '';
								lastItem.content += result.content;
							}else{
								lastItem.content += result.content;
							}
							that.contentIdx += 1;
							that.scrollBottom();
						}
					} catch (error) {
						console.log(error);
					}
				}
				// this.chatList[this.chatList.length - 1]['contentList'];
				this.eventSource.onerror = (event)=>{
					let lastItem = that.chatList[that.chatList.length - 1];
					this.eventSource.close();
					lastItem.isEnd = true;
					that.ifSend = false;
					console.log((new Date().getTime()), 'answer end error')
					// console.error("发生错误:", JSON.stringify(event));
					// console.error("发生错误:");
				}
				this.eventSource.onclose = (event)=>{
					let lastItem = that.chatList[that.chatList.length - 1];
					// console.log("连接已关闭", JSON.stringify(event.data));
					this.eventSource.close();
					isEnd = true;
					console.log((new Date().getTime()), 'answer end close');
				}
			},
			sendMsg(){
				if (!this.content) {
					return uni.showToast({
						title:'发送内容不能为空',
						icon:'none'
					});
				}
				this.chatList.push({
					modelRole: this.user.nickName,
					avatarImg: this.user.avatar,
					self: 1,
					id: +new Date()+1,
					content: this.content,
				})
				this.chatList.push({
					modelRole: this.aiUser.nickName,
					avatarImg: this.aiUser.avatar,
					self: 0,
					id: +new Date()+10,
					content: this.aiLoadding,
					isEnd: false,
					isList:false
				})
				this.ifSend = true;
				this.msg.renderContent = this.content;
				this.content = '';
				this.$nextTick(this.scrollBottom());
				//创建eventSource
				// this.eventSourceBox();
			},
			scrollBottom(height){
				const query = uni.createSelectorQuery().select('.page-top');
				query.boundingClientRect((data) => {
						let pageScrollTop = Math.round(data.height);
						if(height != undefined){
							pageScrollTop = height;
						}
						// console.log(pageScrollTop);
						setTimeout(() => {
							uni.pageScrollTo({
								scrollTop: pageScrollTop, //滚动的距离
								duration: 0, //过渡时间
							})
						},50)
					}).exec()
			},
			toPrev(){
				uni.reLaunch({
					url:'/pages/print/worksDetail/worksDetail?batchId='+this.batchId+'&subjectId=' + this.subjectId + "&quesIds=" + this.quesIds + "&planId=" + this.planId + '&userPlanId=' +this.userPlanId
				})
			},
			copyContentBtn(item){
				copyContent(item)
			},
			reloadContent(){
				let ques = this.chatList[this.chatList.length - 2]['content'];
				this.chatList[this.chatList.length - 1]['content'] = this.aiLoadding;
				this.chatList[this.chatList.length - 1]['isEnd'] = false;
				this.ifSend = true;
				// console.log(ques);
				this.msg.renderContent = '';
				this.msg.renderContent = ' '+ques;
				this.$nextTick(this.scrollBottom());
				// this.eventSourceBox();
			},
			// 接收renderjs发回的数据
			acceptDataFromRenderjs(options) {
				let lastItem = this.chatList[this.chatList.length - 1];
				this.ifSend = true;//没有生成完毕禁止点击
				if(lastItem.content == this.aiLoadding){
					lastItem.content = '';
					lastItem.content += options.messageData;
				}else{
					lastItem.content += options.messageData;
				}
				this.scrollBottom();
				// this.projNotices = JSON.parse(options.type)
			},
			acceptDataFromRenderjsEnd(options){
				let lastItem = this.chatList[this.chatList.length - 1];
				lastItem.isEnd = options.renderIsEnd;
				this.ifSend = options.renderIfSend;//没有生成完毕禁止点击
			}
		}
	}
</script>
<script module="renderScript" lang="renderjs">
	import {BASE_URL} from '@/util/request.js'
	import {EventSourcePolyfill} from 'event-source-polyfill'
	
	export default {
		data(){
			return {
				message:'',
				renderIsEnd:false,
				renderIfSend:false
			}
		},
		mounted() {
			
		},
		methods: {
			onChange(newValue, oldValue, ownerInstance, instance){
				if(newValue.userId != '' && newValue.conversationId != ''){
					this.sse(newValue.userId,newValue.conversationId,newValue.renderContent)
				}
			},
			// 发送数据到service层
			emitData() {
				// #ifdef APP
				UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
					cid: this._$id,
					method: 'acceptDataFromRenderjs',
					args: {
						messageData: this.messageData
					}
				})
				// #endif
				// #ifdef H5
				var options = {
					messageData:this.messageData
				};
				this.acceptDataFromRenderjs(options);
				// #endif
			},
			emitDataEnd(){
				// #ifdef APP
				UniViewJSBridge.publishHandler('onWxsInvokeCallMethod', {
					cid: this._$id,
					method: 'acceptDataFromRenderjsEnd',
					args: {
						renderIsEnd: this.renderIsEnd,
						renderIfSend:this.renderIfSend
					}
				})
				// #endif
				// #ifdef H5
				var options = {
					renderIsEnd: this.renderIsEnd,
					renderIfSend:this.renderIfSend
				};
				this.acceptDataFromRenderjsEnd(options);
				// #endif
			},
			sse(userId,conversationId,renderContent){
				// console.log(renderContent);
				let that = this;
				const url = BASE_URL+"/stream-chat/chat.php?question="+encodeURIComponent(renderContent.replace(/\+/g, '{[$add$]}'))+"&conversationId="+conversationId+"&userId="+userId;
				const eventSource = new EventSourcePolyfill(url);
				eventSource.onopen = (event)=>{
					console.log("连接已建立");
				}
				eventSource.onmessage = (event)=>{
					var result = JSON.parse(event.data);
					if(result.time && result.content ){
						that.messageData = '';
						that.messageData = result.content;
						that.emitData();
					}
				}
				eventSource.onerror = (event)=>{
					console.log((new Date().getTime()), 'answer end error')
					that.renderIsEnd = true;
					that.renderIfSend = false;
					that.emitDataEnd();
				}
				eventSource.onclose = (event)=>{
					// console.log("连接已关闭", JSON.stringify(event.data));
					eventSource.close();
					console.log((new Date().getTime()), 'answer end close');
				}
			}
		}
	}
</script>

<style lang="less">
	/* #ifdef APP */
	page {
		background-color: #F1F1F1;
	}
	/* #endif */
</style>
<style lang="less" scoped>
	/* #ifdef H5 */
	page {
		background-color: #F1F1F1;
	}
	/* #endif */
	
	/* #ifdef APP */
	.status_bar {
		height: var(--status-bar-height);
		width: 100%;
	}
	.top_view {  
	    height: var(--status-bar-height);  
	    width: 100%;
	    position: fixed;  
	    background-color: #F8F8F8;  
	    top: 0;  
	    z-index: 999;  
	} 
	/* #endif */
	.nav-title /deep/ .uni-nav-bar-text{
		font-size: 0.3rem;
		overflow: initial;
	}
	.cu-avatar{
		background-color: #ffffff !important;
	}
	.self-content{
		overflow: auto;
	}
	.main{
		flex-direction: column;
		align-items: flex-end !important;
	}
	.chat-tools{
		padding: 10rpx;
		justify-content: flex-end;
	}
	.chat-tools .cu-btn{
		border-radius: 10rpx;
		margin-left: 12rpx;
	}
</style>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/378468
推荐阅读
相关标签
  

闽ICP备14008679号