优化: 界面交互完善与设置体验
- 审批卡尊重滚动意图,等长切换回底,排队超时按钮修活 - 带图编辑提示不静默丢,删除目标回写,切换文案消歧 - 会话键盘可达+搜索态重命名,筛选计数口径对齐 - 子任务提示正名,看板加载态 - 主题跟随系统,表单脏态拦截,密钥显隐留空提示
This commit is contained in:
@@ -65,6 +65,11 @@ const emit = defineEmits<{
|
||||
* 调 store.sendMessage 触发 AI 装流式。仅 fetch_url 工具会发此事件。
|
||||
*/
|
||||
'install-obscura': []
|
||||
/**
|
||||
* 审批卡到达但用户不在底部附近(上滚读历史中):不强拉滚动,
|
||||
* 由父(MessageList)出「有新审批」轻提示,尊重用户阅读位置。
|
||||
*/
|
||||
'pending-out-of-view': []
|
||||
}>()
|
||||
|
||||
// 根元素 ref(scrollToFirstPending 查 DOM 用)
|
||||
@@ -306,6 +311,28 @@ let _unlistenPending: UnlistenFn | null = null
|
||||
// 论证 workflow 回归中优:防卸载竞态——await listen 解析前组件已卸载(HMR/快速切会话)时,
|
||||
// onBeforeUnmount 跑到 _unlistenPending 仍 null 跳过 unlisten → 孤儿监听器泄漏。disposed 标志兜底。
|
||||
let _disposed = false
|
||||
|
||||
/** 距滚动容器底部 <150px 视为"在底部附近",审批卡到达才跟随滚动(宽于 useMessageScroll 的 80px 在底判定) */
|
||||
const PENDING_FOLLOW_PX = 150
|
||||
/** 轻提示去重阈值:审批卡短时间连发多条时 5s 内只提示一次 */
|
||||
const PENDING_HINT_INTERVAL_MS = 5000
|
||||
// 模块级(跨实例共享):ai-pending-arrived 广播所有 ToolCardList 实例都会收到,去重须超组件实例
|
||||
let _lastPendingHintTs = 0
|
||||
|
||||
/** 滚动容器(.ai-messages,MessageList 持有)是否在底部附近 */
|
||||
function isContainerNearBottom(el: Element): boolean {
|
||||
const he = el as HTMLElement
|
||||
return he.scrollHeight - he.scrollTop - he.clientHeight < PENDING_FOLLOW_PX
|
||||
}
|
||||
|
||||
/** 用户不在底部时的轻提示:不拉滚,经父转发 toast(5s 去重防连发刷屏) */
|
||||
function notifyPendingOutOfView(): void {
|
||||
const now = Date.now()
|
||||
if (now - _lastPendingHintTs < PENDING_HINT_INTERVAL_MS) return
|
||||
_lastPendingHintTs = now
|
||||
emit('pending-out-of-view')
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
const fn = await listen('ai-pending-arrived', () => {
|
||||
// BUG-260624-01 残留优化:本实例无 pending 卡时短路返回,避免大列表 N 个 ToolCardList 实例
|
||||
@@ -313,7 +340,17 @@ onMounted(async () => {
|
||||
// 内 querySelector 返 null no-op 天然过滤(功能正确),此处显式 props 过滤把无 pending 实例挡在
|
||||
// 进入函数前。含 pending 的实例再走 nextTick + scrollToFirstPending(展开折叠组 + scroll)。
|
||||
if (!props.toolCalls.some(tc => tc.status === 'pending_approval')) return
|
||||
nextTick(() => scrollToFirstPending())
|
||||
nextTick(() => {
|
||||
// UX 走查-对话域 B1:尊重用户滚动意图。nextTick 等审批卡渲染完再测距底距离:
|
||||
// 在底部附近(含本就贴底)才跟随滚到审批卡;用户上滚读历史时不强拉,改轻提示。
|
||||
// 容器找不到(极端:分离窗口 DOM 层级变化)按可滚处理,保留原展开+滚动兜底。
|
||||
const container = rootEl.value?.closest('.ai-messages')
|
||||
if (!container || isContainerNearBottom(container)) {
|
||||
scrollToFirstPending()
|
||||
} else {
|
||||
notifyPendingOutOfView()
|
||||
}
|
||||
})
|
||||
})
|
||||
// 解析时若已卸载(HMR/极速 mount/unmount),立即 unlisten 刚拿到的句柄,防孤儿监听器。
|
||||
if (_disposed) { fn(); return }
|
||||
|
||||
Reference in New Issue
Block a user