修复关闭标签页 key 重排序错误的问题
This commit is contained in:
parent
4f9900a64c
commit
a535690bc6
24
renderer/package-lock.json
generated
24
renderer/package-lock.json
generated
@ -14,6 +14,7 @@
|
|||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"markdown-it-katex": "^2.0.3",
|
"markdown-it-katex": "^2.0.3",
|
||||||
"openai": "^4.93.0",
|
"openai": "^4.93.0",
|
||||||
|
"uuid": "^11.1.0",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-i18n": "^11.1.0",
|
"vue-i18n": "^11.1.0",
|
||||||
"vue-router": "^4.0.3"
|
"vue-router": "^4.0.3"
|
||||||
@ -11820,6 +11821,16 @@
|
|||||||
"websocket-driver": "^0.7.4"
|
"websocket-driver": "^0.7.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/sockjs/node_modules/uuid": {
|
||||||
|
"version": "8.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||||
|
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"uuid": "dist/bin/uuid"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/source-map": {
|
"node_modules/source-map": {
|
||||||
"version": "0.6.1",
|
"version": "0.6.1",
|
||||||
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
|
"resolved": "https://registry.npmmirror.com/source-map/-/source-map-0.6.1.tgz",
|
||||||
@ -12970,13 +12981,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/uuid": {
|
"node_modules/uuid": {
|
||||||
"version": "8.3.2",
|
"version": "11.1.0",
|
||||||
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-8.3.2.tgz",
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||||
"dev": true,
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa",
|
||||||
|
"https://github.com/sponsors/ctavan"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/esm/bin/uuid"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/v8-compile-cache": {
|
"node_modules/v8-compile-cache": {
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
"markdown-it": "^14.1.0",
|
"markdown-it": "^14.1.0",
|
||||||
"markdown-it-katex": "^2.0.3",
|
"markdown-it-katex": "^2.0.3",
|
||||||
"openai": "^4.93.0",
|
"openai": "^4.93.0",
|
||||||
|
"uuid": "^11.1.0",
|
||||||
"vue": "^3.2.13",
|
"vue": "^3.2.13",
|
||||||
"vue-i18n": "^11.1.0",
|
"vue-i18n": "^11.1.0",
|
||||||
"vue-router": "^4.0.3"
|
"vue-router": "^4.0.3"
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
--vscode-scrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6);
|
--vscode-scrollbarSlider-activeBackground: rgba(0, 0, 0, 0.6);
|
||||||
--vscode-progressBar-background: #0e70c0;
|
--vscode-progressBar-background: #0e70c0;
|
||||||
--vscode-editor-background: #ffffff;
|
--vscode-editor-background: #ffffff;
|
||||||
--vscode-editor-foreground: #000000;
|
--vscode-editor-foreground: #3d3d3d;
|
||||||
--vscode-editorStickyScroll-background: #ffffff;
|
--vscode-editorStickyScroll-background: #ffffff;
|
||||||
--vscode-editorStickyScrollHover-background: #f0f0f0;
|
--vscode-editorStickyScrollHover-background: #f0f0f0;
|
||||||
--vscode-editorStickyScroll-shadow: #dddddd;
|
--vscode-editorStickyScroll-shadow: #dddddd;
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<meta name="referrer" content="no-referrer">
|
<meta name="referrer" content="no-referrer">
|
||||||
<link rel="icon" href="<%= BASE_URL %>favicon.svg">
|
<link rel="icon" href="<%= BASE_URL %>favicon.svg">
|
||||||
<link rel="stylesheet" href="default-dark.css">
|
<link rel="stylesheet" href="default-light.css">
|
||||||
<link rel="stylesheet" href="vscode.css">
|
<link rel="stylesheet" href="vscode.css">
|
||||||
<link rel="stylesheet" href="mcp.css">
|
<link rel="stylesheet" href="mcp.css">
|
||||||
<link rel="stylesheet" href="iconfont.css">
|
<link rel="stylesheet" href="iconfont.css">
|
||||||
|
@ -29,8 +29,8 @@ bridge.addCommandListener('hello', data => {
|
|||||||
|
|
||||||
|
|
||||||
function initDebug() {
|
function initDebug() {
|
||||||
// connectionArgs.commandString = 'node /Users/bytedance/projects/mcp/servers/src/puppeteer/dist/index.js';
|
connectionArgs.commandString = 'node /Users/bytedance/projects/mcp/servers/src/puppeteer/dist/index.js';
|
||||||
connectionArgs.commandString = 'node C:/Users/K/code/servers/src/puppeteer/dist/index.js';
|
// connectionArgs.commandString = 'node C:/Users/K/code/servers/src/puppeteer/dist/index.js';
|
||||||
// connectionArgs.commandString = 'uv run mcp run bing-picture.py';
|
// connectionArgs.commandString = 'uv run mcp run bing-picture.py';
|
||||||
connectionArgs.cwd = '../servers';
|
connectionArgs.cwd = '../servers';
|
||||||
connectionMethods.current = 'STDIO';
|
connectionMethods.current = 'STDIO';
|
||||||
@ -107,4 +107,8 @@ onMounted(() => {
|
|||||||
max-width: 300px;
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.icon-chat:before {
|
||||||
|
font-weight: 1000;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@ -5,25 +5,32 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else-if="props.item.type === 'image'" class="tool-image">
|
<div v-else-if="props.item.type === 'image'" class="tool-image">
|
||||||
<div class="media-item">
|
<div class="media-item" @click="showFullImage">
|
||||||
<img :src="thumbnail" alt="screenshot"/>
|
<img :src="thumbnail" alt="screenshot" />
|
||||||
<span class="float-container">
|
<span class="float-container">
|
||||||
<span class="iconfont icon-image"></span>
|
|
||||||
|
<!-- 后处理结束后显示的部分 -->
|
||||||
|
<span class="iconfont icon-image" v-if="finishProcess"></span>
|
||||||
|
|
||||||
|
<!-- 后处理时显示的部分 -->
|
||||||
|
<el-progress v-else
|
||||||
|
class="progress"
|
||||||
|
:percentage="progress"
|
||||||
|
:stroke-width="5"
|
||||||
|
type="circle"
|
||||||
|
:width="80"
|
||||||
|
color="var(--main-color)"
|
||||||
|
>
|
||||||
|
<template #default="{ percentage }">
|
||||||
|
<div class="progress-label">
|
||||||
|
<span class="percentage-value">{{ percentage }}%</span>
|
||||||
|
<span class="percentage-label">{{ progressText }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-progress>
|
||||||
|
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<span v-if="!finishProcess">
|
|
||||||
<el-progress
|
|
||||||
class="progress"
|
|
||||||
:percentage="progress"
|
|
||||||
:stroke-width="3"
|
|
||||||
>
|
|
||||||
<template #default="{ percentage }">
|
|
||||||
<span class="percentage-label">{{ progressText }}</span>
|
|
||||||
<span class="percentage-value">{{ percentage }}%</span>
|
|
||||||
</template>
|
|
||||||
</el-progress>
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-else class="tool-other">{{ JSON.stringify(props.item) }}</div>
|
<div v-else class="tool-other">{{ JSON.stringify(props.item) }}</div>
|
||||||
@ -62,7 +69,7 @@ if (ocr) {
|
|||||||
const { id, progress: p = 1.0, status = 'finish' } = data;
|
const { id, progress: p = 1.0, status = 'finish' } = data;
|
||||||
if (id === workerId) {
|
if (id === workerId) {
|
||||||
progressText.value = status;
|
progressText.value = status;
|
||||||
progress.value = Math.min(Math.ceil(Math.max(p * 100 ,0)), 100);
|
progress.value = Math.min(Math.ceil(Math.max(p * 100, 0)), 100);
|
||||||
}
|
}
|
||||||
}, { once: false });
|
}, { once: false });
|
||||||
|
|
||||||
@ -88,13 +95,48 @@ if (props.item.data) {
|
|||||||
console.log(props.item.data);
|
console.log(props.item.data);
|
||||||
getBlobUrlByFilename(props.item.data).then(url => {
|
getBlobUrlByFilename(props.item.data).then(url => {
|
||||||
console.log(url);
|
console.log(url);
|
||||||
|
|
||||||
if (url) {
|
if (url) {
|
||||||
thumbnail.value = url;
|
thumbnail.value = url;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const showFullImage = () => {
|
||||||
|
const img = new Image();
|
||||||
|
img.src = thumbnail.value;
|
||||||
|
img.onload = () => {
|
||||||
|
const overlay = document.createElement('div');
|
||||||
|
overlay.style.position = 'fixed';
|
||||||
|
overlay.style.top = '0';
|
||||||
|
overlay.style.left = '0';
|
||||||
|
overlay.style.width = '100%';
|
||||||
|
overlay.style.height = '100%';
|
||||||
|
overlay.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
|
||||||
|
overlay.style.zIndex = '9999';
|
||||||
|
overlay.style.display = 'flex';
|
||||||
|
overlay.style.justifyContent = 'center';
|
||||||
|
overlay.style.alignItems = 'center';
|
||||||
|
overlay.onclick = () => document.body.removeChild(overlay);
|
||||||
|
|
||||||
|
const imgContainer = document.createElement('div');
|
||||||
|
imgContainer.style.maxWidth = '90vw';
|
||||||
|
imgContainer.style.maxHeight = '90vh';
|
||||||
|
imgContainer.style.overflow = 'auto';
|
||||||
|
|
||||||
|
const fullImg = new Image();
|
||||||
|
fullImg.src = thumbnail.value;
|
||||||
|
fullImg.style.width = 'auto';
|
||||||
|
fullImg.style.height = 'auto';
|
||||||
|
fullImg.style.maxWidth = '100%';
|
||||||
|
fullImg.style.maxHeight = '100%';
|
||||||
|
|
||||||
|
imgContainer.appendChild(fullImg);
|
||||||
|
overlay.appendChild(imgContainer);
|
||||||
|
document.body.appendChild(overlay);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@ -106,10 +148,6 @@ if (props.item.data) {
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.percentage-label {
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tool-image .media-item {
|
.tool-image .media-item {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
@ -130,7 +168,7 @@ if (props.item.data) {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tool-image .media-item > img {
|
.tool-image .media-item>img {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 50%;
|
top: 50%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
@ -145,7 +183,7 @@ if (props.item.data) {
|
|||||||
top: 0;
|
top: 0;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
background-color: rgba(0, 0, 0, 0.5);
|
background-color: rgba(0, 0, 0, 0.6);
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@ -153,6 +191,25 @@ if (props.item.data) {
|
|||||||
transition: var(--animation-3s);
|
transition: var(--animation-3s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.progress-label {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-label {
|
||||||
|
max-width: 50px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.percentage-value {
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
.tool-image .media-item .float-container .iconfont {
|
.tool-image .media-item .float-container .iconfont {
|
||||||
color: var(--background);
|
color: var(--background);
|
||||||
}
|
}
|
||||||
@ -161,4 +218,11 @@ if (props.item.data) {
|
|||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.media-item {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-item:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -45,7 +45,7 @@
|
|||||||
反馈
|
反馈
|
||||||
</el-button>
|
</el-button>
|
||||||
</span>
|
</span>
|
||||||
<span style="width: 200px;" class="tools-dialog-container" v-if="isValid">
|
<span style="width: 200px;" class="tools-dialog-container" v-if="currentMessageLevel === 'info'">
|
||||||
<el-switch v-model="props.message.showJson!.value" inline-prompt active-text="JSON"
|
<el-switch v-model="props.message.showJson!.value" inline-prompt active-text="JSON"
|
||||||
inactive-text="Text" style="margin-left: 10px; width: 200px;"
|
inactive-text="Text" style="margin-left: 10px; width: 200px;"
|
||||||
:inactive-action-style="'backgroundColor: var(--sidebar)'" />
|
:inactive-action-style="'backgroundColor: var(--sidebar)'" />
|
||||||
|
@ -312,7 +312,7 @@ export class TaskLoop {
|
|||||||
|
|
||||||
const toolCallResult = await this.handleToolCalls(this.streamingToolCalls.value);
|
const toolCallResult = await this.handleToolCalls(this.streamingToolCalls.value);
|
||||||
|
|
||||||
console.log(toolCallResult);
|
console.log('toolCallResult', toolCallResult);
|
||||||
|
|
||||||
if (toolCallResult.state === MessageState.ParseJsonError) {
|
if (toolCallResult.state === MessageState.ParseJsonError) {
|
||||||
// 如果是因为解析 JSON 错误,则重新开始
|
// 如果是因为解析 JSON 错误,则重新开始
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<span
|
<span
|
||||||
class="tab"
|
class="tab"
|
||||||
v-for="(tab, index) of tabs.content"
|
v-for="(tab, index) of tabs.content"
|
||||||
:key="index"
|
:key="tab.id"
|
||||||
:class="{ 'active-tab': tabs.activeIndex === index }"
|
:class="{ 'active-tab': tabs.activeIndex === index }"
|
||||||
@click="setActiveTab(index)"
|
@click="setActiveTab(index)"
|
||||||
>
|
>
|
||||||
@ -56,7 +56,7 @@ function pageAddNewTab() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setActiveTab(index: number) {
|
function setActiveTab(index: number) {
|
||||||
if (index >= 0 && index < tabs.content.length) {
|
if (index >= 0 && index < tabs.content.length) {
|
||||||
tabs.activeIndex = index;
|
tabs.activeIndex = index;
|
||||||
// 如果不在 debug 路由,则进入
|
// 如果不在 debug 路由,则进入
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { watch, reactive } from 'vue';
|
import { watch, reactive } from 'vue';
|
||||||
import { useRoute, useRouter } from 'vue-router';
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
import Resource from './resource/index.vue';
|
import Resource from './resource/index.vue';
|
||||||
import Chat from './chat/index.vue';
|
import Chat from './chat/index.vue';
|
||||||
@ -11,6 +11,7 @@ import { safeSavePanels, savePanels } from '@/hook/panel';
|
|||||||
const { t } = I18n.global;
|
const { t } = I18n.global;
|
||||||
|
|
||||||
interface Tab {
|
interface Tab {
|
||||||
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
icon: string;
|
icon: string;
|
||||||
type: string;
|
type: string;
|
||||||
@ -52,6 +53,7 @@ watch(
|
|||||||
|
|
||||||
export function createTab(type: string, index: number): Tab {
|
export function createTab(type: string, index: number): Tab {
|
||||||
let customName: string | null = null;
|
let customName: string | null = null;
|
||||||
|
const id = uuidv4();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
get name() {
|
get name() {
|
||||||
@ -65,6 +67,7 @@ export function createTab(type: string, index: number): Tab {
|
|||||||
},
|
},
|
||||||
icon: 'icon-blank',
|
icon: 'icon-blank',
|
||||||
type,
|
type,
|
||||||
|
id,
|
||||||
componentIndex: -1,
|
componentIndex: -1,
|
||||||
component: undefined,
|
component: undefined,
|
||||||
storage: {},
|
storage: {},
|
||||||
@ -83,6 +86,8 @@ export function closeTab(index: number) {
|
|||||||
|
|
||||||
tabs.content.splice(index, 1);
|
tabs.content.splice(index, 1);
|
||||||
|
|
||||||
|
console.log(tabs.content);
|
||||||
|
|
||||||
// 调整活动标签索引
|
// 调整活动标签索引
|
||||||
if (tabs.activeIndex >= index) {
|
if (tabs.activeIndex >= index) {
|
||||||
tabs.activeIndex = Math.max(0, tabs.activeIndex - 1);
|
tabs.activeIndex = Math.max(0, tabs.activeIndex - 1);
|
||||||
|
@ -2,6 +2,7 @@ import { useMessageBridge } from "@/api/message-bridge";
|
|||||||
import { pinkLog } from "@/views/setting/util";
|
import { pinkLog } from "@/views/setting/util";
|
||||||
import { debugModes, tabs } from "@/components/main-panel/panel";
|
import { debugModes, tabs } from "@/components/main-panel/panel";
|
||||||
import { markRaw, ref, nextTick } from "vue";
|
import { markRaw, ref, nextTick } from "vue";
|
||||||
|
import { v4 as uuidv4 } from 'uuid';
|
||||||
|
|
||||||
interface SaveTabItem {
|
interface SaveTabItem {
|
||||||
name: string;
|
name: string;
|
||||||
@ -48,6 +49,7 @@ export function loadPanels() {
|
|||||||
const component = tab.componentIndex >= 0? markRaw(debugModes[tab.componentIndex]) : undefined;
|
const component = tab.componentIndex >= 0? markRaw(debugModes[tab.componentIndex]) : undefined;
|
||||||
|
|
||||||
tabs.content.push({
|
tabs.content.push({
|
||||||
|
id: uuidv4(),
|
||||||
name: tab.name,
|
name: tab.name,
|
||||||
icon: tab.icon,
|
icon: tab.icon,
|
||||||
type: tab.type,
|
type: tab.type,
|
||||||
@ -57,7 +59,7 @@ export function loadPanels() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tabs.activeIndex = persistTab.currentIndex;
|
tabs.activeIndex = persistTab.currentIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
panelLoaded.value = true;
|
panelLoaded.value = true;
|
||||||
@ -76,7 +78,7 @@ export function safeSavePanels() {
|
|||||||
clearTimeout(debounceHandler);
|
clearTimeout(debounceHandler);
|
||||||
debounceHandler = setTimeout(() => {
|
debounceHandler = setTimeout(() => {
|
||||||
savePanels();
|
savePanels();
|
||||||
}, 1000);
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function savePanels(saveHandler?: () => void) {
|
export function savePanels(saveHandler?: () => void) {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<component
|
<component
|
||||||
v-show="tab === tabs.content[tabs.activeIndex]"
|
v-show="tab === tabs.content[tabs.activeIndex]"
|
||||||
v-for="(tab, index) of tabs.content"
|
v-for="(tab, index) of tabs.content"
|
||||||
:key="index"
|
:key="tab.id"
|
||||||
:is="tab.component"
|
:is="tab.component"
|
||||||
:tab-id="index"
|
:tab-id="index"
|
||||||
/>
|
/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user