mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-30 04:40:18 +08:00
feat: npm 源可配置,支持淘宝/官方/华为云镜像切换
- 所有 npm 操作使用用户配置的 registry,默认淘宝镜像 - 服务管理页面新增 npm 源设置区域(预设 + 自定义) - 版本检测 API 同步使用配置源 - 配置持久化到 ~/.openclaw/npm-registry.txt
This commit is contained in:
@@ -99,6 +99,8 @@ function mockInvoke(cmd, args) {
|
||||
upgrade_openclaw: () => '升级成功,当前版本: 2026.2.26-zh.3 (mock)',
|
||||
install_gateway: () => 'Gateway 服务已安装 (mock)',
|
||||
uninstall_gateway: () => 'Gateway 服务已卸载 (mock)',
|
||||
get_npm_registry: () => 'https://registry.npmmirror.com',
|
||||
set_npm_registry: () => true,
|
||||
test_model: ({ modelId }) => `模型 ${modelId} 连通正常 (mock)`,
|
||||
list_remote_models: () => ['gpt-4o', 'gpt-4o-mini', 'gpt-4-turbo', 'gpt-3.5-turbo', 'o3-mini', 'dall-e-3', 'text-embedding-3-small'],
|
||||
write_env_file: () => true,
|
||||
@@ -144,6 +146,8 @@ export const api = {
|
||||
upgradeOpenclaw: (source = 'chinese') => invoke('upgrade_openclaw', { source }),
|
||||
installGateway: () => invoke('install_gateway'),
|
||||
uninstallGateway: () => invoke('uninstall_gateway'),
|
||||
getNpmRegistry: () => invoke('get_npm_registry'),
|
||||
setNpmRegistry: (registry) => invoke('set_npm_registry', { registry }),
|
||||
testModel: (baseUrl, apiKey, modelId) => invoke('test_model', { baseUrl, apiKey, modelId }),
|
||||
listRemoteModels: (baseUrl, apiKey) => invoke('list_remote_models', { baseUrl, apiKey }),
|
||||
|
||||
|
||||
@@ -27,6 +27,10 @@ export async function render() {
|
||||
</div>
|
||||
<div id="version-bar"></div>
|
||||
<div id="services-list">加载中...</div>
|
||||
<div class="config-section" id="registry-section">
|
||||
<div class="config-section-title">npm 源设置</div>
|
||||
<div id="registry-bar">加载中...</div>
|
||||
</div>
|
||||
<div class="config-section" id="backup-section">
|
||||
<div class="config-section-title">配置备份</div>
|
||||
<div id="backup-actions" style="margin-bottom:var(--space-md)">
|
||||
@@ -45,6 +49,7 @@ async function loadAll(page) {
|
||||
await Promise.all([
|
||||
loadVersion(page),
|
||||
loadServices(page),
|
||||
loadRegistry(page),
|
||||
loadBackups(page),
|
||||
])
|
||||
}
|
||||
@@ -85,6 +90,41 @@ async function loadVersion(page) {
|
||||
}
|
||||
}
|
||||
|
||||
// ===== npm 源设置 =====
|
||||
|
||||
const REGISTRIES = [
|
||||
{ label: '淘宝镜像 (推荐)', value: 'https://registry.npmmirror.com' },
|
||||
{ label: 'npm 官方源', value: 'https://registry.npmjs.org' },
|
||||
{ label: '华为云镜像', value: 'https://repo.huaweicloud.com/repository/npm/' },
|
||||
]
|
||||
|
||||
async function loadRegistry(page) {
|
||||
const bar = page.querySelector('#registry-bar')
|
||||
try {
|
||||
const current = await api.getNpmRegistry()
|
||||
const isPreset = REGISTRIES.some(r => r.value === current)
|
||||
bar.innerHTML = `
|
||||
<div style="display:flex;align-items:center;gap:var(--space-sm);flex-wrap:wrap">
|
||||
<select class="form-input" data-name="registry" style="max-width:320px">
|
||||
${REGISTRIES.map(r => `<option value="${r.value}" ${r.value === current ? 'selected' : ''}>${r.label}</option>`).join('')}
|
||||
<option value="custom" ${!isPreset ? 'selected' : ''}>自定义</option>
|
||||
</select>
|
||||
<input class="form-input" data-name="custom-registry" placeholder="https://..." value="${isPreset ? '' : escapeHtml(current)}" style="max-width:320px;${isPreset ? 'display:none' : ''}">
|
||||
<button class="btn btn-primary btn-sm" data-action="save-registry">保存</button>
|
||||
</div>
|
||||
<div class="form-hint" style="margin-top:var(--space-xs)">升级和版本检测使用此源下载 npm 包,国内用户推荐淘宝镜像</div>
|
||||
`
|
||||
// 切换预设/自定义
|
||||
const select = bar.querySelector('[data-name="registry"]')
|
||||
const customInput = bar.querySelector('[data-name="custom-registry"]')
|
||||
select.onchange = () => {
|
||||
customInput.style.display = select.value === 'custom' ? '' : 'none'
|
||||
}
|
||||
} catch (e) {
|
||||
bar.innerHTML = `<div style="color:var(--error)">加载失败: ${escapeHtml(String(e))}</div>`
|
||||
}
|
||||
}
|
||||
|
||||
// ===== 服务列表 =====
|
||||
|
||||
async function loadServices(page) {
|
||||
@@ -214,6 +254,9 @@ function bindEvents(page) {
|
||||
case 'uninstall-gateway':
|
||||
await handleUninstallGateway(btn, page)
|
||||
break
|
||||
case 'save-registry':
|
||||
await handleSaveRegistry(btn, page)
|
||||
break
|
||||
}
|
||||
} catch (e) {
|
||||
toast(e.toString(), 'error')
|
||||
@@ -310,3 +353,13 @@ async function handleUninstallGateway(btn, page) {
|
||||
toast('Gateway 服务已卸载', 'success')
|
||||
await loadServices(page)
|
||||
}
|
||||
|
||||
async function handleSaveRegistry(btn, page) {
|
||||
const section = page.querySelector('#registry-section')
|
||||
const select = section.querySelector('[data-name="registry"]')
|
||||
const customInput = section.querySelector('[data-name="custom-registry"]')
|
||||
const registry = select.value === 'custom' ? customInput.value.trim() : select.value
|
||||
if (!registry) { toast('请输入源地址', 'error'); return }
|
||||
await api.setNpmRegistry(registry)
|
||||
toast('npm 源已保存', 'success')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user