feat: v0.9.1 — 面板设置页、网络代理、后台安装、模型服务商扩展、多项修复

新功能:
- 新增独立面板设置页面(网络代理 + 代理测试 + 模型代理开关 + npm源)
- 网络代理支持:下载类操作走代理,自动绕过内网地址
- 安装/升级/卸载改为后台执行,不再阻塞界面
- 全局任务状态栏:关闭弹窗后顶部显示进度,可重新查看日志
- 安装/卸载完成后自动刷新界面状态
- 新增多个模型服务商快捷配置(硅基流动、火山引擎、阿里云百炼、智谱AI、MiniMax、NVIDIA NIM、胜算云)
- AI助手浮动按钮恢复,首次提示可拖动,实时聊天页隐藏

修复:
- 修复版本更新误判(本地版本高于远端不再误弹更新)
- 修复Windows下nvm/自定义Node路径CLI检测
- 修复npm EEXIST文件冲突(--force + 安装前自动清理)
- 修复汉化版-zh.x后缀版本比较错误
- 修复模型URL自动拼接/v1问题
- 修复切换版本后Gateway重装失败(PATH缓存刷新)
- 修复切换助手服务商时旧模型名残留

优化:
- macOS图标改用docs/logo.png统一生成
- 内置推荐版本号更新到OpenClaw 2026.3.13
- 错误诊断增强(EEXIST识别)
- 弹窗标题根据操作类型显示
- 新增版本维护文档
This commit is contained in:
晴天
2026-03-14 19:57:22 +08:00
parent c8ccb5dd4b
commit 394813a96c
88 changed files with 1807 additions and 513 deletions

View File

@@ -7,6 +7,7 @@
const BOT_ICON = '<svg viewBox="0 0 24 24"><path d="M12 8V4H8"/><rect x="5" y="8" width="14" height="12" rx="2"/><path d="M9 13h0"/><path d="M15 13h0"/><path d="M10 17h4"/></svg>'
const POS_KEY = 'clawpanel-fab-pos'
const ENABLE_AI_FAB = true
// ── 页面上下文收集器注册表 ──
const _contextProviders = {}
@@ -25,8 +26,14 @@ let _fab = null
/** 初始化 FAB */
export function initAIFab() {
if (!ENABLE_AI_FAB) {
document.querySelectorAll('.ai-fab').forEach(el => el.remove())
_fab = null
return null
}
if (_fab) return _fab
_fab = createFab()
showDragHintOnce(_fab.el)
return _fab
}
@@ -42,8 +49,13 @@ export function openAIDrawerWithError(errorCtx) {
// 不自动导航 — FAB 按钮会出现红点提示,用户主动点击时跳转
// 如果用户已在助手页,也会实时检测到
if (getCurrentRoute() !== '/assistant') {
// 让 FAB 显示红点
if (_fab?.el) _fab.el.classList.add('has-error')
if (_fab?.el) {
_fab.el.classList.add('has-error')
} else {
import('./toast.js')
.then(({ toast }) => toast('已保存诊断上下文,可从侧边栏进入「晴辰助手」继续处理', 'info'))
.catch(() => {})
}
} else {
// 已在助手页 → 直接触发 banner 显示
window.dispatchEvent(new CustomEvent('assistant-error-injected'))
@@ -172,10 +184,11 @@ function createFab() {
window.location.hash = '#/assistant'
}
// ── 路由变化时隐藏/显示 ──
// ── 路由变化时隐藏/显示(助手页和实时聊天页隐藏) ──
const HIDE_ROUTES = ['/assistant', '/chat']
function updateVisibility() {
const route = getCurrentRoute()
fab.style.display = route === '/assistant' ? 'none' : 'flex'
fab.style.display = HIDE_ROUTES.includes(route) ? 'none' : 'flex'
}
window.addEventListener('hashchange', updateVisibility)
@@ -209,3 +222,14 @@ function restorePosition(fab) {
}
} catch {}
}
const HINT_KEY = 'clawpanel-fab-hint-shown'
function showDragHintOnce(el) {
if (!el || localStorage.getItem(HINT_KEY)) return
const tip = document.createElement('div')
tip.className = 'ai-fab-hint'
tip.textContent = '长按可拖动'
el.appendChild(tip)
localStorage.setItem(HINT_KEY, '1')
setTimeout(() => tip.remove(), 4000)
}

View File

@@ -197,7 +197,7 @@ export function showUpgradeModal(title) {
</div>
<div class="upgrade-log-box"></div>
<div class="modal-actions">
<button class="btn btn-secondary btn-sm" data-action="close" disabled>关闭</button>
<button class="btn btn-secondary btn-sm" data-action="close">关闭</button>
</div>
</div>
`
@@ -210,9 +210,51 @@ export function showUpgradeModal(title) {
const _logLines = []
let _onClose = null
closeBtn.onclick = () => { overlay.remove(); _onClose?.() }
let _finished = false
let _taskBar = null
// 重新打开弹窗(从任务状态栏点击时)
function reopenModal() {
if (_taskBar) { _taskBar.remove(); _taskBar = null }
document.body.appendChild(overlay)
}
// 关闭弹窗:未完成时显示任务状态栏
function closeModal() {
overlay.remove()
if (!_finished) {
showTaskBar()
} else {
if (_taskBar) { _taskBar.remove(); _taskBar = null }
_onClose?.()
}
}
// 全局任务状态栏:关闭弹窗后显示在页面顶部
function showTaskBar() {
if (_taskBar) return
_taskBar = document.createElement('div')
_taskBar.className = 'upgrade-task-bar'
_taskBar.innerHTML = `
<span class="upgrade-task-bar-text">${text.textContent}</span>
<button class="btn btn-sm upgrade-task-bar-open">查看详情</button>
<button class="btn btn-sm btn-ghost upgrade-task-bar-dismiss">×</button>
`
_taskBar.querySelector('.upgrade-task-bar-open').onclick = reopenModal
_taskBar.querySelector('.upgrade-task-bar-dismiss').onclick = () => { _taskBar.remove(); _taskBar = null }
document.body.appendChild(_taskBar)
}
function updateTaskBar(statusText) {
if (_taskBar) {
const span = _taskBar.querySelector('.upgrade-task-bar-text')
if (span) span.textContent = statusText
}
}
closeBtn.onclick = closeModal
overlay.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && !closeBtn.disabled) { overlay.remove(); _onClose?.() }
if (e.key === 'Escape') closeModal()
})
return {
@@ -233,25 +275,33 @@ export function showUpgradeModal(title) {
getLogText() { return _logLines.join('\n') },
setProgress(pct) {
fill.style.width = pct + '%'
if (pct >= 100) text.textContent = '完成'
else if (pct >= 75) text.textContent = '正在安装...'
else if (pct >= 30) text.textContent = '正在下载依赖...'
else text.textContent = '准备中...'
let statusText
if (pct >= 100) statusText = '完成'
else if (pct >= 75) statusText = '正在安装...'
else if (pct >= 30) statusText = '正在下载依赖...'
else statusText = '准备中...'
text.textContent = statusText
updateTaskBar(statusText)
},
setDone(msg) {
_finished = true
text.textContent = msg || '升级完成'
fill.style.width = '100%'
fill.classList.add('done')
closeBtn.disabled = false
if (_taskBar) { _taskBar.remove(); _taskBar = null }
closeBtn.focus()
},
setError(msg) {
_finished = true
text.textContent = msg || '升级失败'
fill.classList.add('error')
closeBtn.disabled = false
if (_taskBar) {
const span = _taskBar.querySelector('.upgrade-task-bar-text')
if (span) { span.textContent = msg || '升级失败'; span.style.color = 'var(--error)' }
}
closeBtn.focus()
},
onClose(fn) { _onClose = fn },
destroy() { overlay.remove(); _onClose?.() },
destroy() { overlay.remove(); if (_taskBar) { _taskBar.remove(); _taskBar = null } _onClose?.() },
}
}

View File

@@ -47,6 +47,7 @@ const NAV_ITEMS_FULL = [
{
section: '',
items: [
{ route: '/settings', label: '面板设置', icon: 'settings' },
{ route: '/chat-debug', label: '系统诊断', icon: 'debug' },
{ route: '/about', label: '关于', icon: 'about' },
]
@@ -64,6 +65,7 @@ const NAV_ITEMS_SETUP = [
{
section: '',
items: [
{ route: '/settings', label: '面板设置', icon: 'settings' },
{ route: '/chat-debug', label: '系统诊断', icon: 'debug' },
{ route: '/about', label: '关于', icon: 'about' },
]