YingXingAI/pages/home/history/history.vue

656 lines
17 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 in groupedHistoryList"
:key="group.header"
>
<view class="date-header">{{ group.header }}</view>
<view class="history-item" v-for="item in group.items" :key="item.id">
<!-- 批量删除模式下的选择框 -->
<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">
<text class="icon-text">B</text>
</view>
<view class="item-title">{{ item.title }}</view>
</view>
<view class="item-description">{{ item.content }}</view>
</view>
</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";
export default {
components: {
HeaderBar,
},
data() {
return {
activeTab: "1", // 当前激活的tab
tabList: [
{ id: "1", name: "AI咨询" },
{ id: "2", name: "人工咨询" },
],
isBatchDeleteMode: false, // 是否为批量删除模式
isMoreMenuVisible: false, // 右上角更多菜单是否可见
selectedItems: [], // 选中的项目
selectAll: false, // 是否全选
historyList: [
{
id: 1,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime(), // 今天
type: "ai",
},
{
id: 2,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime(), // 今天
type: "ai",
},
{
id: 3,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime(), // 今天
type: "ai",
},
{
id: 4,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime(), // 今天
type: "ai",
},
{
id: 5,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime() - 24 * 60 * 60 * 1000 * 2, // 2天前
type: "ai",
},
{
id: 6,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime() - 365 * 24 * 60 * 60 * 1000, // 去年
type: "human",
},
{
id: 7,
title: "学校哪些专业比较好?",
content:
"学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?学校哪些专业比较好?",
time: new Date().getTime() - 24 * 60 * 60 * 1000 * 5, // 5天前
type: "human",
},
],
};
},
computed: {
// 根据当前tab过滤历史记录
filteredHistoryList() {
return this.historyList.filter((item) => {
if (this.activeTab === "1") {
return item.type === "ai";
} else {
return item.type === "human";
}
});
},
// 按日期分组后的历史记录(日期标题固定在上方)
groupedHistoryList() {
// 先按时间倒序
const list = [...this.filteredHistoryList].sort(
(a, b) => b.time - a.time
);
const groups = [];
let currentHeader = null;
let currentItems = [];
list.forEach((item) => {
const header = this.formatTime(item.time);
if (header !== currentHeader) {
if (currentItems.length) {
groups.push({ header: currentHeader, items: currentItems });
}
currentHeader = header;
currentItems = [item];
} else {
currentItems.push(item);
}
});
if (currentItems.length) {
groups.push({ header: currentHeader, items: currentItems });
}
return groups;
},
},
methods: {
// 格式化时间显示
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) {
this.activeTab = tab;
},
// 显示/隐藏右上角更多菜单
toggleMoreMenu() {
this.isMoreMenuVisible = !this.isMoreMenuVisible;
},
// 点击蒙层隐藏更多菜单
hideMoreMenu() {
this.isMoreMenuVisible = false;
},
// 取消批量删除模式
cancelBatchDelete() {
this.isBatchDeleteMode = false;
},
// 点击“批量删除”菜单项,进入批量删除模式
handleBatchDeleteClick() {
this.isMoreMenuVisible = false;
if (!this.isBatchDeleteMode) {
this.toggleBatchDeleteMode();
}
},
// 切换批量删除模式
toggleBatchDeleteMode() {
this.isBatchDeleteMode = !this.isBatchDeleteMode;
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 === this.filteredHistoryList.length;
},
// 切换全选状态
toggleSelectAll() {
this.selectAll = !this.selectAll;
if (this.selectAll) {
this.selectedItems = this.filteredHistoryList.map((item) => item.id);
} else {
this.selectedItems = [];
}
},
// 批量删除选中项
batchDelete() {
if (this.selectedItems.length === 0) {
this.$refs.uToast.show({
title: "请选择要删除的项目",
type: "warning",
});
return;
}
// 删除选中的项目
this.historyList = this.historyList.filter(
(item) => !this.selectedItems.includes(item.id)
);
// 重置状态
this.selectedItems = [];
this.selectAll = false;
this.isBatchDeleteMode = false;
this.$refs.uToast.show({
title: "删除成功",
type: "success",
});
},
handleDelete(item, callback) {
console.log("handleDelete", item);
setTimeout(() => {
this.$refs.uToast.show({
title: "撤回成功",
type: "success",
});
callback(true);
}, 1500);
},
},
};
</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 {
.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 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: 24rpx;
.item-icon {
width: 48rpx;
height: 48rpx;
background-color: #4f6aff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 16rpx;
.icon-text {
color: #ffffff;
font-size: 24rpx;
font-weight: bold;
}
}
.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>