删除聊天记录功能开发
This commit is contained in:
@@ -1,7 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<view class="chat-container">
|
<view class="chat-container">
|
||||||
|
<!-- 选择模式操作栏 -->
|
||||||
|
<view v-if="isSelectMode" class="select-mode-header">
|
||||||
|
<view class="select-header-left">
|
||||||
|
<view class="select-count">{{ selectedMessages.length }} 条已选择</view>
|
||||||
|
<view class="select-all" @click="selectAllMessages">全选</view>
|
||||||
|
</view>
|
||||||
|
<view class="select-header-right">
|
||||||
|
<view class="cancel-btn" @click="exitSelectMode">取消</view>
|
||||||
|
<view class="delete-btn" @click="deleteSelectedMessages" :disabled="selectedMessages.length === 0">删除</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<!-- Tab切换 -->
|
<!-- Tab切换 -->
|
||||||
<view class="tab-container">
|
<view v-else class="tab-container">
|
||||||
<view
|
<view
|
||||||
class="tab-item"
|
class="tab-item"
|
||||||
:class="{ active: activeTab === 'policy' }"
|
:class="{ active: activeTab === 'policy' }"
|
||||||
@@ -74,7 +85,15 @@
|
|||||||
:id="'msg-' + index"
|
:id="'msg-' + index"
|
||||||
class="chat-item"
|
class="chat-item"
|
||||||
:class="{ self: msg.self }"
|
:class="{ self: msg.self }"
|
||||||
|
@longpress="handleLongPress(msg, index)"
|
||||||
|
@click="isSelectMode ? toggleSelectMessage(index) : null"
|
||||||
>
|
>
|
||||||
|
<!-- 选择框 -->
|
||||||
|
<view v-if="isSelectMode" class="message-checkbox">
|
||||||
|
<view class="checkbox" :class="{ checked: selectedMessages.includes(index) }">
|
||||||
|
<uni-icons v-if="selectedMessages.includes(index)" type="success" size="24" color="#FFFFFF"></uni-icons>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
<view class="message" v-if="msg.self">
|
<view class="message" v-if="msg.self">
|
||||||
<view class="msg-filecontent" v-if="msg.files.length">
|
<view class="msg-filecontent" v-if="msg.files.length">
|
||||||
<view
|
<view
|
||||||
@@ -96,7 +115,7 @@
|
|||||||
:content="msg.displayText"
|
:content="msg.displayText"
|
||||||
:typing="isTyping && messages.length - 1 === index"
|
:typing="isTyping && messages.length - 1 === index"
|
||||||
></md-render>
|
></md-render>
|
||||||
<view class="message-controll" v-show="showControll(index)">
|
<view class="message-controll" v-show="showControll(index) && !isSelectMode">
|
||||||
<view class="controll-left">
|
<view class="controll-left">
|
||||||
<image
|
<image
|
||||||
class="controll-icon btn-light"
|
class="controll-icon btn-light"
|
||||||
@@ -134,7 +153,7 @@
|
|||||||
<!-- guess -->
|
<!-- guess -->
|
||||||
<view
|
<view
|
||||||
class="guess"
|
class="guess"
|
||||||
v-if="showGuess && !msg.self && messages.length - 1 === index && msg.displayText"
|
v-if="showGuess && !msg.self && messages.length - 1 === index && msg.displayText && !isSelectMode"
|
||||||
>
|
>
|
||||||
<view class="gulist">
|
<view class="gulist">
|
||||||
<view
|
<view
|
||||||
@@ -386,6 +405,9 @@ const cancelThreshold = 100;
|
|||||||
const speechIndex = ref(0);
|
const speechIndex = ref(0);
|
||||||
const isAudioPermission = ref(false);
|
const isAudioPermission = ref(false);
|
||||||
const feebackData = ref(null);
|
const feebackData = ref(null);
|
||||||
|
// 删除功能相关状态
|
||||||
|
const isSelectMode = ref(false);
|
||||||
|
const selectedMessages = ref([]);
|
||||||
// ref for DOM element
|
// ref for DOM element
|
||||||
const voiceBtn = ref(null);
|
const voiceBtn = ref(null);
|
||||||
const feeback = ref(null);
|
const feeback = ref(null);
|
||||||
@@ -942,6 +964,88 @@ function shouldShowMessage(msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 长按事件处理函数
|
||||||
|
function handleLongPress(msg, index) {
|
||||||
|
isSelectMode.value = true;
|
||||||
|
selectedMessages.value = [index];
|
||||||
|
|
||||||
|
// 如果长按的是用户消息,同时选中对应的AI回复
|
||||||
|
if (msg.self) {
|
||||||
|
const nextIndex = index + 1;
|
||||||
|
if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
|
||||||
|
selectedMessages.value.push(nextIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择/取消选择消息
|
||||||
|
function toggleSelectMessage(index) {
|
||||||
|
const msg = messages.value[index];
|
||||||
|
const idx = selectedMessages.value.indexOf(index);
|
||||||
|
|
||||||
|
if (idx > -1) {
|
||||||
|
// 取消选择
|
||||||
|
selectedMessages.value.splice(idx, 1);
|
||||||
|
|
||||||
|
// 如果取消选择的是用户消息,同时取消选择对应的AI回复
|
||||||
|
if (msg.self) {
|
||||||
|
const nextIndex = index + 1;
|
||||||
|
if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
|
||||||
|
const aiIdx = selectedMessages.value.indexOf(nextIndex);
|
||||||
|
if (aiIdx > -1) {
|
||||||
|
selectedMessages.value.splice(aiIdx, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedMessages.value.length === 0) {
|
||||||
|
isSelectMode.value = false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 选择消息
|
||||||
|
selectedMessages.value.push(index);
|
||||||
|
|
||||||
|
// 如果选择的是用户消息,同时选择对应的AI回复
|
||||||
|
if (msg.self) {
|
||||||
|
const nextIndex = index + 1;
|
||||||
|
if (nextIndex < messages.value.length && !messages.value[nextIndex].self) {
|
||||||
|
if (!selectedMessages.value.includes(nextIndex)) {
|
||||||
|
selectedMessages.value.push(nextIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 退出选择模式
|
||||||
|
function exitSelectMode() {
|
||||||
|
isSelectMode.value = false;
|
||||||
|
selectedMessages.value = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全选消息
|
||||||
|
function selectAllMessages() {
|
||||||
|
selectedMessages.value = messages.value.map((_, index) => index);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 删除选中消息
|
||||||
|
function deleteSelectedMessages() {
|
||||||
|
if (selectedMessages.value.length === 0) return;
|
||||||
|
|
||||||
|
uni.showModal({
|
||||||
|
content: `确定删除${selectedMessages.value.length}条消息吗?`,
|
||||||
|
success(res) {
|
||||||
|
if (res.confirm) {
|
||||||
|
// 调用store中的删除方法
|
||||||
|
useChatGroupDBStore().deleteMessages(selectedMessages.value);
|
||||||
|
// 退出选择模式
|
||||||
|
exitSelectMode();
|
||||||
|
$api.msg('消息删除成功');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
defineExpose({ scrollToBottom, closeGuess, closeFile, changeQueries, handleTouchCancel, switchTab });
|
defineExpose({ scrollToBottom, closeGuess, closeFile, changeQueries, handleTouchCancel, switchTab });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -1473,4 +1577,88 @@ image-margin-top = 40rpx
|
|||||||
.tab-item:active {
|
.tab-item:active {
|
||||||
background-color: #F5F5F5;
|
background-color: #F5F5F5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 选择模式样式 */
|
||||||
|
.select-mode-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0 44rpx;
|
||||||
|
height: 88rpx;
|
||||||
|
background: #FFFFFF;
|
||||||
|
border-bottom: 2rpx solid #F4F4F4;
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-header-left {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 24rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-count {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #333333;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-all {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #256BFA;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.select-header-right {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 32rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cancel-btn {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #666666;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
font-size: 28rpx;
|
||||||
|
color: #FF4444;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn:disabled {
|
||||||
|
color: #CCCCCC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 消息选择框样式 */
|
||||||
|
.message-checkbox {
|
||||||
|
margin-right: 12rpx;
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
padding-top: 8rpx;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox {
|
||||||
|
width: 40rpx;
|
||||||
|
height: 40rpx;
|
||||||
|
border: 2rpx solid #CCCCCC;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.checkbox.checked {
|
||||||
|
background-color: #256BFA;
|
||||||
|
border-color: #256BFA;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 调整消息项布局,为选择框留出空间 */
|
||||||
|
.chat-item {
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chat-item .message {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -335,6 +335,22 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 删除消息
|
||||||
|
async function deleteMessages(indices) {
|
||||||
|
// 按索引从大到小排序,避免删除时索引变化
|
||||||
|
const sortedIndices = [...indices].sort((a, b) => b - a);
|
||||||
|
|
||||||
|
// 从内存中删除消息
|
||||||
|
for (const index of sortedIndices) {
|
||||||
|
const message = messages.value[index];
|
||||||
|
if (message && message.id) {
|
||||||
|
// 从本地数据库中删除
|
||||||
|
await baseDB.db.delete(massageName.value, message.id);
|
||||||
|
}
|
||||||
|
messages.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
messages,
|
messages,
|
||||||
isTyping,
|
isTyping,
|
||||||
@@ -348,7 +364,8 @@ const useChatGroupDBStore = defineStore("messageGroup", () => {
|
|||||||
changeDialogue,
|
changeDialogue,
|
||||||
getStearm,
|
getStearm,
|
||||||
getHistory,
|
getHistory,
|
||||||
badFeedback
|
badFeedback,
|
||||||
|
deleteMessages
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user