<scroll-view class="scroll-view" :scroll-y="true"
:scroll-top="scrollTop" :scroll-with-animation="true">
<view class="official-content">
<view class="title">
猜你想问
</view>
<view class="guess" v-for="(item,index) in guessList" :key='index' @click="sendMessage(item)">
{{item}}
</view>
<view class="title">
常见问题
</view>
<view class="list">
<view class="question flex-justify" v-for="(item,index) in questions" :key="index"
@click="sendMessage(item)">
<view>
{{item}}
</view>
<view class="right-arrow"></view>
</view>
</view>
<view class="message" v-if="messageList.length>0">
<view :class="{'text-right':1===item.source}" v-for="(item,index) in messageList"
:key="index">
<view class="time">{{$util.timeStampTurnTime(item.time,'hourMinute')}}</view>
<!-- 富文本 -->
<view :class="1===item.source?'request':'response'" v-html="item.text"
v-if="'RICH_TEXT'===item.contentType">
</view>
<!-- 猜你想问 -->
<view :class="1===item.source?'request':'response'"
v-else-if="'Recommend'===item.answerType">
<view class="recommend">
<view class="text">
{{item.text}}
</view>
<view class="info" @click="sendMessage(recommend.title)"
v-for="(recommend,rindex) in item.recommends" :key="rindex">
{{recommend.title}}
</view>
</view>
</view>
<!-- 卡片 -->
<view :class="1===item.source?'request':'response'"
v-else-if="'CARD_TEMPLATE'===item.contentType">
<!-- 人物卡片 -->
<view class="qa-tabs" v-if="'qa-tabs'===item.cardType">
<view class="img">
<image :src="item.avatar" mode="widthFix"></image>
<view class="name">
{{item.name}}
</view>
</view>
<view class="tabs">
<view class="item" :class="{'active':tabIndex===tindex}"
v-for="(tab,tindex) in item.tabs" :key='tindex'
@click="tabChange(tab.url,index)">
{{tab.name}}
</view>
</view>
<view class="text">
{{item.tabs[tabIndex].content}}
</view>
</view>
<!-- 短分点卡片 -->
<view class="qa-list" v-if="'qa-list'===item.cardType">
<view class="qa-list-item" v-for="($list,lindex) in item.list" :key='lindex'>
<view class="qa-list-title flex-align"><text></text> {{$list.title}}</view>
<view class="content">
{{$list.content}}
</view>
</view>
</view>
<!-- 长卡片 -->
<view class="qa-collapse-list" v-if="'qa-collapse-list'===item.cardType">
<view class="qa-collapse-list-item" v-for="($list,lindex) in item.list"
:key='lindex' @click="openPopup($list)">
<text class="down-arrow"></text> {{$list.title}}
</view>
</view>
<!-- 表格 -->
<view class="qa-table" v-if="'qa-table'===item.cardType">
<view>{{item.title}}</view>
<view class="qa-table-item flex-align" v-for="($list,lindex) in item.list"
:key='lindex'>
<view>{{$list.title}}</view>
<view>{{$list.content}}</view>
</view>
</view>
<!-- 流程 -->
<view class="qa-progress" v-if="'qa-progress'===item.cardType">
<view>{{item.title}}</view>
<view class="detail mb-3 pl-5" v-for="($list,lindex) in item.list"
:key="lindex">
<view>
{{ $list.title }}
</view>
<view>
{{ $list.desc }}
</view>
</view>
</view>
<!-- 快捷回复 -->
<view class="qa-slot" v-if="'slot'===item.cardType">
<view class="content text-ellipsis">{{item.content}}</view>
<view class="flex-wrap">
<view class="item flex-resize" v-for="($list,lindex) in item.list"
:key="lindex" @click="sendMessage($list.title)">
<view>
{{ $list.title }}
</view>
<view class="font-size-center-10">
{{ $list.desc }}
</view>
</view>
</view>
</view>
<!-- 图文按钮 -->
<view class="adaptable-action-card" v-if="'adaptable-action-card'===item.cardType">
<image :src="item.picUrl" mode="widthFix"></image>
<view class="p-5">
<view class="adaptable-action-card-title">{{item.title}}</view>
<view class="adaptable-action-card-content">{{item.content}}</view>
<view
:class="1==item.actionOrientation ? 'flex-wrap transverse':'vertical'">
<view class="item"
:class="$list.style+ (1==item.actionOrientation ? ' flex-resize':'')"
v-for="($list,lindex) in item.actionList" :key="lindex"
@click="'openWindow'===$list.action?gotoPage($list.param.url):sendMessage($list.param.text)">
{{ $list.text }}
</view>
</view>
</view>
</view>
</view>
<!-- 文本 -->
<view :class="1===item.source?'request':'response'" v-else>
{{item.text}}
</view>
</view>
</view>
</view>
</scroll-view>
<uni-popup ref="collapse">
<view class="collapse-popup">
<view class="text-white">{{info.title}}</view>
<view class="text-default">{{info.content}}</view>
<uni-icons class="close" type="closeempty" color="#444" size="30"
@click="$refs.collapse.close()"></uni-icons>
</view>
</uni-popup>
<view class="fixed-btn flex-center over-max-width px-5">
<input class="uni-input" maxlength="50" placeholder-style="color:#999" v-model="inputValue"
confirm-type="search" placeholder="请描述您的问题" @confirm="inputChange" />
</view>
data() {
return {
tabIndex: 0,
scrollTop: 0,
scrollHeight: 0,
inputValue: '',
guessList: [],
questions: [],
info: {},
title: '',
messageList: []
}
},
mounted() {
this.initScrollHeight();
},
methods: {
// 获取聊天框高度
initScrollHeight() {
uni.createSelectorQuery()
.in(this)
.select('.scroll-view')
.boundingClientRect(data => {
if (data) {
this.scrollHeight = data.height
}
})
.exec();
},
// 滚动到底部
initContentHeight() {
uni.createSelectorQuery()
.in(this)
.select('.official-content')
.boundingClientRect(data => {
if (data) {
// 判断内容与聊天框相差高度
let top = data.height - this.scrollHeight;
// 如果超出聊天框,则滚动
if (top > 0) {
this.scrollTop = top;
}
}
})
.exec();
},
// 发送信息
sendMessage(item) {
// 讲问题记录到信息列表
this.messageList.push({
text: item,
time: new Date().getTime() / 1000,
source: 1
})
let that = this
this.$nextTick(() => {
setTimeout(() => {
// 发完后滚动到底部查看最近消息
that.initContentHeight()
}, 10)
})
// todo 请求接口,对接口返回的信息进行处理
let message = ''
res.data.messages.forEach(item => {
let cardType = ''
let knowledgeText = item.knowledge.content
// 卡片信息
if ('CARD_TEMPLATE' === item.knowledge.contentType) {
knowledgeText = JSON.parse(knowledgeText)
cardType = knowledgeText.code;
}
// 整理此信息数据
let content = {
time: new Date().getTime() / 1000,
source: 2,
answerType: item.answerType,
contentType: item.knowledge.contentType,
cardType: cardType
}
// 猜你想问
if ('Recommend' === item.answerType) {
this.messageList.push({
...content,
text: item.title,
recommends: item.recommends
})
}
if ('Knowledge' === item.answerType) {
if (cardType) {
// 人物卡片
if ('qa-tabs' === cardType) {
knowledgeText.data.tabs.map(item => {
item.name = item.title.split('url=')[0]
item.url = item.title.split('url=')[1]
return item
})
}
// 信息更新
this.messageList.push({
...content,
...knowledgeText.data
})
} else {
// 更新其他类型信息
this.messageList.push({
...content,
text: knowledgeText
})
}
}
// 纯文本信息
if ("Text" === item.answerType) {
this.messageList.push({
...content,
text: item.text.content
})
}
})
// 滚动到顶部
let that = this
this.$nextTick(() => {
setTimeout(() => {
that.initContentHeight()
}, 10)
})
},
inputChange(e) {
if (e.detail.value) {
this.sendMessage(e.detail.value)
}
this.inputValue = ''
},
tabChange(url, index) {
this.tabIndex = index;
this.gotoPage(url)
},
openPopup(item) {
this.info = item
this.$refs.collapse.open()
},
gotoPage(url){
uni.redirectTo({
url
});
}
}
.official {
.scroll-view {
// 聊天框高度
height: calc(100vh - 500rpx);
background-color: #fff;
}
&-content {
padding: 0 30rpx 30rpx;
.title {
color: #090d0e;
font-size: 30rpx;
font-weight: bold;
padding-top: 40rpx;
}
.guess {
display: inline-block;
color: #45588a;
background-color: #f1f5ff;
font-size: 26rpx;
margin-right: 30rpx;
margin-top: 20rpx;
padding: 20rpx 50rpx;
border-radius: 40rpx;
}
.list {
box-shadow: 0 0 8rpx 5rpx rgba(0, 0, 0, 0.05);
border-radius: 30rpx;
margin-top: 20rpx;
padding: 10rpx 30rpx;
.question {
border-bottom: 1px solid #eeeeee;
&:last-child {
border-bottom: none;
}
view {
color: #333333;
font-size: 26rpx;
line-height: 80rpx;
}
.right-arrow {
&::after {
width: 10rpx;
height: 10rpx;
border-color: #666666;
}
}
}
}
.message {
.time {
color: #888888;
font-size: 24rpx;
text-align: center;
margin-top: 40rpx;
margin-bottom: 20rpx;
}
@mixin item {
max-width: 100%;
display: inline-block;
color: #45588a;
font-size: 26rpx;
padding: 30rpx;
background-color: #f1f5ff;
}
.request {
@include item;
border-radius: 42rpx 42rpx 4rpx 42rpx;
text-align: left;
}
.response {
@include item;
border-radius: 42rpx 42rpx 42rpx 4rpx;
}
.recommend {
width: calc(100vw - 120rpx);
border-radius: 30rpx;
.text {
color: rgba(0, 0, 0, 0.4);
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding: 8rpx 10px;
}
.info {
padding: 20rpx 10px;
color: rgba(0, 0, 0, 0.87);
font-size: 34rpx;
font-weight: 500;
line-height: 1.5;
}
}
.qa-list {
&-item {
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
padding-bottom: 20rpx;
margin-bottom: 20rpx;
&:last-child {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 0;
}
}
&-title {
font-weight: 700;
margin-bottom: 10rpx;
text {
width: 28rpx;
height: 28rpx;
display: inline-block;
border-radius: 50%;
background-color: rgb(255, 236, 0);
margin-right: 8rpx;
}
}
.content {
margin-left: 36rpx;
line-height: 1.5;
}
}
.qa-collapse-list {
&-item {
font-weight: 500;
padding: 20rpx 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:first-child {
padding-top: 0;
}
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
text {
margin-right: 20rpx;
}
}
}
.qa-table {
&-item {
padding: 20rpx 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.05);
&:last-child {
border-bottom: none;
padding-bottom: 0;
}
view {
font-size: 32rpx;
&:first-child {
font-weight: 700;
margin-right: 16rpx;
}
}
}
}
.qa-tabs {
.img {
width: 256rpx;
background-color: #fff;
border-radius: 30rpx;
text-align: center;
padding: 34rpx 0;
image {
width: 192rpx;
}
.name {
margin-top: 16rpx;
}
}
.tabs {
margin: 25rpx 0;
.item {
display: inline-block;
color: rgba(0, 0, 0, 0.54);
background-color: #fff;
border-radius: 40rpx;
padding: 10rpx 30rpx;
margin-right: 10rpx;
font-size: 34rpx;
font-weight: 500;
}
.active {
color: rgba(0, 0, 0, 0.87);
background-color: rgb(252, 224, 150);
}
}
.text {
background-color: #fff;
border-radius: 30rpx;
padding: 30rpx;
line-height: 1.3;
}
}
.qa-progress {
position: relative;
&::before {
width: 4rpx;
height: calc(100% - 130rpx);
background-color: #ffe48c;
content: '';
display: block;
position: absolute;
left: 0;
top: 80rpx;
}
.detail {
position: relative;
view {
&:first-child {
color: rgba(0, 0, 0, 0.54);
font-size: 26rpx;
}
&:last-child {
color: rgba(0, 0, 0, 0.4);
font-size: 24rpx;
line-height: 1.5;
}
}
&::before {
width: 16rpx;
height: 16rpx;
border-radius: 8rpx;
background-color: #ffe48c;
content: '';
display: block;
position: absolute;
left: -6rpx;
top: 25rpx;
}
}
}
.qa-slot {
.content {
width: calc(100vw - 120rpx);
background-color: #fff;
padding: 10rpx 16rpx;
border-radius: 32rpx;
margin-bottom: 16rpx;
box-sizing: border-box;
}
.item {
display: inline-block;
background: rgb(254, 242, 218);
padding: 10rpx 12rpx;
border-radius: 30rpx;
margin-right: 10rpx;
margin-bottom: 15rpx;
text-align: center;
view {
line-height: 1;
&:first-child {
color: rgb(51, 51, 51);
font-size: 24rpx;
}
&:last-child {
color: rgba(0, 0, 0, 0.4);
}
}
}
}
.adaptable-action-card {
width: calc(100vw - 120rpx);
background-color: #fff;
border-radius: 30rpx;
image {
width: 100%;
border-radius: 30rpx 30rpx 0 0;
}
&-title {
color: rgba(0, 0, 0, 0.87);
font-size: 34rpx;
font-weight: 500;
}
&-content {
color: #333;
line-height: 1.3;
margin-top: 20rpx;
margin-bottom: 10rpx;
}
.transverse {
.default,
.primary {
text-align: center;
padding: 5rpx 12rpx;
border-radius: 30rpx;
margin-right: 10rpx;
margin-bottom: 10rpx;
}
.default {
color: rgba(0, 0, 0, 0.87);
border: 1px solid rgba(0, 0, 0, 0.1);
}
.primary {
color: #fff;
background-color: #ffb300;
border: 1px solid #ffb300;
}
}
.vertical{
.default,
.primary {
text-align: center;
padding: 10rpx 0;
border-top: 1px solid rgba(0, 0, 0, 0.1);
}
.default {
color: rgba(0, 0, 0, 0.87);
}
.primary {
color: #ffb300;
}
}
}
}
}
.fixed-btn {
width: 100%;
height: 140rpx;
position: fixed;
bottom: 0;
--window-left: 0;
background-color: #fff;
box-shadow: 0 0 5rpx 1rpx rgba(0, 0, 0, 0.08);
box-sizing: border-box;
input {
width: 100%;
height: 76rpx;
line-height: 76rpx;
border-radius: 100rpx;
background-color: #f1f5ff;
padding: 0 30rpx;
}
}
}
.collapse-popup {
position: relative;
padding: 40rpx;
.close {
position: absolute;
top: -15rpx;
right: 10rpx;
}
view {
font-size: 26rpx;
&:first-child {
font-size: 28rpx;
margin-bottom: 20rpx;
text-align: center;
font-weight: bold;
}
}
}
效果图如下