From ed1d8ee7641bcf295240838bd1337545f2003bb2 Mon Sep 17 00:00:00 2001 From: chengma Date: Mon, 20 Jul 2026 15:50:59 +0800 Subject: [PATCH] docs(ui): apply T-677 gateway source switch to workbench prototype MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⑤ 设置的网关分区按 T-677 改为生成来源二选一: - 分区标题「cmhub 网关」改为「生成网关」并保留,新增互斥选中态的 「默认网关 / 自定义网关」分段选择器(radiogroup,表达状态而非动作)。 - 双面板显隐:默认网关面板含网关地址、API Key、生文/生图/图片理解别名、 连接超时、测试连接·查余额、批量生成前检查余额;自定义网关面板含模型 列表、模型详情(名称/类别/接口地址/模型ID/API Key/接口类型/超时/启用)、 独立的测试按钮与结果标签、默认文本与默认图像模型选择。 - 保存语义区分:来源切换只标记未保存,点「保存设置」才生效;模型的新增、 保存、删除立即写入配置,「放弃更改」不回滚这些操作,两者各有中文反馈。 - 接口类型按现有 direct 实现说明三种行为,明确「自动」不探测对方服务。 - 文案收敛:⑤面板、标题栏网关状态与②余额展示不再出现 cmhub 字样; 自定义网关下②显示「不计点数,费用由服务商收取」而非 0 点或旧余额, 稳定取值 cmhub/direct 仅保留在 value 与 data-* 中。 - ⑥联动:自定义网关下停用「生成套图」与「AI 帮写」,同时保留 「继续查询已提交图片」入口取回已扣点的默认网关任务,不新建、不重复计费。 Co-Authored-By: Claude Fable 5 --- docs/ui/workbench-redesign-v1.html | 295 +++++++++++++++++++++++++++-- 1 file changed, 278 insertions(+), 17 deletions(-) diff --git a/docs/ui/workbench-redesign-v1.html b/docs/ui/workbench-redesign-v1.html index 41f55af..387f9f7 100644 --- a/docs/ui/workbench-redesign-v1.html +++ b/docs/ui/workbench-redesign-v1.html @@ -517,6 +517,42 @@ .form-section { padding: var(--space-4); border-bottom: 1px solid var(--stroke-divider); } .form-section:last-child { border-bottom: 0; } .form-section h2 { margin: 0 0 var(--space-3); font-size: 13px; font-weight: 600; } + .section-head { display: flex; align-items: center; flex-wrap: wrap; gap: var(--space-3); margin-bottom: var(--space-3); } + .section-head h2 { margin: 0; } + .section-head .push { margin-left: auto; } + + /* ---- 分段选择器:表达“当前来源”这一状态,不是动作按钮 ---- + Qt 端对应 QButtonGroup(setExclusive) + setCheckable 的两个按钮, + 或两个 QRadioButton;不得退化为普通 QPushButton。 */ + .segmented { display: inline-flex; border: 1px solid var(--stroke-control); border-radius: var(--radius-control); overflow: hidden; } + .segmented label { + display: flex; align-items: center; + min-height: 32px; padding: 0 var(--space-3); + border-right: 1px solid var(--stroke-control); + color: var(--text-primary); font-size: 13px; cursor: pointer; + transition: background var(--motion-fast) var(--ease); + } + .segmented label:last-of-type { border-right: 0; } + .segmented label:hover { background: var(--surface-hover); } + .segmented label.is-checked { background: var(--accent-default); color: #fff; font-weight: 600; } + .segmented label.is-focused { outline: 2px solid var(--focus-stroke); outline-offset: -2px; } + .segmented input { position: absolute; width: 1px; height: 1px; opacity: 0; } + + .gateway-panel[hidden] { display: none; } + .gateway-note { margin: 0 0 var(--space-3); } + + .model-layout { display: grid; grid-template-columns: minmax(170px, .55fr) minmax(0, 1.45fr); gap: var(--space-3); align-items: start; } + .model-list { max-height: 232px; overflow: auto; padding: var(--space-1); border: 1px solid var(--stroke-control); border-radius: var(--radius-control); background: var(--surface-layer); } + .model-item { + display: grid; grid-template-columns: 1fr auto; align-items: center; gap: var(--space-2); + width: 100%; min-height: 40px; padding: var(--space-1) var(--space-2); + border: 0; border-radius: var(--radius-control); background: transparent; text-align: left; + } + .model-item[aria-current="true"] { background: var(--accent-subtle); box-shadow: inset 3px 0 0 var(--accent-default); } + .model-item .name { display: block; font-size: 13px; font-weight: 600; } + .model-item .meta { display: block; overflow: hidden; color: var(--text-secondary); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; } + .test-result { display: inline-flex; align-items: center; font-size: 12px; color: var(--text-secondary); } + @media (max-width: 1000px) { .model-layout { grid-template-columns: minmax(0, 1fr); } .model-list { max-height: 160px; } } .form-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--space-3); } .form-grid .span-2 { grid-column: span 2; } .form-grid .span-3 { grid-column: 1 / -1; } @@ -654,7 +690,7 @@ 蝦皮圈優化助手 - cmhub 已连接 + 默认网关 已连接
@@ -784,8 +820,10 @@
@@ -1093,6 +1131,17 @@
+ +
+
+ 当前生成来源为自定义网关,商品套图已停用 + 商品套图与「AI 帮写」仅支持默认网关。此前已提交到默认网关的任务仍可继续查询并取回,不会重复扣点。需要重新生成请到⑤把生成来源切回默认网关。 +
+
+ +
+
+
@@ -1105,8 +1154,8 @@ 3 类共 3 张 · 预计消耗 6 点
- - + +
@@ -1179,25 +1228,99 @@
+
-

cmhub 网关

-
-
只填写网关根地址,保存时自动规整路径。
-
保存在本地配置,不会写入日志。
-
-
-
+
+

生成网关

+
+ + +
+ + 切换来源只标记未保存,点击「保存设置」后才生效。 +
+ + +
+
+
只填写网关根地址,保存时自动规整路径。
+
以明文保存在本地配置文件中,请勿在共用电脑上使用。不会写入日志。
+
+
+
+
+
+
+ + 尚未测试 +
+
+ +
+
+ + +
+
-

生成参数

+

角色与生成参数

-
@@ -1354,6 +1477,18 @@
+ + +
+

删除模型“本地 Qwen 文本”?

+

将立即从自定义模型配置中删除,不需要点「保存设置」,也无法通过「放弃更改」恢复。如果它正被设为默认文本模型,②生成标题时会提示去⑤补齐。

+
+
+ + +
+
+
@@ -1404,6 +1539,8 @@
  • 按钮文案为「采集架上商品 / 采集全部商品」与「生成架上商品 / 生成全部商品」(T-664、T-665)。
  • ③不提供任何强制更新异常商品的入口,商品状态异常一律后台拦截(T-662d)。
  • 历史批次已由数据库迁移默认为架上商品,不出现「待检测」状态和状态重检入口(T-667)。
  • +
  • ⑤「生成网关」分区提供互斥选中态的「默认网关 / 自定义网关」来源选择器与双面板;切换只标记未保存,点「保存设置」才生效;模型的新增/保存/删除立即写入,「放弃更改」不回滚这些操作。⑤与②的可见文案不再出现 cmhub 字样(T-677)。
  • +
  • 切到自定义网关后,②照常生成,⑥商品套图的生成与「AI 帮写」停用,但保留「继续查询已提交图片」入口取回已扣点任务(T-677 第 4 节)。
  • 仍需确认的假设

    @@ -1943,14 +2080,138 @@ settingsForm.addEventListener('input', function () { setDirty(true); }); settingsForm.addEventListener('change', function () { setDirty(true); }); - settingsSave.addEventListener('click', function () { setDirty(false); showToast('设置已保存'); }); - settingsDiscard.addEventListener('click', function () { setDirty(false); showToast('已放弃未保存的更改'); }); + + /* ---------- ⑤ 生成网关来源(T-677) ---------- + savedSource 是已落盘的来源;pendingSource 只在点「保存设置」后才生效。 + ②的余额文案跟随 savedSource,不跟随未保存的选择。 */ + var savedSource = 'cmhub'; + var pendingSource = 'cmhub'; + var sourceRadios = Array.prototype.slice.call(document.querySelectorAll('input[name="gateway-source"]')); + var generateBalance = document.getElementById('generate-balance'); + var generateScopeText = document.getElementById('generate-scope-text'); + + function renderSourcePanels(source) { + document.querySelectorAll('[data-gateway-panel]').forEach(function (panel) { + panel.hidden = panel.dataset.gatewayPanel !== source; + }); + document.querySelectorAll('#gateway-source label').forEach(function (label) { + label.classList.toggle('is-checked', label.dataset.source === source); + }); + } + + /* 已保存来源决定②的点数口径与⑥的可用性。 + 保存后立即刷新,不需要重启程序,也不等待用户重新进入⑥。 */ + function renderSavedSource() { + var custom = savedSource === 'direct'; + + if (custom) { + generateBalance.className = 'status-chip chip-caution'; + generateBalance.textContent = '自定义网关(不计点数,费用由服务商收取)'; + generateScopeText.textContent = '通过自定义网关生成新标题与新封面,费用由服务商收取'; + } else { + generateBalance.className = 'status-chip chip-success'; + generateBalance.textContent = '默认网关余额:1,280 点'; + generateScopeText.textContent = '通过默认网关生成新标题与新封面,会消耗点数'; + } + + document.getElementById('titlebar-gateway').textContent = custom ? '自定义网关 已配置' : '默认网关 已连接'; + + /* ⑥:拦截新建与新提交,但保留已扣点任务的取回入口 */ + document.querySelectorAll('[data-suite-gated]').forEach(function (button) { + button.disabled = custom; + button.title = custom ? '商品套图仅支持默认网关,请到⑤把生成来源切回默认网关' : ''; + }); + document.getElementById('suite-gateway-bar').classList.toggle('show', custom); + } + + sourceRadios.forEach(function (radio) { + radio.addEventListener('change', function () { + pendingSource = radio.value; + renderSourcePanels(pendingSource); + /* dirty 由 settingsForm 的 change 监听统一标记,这里不单独清除, + 避免把同页其他字段的未保存更改误判为已恢复 */ + }); + radio.addEventListener('focus', function () { + radio.closest('label').classList.add('is-focused'); + }); + radio.addEventListener('blur', function () { + radio.closest('label').classList.remove('is-focused'); + }); + }); + + /* 模型 CRUD 立即写入,与来源的待保存语义区分开 */ + document.querySelectorAll('[data-model-crud]').forEach(function (button) { + button.addEventListener('click', function () { + showToast(button.dataset.modelCrud + '已立即写入配置,不需要点「保存设置」'); + }); + }); + + document.querySelectorAll('#model-list .model-item').forEach(function (item, index, items) { + item.addEventListener('click', function () { + Array.prototype.slice.call(items).forEach(function (other) { + other.setAttribute('aria-current', other === item ? 'true' : 'false'); + other.setAttribute('aria-selected', other === item ? 'true' : 'false'); + }); + }); + }); + + var testDefault = document.getElementById('test-default-gateway'); + if (testDefault) { + testDefault.addEventListener('click', function () { + var result = document.getElementById('default-gateway-result'); + result.textContent = '连接中…'; + testDefault.disabled = true; + window.setTimeout(function () { + result.textContent = '连接成功 · 余额 1,280 点'; + testDefault.disabled = false; + }, 900); + }); + } + + var testCustom = document.getElementById('test-custom-model'); + if (testCustom) { + testCustom.addEventListener('click', function () { + var result = document.getElementById('custom-model-result'); + result.textContent = '连接中…'; + testCustom.disabled = true; + window.setTimeout(function () { + result.textContent = '连接成功 · 已返回结果'; + testCustom.disabled = false; + }, 900); + }); + } + + function saveSettings() { + var switched = pendingSource !== savedSource; + savedSource = pendingSource; + setDirty(false); + renderSavedSource(); + showToast(switched + ? (savedSource === 'direct' + ? '设置已保存:生成来源已切换为自定义网关,商品套图已停用' + : '设置已保存:生成来源已切换为默认网关') + : '设置已保存'); + } + + /* 放弃更改只恢复来源和普通字段,不回滚已经立即保存的模型 CRUD */ + function discardSettings() { + pendingSource = savedSource; + sourceRadios.forEach(function (radio) { radio.checked = radio.value === savedSource; }); + renderSourcePanels(savedSource); + setDirty(false); + showToast('已恢复未保存的更改;已单独保存的模型不受影响'); + } + + settingsSave.addEventListener('click', saveSettings); + settingsDiscard.addEventListener('click', discardSettings); + + renderSourcePanels(savedSource); + renderSavedSource(); document.querySelectorAll('[data-unsaved]').forEach(function (button) { button.addEventListener('click', function () { button.closest('dialog').close(); - if (button.dataset.unsaved === 'save') { setDirty(false); showToast('设置已保存'); } - else { setDirty(false); showToast('已放弃未保存的更改'); } + if (button.dataset.unsaved === 'save') { saveSettings(); } else { discardSettings(); } }); });