<template>
|
<view class="min-h-screen bg-gray-100 flex flex-col">
|
<!-- 顶部固定按钮区域 -->
|
<view class="fixed bottom-0 left-0 right-0 z-10 bg-white shadow p-4">
|
<view class="flex flex-wrap ">
|
<button v-for="category in categories" :key="category"
|
class="bg-blue-500 text-white text-sm px-4 py-2 rounded m-1" @click="handleCategoryClick(category)">
|
{{ category }}
|
</button>
|
</view>
|
</view>
|
|
<!-- 聊天对话区域 -->
|
<scroll-view scroll-y scroll-with-animation class="flex-1 px-4 pt-20 pb-20" :scroll-top="scrollTop">
|
<view v-for="(msg, index) in messages" :key="index" class="mb-4">
|
<view v-if="msg.role === 'user'" class="flex justify-end">
|
<view class="bg-blue-200 text-black p-3 rounded-lg max-w-3-4 m-3">
|
{{ msg.content }}
|
</view>
|
</view>
|
<view v-if="msg.role === 'bot'" class="flex justify-start">
|
<view class="bg-gray-200 text-black p-3 rounded-lg max-w-3-4 m-3">
|
{{ msg.content }}
|
</view>
|
</view>
|
</view>
|
<!-- 占位元素确保输入框可见 -->
|
<view class="h-20"></view>
|
</scroll-view>
|
|
<!-- 底部输入框 -->
|
<!--
|
<view class="fixed bottom-0 left-0 right-0 bg-white shadow-t p-4 flex items-center">
|
<input v-model="inputMessage" type="text" placeholder="请输入问题..."
|
class="flex-1 border border-gray-300 rounded-l p-2 h-10" @confirm="sendMessage" />
|
|
<button class="ml-2 bg-blue-500 text-white px-4 text-base rounded-r h-10" @click="sendMessage">
|
发送
|
</button>
|
</view>
|
-->
|
</view>
|
</template>
|
|
<script>
|
import {
|
ref,
|
computed,
|
onMounted,
|
nextTick
|
} from 'vue';
|
import {
|
QUESTIONS
|
} from './questions';
|
|
export default {
|
setup() {
|
const categories = ['吃', '住', '行', '游', '购', '娱'];
|
const messages = ref([]); // 聊天记录 [{ role: 'user'/'bot', content: '' }]
|
const inputMessage = ref('');
|
const scrollTop = ref(0);
|
|
// 处理类别按钮点击
|
const handleCategoryClick = (category) => {
|
const question = `关于${category}的推荐?`; // 模拟问题
|
messages.value.push({
|
role: 'user',
|
content: question
|
});
|
const response = getResponse(question);
|
messages.value.push({
|
role: 'bot',
|
content: response
|
});
|
scrollToBottom();
|
};
|
|
// 发送消息
|
const sendMessage = () => {
|
if (!inputMessage.value.trim()) return;
|
messages.value.push({
|
role: 'user',
|
content: inputMessage.value
|
});
|
const response = getResponse(inputMessage.value);
|
messages.value.push({
|
role: 'bot',
|
content: response
|
});
|
inputMessage.value = '';
|
scrollToBottom();
|
};
|
|
// 关键字匹配逻辑
|
const getResponse = (query) => {
|
// 拆分查询关键字(简单分词)
|
const keywords = query.split(/[\s,、?!.]+/).filter(k => k.trim());
|
|
let bestMatch = null;
|
let maxScore = 0;
|
|
QUESTIONS.forEach((item) => {
|
let score = 0;
|
keywords.forEach((kw) => {
|
if (item.keys.some(key => kw.includes(key) || key.includes(kw))) {
|
score++;
|
}
|
});
|
if (score > maxScore) {
|
maxScore = score;
|
bestMatch = item.value;
|
}
|
});
|
|
return bestMatch || '抱歉,我不理解您的问题。请尝试其他关键词或咨询人工客服。';
|
};
|
|
// 滚动到底部
|
const scrollToBottom = () => {
|
nextTick(() => {
|
scrollTop.value = 999999; // 大值确保滚动到底部
|
});
|
};
|
|
return {
|
categories,
|
messages,
|
inputMessage,
|
scrollTop,
|
handleCategoryClick,
|
sendMessage,
|
};
|
}
|
};
|
</script>
|
|
<style>
|
/* 容器 */
|
.min-h-screen {
|
min-height: 100vh;
|
}
|
|
.bg-gray-100 {
|
background-color: #f7fafc;
|
}
|
|
.flex {
|
display: flex;
|
}
|
|
.flex-col {
|
flex-direction: column;
|
}
|
|
.flex-1 {
|
flex: 1 1 0%;
|
}
|
.h-10 {
|
height: 40px;
|
}
|
|
.flex-wrap {
|
flex-wrap: wrap;
|
}
|
|
.justify-around {
|
justify-content: space-around;
|
}
|
|
.justify-end {
|
justify-content: flex-end;
|
}
|
|
.justify-start {
|
justify-content: flex-start;
|
}
|
|
.items-center {
|
align-items: center;
|
}
|
|
/* 定位 */
|
.fixed {
|
position: fixed;
|
}
|
|
.top-0 {
|
top: 0;
|
}
|
|
.left-0 {
|
left: 0;
|
}
|
|
.right-0 {
|
right: 0;
|
}
|
|
.right-10 {
|
right: 10;
|
}
|
|
.bottom-0 {
|
bottom: 0;
|
}
|
|
.z-10 {
|
z-index: 10;
|
}
|
|
/* 背景与阴影 */
|
.bg-white {
|
background-color: #ffffff;
|
}
|
|
.shadow {
|
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1),
|
0 1px 2px rgba(0, 0, 0, 0.06);
|
}
|
|
.shadow-t {
|
box-shadow: 0 -1px 3px rgba(0, 0, 0, 0.1),
|
0 -1px 2px rgba(0, 0, 0, 0.06);
|
}
|
|
/* 间距 */
|
.p-4 {
|
padding: 1rem;
|
}
|
|
.p-3 {
|
padding: 0.75rem;
|
}
|
|
.px-4 {
|
padding-left: 1rem;
|
padding-right: 1rem;
|
}
|
|
.pb-20 {
|
padding-bottom: 5rem;
|
}
|
|
.pt-20 {
|
padding-top: 5rem;
|
}
|
|
.m-1 {
|
margin: 0.25rem;
|
}
|
|
.m-3 {
|
margin-right: 2rem;
|
}
|
|
.mb-4 {
|
margin-bottom: 1rem;
|
}
|
|
/* 按钮 & 输入框 */
|
.bg-blue-200 {
|
background-color: #00ff00;
|
}
|
|
.bg-gray-200 {
|
background-color: #808080;
|
}
|
|
.bg-blue-500 {
|
background-color: #3b82f6;
|
}
|
|
.text-white {
|
color: #ffffff;
|
}
|
|
.text-black {
|
color: #000000;
|
}
|
|
.text-sm {
|
font-size: 0.875rem;
|
}
|
|
.text-base {
|
font-size: 1rem;
|
}
|
|
.rounded {
|
border-radius: 0.25rem;
|
}
|
|
.rounded-lg {
|
border-radius: 0.5rem;
|
}
|
|
.rounded-r {
|
border-top-right-radius: 0.25rem;
|
border-bottom-right-radius: 0.25rem;
|
}
|
|
.border {
|
border-width: 1px;
|
border-style: solid;
|
}
|
|
.border-gray-300 {
|
border-color: #d1d5db;
|
}
|
|
.h-12 {
|
height: 3rem;
|
}
|
|
.h-20 {
|
height: 5rem;
|
}
|
|
.max-w-3-4 {
|
max-width: 90%;
|
}
|
|
/* 注意转义 / */
|
|
/* 滚动区域 */
|
.scroll-y {
|
overflow-y: auto;
|
}
|
|
.scroll-with-animation {
|
scroll-behavior: smooth;
|
}
|
</style>
|