This commit is contained in:
xingyu4j
2025-06-16 16:59:04 +08:00
parent d09b993bc8
commit 014785a1ad
71 changed files with 447 additions and 423 deletions

View File

@@ -28,7 +28,6 @@ const props = defineProps({
default: null,
},
});
/** 新建对话 */
// 定义钩子
const emits = defineEmits([
@@ -37,9 +36,11 @@ const emits = defineEmits([
'onConversationClear',
'onConversationDelete',
]);
const [Drawer, drawerApi] = useVbenDrawer({
connectedComponent: RoleRepository,
});
// 定义属性
const searchName = ref<string>(''); // 对话搜索
const activeConversationId = ref<null | number>(null); // 选中的对话,默认为 null
@@ -50,7 +51,7 @@ const loading = ref<boolean>(false); // 加载中
const loadingTime = ref<any>();
/** 搜索对话 */
const searchConversation = async () => {
async function searchConversation() {
// 恢复数据
if (searchName.value.trim().length === 0) {
conversationMap.value = await getConversationGroupByCreateTime(
@@ -64,25 +65,25 @@ const searchConversation = async () => {
conversationMap.value =
await getConversationGroupByCreateTime(filterValues);
}
};
}
/** 点击对话 */
const handleConversationClick = async (id: number) => {
async function handleConversationClick(id: number) {
// 过滤出选中的对话
const filterConversation = conversationList.value.find((item) => {
return item.id === id;
});
// 回调 onConversationClick
// noinspection JSVoidFunctionReturnValueUsed
const success = emits('onConversationClick', filterConversation);
const success = emits('onConversationClick', filterConversation) as any;
// 切换对话
if (success) {
activeConversationId.value = id;
}
};
}
/** 获取对话列表 */
const getChatConversationList = async () => {
async function getChatConversationList() {
try {
// 加载中
loadingTime.value = setTimeout(() => {
@@ -114,12 +115,12 @@ const getChatConversationList = async () => {
// 加载完成
loading.value = false;
}
};
}
/** 按照 creteTime 创建时间,进行分组 */
const getConversationGroupByCreateTime = async (
async function getConversationGroupByCreateTime(
list: AiChatConversationApi.ChatConversationVO[],
) => {
) {
// 排序、指定、时间分组(今天、一天前、三天前、七天前、30天前)
// noinspection NonAsciiCharacters
const groupMap: any = {
@@ -159,8 +160,9 @@ const getConversationGroupByCreateTime = async (
}
}
return groupMap;
};
const createConversation = async () => {
}
async function createConversation() {
// 1. 新建对话
const conversationId = await createChatConversationMy(
{} as unknown as AiChatConversationApi.ChatConversationVO,
@@ -171,12 +173,12 @@ const createConversation = async () => {
await handleConversationClick(conversationId);
// 4. 回调
emits('onConversationCreate');
};
}
/** 修改对话的标题 */
const updateConversationTitle = async (
async function updateConversationTitle(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 1. 二次确认
prompt({
async beforeClose(scope) {
@@ -225,12 +227,12 @@ const updateConversationTitle = async (
title: '修改标题',
modelPropName: 'value',
});
};
}
/** 删除聊天对话 */
const deleteChatConversation = async (
async function deleteChatConversation(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
try {
// 删除的二次确认
await confirm(`是否确认删除对话 - ${conversation.title}?`);
@@ -242,8 +244,9 @@ const deleteChatConversation = async (
// 回调
emits('onConversationDelete', conversation);
} catch {}
};
const handleClearConversation = async () => {
}
async function handleClearConversation() {
try {
await confirm('确认后对话会全部清空,置顶的对话除外。');
await deleteChatConversationMyByUnpinned();
@@ -255,18 +258,18 @@ const handleClearConversation = async () => {
// 回调 方法
emits('onConversationClear');
} catch {}
};
}
/** 对话置顶 */
const handleTop = async (
async function handleTop(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 更新对话置顶
conversation.pinned = !conversation.pinned;
await updateChatConversationMy(conversation);
// 刷新对话
await getChatConversationList();
};
}
// ============ 角色仓库 ============

View File

@@ -47,10 +47,10 @@ const documentList = computed(() => {
});
/** 点击 document 处理 */
const handleClick = (doc: any) => {
function handleClick(doc: any) {
document.value = doc;
dialogVisible.value = true;
};
}
</script>
<template>

View File

@@ -14,7 +14,7 @@ import { useClipboard } from '@vueuse/core';
import { Avatar, Button, message } from 'ant-design-vue';
import { deleteChatMessage } from '#/api/ai/chat/message';
import MarkdownView from '#/components/MarkdownView/index.vue';
import { MarkdownView } from '#/components/markdown-view';
import MessageKnowledge from './MessageKnowledge.vue';
// 定义 props
@@ -67,44 +67,44 @@ function handleScroll() {
}
/** 回到底部 */
const handleGoBottom = async () => {
async function handleGoBottom() {
const scrollContainer = messageContainer.value;
scrollContainer.scrollTop = scrollContainer.scrollHeight;
};
}
/** 回到顶部 */
const handlerGoTop = async () => {
async function handlerGoTop() {
const scrollContainer = messageContainer.value;
scrollContainer.scrollTop = 0;
};
}
defineExpose({ scrollToBottom, handlerGoTop }); // 提供方法给 parent 调用
// ============ 处理消息操作 ==============
/** 复制 */
const copyContent = async (content: string) => {
async function copyContent(content: string) {
await copy(content);
message.success('复制成功!');
};
}
/** 删除 */
const onDelete = async (id: number) => {
async function onDelete(id: number) {
// 删除 message
await deleteChatMessage(id);
message.success('删除成功!');
// 回调
emits('onDeleteSuccess');
};
}
/** 刷新 */
const onRefresh = async (message: AiChatMessageApi.ChatMessageVO) => {
async function onRefresh(message: AiChatMessageApi.ChatMessageVO) {
emits('onRefresh', message);
};
}
/** 编辑 */
const onEdit = async (message: AiChatMessageApi.ChatMessageVO) => {
async function onEdit(message: AiChatMessageApi.ChatMessageVO) {
emits('onEdit', message);
};
}
/** 初始化 */
onMounted(async () => {

View File

@@ -11,9 +11,9 @@ const promptList = [
prompt: '写一首好听的诗歌?',
},
]; /** 选中 prompt 点击 */
const handlerPromptClick = async (prompt: any) => {
async function handlerPromptClick(prompt: any) {
emits('onPrompt', prompt.prompt);
};
}
</script>
<template>
<div class="relative flex h-full w-full flex-row justify-center">

View File

@@ -4,9 +4,9 @@ import { Button } from 'ant-design-vue';
const emits = defineEmits(['onNewConversation']);
/** 新建 conversation 聊天对话 */
const handlerNewChat = () => {
function handlerNewChat() {
emits('onNewConversation');
};
}
</script>
<template>

View File

@@ -19,9 +19,9 @@ defineProps({
const emits = defineEmits(['onCategoryClick']);
/** 处理分类点击事件 */
const handleCategoryClick = async (category: string) => {
async function handleCategoryClick(category: string) {
emits('onCategoryClick', category);
};
}
</script>
<template>

View File

@@ -33,7 +33,7 @@ const emits = defineEmits(['onDelete', 'onEdit', 'onUse', 'onPage']);
const tabsRef = ref<any>();
/** 操作:编辑、删除 */
const handleMoreClick = async (data: any) => {
async function handleMoreClick(data: any) {
const type = data[0];
const role = data[1];
if (type === 'delete') {
@@ -41,22 +41,22 @@ const handleMoreClick = async (data: any) => {
} else {
emits('onEdit', role);
}
};
}
/** 选中 */
const handleUseClick = (role: any) => {
function handleUseClick(role: any) {
emits('onUse', role);
};
}
/** 滚动 */
const handleTabsScroll = async () => {
async function handleTabsScroll() {
if (tabsRef.value) {
const { scrollTop, scrollHeight, clientHeight } = tabsRef.value;
if (scrollTop + clientHeight >= scrollHeight - 20 && !props.loading) {
await emits('onPage');
}
}
};
}
</script>
<template>

View File

@@ -46,15 +46,15 @@ const activeCategory = ref<string>('全部'); // 选择中的分类
const categoryList = ref<string[]>([]); // 角色分类类别
/** tabs 点击 */
const handleTabsClick = async (tab: any) => {
async function handleTabsClick(tab: any) {
// 设置切换状态
activeTab.value = tab;
// 切换的时候重新加载数据
await getActiveTabsRole();
};
}
/** 获取 my role 我的角色 */
const getMyRole = async (append?: boolean) => {
async function getMyRole(append?: boolean) {
const params: AiModelChatRoleApi.ChatRolePageReqVO = {
...myRoleParams,
name: search.value,
@@ -66,10 +66,10 @@ const getMyRole = async (append?: boolean) => {
} else {
myRoleList.value = list;
}
};
}
/** 获取 public role 公共角色 */
const getPublicRole = async (append?: boolean) => {
async function getPublicRole(append?: boolean) {
const params: AiModelChatRoleApi.ChatRolePageReqVO = {
...publicRoleParams,
category: activeCategory.value === '全部' ? '' : activeCategory.value,
@@ -82,10 +82,10 @@ const getPublicRole = async (append?: boolean) => {
} else {
publicRoleList.value = list;
}
};
}
/** 获取选中的 tabs 角色 */
const getActiveTabsRole = async () => {
async function getActiveTabsRole() {
if (activeTab.value === 'my-role') {
myRoleParams.pageNo = 1;
await getMyRole();
@@ -93,43 +93,44 @@ const getActiveTabsRole = async () => {
publicRoleParams.pageNo = 1;
await getPublicRole();
}
};
}
/** 获取角色分类列表 */
const getRoleCategoryList = async () => {
async function getRoleCategoryList() {
categoryList.value = ['全部', ...(await getCategoryList())];
};
}
/** 处理分类点击 */
const handlerCategoryClick = async (category: string) => {
async function handlerCategoryClick(category: string) {
// 切换选择的分类
activeCategory.value = category;
// 筛选
await getActiveTabsRole();
};
}
const handlerAddRole = async () => {
async function handlerAddRole() {
formModalApi.setData({ formType: 'my-create' }).open();
};
}
/** 编辑角色 */
const handlerCardEdit = async (role: any) => {
async function handlerCardEdit(role: any) {
formModalApi.setData({ formType: 'my-update', id: role.id }).open();
};
}
/** 添加角色成功 */
const handlerAddRoleSuccess = async () => {
async function handlerAddRoleSuccess() {
// 刷新数据
await getActiveTabsRole();
};
}
/** 删除角色 */
const handlerCardDelete = async (role: any) => {
async function handlerCardDelete(role: any) {
await deleteMy(role.id);
// 刷新数据
await getActiveTabsRole();
};
}
/** 角色分页:获取下一页 */
const handlerCardPage = async (type: string) => {
async function handlerCardPage(type: string) {
try {
loading.value = true;
if (type === 'public') {
@@ -142,10 +143,10 @@ const handlerCardPage = async (type: string) => {
} finally {
loading.value = false;
}
};
}
/** 选择 card 角色:新建聊天对话 */
const handlerCardUse = async (role: any) => {
async function handlerCardUse(role: any) {
// 1. 创建对话
const data: AiChatConversationApi.ChatConversationVO = {
roleId: role.id,
@@ -159,7 +160,8 @@ const handlerCardUse = async (role: any) => {
conversationId,
},
});
};
}
/** 初始化 */
onMounted(async () => {
// 获取分类

View File

@@ -61,7 +61,7 @@ const receiveMessageDisplayedText = ref('');
// =========== 【聊天对话】相关 ===========
/** 获取对话信息 */
const getConversation = async (id: null | number) => {
async function getConversation(id: null | number) {
if (!id) {
return;
}
@@ -72,7 +72,7 @@ const getConversation = async (id: null | number) => {
}
activeConversation.value = conversation;
activeConversationId.value = conversation.id;
};
}
/**
* 点击某个对话
@@ -80,9 +80,9 @@ const getConversation = async (id: null | number) => {
* @param conversation 选中的对话
* @return 是否切换成功
*/
const handleConversationClick = async (
async function handleConversationClick(
conversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 对话进行中,不允许切换
if (conversationInProgress.value) {
alert('对话中,不允许切换!');
@@ -99,20 +99,20 @@ const handleConversationClick = async (
// 清空输入框
prompt.value = '';
return true;
};
}
/** 删除某个对话*/
const handlerConversationDelete = async (
async function handlerConversationDelete(
delConversation: AiChatConversationApi.ChatConversationVO,
) => {
) {
// 删除的对话如果是当前选中的,那么就重置
if (activeConversationId.value === delConversation.id) {
await handleConversationClear();
}
};
}
/** 清空选中的对话 */
const handleConversationClear = async () => {
async function handleConversationClear() {
// 对话进行中,不允许切换
if (conversationInProgress.value) {
alert('对话中,不允许切换!');
@@ -121,31 +121,31 @@ const handleConversationClear = async () => {
activeConversationId.value = null;
activeConversation.value = null;
activeMessageList.value = [];
};
}
const openChatConversationUpdateForm = async () => {
async function openChatConversationUpdateForm() {
formModalApi.setData({ id: activeConversationId.value }).open();
};
const handleConversationUpdateSuccess = async () => {
}
async function handleConversationUpdateSuccess() {
// 对话更新成功,刷新最新信息
await getConversation(activeConversationId.value);
};
}
/** 处理聊天对话的创建成功 */
const handleConversationCreate = async () => {
async function handleConversationCreate() {
// 创建对话
await conversationListRef.value.createConversation();
};
}
/** 处理聊天对话的创建成功 */
const handleConversationCreateSuccess = async () => {
async function handleConversationCreateSuccess() {
// 创建新的对话,清空输入框
prompt.value = '';
};
}
// =========== 【消息列表】相关 ===========
/** 获取消息 message 列表 */
const getMessageList = async () => {
async function getMessageList() {
try {
if (activeConversationId.value === null) {
return;
@@ -171,7 +171,7 @@ const getMessageList = async () => {
// 加载结束
activeMessageListLoading.value = false;
}
};
}
/**
* 消息列表
@@ -196,17 +196,17 @@ const messageList = computed(() => {
});
/** 处理删除 message 消息 */
const handleMessageDelete = () => {
function handleMessageDelete() {
if (conversationInProgress.value) {
alert('回答中,不能删除!');
return;
}
// 刷新 message 列表
getMessageList();
};
}
/** 处理 message 清空 */
const handlerMessageClear = async () => {
async function handlerMessageClear() {
if (!activeConversationId.value) {
return;
}
@@ -218,16 +218,16 @@ const handlerMessageClear = async () => {
// 刷新 message 列表
activeMessageList.value = [];
} catch {}
};
}
/** 回到 message 列表的顶部 */
const handleGoTopMessage = () => {
function handleGoTopMessage() {
messageRef.value.handlerGoTop();
};
}
// =========== 【发送消息】相关 ===========
/** 处理来自 keydown 的发送消息 */
const handleSendByKeydown = async (event: any) => {
async function handleSendByKeydown(event: any) {
// 判断用户是否在输入
if (isComposing.value) {
return;
@@ -248,15 +248,15 @@ const handleSendByKeydown = async (event: any) => {
event.preventDefault(); // 防止默认的提交行为
}
}
};
}
/** 处理来自【发送】按钮的发送消息 */
const handleSendByButton = () => {
function handleSendByButton() {
doSendMessage(prompt.value?.trim() as string);
};
}
/** 处理 prompt 输入变化 */
const handlePromptInput = (event) => {
function handlePromptInput(event: any) {
// 非输入法 输入设置为 true
if (!isComposing.value) {
// 回车 event data 是 null
@@ -273,27 +273,27 @@ const handlePromptInput = (event) => {
inputTimeout.value = setTimeout(() => {
isComposing.value = false;
}, 400);
};
}
const onCompositionstart = () => {
function onCompositionstart() {
isComposing.value = true;
};
}
const onCompositionend = () => {
function onCompositionend() {
// console.log('输入结束...')
setTimeout(() => {
isComposing.value = false;
}, 200);
};
}
/** 真正执行【发送】消息操作 */
const doSendMessage = async (content: string) => {
async function doSendMessage(content: string) {
// 校验
if (content.length === 0) {
message.error('发送失败,原因:内容为空!');
return;
}
if (activeConversationId.value == null) {
if (activeConversationId.value === null) {
message.error('还没创建对话,不能发送!');
return;
}
@@ -304,12 +304,12 @@ const doSendMessage = async (content: string) => {
conversationId: activeConversationId.value,
content,
} as AiChatMessageApi.ChatMessageVO);
};
}
/** 真正执行【发送】消息操作 */
const doSendMessageStream = async (
async function doSendMessageStream(
userMessage: AiChatMessageApi.ChatMessageVO,
) => {
) {
// 创建 AbortController 实例,以便中止请求
conversationInAbortController.value = new AbortController();
// 标记对话进行中
@@ -385,40 +385,40 @@ const doSendMessageStream = async (
},
);
} catch {}
};
}
/** 停止 stream 流式调用 */
const stopStream = async () => {
async function stopStream() {
// tip如果 stream 进行中的 message就需要调用 controller 结束
if (conversationInAbortController.value) {
conversationInAbortController.value.abort();
}
// 设置为 false
conversationInProgress.value = false;
};
}
/** 编辑 message设置为 prompt可以再次编辑 */
const handleMessageEdit = (message: AiChatMessageApi.ChatMessageVO) => {
function handleMessageEdit(message: AiChatMessageApi.ChatMessageVO) {
prompt.value = message.content;
};
}
/** 刷新 message基于指定消息再次发起对话 */
const handleMessageRefresh = (message: AiChatMessageApi.ChatMessageVO) => {
function handleMessageRefresh(message: AiChatMessageApi.ChatMessageVO) {
doSendMessage(message.content);
};
}
// ============== 【消息滚动】相关 =============
/** 滚动到 message 底部 */
const scrollToBottom = async (isIgnore?: boolean) => {
async function scrollToBottom(isIgnore?: boolean) {
await nextTick();
if (messageRef.value) {
messageRef.value.scrollToBottom(isIgnore);
}
};
}
/** 自提滚动效果 */
const textRoll = async () => {
async function textRoll() {
let index = 0;
try {
// 只能执行一次
@@ -475,7 +475,7 @@ const textRoll = async () => {
};
let timer = setTimeout(task, textSpeed.value);
} catch {}
};
}
/** 初始化 */
onMounted(async () => {
@@ -569,8 +569,8 @@ onMounted(async () => {
<MessageList
v-if="!activeMessageListLoading && messageList.length > 0"
ref="messageRef"
:conversation="activeConversation"
:list="messageList"
:conversation="activeConversation as any"
:list="messageList as any"
@on-delete-success="handleMessageDelete"
@on-edit="handleMessageEdit"
@on-refresh="handleMessageRefresh"

View File

@@ -2,7 +2,7 @@ import type { VbenFormSchema } from '#/adapter/form';
import type { VxeTableGridOptions } from '#/adapter/vxe-table';
import { getSimpleUserList } from '#/api/system/user';
import { DICT_TYPE } from '#/utils';
import { DICT_TYPE, getRangePickerDefaultProps } from '#/utils';
/** 列表的搜索表单 */
export function useGridFormSchemaConversation(): VbenFormSchema[] {
@@ -22,8 +22,7 @@ export function useGridFormSchemaConversation(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},
@@ -118,8 +117,7 @@ export function useGridFormSchemaMessage(): VbenFormSchema[] {
label: '创建时间',
component: 'RangePicker',
componentProps: {
placeholder: ['开始时间', '结束时间'],
valueFormat: 'YYYY-MM-DD HH:mm:ss',
...getRangePickerDefaultProps(),
allowClear: true,
},
},