| @@ -7,4 +7,4 @@ | |||
| justify-content: space-between; | |||
| padding: 200rpx 0; | |||
| box-sizing: border-box; | |||
| } | |||
| } | |||
| @@ -6,7 +6,11 @@ Page({ | |||
| */ | |||
| data: { | |||
| chatList: [], | |||
| message: "" | |||
| message: "", | |||
| waitingMessage: "", | |||
| isResponing: false, | |||
| reLoadSocket: false, | |||
| messageFlag: true | |||
| }, | |||
| /** | |||
| @@ -23,18 +27,84 @@ Page({ | |||
| }, | |||
| send() { | |||
| if (!this.data.message) return | |||
| // 当socket连接被关闭时,重新连接socket | |||
| if (this.data.reLoadSocket) { | |||
| this.socketLink() | |||
| this.setData({ | |||
| waitingMessage: this.data.message | |||
| }) | |||
| } | |||
| const data = { | |||
| message: this.data.message | |||
| message: this.data.message, | |||
| id: 1 // 带id为用户发送的讯息,不带则为服务器返回的讯息 | |||
| } | |||
| const arr = this.data.chatList | |||
| arr.push(data) | |||
| // 非重载状态下向服务器发送讯息 | |||
| if (!this.data.reLoadSocket) { | |||
| this.socketSend(this.data.message) | |||
| } | |||
| this.setData({ | |||
| chatList: arr, | |||
| message: '' | |||
| message: '', | |||
| messageFlag: true | |||
| }) | |||
| console.log(this.data.chatList, 'chatList'); | |||
| }, | |||
| // 打招呼信息 | |||
| sayHello(message) { | |||
| const messageArr = message.split(',') | |||
| const len = messageArr.length | |||
| let msg = '' | |||
| let i = 0; | |||
| let timer = setInterval(() => { | |||
| const arr = this.data.chatList | |||
| arr.splice(arr.length - 1, '1') | |||
| msg += i + 1 == len ? messageArr[i] : messageArr[i] + ','; | |||
| const data = { | |||
| message: msg | |||
| } | |||
| arr.push(data) | |||
| this.setData({ | |||
| chatList: arr, | |||
| }) | |||
| if (i + 1 == len) { | |||
| clearInterval(timer); | |||
| } else { | |||
| i++; | |||
| } | |||
| }, 150); | |||
| }, | |||
| // 插入的信息,高频触发,每一次返回插入一条信息 | |||
| messageIn(message) { | |||
| // 第一次触发 | |||
| const tempArr = this.data.chatList | |||
| if (this.data.messageFlag) { | |||
| const data = { message } | |||
| tempArr.push(data) | |||
| this.setData({ | |||
| chatList: tempArr, | |||
| messageFlag: false | |||
| }) | |||
| } else { | |||
| tempArr[tempArr.length - 1].message += message | |||
| this.setData({ | |||
| chatList: tempArr | |||
| }) | |||
| } | |||
| }, | |||
| // 进行socket连接 | |||
| socketLink() { | |||
| const that = this | |||
| wx.connectSocket({ | |||
| url: 'wss://gptsockettest.malls.iformall.com:8010', | |||
| header: { | |||
| @@ -42,9 +112,67 @@ Page({ | |||
| }, | |||
| success: function (res) { | |||
| console.log(res) | |||
| if (!that.data.reLoadSocket) { | |||
| that.sayHello('Hello,我是GPT-Agent,你可以和我聊天,😘😘😘(出现这条消息,则WebSocket连接已成功)') | |||
| } | |||
| if (that.data.waitingMessage) { | |||
| that.socketSend(that.data.waitingMessage) | |||
| that.setData({ | |||
| reLoadSocket: false | |||
| }) | |||
| } | |||
| wx.onSocketClose(() => { | |||
| console.log('连接已丢失!'); | |||
| that.setData({ | |||
| reLoadSocket: true | |||
| }) | |||
| }) | |||
| }, | |||
| fail: function (err) { | |||
| console.log(err) | |||
| }, | |||
| complete: function (info) { | |||
| console.log(info) | |||
| } | |||
| }) | |||
| }, | |||
| socketSend(data) { | |||
| const that = this | |||
| const msgArr = [] | |||
| wx.sendSocketMessage({ | |||
| data: data, | |||
| success: function (res) { | |||
| console.log(res) | |||
| wx.onSocketMessage(data => { | |||
| const msgBack = data.data | |||
| console.log(msgBack); | |||
| if (msgBack == '___talk_end___') { | |||
| that.setData({ | |||
| isResponing: false | |||
| }) | |||
| setTimeout(() => { | |||
| console.log('当前会话已关闭'); | |||
| // wx.showToast({ | |||
| // title: '当前会话已关闭', | |||
| // icon: 'error' | |||
| // }) | |||
| }, 10000); | |||
| } else { | |||
| that.messageIn(msgBack) | |||
| that.setData({ | |||
| isResponing: true | |||
| }) | |||
| } | |||
| }) | |||
| }, | |||
| fail: function (err) { | |||
| console.log(err) | |||
| }, | |||
| complete: function (info) { | |||
| console.log(info) | |||
| } | |||
| }) | |||
| }, | |||
| @@ -1,4 +1,5 @@ | |||
| { | |||
| "navigationBarTitleText": "聊天", | |||
| "navigationBarBackgroundColor": "#f0f0f0", | |||
| "usingComponents": {} | |||
| } | |||
| @@ -1,29 +1,106 @@ | |||
| /* pages/chat/chat.wxss */ | |||
| page { | |||
| background-color: #f0f0f0; | |||
| } | |||
| @keyframes rotation { | |||
| from { | |||
| -webkit-transform: rotate(0deg); | |||
| } | |||
| to { | |||
| -webkit-transform: rotate(360deg); | |||
| } | |||
| } | |||
| .content { | |||
| padding: 0 50rpx; | |||
| padding: 50rpx 50rpx; | |||
| padding-bottom: 150rpx; | |||
| .chatItem { | |||
| margin-bottom: 20rpx; | |||
| margin-bottom: 40rpx; | |||
| .chatContent { | |||
| position: relative; | |||
| &.left { | |||
| text-align: left; | |||
| } | |||
| &.right { | |||
| text-align: right; | |||
| } | |||
| .chatGpt { | |||
| position: absolute; | |||
| top: 0; | |||
| left: -25rpx; | |||
| height: 100rpx; | |||
| border-radius: 50% 50%; | |||
| &.isResponing { | |||
| animation: rotation 2s linear infinite; | |||
| } | |||
| } | |||
| .message { | |||
| position: relative; | |||
| display: inline-block; | |||
| max-width: 450rpx; | |||
| text-align: left; | |||
| &.left { | |||
| left: 100rpx; | |||
| color: #000000; | |||
| background-color: #ffffff; | |||
| padding: 20rpx; | |||
| border-radius: 20rpx; | |||
| } | |||
| &.right { | |||
| right: 100rpx; | |||
| color: #ffffff; | |||
| background-color: #07c160; | |||
| padding: 20rpx; | |||
| border-radius: 20rpx; | |||
| } | |||
| } | |||
| .userAvatar { | |||
| position: absolute; | |||
| top: 0; | |||
| right: -25rpx; | |||
| height: 100rpx; | |||
| border-radius: 50% 50%; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| .chatBox { | |||
| position: fixed; | |||
| bottom: 100rpx; | |||
| width: 100%; | |||
| height: 120rpx; | |||
| bottom: 0; | |||
| padding-left: 40rpx; | |||
| padding-top: 20rpx; | |||
| background-color: #f5f5f5; | |||
| .inputBox { | |||
| display: inline-block; | |||
| width: 500rpx; | |||
| border: 1px solid #000; | |||
| height: 60rpx; | |||
| border-radius: 10rpx; | |||
| margin-right: 15rpx; | |||
| padding-left: 10rpx; | |||
| background-color: #ffffff; | |||
| } | |||
| .sendBtn { | |||
| display: inline-block; | |||
| width: 150rpx; | |||
| height: 60rpx; | |||
| line-height: 50rpx; | |||
| padding: 5rpx 0; | |||
| } | |||
| } | |||
| @@ -1,7 +1,11 @@ | |||
| <!--pages/chat/chat.wxml--> | |||
| <view class="content"> | |||
| <view class="chatItem" wx:for="{{chatList}}" wx:key="index"> | |||
| 我: {{item.message}} | |||
| <view class="{{item.id == 1 ? 'chatContent right' : 'chatContent left'}}"> | |||
| <image class="{{isResponing ? 'chatGpt isResponing' : 'chatGpt'}}" wx:if="{{!item.id}}" src="../../asset/icon/chatGpt.png" mode="heightFix" /> | |||
| <text class="{{item.id == 1 ? 'message right' : 'message left'}}">{{item.message}}</text> | |||
| <image class="userAvatar" wx:if="{{item.id && item.id == 1}}" src="../../asset/icon/user.png" mode="heightFix" /> | |||
| </view> | |||
| </view> | |||
| </view> | |||
| @@ -32,15 +32,18 @@ Page({ | |||
| wx.getUserProfile({ | |||
| desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写 | |||
| success: (res) => { | |||
| console.log(res) | |||
| this.setData({ | |||
| userInfo: res.userInfo, | |||
| hasUserInfo: true | |||
| }) | |||
| console.log(res, 'getUserProfile') | |||
| } | |||
| }) | |||
| }, | |||
| // 跳转至购买历史页面 | |||
| checkPayHistory() { | |||
| wx.navigateTo({ | |||
| url: '/pages/payHistory/payHistory', | |||
| }) | |||
| }, | |||
| // 获取手机号授权 | |||
| getUserPhone(e) { | |||
| const sessionKey = wx.getStorageSync('sessionKey') | |||
| @@ -6,18 +6,20 @@ | |||
| height: 120rpx; | |||
| line-height: 120rpx; | |||
| text-align: center; | |||
| color: #ffffff; | |||
| color: #838383; | |||
| font-size: 50rpx; | |||
| background-color: red; | |||
| font-weight: 600; | |||
| margin: auto; | |||
| border-bottom: 1px solid #000; | |||
| } | |||
| .introduction { | |||
| width: 600rpx; | |||
| height: 900rpx; | |||
| background-color: #79f779; | |||
| margin: 50rpx auto; | |||
| padding-top: 20rpx; | |||
| border: 1px dashed #747474; | |||
| border-radius: 60rpx; | |||
| .title { | |||
| text-align: center; | |||
| @@ -28,18 +30,52 @@ | |||
| .contain { | |||
| width: 500rpx; | |||
| height: 650rpx; | |||
| background-color: #00ffc8; | |||
| height: 600rpx; | |||
| font-size: 30rpx; | |||
| color: #585858; | |||
| text-indent: 1cm; | |||
| margin: auto; | |||
| padding-top: 20rpx; | |||
| padding: 20rpx; | |||
| } | |||
| .chatGptICon { | |||
| position: relative; | |||
| text-align: center; | |||
| image { | |||
| position: absolute; | |||
| left: 50%; | |||
| top: 50%; | |||
| transform: translate(-50%, 50%); | |||
| width: 80rpx; | |||
| } | |||
| } | |||
| .notice { | |||
| text-indent: 44rpx; | |||
| font-size: 22rpx; | |||
| color: #929292; | |||
| padding: 0 50rpx; | |||
| margin-top: 30rpx; | |||
| } | |||
| } | |||
| .buttons { | |||
| .userPhone { | |||
| text-align: center; | |||
| margin-bottom: 25rpx; | |||
| margin-bottom: 15rpx; | |||
| color: #929292; | |||
| } | |||
| .payHistory { | |||
| text-align: center; | |||
| color: #929292; | |||
| text-decoration: underline; | |||
| margin-bottom: 15rpx; | |||
| } | |||
| button { | |||
| border-radius: 30rpx; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,11 +1,26 @@ | |||
| <!--index.wxml--> | |||
| <view class="content"> | |||
| <view class="logo"> | |||
| GPT-Agent | |||
| 𝑮𝑷𝑻-𝑨𝒈𝒆𝒏𝒕 | |||
| </view> | |||
| <view class="introduction"> | |||
| <view class="title">简介</view> | |||
| <view class="contain">正文部分</view> | |||
| <view class="title">欢迎使用𝑮𝑷𝑻</view> | |||
| <view class="contain"> | |||
| <view> | |||
| ChatGPT是一个基于大规模预训练语言模型的对话系统,由OpenAI开发。 | |||
| </view> | |||
| <view> | |||
| 它的核心技术是GPT模型,英文全称为(Generative Pre-trained Transformer)是一种基于深度学习的自然语言处理技术。GPT模型采用Transformer架构,利用无监督学习从大规模语料库中学习语言知识,具有强大的语言理解和生成能力。 | |||
| </view> | |||
| <view> | |||
| ChatGPT将GPT模型应用于对话生成,可以进行自然流畅的对话,具有人类般的语言交互能力。 | |||
| </view> | |||
| <view class="chatGptICon"> | |||
| <image src="../../asset/icon/chatGpt.png" mode="widthFix" /> | |||
| </view> | |||
| </view> | |||
| <view class="notice">严格遵守国家法律法规,自觉遵守中国互联网协会《文明上网自律公约》,不发布危害国家安全、违反法律法规、影响社会和谐稳定的有害信息</view> | |||
| </view> | |||
| <view class="buttons"> | |||
| <block wx:if="{{!userInfo.phone}}"> | |||
| @@ -13,10 +28,14 @@ | |||
| </block> | |||
| <block wx:if="{{userInfo.isMember == 1 && userInfo.isValid == 1}}"> | |||
| <view class="userPhone">当前用户:{{userInfo.phone}}</view> | |||
| <view class="payHistory" bindtap="checkPayHistory">购买历史</view> | |||
| <button type="primary" bindtap="goToChat">开始聊天</button> | |||
| </block> | |||
| <block wx:if="{{userInfo.isMember == 1 && userInfo.isValid == 0}}"> | |||
| <view class="userPhone">当前用户:{{userInfo.phone}}</view> | |||
| <view class="payHistory" bindtap="checkPayHistory">购买历史</view> | |||
| <button type="primary" bindtap="goToBuy">续费会员</button> | |||
| </block> | |||
| @@ -8,44 +8,9 @@ Page({ | |||
| */ | |||
| data: { | |||
| userInfo: {}, | |||
| orderList: [ | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: true | |||
| }, | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: false | |||
| }, | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: false | |||
| }, | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: false | |||
| }, | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: false | |||
| }, | |||
| { | |||
| salePrice: '¥30', | |||
| orignPrice: '¥60', | |||
| effectiveTime: '30', | |||
| show: false | |||
| }, | |||
| ] | |||
| salePrice: '', | |||
| price: '', | |||
| days: '' | |||
| }, | |||
| /** | |||
| @@ -55,6 +20,23 @@ Page({ | |||
| this.setData({ | |||
| userInfo: JSON.parse(options.userInfo) | |||
| }) | |||
| this.getProductDetail() | |||
| }, | |||
| getProductDetail() { | |||
| const that = this | |||
| request.get({ | |||
| url: '/api/product/detail', | |||
| }).then(res => { | |||
| console.log(res, 'getProductDetail'); | |||
| that.setData({ | |||
| salePrice: res.data.salePrice, | |||
| price: res.data.price, | |||
| days: res.data.days, | |||
| }) | |||
| }).catch(err => { | |||
| console.log(err, 'err'); | |||
| }) | |||
| }, | |||
| createPayOrder() { | |||
| @@ -85,8 +67,14 @@ Page({ | |||
| setTimeout(() => { | |||
| wx.showToast({ | |||
| title: '支付成功', | |||
| icon: 'success' | |||
| icon: 'success', | |||
| duration: 2000 | |||
| }) | |||
| setTimeout(() => { | |||
| wx.navigateTo({ | |||
| url: '/pages/payHistory/payHistory', | |||
| }) | |||
| }, 2000); | |||
| wx.hideLoading(); | |||
| }, 2000); | |||
| }, | |||
| @@ -104,13 +92,6 @@ Page({ | |||
| }); | |||
| }, | |||
| // 跳转至购买历史页面 | |||
| checkPayHistory() { | |||
| wx.navigateTo({ | |||
| url: '/pages/payHistory/payHistory', | |||
| }) | |||
| }, | |||
| /** | |||
| * 生命周期函数--监听页面初次渲染完成 | |||
| */ | |||
| @@ -3,33 +3,78 @@ | |||
| .backGround { | |||
| position: relative; | |||
| width: 600rpx; | |||
| height: 200rpx; | |||
| line-height: 200rpx; | |||
| width: 650rpx; | |||
| height: 400rpx; | |||
| line-height: 150rpx; | |||
| color: #ffffff; | |||
| text-align: center; | |||
| font-size: 60rpx; | |||
| background-color: red; | |||
| margin: auto; | |||
| } | |||
| border-radius: 50rpx; | |||
| overflow: hidden; | |||
| .payHistory { | |||
| position: absolute; | |||
| right: 0; | |||
| bottom: -135rpx; | |||
| font-size: 25rpx; | |||
| color: #07c160; | |||
| image { | |||
| position: absolute; | |||
| top: 0; | |||
| left: 50%; | |||
| transform: translateX(-50%); | |||
| width: 100%; | |||
| height: 100%; | |||
| } | |||
| } | |||
| // .payHistory { | |||
| // position: absolute; | |||
| // right: 100rpx; | |||
| // top: 500rpx; | |||
| // font-size: 25rpx; | |||
| // color: #07c160; | |||
| // } | |||
| .orderList { | |||
| width: 600rpx; | |||
| margin: 50rpx auto; | |||
| position: relative; | |||
| text-align: center; | |||
| margin: auto; | |||
| .payInfo { | |||
| width: 550rpx; | |||
| height: 200rpx; | |||
| border: 1px dashed #9f9b88; | |||
| border-radius: 30rpx; | |||
| background-color: #f7f7f7; | |||
| margin: 50rpx auto; | |||
| .saleInfo { | |||
| font-size: 45rpx; | |||
| margin-top: 25rpx; | |||
| .salePrice { | |||
| font-size: 55rpx; | |||
| color: #ff0000; | |||
| font-weight: 600; | |||
| margin-right: 10rpx; | |||
| } | |||
| .price { | |||
| font-size: 42rpx; | |||
| text-decoration: line-through; | |||
| } | |||
| } | |||
| .validInfo { | |||
| margin-top: 15rpx; | |||
| .day { | |||
| font-size: 40rpx; | |||
| color: #ff0000; | |||
| font-weight: 600; | |||
| } | |||
| } | |||
| } | |||
| .btn { | |||
| display: inline-block; | |||
| width: 280rpx; | |||
| margin-right: 22rpx; | |||
| margin-top: 20rpx; | |||
| border-radius: 30rpx; | |||
| } | |||
| } | |||
| } | |||
| @@ -1,17 +1,23 @@ | |||
| <!--pages/payOrder.wxml--> | |||
| <view class="content"> | |||
| <view class="backGround"> | |||
| <text>购买会员</text> | |||
| <view class="payHistory" bindtap="checkPayHistory">购买历史</view> | |||
| <image src="../../asset/image/payOrder.png" mode="" /> | |||
| </view> | |||
| <view class="orderList"> | |||
| <block wx:for="{{orderList}}" wx:key="index"> | |||
| <button class="btn" type="primary" disabled="{{!item.show}}" bindtap="createPayOrder"> | |||
| <view>售价:{{item.salePrice}}</view> | |||
| <view>原价:{{item.orignPrice}}</view> | |||
| <view>时长:{{item.effectiveTime}}天</view> | |||
| </button> | |||
| </block> | |||
| <view class="payInfo"> | |||
| <view class="saleInfo"> | |||
| 售价: | |||
| <text class="salePrice">{{salePrice / 100 }}</text> | |||
| <text class="price">{{price / 100}}</text> | |||
| 元 | |||
| </view> | |||
| <view class="validInfo"> | |||
| 有效期:自购买日起 | |||
| <text class="day">{{days}}</text> | |||
| 天 | |||
| </view> | |||
| </view> | |||
| <button class="btn" type="primary" bindtap="createPayOrder">立即购买</button> | |||
| </view> | |||
| </view> | |||
| @@ -15,6 +15,13 @@ | |||
| "query": "", | |||
| "launchMode": "default", | |||
| "scene": null | |||
| }, | |||
| { | |||
| "name": "", | |||
| "pathName": "pages/payOrder/payOrder", | |||
| "query": "", | |||
| "launchMode": "default", | |||
| "scene": null | |||
| } | |||
| ] | |||
| } | |||