2025-12-08 16:55:30 +08:00
|
|
|
|
<template>
|
|
|
|
|
|
<view class="chat-page">
|
|
|
|
|
|
<!-- 顶部导航 -->
|
|
|
|
|
|
<header-bar
|
2025-12-15 17:03:54 +08:00
|
|
|
|
:title="vuex_msgUser.name"
|
2025-12-08 16:55:30 +08:00
|
|
|
|
leftIcon="arrow-left"
|
|
|
|
|
|
@leftClick="handleLeftClick"
|
|
|
|
|
|
></header-bar>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 消息列表 -->
|
|
|
|
|
|
<view class="chat-container">
|
|
|
|
|
|
<scroll-view
|
|
|
|
|
|
class="chat-scroll"
|
|
|
|
|
|
scroll-y
|
|
|
|
|
|
:scroll-into-view="scrollToView"
|
2025-12-17 15:30:03 +08:00
|
|
|
|
:scroll-top="scrollTop"
|
2025-12-17 16:27:08 +08:00
|
|
|
|
:scroll-with-animation="!isLoading"
|
2025-12-17 15:30:03 +08:00
|
|
|
|
:upper-threshold="20"
|
|
|
|
|
|
@scroll="handleScroll"
|
|
|
|
|
|
@scrolltoupper="handleScrollToUpper"
|
2025-12-08 16:55:30 +08:00
|
|
|
|
>
|
2025-12-17 15:30:03 +08:00
|
|
|
|
<view class="chat-content">
|
|
|
|
|
|
<!-- 教师信息 -->
|
|
|
|
|
|
<div class="teacher-info-card">
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="teacher-avatar"
|
|
|
|
|
|
:src="receiverHeadSculptureUrl"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<div class="teacher-info">
|
|
|
|
|
|
<div class="teacher-name">{{ vuex_msgUser.name }}</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="teacher-school">
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="school-icon"
|
|
|
|
|
|
src="/static/common/images/icon_college.png"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<text class="school-text">{{ vuex_msgUser.collegeName }}</text>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="teacher-college">
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="college-icon"
|
|
|
|
|
|
src="/static/common/images/icon_major.png"
|
|
|
|
|
|
></image>
|
|
|
|
|
|
<text class="college-text">{{ vuex_msgUser.collegeName }}</text>
|
|
|
|
|
|
</div>
|
2025-12-12 17:03:54 +08:00
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
2025-12-17 16:27:08 +08:00
|
|
|
|
<!-- 上拉刷新loading -->
|
|
|
|
|
|
<view class="loading-more" v-if="isLoading">
|
|
|
|
|
|
<u-loading mode="circle" color="#4370fe"></u-loading>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 到顶部提示 -->
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="no-more-data"
|
|
|
|
|
|
v-if="noMoreData && vuex_msgList && vuex_msgList.length"
|
|
|
|
|
|
>
|
|
|
|
|
|
<text>已经到顶了</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-12-08 16:55:30 +08:00
|
|
|
|
<view
|
2025-12-17 15:30:03 +08:00
|
|
|
|
v-for="(message, index) in vuex_msgList"
|
|
|
|
|
|
:key="message.id"
|
2025-12-08 16:55:30 +08:00
|
|
|
|
:id="'msg-' + message.id"
|
|
|
|
|
|
>
|
2025-12-17 15:30:03 +08:00
|
|
|
|
<!-- 时间 -->
|
|
|
|
|
|
<view class="message-time" v-if="isShowTime(index)">
|
|
|
|
|
|
{{ formatShowTime(message.sendDate) }}
|
2025-12-08 16:55:30 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
|
2025-12-17 15:30:03 +08:00
|
|
|
|
<!-- 0 发送消息 -->
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="message-right"
|
|
|
|
|
|
v-if="message.senderId === vuex_user.Id"
|
|
|
|
|
|
:id="'msg-' + message.id"
|
|
|
|
|
|
>
|
|
|
|
|
|
<view class="message-content">
|
|
|
|
|
|
<text>{{ message.message }}</text>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="user-avatar"
|
|
|
|
|
|
:src="headSculptureUrl"
|
|
|
|
|
|
mode="scaleToFill"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 1 收到消息 -->
|
|
|
|
|
|
<view
|
|
|
|
|
|
class="message-left"
|
|
|
|
|
|
v-if="message.senderId !== vuex_user.Id"
|
|
|
|
|
|
:id="'msg-' + message.id"
|
|
|
|
|
|
>
|
|
|
|
|
|
<image
|
|
|
|
|
|
class="ai-avatar"
|
|
|
|
|
|
:src="receiverHeadSculptureUrl"
|
|
|
|
|
|
mode="scaleToFill"
|
|
|
|
|
|
/>
|
|
|
|
|
|
<view class="message-content">
|
|
|
|
|
|
<text>{{ message.message }}</text>
|
|
|
|
|
|
</view>
|
2025-12-08 16:55:30 +08:00
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
2025-12-17 13:49:44 +08:00
|
|
|
|
|
2025-12-17 15:30:03 +08:00
|
|
|
|
<!-- 底部间距 滚动锚点 -->
|
|
|
|
|
|
<view id="bottom-anchor" class="bottom-anchor"></view>
|
|
|
|
|
|
</view>
|
2025-12-08 16:55:30 +08:00
|
|
|
|
</scroll-view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
|
|
|
|
|
|
<!-- 输入栏 -->
|
|
|
|
|
|
<view class="chat-footer">
|
|
|
|
|
|
<view class="input-area">
|
|
|
|
|
|
<input
|
2025-12-09 09:19:02 +08:00
|
|
|
|
v-model="messageValue"
|
2025-12-08 16:55:30 +08:00
|
|
|
|
type="text"
|
|
|
|
|
|
class="chat-input"
|
|
|
|
|
|
:focus="true"
|
|
|
|
|
|
placeholder="请输入内容"
|
|
|
|
|
|
placeholder-style="color: #adadad;"
|
2025-12-09 09:19:02 +08:00
|
|
|
|
@confirm="handleSend"
|
2025-12-08 16:55:30 +08:00
|
|
|
|
/>
|
2025-12-09 09:19:02 +08:00
|
|
|
|
<view class="send-btn" @click="handleSend">
|
2025-12-08 16:55:30 +08:00
|
|
|
|
<image
|
|
|
|
|
|
class="send-icon"
|
|
|
|
|
|
src="/static/common/images/icon_send.png"
|
|
|
|
|
|
mode="scaleToFill"
|
|
|
|
|
|
/>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</view>
|
|
|
|
|
|
</template>
|
|
|
|
|
|
|
|
|
|
|
|
<script>
|
|
|
|
|
|
import HeaderBar from "@/components/HeaderBar.vue"; // 导入头部组件
|
2025-12-17 16:51:43 +08:00
|
|
|
|
import {
|
|
|
|
|
|
formatChatShowTime,
|
|
|
|
|
|
scrollToBottomByContentHeight,
|
|
|
|
|
|
shouldShowTime,
|
|
|
|
|
|
} from "@/utils/chat.js";
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
|
|
|
|
|
export default {
|
|
|
|
|
|
name: "ChatDetail",
|
|
|
|
|
|
components: {
|
|
|
|
|
|
HeaderBar, // 注册头部组件
|
|
|
|
|
|
},
|
|
|
|
|
|
data() {
|
|
|
|
|
|
return {
|
|
|
|
|
|
baseUrl: "",
|
|
|
|
|
|
|
|
|
|
|
|
// 头像
|
|
|
|
|
|
myAvatar: "/static/avatar/default-avatar.png",
|
|
|
|
|
|
otherAvatar: "/static/avatar/default-avatar.png",
|
|
|
|
|
|
|
|
|
|
|
|
// 消息列表
|
|
|
|
|
|
messageList: [
|
|
|
|
|
|
{
|
|
|
|
|
|
id: "9cac8661-bf09-4b63-ab15-1a0a36b91110",
|
|
|
|
|
|
message: "你知道今年的录取分数线吗",
|
|
|
|
|
|
sendDate: "2025-08-10T15:11:32.886075",
|
|
|
|
|
|
isSend: true,
|
|
|
|
|
|
isRead: false,
|
|
|
|
|
|
interactMode: 0,
|
|
|
|
|
|
messageType: 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
{
|
|
|
|
|
|
id: "02306fc3-c821-4a23-ad66-0bd788854105",
|
|
|
|
|
|
message: "回答。",
|
|
|
|
|
|
sendDate: "2025-08-10T15:11:36.88644",
|
|
|
|
|
|
isSend: true,
|
|
|
|
|
|
isRead: false,
|
|
|
|
|
|
interactMode: 1,
|
|
|
|
|
|
messageType: 0,
|
|
|
|
|
|
},
|
|
|
|
|
|
],
|
|
|
|
|
|
|
|
|
|
|
|
// 输入框
|
2025-12-09 09:19:02 +08:00
|
|
|
|
messageValue: "",
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 滚动位置
|
|
|
|
|
|
scrollToView: "",
|
2025-12-17 15:30:03 +08:00
|
|
|
|
scrollTop: 0,
|
|
|
|
|
|
currentScrollTop: 0,
|
|
|
|
|
|
currentScrollHeight: 0,
|
2025-12-09 16:11:45 +08:00
|
|
|
|
|
|
|
|
|
|
PageIndex: 1,
|
|
|
|
|
|
PageSize: 20,
|
2025-12-17 15:30:03 +08:00
|
|
|
|
|
2025-12-17 16:27:08 +08:00
|
|
|
|
isLoading: false,
|
|
|
|
|
|
noMoreData: false,
|
2025-12-08 16:55:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
onLoad(options) {
|
2025-12-09 16:11:45 +08:00
|
|
|
|
console.log(this.vuex_msgList);
|
2025-12-15 17:03:54 +08:00
|
|
|
|
console.log(this.vuex_msgUser, "this.vuex_msgUser");
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
2025-12-09 16:11:45 +08:00
|
|
|
|
this.baseUrl = this.$u.http.config.baseUrl;
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
|
|
|
|
|
// 加载历史消息
|
2025-12-09 16:11:45 +08:00
|
|
|
|
this.getMsgList();
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
computed: {
|
2025-12-17 13:49:44 +08:00
|
|
|
|
// 最后一条消息的ID
|
|
|
|
|
|
lastMsgId() {
|
|
|
|
|
|
const list = this.vuex_msgList || [];
|
|
|
|
|
|
if (!list.length) return "";
|
|
|
|
|
|
return list[list.length - 1]?.id || "";
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-12-12 17:03:54 +08:00
|
|
|
|
receiverHeadSculptureUrl() {
|
2025-12-15 17:03:54 +08:00
|
|
|
|
if (this.vuex_msgUser.headSculptureUrl) {
|
|
|
|
|
|
return this.baseUrl + "/" + this.vuex_msgUser.headSculptureUrl;
|
2025-12-12 17:03:54 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-15 10:39:55 +08:00
|
|
|
|
return "/static/common/images/avatar_default2.png";
|
2025-12-12 17:03:54 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2025-12-08 16:55:30 +08:00
|
|
|
|
headSculptureUrl() {
|
|
|
|
|
|
if (this.vuex_user.HeadSculptureUrl) {
|
|
|
|
|
|
return this.baseUrl + "/" + this.vuex_user.HeadSculptureUrl;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-17 13:49:44 +08:00
|
|
|
|
return "/static/common/images/avatar_default2.png";
|
|
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
watch: {
|
|
|
|
|
|
// 监听最后一条消息的ID变化,滚动到底部
|
|
|
|
|
|
lastMsgId(val) {
|
|
|
|
|
|
if (!val) return;
|
2025-12-17 16:27:08 +08:00
|
|
|
|
if (this.isLoading) return;
|
2025-12-17 13:49:44 +08:00
|
|
|
|
this.$nextTick(() => {
|
|
|
|
|
|
this.scrollToBottom();
|
|
|
|
|
|
});
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
methods: {
|
|
|
|
|
|
// 返回
|
|
|
|
|
|
handleLeftClick() {
|
|
|
|
|
|
uni.navigateBack();
|
|
|
|
|
|
},
|
|
|
|
|
|
|
2025-12-09 09:19:02 +08:00
|
|
|
|
// 点击发送
|
|
|
|
|
|
handleSend() {
|
|
|
|
|
|
if (!this.messageValue) {
|
2025-12-08 16:55:30 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 构建消息对象
|
|
|
|
|
|
const message = {
|
2025-12-09 16:11:45 +08:00
|
|
|
|
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
2025-12-17 10:51:29 +08:00
|
|
|
|
receiverId: this.vuex_msgUser.id,
|
2025-12-09 09:19:02 +08:00
|
|
|
|
message: this.messageValue,
|
2025-12-09 16:11:45 +08:00
|
|
|
|
messageType: 0,
|
2025-12-09 09:19:02 +08:00
|
|
|
|
filePath: "",
|
|
|
|
|
|
ip: "",
|
2025-12-08 16:55:30 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-12-09 09:19:02 +08:00
|
|
|
|
this.sendMsgFn(message);
|
|
|
|
|
|
},
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
2025-12-09 09:19:02 +08:00
|
|
|
|
// 发送消息
|
|
|
|
|
|
sendMsgFn(message) {
|
2025-12-09 16:11:45 +08:00
|
|
|
|
this.$u.api
|
|
|
|
|
|
.SendMessage_PrivateApi(message)
|
2025-12-09 09:19:02 +08:00
|
|
|
|
.then((res) => {
|
2025-12-09 16:11:45 +08:00
|
|
|
|
console.log(res, "发送消息成功");
|
|
|
|
|
|
if (res.succeed) {
|
|
|
|
|
|
// 添加到消息列表
|
|
|
|
|
|
const msgUserData = {
|
2025-12-09 16:36:04 +08:00
|
|
|
|
id: Math.random().toString(36).substring(2),
|
2025-12-09 16:11:45 +08:00
|
|
|
|
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
|
|
|
|
|
senderId: this.vuex_user.Id,
|
|
|
|
|
|
receiverId: this.vuex_msgUser.receiverId,
|
|
|
|
|
|
sendDate: new Date().toISOString(),
|
|
|
|
|
|
message: this.messageValue,
|
|
|
|
|
|
messageType: 0,
|
|
|
|
|
|
filePath: "",
|
2025-12-15 17:03:54 +08:00
|
|
|
|
// interactMode: 0,
|
2025-12-09 16:11:45 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
this.$store.commit("push_Msg", msgUserData);
|
|
|
|
|
|
// 清空输入框
|
|
|
|
|
|
this.messageValue = "";
|
2025-12-17 13:49:44 +08:00
|
|
|
|
// // 滚动到底部
|
|
|
|
|
|
// this.$nextTick(() => {
|
|
|
|
|
|
// this.scrollToBottom();
|
|
|
|
|
|
// });
|
2025-12-09 16:11:45 +08:00
|
|
|
|
}
|
2025-12-09 09:19:02 +08:00
|
|
|
|
})
|
|
|
|
|
|
.catch((error) => {
|
|
|
|
|
|
return msg.warning("发送失败");
|
|
|
|
|
|
});
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
2025-12-09 16:11:45 +08:00
|
|
|
|
// 加载对话消息
|
|
|
|
|
|
getMsgList() {
|
2025-12-17 16:27:08 +08:00
|
|
|
|
return this.$store
|
|
|
|
|
|
.dispatch("fetchChatRecord", {
|
|
|
|
|
|
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
|
|
|
|
|
PageIndex: this.PageIndex,
|
|
|
|
|
|
PageSize: this.PageSize,
|
|
|
|
|
|
})
|
|
|
|
|
|
.then((list) => {
|
|
|
|
|
|
const len = Array.isArray(list) ? list.length : 0;
|
2025-12-17 16:51:43 +08:00
|
|
|
|
// 第一页无数据,设置为没有更多数据
|
2025-12-17 16:42:52 +08:00
|
|
|
|
if (len === 0 && this.PageIndex === 1) {
|
2025-12-17 16:27:08 +08:00
|
|
|
|
this.noMoreData = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
return list;
|
|
|
|
|
|
});
|
2025-12-17 15:30:03 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
handleScroll(e) {
|
|
|
|
|
|
const detail = (e && e.detail) || {};
|
|
|
|
|
|
this.currentScrollTop = Number(detail.scrollTop) || 0;
|
|
|
|
|
|
this.currentScrollHeight = Number(detail.scrollHeight) || 0;
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到顶部,加载下一页历史消息
|
|
|
|
|
|
handleScrollToUpper() {
|
2025-12-17 16:27:08 +08:00
|
|
|
|
if (this.isLoading || this.noMoreData) return;
|
2025-12-17 15:30:03 +08:00
|
|
|
|
|
2025-12-17 16:27:08 +08:00
|
|
|
|
this.isLoading = true;
|
2025-12-17 15:30:03 +08:00
|
|
|
|
const beforeTop = this.currentScrollTop || 0;
|
|
|
|
|
|
const beforeHeight = this.currentScrollHeight || 0;
|
2025-12-17 16:27:08 +08:00
|
|
|
|
const nextPageIndex = this.PageIndex + 1;
|
2025-12-17 15:30:03 +08:00
|
|
|
|
this.scrollToView = "";
|
|
|
|
|
|
|
|
|
|
|
|
this.$store
|
|
|
|
|
|
.dispatch("fetchChatRecordNextPage", {
|
|
|
|
|
|
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
|
2025-12-17 16:27:08 +08:00
|
|
|
|
PageIndex: nextPageIndex,
|
2025-12-09 16:11:45 +08:00
|
|
|
|
PageSize: this.PageSize,
|
|
|
|
|
|
})
|
2025-12-17 15:30:03 +08:00
|
|
|
|
.then((list) => {
|
|
|
|
|
|
if (!list || !list.length) {
|
2025-12-17 16:27:08 +08:00
|
|
|
|
this.noMoreData = true;
|
2025-12-17 15:30:03 +08:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
2025-12-17 16:27:08 +08:00
|
|
|
|
this.PageIndex = nextPageIndex;
|
2025-12-17 16:42:52 +08:00
|
|
|
|
// this.$nextTick(() => {
|
|
|
|
|
|
// const query = uni.createSelectorQuery().in(this);
|
|
|
|
|
|
// query
|
|
|
|
|
|
// .select(".chat-content")
|
|
|
|
|
|
// .boundingClientRect((rect) => {
|
|
|
|
|
|
// const afterHeight = Number(rect && rect.height) || 0;
|
|
|
|
|
|
// const delta = afterHeight - beforeHeight;
|
|
|
|
|
|
// if (delta > 0) {
|
|
|
|
|
|
// this.scrollTop = beforeTop + delta;
|
|
|
|
|
|
// }
|
|
|
|
|
|
// })
|
|
|
|
|
|
// .exec();
|
|
|
|
|
|
// });
|
2025-12-17 15:30:03 +08:00
|
|
|
|
})
|
|
|
|
|
|
.finally(() => {
|
|
|
|
|
|
setTimeout(() => {
|
2025-12-17 16:27:08 +08:00
|
|
|
|
this.isLoading = false;
|
2025-12-17 16:42:52 +08:00
|
|
|
|
}, 100);
|
2025-12-09 16:11:45 +08:00
|
|
|
|
});
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 滚动到底部
|
|
|
|
|
|
scrollToBottom() {
|
2025-12-17 16:42:52 +08:00
|
|
|
|
if (this.isLoading) return;
|
2025-12-17 16:51:43 +08:00
|
|
|
|
scrollToBottomByContentHeight(this, {
|
|
|
|
|
|
selector: ".chat-content",
|
|
|
|
|
|
extraOffset: 200,
|
2025-12-17 16:42:52 +08:00
|
|
|
|
});
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
// 是否显示时间
|
|
|
|
|
|
isShowTime(index) {
|
2025-12-17 16:51:43 +08:00
|
|
|
|
return shouldShowTime(this.vuex_msgList, index);
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
// 格式化显示时间
|
|
|
|
|
|
formatShowTime(sendDate) {
|
2025-12-17 16:51:43 +08:00
|
|
|
|
return formatChatShowTime(sendDate);
|
2025-12-08 16:55:30 +08:00
|
|
|
|
},
|
|
|
|
|
|
},
|
|
|
|
|
|
};
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
|
|
.chat-page {
|
|
|
|
|
|
height: 100vh;
|
|
|
|
|
|
padding-top: 88rpx;
|
|
|
|
|
|
background-image: url("@/static/common/images/images_bg.png");
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
background-repeat: no-repeat;
|
|
|
|
|
|
background-size: 100% 100%;
|
|
|
|
|
|
background-position: 0 88rpx;
|
|
|
|
|
|
background-attachment: fixed;
|
|
|
|
|
|
|
|
|
|
|
|
.chat-container {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
|
padding: 0 30rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
height: calc(100vh - 88rpx - 146rpx);
|
|
|
|
|
|
position: relative;
|
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
|
|
|
|
|
|
|
.chat-scroll {
|
|
|
|
|
|
flex: 1;
|
|
|
|
|
|
height: 100%;
|
|
|
|
|
|
overflow-y: scroll;
|
|
|
|
|
|
|
2025-12-17 16:27:08 +08:00
|
|
|
|
.loading-more {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
}
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
2025-12-17 16:27:08 +08:00
|
|
|
|
.no-more-data {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999;
|
|
|
|
|
|
margin-bottom: 32rpx;
|
|
|
|
|
|
padding: 10rpx 0;
|
|
|
|
|
|
}
|
2025-12-08 16:55:30 +08:00
|
|
|
|
|
2025-12-12 17:03:54 +08:00
|
|
|
|
.teacher-info-card {
|
|
|
|
|
|
background-color: #ffffff;
|
2025-12-17 13:49:44 +08:00
|
|
|
|
padding: 32rpx;
|
2025-12-12 17:03:54 +08:00
|
|
|
|
border-radius: 16rpx;
|
|
|
|
|
|
margin: 30rpx 0;
|
|
|
|
|
|
box-shadow: 0 2rpx 10rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
margin-bottom: 36rpx;
|
|
|
|
|
|
|
|
|
|
|
|
.teacher-avatar {
|
|
|
|
|
|
width: 120rpx;
|
|
|
|
|
|
height: 120rpx;
|
|
|
|
|
|
border-radius: 10rpx;
|
2025-12-17 13:49:44 +08:00
|
|
|
|
margin-right: 36rpx;
|
2025-12-12 17:03:54 +08:00
|
|
|
|
object-fit: cover;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.teacher-info {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
flex-direction: column;
|
2025-12-17 13:49:44 +08:00
|
|
|
|
justify-content: space-evenly;
|
|
|
|
|
|
gap: 16rpx;
|
2025-12-12 17:03:54 +08:00
|
|
|
|
flex: 1;
|
|
|
|
|
|
|
|
|
|
|
|
.teacher-name {
|
|
|
|
|
|
font-family: PingFang SC;
|
|
|
|
|
|
font-weight: bold;
|
2025-12-17 13:49:44 +08:00
|
|
|
|
font-size: 36rpx;
|
2025-12-12 17:03:54 +08:00
|
|
|
|
color: #333333;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.teacher-school,
|
|
|
|
|
|
.teacher-college {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
align-items: center;
|
|
|
|
|
|
|
|
|
|
|
|
.school-icon,
|
|
|
|
|
|
.college-icon {
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
width: 24rpx;
|
|
|
|
|
|
height: 24rpx;
|
|
|
|
|
|
display: inline-block;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.school-text,
|
|
|
|
|
|
.college-text {
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #666666;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-08 16:55:30 +08:00
|
|
|
|
.message-time {
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
font-size: 24rpx;
|
|
|
|
|
|
color: #999999;
|
|
|
|
|
|
padding: 20rpx;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-left,
|
|
|
|
|
|
.message-right {
|
|
|
|
|
|
display: flex;
|
|
|
|
|
|
margin-bottom: 40rpx;
|
|
|
|
|
|
align-items: flex-start;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-left {
|
|
|
|
|
|
justify-content: flex-start;
|
|
|
|
|
|
flex-wrap: wrap; /* 允许反馈区换行到消息下方 */
|
|
|
|
|
|
|
|
|
|
|
|
.ai-avatar {
|
|
|
|
|
|
width: 64rpx;
|
|
|
|
|
|
height: 64rpx;
|
|
|
|
|
|
border-radius: 50%;
|
|
|
|
|
|
margin-right: 16rpx;
|
|
|
|
|
|
background-color: #f0f0f0;
|
|
|
|
|
|
flex-shrink: 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.message-content {
|
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
|
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;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-12-17 13:49:44 +08:00
|
|
|
|
|
|
|
|
|
|
.bottom-anchor {
|
|
|
|
|
|
height: 48rpx;
|
|
|
|
|
|
width: 100%;
|
|
|
|
|
|
}
|
2025-12-08 16:55:30 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.chat-footer {
|
|
|
|
|
|
position: absolute;
|
|
|
|
|
|
bottom: 0;
|
|
|
|
|
|
left: 0;
|
|
|
|
|
|
right: 0;
|
|
|
|
|
|
padding: 32rpx;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
background-color: #ffffff;
|
|
|
|
|
|
box-shadow: 0 -2rpx 10rpx rgba(0, 0, 0, 0.1);
|
|
|
|
|
|
|
|
|
|
|
|
.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>
|