YingXingAI/components/ChatHistory.vue

516 lines
13 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>
<u-popup v-model="showPopup" width="550rpx">
<view class="drawer-container">
<view class="drawer-header">
<view class="header-top">
<view class="header-tabs">
<u-tabs
:list="tabList"
:is-scroll="false"
:current="currentTab"
@change="changeTab"
bg-color="transparent"
active-color="#4F6AFF"
inactive-color="#505866"
bar-width="80"
font-size="32"
:bold="true"
></u-tabs>
</view>
<view class="header-icon" @click="handleHistoryClick">
<u-icon name="clock" size="40" color="#333333"></u-icon>
</view>
</view>
<view
class="drawer-title header-bottom"
@click="handleCreateConversation"
>
<u-icon
class="drawer-title-icon"
name="plus"
size="32rpx"
color="#666666"
></u-icon>
新建对话
</view>
</view>
<scroll-view
scroll-y
class="chat-history-list"
:scroll-into-view="scrollToView"
:show-scrollbar="false"
scroll-with-animation="true"
>
<!-- 使用新的数据结构渲染聊天历史 -->
<view
v-for="(group, groupIndex) in chatHistoryList3"
:key="'group-' + group.id + groupIndex"
@click="closePopover"
>
<!-- 日期标题 -->
<view class="chat-day">
<text class="day-text">{{ group.id }}</text>
</view>
<!-- 该日期下的对话列表 -->
<view
class="chat-item"
v-for="(item, index) in group.conversation"
:key="'conv-' + groupIndex + '-' + index"
:id="'chat-item-' + item.id"
:class="{
'chat-item-active': item.isActiveChat,
}"
@click.stop="
selectChatItem(groupIndex, index, item.id, item.conversationId)
"
>
<view class="chat-item-content">
<text class="chat-text u-line-1">{{ item.title }}</text>
<view
class="more-icon"
v-if="item.isActiveChat"
:id="'more-' + item.id"
@click.stop="togglePopover(item.id)"
>
<image
style="width: 40rpx; height: 40rpx"
src="/static/common/images/icon-more-white.png"
></image>
</view>
</view>
<!-- Popover菜单 -->
<view
class="popover-menu"
v-if="activePopoverId === item.id"
@click.stop
>
<view
class="popover-item"
@click.stop="
selectChatItem(
groupIndex,
index,
item.id,
item.conversationId
)
"
>
<u-icon
name="chat"
color="#4f6aff"
size="32"
custom-style="margin-right: 12rpx"
></u-icon>
<text class="popover-text" style="color: #4f6aff">回复</text>
</view>
<view class="popover-item" @click="handleDelete(item)">
<u-icon
name="trash"
color="#fa3534"
size="32"
custom-style="margin-right: 12rpx"
></u-icon>
<text class="popover-text" style="color: #fa3534">删除</text>
</view>
</view>
</view>
</view>
<!-- 添加底部空白区域 -->
<view class="bottom-space"></view>
</scroll-view>
<view class="drawer-footer">
<view class="user-info">
<image
class="user-avatar"
src="/static/common/images/avatar.png"
></image>
<text class="user-name">{{ userName || "晓德塔," }}</text>
</view>
<view class="settings" @click="handleSettingsClick">
<u-icon name="setting" size="40rpx" color="#999"></u-icon>
</view>
</view>
<!-- 删除确认弹窗使用 uView u-modal 组件实现 -->
<!-- <u-modal
border-radius="20rpx"
v-model="deleteConfirmShow"
title="提示"
content="删除后,该对话将不可恢复。确认删除吗?"
:show-cancel-button="true"
@confirm="confirmDelete"
@cancel="cancelDelete"
></u-modal> -->
</view>
</u-popup>
</template>
<script>
export default {
name: "ChatHistory",
props: {
show: {
type: Boolean,
default: false,
},
chatHistoryList3: {
type: Array,
default: () => [],
},
activeIndex: {
type: Number,
default: 0,
},
userName: {
type: String,
default: "",
},
},
data() {
return {
showPopup: false,
currentActiveGroup: -1,
currentActiveIndex: -1,
activeItemId: "", // 存储当前激活项的ID
scrollToView: "", // 用于scroll-into-view属性
tabList: [
{
name: "AI咨询",
},
{
name: "人工咨询",
},
],
currentTab: 0,
activePopoverId: null, // 当前打开的popover对应的itemId
// 删除确认弹窗的显示状态与目标项
// deleteConfirmShow: false,
// deleteTargetItem: null,
};
},
watch: {
show: {
handler(newVal) {
this.showPopup = newVal;
// 弹层每次打开时,收起右侧“回复/删除”浮窗
if (newVal) {
this.activePopoverId = null;
}
},
immediate: true,
},
showPopup(val) {
if (val !== this.show) {
this.$emit("update:show", val);
}
// 兼容从内部改变显示状态的场景,打开时关闭浮窗
if (val) {
this.activePopoverId = null;
}
},
// 监听聊天历史数据变化,找到激活项并滚动
chatHistoryList3: {
handler() {
this.$nextTick(() => {
this.scrollToActiveItem();
});
},
deep: true,
immediate: true,
},
},
methods: {
// 处理历史记录点击事件
handleHistoryClick() {
uni.navigateTo({
url: "/pages/home/history/history",
});
},
// 处理设置点击事件
handleSettingsClick() {
uni.navigateTo({
url: "/pages/home/userSetting/index",
});
},
// 关闭Popover
closePopover() {
this.activePopoverId = null;
},
// 切换Popover显示状态
togglePopover(itemId) {
if (this.activePopoverId === itemId) {
this.activePopoverId = null;
return;
}
this.activePopoverId = itemId;
},
// 处理回复(暂时无用)
// handleReply(item) {
// this.closePopover();
// // 这里添加回复逻辑,比如跳转或弹窗
// console.log("Reply to:", item);
// this.$emit("reply-conversation", item);
// },
// 处理删除
handleDelete(item) {
// 关闭右侧浮窗,弹出确认弹窗
this.closePopover();
// this.deleteTargetItem = item;
// this.deleteConfirmShow = true;
this.$u.api
.DeleteDialogueManagement({
id: [item.id],
})
.then((res) => {
if (res.succeed) {
this.$u.toast("删除成功");
// 刷新聊天历史数据
this.$emit("refresh-chat-history");
} else {
this.$u.toast(res.msg || "删除失败");
}
});
},
// // 确认删除:确认后发出删除事件并重置状态
// confirmDelete() {
// if (this.deleteTargetItem) {
// this.$emit("delete-conversation", this.deleteTargetItem);
// }
// this.deleteTargetItem = null;
// this.deleteConfirmShow = false;
// },
// // 取消删除:仅关闭弹窗并清空目标
// cancelDelete() {
// this.deleteConfirmShow = false;
// this.deleteTargetItem = null;
// },
// 滚动到激活的聊天项
scrollToActiveItem() {
// 查找激活的聊天项
let activeItemFound = false;
for (
let groupIndex = 0;
groupIndex < this.chatHistoryList3.length;
groupIndex++
) {
const group = this.chatHistoryList3[groupIndex];
for (let index = 0; index < group.conversation.length; index++) {
const item = group.conversation[index];
if (item.isActiveChat) {
activeItemFound = true;
this.activeItemId = `chat-item-${item.id}`;
// 设置scrollToView的值使scroll-view自动滚动到该元素
this.scrollToView = this.activeItemId;
break;
}
}
if (activeItemFound) break;
}
},
selectChatItem(groupIndex, index, id, conversationId) {
// this.currentActiveGroup = groupIndex;
// this.currentActiveIndex = index;
console.log("selectChatItem", groupIndex, index, id, conversationId);
// 向父组件发送选中的对话信息
this.$emit("select-conversation", {
id,
conversationId,
});
},
handleCreateConversation() {
this.$emit("create-conversation");
},
changeTab(index) {
this.currentTab = index;
},
},
};
</script>
<style lang="scss" scoped>
.drawer-container {
padding: 32rpx;
display: flex;
flex-direction: column;
height: 100vh;
background-color: #ffffff;
.drawer-header {
.header-top {
height: 80rpx;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20rpx;
.header-tabs {
width: 300rpx;
}
.header-icon {
width: 40rpx;
height: 40rpx;
}
}
.header-bottom {
padding: 16rpx 32rpx;
}
.drawer-title {
font-family: DouyinSans;
font-weight: bold;
font-size: 32rpx;
color: #666666;
.drawer-title-icon {
margin-right: 10rpx;
}
}
}
.chat-history-list {
flex: 1;
height: calc(100vh - 420rpx);
padding-bottom: 20rpx;
.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 24rpx 24rpx 30rpx;
border-radius: 16rpx;
margin-bottom: 4rpx;
position: relative;
// overflow: hidden; // 移除overflow hidden以便显示popover
.chat-item-content {
display: flex;
justify-content: space-between;
align-items: center;
width: 100%;
.more-icon {
width: 40rpx;
height: 40rpx;
}
}
.chat-text {
font-size: 28rpx;
color: #303030;
font-family: PingFang SC;
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
margin-right: 10rpx;
}
&-active {
background-color: #4f6aff;
box-shadow: 0 2rpx 8rpx rgba(79, 106, 255, 0.3);
.chat-text {
color: #fff;
}
}
.popover-menu {
width: 200rpx;
// 相对当前 chat-item 进行绝对定位,随 item 滚动
position: absolute;
right: 10rpx;
top: 80rpx;
background: linear-gradient(
135deg,
rgba(79, 106, 255, 0.02),
rgba(215, 237, 237, 0.01)
);
box-shadow: 0px 2px 8px 0px rgba(91, 92, 94, 0.3);
background-color: #ffffff;
border-radius: 20rpx;
padding: 10rpx 0;
z-index: 10005;
.popover-item {
display: flex;
gap: 12rpx;
justify-content: center;
align-items: center;
padding: 20rpx 30rpx;
&:active {
background-color: #f5f5f5;
}
.popover-text {
font-size: 28rpx;
font-family: PingFang SC;
font-weight: 500;
}
}
}
}
}
.bottom-space {
// 增加底部留白,避免最底部项的浮层阴影被裁剪
height: 200rpx;
width: 100%;
}
.drawer-footer {
margin-top: 20rpx;
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;
}
}
}
</style>