YingXingAI/pages/home/index/index.vue

980 lines
24 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<view class="home-container">
<view class="header">
<div class="header-left">
<u-icon
class="header-left-icon"
name="list"
@click="handleLeftClick"
></u-icon>
</div>
<text class="header-title">源小新</text>
<div></div>
</view>
<!-- 首页 -->
<view class="content" v-if="!isChat">
<view class="welcome-message">
<image
class="avatar"
src="/static/common/images/images_logo.png"
></image>
<text class="message-text"
>Hi~我是小小新您的AI聊天伙伴未来高效认知助手我们可尽量互相解惑</text
>
</view>
<!-- <view class="qa-section">
<view class="qa-header">
<text class="qa-title">大家都在问</text>
<view class="more-link">
<text class="more-text">换一批</text>
</view>
</view>
<view class="qa-list">
<view
class="qa-item"
v-for="(item, index) in questionList"
:key="index"
>
<text class="qa-question">{{ item }}</text>
</view>
</view>
<button class="chat-button" @click="isChat = true">
<image
class="chat-icon"
src="/static/common/images/icon_chat.png"
></image>
<text class="chat-text">开启对话</text>
</button>
</view> -->
<view class="start-chat">
<button class="chat-button" @click="isChat = true">
<image
class="chat-icon"
src="/static/common/images/icon_chat.png"
></image>
<text class="chat-text">开启对话</text>
</button>
</view>
<view class="feature-grid">
<view
class="feature-item"
v-for="(item, index) in features"
:key="index"
@click="handleFeatureClick(item)"
>
<image :src="item.icon" class="feature-icon"></image>
<text class="feature-text">{{ item.title }}</text>
</view>
</view>
</view>
<!-- 对话 -->
<view class="chat-container" v-if="isChat">
<scroll-view
class="chat-scroll"
scroll-y
:scroll-into-view="scrollToView"
scroll-with-animation
:scroll-top="scrollTop"
:show-scrollbar="true"
@scrolltoupper="loadMoreMessages"
@scroll="onScroll"
>
<!-- 头部卡片 -->
<!-- 后端让先注释 -->
<!-- <view class="chat-card">
<view class="chat-card-title">源小新AI校园小助手</view>
<view class="chat-card-desc"
>我是你们的AI校园助手我可以为您答疑解惑。</view
>
<view class="chat-card-questions">
<view class="question-item">学校哪些专业比较好?</view>
<view class="question-item">如何报考学校综合素质评价招生?</view>
<view class="question-item">学校有那些专业?</view>
<view class="question-item"
>学校在录取时有没有一些专业会有特殊...</view
>
<view class="question-item">我什么时候能够知道自己是否被录取?</view>
</view>
</view> -->
<!-- 对话内容区域 -->
<view class="chat-content">
<!-- 消息循环渲染 -->
<block
v-for="(group, groupIndex) in messageGroups"
:key="'group-' + groupIndex"
>
<!-- 时间 -->
<view class="message-time" v-if="group.time">{{ group.time }}</view>
<!-- 消息列表 -->
<block
v-for="(message, messageIndex) in group.messages"
:key="'msg-' + groupIndex + '-' + messageIndex"
>
<!-- 用户消息 -->
<view
class="message-right"
v-if="message.isUser"
:id="'msg-' + message.id"
>
<view class="message-content">
<text>{{ message.content }}</text>
</view>
<image
class="user-avatar"
src="/static/common/images/avatar.png"
mode="scaleToFill"
/>
</view>
<!-- AI消息 -->
<view class="message-left" v-else :id="'msg-' + message.id">
<image
class="ai-avatar"
src="/static/common/images/avatar_ai.png"
mode="scaleToFill"
/>
<view class="message-content">
<text space="nbsp" decode>{{ message.content }}</text>
</view>
</view>
</block>
</block>
</view>
</scroll-view>
<!-- 底部工具栏 -->
<view class="chat-footer">
<!-- 悬浮工具栏 -->
<view class="floating-tabs">
<view
class="tab-item"
@click="handleFeatureClick({ title: '招生在线' })"
>
<image
class="tab-icon"
src="/static/common/images/icon_admissions2.png"
mode="scaleToFill"
/>
<text>招生在线</text>
</view>
<view
class="tab-item"
@click="handleFeatureClick({ title: '留言板' })"
>
<image
class="tab-icon"
src="/static/common/images/icon_messageBoard2.png"
mode="scaleToFill"
/>
<text>留言板</text>
</view>
<view
class="tab-item"
@click="handleFeatureClick({ title: '电话咨询' })"
>
<image
class="tab-icon"
src="/static/common/images/icon_phone2.png"
mode="scaleToFill"
/>
<text>电话咨询</text>
</view>
</view>
<view class="input-container">
<view class="input-area">
<input
v-model="messageValue"
type="text"
class="chat-input"
placeholder="请输入内容"
placeholder-style="color: #adadad;"
@confirm="sendMessageFn"
/>
<view class="send-btn" @click="sendMessageFn">
<image
class="send-icon"
src="/static/common/images/icon_send.png"
mode="scaleToFill"
/>
</view>
</view>
</view>
</view>
</view>
<!-- 对话弹出层 -->
<u-popup v-model="popupShow" width="550rpx">
<view class="drawer-container">
<scroll-view scroll-y class="chat-history-list">
<view class="chat-day">
<text class="day-text">周三</text>
</view>
<view
class="chat-item"
v-for="(item, index) in chatHistoryList"
:key="index"
:class="{ 'chat-item-active': index === activeIndex }"
@click="selectChatItem(index)"
>
<text class="chat-text">{{ item.content }}</text>
</view>
<view class="chat-day">
<text class="day-text">6/27</text>
</view>
<view
class="chat-item"
v-for="(item, index) in chatHistoryList2"
:key="'history2-' + index"
:class="{
'chat-item-active':
index + chatHistoryList.length === activeIndex,
}"
@click="selectChatItem(index + chatHistoryList.length)"
>
<text class="chat-text">{{ item.content }}</text>
</view>
</scroll-view>
<view class="drawer-footer">
<view class="user-info">
<image
class="user-avatar"
src="/static/common/avatar/male.png"
></image>
<!-- <u-avatar
class="user-avatar"
src="/static/common/avatar/user-avatar.png"
></u-avatar> -->
<text class="user-name">晓德塔,</text>
</view>
<view class="settings">
<u-icon name="setting" size="40rpx" color="#999"></u-icon>
</view>
</view>
</view>
</u-popup>
<!-- 咨询电话弹出层 -->
<advice-phone :show.sync="advicePhoneShow"></advice-phone>
<!-- 提示 -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import CustomTabBar from "@/components/custom-tab-bar/custom-tab-bar.vue";
import AdvicePhone from "@/components/AdvicePhone.vue";
export default {
components: {
CustomTabBar,
AdvicePhone,
},
data() {
return {
isChat: false,
advicePhoneShow: false,
questionList: [
"学习哪些专业比较好?",
"处于香港学校综合录取的城市招生?",
"学校有新华专业?",
"学校录取科目与有一些专业会有特殊...",
"我什么时候能推知道自己是否被录取?",
],
features: [
{
title: "招办在线",
icon: "/static/common/images/icon_admissions.png",
},
{
title: "留言板",
icon: "/static/common/images/icon_messageBoard.png",
},
{
title: "电话咨询",
icon: "/static/common/images/icon_phone.png",
},
],
popupShow: false,
chatHistoryList: [
{ content: "学校哪些专业比较好?" },
{ content: "如何报考学校综合合录取评澳市评招生?" },
{ content: "学校有新华专业?" },
],
chatHistoryList2: [
{ content: "学校哪些专业比较好?" },
{ content: "如何报考学校综合合录取评澳市评招生?" },
{ content: "如何报考学校综合合录取评澳市评招生?" },
{ content: "如何报考学校综合合录取评澳市评招生?" },
{ content: "如何报考学校综合合录取评澳市评招生?" },
{ content: "学校有新华专业?" },
{ content: "学校有新华专业?" },
{ content: "学校有新华专业?" },
{ content: "学校有新华专业?" },
{ content: "学校有新华专业?" },
],
activeIndex: 0,
commonQuestions: [
"新生报到流程",
"如何报考学校综合合录取评澳市评招生?",
"学校有新华专业?",
"学校录取科目与有一些专业会有特殊...",
"我什么时候能推知道自己是否被录取?",
],
scrollToView: "",
messageGroups: [
// {
// time: "2025-07-01 10:00:00",
// messages: [
// { id: 1, content: "学校哪些专业比较好?", isUser: true },
// {
// id: 2,
// content:
// "我校有多个优势学科,包括计算机科学与技术、电子信息工程、机械工程、生物医学工程等。这些专业在国内都有较高的学术声誉和就业率。如果您对某个具体专业感兴趣,可以进一步咨询更多详情。",
// isUser: false,
// },
// { id: 3, content: "计算机科学专业就业前景如何?", isUser: true },
// {
// id: 4,
// content:
// "计算机科学专业的就业前景非常好。根据最新数据我校计算机专业毕业生就业率超过95%平均起薪在全校名列前茅。主要就业方向包括互联网公司、IT企业、金融科技等领域担任软件工程师、数据分析师、产品经理等职位。",
// isUser: false,
// },
// ],
// },
// {
// time: "2025-07-02 09:15:36",
// messages: [
// { id: 5, content: "新生报到流程", isUser: true },
// {
// id: 6,
// content:
// "新生报到流程:个人信息完善 --预报到 -- 照片信息采集 --缴费 --入校验审 -- 人脸识别 --打印报到单",
// isUser: false,
// },
// { id: 7, content: "预报到需要准备哪些材料?", isUser: true },
// {
// id: 8,
// content:
// "预报到需要准备以下材料:\n1. 身份证原件及复印件\n2. 录取通知书原件\n3. 2寸蓝底证件照4张\n4. 学籍档案(密封)\n5. 党团关系材料(如有)\n\n建议提前准备齐全以便快速完成报到流程。",
// isUser: false,
// },
// ],
// },
{
time: "",
messages: [
{ id: 5, content: "新生报到流程", isUser: true },
{
id: 6,
content:
"新生报到流程:个人信息完善 --预报到 -- 照片信息采集 --缴费 --入校验审 -- 人脸识别 --打印报到单",
isUser: false,
},
],
},
],
scrollTop: 0,
messageValue: "", // 输入框内容
};
},
watch: {
// 确保消息更新后自动滚动到底部
messageGroups: {
handler() {
this.$nextTick(() => {
this.scrollToBottom();
});
},
deep: true,
},
},
onLoad() {},
mounted() {
this.$nextTick(() => {
this.scrollToBottom();
});
},
updated() {
this.$nextTick(() => {
this.scrollToBottom();
});
},
methods: {
handleLeftClick() {
this.$refs.uToast.show({
title: "暂未开放",
type: "warning",
});
return;
this.popupShow = true;
},
selectChatItem(index) {
this.activeIndex = index;
},
loadMoreMessages() {
// 加载更多历史消息的实现
console.log("加载更多历史消息");
},
onScroll(event) {
// 滚动事件处理
},
scrollToBottom() {
// 使用nextTick确保DOM已更新
this.$nextTick(() => {
// 获取滚动区域的高度
const query = uni.createSelectorQuery().in(this);
query
.select(".chat-content")
.boundingClientRect((data) => {
if (data) {
// 计算滚动到底部的位置
const scrollHeight = data.height;
// 设置滚动位置加100px确保滚动到底部
this.scrollTop = scrollHeight + 100;
}
})
.exec();
});
},
handleFeatureClick(item) {
if (item.title === "电话咨询") {
this.advicePhoneShow = true;
} else {
this.$refs.uToast.show({
title: "暂未开放",
type: "warning",
});
return;
}
},
sendMessageFn() {
if (!this.messageValue) {
return;
}
const sendMessage = this.messageValue;
console.log("发送消息", sendMessage);
this.messageGroups[0].messages.push({
id: this.messageGroups[0].messages.length + 1,
content: sendMessage,
isUser: true,
});
this.messageValue = "";
this.$u.api
.SendMessageApi({
query: sendMessage,
conversationId: "",
})
.then((res) => {
console.log("res.....", res);
this.messageGroups[0].messages.push({
id: res.messageId,
content: res.content,
isUser: false,
});
});
},
},
};
</script>
<style lang="scss" scoped>
page {
background-image: url("/static/common/images/images_bg.png");
width: 100%;
background-repeat: no-repeat;
background-size: 100% 100%;
background-position: 0 88rpx;
}
.home-container {
height: 100vh;
// background-color: #f5f7fc;
padding-bottom: calc(
112rpx + env(safe-area-inset-bottom)
); /* 为自定义tabBar预留空间 */
padding-top: 88rpx;
.header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #ffffff;
height: 88rpx;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 30rpx;
z-index: 99;
.header-left {
font-size: 36rpx;
}
.header-title {
font-size: 36rpx;
font-weight: 500;
color: #333333;
}
}
.content {
padding: 30rpx;
padding-top: 100rpx;
.welcome-message {
// display: inline-block;
// flex-wrap: wrap;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 32rpx;
// margin-bottom: 100rpx;
.avatar {
display: inline-block;
width: 42rpx;
height: 34rpx;
margin-right: 12rpx;
}
.message-text {
font-size: 24rpx;
color: #333333;
font-family: PingFang SC;
vertical-align: super;
}
}
.qa-section {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 32rpx;
.qa-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30rpx;
.qa-title {
font-size: 32rpx;
font-weight: 500;
color: #333;
}
.more-link {
.more-text {
font-size: 26rpx;
color: #999;
}
}
}
.qa-list {
.qa-item {
margin-bottom: 24rpx;
.qa-question {
font-size: 28rpx;
color: #333;
line-height: 1.5;
}
}
}
.chat-button {
display: flex;
align-items: center;
justify-content: center;
background-color: #4377fe;
border-radius: 16rpx;
height: 88rpx;
width: 100%;
margin-top: 30rpx;
border: none;
.chat-icon {
width: 38rpx;
height: 32rpx;
margin-right: 12rpx;
}
.chat-text {
color: #ffffff;
font-size: 32rpx;
}
}
}
.start-chat {
.chat-button {
display: flex;
align-items: center;
justify-content: center;
background-color: #4377fe;
border-radius: 16rpx;
height: 88rpx;
width: 100%;
margin-top: 30rpx;
border: none;
.chat-icon {
width: 38rpx;
height: 32rpx;
margin-right: 12rpx;
}
.chat-text {
color: #ffffff;
font-size: 32rpx;
}
}
}
.feature-grid {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
display: flex;
justify-content: space-between;
margin-top: 32rpx;
gap: 30rpx;
.feature-item {
height: 210rpx;
border-radius: 16rpx;
background-color: #fafafc;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
// gap: 20rpx;
flex: 1;
.feature-icon {
width: 80rpx;
height: 80rpx;
margin-bottom: 12rpx;
}
.feature-text {
font-size: 26rpx;
color: #333333;
}
}
}
}
}
.drawer-container {
padding: 32rpx;
display: flex;
flex-direction: column;
height: 100vh;
background-color: #ffffff;
.chat-history-list {
flex: 1;
// padding: 30rpx 40rpx;
height: calc(100vh - 200rpx);
.chat-day {
display: flex;
margin: 20rpx 0 20rpx 30rpx;
.day-text {
font-size: 24rpx;
color: #999999;
font-family: PingFang SC;
margin-bottom: 10rpx;
}
}
.chat-item {
padding: 24rpx 30rpx;
border-radius: 16rpx;
// margin-bottom: 30rpx;
.chat-text {
font-size: 28rpx;
color: #303030;
font-family: PingFang SC;
}
&-active {
background-color: #4f6aff;
.chat-text {
color: #fff;
}
}
}
}
.drawer-footer {
height: 130rpx;
border: 1rpx solid #eeeeee;
border-radius: 12rpx;
padding: 0 30rpx;
display: flex;
justify-content: space-between;
align-items: center;
.user-info {
display: flex;
align-items: center;
.user-avatar {
width: 56rpx;
height: 56rpx;
border-radius: 50%;
margin-right: 30rpx;
}
.user-name {
font-size: 28rpx;
font-weight: bold;
font-family: DouyinSans;
color: #333;
}
}
.settings {
padding: 10rpx;
}
}
}
/* 响应式布局 - PC端样式 */
@media screen and (min-width: 768px) {
.home-container {
.content {
max-width: 1200rpx;
margin: 0 auto;
.qa-section {
.qa-list {
display: flex;
flex-wrap: wrap;
.qa-item {
width: 48%;
margin-right: 2%;
}
}
}
.feature-grid {
max-width: 1200rpx;
margin: 40rpx auto 0;
}
}
}
}
.chat-container {
display: flex;
flex-direction: column;
padding: 30rpx;
box-sizing: border-box;
.chat-scroll {
flex: 1;
flex-shrink: 0;
// overflow-y: auto; /* 使用auto而不是scroll */ // 添加这行会导致滚动条不见
}
.chat-card {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.chat-card-title {
font-size: 32rpx;
font-weight: 500;
color: #333333;
margin-bottom: 10rpx;
}
.chat-card-desc {
font-size: 24rpx;
color: #666666;
margin-bottom: 20rpx;
}
.chat-card-questions {
display: flex;
flex-direction: column;
gap: 16rpx;
.question-item {
font-size: 28rpx;
color: #333333;
line-height: 1.5;
}
}
}
.chat-content {
flex: 1;
padding: 20rpx 0;
margin-bottom: 150rpx;
.message-time {
text-align: center;
font-size: 24rpx;
color: #999999;
padding: 20rpx;
}
.message-left,
.message-right {
display: flex;
margin-bottom: 30rpx;
align-items: flex-start;
}
.message-left {
.ai-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
margin-right: 16rpx;
flex-shrink: 0;
}
.message-content {
background-color: #ffffff;
color: #333333;
max-width: 70%;
padding: 20rpx 24rpx;
border-radius: 0 16rpx 16rpx 16rpx;
font-size: 28rpx;
line-height: 1.5;
}
}
.message-right {
justify-content: flex-end;
.user-avatar {
width: 64rpx;
height: 64rpx;
border-radius: 50%;
margin-left: 16rpx;
background-color: #f0f0f0;
flex-shrink: 0;
}
.message-content {
background-color: #4370fe;
color: #ffffff;
max-width: 70%;
padding: 20rpx 24rpx;
border-radius: 16rpx 0 16rpx 16rpx;
font-size: 28rpx;
line-height: 1.5;
text-align: left;
}
}
}
.chat-footer {
position: fixed;
bottom: 0;
left: 0;
right: 0;
.floating-tabs {
display: flex;
justify-content: flex-start;
margin: 0 0 20rpx 20rpx;
.tab-item {
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
background-color: #ffffff;
padding: 8rpx 24rpx;
border-radius: 50rpx;
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
margin-right: 12rpx;
.tab-icon {
width: 28rpx;
height: 28rpx;
margin-right: 10rpx;
}
text {
font-size: 28rpx;
color: #333333;
}
}
}
.input-container {
padding: 32rpx;
background-color: #fff;
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.05);
.input-area {
display: flex;
align-items: center;
background-color: #f2f4f9;
border-radius: 20rpx;
padding: 16rpx 24rpx;
box-sizing: border-box;
.chat-input {
flex: 1;
height: 40rpx;
font-size: 28rpx;
color: #333;
background-color: transparent;
}
.send-btn {
width: 50rpx;
height: 50rpx;
display: flex;
align-items: center;
justify-content: center;
.send-icon {
width: 40rpx;
height: 46rpx;
}
}
}
}
}
}
</style>