252 lines
8.3 KiB
Vue
Raw Normal View History

2025-05-23 16:00:15 +08:00
<template>
<!-- 悬浮按钮 -->
<button
v-if="!showChat"
class="fixed z-50 bottom-6 right-6 bg-white dark:bg-gray-800 text-blue-600 rounded-full shadow-lg w-14 h-14 flex items-center justify-center text-2xl hover:bg-blue-600 hover:text-white transition"
@click="showChat = true"
aria-label="在线咨询"
>
<img src="../public/img/customerservice.svg" alt="logo" class="w-8 h-8 rounded-full" />
</button>
<!-- Chat 弹窗 -->
<transition name="fade">
<div
v-if="showChat"
class="fixed z-50 bottom-6 right-6"
style="max-width: 400px; width: 90vw;"
>
<div class="relative">
<button
class="absolute -top-3 -right-3 bg-white dark:bg-gray-700 border border-gray-200 dark:border-gray-700 rounded-full w-7 h-7 flex items-center justify-center shadow hover:bg-gray-100 dark:hover:bg-gray-600"
@click="showChat = false"
aria-label="关闭"
></button>
<div class="bg-white dark:bg-gray-800 rounded-xl shadow-lg overflow-hidden">
<!-- 标题栏 -->
<div class="flex items-center px-6 py-4 border-b">
<img src="../public/img/sitelogo.svg" alt="logo" class="w-8 h-8 rounded-full bg-blue-100 mr-2" />
<span class="font-bold text-lg text-primary dark:text-[#4da6ff]">PinnovateCloud</span>
</div>
<!-- 聊天内容 -->
<div id="content" class="px-6 py-4 h-[432px] min-h-[432px] max-h-[432px] overflow-y-auto bg-gray-50 dark:bg-gray-700">
<div v-for="(item, index) in info" :key="index">
<!-- 机器人消息 -->
<div v-if="item.type === 'leftinfo'" class="flex items-start mb-4">
<img src="/img/sitelogo.svg" alt="logo" class="w-8 h-8 rounded-full object-cover mr-2" />
<div>
<div class="bg-gray-200 dark:bg-gray-600 rounded-lg px-4 py-2 text-gray-800 dark:text-white shadow">
{{ item.content }}
<div v-for="(item2, idx) in item.question" :key="idx">
<div class="text-blue-600 cursor-pointer hover:underline mt-1" @click="clickRobot(item2.content, item2.id)">
{{ item2.index }}. {{ item2.content }}
</div>
</div>
</div>
<div class="text-xs text-gray-400 dark:text-gray-300 mt-1">{{ item.time }}</div>
</div>
</div>
<!-- 用户消息 -->
<div v-else-if="item.type === 'rightinfo'" class="flex items-end justify-end mb-4">
<div>
<div class="bg-blue-600 text-white rounded-lg px-4 py-2 shadow text-right">
{{ item.content }}
</div>
<div class="text-xs text-gray-400 text-right mt-1">{{ item.time }}</div>
</div>
<div class="w-8 h-8 rounded-full bg-blue-100 flex items-center justify-center ml-2">
<span class="text-blue-500">😎</span>
</div>
</div>
</div>
</div>
<!-- 输入区 -->
<div class="flex items-center px-6 py-4 border-t bg-white dark:bg-gray-700">
<textarea
v-model="customerText"
placeholder="请输入您的问题..."
class="flex-1 resize-none border border-gray-200 dark:border-gray-700 rounded-lg px-3 py-2 mr-2 focus:outline-none focus:border-blue-400"
rows="2"
@keyup.enter="sentMsg"
></textarea>
<button
@click="sentMsg"
class="bg-blue-600 text-white px-6 py-2 rounded-lg shadow hover:bg-blue-700 transition"
>
发送
</button>
</div>
</div>
</div>
</div>
</transition>
</template>
<script setup>
import { ref, nextTick, onMounted } from 'vue'
const customerText = ref('')
const info = ref([
{
type: 'leftinfo',
time: getTodayTime(),
name: 'robot',
content: '您好欢迎使用PinnovateCloud在线客服我们是AWS云服务专家提供云服务器、对象存储、数据库、AI等全线AWS产品与解决方案。如需帮助请随时咨询。',
question: [
{ id: 1, content: '如何选购AWS云服务器', index: 1 },
{ id: 2, content: 'AWS对象存储S3有哪些优势', index: 2 },
{ id: 3, content: '如何获取AWS产品报价', index: 3 },
{ id: 4, content: '企业上云迁移流程是怎样的?', index: 4 },
{ id: 5, content: '如何联系技术支持?', index: 5 },
],
},
{
type: 'leftinfo',
time: getTodayTime(),
name: 'robot',
content: '网站信息PinnovateCloud 新加坡AWS授权合作伙伴。联系方式support@pinnovatecloud.com电话+86 15656988217',
question: [],
},
])
const robotQuestion = [
{ id: 1, content: '如何选购AWS云服务器', index: 1 },
{ id: 2, content: 'AWS对象存储S3有哪些优势', index: 2 },
{ id: 3, content: '如何获取AWS产品报价', index: 3 },
{ id: 4, content: '企业上云迁移流程是怎样的?', index: 4 },
{ id: 5, content: '如何联系技术支持?', index: 5 },
]
const robotAnswer = [
{ id: 1, content: '您可以根据业务需求选择EC2实例类型我们可为您提供专业选型建议和报价。', index: 1 },
{ id: 2, content: 'S3具备高可用、高持久性、弹性扩展、按需付费等优势适合备份、归档、数据湖等多场景。', index: 2 },
{ id: 3, content: '请提供您的需求我们会有专属顾问为您定制AWS产品报价方案。', index: 3 },
{ id: 4, content: '企业上云迁移包括评估、方案设计、数据迁移、系统上线等环节,我们可全程协助。', index: 4 },
{ id: 5, content: '您可通过在线客服、邮箱support@pinnovatecloud.com或电话+86 15656988217联系我们的技术支持团队。', index: 5 },
]
let timer = null
const showChat = ref(false)
function sentMsg() {
clearTimeout(timer)
showTimer()
const text = customerText.value.trim()
if (text !== '') {
info.value.push({
type: 'rightinfo',
time: getTodayTime(),
content: text,
})
appendRobotMsg(text)
customerText.value = ''
nextTick(scrollToBottom)
}
}
function appendRobotMsg(text) {
clearTimeout(timer)
showTimer()
text = text.trim()
let answerText = ''
let flag = false
for (let i = 0; i < robotAnswer.length; i++) {
if (robotAnswer[i].content.indexOf(text) !== -1) {
flag = true
answerText = robotAnswer[i].content
break
}
}
if (flag) {
info.value.push({
type: 'leftinfo',
time: getTodayTime(),
name: 'robot',
content: answerText,
question: [],
})
} else {
info.value.push({
type: 'leftinfo',
time: getTodayTime(),
name: 'robot',
content: '您可能想问:',
question: robotQuestion,
})
}
nextTick(scrollToBottom)
}
function sentMsgById(val, id) {
clearTimeout(timer)
showTimer()
const robotById = robotAnswer.filter((item) => item.id === id)
info.value.push({
type: 'rightinfo',
time: getTodayTime(),
content: val,
})
info.value.push({
type: 'leftinfo',
time: getTodayTime(),
name: 'robot',
content: robotById[0].content,
question: [],
})
nextTick(scrollToBottom)
}
function clickRobot(val, id) {
sentMsgById(val, id)
}
function endMsg() {
info.value.push({
type: 'leftinfo',
time: getTodayTime(),
content: '欢迎下次咨询',
question: [],
})
nextTick(scrollToBottom)
}
function showTimer() {
timer = setTimeout(endMsg, 1000 * 60)
}
function getTodayTime() {
const day = new Date()
const pad = (n) => (n < 10 ? '0' + n : n)
return (
day.getFullYear() +
'-' +
pad(day.getMonth() + 1) +
'-' +
pad(day.getDate()) +
' ' +
pad(day.getHours()) +
':' +
pad(day.getMinutes()) +
':' +
pad(day.getSeconds())
)
}
function scrollToBottom() {
const contentHeight = document.getElementById('content')
if (contentHeight) {
contentHeight.scrollTop = contentHeight.scrollHeight
}
}
onMounted(() => {
showTimer()
})
</script>
<style scoped>
.fade-enter-active, .fade-leave-active {
transition: opacity 0.3s;
}
.fade-enter-from, .fade-leave-to {
opacity: 0;
}
</style>