mirror of
https://github.com/kuaifan/dootask.git
synced 2026-01-04 02:38:11 +00:00
feat: 添加MCP服务器状态切换功能
This commit is contained in:
parent
00b4d6a748
commit
8958f2f234
17
electron/electron.js
vendored
17
electron/electron.js
vendored
@ -46,7 +46,7 @@ const utils = require('./lib/utils');
|
||||
const config = require('./package.json');
|
||||
const electronDown = require("./electron-down");
|
||||
const electronMenu = require("./electron-menu");
|
||||
const { startMCPServer } = require("./lib/mcp");
|
||||
const { startMCPServer, stopMCPServer } = require("./lib/mcp");
|
||||
|
||||
// 实例初始化
|
||||
const userConf = new electronConf()
|
||||
@ -1159,8 +1159,6 @@ if (!getTheLock) {
|
||||
preCreateChildWindow()
|
||||
// 监听主题变化
|
||||
monitorThemeChanges()
|
||||
// 启动 MCP 服务器
|
||||
startMCPServer(mainWindow, mcpPort)
|
||||
// 创建托盘
|
||||
if (['darwin', 'win32'].includes(process.platform) && utils.isJson(config.trayIcon)) {
|
||||
mainTray = new Tray(path.join(__dirname, config.trayIcon[isDevelopMode ? 'dev' : 'prod'][process.platform === 'darwin' ? 'mac' : 'win']));
|
||||
@ -1664,6 +1662,19 @@ ipcMain.on('setDockBadge', (event, args) => {
|
||||
event.returnValue = "ok"
|
||||
})
|
||||
|
||||
/**
|
||||
* MCP 服务器状态切换
|
||||
* @param args
|
||||
*/
|
||||
ipcMain.on('mcpServerToggle', (event, args) => {
|
||||
const { running } = args;
|
||||
if (running === 'running') {
|
||||
startMCPServer(mainWindow, mcpPort)
|
||||
} else {
|
||||
stopMCPServer()
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* 复制Base64图片
|
||||
* @param args
|
||||
|
||||
@ -28,7 +28,9 @@
|
||||
placement="right-start">
|
||||
<DropdownItem :divided="!!item.divided">
|
||||
<div class="manage-menu-flex">
|
||||
{{$L(item.name)}}
|
||||
<div class="manage-menu-title">
|
||||
{{$L(item.name)}}
|
||||
</div>
|
||||
<Icon type="ios-arrow-forward"></Icon>
|
||||
</div>
|
||||
</DropdownItem>
|
||||
@ -66,7 +68,9 @@
|
||||
placement="right-start">
|
||||
<DropdownItem :divided="!!item.divided">
|
||||
<div class="manage-menu-flex">
|
||||
{{$L(item.name)}}
|
||||
<div class="manage-menu-title">
|
||||
{{$L(item.name)}}
|
||||
</div>
|
||||
<Icon type="ios-arrow-forward"></Icon>
|
||||
</div>
|
||||
</DropdownItem>
|
||||
@ -86,7 +90,12 @@
|
||||
:name="item.path"
|
||||
:style="item.style || {}">
|
||||
<div class="manage-menu-flex">
|
||||
{{$L(item.name)}}
|
||||
<div class="manage-menu-title">
|
||||
{{$L(item.name)}}
|
||||
</div>
|
||||
<Icon
|
||||
v-if="item.selected === true"
|
||||
type="md-checkmark" />
|
||||
<Badge
|
||||
v-if="item.path === 'version'"
|
||||
class="manage-menu-report-badge"
|
||||
@ -317,6 +326,9 @@
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
<!--弹出 MCP 服务器信息-->
|
||||
<MCPHelper v-model="mcpHelperShow"/>
|
||||
|
||||
<!--导出任务统计-->
|
||||
<TaskExport v-model="exportTaskShow"/>
|
||||
|
||||
@ -415,6 +427,7 @@
|
||||
import { mapState, mapGetters } from 'vuex'
|
||||
import ProjectArchived from "./manage/components/ProjectArchived";
|
||||
import TeamManagement from "./manage/components/TeamManagement";
|
||||
import MCPHelper from "./manage/components/MCPHelper";
|
||||
import FavoriteManagement from "./manage/components/FavoriteManagement";
|
||||
import RecentManagement from "./manage/components/RecentManagement";
|
||||
import ProjectManagement from "./manage/components/ProjectManagement";
|
||||
@ -460,6 +473,7 @@ export default {
|
||||
DrawerOverlay,
|
||||
ProjectManagement,
|
||||
TeamManagement,
|
||||
MCPHelper,
|
||||
FavoriteManagement,
|
||||
RecentManagement,
|
||||
ProjectArchived,
|
||||
@ -529,9 +543,11 @@ export default {
|
||||
approveShow: false,
|
||||
approveDetails: {id: 0},
|
||||
approveDetailsShow: false,
|
||||
|
||||
|
||||
taskBrowseLoading: false,
|
||||
taskBrowseHistory: [], // 存储任务浏览历史
|
||||
taskBrowseHistory: [],
|
||||
|
||||
mcpHelperShow: false,
|
||||
}
|
||||
},
|
||||
|
||||
@ -596,6 +612,8 @@ export default {
|
||||
'formOptions',
|
||||
'mobileTabbar',
|
||||
'longpressData',
|
||||
|
||||
'mcpServerStatus'
|
||||
]),
|
||||
|
||||
...mapGetters(['dashboardTask', "filterMicroAppsMenusMain"]),
|
||||
@ -699,6 +717,7 @@ export default {
|
||||
{path: 'taskBrowse', name: '最近打开的任务'},
|
||||
{path: 'favorite', name: '我的收藏'},
|
||||
{path: 'download', name: '下载内容', visible: !!this.$Electron},
|
||||
{path: 'mcpServer', name: '启用桌面 MCP 服务器', visible: !!this.$Electron, selected: this.mcpServerStatus.running === 'running'},
|
||||
];
|
||||
if (userIsAdmin) {
|
||||
array.push(...[
|
||||
@ -848,6 +867,16 @@ export default {
|
||||
},
|
||||
immediate: true
|
||||
},
|
||||
|
||||
mcpServerStatus: {
|
||||
handler(data) {
|
||||
if (!this.$Electron) {
|
||||
return;
|
||||
}
|
||||
this.$Electron.sendMessage('mcpServerToggle', data);
|
||||
},
|
||||
immediate: true
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
@ -923,6 +952,12 @@ export default {
|
||||
theme: this.themeName,
|
||||
});
|
||||
return;
|
||||
case 'mcpServer':
|
||||
if (this.mcpServerStatus.running !== 'running') {
|
||||
this.mcpHelperShow = true;
|
||||
}
|
||||
this.$store.dispatch('toggleMcpServer');
|
||||
return;
|
||||
case 'logout':
|
||||
$A.modalConfirm({
|
||||
title: '退出登录',
|
||||
@ -1549,7 +1584,7 @@ export default {
|
||||
*/
|
||||
loadTaskBrowseHistory() {
|
||||
if (this.taskBrowseLoading) return
|
||||
|
||||
|
||||
this.taskBrowseLoading = true
|
||||
this.$store.dispatch("getTaskBrowseHistory", 20).then(({data}) => {
|
||||
// 更新组件内的浏览历史数据
|
||||
|
||||
167
resources/assets/js/pages/manage/components/MCPHelper.vue
Normal file
167
resources/assets/js/pages/manage/components/MCPHelper.vue
Normal file
@ -0,0 +1,167 @@
|
||||
<template>
|
||||
<Modal v-model="mcpHelperShow" :title="$L('桌面 MCP 服务器')" :mask-closable="false" width="700">
|
||||
<div class="mcp-helper-content">
|
||||
<Alert type="success" show-icon>
|
||||
{{ $L('MCP 服务器已启动成功!') }}
|
||||
<span slot="desc">
|
||||
{{ $L('服务地址') }}: <code>http://localhost:22224/sse</code>
|
||||
</span>
|
||||
</Alert>
|
||||
|
||||
<div class="mcp-section">
|
||||
<h3>🔗 {{ $L('接入配置') }}</h3>
|
||||
<p>{{ $L('以接入 Claude 为例,在配置文件中添加以下配置') }}:</p>
|
||||
<div class="mcp-code-block">
|
||||
<pre ref="mcpConfig">{{ mcpConfig }}</pre>
|
||||
<Button size="small" class="mcp-copy-btn" @click="copyMcpConfig">{{ $L('复制配置') }}</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mcp-section">
|
||||
<h3>💡 {{ $L('使用示例') }}</h3>
|
||||
<p>{{ $L('配置生效后,即可通过自然语言使用 MCP 服务') }}:</p>
|
||||
<ul class="mcp-examples">
|
||||
<li>"{{ $L("查看我未完成的任务") }}"</li>
|
||||
<li>"{{ $L("搜索包含'报告'的任务") }}"</li>
|
||||
<li>"{{ $L("标记任务456为已完成") }}"</li>
|
||||
<li>"{{ $L("在项目1中创建任务:完成用户手册") }}"</li>
|
||||
<li>"{{ $L("把任务789的截止时间改为下周五") }}"</li>
|
||||
<li>"{{ $L("我有哪些项目?") }}"</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div slot="footer" class="adaption">
|
||||
<Button type="primary" @click="mcpHelperShow = false">{{ $L('我知道了') }}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.mcp-helper-content {
|
||||
.mcp-section {
|
||||
margin-top: 20px;
|
||||
|
||||
h3 {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
margin-bottom: 12px;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 10px;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.mcp-code-block {
|
||||
position: relative;
|
||||
background: #f5f7fa;
|
||||
border: 1px solid #e4e7ed;
|
||||
border-radius: 4px;
|
||||
padding: 12px;
|
||||
margin: 12px 0;
|
||||
|
||||
pre {
|
||||
margin: 0;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
color: #333;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.mcp-copy-btn {
|
||||
position: absolute;
|
||||
top: 8px;
|
||||
right: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.mcp-hint {
|
||||
font-size: 13px;
|
||||
color: #999;
|
||||
margin-top: 8px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
|
||||
code {
|
||||
background: #f5f7fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.mcp-examples {
|
||||
margin: 12px 0;
|
||||
padding-left: 20px;
|
||||
|
||||
li {
|
||||
margin: 8px 0;
|
||||
color: #666;
|
||||
line-height: 1.6;
|
||||
font-size: 14px;
|
||||
|
||||
&:before {
|
||||
content: '•';
|
||||
color: #2d8cf0;
|
||||
font-weight: bold;
|
||||
display: inline-block;
|
||||
width: 1em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
background: #f5f7fa;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
color: #e96900;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "MCPHelper",
|
||||
props: {
|
||||
value: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mcpConfig: `{
|
||||
"mcpServers": {
|
||||
"DooTask": {
|
||||
"url": "http://localhost:22224/sse"
|
||||
}
|
||||
}
|
||||
}`
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
mcpHelperShow: {
|
||||
get() {
|
||||
return this.value;
|
||||
},
|
||||
set(value) {
|
||||
this.$emit('input', value);
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
copyMcpConfig() {
|
||||
this.copyText(this.$refs.mcpConfig.textContent);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
22
resources/assets/js/store/actions.js
vendored
22
resources/assets/js/store/actions.js
vendored
@ -1081,6 +1081,7 @@ export default {
|
||||
cacheTranslations: await $A.IDBArray("cacheTranslations"),
|
||||
cacheEmojis: await $A.IDBArray("cacheEmojis"),
|
||||
userInfo: await $A.IDBJson("userInfo"),
|
||||
mcpServerStatus: await $A.IDBJson("mcpServerStatus"),
|
||||
cacheVersion: state.cacheVersion,
|
||||
};
|
||||
await $A.IDBClear();
|
||||
@ -1141,6 +1142,7 @@ export default {
|
||||
'userInfo',
|
||||
'taskRelatedCache',
|
||||
'dialogCommonCountCache',
|
||||
'mcpServerStatus'
|
||||
]
|
||||
};
|
||||
|
||||
@ -5044,4 +5046,24 @@ export default {
|
||||
commit("microApps/data", data|| [])
|
||||
}
|
||||
},
|
||||
|
||||
/** *****************************************************************************************/
|
||||
/** *********************************** MCP Server ******************************************/
|
||||
/** *****************************************************************************************/
|
||||
|
||||
/**
|
||||
* 切换 MCP 服务器状态
|
||||
* @param state
|
||||
* @param commit
|
||||
*/
|
||||
async toggleMcpServer({state, commit}) {
|
||||
if (state.mcpServerStatus.running === 'running') {
|
||||
// 停止 MCP 服务器
|
||||
commit('mcp/server/status', {running: 'stopped'});
|
||||
} else {
|
||||
// 启动 MCP 服务器
|
||||
commit('mcp/server/status', {running: 'running'});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
5
resources/assets/js/store/mutations.js
vendored
5
resources/assets/js/store/mutations.js
vendored
@ -439,4 +439,9 @@ export default {
|
||||
$A.IDBSave("microAppsIds", state.microAppsIds = data.map(item => item.id));
|
||||
$A.IDBSave("microAppsMenus", state.microAppsMenus = menus);
|
||||
},
|
||||
|
||||
// MCP 服务器状态
|
||||
'mcp/server/status': function(state, data) {
|
||||
$A.IDBSave("mcpServerStatus", state.mcpServerStatus = data);
|
||||
},
|
||||
}
|
||||
|
||||
3
resources/assets/js/store/state.js
vendored
3
resources/assets/js/store/state.js
vendored
@ -277,4 +277,7 @@ export default {
|
||||
microAppsInstalled: [],
|
||||
microAppsIds: [],
|
||||
microAppsMenus: [],
|
||||
|
||||
// MCP 服务器状态
|
||||
mcpServerStatus: {running: 'stopped'},
|
||||
};
|
||||
|
||||
7
resources/assets/sass/pages/page-manage.scss
vendored
7
resources/assets/sass/pages/page-manage.scss
vendored
@ -418,6 +418,13 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
column-gap: 8px;
|
||||
.manage-menu-title {
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
.ivu-icon {
|
||||
color: $primary-text-color;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user