mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-31 05:10:14 +08:00
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:
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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?.() },
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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' },
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user