Compare commits

...

3 Commits

Author SHA1 Message Date
1ca5e15f8e fix(ui): 末条消息复制/分支按钮加桥接热区,修复鼠标滑向按钮时 hover 断链收回
Co-authored-by: Astrion powered by DeepSeek-V4-Flash <astrion-agent@users.noreply.github.com>
2026-08-29 15:28:07 +08:00
bc8337ab09 feat(ui): 编辑摘要弹窗位置钉死、外部滚动与窗口缩放即关、hover 延迟 600ms 且打开后瞬间切换
Co-authored-by: Astrion powered by DeepSeek-V4-Flash <astrion-agent@users.noreply.github.com>
2026-08-29 15:26:39 +08:00
2a870c5a35 fix(multi-agent): 多智能体对话创建继承 work_mode,/new 切换后新建对话不再回落默认
Co-authored-by: Astrion powered by DeepSeek-V4-Flash <astrion-agent@users.noreply.github.com>
2026-08-29 15:26:39 +08:00
3 changed files with 72 additions and 12 deletions

View File

@ -354,6 +354,18 @@ def create_multi_agent_conversation():
default_permission_mode = (prefs or {}).get("default_permission_mode")
if default_permission_mode not in ("readonly", "approval", "auto_approval", "unrestricted"):
default_permission_mode = None
# 运行模式work_mode沿用 terminal 当前值(与正常创建路径一致,
# /new 页面切换后新对话继承plan 档不变量 ⇒ 权限必须只读,
# 同时记录进入前权限供离开 plan 恢复
safe_work_mode = getattr(terminal, "get_work_mode", lambda: "plan")()
if safe_work_mode not in ("plan", "ask", "execute"):
safe_work_mode = "plan"
safe_permission_mode = default_permission_mode or getattr(terminal, "get_permission_mode", lambda: "unrestricted")()
safe_pre_plan_permission = None
if safe_work_mode == "plan":
if safe_permission_mode != "readonly":
safe_pre_plan_permission = safe_permission_mode
safe_permission_mode = "readonly"
previous_cm_current = getattr(ctx_manager, "current_conversation_id", None)
@ -380,8 +392,10 @@ def create_multi_agent_conversation():
initial_messages=[],
model_key=(prefs or {}).get("default_model") or getattr(terminal, "model_key", None),
metadata_overrides={
"permission_mode": default_permission_mode or getattr(terminal, "get_permission_mode", lambda: "unrestricted")(),
"permission_mode": safe_permission_mode,
"execution_mode": getattr(terminal, "get_execution_mode", lambda: "sandbox")(),
"work_mode": safe_work_mode,
"pre_plan_permission_mode": safe_pre_plan_permission,
"multi_agent_mode": True,
"reasoning_effort": ma_effort,
},

View File

@ -7,8 +7,12 @@
* assistant 消息末尾同一文件多次编辑只展示合并后的最终结果净变化
*
* 交互
* - 桌面端 hover 150ms 意图延迟打开居中浮窗离开行与浮窗后自动关闭
* - 桌面端 hover 600ms 意图延迟打开居中浮窗离开行与浮窗后自动关闭
* 弹窗已打开时鼠标移到其他行瞬间切换内容不再等延迟
* - 点击行钉住弹窗带遮罩 + 关闭按钮移动端无 hover点击为唯一入口
* - 弹窗位置/高度在展开瞬间一次性计算并钉死之后不再重算
* - 外部滚动 / 窗口缩放直接关闭弹窗钉住弹窗内部滚动放行可滚动查看长 diff
* hover 弹窗内部滚动同样关闭
* - Esc 关闭
*/
import { computed, onBeforeUnmount, ref, watch } from 'vue';
@ -132,9 +136,25 @@ function computePanelStyle() {
}
}
function onWindowReposition() {
// / open
// - /
// - diff hover
// - /
let suppressOpenUntil = 0;
function onScrollCapture(e: Event) {
if (!activePath.value) return;
computePanelStyle();
const target = e.target as Element | null;
const isInsidePanel = target instanceof Element && !!target.closest('.es-modal');
if (isInsidePanel && pinned.value) return;
suppressOpenUntil = Date.now() + 250;
close();
}
function onResizeClose() {
if (!activePath.value) return;
suppressOpenUntil = Date.now() + 250;
close();
}
function clearOpenTimer() {
@ -160,9 +180,18 @@ function open(path: string, pin: boolean, rowEl: HTMLElement | null = null) {
computePanelStyle();
}
// hover
const HOVER_OPEN_DELAY = 600;
function scheduleOpen(path: string, rowEl: HTMLElement | null) {
clearOpenTimer();
openTimer = setTimeout(() => open(path, false, rowEl), 150);
if (Date.now() < suppressOpenUntil) return;
if (activePath.value) {
// +
open(path, false, rowEl);
return;
}
openTimer = setTimeout(() => open(path, false, rowEl), HOVER_OPEN_DELAY);
}
function scheduleClose() {
@ -215,13 +244,14 @@ function onKeydown(e: KeyboardEvent) {
watch(activePath, (v) => {
if (v) {
window.addEventListener('keydown', onKeydown);
window.addEventListener('resize', onWindowReposition);
//
window.addEventListener('scroll', onWindowReposition, true);
//
window.addEventListener('resize', onResizeClose);
//
window.addEventListener('scroll', onScrollCapture, true);
} else {
window.removeEventListener('keydown', onKeydown);
window.removeEventListener('resize', onWindowReposition);
window.removeEventListener('scroll', onWindowReposition, true);
window.removeEventListener('resize', onResizeClose);
window.removeEventListener('scroll', onScrollCapture, true);
}
});
@ -229,8 +259,8 @@ onBeforeUnmount(() => {
clearOpenTimer();
clearCloseTimer();
window.removeEventListener('keydown', onKeydown);
window.removeEventListener('resize', onWindowReposition);
window.removeEventListener('scroll', onWindowReposition, true);
window.removeEventListener('resize', onResizeClose);
window.removeEventListener('scroll', onScrollCapture, true);
});
// ---------------- diff ----------------

View File

@ -869,6 +869,22 @@
z-index: 1;
}
/* 透明桥接热区按钮被绝对定位在容器外与气泡之间有 4px 间隙
鼠标从气泡滑向按钮会经过间隙导致 :hover 中断按钮收回
用伪元素覆盖间隙 hover 从气泡平滑转移到按钮仅命中区域无视觉变化 */
.message-block--last
.user-message:not(.user-message--compact):not(.user-message--brief):not(
.user-message--multi-agent
)
.user-bubble-actions::before {
content: '';
position: absolute;
left: -12px;
right: -12px;
top: -4px;
height: 4px;
}
.message-block--last .assistant-message .text-output {
margin-top: 0;
margin-bottom: 0;