YingXingAI/pages/home/history/index.vue

813 lines
21 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="history-page">
<header-bar title="历史记录" @leftClick="handleLeftClick"></header-bar>
<view class="tab-container">
<view class="custom-tab">
<view
v-for="tab in tabList"
:key="tab.id"
:class="['tab-item', { active: activeTab === tab.id }]"
@click="switchTab(tab.id)"
>
<text class="tab-text">{{ tab.name }}</text>
<view class="tab-underline" v-if="activeTab === tab.id"></view>
</view>
</view>
<view class="more-icon-container" @click="toggleMoreMenu">
<image
class="more-icon"
src="/static/common/images/icon-more.png"
mode="scaleToFill"
></image>
</view>
<!-- 右上角弹出菜单:批量删除 -->
<view v-if="isMoreMenuVisible" class="more-menu" @click.stop>
<view class="menu-card" @click="handleBatchDeleteClick">
<!-- <image
class="menu-icon"
src="/static/common/images/icon_delete.png"
mode="widthFix"
/> -->
<u-icon name="trash" color="#FF647D" size="28"></u-icon>
<text class="menu-text">批量删除</text>
</view>
</view>
</view>
<!-- 点击其他区域关闭弹层 -->
<view v-if="isMoreMenuVisible" class="overlay" @click="hideMoreMenu"></view>
<!-- 内容区域包装器 -->
<view class="content-wrapper">
<!-- 历史记录列表(按日期分组,日期固定在上方) -->
<view class="history-list">
<view
class="date-group"
v-for="(group, groupIndex) in currentHistoryList"
:key="groupIndex"
>
<view class="date-header">{{ group.id }}</view>
<view v-for="item in group.conversation" :key="item.id">
<uni-swipe-action ref="swipeActionRef">
<uni-swipe-action-item
:disabled="isBatchDeleteMode"
:threshold="0.3"
:auto-close="true"
@change="handleSwipeChange($event, item.id)"
>
<template v-slot:right>
<view
class="right-btn-box"
@touchend.stop="handleSingleDelete(item)"
>
<!-- <u-icon name="trash" color="#fff" size="34"></u-icon> -->
<image
src="/static/common/images/icon_delete.png"
mode="widthFix"
style="width: 32rpx; height: 32rpx"
/>
<text>删除</text>
</view>
</template>
<view
class="history-item"
:class="{
'no-right-radius': openedItems[item.id] === 'right',
}"
>
<!-- 批量删除模式下的选择框 -->
<view
class="item-checkbox"
v-if="isBatchDeleteMode"
@click="toggleItemSelection(item.id)"
>
<view
class="checkbox"
:class="{ checked: selectedItems.includes(item.id) }"
>
<text
class="checkmark"
v-if="selectedItems.includes(item.id)"
>✓</text
>
</view>
</view>
<!-- 历史记录内容 -->
<view class="item-content">
<view class="item-header">
<view class="item-icon">
<image
class="icon-image"
src="/static/common/images/icon_chat2.png"
/>
</view>
<view class="item-title">{{ item.title }}</view>
</view>
<!-- <view class="item-description">{{ item.content }}</view> -->
</view>
</view>
</uni-swipe-action-item>
</uni-swipe-action>
</view>
</view>
</view>
</view>
<!-- 批量删除操作栏 -->
<view class="batch-actions" v-if="isBatchDeleteMode">
<view class="select-all-container" @click="toggleSelectAll">
<view class="checkbox" :class="{ checked: selectAll }">
<text class="checkmark" v-if="selectAll">✓</text>
</view>
<text class="select-all-text">全选</text>
</view>
<view class="function-btn">
<view class="cancel-btn" @click="cancelBatchDelete">取消</view>
<view class="delete-btn" @click="batchDelete">删除</view>
</view>
</view>
<!-- 提示 -->
<u-toast ref="uToast" />
</view>
</template>
<script>
import HeaderBar from "@/components/HeaderBar.vue";
import UniSwipeAction from "@/uni_modules/uni-swipe-action/components/uni-swipe-action/uni-swipe-action.vue";
export default {
components: {
HeaderBar,
UniSwipeAction,
},
data() {
return {
activeTab: "1", // 当前激活的tab
tabList: [
{ id: "1", name: "AI咨询" },
{ id: "2", name: "人工咨询" },
],
isBatchDeleteMode: false, // 是否为批量删除模式
isMoreMenuVisible: false, // 右上角更多菜单是否可见
selectedItems: [], // 选中的项目
selectAll: false, // 是否全选
chatHistoryAI: [], // ai咨询历史记录
chatHistoryTeacher: [], // 人工咨询历史记录
openedItems: {}, // 记录每个项目的滑动状态
};
},
computed: {
// 当前tab的历史记录
currentHistoryList() {
if (this.activeTab === "1") {
return this.chatHistoryAI;
} else {
return this.chatHistoryTeacher;
}
},
currentHistoryItems() {
const groups = this.currentHistoryList || [];
const items = [];
groups.forEach((group) => {
const conversation = (group && group.conversation) || [];
conversation.forEach((item) => items.push(item));
});
return items;
},
currentHistoryItemIds() {
return this.currentHistoryItems.map((item) => item.id);
},
},
onLoad() {
this.getChatHistoryList();
// this.GetDialogueList_User();
},
methods: {
resetBatchState() {
this.selectedItems = [];
this.selectAll = false;
this.isBatchDeleteMode = false;
},
// 重置滑动状态
closeAllSwipeActions() {
const swipeActionRefs = this.$refs.swipeActionRef || [];
const refs = Array.isArray(swipeActionRefs)
? swipeActionRefs
: [swipeActionRefs];
refs.forEach((ref) => {
if (ref && typeof ref.closeAll === "function") {
ref.closeAll();
}
});
},
// 清空 openedItems 并调用 closeAllSwipeActions()
resetSwipeState() {
this.openedItems = {};
this.closeAllSwipeActions();
},
// 获取ai历史记录
async getChatHistoryList() {
this.$u.api.GetConversationPage().then((res) => {
this.chatHistoryAI = res.data;
// if (this.chatHistoryAI.length > 0) {
// this.chatHistoryAI = res.data.map((group) => {
// // 对每个组的conversation数组进行倒序排序
// return {
// ...group,
// conversation: group.conversation.sort((a, b) => {
// // 将日期字符串转换为时间戳并比较(倒序)
// return (
// new Date(b.startTime).getTime() -
// new Date(a.startTime).getTime()
// );
// }),
// };
// });
// }
// console.log("this.chatHistoryAI", this.chatHistoryAI);
});
},
// 获取人工咨询数据
async GetDialogueList_User() {
this.$u.api.GetDialogueList_UserApi().then((res) => {
this.chatHistoryTeacher = res.data;
// if (this.chatHistoryTeacher.length > 0) {
// this.chatHistoryTeacher = res.data.map((group) => {
// // 对每个组的conversation数组进行倒序排序
// return {
// ...group,
// conversation: group.conversation.sort((a, b) => {
// // 将日期字符串转换为时间戳并比较(倒序)
// return (
// new Date(b.startTime).getTime() -
// new Date(a.startTime).getTime()
// );
// }),
// };
// });
// }
});
},
// 格式化时间显示
formatTime(timestamp) {
const now = new Date();
const date = new Date(timestamp);
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const itemDate = new Date(
date.getFullYear(),
date.getMonth(),
date.getDate()
);
// 计算时间差
const diffTime = today.getTime() - itemDate.getTime();
const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));
// 今天
if (diffDays === 0) {
return `${String(date.getMonth() + 1).padStart(2, "0")}/${String(
date.getDate()
).padStart(2, "0")}`;
}
// 本周内1-6天前
if (diffDays > 0 && diffDays <= 6) {
const weekdays = [
"周日",
"周一",
"周二",
"周三",
"周四",
"周五",
"周六",
];
return weekdays[date.getDay()];
}
// 今年但不是本周
if (date.getFullYear() === now.getFullYear()) {
return `${String(date.getMonth() + 1).padStart(2, "0")}/${String(
date.getDate()
).padStart(2, "0")}`;
}
// 往年
return `${date.getFullYear()}/${String(date.getMonth() + 1).padStart(
2,
"0"
)}/${String(date.getDate()).padStart(2, "0")}`;
},
handleLeftClick() {
uni.navigateBack();
},
switchTab(tab) {
if (this.activeTab === tab) return;
// 批量删除模式下切换tab时清空选中项
if (this.isBatchDeleteMode) {
this.selectedItems = [];
this.selectAll = false;
}
this.activeTab = tab;
this.resetSwipeState();
// 切换tab时刷新当前tab的历史记录
if (tab === "1") {
this.getChatHistoryList();
} else {
this.GetDialogueList_User();
}
},
// 显示/隐藏右上角更多菜单
toggleMoreMenu() {
if (this.isBatchDeleteMode) return;
this.isMoreMenuVisible = !this.isMoreMenuVisible;
},
// 点击蒙层隐藏更多菜单
hideMoreMenu() {
this.isMoreMenuVisible = false;
},
// 取消批量删除模式
cancelBatchDelete() {
this.resetBatchState();
this.resetSwipeState();
},
// 点击“批量删除”菜单项,进入批量删除模式
handleBatchDeleteClick() {
this.isMoreMenuVisible = false;
if (!this.isBatchDeleteMode) {
this.toggleBatchDeleteMode();
}
},
// 切换批量删除模式
toggleBatchDeleteMode() {
this.isBatchDeleteMode = !this.isBatchDeleteMode;
if (this.isBatchDeleteMode) {
this.resetSwipeState();
}
if (!this.isBatchDeleteMode) {
// 退出批量删除模式时清空选中项
this.selectedItems = [];
this.selectAll = false;
}
},
// 切换单个项目选中状态
toggleItemSelection(itemId) {
const index = this.selectedItems.indexOf(itemId);
if (index > -1) {
this.selectedItems.splice(index, 1);
} else {
this.selectedItems.push(itemId);
}
// 更新全选状态
this.selectAll =
this.selectedItems.length > 0 &&
this.selectedItems.length === this.currentHistoryItemIds.length;
},
// 切换全选状态
toggleSelectAll() {
const allIds = this.currentHistoryItemIds || [];
if (!allIds.length) {
this.selectAll = false;
this.selectedItems = [];
return;
}
this.selectAll = !this.selectAll;
if (this.selectAll) {
this.selectedItems = [...allIds];
} else {
this.selectedItems = [];
}
},
// 批量删除选中项
async batchDelete() {
if (this.selectedItems.length === 0) {
this.$refs.uToast.show({
title: "请选择要删除的记录",
type: "warning",
});
return;
}
const deleteIds = [...this.selectedItems];
const isAiTab = this.activeTab === "1";
try {
let res = null;
if (isAiTab) {
res = await this.$u.api.DeleteDialogueManagement({ id: deleteIds });
} else {
res = await this.$u.api.DeleteDialogueApi({
dialogueManagementIds: deleteIds,
});
}
if (res && res.succeed === true) {
this.resetBatchState();
if (isAiTab) {
this.getChatHistoryList();
} else {
this.GetDialogueList_User();
}
this.$refs.uToast.show({
title: "删除成功",
type: "success",
});
return;
}
this.$refs.uToast.show({
title: (res && (res.msg || res.message)) || "删除失败",
type: "error",
});
} catch (e) {
this.$refs.uToast.show({
title: "删除失败",
type: "error",
});
}
},
// 处理滑动操作变化
handleSwipeChange(e, itemId) {
this.$set(this.openedItems, itemId, e);
},
// 处理单个删除操作
async handleSingleDelete(item) {
if (!item || !item.id) return;
if (this.isBatchDeleteMode) return;
const isAiTab = this.activeTab === "1";
const deleteIds = [item.id];
try {
let res = null;
if (isAiTab) {
res = await this.$u.api.DeleteDialogueManagement({ id: deleteIds });
} else {
res = await this.$u.api.DeleteDialogueApi({
dialogueManagementIds: deleteIds,
});
}
if (res && res.succeed === true) {
if (isAiTab) {
this.getChatHistoryList();
} else {
this.GetDialogueList_User();
}
this.$refs.uToast.show({
title: "删除成功",
type: "success",
});
return;
}
this.$refs.uToast.show({
title: (res && (res.msg || res.message)) || "删除失败",
type: "error",
});
} catch (e) {
this.$refs.uToast.show({
title: "删除失败",
type: "error",
});
}
},
},
};
</script>
<style lang="scss" scoped>
.history-page {
height: 100vh;
background-color: #ffffff;
display: flex;
flex-direction: column;
position: relative;
padding-top: 88rpx;
.tab-container {
display: flex;
justify-content: space-between;
align-items: center;
position: relative;
}
.custom-tab {
padding: 0 30rpx;
margin: 24rpx 0;
display: flex;
justify-content: space-between;
align-items: center;
.tab-item {
position: relative;
padding: 12rpx 0;
margin-right: 80rpx;
cursor: pointer;
.tab-text {
font-size: 32rpx;
font-weight: 500;
color: #505866;
letter-spacing: 0.04rpx;
}
&.active .tab-text {
color: #4f6aff;
font-weight: 600;
}
.tab-underline {
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
right: 0;
width: 80rpx;
height: 4rpx;
background-color: #4f6aff;
border-radius: 2rpx;
}
}
}
.more-icon-container {
width: 50rpx;
height: 50rpx;
margin-right: 30rpx;
.more-icon {
width: 50rpx;
height: 10rpx;
margin-right: 30rpx;
}
}
/* 右上角更多菜单弹层 */
.more-menu {
position: absolute;
top: 80rpx;
right: 30rpx;
z-index: 100;
background-color: #ffffff;
border: 1rpx solid rgba(79, 106, 255, 0.12);
border-radius: 24rpx;
box-shadow: 0 8rpx 24rpx rgba(0, 0, 0, 0.08);
padding: 24rpx 28rpx;
}
.menu-card {
display: flex;
align-items: center;
gap: 6rpx;
// .menu-icon {
// color: #FF647D;
// width: 32rpx;
// height: 32rpx;
// margin-right: 12rpx;
// }
.menu-text {
font-size: 28rpx;
color: #ff647d;
letter-spacing: 2rpx;
}
}
/* 点击其它区域关闭的遮罩(透明) */
.overlay {
position: fixed;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 99;
background: rgba(0, 0, 0, 0);
}
.content-wrapper {
padding: 30rpx;
flex: 1;
overflow-y: auto;
}
.history-list {
.right-btn-box {
width: 160rpx;
color: #ffffff;
background-color: #ff4757;
display: flex;
flex-direction: column;
gap: 10rpx;
align-items: center;
justify-content: center;
border-radius: 0 16rpx 16rpx 0;
border-left: 1px solid #fff;
}
.date-group {
margin-bottom: 32rpx;
}
.date-header {
font-size: 26rpx;
color: #9aa0a8;
margin-bottom: 16rpx;
line-height: 1;
}
.history-item {
display: flex;
align-items: flex-start;
padding: 24rpx;
background-color: #ffffff;
border-radius: 16rpx;
transition: border-radius 0.3s;
&.no-right-radius {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.item-checkbox {
margin-right: 24rpx;
padding-top: 8rpx;
cursor: pointer;
width: 48rpx;
flex: 0 0 48rpx; /* 固定宽度,避免内容因显隐而抖动 */
.checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #d9d9d9;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: #ffffff;
&.checked {
background-color: #ff4757;
border-color: #ff4757;
.checkmark {
color: #ffffff;
font-size: 22rpx;
font-weight: bold;
}
}
}
}
.item-content {
flex: 1;
.item-header {
display: flex;
align-items: center;
margin-bottom: 30rpx;
.item-icon {
width: 50rpx;
height: 50rpx;
background-color: rgba(79, 106, 255, 0.1);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
.icon-image {
width: 26rpx;
height: 26rpx;
}
}
.item-title {
font-size: 32rpx;
font-weight: bold;
color: #333333;
flex: 1;
}
}
.item-description {
letter-spacing: 0.04rpx;
font-size: 28rpx;
color: #666666;
line-height: 1.5;
margin-bottom: 12rpx;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
}
}
}
}
.batch-actions {
height: 130rpx;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 30rpx;
border-top: 1rpx solid #eeeeee;
.select-all-container {
display: flex;
align-items: center;
cursor: pointer;
.checkbox {
width: 40rpx;
height: 40rpx;
border: 2rpx solid #d9d9d9;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
background-color: #ffffff;
&.checked {
background-color: #ff4757;
border-color: #ff4757;
.checkmark {
color: #ffffff;
font-size: 22rpx;
font-weight: bold;
}
}
}
.select-all-text {
margin-left: 16rpx;
font-size: 28rpx;
color: #333333;
}
}
.function-btn {
display: flex;
align-items: center;
gap: 20rpx;
.cancel-btn {
background-color: #e5e3e3e4;
color: #333333;
padding: 16rpx 32rpx;
border-radius: 16rpx;
font-size: 28rpx;
cursor: pointer;
}
.delete-btn {
background-color: #ff4757;
color: #ffffff;
padding: 16rpx 32rpx;
border-radius: 16rpx;
font-size: 28rpx;
cursor: pointer;
}
}
}
}
</style>