2025-06-06 20:21:00 +08:00

135 lines
4.2 KiB
Vue

<template>
<el-tooltip :content="t('resources')" placement="top">
<div class="setting-button" @click="showChooseResource = true; saveCursorPosition();">
<span class="iconfont icon-file"></span>
</div>
</el-tooltip>
<el-dialog v-model="showChooseResource" :title="t('resources')" width="400px">
<div class="resource-template-container-scrollbar" v-if="!selectResource">
<ResourceList :tab-id="-1" @resource-selected="resource => handleResourceSelected(resource)" />
</div>
<div v-else>
<ResourceReader :tab-id="-1" :current-resource-name="selectResource!.name"
@resource-get-response="msg => whenGetResourceResponse(msg)" />
</div>
<template #footer>
<el-button v-if="selectResource" @click="selectResource = undefined;">{{ t('return') }}</el-button>
<el-button @click="showChooseResource = false; selectResource = undefined;">{{ t("cancel") }}</el-button>
</template>
</el-dialog>
</template>
<script setup lang="ts">
import { createApp, inject, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import type { ChatStorage, EditorContext } from '../chat';
import type { Resources, ResourcesReadResponse, ResourceTemplate } from '@/hook/type';
import ResourceList from '@/components/main-panel/resource/resource-list.vue';
import ResourceReader from '@/components/main-panel/resource/resouce-reader.vue';
import { ElMessage, ElTooltip, ElProgress, ElPopover } from 'element-plus';
import ResourceChatItem from '../resource-chat-item.vue';
import { mcpClientAdapter } from '@/views/connect/core';
const { t } = useI18n();
const tabStorage = inject('tabStorage') as ChatStorage;
let selectResource = ref<ResourceTemplate | undefined>(undefined);
const showChooseResource = ref(false);
const editorContext = inject('editorContext') as EditorContext;
let savedSelection: Range | null = null;
function saveCursorPosition() {
const editor = editorContext.editor.value;
if (editor) {
const selection = window.getSelection();
if (selection && selection.rangeCount > 0) {
const range = selection.getRangeAt(0);
if (editor.contains(range.startContainer) && editor.contains(range.endContainer)) {
savedSelection = range;
} else {
savedSelection = null;
}
}
}
}
async function handleResourceSelected(resource: Resources) {
selectResource.value = undefined;
const msg = await mcpClientAdapter.readResource(resource.uri);
if (msg) {
await whenGetResourceResponse(msg as ResourcesReadResponse);
}
}
async function whenGetResourceResponse(msg: ResourcesReadResponse) {
if (!msg) {
return;
}
try {
console.log(msg);
selectResource.value = undefined;
const editor = editorContext.editor.value;
if (msg.contents.length === 0 || !editor) {
return;
}
const container = document?.createElement('div');
const resourceChatItem = createApp(ResourceChatItem, {
contents: msg.contents
});
resourceChatItem
.use(ElTooltip)
.use(ElProgress)
.use(ElPopover)
resourceChatItem.mount(container);
const firstElement = container.firstElementChild!;
if (savedSelection) {
savedSelection.deleteContents();
savedSelection.insertNode(firstElement);
} else {
editor.appendChild(firstElement);
}
const newRange = document?.createRange();
newRange.setStartAfter(firstElement);
newRange.collapse(true);
const selection = window.getSelection();
selection?.removeAllRanges();
selection?.addRange(newRange);
editor.dispatchEvent(new Event('input'));
editor.focus();
showChooseResource.value = false;
} catch (error) {
ElMessage.error((error as Error).message);
}
}
</script>
<style>
.icon-length {
font-size: 16px;
}
.el-dialog .el-collapse-item__header {
background-color: transparent !important;
}
.el-dialog .el-collapse-item__wrap {
background-color: transparent !important;
}
</style>