Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions ui/src/components/COMPONENT_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,14 @@ Workspace API 内部使用 `getWorkspaceId()`,System 共享 API 不接收工

## 对话模块组件

### RenameConversation(对话模块)

位于 `conversation-panel/components/rename/index.vue`,显式导入并传入
`conversation`。入口维护重命名菜单项,同目录 `RenameDialog.vue` 维护弹窗、标题校验及保存调用,
点击菜单时才挂载弹窗,`closed` 后卸载;放入 Dropdown 菜单时,
调用方开启 `persistent`,确保菜单收起后保留弹窗实例。门户调用方额外传入 `applicationId`,
按所属智能体保存并同步分组及当前会话列表;`renamed(title)` 事件供历史抽屉同步标题。

### ReverseInfiniteScroll(对话模块)

位于 `conversation-panel/core/reverse-infinite-scroll/index.vue`,由对话模块显式导入,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const { appInfo, leftSideOpen, toggleLeftSide, newConversation } = useConversati
<MkIcon name="icon_sidebar_outlined" :size="18" class="text-N900!" />
</el-button>
</MkTooltip>
<el-divider direction="vertical" class="mx-1!" />
<el-divider direction="vertical" class="ml-2! mr-3!" />
<ApplicationIcon :icon="appInfo?.icon" :size="24" class="shrink-0" />
<h4 class="ml-1 min-w-0 flex-1 truncate" :title="appInfo?.name">{{ appInfo?.name }}</h4>
<MkTooltip content="新建对话">
Expand All @@ -23,6 +23,9 @@ const { appInfo, leftSideOpen, toggleLeftSide, newConversation } = useConversati
<MkIcon name="icon_new-chat_outlined" :size="18" />
</el-button>
</MkTooltip>
<HistoryPopover />
<!-- 历史记录 -->
<span class="ml-1">
<HistoryPopover></HistoryPopover>
</span>
</header>
</template>
52 changes: 26 additions & 26 deletions ui/src/conversation-panel/components/history-popover/index.vue
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
<script setup lang="ts">
import { ref } from 'vue'
import { ElMessageBox, type ScrollbarDirection } from 'element-plus'
import type { ScrollbarDirection } from 'element-plus'
import type { Conversation } from '../../core/types'
import { useConversationListStore } from '../../left-sidebar/conversation-list/index'
import RenameConversation from '../rename/index.vue'
import { relativeTimeFormat } from '@/utils/time'
import { MsgConfirm } from '@/utils/message'

Expand All @@ -27,19 +28,6 @@ function handleSelectConversation(conversation: Conversation) {
visible.value = false
}

/* 重命名:去除首尾空格后提交,取消或请求失败保留原名称。 */
function handleRenameConversation(conversation: Conversation) {
ElMessageBox.prompt('', '重命名', {
inputValue: conversation.abstract || '',
inputPattern: /\S/,
inputErrorMessage: '请输入对话名称',
confirmButtonText: '确定',
cancelButtonText: '取消',
})
.then(({ value }) => conversationList.renameChat(conversation.id, value.trim()))
.catch(() => {})
}

function handleDeleteConversation(conversation: Conversation) {
MsgConfirm('确认删除该对话?', '删除后无法恢复。')
.then(() => conversationList.deleteChat(conversation.id))
Expand Down Expand Up @@ -67,7 +55,15 @@ function handleClearConversations() {
</script>

<template>
<el-popover v-model:visible="visible" trigger="click" placement="bottom-end" :width="280" popper-class="p-2!" @show="handleShow">
<el-popover
v-model:visible="visible"
trigger="click"
placement="bottom-end"
:width="280"
popper-class="p-2!"
:popper-style="{ '--el-bg-color-overlay': 'var(--mk-N100)' }"
@show="handleShow"
>
<template #reference>
<span class="inline-flex">
<MkTooltip content="历史对话">
Expand Down Expand Up @@ -109,17 +105,21 @@ function handleClearConversations() {
{{ conversationTime(conversation) }}
</span>
</template>
<template #action-dropdown>
<!-- 重命名历史对话 -->
<MkDropdownItem @click="handleRenameConversation(conversation)">
<template #icon><MkIcon name="icon_edit_outlined" /></template>
<span>重命名</span>
</MkDropdownItem>
<!-- 删除历史对话 -->
<MkDropdownItem @click="handleDeleteConversation(conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
<template #action>
<MkDropdown trigger="click" persistent :teleported="false">
<!-- 打开历史对话操作菜单 -->
<el-button text><MkIcon name="icon_more_outlined" /></el-button>
<template #dropdown>
<MkDropdownMenu>
<RenameConversation :conversation="conversation" />
<!-- 删除历史对话 -->
<MkDropdownItem @click="handleDeleteConversation(conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
</MkDropdownMenu>
</template>
</MkDropdown>
</template>
</MkListItem>
</div>
Expand Down
73 changes: 73 additions & 0 deletions ui/src/conversation-panel/components/rename/RenameDialog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<script setup lang="ts">
import { inject, reactive, ref } from 'vue'
import type { FormInstance, FormRules } from 'element-plus'
import ConversationApi from '@/api/chat/conversation'
import { PORTAL_CONVERSATION_LIST_KEY } from '../../left-sidebar/portal-conversation-list/index'
import type { Conversation } from '../../core/types'
import { useConversationListStore } from '../../left-sidebar/conversation-list/index'

defineOptions({ name: 'RenameDialog' })

const props = defineProps<{ conversation: Conversation; applicationId?: string }>()
const conversationList = useConversationListStore()
const portalList = inject(PORTAL_CONVERSATION_LIST_KEY, null)
const emit = defineEmits<{ renamed: [title: string]; closed: [] }>()

// 重命名会话:回填标题,校验并去除首尾空格后提交。
const renameDialogVisible = ref(true)
const renameSubmitting = ref(false)
const renameConversationId = props.conversation.id
const renameFormRef = ref<FormInstance>()
const renameForm = reactive({ abstract: props.conversation.abstract || '' })
const renameRules: FormRules<typeof renameForm> = {
abstract: [{ required: true, whitespace: true, message: '请输入', trigger: 'blur' }],
}

function submitRename() {
if (renameSubmitting.value) return
renameFormRef.value?.validate((valid) => {
if (!valid) return
renameSubmitting.value = true
const title = renameForm.abstract.trim()
const conversationId = renameConversationId
const applicationId = props.applicationId
const request = applicationId
? ConversationApi.putConversation(applicationId, conversationId, { abstract: title })
: conversationList.renameChat(conversationId, title)
return request
.then(() => {
if (applicationId && portalList) {
const group = portalList.applicationGroups.value.find((group) => group.id === applicationId)
const groupConversation = group?.conversations.find((conversation) => conversation.id === conversationId)
if (groupConversation) groupConversation.abstract = title
if (portalList.currentApplicationId.value === applicationId) {
const currentConversation = conversationList.conversations.value.find((conversation) => conversation.id === conversationId)
if (currentConversation) currentConversation.abstract = title
}
}
emit('renamed', title)
renameDialogVisible.value = false
})
.catch(() => {})
.finally(() => {
renameSubmitting.value = false
})
})
}
</script>

<template>
<MkDialog v-model="renameDialogVisible" title="重命名" @closed="emit('closed')">
<el-form ref="renameFormRef" :model="renameForm" :rules="renameRules" label-position="top" require-asterisk-position="right" @submit.prevent>
<el-form-item label="会话标题" prop="abstract">
<el-input v-model="renameForm.abstract" placeholder="请输入" />
</el-form-item>
</el-form>
<template #footer>
<!-- 取消重命名 -->
<el-button plain @click="renameDialogVisible = false">取消</el-button>
<!-- 保存会话标题 -->
<el-button type="primary" :loading="renameSubmitting" @click="submitRename">保存</el-button>
</template>
</MkDialog>
</template>
26 changes: 26 additions & 0 deletions ui/src/conversation-panel/components/rename/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<script setup lang="ts">
import { ref } from 'vue'
import type { Conversation } from '../../core/types'
import RenameDialog from './RenameDialog.vue'

defineOptions({ name: 'RenameConversation' })

defineProps<{ conversation: Conversation; applicationId?: string }>()
const emit = defineEmits<{ renamed: [title: string] }>()
const renameDialogRendered = ref(false)
</script>

<template>
<!-- 重命名历史对话 -->
<MkDropdownItem @click="renameDialogRendered = true">
<template #icon><MkIcon name="icon_edit_outlined" /></template>
<span>重命名</span>
</MkDropdownItem>
<RenameDialog
v-if="renameDialogRendered"
:conversation="conversation"
:application-id="applicationId"
@renamed="emit('renamed', $event)"
@closed="renameDialogRendered = false"
/>
</template>
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { PortalConversationSummary } from '@/api/types'
import { relativeTimeFormat } from '@/utils/time'
import { useConversationListStore } from '../conversation-list/index'
import { usePortalConversationListStore } from './index'
import RenameConversation from '../../components/rename/index.vue'

defineOptions({ name: 'HistoryConversationDrawer' })
const props = defineProps<{ applicationId: string }>()
Expand Down Expand Up @@ -82,12 +83,25 @@ const handleDeleteConversation = (conversation: PortalConversationSummary) => {
{{ relativeTimeFormat(conversation.update_time || conversation.create_time) }}
</span>
</template>
<template #action-dropdown>
<!-- 删除历史对话 -->
<MkDropdownItem divided @click="handleDeleteConversation(conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
<template #action>
<MkDropdown trigger="click" persistent :teleported="false">
<!-- 打开历史对话操作菜单 -->
<el-button text><MkIcon name="icon_more_outlined" /></el-button>
<template #dropdown>
<MkDropdownMenu>
<RenameConversation
:conversation="conversation"
:application-id="selectedApplicationId"
@renamed="conversation.abstract = $event"
/>
<!-- 删除历史对话 -->
<MkDropdownItem divided @click="handleDeleteConversation(conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
</MkDropdownMenu>
</template>
</MkDropdown>
</template>
</MkListItem>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { useConversationListStore } from '../conversation-list/index'
import HistoryConversationDrawer from './HistoryConversationDrawer.vue'
import AccountMenu from '../account-menu/index.vue'
import { usePortalConversationListStore, type PortalApplicationGroup } from './index'
import RenameConversation from '../../components/rename/index.vue'

defineOptions({ name: 'PortalConversationList' })

Expand Down Expand Up @@ -122,6 +123,11 @@ const handleDeleteConversation = (group: PortalApplicationGroup, conversation: C
</el-button>
<template #dropdown>
<MkDropdownMenu>
<!-- 新建当前分组智能体的对话 -->
<MkDropdownItem @click="portalList.openApplication(group.id)">
<template #icon><MkIcon name="icon_new-chat_outlined" /></template>
<span>新建对话</span>
</MkDropdownItem>
<!-- 删除智能体历史分组,待接入对应接口 -->
<MkDropdownItem divided disabled>
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
Expand Down Expand Up @@ -154,12 +160,21 @@ const handleDeleteConversation = (group: PortalApplicationGroup, conversation: C
{{ conversationTime(conversation) }}
</span>
</template>
<template #action-dropdown>
<!-- 删除 -->
<MkDropdownItem divided @click="handleDeleteConversation(group, conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
<template #action>
<MkDropdown trigger="click" persistent :teleported="false">
<!-- 打开历史对话操作菜单 -->
<el-button text><MkIcon name="icon_more_outlined" /></el-button>
<template #dropdown>
<MkDropdownMenu>
<RenameConversation :conversation="conversation" :application-id="group.id" @renamed="conversation.abstract = $event" />
<!-- 删除历史对话 -->
<MkDropdownItem divided @click="handleDeleteConversation(group, conversation)">
<template #icon><MkIcon name="icon_delete-trash_outlined" /></template>
<span>删除</span>
</MkDropdownItem>
</MkDropdownMenu>
</template>
</MkDropdown>
</template>
</MkListItem>
<!-- 超过5条 查看更多 -->
Expand Down
2 changes: 1 addition & 1 deletion ui/src/conversation-panel/view/simple-debug/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ defineExpose({ openSetting: () => (bundle.list.leftSideOpen.value = true) })
/* 设置表单使用白底;两侧抽屉沿用挤压宽度并限制占比,避免把对话区完全覆盖。 */
.mk-simple-debug .mk-conversation-side-panel {
&.left {
background: var(--color-white);
background: white;
}

&.drawer {
Expand Down
Loading