fix(web): 手机端文件预览改悬浮卡片——四边留边距、不压输入区(bump 0.58.54)

移动端预览弹框原为全屏贴边(100vw×100dvh、直角),观感差且糊在消息
输入框上。≤640px 下改为:遮罩层四边 10px 呼吸边距,底部在
--preview-bottom-inset(chat-form 让位)之上再加 10px;卡片尺寸改
100%(相对遮罩内容区,弃 100dvh,旧 WebView 兼容更稳),恢复默认圆角。
输入区仍由 body.fp-open #chat-form z-index 抬升保持可见可用;桌面端不动。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-07-21 15:20:08 +08:00
parent c1508d0df0
commit 2e3a4db4e0
4 changed files with 15 additions and 5 deletions

View File

@ -5,6 +5,10 @@
> 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。 > 所以不是每个版本号都有条目。条目格式 `## <版本> — <日期>`,新条目加在最上面。
> 工程口径的完整记录见 `PROGRESS.md` / git log。 > 工程口径的完整记录见 `PROGRESS.md` / git log。
## 0.58.54 — 2026-07-21
- 手机上打开文件预览的体验优化:预览窗口不再全屏贴边糊满整个屏幕,改为四边留有边距的悬浮卡片,底部消息输入框也不再被挡住,可以边看文件边打字。
## 0.58.50 — 2026-07-21 ## 0.58.50 — 2026-07-21
- 对话过程中偶尔出现的黄色警告「工具调用参数损坏但已就地抢救」改为低调的灰色提示,措辞也更平和(「已自动修复工具调用参数」)。这种情况系统会自动修复,对回答质量和后续对话没有任何影响;黄色警告今后只用于真正需要留意的中断重试类情况。 - 对话过程中偶尔出现的黄色警告「工具调用参数损坏但已就地抢救」改为低调的灰色提示,措辞也更平和(「已自动修复工具调用参数」)。这种情况系统会自动修复,对回答质量和后续对话没有任何影响;黄色警告今后只用于真正需要留意的中断重试类情况。

View File

@ -23,6 +23,7 @@
### 2026-07 ### 2026-07
- **07-21 / 0.58.54 / 手机端文件预览改悬浮卡片(四边留边距、不压输入区)**:用户反馈移动端预览弹框全屏贴边(100vw×100dvh、直角)观感差且糊在消息输入框上。改 `dev.html` ≤640px 媒体查询:遮罩层 `padding:10px` 四边留呼吸边距、底部 `calc(--preview-bottom-inset + 10px)` 在 chat-form 让位之上再加间隙;卡片尺寸改 `100%`(相对遮罩内容区,弃 100dvh,旧 WebView 兼容更稳),恢复默认圆角。输入区仍走既有 `body.fp-open #chat-form` z-index 抬升保持可用;桌面端不动。
- **07-21 / 0.58.53 / App 套壳进入契约(embed app 变体 relogin_url)+ 对接文档**:移动 App 方案定型——原生壳(WebView)+ 原生登录页,登录走 platform 自有接口(`/api/login/token` → `/api/login/external-login`,已实测打通,后者服务端用 PLATFORM_KEY 换 zcbot JWT,user_id=platform user.uuid)。顶层 WebView 无父窗口,iframe 的 postMessage 协议失效(`zcbot-401` 经 `window.parent` 发不出去),故把企微免登模式泛化为 **app 变体**:`?embed=1&relogin_url=<绝对地址>#token=..&user_id=..` —— fragment 注入(读完即清,同 wecom)+ 401/logout 时 `location.replace(relogin_url)`(原生壳拦自定义 scheme 如 `zcbotapp://relogin` → 静默换新 token 重进;H5 登录页同契约)。改动:`state.js` 加 `EMBED_RELOGIN_URL` 解析+消毒(必须带 scheme 的绝对地址,拦 `javascript:`/`data:` 等可执行 scheme——该值喂 `location.replace`,不消毒是 XSS 口子);`embed.js` 抽共用 `readFragmentToken`/`gotoInitialTask`,加 `embedAppInit`/`embedAppRelogin`;`auth.js` logout 分支序 wecom→app→iframe。新增 `APP.md`(进入契约 + platform 登录链路实测 + 原生壳杂活清单 + H5 备选),`EMBED.md` 精简 243→约 120 行。ESM 语法检查过,浏览器级实测待跑(逻辑与线上企微免登同构)。顺带:实测发现 platform `/api/login/token` 响应把 `hashed_password` 下发到客户端,修复建议已写进 APP.md §5 转交对方。 - **07-21 / 0.58.53 / App 套壳进入契约(embed app 变体 relogin_url)+ 对接文档**:移动 App 方案定型——原生壳(WebView)+ 原生登录页,登录走 platform 自有接口(`/api/login/token` → `/api/login/external-login`,已实测打通,后者服务端用 PLATFORM_KEY 换 zcbot JWT,user_id=platform user.uuid)。顶层 WebView 无父窗口,iframe 的 postMessage 协议失效(`zcbot-401` 经 `window.parent` 发不出去),故把企微免登模式泛化为 **app 变体**:`?embed=1&relogin_url=<绝对地址>#token=..&user_id=..` —— fragment 注入(读完即清,同 wecom)+ 401/logout 时 `location.replace(relogin_url)`(原生壳拦自定义 scheme 如 `zcbotapp://relogin` → 静默换新 token 重进;H5 登录页同契约)。改动:`state.js` 加 `EMBED_RELOGIN_URL` 解析+消毒(必须带 scheme 的绝对地址,拦 `javascript:`/`data:` 等可执行 scheme——该值喂 `location.replace`,不消毒是 XSS 口子);`embed.js` 抽共用 `readFragmentToken`/`gotoInitialTask`,加 `embedAppInit`/`embedAppRelogin`;`auth.js` logout 分支序 wecom→app→iframe。新增 `APP.md`(进入契约 + platform 登录链路实测 + 原生壳杂活清单 + H5 备选),`EMBED.md` 精简 243→约 120 行。ESM 语法检查过,浏览器级实测待跑(逻辑与线上企微免登同构)。顺带:实测发现 platform `/api/login/token` 响应把 `hashed_password` 下发到客户端,修复建议已写进 APP.md §5 转交对方。
- **07-21 / 0.58.52 / 窗口体量估算实测校准(50%压缩/85%折叠/前端占用环共用)**:diag 复盘窗口约束现状(`scripts/diag_context_pressure.py` 留仓):机制有效(折叠上线后唯一越线 task 9a863424 下个 run 起点即回落 400k→137k)、零撞硬上限(6 条终态错误无一 context 超限),但量出静态 `CHARS_PER_TOKEN=2.5` 对中文密集窗口**低估近一倍**——名义 85% 折叠线实际 ~155% reliable 才触发(该 task 实测 40.7 万 tokens);代码密集反向虚高(fe2d8b73 估 1.2M 实际 616k)。**修(信号校准,不加新机制)**:`context.py` 加 `estimate_window_tokens`(provider 实报 tokens_in/out 覆盖窗口主体,仅实测点后尾巴按 2.5 估)+ `calibrated_chars_per_token`(比值夹 [1.0,4.0] 带宽);`Session.last_measured_usage()` 从 messages 表取窗口内最后一条实报 usage(best-effort 绝不抛,idx→内存 pos 映射校验 role);`maybe_fold` 触发判定换 token 实测口径;loop 的压缩门槛与 `context_limit_chars`(前端环)用校准比值,每轮成功调用后以 (sent_chars/prompt_tokens) 刷新。已知残余:折叠后 run 若在首次 chat 完成前崩,下个 run 起点读到旧实测会多折一次(后果=摘要偏保守,原文全在 DB,不为此加持久化状态)。run 中途折叠/超限自愈按 §5 无信号不实施继续搁置。真实生产 task 验证映射与校准(9a863424 drift 0.95x、fe2d8b73 0.51x、74696048 0.86x),286 测试全绿。 - **07-21 / 0.58.52 / 窗口体量估算实测校准(50%压缩/85%折叠/前端占用环共用)**:diag 复盘窗口约束现状(`scripts/diag_context_pressure.py` 留仓):机制有效(折叠上线后唯一越线 task 9a863424 下个 run 起点即回落 400k→137k)、零撞硬上限(6 条终态错误无一 context 超限),但量出静态 `CHARS_PER_TOKEN=2.5` 对中文密集窗口**低估近一倍**——名义 85% 折叠线实际 ~155% reliable 才触发(该 task 实测 40.7 万 tokens);代码密集反向虚高(fe2d8b73 估 1.2M 实际 616k)。**修(信号校准,不加新机制)**:`context.py` 加 `estimate_window_tokens`(provider 实报 tokens_in/out 覆盖窗口主体,仅实测点后尾巴按 2.5 估)+ `calibrated_chars_per_token`(比值夹 [1.0,4.0] 带宽);`Session.last_measured_usage()` 从 messages 表取窗口内最后一条实报 usage(best-effort 绝不抛,idx→内存 pos 映射校验 role);`maybe_fold` 触发判定换 token 实测口径;loop 的压缩门槛与 `context_limit_chars`(前端环)用校准比值,每轮成功调用后以 (sent_chars/prompt_tokens) 刷新。已知残余:折叠后 run 若在首次 chat 完成前崩,下个 run 起点读到旧实测会多折一次(后果=摘要偏保守,原文全在 DB,不为此加持久化状态)。run 中途折叠/超限自愈按 §5 无信号不实施继续搁置。真实生产 task 验证映射与校准(9a863424 drift 0.95x、fe2d8b73 0.51x、74696048 0.86x),286 测试全绿。
- **07-21 / 0.58.50 / salvage 成功提示降噪(黄→灰)**:用户反馈"工具调用参数损坏但已就地抢救"黄字吓人、问是否影响后续对话——核实**零影响**(salvage 只就地改写 arguments,当轮照常执行,对话历史与正常轮无异;warn 是纯前端 SSE 展示事件,不入 messages 不回灌 LLM,刷新即消失)。处置:不全静默(上游返脏数据的事实要可见、可与 `tool_salvaged` DB 留痕对上),改**分级降噪**——`loop.py` 该 emit 加 `level:"info"` + 措辞软化「已自动修复工具调用参数…继续执行」;`chat.js` warn 渲染按 level 分流,info 走灰色 muted 无 ⚠,黄色 ⚠ 只留给真打断本轮的路径(丢弃重试/熔断等)。 - **07-21 / 0.58.50 / salvage 成功提示降噪(黄→灰)**:用户反馈"工具调用参数损坏但已就地抢救"黄字吓人、问是否影响后续对话——核实**零影响**(salvage 只就地改写 arguments,当轮照常执行,对话历史与正常轮无异;warn 是纯前端 SSE 展示事件,不入 messages 不回灌 LLM,刷新即消失)。处置:不全静默(上游返脏数据的事实要可见、可与 `tool_salvaged` DB 留痕对上),改**分级降噪**——`loop.py` 该 emit 加 `level:"info"` + 措辞软化「已自动修复工具调用参数…继续执行」;`chat.js` warn 渲染按 level 分流,info 走灰色 muted 无 ⚠,黄色 ⚠ 只留给真打断本轮的路径(丢弃重试/熔断等)。

View File

@ -1,3 +1,3 @@
# zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。 # zcbot 版本号单一事实源:web/app.py 的 FastAPI version、/healthz 返回、前端展示都引这里。
# 改版本只动这一行。 # 改版本只动这一行。
__version__ = "0.58.53" __version__ = "0.58.54"

View File

@ -1355,11 +1355,16 @@
#admin-modal .card { width: min(92vw, 360px); } #admin-modal .card { width: min(92vw, 360px); }
#new-task-modal .card { width: min(92vw, 420px); } #new-task-modal .card { width: min(92vw, 420px); }
#src-picker-modal .card { width: min(96vw, 560px); max-height: 88dvh; } #src-picker-modal .card { width: min(96vw, 560px); max-height: 88dvh; }
/* 手机端预览:不做全屏贴边,四边留 10px 呼吸边距;底部在 chat-form
让位(--preview-bottom-inset)之上再加 10px,卡片始终悬停在输入区上方 */
#file-preview-modal {
padding: 10px;
padding-bottom: calc(var(--preview-bottom-inset, 0px) + 10px);
}
#file-preview-modal .card { #file-preview-modal .card {
width: 100vw; height: 100dvh; width: 100%; height: 100%;
max-width: 100vw; max-width: none;
max-height: calc(100dvh - var(--preview-bottom-inset, 0px)); max-height: 100%;
border-radius: 0;
} }
} }