feat(channels): 模型配置入口收口到模型渠道页,渠道卡片强化绑定状态

模型配置此前散落三处、口径不一。本次把模型渠道页确立为配置中枢:

- OpenClaw 模型配置页顶部新增引导条:推荐在模型渠道统一维护并同步
- Hermes 安装向导配置步新增引导:已有渠道可从渠道页一键同步到 Hermes
- 晴辰助手 API 设置新增引导:已有渠道可直接同步到助手,无需重复填写
- 渠道卡片同步区新增「绑定状态」标题,OpenClaw / Hermes / 助手三行
  绑定关系(已同步 / 有未同步变更 / 未同步 / 不支持)一目了然

i18n:models / assistant / engine / modelChannels 四个模块补充
简中 / 繁中 / 英文案。验证:npm build + node --test 427 通过。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
晴天
2026-07-05 12:32:31 -07:00
parent 8a247af03e
commit 79863ffddd
9 changed files with 36 additions and 1 deletions

View File

@@ -4089,6 +4089,10 @@ function showSettings() {
<div class="modal-body">
<div class="ast-settings-form">
<div class="ast-tab-panel active" data-panel="api">
<div style="display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:12px;padding:8px 12px;background:var(--bg-tertiary);border-radius:var(--radius-md);font-size:12px;color:var(--text-secondary)">
<span>${t('assistant.channelsGuide')}</span>
<button class="btn btn-sm btn-secondary ast-goto-channels" type="button" style="white-space:nowrap;flex-shrink:0">${t('assistant.channelsGuideBtn')}</button>
</div>
<div class="form-group" style="margin-bottom:8px">
<label class="form-label">${t('assistant.quickSelect')}</label>
<div id="ast-provider-presets" style="display:flex;flex-wrap:wrap;gap:6px">
@@ -4555,6 +4559,12 @@ function showSettings() {
})
})
// 前往模型渠道页(统一维护接入配置的中枢入口)
overlay.querySelector('.ast-goto-channels')?.addEventListener('click', () => {
overlay.remove()
window.location.hash = '#/model-channels'
})
// 服务商快捷预设按钮
const apiTypeSelect = overlay.querySelector('#ast-apitype')
const apiHintEl = overlay.querySelector('#ast-api-hint')

View File

@@ -187,6 +187,7 @@ function renderChannelCard(state, channel) {
${channel.defaultModel ? `<span class="mch-chip">${icon('check', 11)} ${esc(channel.defaultModel)}</span>` : ''}
</div>
<div class="mch-sync-row">
<div style="font-size:11px;font-weight:600;color:var(--text-tertiary);letter-spacing:0.3px">${t('modelChannels.bindings')}</div>
${renderSyncLine(state, channel, 'openclaw', t('modelChannels.targetOpenclaw'), true, '', t('modelChannels.syncOpenclaw'))}
${renderSyncLine(state, channel, 'hermes', t('modelChannels.targetHermes'), hermesSyncSupported(channel), t('modelChannels.syncHermesUnsupported'), t('modelChannels.syncHermes'))}
${renderSyncLine(state, channel, 'assistant', t('modelChannels.targetAssistant'), assistantSyncSupported(channel), t('modelChannels.syncAssistantUnsupported'), t('modelChannels.syncAssistant'))}

View File

@@ -35,6 +35,10 @@ export async function render() {
<div class="form-hint" style="margin-bottom:var(--space-md)">
${t('models.providerHint')}
</div>
<div style="display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:var(--space-md);padding:10px 14px;background:var(--bg-secondary);border:1px solid var(--border-primary);border-left:3px solid var(--primary);border-radius:var(--radius-md);font-size:var(--font-size-sm);color:var(--text-secondary)">
<span>${t('models.channelsGuide')}</span>
<button class="btn btn-sm btn-secondary" id="btn-goto-channels" type="button" style="white-space:nowrap;flex-shrink:0">${t('models.channelsGuideBtn')}</button>
</div>
<div id="qtcool-promo" style="margin-bottom:var(--space-md);border-radius:var(--radius-lg);border:1px solid var(--border-primary);border-left:3px solid var(--primary);background:var(--bg-secondary);padding:16px 20px">
<div style="display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:12px;margin-bottom:12px">
<div style="flex:1;min-width:200px">
@@ -1168,6 +1172,8 @@ function applyDefaultModel(state) {
function bindTopActions(page, state) {
page.querySelector('#btn-add-provider').onclick = () => addProvider(page, state)
page.querySelector('#btn-import-client').onclick = () => importClientConfigs(page, state)
const gotoChannels = page.querySelector('#btn-goto-channels')
if (gotoChannels) gotoChannels.onclick = () => { window.location.hash = '#/model-channels' }
page.querySelector('#btn-undo').onclick = () => undo(page, state)
// 晴辰云:获取模型列表 → 弹窗让用户选择要添加的模型