DESKTOP-SVI9JE1\muzen 1 éve
szülő
commit
ad2f66e847
1 módosított fájl, 156 hozzáadás és 239 törlés
  1. 156 239
      pages/main/index.vue

+ 156 - 239
pages/main/index.vue

@@ -1,87 +1,75 @@
 <template>
-	<view>
-		<cu-custom bgColor="bg-cyan" :isBack="$squni.getPrePage() != null">
-			<block slot="backText">返回</block>
-			<block slot="content">AirSmartChat</block>
-		</cu-custom>
-		<view class="cu-chat">
-			<block v-for="(x,i) in msgList" :key="i">
-				<!-- 用户消息 -->
-				<view v-if="x.my && x.type === 'msg'" class="cu-item self"
-					:class="[i === 0 ? 'first' : '', i === 1 ? 'sec' : '']">
-					<view class="main">
-						<view class="content bg-cyan shadow"><!-- @click="x.msg && $squni.copy(x.msg)" -->
-							<text>{{ x.msg }}</text>
+	<view class="w100 h100 flex">
+		<!-- 侧边栏 -->
+		<navbar :chatAsset="chatAsset" @click="getInputList" @history="getHistory" @delete="msgList = []" />
+		<!-- 主体 -->
+		<view class="w100 relative">
+			<!-- 标题栏 -->
+			<view class="title w100 flex item-center content-center size-large">
+				{{ `AirSmartChat(${this.model})` }}
+			</view>
+			<!-- 			<view v-else class="flex item-center content-center p-10">
+				<view class="background-color-gray p-5 gap radius flex">
+					<button style="width: 400rpx;" v-for="item in chatgptVersion" :key="item"
+						:class="['change-button radius button-none', item === model ? 'background-color-white' : 'background-color-gray']"
+						@click="handleChangeVersion(item)">{{ item }}</button>
+				</view>
+			</view> -->
+			<!-- 聊天区 -->
+			<view class="chat size-large">
+				<block v-for="(x, i) in msgList" :key="i">
+					<!-- 用户消息 -->
+					<view v-if="x.my && x.type === 'msg'" class="chat-item " style="background-color: rgba(247,247,248,0.7);">
+						<view class="chat-content">
+							<view class="flex gap">
+								<img class="flex direction item-end" src="../../static/logo-100.png" width="24" height="24" />
+								<text>{{ x.msg }}</text>
+							</view>
 						</view>
 					</view>
-					<image class="cu-avatar round" src="/static/logo-100.png">
-						<view v-if="i === 0" class="date">{{ x.date }}</view>
-				</view>
-				<!-- AI消息 -->
-				<view v-if="!x.my && x.type === 'msg'" class="cu-item"
-					:class="[i === 0 ? 'first' : '', i === 1 ? 'sec' : '']">
-					<view class="flex flex-direction align-center">
-						<image class="cu-avatar round chat-avatar" src="/static/robot.png">
-							<text v-if="i === 0" class="cuIcon-title" :class="[statusColor]"></text>
+					<!-- AI消息 -->
+					<view v-if="!x.my && x.type === 'msg'" class="chat-item">
+						<view class="chat-content">
+							<view class="flex gap">
+								<img class="flex direction item-end" src="/static/chatgpt.png" width="24" height="24" />
+								<img v-if="x.pic" :src="x.msg" />
+								<text v-else>{{x.msg}}</text>
+								<uni-icons class="ml-auto cursor-pointer" type="download" color="#acacbe"
+									@click="x.msg && $squni.copy(x.msg)" />
+							</view>
+						</view>
 					</view>
-					<view class="main">
-						<view class="content shadow"><!-- @click="x.msg && $squni.copy(x.msg)" -->
-							<img v-if="x.pic" :src="x.msg" />
-							<text v-else>{{ x.msg }}</text>
+					<!-- 报错信息 -->
+					<view v-if="x.type === 'error'" class="chat-item">
+						<view class="chat-content flex gap item-center">
+							<text class="cuIcon-roundclosefill text-red"></text> {{ x.msg }}
 						</view>
 					</view>
-					<view v-if="i === 0" class="date">{{ x.date }}</view>
-				</view>
-				<view v-if="x.type === 'error'" class="cu-info">
-					<text class="cuIcon-roundclosefill text-red "></text> {{ x.msg }}
-				</view>
-			</block>
-
-			<view v-if="msgLoading" class="cu-item">
-				<view class="flex flex-direction align-center">
-					<image class="cu-avatar round chat-avatar" src="/static/robot.png">
+				</block>
+			</view>
+			<!-- 底部 -->
+			<view class="w100 p-20 absolute flex b0 direction item-center background-color-white" style="height: 180px">
+				<view class="w100">
+					<view class="list flex wrap gap">
+						<uni-transition v-for="item in inputTipList" :key="item.type" :duration="500" show
+							:mode-class="['fade', 'zoom-in']" @click="handleSendMsg(item)" :title="item.name"
+							custom-class="item box-shadow p-15 border-gray radius cursor-pointer space-nowrap overflow-ellipsis overflow-hidden hover">
+							{{ item.name }}
+						</uni-transition>
+					</view>
 				</view>
-				<view class="main">
-					<text class="cuIcon-loading2 cuIconfont-spin text-cyan"></text>
+				<!-- 输入框 -->
+				<view class="w100">
+					<view class="send-message relative box-shadow mt-10 radius border-gray">
+						<textarea class="w100" v-model="msg" auto-height maxlength="5000" cursor-spacing="10"
+							:adjust-position="false" :placeholder="loading ? 'AirSmart is loading...' : 'Send a message'"
+							@confirm="sendMsg" @input="handleInput" @keydown.tab.native.prevent="handleTab" />
+						<uni-icons class="send-btn absolute cursor-pointer" type="paperplane-filled" size="24"
+							:color="msg ? '#19c37d' : '#4559a480'" @click="sendMsg" />
+					</view>
 				</view>
 			</view>
 		</view>
-
-		<view class="cu-bar foot input" :style="[{bottom:inputBottom+'px'}]">
-			<view class="tip-box">
-				<button class="cu-btn round shadow sm cuIcon line-cyan" @click="startNewChat">
-					<text class="cuIcon-paint"></text>
-				</button>
-				<button class="cu-btn round shadow sm line-cyan"
-					@click="$squni.navigateTo('/pages/main/history')">历史消息</button>
-				<button class="cu-btn round shadow sm bg-orange"
-					@click="$squni.navigateTo('/pages/main/prompt/prompt')">提示词</button>
-				<button class="cu-btn round shadow sm line-cyan" @click="openBottomFunc">我的信息</button>
-			</view>
-			<!-- <view class="action func" @click="openBottomFunc">
-				<text class="cuIcon-list text-cyan" style="font-size: 60upx;"></text>
-			</view> -->
-			<view class="input-msg">
-				<ol class="tip-list">
-					<li class="tip-item" v-for="item in inputTipList" :key="item.type" @click="handleSendMsg(item)">
-						{{ item.name }}
-					</li>
-				</ol>
-				<input v-model="msg" class="solid padding-lr" :adjust-position="false" :focus="false" maxlength="5000"
-					cursor-spacing="10" :placeholder="loading ? '小AirSmart正在思考中,请稍后~' : '你可以问我任何问题或输入  “/”  获取模板'" @focus="inputFocus"
-					@blur="inputBlur" @confirm="sendMsg" @input="handleInput"></input>
-			</view>
-			<!-- <view class="action">
-				<text class="cuIcon-emojifill text-grey"></text>
-			</view> -->
-			<button class="cu-btn bg-cyan shadow" :disabled="loading" @click="sendMsg">
-				<text class="cuIcon-loading2 cuIconfont-spin"
-					v-if="loading || !ready"></text>{{ !ready ? '连接中' : '发送' }}
-			</button>
-		</view>
-
-		<bottom-func v-if="bottomFuncShow" ref="bottomFunc" :chatAsset="chatAsset"
-			@rewarded-video-ad="() => chatAsset.dfn += 2"></bottom-func>
 	</view>
 </template>
 
@@ -99,43 +87,27 @@
 		getUserChatAssetApi,
 		startNewChatApi,
 		findPromptListApi,
-		msgList,
-		sendMsgPic
+		sendMsgPic,
+		msgList
 	} from '@/api/chat.js'
-	import BottomFunc from './bottom-func'
-	const HELLO_MSG = {
-		type: 'msg',
-		my: false,
-		msg: '连接中,请稍后~',
-		date: dateFormat(new Date(), 'yyyy年MM月dd日 hh:mm')
-	}
 	export default {
-		components: {
-			BottomFunc
-		},
 		data() {
 			return {
 				loading: false,
 				userId: null,
-				msgList: [HELLO_MSG],
+				msgList: [],
 				msgContent: "",
 				msg: "",
 				msgType: 0,
-				inputBottom: 0,
-				bottomFuncShow: false,
 				chatAsset: {},
 				assetType: 'n',
-				statusColor: 'text-red',
-				statusTimer: null,
 				msgLoading: false,
 				promptId: null,
 				curPrompt: {},
-				inputTipList: []
-			}
-		},
-		computed: {
-			ready() {
-				return this.statusColor === 'text-green'
+				inputTipList: [],
+				model: 'gpt-4',
+				// chatgpt版本
+				chatgptVersion: ['gpt-3.5', 'gpt-4']
 			}
 		},
 		watch: {
@@ -147,17 +119,6 @@
 					}
 				}
 			},
-			statusColor(n, o) {
-				if (n === 'text-green') {
-					let prompt = ''
-					if (this.curPrompt && this.curPrompt.title) {
-						prompt = `(提示词:${this.curPrompt.title})`
-					}
-					HELLO_MSG.msg = '你好,我是AirSmartChat机器人,可以帮你解答疑惑或提供灵感' + prompt
-				} else {
-					HELLO_MSG.msg = '连接中,请稍后~'
-				}
-			}
 		},
 		async onShow() {
 			await this.$ready
@@ -193,7 +154,6 @@
 				}
 			})
 
-			this.heartStatus()
 			try {
 				//建立socket连接
 				websocket.connectSocket(this.$config.wssUrl + '/tools/chat/user/' + this.userId, msg => {
@@ -206,6 +166,13 @@
 				console.log('websocket connectSocket error:' + error)
 			}
 		},
+		onLoad() {
+			msgList().then(res => {
+				if (res.code === 20000) {
+					this.inputTipList = res.data
+				}
+			})
+		},
 		onHide() {
 			this.closeSocket()
 		},
@@ -241,37 +208,37 @@
 				this.putMsg(this.msg, true)
 				this.msgLoading = true
 				this.loading = true
-				
+
 				// ======== 开发环境模拟回复 ========
 				// return this.mockReply()
 				// ======== 开发环境模拟回复 ========
-				
+
 				if (this.calcAsset() === false) {
 					this.loading = false
 					return
 				}
-				
-				if(this.msgType === 2){
+
+				if (this.msgType === 2) {
 					sendMsgPic({
 						userId: this.$squni.getStorageSync('userId'),
 						question: msg,
 						type: this.msgType
 					}).then(res => {
-						if(res.code === 20000) {
+						if (res.code === 20000) {
 							JSON.parse(res.data.ack).map(i => {
 								this.putMsg(i.url, false, 'msg', true)
 								this.loading = false
 								this.msgLoading = false
 								this.msgType = 0
 							})
-						}else{
+						} else {
 							this.putMsgError('机器人被拔网线了,请稍后再试~')
 						}
 					})
-				}else{
+				} else {
 					// 发送消息: M1/M2
 					websocket.sendMessage(JSON.stringify({
-						model: 'M1',
+						model: this.model,
 						msg: msg,
 						platform: this.$squni.getStorageSync('platform'),
 						openid: this.$squni.getStorageSync('openid'),
@@ -304,7 +271,7 @@
 							if (msgJson.codeKey) {
 								content += `[${msgJson.codeKey}]`
 								if (msgJson.codeKey === 'chat.asset_short') {
-									this.openBottomFunc()
+
 								} else if (msgJson.codeKey.indexOf('chat.asset_') >= 0) {
 									this.chatAsset[this.assetType]++
 								}
@@ -327,35 +294,6 @@
 				this.msgList = [HELLO_MSG]
 				startNewChatApi()
 			},
-			// sendMsgBak() {
-			// 	let that = this
-			// 	if (this.msg == "") {
-			// 		return
-			// 	}
-			// 	this.msgContent += (this.userId + ":" + this.msg + "\n")
-			// 	this.putMsg(this.msg, true)
-			// 	this.loading = true
-
-			// 	// ======== 开发环境模拟回复 ========
-			// 	return this.mockReply()
-			// 	// ======== 开发环境模拟回复 ========
-
-			// 	sendMsgApi({
-			// 		userId: this.userId + '',
-			// 		question: this.msgContent
-			// 	}).then(({
-			// 		status,
-			// 		data
-			// 	}) => {
-			// 		if (status === 'success') {
-			// 			this.putMsg(data.ack, false)
-			// 			this.msgContent += ("openai:" + this.msg + "\n")
-			// 		} else {
-			// 			this.putMsg(res.message || '机器人开小差了,请稍后再试~', false, 'error')
-			// 		}
-			// 		that.loading = false
-			// 	})
-			// },
 			calcAsset() {
 				if (this.chatAsset.dfn > 0) {
 					this.chatAsset.dfn--
@@ -365,7 +303,6 @@
 					this.assetType = 'n'
 				} else {
 					this.$squni.toast('剩余次数不足')
-					this.openBottomFunc()
 					return false
 				}
 			},
@@ -418,52 +355,34 @@
 					})
 				}, 10000)
 			},
-			heartStatus() {
-				this.statusTimer = interval(() => {
-					if (websocket.isOpen) {
-						this.statusColor = 'text-green'
-					} else if (this.statusColor === 'text-red') {
-						this.statusColor = 'text-yellow'
-					} else {
-						this.statusColor = 'text-red'
-					}
-				}, this.statusTimer, 200)
-			},
 			closeSocket() {
 				websocket.closeSocket()
-				clearInterval(this.statusTimer)
-				this.statusColor = 'text-red'
-			},
-			inputFocus(e) {
-				this.inputBottom = e.detail.height
-			},
-			inputBlur(e) {
-				this.inputBottom = 0
 			},
 			// 对话输入框输入'/'显示提示信息
 			handleInput(e) {
-				if (e.detail.value.startsWith('/')) {
-					msgList().then(res => {
-						this.inputTipList = res.data
-					})
-				}else{
-					this.inputTipList = []
-				}
-				
-				if(e.detail.value === '') {
+				if (e.detail.value === '') {
 					this.msgType = 0
 				}
 			},
-			handleSendMsg(e){
+			// 支持tab输入空格
+			insertInputTxt(className, insertTxt) {
+				var elInput = document.getElementsByClassName(className)
+				var startPos = elInput[0].selectionStart
+				var endPos = elInput[0].selectionEnd
+				if (startPos === undefined || endPos === undefined) return
+				var txt = elInput[0].value
+				var result = txt.substring(0, startPos) + insertTxt + txt.substring(endPos)
+				this.msg = elInput[0].value = result
+				// elInput[0].focus()
+				// elInput[0].selectionStart = startPos + insertTxt.length
+				// elInput[0].selectionEnd = startPos + insertTxt.length
+			},
+			handleTab() {
+				this.insertInputTxt('uni-textarea-textarea', '\t')
+			},
+			handleSendMsg(e) {
 				this.msgType = e.type
 				this.msg = e.name
-				this.inputTipList = []
-			},
-			openBottomFunc() {
-				this.bottomFuncShow = true
-				this.$nextTick(() => {
-					this.$refs.bottomFunc.open()
-				})
 			},
 			mockReply() {
 				// 开发环境模拟回复
@@ -474,80 +393,78 @@
 					}, 1000)
 					return
 				}
+			},
+
+			getInputList(e) {
+				this.inputTipList = e
+				this.msgList = []
+			},
+
+			// 切換chatgpt版本
+			handleChangeVersion(e) {
+				this.model = e
+			},
+
+			getHistory(e) {
+				if (e) {
+					this.msgList = e.children
+				}
 			}
 		}
 	}
 </script>
 
-<style>
-	page {
-		padding-bottom: 220upx;
+<style lang="scss" scoped>
+	uni-page-body {
+		height: 100%;
+		background-color: #FFF;
 	}
 
-	.cu-chat .chat-avatar.cu-avatar {
-		width: 82upx;
-		height: 82upx;
+	.title {
+		height: 128rpx;
+		border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 	}
 
-	.cu-item:not(.first) {
-		padding-bottom: 0upx;
-	}
-
-	.cu-item.sec {
-		padding-top: 0upx;
-	}
+	.chat {
+		height: calc(100% - 245px);
+		overflow-y: auto;
 
-	.cu-chat .cu-item>.main {
-		max-width: calc(100% - 160upx);
-	}
+		.chat-item {
+			width: 100%;
+			border-bottom: 1px solid rgba(0, 0, 0, 0.1);
 
-	.main .content {
-		word-wrap: break-word;
-		cursor: text;
-		user-select: text;
-	}
+			.chat-content {
+				max-width: 1600rpx;
+				margin: 0 auto;
+				padding: 62rpx 40rpx;
+				cursor: text;
+				user-select: text;
+			}
 
-	.cu-bar.foot {
-		box-shadow: 0 -0.5px 1px rgba(0, 0, 0, 0.1);
-		align-items: flex-end;
+			.date {
+				margin-top: 10px;
+			}
+		}
 	}
 
-	.foot {
-		padding-top: 20upx;
-		padding-bottom: 60upx;
+	.item {
+		width: 24%;
 	}
 
-	.foot .cu-btn {
-		margin-right: 20upx;
-		width: 200upx;
+	.list,
+	.send-message {
+		max-width: 1560rpx;
+		margin: 10px auto 0;
 	}
 
-	.foot .action.func {
-		margin-left: 30upx;
+	uni-textarea {
+		padding: 15px 20px;
+		line-height: 1.6;
 	}
 
-	.foot .tip-box {
-		position: absolute;
-		top: -60upx;
-		margin: 0 30upx;
-	}
-	
-	.input-msg{
-		width: 100%;
-		.tip-list{
-			margin: 0 40upx;
-			padding: 0 40upx;
-			
-			.tip-item{
-				cursor: pointer;
-				color: #909399;
-				line-height: 64upx;
-			}
-			
-			.tip-item:hover{
-				background: #d9ecff;
-				color: #000;
-			}
-		}
+	.send-btn {
+		right: 30rpx;
+		top: 50%;
+		transform: translate(0, -50%) rotate(45deg);
 	}
 </style>