Files
cocos-mcp/source/panels/default/index.ts
2025-07-17 18:12:56 +08:00

229 lines
10 KiB
TypeScript

import { readSettings } from '../../settings';
import { readFileSync } from 'fs-extra';
import { join } from 'path';
/**
* @zh 如果希望兼容 3.3 之前的版本可以使用下方的代码
* @en You can add the code below if you want compatibility with versions prior to 3.3
*/
// Editor.Panel.define = Editor.Panel.define || function(options: any) { return options }
module.exports = Editor.Panel.define({
listeners: {
show() { console.log('MCP Server panel shown'); },
hide() { console.log('MCP Server panel hidden'); }
},
template: readFileSync(join(__dirname, '../../../static/template/default/index.html'), 'utf-8'),
style: readFileSync(join(__dirname, '../../../static/style/default/index.css'), 'utf-8'),
$: {
panelTitle: '#panelTitle',
serverStatusLabel: '#serverStatusLabel',
serverStatusLabelProp: '#serverStatusLabelProp',
serverStatusValue: '#serverStatusValue',
connectedLabel: '#connectedLabel',
connectedClients: '#connectedClients',
toggleServerBtn: '#toggleServerBtn',
settingsLabel: '#settingsLabel',
portLabel: '#portLabel',
autoStartLabel: '#autoStartLabel',
debugLogLabel: '#debugLogLabel',
maxConnectionsLabel: '#maxConnectionsLabel',
connectionInfoLabel: '#connectionInfoLabel',
httpUrlLabel: '#httpUrlLabel',
httpUrlInput: '#httpUrlInput',
copyBtn: '#copyBtn',
saveSettingsBtn: '#saveSettingsBtn',
// 新增输入控件id
portInput: '#portInput',
maxConnInput: '#maxConnInput',
autoStartInput: '#autoStartInput',
debugLogInput: '#debugLogInput',
},
methods: {
async updateServerStatus(this: any) {
try {
const status = await Editor.Message.request('cocos-mcp-server', 'get-server-status');
this.serverRunning = status.running;
this.connectedClients = status.clients || 0;
this.serverStatus = this.serverRunning ?
Editor.I18n.t('cocos-mcp-server.connected') :
Editor.I18n.t('cocos-mcp-server.disconnected');
this.statusClass = this.serverRunning ? 'running' : 'stopped';
this.buttonText = this.serverRunning ?
Editor.I18n.t('cocos-mcp-server.stop_server') :
Editor.I18n.t('cocos-mcp-server.start_server');
// 刷新UI
this.$.serverStatusValue.innerText = this.serverStatus;
this.$.connectedClients.innerText = this.connectedClients;
this.$.toggleServerBtn.innerText = this.buttonText;
if (this.serverRunning) {
this.httpUrl = `http://localhost:${this.settings.port}/mcp`;
this.$.httpUrlInput.value = this.httpUrl;
} else {
this.httpUrl = '';
this.$.httpUrlInput.value = '';
}
} catch (err) {
console.error('Failed to update server status:', err);
}
},
async toggleServer(this: any) {
this.isProcessing = true;
try {
if (this.serverRunning) {
await this.stopServer();
} else {
await this.startServer();
}
} finally {
this.isProcessing = false;
}
},
async startServer(this: any) {
try {
await Editor.Message.request('cocos-mcp-server', 'start-server');
Editor.Dialog.info(Editor.I18n.t('cocos-mcp-server.server_started'), {
detail: Editor.I18n.t('cocos-mcp-server.server_running').replace('{0}', this.settings.port.toString())
});
await this.updateServerStatus();
} catch (err: any) {
Editor.Dialog.error(Editor.I18n.t('cocos-mcp-server.failed_to_start'), err.message);
}
},
async stopServer(this: any) {
try {
await Editor.Message.request('cocos-mcp-server', 'stop-server');
Editor.Dialog.info(Editor.I18n.t('cocos-mcp-server.server_stopped_msg'), {
detail: Editor.I18n.t('cocos-mcp-server.server_stopped')
});
await this.updateServerStatus();
} catch (err: any) {
Editor.Dialog.error(Editor.I18n.t('cocos-mcp-server.failed_to_stop'), err.message);
}
},
async saveSettings(this: any) {
try {
// 直接用 this.$ 获取所有输入控件的当前值
const port = this.$.portInput ? Number((this.$.portInput as any).value) : 3000;
const maxConnections = this.$.maxConnInput ? Number((this.$.maxConnInput as any).value) : 10;
const autoStart = this.$.autoStartInput ? !!(this.$.autoStartInput as any).checked : false;
const enableDebugLog = this.$.debugLogInput ? !!(this.$.debugLogInput as any).checked : false;
// 组装 settings
const settings = {
...this.settings,
port,
maxConnections,
autoStart,
enableDebugLog,
};
await Editor.Message.request('cocos-mcp-server', 'update-settings', settings);
// 重新拉取设置
const newSettings = await Editor.Message.request('cocos-mcp-server', 'get-server-settings');
this.settings = newSettings;
this.originalSettings = JSON.stringify(newSettings);
Editor.Dialog.info(Editor.I18n.t('cocos-mcp-server.settings_saved'));
} catch (err: any) {
Editor.Dialog.error(Editor.I18n.t('cocos-mcp-server.failed_to_save'), err.message);
}
},
copyUrl(this: any) {
Editor.Clipboard.write('text', this.httpUrl);
Editor.Dialog.info(Editor.I18n.t('cocos-mcp-server.url_copied'));
},
settingsChanged(this: any) {
return JSON.stringify(this.settings) !== this.originalSettings;
},
bindSettingsEvents(this: any) {
// 端口输入框
const portInput = document.querySelectorAll('ui-num-input[slot="content"]')[0];
if (portInput) {
portInput.addEventListener('change', (e: any) => {
this.settings.port = Number(e.detail.value);
});
}
// 最大连接数
const maxConnInput = document.querySelectorAll('ui-num-input[slot="content"]')[1];
if (maxConnInput) {
maxConnInput.addEventListener('change', (e: any) => {
this.settings.maxConnections = Number(e.detail.value);
});
}
// 复选框
const checkboxes = document.querySelectorAll('ui-checkbox[slot="content"]');
if (checkboxes && checkboxes.length >= 2) {
checkboxes[0].addEventListener('change', (e: any) => {
this.settings.autoStart = !!e.detail.value;
});
checkboxes[1].addEventListener('change', (e: any) => {
this.settings.enableDebugLog = !!e.detail.value;
});
}
},
},
ready() {
Editor.Message.request('cocos-mcp-server', 'get-server-settings').then((settings) => {
this.settings = settings;
this.originalSettings = JSON.stringify(settings);
// 本地化label赋值
this.$.panelTitle.innerText = Editor.I18n.t('cocos-mcp-server.panel_title');
this.$.serverStatusLabel.innerText = Editor.I18n.t('cocos-mcp-server.server_status');
this.$.serverStatusLabelProp.innerText = Editor.I18n.t('cocos-mcp-server.server_status');
this.$.connectedLabel.innerText = Editor.I18n.t('cocos-mcp-server.connected');
this.$.settingsLabel.innerText = Editor.I18n.t('cocos-mcp-server.settings');
this.$.portLabel.innerText = Editor.I18n.t('cocos-mcp-server.port');
this.$.autoStartLabel.innerText = Editor.I18n.t('cocos-mcp-server.auto_start');
this.$.debugLogLabel.innerText = Editor.I18n.t('cocos-mcp-server.debug_log');
this.$.maxConnectionsLabel.innerText = Editor.I18n.t('cocos-mcp-server.max_connections');
this.$.connectionInfoLabel.innerText = Editor.I18n.t('cocos-mcp-server.connection_info');
this.$.httpUrlLabel.innerText = Editor.I18n.t('cocos-mcp-server.http_url');
this.$.copyBtn.innerText = Editor.I18n.t('cocos-mcp-server.copy');
this.$.saveSettingsBtn.innerText = Editor.I18n.t('cocos-mcp-server.save_settings');
// 动态内容初始化
this.$.serverStatusValue.innerText = '';
this.$.connectedClients.innerText = '';
this.$.toggleServerBtn.innerText = '';
this.$.httpUrlInput.value = '';
// 绑定按钮事件
this.$.toggleServerBtn.addEventListener('confirm', this.toggleServer.bind(this));
this.$.saveSettingsBtn.addEventListener('confirm', this.saveSettings.bind(this));
this.$.copyBtn.addEventListener('confirm', this.copyUrl.bind(this));
// 延迟绑定事件,确保 UI 组件已渲染
setTimeout(() => {
this.bindSettingsEvents();
}, 100);
// Set up periodic status updates
(this as any).statusInterval = setInterval(() => {
(this as any).updateServerStatus();
}, 2000);
// 不再自动启动服务器,用户点击才启动
(this as any).updateServerStatus();
});
},
beforeClose() {
if ((this as any).statusInterval) {
clearInterval((this as any).statusInterval);
}
},
close() {
// Panel close cleanup
},
// Direct properties for data access
serverRunning: false,
connectedClients: 0,
serverStatus: '',
statusClass: 'stopped',
buttonText: '',
isProcessing: false,
settings: {},
httpUrl: '',
statusInterval: null as any,
originalSettings: ''
} as any);