@@ -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 | |||
} | |||
] | |||
} | |||