YingXingAI/pages/chat/index.vue

573 lines
14 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="chat-page">
<!-- 顶部导航 -->
<header-bar
:title="vuex_msgUser.name"
leftIcon="arrow-left"
@leftClick="handleLeftClick"
></header-bar>
<!-- 消息列表 -->
<view class="chat-container">
<scroll-view
class="chat-scroll"
scroll-y
:scroll-into-view="scrollToView"
scroll-with-animation
>
<!-- 教师信息 -->
<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>
</div>
</div>
<view
v-for="(message, index) in vuex_msgList"
:key="message.id"
:id="'msg-' + message.id"
>
<!-- 时间 -->
<view class="message-time" v-if="isShowTime(index)">
{{ formatShowTime(message.sendDate) }}
</view>
<!-- 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>
</view>
</view>
<!-- 底部间距 滚动锚点 -->
<view id="bottom-anchor" class="bottom-anchor"></view>
</scroll-view>
</view>
<!-- 输入栏 -->
<view class="chat-footer">
<view class="input-area">
<input
v-model="messageValue"
type="text"
class="chat-input"
:focus="true"
placeholder="请输入内容"
placeholder-style="color: #adadad;"
@confirm="handleSend"
/>
<view class="send-btn" @click="handleSend">
<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"; // 导入头部组件
import dayjs from "dayjs"; // 导入 dayjs
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,
},
],
// 输入框
messageValue: "",
// 滚动位置
scrollToView: "",
PageIndex: 1,
PageSize: 20,
};
},
onLoad(options) {
console.log(this.vuex_msgList);
console.log(this.vuex_msgUser, "this.vuex_msgUser");
this.baseUrl = this.$u.http.config.baseUrl;
// 加载历史消息
this.getMsgList();
},
computed: {
// 最后一条消息的ID
lastMsgId() {
const list = this.vuex_msgList || [];
if (!list.length) return "";
return list[list.length - 1]?.id || "";
},
receiverHeadSculptureUrl() {
if (this.vuex_msgUser.headSculptureUrl) {
return this.baseUrl + "/" + this.vuex_msgUser.headSculptureUrl;
}
return "/static/common/images/avatar_default2.png";
},
headSculptureUrl() {
if (this.vuex_user.HeadSculptureUrl) {
return this.baseUrl + "/" + this.vuex_user.HeadSculptureUrl;
}
return "/static/common/images/avatar_default2.png";
},
},
watch: {
// 监听最后一条消息的ID变化滚动到底部
lastMsgId(val) {
if (!val) return;
this.$nextTick(() => {
this.scrollToBottom();
});
},
},
methods: {
// 返回
handleLeftClick() {
uni.navigateBack();
},
// 点击发送
handleSend() {
if (!this.messageValue) {
return;
}
// 构建消息对象
const message = {
dialogueManagementId: this.vuex_msgUser.dialogueManagementId,
receiverId: this.vuex_msgUser.id,
message: this.messageValue,
messageType: 0,
filePath: "",
ip: "",
};
this.sendMsgFn(message);
},
// 发送消息
sendMsgFn(message) {
this.$u.api
.SendMessage_PrivateApi(message)
.then((res) => {
console.log(res, "发送消息成功");
if (res.succeed) {
// 添加到消息列表
const msgUserData = {
id: Math.random().toString(36).substring(2),
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: "",
// interactMode: 0,
};
this.$store.commit("push_Msg", msgUserData);
// 清空输入框
this.messageValue = "";
// // 滚动到底部
// this.$nextTick(() => {
// this.scrollToBottom();
// });
}
})
.catch((error) => {
return msg.warning("发送失败");
});
},
// 加载对话消息
getMsgList() {
this.$u.api
.GetChatHistoryDataApi({
"Item1.DialogueManagementId": this.vuex_msgUser.dialogueManagementId,
PageIndex: this.PageIndex,
PageSize: this.PageSize,
})
.then((res) => {
const msgList = res.data.item1.reverse();
this.$store.commit("push_MsgList", msgList);
// // 滚动到底部
// this.$nextTick(() => {
// this.scrollToBottom();
// });
});
},
// 滚动到底部
scrollToBottom() {
// if (this.vuex_msglist.length > 0) {
// const lastMsg = this.vuex_msglist[this.vuex_msglist.length - 1];
// this.scrollToView = "msg-" + lastMsg.id;
// }
// 滚动到底部锚点
if (this.scrollToView === "bottom-anchor") {
this.scrollToView = "";
this.$nextTick(() => {
this.scrollToView = "bottom-anchor";
});
return;
}
this.scrollToView = "bottom-anchor";
},
// 格式化时间
formatTime(date) {
const hours = date.getHours().toString().padStart(2, "0");
const minutes = date.getMinutes().toString().padStart(2, "0");
return `${hours}:${minutes}`;
},
// 是否显示时间
isShowTime(index) {
if (index == 0) {
return true;
}
let isTime = new Date(this.vuex_msgList[index].sendDate).getTime(); //当前时间
const time = new Date(this.vuex_msgList[index - 1].sendDate).getTime(); //上条消息的时间
// 30 分钟内不显示时间提示
return isTime - time > 30 * 60 * 1000;
},
// 格式化显示时间
formatShowTime(sendDate) {
// 《消息时间为今天发送》 1分钟内显示 ‘刚刚’ 超过一分钟 且小于60分钟 显示 x分钟前 大于等于60分钟显示 ‘今天 hh:mm
// 《消息时间为昨天发送》显示 ‘昨天 hh:mm
// 《消息时间为昨天以前,并且是今年发起》 显示 MM月DD日 hh:mm
// 《消息时间为往年发送》 显示 YYYY年MM月DD日
var isTime = dayjs(); //当前时间
var msgTime = dayjs(sendDate); //消息发送时间
if (isTime.diff(msgTime, "second") < 60) {
return "刚刚";
}
if (isTime.diff(msgTime, "hour") < 1) {
return `${isTime.diff(msgTime, "minute")}分钟前`;
}
// 使用 startOf('day') 获取当天 00:00:00
var today = dayjs().startOf("day");
var msgDay = dayjs(sendDate).startOf("day");
var dayDiff = today.diff(msgDay, "day");
if (dayDiff === 0) {
return `今天 ${msgTime.format("HH:mm")}`;
}
if (dayDiff === 1) {
return `昨天 ${msgTime.format("HH:mm")}`;
}
// 使用 startOf('year') 获取当年第一天
var thisYear = dayjs().startOf("year");
var msgYear = dayjs(sendDate).startOf("year");
var yearDiff = thisYear.diff(msgYear, "year");
if (yearDiff === 0) {
// 今年
return `${msgTime.format("MM月DD日 HH:mm")}`; // 原代码这里有一处是 HH:mm:ss但注释和逻辑看来 HH:mm 更一致,根据需求调整
}
// 往年
return `${msgTime.format("YYYY年MM月DD日 HH:mm")}`;
},
},
};
</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;
// .loading-more {
// text-align: center;
// margin-bottom: 32rpx;
// }
// .no-more-data {
// text-align: center;
// font-size: 24rpx;
// color: #999;
// margin-bottom: 32rpx;
// padding: 10rpx 0;
// }
.teacher-info-card {
background-color: #ffffff;
padding: 32rpx;
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;
margin-right: 36rpx;
object-fit: cover;
}
.teacher-info {
display: flex;
flex-direction: column;
justify-content: space-evenly;
gap: 16rpx;
flex: 1;
.teacher-name {
font-family: PingFang SC;
font-weight: bold;
font-size: 36rpx;
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;
}
}
}
}
.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;
}
}
.bottom-anchor {
height: 48rpx;
width: 100%;
}
}
}
.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>