【代码优化】AI:对话 deleteChatConversationMyByUnpinned 接口

pull/471/head^2
YunaiV 2024-07-04 23:40:03 +08:00
parent cabfc5ccc0
commit c09af1cbe1
8 changed files with 55 additions and 62 deletions

View File

@ -43,8 +43,8 @@ export const ChatConversationApi = {
}, },
// 删除【我的】所有对话,置顶除外 // 删除【我的】所有对话,置顶除外
deleteMyAllExceptPinned: async () => { deleteChatConversationMyByUnpinned: async () => {
return await request.delete({ url: `/ai/chat/conversation/delete-my-all-except-pinned` }) return await request.delete({ url: `/ai/chat/conversation/delete-by-unpinned` })
}, },
// 获得【我的】聊天对话列表 // 获得【我的】聊天对话列表

Binary file not shown.

Before

Width:  |  Height:  |  Size: 150 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 133 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 174 KiB

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -29,7 +29,7 @@ const download = {
html: (data: Blob, fileName: string) => { html: (data: Blob, fileName: string) => {
download0(data, fileName, 'text/html') download0(data, fileName, 'text/html')
}, },
// 下载 MarkdownView 方法 // 下载 Markdown 方法
markdown: (data: Blob, fileName: string) => { markdown: (data: Blob, fileName: string) => {
download0(data, fileName, 'text/markdown') download0(data, fileName, 'text/markdown')
} }

View File

@ -1,11 +1,10 @@
<!-- AI 对话 --> <!-- AI 对话 -->
<template> <template>
<el-aside width="260px" class="conversation-container" style="height: 100%;"> <el-aside width="260px" class="conversation-container" style="height: 100%">
<!-- 左顶部对话 --> <!-- 左顶部对话 -->
<div style="height: 100%;"> <div style="height: 100%">
<el-button class="w-1/1 btn-new-conversation" type="primary" @click="createConversation"> <el-button class="w-1/1 btn-new-conversation" type="primary" @click="createConversation">
<Icon icon="ep:plus" class="mr-5px"/> <Icon icon="ep:plus" class="mr-5px" />
新建对话 新建对话
</el-button> </el-button>
@ -18,17 +17,19 @@
@keyup="searchConversation" @keyup="searchConversation"
> >
<template #prefix> <template #prefix>
<Icon icon="ep:search"/> <Icon icon="ep:search" />
</template> </template>
</el-input> </el-input>
<!-- 左中间对话列表 --> <!-- 左中间对话列表 -->
<div class="conversation-list"> <div class="conversation-list">
<el-empty v-if="loading" description="." :v-loading="loading" /> <el-empty v-if="loading" description="." :v-loading="loading" />
<div v-for="conversationKey in Object.keys(conversationMap)" :key="conversationKey"> <div v-for="conversationKey in Object.keys(conversationMap)" :key="conversationKey">
<div class="conversation-item classify-title" v-if="conversationMap[conversationKey].length"> <div
class="conversation-item classify-title"
v-if="conversationMap[conversationKey].length"
>
<el-text class="mx-1" size="small" tag="b">{{ conversationKey }}</el-text> <el-text class="mx-1" size="small" tag="b">{{ conversationKey }}</el-text>
</div> </div>
<div <div
@ -40,25 +41,27 @@
@mouseout="hoverConversationId = ''" @mouseout="hoverConversationId = ''"
> >
<div <div
:class="conversation.id === activeConversationId ? 'conversation active' : 'conversation'" :class="
conversation.id === activeConversationId ? 'conversation active' : 'conversation'
"
> >
<div class="title-wrapper"> <div class="title-wrapper">
<img class="avatar" :src="conversation.roleAvatar || roleAvatarDefaultImg"/> <img class="avatar" :src="conversation.roleAvatar || roleAvatarDefaultImg" />
<span class="title">{{ conversation.title }}</span> <span class="title">{{ conversation.title }}</span>
</div> </div>
<div class="button-wrapper" v-show="hoverConversationId === conversation.id"> <div class="button-wrapper" v-show="hoverConversationId === conversation.id">
<el-button class="btn" link @click.stop="handlerTop(conversation)" > <el-button class="btn" link @click.stop="handlerTop(conversation)">
<el-icon title="置顶" v-if="!conversation.pinned"><Top /></el-icon> <el-icon title="置顶" v-if="!conversation.pinned"><Top /></el-icon>
<el-icon title="置顶" v-if="conversation.pinned"><Bottom /></el-icon> <el-icon title="置顶" v-if="conversation.pinned"><Bottom /></el-icon>
</el-button> </el-button>
<el-button class="btn" link @click.stop="updateConversationTitle(conversation)"> <el-button class="btn" link @click.stop="updateConversationTitle(conversation)">
<el-icon title="编辑" > <el-icon title="编辑">
<Icon icon="ep:edit"/> <Icon icon="ep:edit" />
</el-icon> </el-icon>
</el-button> </el-button>
<el-button class="btn" link @click.stop="deleteChatConversation(conversation)"> <el-button class="btn" link @click.stop="deleteChatConversation(conversation)">
<el-icon title="删除对话" > <el-icon title="删除对话">
<Icon icon="ep:delete"/> <Icon icon="ep:delete" />
</el-icon> </el-icon>
</el-button> </el-button>
</div> </div>
@ -66,20 +69,19 @@
</div> </div>
</div> </div>
<!-- 底部站位 --> <!-- 底部站位 -->
<div style="height: 160px; width: 100%;"></div> <div style="height: 160px; width: 100%"></div>
</div> </div>
</div> </div>
<!-- 左底部工具栏 --> <!-- 左底部工具栏 -->
<!-- TODO @fan下面两个 icon可以使用类似 <Icon icon="ep:question-filled" /> 替代哈 --> <!-- TODO @fan下面两个 icon可以使用类似 <Icon icon="ep:question-filled" /> 替代哈 -->
<div class="tool-box"> <div class="tool-box">
<div @click="handleRoleRepository"> <div @click="handleRoleRepository">
<Icon icon="ep:user"/> <Icon icon="ep:user" />
<el-text size="small">角色仓库</el-text> <el-text size="small">角色仓库</el-text>
</div> </div>
<div @click="handleClearConversation"> <div @click="handleClearConversation">
<Icon icon="ep:delete"/> <Icon icon="ep:delete" />
<el-text size="small">清空未置顶对话</el-text> <el-text size="small">清空未置顶对话</el-text>
</div> </div>
</div> </div>
@ -88,17 +90,16 @@
<!-- 角色仓库抽屉 --> <!-- 角色仓库抽屉 -->
<el-drawer v-model="drawer" title="角色仓库" size="754px"> <el-drawer v-model="drawer" title="角色仓库" size="754px">
<Role/> <Role />
</el-drawer> </el-drawer>
</el-aside> </el-aside>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import {ChatConversationApi, ChatConversationVO} from '@/api/ai/chat/conversation' import { ChatConversationApi, ChatConversationVO } from '@/api/ai/chat/conversation'
import {ref} from "vue"; import { ref } from 'vue'
import Role from "@/views/ai/chat/role/index.vue"; import Role from '@/views/ai/chat/role/index.vue'
import {Bottom, Top} from "@element-plus/icons-vue"; import { Bottom, Top } from '@element-plus/icons-vue'
import roleAvatarDefaultImg from '@/assets/ai/gpt.svg' import roleAvatarDefaultImg from '@/assets/ai/gpt.svg'
const message = useMessage() // const message = useMessage() //
@ -107,8 +108,8 @@ const message = useMessage() // 消息弹窗
const searchName = ref<string>('') // const searchName = ref<string>('') //
const activeConversationId = ref<string | null>(null) // null const activeConversationId = ref<string | null>(null) // null
const hoverConversationId = ref<string | null>(null) // const hoverConversationId = ref<string | null>(null) //
const conversationList = ref([] as ChatConversationVO[]) // const conversationList = ref([] as ChatConversationVO[]) //
const conversationMap = ref<any>({}) // () const conversationMap = ref<any>({}) // ()
const drawer = ref<boolean>(false) // TODO @fanroleDrawer const drawer = ref<boolean>(false) // TODO @fanroleDrawer
const loading = ref<boolean>(false) // const loading = ref<boolean>(false) //
const loadingTime = ref<any>() // const loadingTime = ref<any>() //
@ -138,7 +139,7 @@ const searchConversation = async (e) => {
conversationMap.value = await conversationTimeGroup(conversationList.value) conversationMap.value = await conversationTimeGroup(conversationList.value)
} else { } else {
// //
const filterValues = conversationList.value.filter(item => { const filterValues = conversationList.value.filter((item) => {
return item.title.includes(searchName.value.trim()) return item.title.includes(searchName.value.trim())
}) })
conversationMap.value = await conversationTimeGroup(filterValues) conversationMap.value = await conversationTimeGroup(filterValues)
@ -150,7 +151,7 @@ const searchConversation = async (e) => {
*/ */
const handleConversationClick = async (id: string) => { const handleConversationClick = async (id: string) => {
// //
const filterConversation = conversationList.value.filter(item => { const filterConversation = conversationList.value.filter((item) => {
return item.id === id return item.id === id
}) })
// onConversationClick // onConversationClick
@ -211,20 +212,20 @@ const getChatConversationList = async () => {
const conversationTimeGroup = async (list: ChatConversationVO[]) => { const conversationTimeGroup = async (list: ChatConversationVO[]) => {
// (30) // (30)
const groupMap = { const groupMap = {
'置顶': [], 置顶: [],
'今天': [], 今天: [],
'一天前': [], 一天前: [],
'三天前': [], 三天前: [],
'七天前': [], 七天前: [],
'三十天前': [] 三十天前: []
} }
// //
const now = Date.now(); const now = Date.now()
// //
const oneDay = 24 * 60 * 60 * 1000; const oneDay = 24 * 60 * 60 * 1000
const threeDays = 3 * oneDay; const threeDays = 3 * oneDay
const sevenDays = 7 * oneDay; const sevenDays = 7 * oneDay
const thirtyDays = 30 * oneDay; const thirtyDays = 30 * oneDay
for (const conversation: ChatConversationVO of list) { for (const conversation: ChatConversationVO of list) {
// //
if (conversation.pinned) { if (conversation.pinned) {
@ -232,7 +233,7 @@ const conversationTimeGroup = async (list: ChatConversationVO[]) => {
continue continue
} }
// //
const diff = now - conversation.updateTime; const diff = now - conversation.updateTime
// //
if (diff < oneDay) { if (diff < oneDay) {
groupMap['今天'].push(conversation) groupMap['今天'].push(conversation)
@ -271,7 +272,7 @@ const createConversation = async () => {
*/ */
const updateConversationTitle = async (conversation: ChatConversationVO) => { const updateConversationTitle = async (conversation: ChatConversationVO) => {
// 1. // 1.
const {value} = await ElMessageBox.prompt('修改标题', { const { value } = await ElMessageBox.prompt('修改标题', {
inputPattern: /^[\s\S]*.*\S[\s\S]*$/, // inputPattern: /^[\s\S]*.*\S[\s\S]*$/, //
inputErrorMessage: '标题不能为空', inputErrorMessage: '标题不能为空',
inputValue: conversation.title inputValue: conversation.title
@ -285,7 +286,7 @@ const updateConversationTitle = async (conversation: ChatConversationVO) => {
// 3. // 3.
await getChatConversationList() await getChatConversationList()
// 4. // 4.
const filterConversationList = conversationList.value.filter(item => { const filterConversationList = conversationList.value.filter((item) => {
return item.id === conversation.id return item.id === conversation.id
}) })
if (filterConversationList.length > 0) { if (filterConversationList.length > 0) {
@ -310,8 +311,7 @@ const deleteChatConversation = async (conversation: ChatConversationVO) => {
await getChatConversationList() await getChatConversationList()
// //
emits('onConversationDelete', conversation) emits('onConversationDelete', conversation)
} catch { } catch {}
}
} }
/** /**
@ -343,16 +343,13 @@ const handleRoleRepository = async () => {
*/ */
const handleClearConversation = async () => { const handleClearConversation = async () => {
// TODO @fan使 await message.confirm( 使 await // TODO @fan使 await message.confirm( 使 await
ElMessageBox.confirm( ElMessageBox.confirm('确认后对话会全部清空,置顶的对话除外。', '确认提示', {
'确认后对话会全部清空,置顶的对话除外。', confirmButtonText: '确认',
'确认提示', cancelButtonText: '取消',
{ type: 'warning'
confirmButtonText: '确认', })
cancelButtonText: '取消',
type: 'warning',
})
.then(async () => { .then(async () => {
await ChatConversationApi.deleteMyAllExceptPinned() await ChatConversationApi.deleteChatConversationMyByUnpinned()
ElMessage({ ElMessage({
message: '操作成功!', message: '操作成功!',
type: 'success' type: 'success'
@ -364,8 +361,7 @@ const handleClearConversation = async () => {
// //
emits('onConversationClear') emits('onConversationClear')
}) })
.catch(() => { .catch(() => {})
})
} }
// ============ onMounted // ============ onMounted
@ -377,7 +373,7 @@ watch(activeId, async (newValue, oldValue) => {
}) })
// public // public
defineExpose({createConversation}) defineExpose({ createConversation })
onMounted(async () => { onMounted(async () => {
// //
@ -394,11 +390,9 @@ onMounted(async () => {
} }
} }
}) })
</script> </script>
<style scoped lang="scss"> <style scoped lang="scss">
.conversation-container { .conversation-container {
position: relative; position: relative;
display: flex; display: flex;

1
types/env.d.ts vendored
View File

@ -19,7 +19,6 @@ interface ImportMetaEnv {
readonly VITE_UPLOAD_URL: string readonly VITE_UPLOAD_URL: string
readonly VITE_API_URL: string readonly VITE_API_URL: string
readonly VITE_BASE_PATH: string readonly VITE_BASE_PATH: string
readonly VITE_STATIC_URL: string
readonly VITE_DROP_DEBUGGER: string readonly VITE_DROP_DEBUGGER: string
readonly VITE_DROP_CONSOLE: string readonly VITE_DROP_CONSOLE: string
readonly VITE_SOURCEMAP: string readonly VITE_SOURCEMAP: string