fix(web): 导出按钮简写 + 任务菜单加清空 + 修移动端 task 滚动 + admin 自适应 + bump 0.12.1

- 顶栏「导出对话记录」→「导出对话」,与「清空对话」对齐(dev.html + chat.js 菜单 export 项)
- 任务菜单(每行 ⋯)新增「清空对话」,复用 clearMessages;dropdown 加 .act-clear 紫色
- 修移动端 task 列表无法滚动:手机断点 #pane-left 误用 display:block 致 #task-scroll
  flex:1 失效被 overflow:hidden 截断;改 display:flex 恢复滚动
- admin 移动端自适应:header 紧凑化 + .card-head/.ctrl 允许换行,避免窄屏横向溢出

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
caoqianming 2026-06-13 12:41:53 +08:00
parent c870b10368
commit 1f57bbd201
5 changed files with 24 additions and 4 deletions

View File

@ -21,6 +21,14 @@
## 已完成关键能力 ## 已完成关键能力
### 2026-06-13 / 前端小修:导出按钮简写 + 任务菜单加清空 + 移动端 task 可滚 + admin 自适应
- **顶栏「导出对话记录」→「导出对话」**:与「清空对话」对齐(`dev.html` 按钮 + `chat.js` 任务菜单 export 项同步)。
- **任务菜单加「清空对话」项**:`chat.js::taskMenuItems` 新增一条,复用已有 `clearMessages`;disabled 条件 `!hasMsg` 与 export 项一致;dropdown 新增 `.dd-item.act-clear` 紫色(与顶栏清空按钮 hover 同色)。
- **修移动端 task 列表无法滚动**:手机断点把 `#pane-left` 设成 `display:block`,但 `#task-scroll``flex:1` 撑高才能滚 —— 父级非 flex 时 flex:1 失效,列表被 `overflow:hidden` 截断不能滚。改 `body.mv-left #pane-left { display:flex }`(`flex-direction:column` 由默认规则给),恢复滚动。
- **admin 移动端自适应增强**:`admin.html` 的 `@media(max-width:640px)` 补 header 紧凑化(缩 padding/字号、gen-at 时间戳截断)+ `.card-head`/`.ctrl` 允许换行(标题长 + 下拉不再撑出横向溢出)。
- bump 0.12.0 → 0.12.1(patch:bugfix + 样式)。
### 2026-06-12 / 双层记忆升级为 agent 自管(写入路径) ### 2026-06-12 / 双层记忆升级为 agent 自管(写入路径)
- **背景**:`.memory/`(core.md + extended/)存储原语已在,但纯手工维护 —— 系统不往里写,用户也不会主动整理 → 记忆形同虚设。**这轮补「写入」与「召回」两条路,不碰存储/DB,不破坏存量 `.memory/` 数据。** - **背景**:`.memory/`(core.md + extended/)存储原语已在,但纯手工维护 —— 系统不往里写,用户也不会主动整理 → 记忆形同虚设。**这轮补「写入」与「召回」两条路,不碰存储/DB,不破坏存量 `.memory/` 数据。**

View File

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

View File

@ -114,6 +114,15 @@
main { padding: 10px; } main { padding: 10px; }
.grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); } .grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
.stat .v { font-size: 18px; } .stat .v { font-size: 18px; }
/* header 紧凑化:缩 padding/gap、字号,gen-at 时间戳截断不撑宽 */
header { padding: 8px 10px; gap: 8px; }
header .title { font-size: 14px; }
header .meta { font-size: 11px; max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
header a, header button { padding: 4px 8px; }
/* card-head 允许换行,标题长 + 下拉不再撑出横向溢出 */
.card-head { flex-wrap: wrap; }
.ctrl { flex-wrap: wrap; }
.ctrl select { min-width: 0; }
/* 窄屏:目录变顶部横向 chip 条 */ /* 窄屏:目录变顶部横向 chip 条 */
#layout { grid-template-columns: 1fr; gap: 10px; } #layout { grid-template-columns: 1fr; gap: 10px; }
#toc { #toc {

View File

@ -451,6 +451,7 @@
.dd-item.act-complete, .dd-item.act-download { color: var(--c-green); } .dd-item.act-complete, .dd-item.act-download { color: var(--c-green); }
.dd-item.act-abandon { color: var(--c-orange); } .dd-item.act-abandon { color: var(--c-orange); }
.dd-item.act-export, .dd-item.act-rename { color: var(--c-blue); } .dd-item.act-export, .dd-item.act-rename { color: var(--c-blue); }
.dd-item.act-clear { color: var(--c-purple); }
.dd-item.act-delete { color: var(--accent); } .dd-item.act-delete { color: var(--accent); }
/* ───── task list ───── */ /* ───── task list ───── */
@ -919,7 +920,7 @@
#pane-left, #pane-mid, #pane-right { #pane-left, #pane-mid, #pane-right {
grid-area: main; border-right: none; display: none; grid-area: main; border-right: none; display: none;
} }
body.mv-left #pane-left { display: block; } body.mv-left #pane-left { display: flex; } /* flex(非 block):配合默认 flex-direction:column 让 #task-scroll flex:1 撑高可滚 */
body.mv-mid #pane-mid { display: flex; } body.mv-mid #pane-mid { display: flex; }
body.mv-right #pane-right { display: flex; } body.mv-right #pane-right { display: flex; }
/* 折叠按钮在手机不可见 */ /* 折叠按钮在手机不可见 */
@ -1240,7 +1241,7 @@
<div class="pane-head"> <div class="pane-head">
<span class="label">对话</span> <span class="label">对话</span>
<span class="spacer"></span> <span class="spacer"></span>
<button id="btn-export" class="small" disabled>导出对话记录</button> <button id="btn-export" class="small" disabled>导出对话</button>
<button id="btn-clear-msgs" class="small" disabled title="清空当前任务的对话历史(messages + token 累计归零),工作目录文件保留">清空对话</button> <button id="btn-clear-msgs" class="small" disabled title="清空当前任务的对话历史(messages + token 累计归零),工作目录文件保留">清空对话</button>
<button id="btn-done" class="small" disabled>完成</button> <button id="btn-done" class="small" disabled>完成</button>
<button id="btn-abandon" class="small danger" disabled>废弃</button> <button id="btn-abandon" class="small danger" disabled>废弃</button>

View File

@ -179,8 +179,10 @@ function taskMenuItems(t) {
onclick: () => setTaskStatus(t.task_id, "completed", t.name || "(未命名)") }, onclick: () => setTaskStatus(t.task_id, "completed", t.name || "(未命名)") },
{ act: "abandon", label: "废弃", cls: "act-abandon", disabled: !isActive, { act: "abandon", label: "废弃", cls: "act-abandon", disabled: !isActive,
onclick: () => setTaskStatus(t.task_id, "abandoned", t.name || "(未命名)") }, onclick: () => setTaskStatus(t.task_id, "abandoned", t.name || "(未命名)") },
{ act: "export", label: "导出对话记录", cls: "act-export", disabled: !hasMsg, { act: "export", label: "导出对话", cls: "act-export", disabled: !hasMsg,
onclick: () => exportTask(t.task_id) }, onclick: () => exportTask(t.task_id) },
{ act: "clear", label: "清空对话", cls: "act-clear", disabled: !hasMsg,
onclick: () => clearMessages(t.task_id, t.name || "(未命名)", t.n_messages || 0) },
{ act: "delete", label: "删除", cls: "act-delete", { act: "delete", label: "删除", cls: "act-delete",
onclick: () => deleteTask(t.task_id, t.name || "(未命名)", t.n_messages || 0) }, onclick: () => deleteTask(t.task_id, t.name || "(未命名)", t.n_messages || 0) },
]; ];