feat: 首页页面还原

This commit is contained in:
yangzhe 2025-07-02 17:07:33 +08:00
parent abc79e407a
commit 6acb8fe916
11 changed files with 899 additions and 121 deletions

View File

@ -1,128 +1,897 @@
<template> <template>
<view class="home-container"> <view class="home-container">
<view class="status-bar" :style="{ height: statusBarHeight + 'px' }"></view>
<view class="header"> <view class="header">
<text class="title">应行AI</text> <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/icon/ai-avatar.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/icon/chat-icon.png"
></image>
<text class="chat-text">开启对话</text>
</button>
</view> </view>
<view class="content">
<text class="welcome-text">欢迎使用应行AI平台</text>
<!-- 这里可以添加首页内容 -->
<view class="feature-grid"> <view class="feature-grid">
<view class="feature-item" v-for="(item, index) in features" :key="index"> <view
class="feature-item"
v-for="(item, index) in features"
:key="index"
>
<image :src="item.icon" class="feature-icon"></image> <image :src="item.icon" class="feature-icon"></image>
<text class="feature-text">{{ item.title }}</text> <text class="feature-text">{{ item.title }}</text>
</view> </view>
</view> </view>
</view> </view>
<!-- 使用自定义TabBar --> <!-- 对话 -->
<custom-tab-bar></custom-tab-bar> <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>
<view class="user-avatar"></view>
</view>
<!-- AI消息 -->
<view class="message-left" v-else :id="'msg-' + message.id">
<view class="ai-avatar"></view>
<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">
<view class="tab-icon icon-people"></view>
<text>招生在线</text>
</view>
<view class="tab-item">
<view class="tab-icon icon-board"></view>
<text>留言板</text>
</view>
<view class="tab-item">
<view class="tab-icon icon-phone"></view>
<text>电话咨询</text>
</view>
</view>
<view class="input-container">
<view class="input-area">
<input
type="text"
class="chat-input"
placeholder="请输入内容"
placeholder-style="color: #adadad;"
/>
<view class="send-btn">
<view class="send-icon"></view>
</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>
</view> </view>
</template> </template>
<script> <script>
import CustomTabBar from '@/components/custom-tab-bar/custom-tab-bar.vue'; import CustomTabBar from "@/components/custom-tab-bar/custom-tab-bar.vue";
export default { export default {
components: { components: {
CustomTabBar CustomTabBar,
}, },
data() { data() {
return { return {
statusBarHeight: 0, isChat: false,
questionList: [
"学习哪些专业比较好?",
"处于香港学校综合录取的城市招生?",
"学校有新华专业?",
"学校录取科目与有一些专业会有特殊...",
"我什么时候能推知道自己是否被录取?",
],
features: [ features: [
{ {
title: '功能一', title: "招办在线",
icon: '/static/common/feature/feature1.png' icon: "/static/common/feature/zhaobao.png",
}, },
{ {
title: '功能二', title: "留言板",
icon: '/static/common/feature/feature1.png' icon: "/static/common/feature/zhiyin.png",
}, },
{ {
title: '功能三', title: "电话咨询",
icon: '/static/common/feature/feature1.png' icon: "/static/common/feature/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,
},
],
}, },
{ {
title: '功能四', time: "2025-07-02 09:15:36",
icon: '/static/common/feature/feature1.png' messages: [
} { id: 5, content: "新生报到流程", isUser: true },
] {
} id: 6,
content:
"新生报到流程:个人信息完善 --预报到 -- 照片信息采集 --缴费 --入校验审 -- 人脸识别 --打印报到单",
isUser: false,
}, },
onLoad() { { id: 7, content: "预报到需要准备哪些材料?", isUser: true },
// {
this.statusBarHeight = uni.getSystemInfoSync().statusBarHeight; id: 8,
content:
"预报到需要准备以下材料:\n1. 身份证原件及复印件\n2. 录取通知书原件\n3. 2寸蓝底证件照4张\n4. 学籍档案(密封)\n5. 党团关系材料(如有)\n\n建议提前准备齐全以便快速完成报到流程。",
isUser: false,
},
],
},
],
scrollTop: 0,
};
},
watch: {
//
messageGroups: {
handler() {
this.$nextTick(() => {
this.scrollToBottom();
});
},
deep: true,
},
},
onLoad() {},
mounted() {
this.$nextTick(() => {
this.scrollToBottom();
});
},
updated() {
this.$nextTick(() => {
this.scrollToBottom();
});
}, },
methods: { methods: {
handleLeftClick() {
} this.popupShow = true;
},
selectChatItem(index) {
this.activeIndex = index;
},
loadMoreMessages() {
//
console.log("加载更多历史消息");
},
onScroll(event) {
//
},
scrollToBottom() {
// 使nextTickDOM
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();
});
},
},
};
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
.home-container { .home-container {
min-height: 100vh; min-height: 100vh;
background-color: #f8f8f8; background-color: #f5f7fc;
padding-bottom: calc(56px + env(safe-area-inset-bottom)); /* 为自定义tabBar预留空间 */ padding-bottom: calc(
112rpx + env(safe-area-inset-bottom)
.status-bar { ); /* 为自定义tabBar预留空间 */
background-color: #ffffff; padding-top: 88rpx;
}
.header { .header {
position: fixed;
top: 0;
left: 0;
right: 0;
background-color: #ffffff; background-color: #ffffff;
height: 44px; height: 88rpx;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: space-between;
padding: 0 15px; padding: 0 30rpx;
z-index: 99;
.title { .header-left {
font-size: 18px; font-size: 36rpx;
font-weight: bold; }
.header-title {
font-size: 36rpx;
font-weight: 500;
color: #333333; color: #333333;
} }
} }
.content { .content {
padding: 20px; padding: 30rpx;
.welcome-text { .welcome-message {
font-size: 16px; // display: inline-block;
// flex-wrap: wrap;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 16rpx;
padding: 24rpx;
margin-bottom: 30rpx;
.avatar {
display: inline-block;
width: 42rpx;
height: 34rpx;
margin-right: 12rpx;
background-color: #4377fe;
}
.message-text {
font-size: 24rpx;
color: #333333; color: #333333;
text-align: center; font-family: PingFang SC;
margin-bottom: 30px; vertical-align: super;
}
}
.qa-section {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
margin-bottom: 30rpx;
.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: 40rpx;
height: 40rpx;
margin-right: 12rpx;
}
.chat-text {
color: #ffffff;
font-size: 30rpx;
}
}
} }
.feature-grid { .feature-grid {
background-color: #ffffff;
border-radius: 16rpx;
padding: 30rpx;
display: flex; display: flex;
flex-wrap: wrap; justify-content: space-between;
margin: 0 -10px; margin-top: 40rpx;
gap: 30rpx;
.feature-item { .feature-item {
width: 50%; height: 210rpx;
padding: 10px; border-radius: 16rpx;
box-sizing: border-box; background-color: #fafafc;
// background-color: #4377fe;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center;
// gap: 20rpx;
flex: 1;
.feature-icon { .feature-icon {
width: 60px; width: 80rpx;
height: 60px; height: 80rpx;
margin-bottom: 10px; margin-bottom: 16rpx;
background-color: #e1f1ff; background-color: #e1e5f2;
border-radius: 15px; border-radius: 50%;
} }
.feature-text { .feature-text {
font-size: 14px; font-size: 26rpx;
color: #333333; 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;
height: calc(100vh - 300rpx);
background-color: #f5f8ff;
padding: 30rpx;
// padding-bottom: 200rpx; /* */
box-sizing: border-box;
.chat-scroll {
flex: 1;
flex-shrink: 0;
// overflow-y: auto; /* 使autoscroll */ //
}
.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;
background-color: #4370fe;
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: right;
}
}
}
.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: 32rpx;
height: 32rpx;
border-radius: 50%;
margin-right: 10rpx;
position: relative;
&.icon-people {
background-color: #4370fe;
&:before {
content: "";
position: absolute;
width: 15rpx;
height: 15rpx;
border-radius: 50%;
background-color: white;
top: 8rpx;
left: 12rpx;
}
&:after {
content: "";
position: absolute;
width: 24rpx;
height: 12rpx;
border: 2rpx solid white;
border-radius: 12rpx 12rpx 0 0;
border-bottom: none;
background-color: transparent;
bottom: 6rpx;
left: 7rpx;
}
}
&.icon-board {
background-color: #d0d0d0;
&:before {
content: "";
position: absolute;
width: 22rpx;
height: 15rpx;
background-color: white;
top: 12rpx;
left: 9rpx;
}
&:after {
content: "";
position: absolute;
width: 10rpx;
height: 5rpx;
border-radius: 0 0 10rpx 10rpx;
background-color: white;
top: 7rpx;
left: 15rpx;
}
}
&.icon-phone {
background-color: #d0d0d0;
&:before {
content: "";
position: absolute;
width: 20rpx;
height: 20rpx;
border: 2rpx solid white;
border-radius: 50%;
top: 8rpx;
left: 8rpx;
}
}
}
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: 30rpx;
height: 30rpx;
background-color: #4370fe;
clip-path: polygon(0% 0%, 0% 100%, 100% 50%);
}
}
}
}
}
}
</style> </style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
// 这是一个占位文件需要替换为实际的AI头像图标

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
// 这是一个占位文件,需要替换为实际的聊天图标

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@