mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 21:00:30 +08:00
feat: Windows 兼容性全面改进
- Windows Gateway 启动改为前台 spawn 模式(绕过 schtasks 管理员权限) - 添加全局 Gateway 未启动引导横幅(黄色提示条 + 一键启动按钮) - 所有页面加载动画改为脉冲效果 - 统一 Windows cmd /c 调用加 CREATE_NO_WINDOW 标志 - 托盘菜单复用 service.rs 逻辑 - 新增 utils.rs 封装 openclaw_command - 修复 config 文件 UI 字段污染问题 - 添加 dev.ps1 启动脚本
This commit is contained in:
81
src/lib/app-state.js
Normal file
81
src/lib/app-state.js
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 全局应用状态
|
||||
* 管理 openclaw 安装状态,供各组件查询
|
||||
*/
|
||||
import { api } from './tauri-api.js'
|
||||
|
||||
let _openclawReady = false
|
||||
let _gatewayRunning = false
|
||||
let _listeners = []
|
||||
let _gwListeners = []
|
||||
|
||||
/** openclaw 是否就绪(CLI 已安装 + 配置文件存在) */
|
||||
export function isOpenclawReady() {
|
||||
return _openclawReady
|
||||
}
|
||||
|
||||
/** Gateway 是否正在运行 */
|
||||
export function isGatewayRunning() {
|
||||
return _gatewayRunning
|
||||
}
|
||||
|
||||
/** 监听 Gateway 状态变化 */
|
||||
export function onGatewayChange(fn) {
|
||||
_gwListeners.push(fn)
|
||||
return () => { _gwListeners = _gwListeners.filter(cb => cb !== fn) }
|
||||
}
|
||||
|
||||
/** 检测 openclaw 安装状态 */
|
||||
export async function detectOpenclawStatus() {
|
||||
try {
|
||||
const [installation, services] = await Promise.allSettled([
|
||||
api.checkInstallation(),
|
||||
api.getServicesStatus(),
|
||||
])
|
||||
const configExists = installation.status === 'fulfilled' && installation.value?.installed
|
||||
const cliInstalled = services.status === 'fulfilled'
|
||||
&& services.value?.length > 0
|
||||
&& services.value[0]?.cli_installed !== false
|
||||
_openclawReady = configExists && cliInstalled
|
||||
|
||||
// 顺便检测 Gateway 运行状态
|
||||
if (services.status === 'fulfilled' && services.value?.length > 0) {
|
||||
_setGatewayRunning(services.value[0]?.running === true)
|
||||
}
|
||||
} catch {
|
||||
_openclawReady = false
|
||||
}
|
||||
_listeners.forEach(fn => { try { fn(_openclawReady) } catch {} })
|
||||
return _openclawReady
|
||||
}
|
||||
|
||||
function _setGatewayRunning(val) {
|
||||
const changed = _gatewayRunning !== val
|
||||
_gatewayRunning = val
|
||||
if (changed) _gwListeners.forEach(fn => { try { fn(val) } catch {} })
|
||||
}
|
||||
|
||||
/** 刷新 Gateway 运行状态(轻量,仅查服务状态) */
|
||||
export async function refreshGatewayStatus() {
|
||||
try {
|
||||
const services = await api.getServicesStatus()
|
||||
if (services?.length > 0) _setGatewayRunning(services[0]?.running === true)
|
||||
} catch {}
|
||||
return _gatewayRunning
|
||||
}
|
||||
|
||||
let _pollTimer = null
|
||||
/** 启动 Gateway 状态轮询(每 5 秒) */
|
||||
export function startGatewayPoll() {
|
||||
if (_pollTimer) return
|
||||
_pollTimer = setInterval(() => refreshGatewayStatus(), 5000)
|
||||
}
|
||||
export function stopGatewayPoll() {
|
||||
if (_pollTimer) { clearInterval(_pollTimer); _pollTimer = null }
|
||||
}
|
||||
|
||||
/** 监听状态变化 */
|
||||
export function onReadyChange(fn) {
|
||||
_listeners.push(fn)
|
||||
return () => { _listeners = _listeners.filter(cb => cb !== fn) }
|
||||
}
|
||||
@@ -5,9 +5,14 @@
|
||||
|
||||
const isTauri = !!window.__TAURI_INTERNALS__
|
||||
|
||||
// 预加载 Tauri invoke,避免每次 API 调用都做动态 import
|
||||
const _invokeReady = isTauri
|
||||
? import('@tauri-apps/api/core').then(m => m.invoke)
|
||||
: null
|
||||
|
||||
async function invoke(cmd, args = {}) {
|
||||
if (isTauri) {
|
||||
const { invoke: tauriInvoke } = await import('@tauri-apps/api/core')
|
||||
if (_invokeReady) {
|
||||
const tauriInvoke = await _invokeReady
|
||||
return tauriInvoke(cmd, args)
|
||||
}
|
||||
return mockInvoke(cmd, args)
|
||||
@@ -17,7 +22,7 @@ async function invoke(cmd, args = {}) {
|
||||
function mockInvoke(cmd, args) {
|
||||
const mocks = {
|
||||
get_services_status: () => [
|
||||
{ label: 'ai.openclaw.gateway', pid: null, running: false, description: 'OpenClaw Gateway' },
|
||||
{ label: 'ai.openclaw.gateway', pid: null, running: false, description: 'OpenClaw Gateway', cli_installed: true },
|
||||
],
|
||||
get_version_info: () => ({
|
||||
current: '2026.2.23',
|
||||
@@ -83,6 +88,7 @@ function mockInvoke(cmd, args) {
|
||||
delete_memory_file: () => true,
|
||||
export_memory_zip: ({ category }) => `/tmp/openclaw-${category}-20260226-160000.zip`,
|
||||
check_installation: () => ({ installed: true, path: '/usr/local/bin/openclaw', version: '2026.2.23' }),
|
||||
check_node: () => ({ installed: true, version: 'v20.11.0' }),
|
||||
get_deploy_config: () => ({ gatewayUrl: 'http://127.0.0.1:18789', authToken: '', version: '2026.2.23' }),
|
||||
read_mcp_config: () => ({
|
||||
mcpServers: {
|
||||
@@ -171,6 +177,7 @@ export const api = {
|
||||
|
||||
// 安装/部署
|
||||
checkInstallation: () => invoke('check_installation'),
|
||||
checkNode: () => invoke('check_node'),
|
||||
getDeployConfig: () => invoke('get_deploy_config'),
|
||||
writeEnvFile: (path, config) => invoke('write_env_file', { path, config }),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user