增加引导页面

This commit is contained in:
锦恢 2025-05-02 01:50:24 +08:00
parent c1b06313d7
commit 96d029f906
22 changed files with 482 additions and 62 deletions

View File

@ -9,7 +9,7 @@
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.9.7", "element-plus": "^2.9.9",
"katex": "^0.16.21", "katex": "^0.16.21",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",
@ -6119,9 +6119,9 @@
"license": "ISC" "license": "ISC"
}, },
"node_modules/element-plus": { "node_modules/element-plus": {
"version": "2.9.7", "version": "2.9.9",
"resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.7.tgz", "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.9.9.tgz",
"integrity": "sha512-6vjZh5SXBncLhUwJGTVKS5oDljfgGMh6J4zVTeAZK3YdMUN76FgpvHkwwFXocpJpMbii6rDYU3sgie64FyPerQ==", "integrity": "sha512-gN553+xr7ETkhJhH26YG0fERmd2BSCcQKslbtR8fats0Mc0yCtZOXr00bmoPOt5xGzhuRN1TWc9+f1pCaiA0/Q==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@ctrl/tinycolor": "^3.4.1", "@ctrl/tinycolor": "^3.4.1",

View File

@ -9,7 +9,7 @@
}, },
"dependencies": { "dependencies": {
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.9.7", "element-plus": "^2.9.9",
"katex": "^0.16.21", "katex": "^0.16.21",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"markdown-it": "^14.1.0", "markdown-it": "^14.1.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -204,6 +204,13 @@ a {
background-position: center; background-position: center;
} }
.openmcp-image {
background-image: url('./images/openmcp.png');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
}
.el-button:hover { .el-button:hover {
color: var(--foreground) !important; color: var(--foreground) !important;
} }

View File

@ -2,6 +2,8 @@
<div class="main"> <div class="main">
<Sidebar></Sidebar> <Sidebar></Sidebar>
<MainPanel></MainPanel> <MainPanel></MainPanel>
<Tour v-if="!userHasReadGuide"/>
</div> </div>
</template> </template>
@ -15,10 +17,12 @@ import MainPanel from '@/components/main-panel/index.vue';
import { setDefaultCss } from './hook/css'; import { setDefaultCss } from './hook/css';
import { greenLog, pinkLog } from './views/setting/util'; import { greenLog, pinkLog } from './views/setting/util';
import { useMessageBridge } from './api/message-bridge'; import { useMessageBridge } from './api/message-bridge';
import { connectionArgs, connectionMethods, doConnect, loadEnvVar } from './views/connect/connection'; import { doConnect, loadEnvVar } from './views/connect/connection';
import { loadSetting } from './hook/setting'; import { getTour, loadSetting } from './hook/setting';
import { loadPanels } from './hook/panel'; import { loadPanels } from './hook/panel';
import { getPlatform } from './api/platform'; import { getPlatform } from './api/platform';
import Tour from '@/components/guide/tour.vue';
import { userHasReadGuide } from './components/guide/tour';
const bridge = useMessageBridge(); const bridge = useMessageBridge();
@ -28,7 +32,6 @@ bridge.addCommandListener('hello', data => {
greenLog(`version: ${data.version}`); greenLog(`version: ${data.version}`);
}, { once: true }); }, { once: true });
const route = useRoute(); const route = useRoute();
const router = useRouter(); const router = useRouter();
@ -63,6 +66,9 @@ onMounted(async () => {
// //
loadEnvVar(); loadEnvVar();
//
getTour();
// //
await doConnect({ await doConnect({
namespace: platform, namespace: platform,

View File

@ -0,0 +1,25 @@
<template>
<div class="tour-title">
<span class="openmcp-image tour-title-icon"></span>
<slot></slot>
</div>
</template>
<script setup lang="ts">
</script>
<style>
.tour-title {
display: flex;
align-items: center;
margin: 10px 0;
font-size: 18px;
}
.tour-title-icon {
height: 45px;
width: 45px;
margin-right: 5px;
}
</style>

View File

@ -0,0 +1,3 @@
import { ref } from "vue";
export const userHasReadGuide = ref(true);

View File

@ -0,0 +1,285 @@
<template>
<el-tour v-model="openTour">
<el-tour-step
:next-button-props="{ children: '开始' }"
:show-close="false"
>
<template #header>
<TourTitle>介绍</TourTitle>
</template>
<div style="display: flex; padding: 10px; padding-bottom: 20px;">
<div class="tour-common-text">
欢迎来到大模型与 mcp 的世界
<br><br>
OpenMCP 将会助力你快速将任何奇思妙想开发成 mcp 服务器通过接入大模型让你的任何 idea 都可以快速落地
<br><br>
倘若阁下是第一次使用 OpenMCP请务必走完我们准备好的引导
</div>
</div>
</el-tour-step>
<el-tour-step
target="#connected-status-container"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
>
<template #header>
<TourTitle>引导</TourTitle>
</template>
<div class="tour-common-text">
这里会显示当前调试的 mcp 服务器的名称缩写和连接状态只有当连接状态为已连接调试工作才能开始
<br><br>
OpenMCP 通过服务器名称对项目所的所有服务进行统一管理请避免在同一个项目中使用相同的名称
</div>
</el-tour-step>
<el-tour-step
target="#sidebar-connect"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步', onClick: () => router.push('/connect') }"
:show-close="false"
>
<template #header>
<TourTitle>连接</TourTitle>
</template>
<div class="tour-common-text">
如果显示未连接或阁下想要更改连接参数或者连接方式可以点击这里进入连接面板
</div>
</el-tour-step>
<el-tour-step
:target="connectionSettingRef"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
placement="right"
>
<template #header>
<TourTitle>连接</TourTitle>
</template>
<div class="tour-common-text">
阁下可以在左侧面板选择与您心爱的 mcp 服务器进行连接的方式并填入对应的连接参数
<br><br>
对于 openmcp vscode/trae/cursor 插件端的用户当您通过面板按钮进入 openmcp 的时候默认就会选择 STDIO 作为连接方式并根据你的上下文生成启动参数
openmcp desktop 的用户可能就需要自己填写了Anyway这总比在你的好友电脑中植入 chrome 浏览器密码破解木马简单
</div>
</el-tour-step>
<el-tour-step
:target="connectionLogRef"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
placement="left"
>
<template #header>
<TourTitle>连接</TourTitle>
</template>
<div class="tour-common-text">
连接响应会在这个地方打印出来如果出现绿色背景的信息代表连接成功
</div>
</el-tour-step>
<el-tour-step
target="#sidebar-debug"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步', onClick: () => router.push('/debug') }"
:show-close="false"
>
<template #header>
<TourTitle>调试</TourTitle>
</template>
<div class="tour-common-text">
假设你已经成功连接了 mcp 服务器那么点击调试按钮你可以开始你的调试工作
</div>
</el-tour-step>
<el-tour-step
:target="welcomeRef"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
placement="right"
>
<template #header>
<TourTitle>调试</TourTitle>
</template>
<div class="tour-common-text">
我们目前提供了四种主要调试选项资源提词工具分别和 MCP 协议中的 resourcespromptstools 对应
交互测试则允许你直接将写好的 mcp 服务器放入大模型中直接做全链路测试从而更加获取更加真实的反馈和数据进而改进的你的 mcp 服务器
<br><br>
基于我们在 agent rl 方向的最佳实践我们后续还会推出更多的调试和数据集聚合制作选项请期待吧
</div>
</el-tour-step>
<el-tour-step
target="#sidebar-setting"
:prev-button-props="{ children: '上一步', onClick: () => router.push('/debug') }"
:next-button-props="{ children: '下一步', onClick: () => router.push('/setting') }"
:show-close="false"
>
<template #header>
<TourTitle>设置</TourTitle>
</template>
<div class="tour-common-text">
如果要进行交互测试请不要忘记先配置你常用的大模型 API
</div>
</el-tour-step>
<el-tour-step
:target="llmSettingRef"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
placement="right"
>
<template #header>
<TourTitle>设置</TourTitle>
</template>
<div class="tour-common-text">
OpenMCP 目前支持所有支持 openai 接口规范的大模型比如 deepseekopenaikimi 等等
本地部署的 ollama 也正在支持
</div>
</el-tour-step>
<el-tour-step
target="#add-new-server-button"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
>
<template #header>
<TourTitle>设置</TourTitle>
</template>
<div class="tour-common-text">
如果需要添加自定义的大模型服务请点击这里比如火山云阿里云硅基流动等
</div>
</el-tour-step>
<el-tour-step
target="#test-llm-button"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
>
<template #header>
<TourTitle>设置</TourTitle>
</template>
<div class="tour-common-text">
填写完成连接签名后点击这里来测试 大模型服务是否可以访问
</div>
</el-tour-step>
<el-tour-step
target="#save-llm-button"
:prev-button-props="{ children: '上一步' }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
>
<template #header>
<TourTitle>设置</TourTitle>
</template>
<div class="tour-common-text">
最后请不要忘记点击保存按钮保存你的设置
</div>
</el-tour-step>
<el-tour-step
:prev-button-props="{ children: '上一步', onClick: () => router.push('/setting') }"
:next-button-props="{ children: '下一步' }"
:show-close="false"
>
<template #header>
<TourTitle>🎉恭喜</TourTitle>
</template>
<div class="tour-common-text">
🎉恭喜我的朋友现在的你已经是半个 mcp 专家了请充好一杯咖啡慢慢享用快乐的开发时间吧
<br><br>
如果是插件用户左侧面板的最下面入门与帮助有一些我们准备好的资料希望能帮到阁下优雅地开发你的 mcp 服务器
让我们一起把越来越多的 api sdk 接入 大模型吧
</div>
</el-tour-step>
<el-tour-step
:prev-button-props="{ children: '上一步', onClick: () => router.push('/setting') }"
:next-button-props="{ children: '结束', onClick: () => finishTour() }"
:show-close="false"
>
<template #header>
<TourTitle>终章</TourTitle>
</template>
<div class="tour-common-text">
<pre><code>(base) <span style="color: greenyellow"></span> <span style="color: #6AC2CF">.openmcp</span> <span style="color: #6BC34B">cat</span> <span style="color: #D357DB">KEY</span>
直面恐惧创造未来
Face your fears, create the future
恐怖に直面し未来を創り出</code></pre>
</div>
</el-tour-step>
</el-tour>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import TourTitle from './tour-title.vue';
import { useI18n } from 'vue-i18n';
import { useRouter } from 'vue-router';
import { welcomeRef } from '@/views/debug/welcome';
import { connectionLogRef, connectionSettingRef } from '@/views/connect/connection';
import { llmSettingRef } from '@/views/setting/api';
import { userHasReadGuide } from './tour';
import { setTour } from '@/hook/setting';
const openTour = ref(true);
const { t } = useI18n();
const router = useRouter();
function finishTour() {
openTour.value = false;
userHasReadGuide.value = true;
setTour();
}
</script>
<style>
.tour-common-text {
font-size: 1.0rem;
padding: 10px;
padding-bottom: 20px;
line-height: 1.5;
}
.tour-warning {
display: flex;
background-color: rgba(230, 162, 60, 0.5);
border-radius: .5em;
padding: 5px;
margin: 5px 0;
}
</style>

View File

@ -1,5 +1,6 @@
<template> <template>
<div class="connected-status-container" <div class="connected-status-container"
id="connected-status-container"
@click.stop="toggleConnectionPanel()" @click.stop="toggleConnectionPanel()"
> >
<span class="mcp-server-info"> <span class="mcp-server-info">

View File

@ -1,6 +1,8 @@
<template> <template>
<div class="sidebar-item-container"> <div class="sidebar-item-container">
<div v-for="(item, index) of sidebarItems" :key="index"> <div v-for="(item, index) of sidebarItems" :key="index"
:id="`sidebar-${item.ident}`"
>
<el-tooltip :content="t(item.ident)" placement="right"> <el-tooltip :content="t(item.ident)" placement="right">
<div class="sidebar-option-item" :class="{ 'active': isActive(item.ident) }" <div class="sidebar-option-item" :class="{ 'active': isActive(item.ident) }"
@click="gotoOption(item.ident)"> @click="gotoOption(item.ident)">

View File

@ -15,7 +15,6 @@ export function setDefaultCss() {
document.body.style.setProperty('--el-border-color-light', 'var(--sidebar)'); document.body.style.setProperty('--el-border-color-light', 'var(--sidebar)');
document.body.style.setProperty('--el-border-color-lighter', 'var(--sidebar)'); document.body.style.setProperty('--el-border-color-lighter', 'var(--sidebar)');
document.body.style.setProperty('--el-bg-color-overlay', 'var(--sidebar)'); document.body.style.setProperty('--el-bg-color-overlay', 'var(--sidebar)');
document.body.style.setProperty('--el-color-info-light-9', 'var(--main-color)');
document.body.style.setProperty('--el-color-info', 'var(--foreground)'); document.body.style.setProperty('--el-color-info', 'var(--foreground)');
document.body.style.setProperty('--el-color-info-light-8', 'var(--main-color)'); document.body.style.setProperty('--el-color-info-light-8', 'var(--main-color)');
document.body.style.setProperty('--el-fill-color-light', 'var(--sidebar-item-selected)'); document.body.style.setProperty('--el-fill-color-light', 'var(--sidebar-item-selected)');

View File

@ -2,6 +2,7 @@ import { useMessageBridge } from "@/api/message-bridge";
import { llmManager, llms } from "@/views/setting/llm"; import { llmManager, llms } from "@/views/setting/llm";
import { pinkLog } from "@/views/setting/util"; import { pinkLog } from "@/views/setting/util";
import I18n from '@/i18n/index'; import I18n from '@/i18n/index';
import { userHasReadGuide } from "@/components/guide/tour";
export async function loadSetting() { export async function loadSetting() {
const bridge = useMessageBridge(); const bridge = useMessageBridge();
@ -24,6 +25,23 @@ export async function loadSetting() {
} }
} }
export async function getTour() {
const bridge = useMessageBridge();
const { code, msg } = await bridge.commandRequest('setting/get-tour');
if (code === 200) {
pinkLog('获取引导状态成功');
userHasReadGuide.value = msg.userHasReadGuide || false;
}
}
export async function setTour() {
const bridge = useMessageBridge();
const { code, msg } = await bridge.commandRequest('setting/set-tour', {
userHasReadGuide: userHasReadGuide.value
});
}
export function saveSetting(saveHandler?: () => void) { export function saveSetting(saveHandler?: () => void) {
const bridge = useMessageBridge(); const bridge = useMessageBridge();

View File

@ -1,8 +1,7 @@
<template> <template>
<div class="about-container" > <div class="about-container" >
<span class="about-icon-container"> <span class="about-icon-container">
<span class="iconfont icon-openmcp"></span> <div class="openmcp-image"></div>
<span>openmcp</span> <span>openmcp</span>
</span> </span>
@ -23,18 +22,13 @@
</p> </p>
<div style="display: inline-flex;"> <div style="display: inline-flex;">
<el-button <el-button class="join-qq" type="primary"
class="join-qq" @click="joinQQGroup('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')">
type="primary"
@click="joinQQGroup('https://qm.qq.com/cgi-bin/qm/qr?k=C6ZUTZvfqWoI12lWe7L93cWa1hUsuVT0&jump_from=webapi&authKey=McW6B1ogTPjPDrCyGttS890tMZGQ1KB3QLuG4aqVNRaYp4vlTSgf2c6dMcNjMuBD')"
>
<span class="iconfont icon-QQ"></span> <span class="iconfont icon-QQ"></span>
加入 OpenMCP 技术群 加入 OpenMCP 技术群
</el-button> </el-button>
<el-button type="success" <el-button type="success" class="join-qq"
class="join-qq" @click="gotoWebsite('https://marketplace.visualstudio.com/items?itemName=kirigaya.openmcp&ssr=false#review-details')">
@click="gotoWebsite('https://marketplace.visualstudio.com/items?itemName=kirigaya.openmcp&ssr=false#review-details')"
>
<span class="iconfont icon-star"></span> <span class="iconfont icon-star"></span>
OpenMCP 撰写评价 OpenMCP 撰写评价
</el-button> </el-button>
@ -71,7 +65,7 @@ function gotoWebsite(url: string) {
.about-icon-container { .about-icon-container {
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.3); box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.3);
border-radius: .8em; border-radius: .8em;
padding: 20px 50px; padding: 20px 30px;
color: var(--main-color); color: var(--main-color);
background-color: var(--background); background-color: var(--background);
display: flex; display: flex;
@ -90,17 +84,24 @@ function gotoWebsite(url: string) {
width: 150px; width: 150px;
} }
.about-container .openmcp-image {
width: 245px;
height: 205px;
}
.about-container>.qr-code { .about-container>.qr-code {
height: 180px; height: 180px;
border: 2px solid transparent; /* 设置边框宽度,但颜色透明 */ border: 2px solid transparent;
/* 设置边框宽度,但颜色透明 */
border-image: linear-gradient(to bottom right, #7DDCEB, #CB81DA); border-image: linear-gradient(to bottom right, #7DDCEB, #CB81DA);
border-image-slice: 1; /* 确保渐变覆盖整个边框 */ border-image-slice: 1;
background: white; /* 可选:防止内容穿透 */ /* 确保渐变覆盖整个边框 */
background: white;
/* 可选:防止内容穿透 */
} }
.join-qq .iconfont { .join-qq .iconfont {
font-size: 20px; font-size: 20px;
margin-right: 6px; margin-right: 6px;
} }
</style> </style>

View File

@ -1,5 +1,5 @@
import { useMessageBridge } from '@/api/message-bridge'; import { useMessageBridge } from '@/api/message-bridge';
import { reactive } from 'vue'; import { reactive, ref } from 'vue';
import { pinkLog } from '../setting/util'; import { pinkLog } from '../setting/util';
import { arrowMiddleware, ElMessage } from 'element-plus'; import { arrowMiddleware, ElMessage } from 'element-plus';
import { ILaunchSigature } from '@/hook/type'; import { ILaunchSigature } from '@/hook/type';
@ -19,6 +19,9 @@ export const connectionMethods = reactive({
] ]
}); });
export const connectionSettingRef = ref<any>(null);
export const connectionLogRef = ref<any>(null);
export const connectionArgs = reactive({ export const connectionArgs = reactive({
commandString: '', commandString: '',
cwd: '', cwd: '',

View File

@ -1,7 +1,9 @@
<template> <template>
<el-scrollbar> <el-scrollbar>
<div class="connection-container"> <div class="connection-container">
<div class="connect-panel-container"> <div class="connect-panel-container"
:ref="el => connectionSettingRef = el"
>
<ConnectionMethod></ConnectionMethod> <ConnectionMethod></ConnectionMethod>
<ConnectionArgs></ConnectionArgs> <ConnectionArgs></ConnectionArgs>
<EnvVar></EnvVar> <EnvVar></EnvVar>
@ -15,7 +17,9 @@
</div> </div>
</div> </div>
<div class="connect-panel-container"> <div class="connect-panel-container"
:ref="el => connectionLogRef = el"
>
<ConnectionLog></ConnectionLog> <ConnectionLog></ConnectionLog>
</div> </div>
</div> </div>
@ -29,7 +33,7 @@ import { useI18n } from 'vue-i18n';
const { t } = useI18n(); const { t } = useI18n();
import { connectionResult, doConnect } from './connection'; import { connectionLogRef, connectionResult, connectionSettingRef, doConnect } from './connection';
import ConnectionMethod from './connection-method.vue'; import ConnectionMethod from './connection-method.vue';
import ConnectionArgs from './connection-args.vue'; import ConnectionArgs from './connection-args.vue';

View File

@ -1,5 +1,5 @@
<template> <template>
<div style="height: 100%;"> <div style="height: 100%;" id="debug-container">
<Welcome v-show="!haveActiveTab"></Welcome> <Welcome v-show="!haveActiveTab"></Welcome>
<!-- 如果存在激活标签页则根据标签页进行渲染 --> <!-- 如果存在激活标签页则根据标签页进行渲染 -->

View File

@ -0,0 +1,3 @@
import { ref } from "vue";
export const welcomeRef = ref<any>(null);

View File

@ -1,7 +1,9 @@
<template> <template>
<div class="debug-welcome"> <div class="debug-welcome">
<span>{{ t('choose-a-project-debug') }}</span> <span>{{ t('choose-a-project-debug') }}</span>
<div class="welcome-container"> <div class="welcome-container"
:ref="el => welcomeRef = el"
>
<!-- TODO: 支持更多的 server --> <!-- TODO: 支持更多的 server -->
<span <span
class="debug-option" class="debug-option"
@ -25,6 +27,7 @@ import { defineComponent, markRaw, computed } from 'vue';
import { useI18n } from 'vue-i18n'; import { useI18n } from 'vue-i18n';
import { connectionResult } from '../connect/connection'; import { connectionResult } from '../connect/connection';
import { ElMessage } from 'element-plus'; import { ElMessage } from 'element-plus';
import { welcomeRef } from './welcome';
defineComponent({ name: 'welcome' }); defineComponent({ name: 'welcome' });

View File

@ -3,6 +3,8 @@ import { TaskLoop } from '@/components/main-panel/chat/task-loop';
import { llmManager } from './llm'; import { llmManager } from './llm';
import { reactive, ref } from 'vue'; import { reactive, ref } from 'vue';
export const llmSettingRef = ref<any>(null);
export const simpleTestResult = reactive<{ export const simpleTestResult = reactive<{
done: boolean, done: boolean,
start: boolean, start: boolean,

View File

@ -1,5 +1,7 @@
<template> <template>
<div class="setting-section"> <div class="setting-section"
:ref="el => llmSettingRef = el"
>
<h2 class="api-title"> <h2 class="api-title">
{{ "API" }} {{ "API" }}
</h2> </h2>
@ -47,12 +49,15 @@
<br> <br>
<div class="setting-save-container"> <div class="setting-save-container">
<el-button type="success" @click="addNewServer"> <el-button
id="add-new-server-button"
type="success" @click="addNewServer">
{{ t("add-new-server") }} {{ t("add-new-server") }}
</el-button> </el-button>
<el-button <el-button
type="primary" type="primary"
id="test-llm-button"
@click="makeSimpleTalk" @click="makeSimpleTalk"
:loading="simpleTestResult.start" :loading="simpleTestResult.start"
> >
@ -60,7 +65,11 @@
{{ t('test') }} {{ t('test') }}
</el-button> </el-button>
<el-button type="primary" @click="saveLlmSetting"> <el-button
type="primary"
id="save-llm-button"
@click="saveLlmSetting"
>
<span class="iconfont icon-save"></span> <span class="iconfont icon-save"></span>
{{ t('save') }} {{ t('save') }}
</el-button> </el-button>
@ -110,7 +119,7 @@ import { pinkLog } from './util';
import ConnectInterfaceOpenai from './connect-interface-openai.vue'; import ConnectInterfaceOpenai from './connect-interface-openai.vue';
import ConnectTest from './connect-test.vue'; import ConnectTest from './connect-test.vue';
import { makeSimpleTalk, simpleTestResult } from './api'; import { llmSettingRef, makeSimpleTalk, simpleTestResult } from './api';
defineComponent({ name: 'api' }); defineComponent({ name: 'api' });
const { t } = useI18n(); const { t } = useI18n();

View File

@ -1,6 +1,6 @@
import { Controller, RequestClientType } from "../common"; import { Controller, RequestClientType } from "../common";
import { PostMessageble } from "../hook/adapter"; import { PostMessageble } from "../hook/adapter";
import { loadSetting, saveSetting } from "./setting.service"; import { getTour, loadSetting, saveSetting, setTour } from "./setting.service";
export class SettingController { export class SettingController {
@ -17,6 +17,8 @@ export class SettingController {
@Controller('setting/load') @Controller('setting/load')
async loadSetting(client: RequestClientType, data: any, webview: PostMessageble) { async loadSetting(client: RequestClientType, data: any, webview: PostMessageble) {
console.log('enter loading');
const config = loadSetting(); const config = loadSetting();
return { return {
code: 200, code: 200,
@ -24,4 +26,30 @@ export class SettingController {
} }
} }
@Controller('setting/set-tour')
async setTourController(client: RequestClientType, data: any, webview: PostMessageble) {
const { userHasReadGuide } = data;
setTour(userHasReadGuide);
return {
code: 200,
msg: 'setTour success'
}
}
@Controller('setting/get-tour')
async getTourController(client: RequestClientType, data: any, webview: PostMessageble) {
console.log('enter');
const { userHasReadGuide } = getTour();
return {
code: 200,
msg:{
userHasReadGuide
}
}
}
} }

View File

@ -6,9 +6,6 @@ import { IConfig } from './setting.dto';
import { llms } from '../hook/llm'; import { llms } from '../hook/llm';
function getConfigurationPath() { function getConfigurationPath() {
// 如果是 vscode 插件下,则修改为 ~/.openmcp/config.json
if (VSCODE_WORKSPACE) {
// 在 VSCode 插件环境下
const homeDir = os.homedir(); const homeDir = os.homedir();
const configDir = path.join(homeDir, '.openmcp'); const configDir = path.join(homeDir, '.openmcp');
if (!fs.existsSync(configDir)) { if (!fs.existsSync(configDir)) {
@ -16,8 +13,6 @@ function getConfigurationPath() {
} }
return path.join(configDir, 'setting.json'); return path.join(configDir, 'setting.json');
} }
return 'setting.json';
}
function getDefaultLanguage() { function getDefaultLanguage() {
if (process.env.VSCODE_PID) { if (process.env.VSCODE_PID) {
@ -75,3 +70,29 @@ export function saveSetting(config: Partial<IConfig>): void {
throw error; throw error;
} }
} }
export function getTour() {
const configPath = getConfigurationPath();
const KEY = path.join(path.dirname(configPath), 'KEY');
console.log(KEY);
if (!fs.existsSync(KEY)) {
return {
userHasReadGuide: false
};
}
return {
userHasReadGuide: true
};
}
export function setTour(userHasReadGuide: boolean): void {
const configPath = getConfigurationPath();
const KEY = path.join(path.dirname(configPath), 'KEY');
if (userHasReadGuide) {
const key = `直面恐惧,创造未来
Face your fears, create the future
`;
fs.writeFileSync(KEY, key, 'utf-8');
}
}