feat(ai-assistant): chat 浮窗接入全局模态栈支持 ESC/滑动返回关闭

- modal.vue: chat 模式新增空助理 Modal(mask=false 不挡背后操作),
  进入 ViewUI 模态栈,由 removeLast() 统一管理 ESC/滑动返回/返回键/Electron 关窗
- index.vue: 移除 onInputKeydown 内重复的 chat ESC 处理,改由全局栈统一处理
- modal.vue: 捕获阶段抢先拦截 ESC,chat 全屏时退全屏而非关闭栈顶 Modal
  (AI 浮窗 z-index 恒最高但未必是栈顶,故不能依赖 ViewUI 冒泡 ESC)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
kuaifan 2026-06-18 10:50:18 +00:00
parent 7844f5500b
commit 7453b79c8d
2 changed files with 50 additions and 5 deletions

View File

@ -703,10 +703,6 @@ export default {
this.onSubmit();
return;
}
if (e.key === 'Escape' && this.displayMode === 'chat') {
this.showModal = false;
return;
}
}
//
if (e.key === 'ArrowUp') {
@ -3416,6 +3412,15 @@ export default {
}
}
.ai-assistant-assist {
width: 0;
height: 0;
opacity: 0;
display: none;
visibility: hidden;
pointer-events: none;
}
.ai-assistant-modal {
--apply-reasoning-before-bg: #e1e1e1;
.ivu-modal {

View File

@ -44,6 +44,15 @@
</template>
</div>
</transition>
<!--窗口助理 Modal 进入全局模态栈 removeLast()ESC/滑动返回/返回键/Electron 关窗统一管理mask=false 不阻挡背后操作-->
<Modal
v-model="visible"
:mask="false"
:mask-closable="false"
:footer-hide="true"
:transition-names="['', '']"
:beforeClose="onAssistClose"
class-name="ai-assistant-assist"/>
</div>
<Modal
v-else
@ -220,9 +229,11 @@ export default {
mounted() {
this.loadSizeAndPosition();
document.addEventListener('keydown', this.onGlobalEscFullscreen, true);
},
beforeDestroy() {
document.removeEventListener('keydown', this.onGlobalEscFullscreen, true);
document.removeEventListener('mousemove', this.onDragMouseMove);
document.removeEventListener('mouseup', this.onDragMouseUp);
document.removeEventListener('mousemove', this.onResizeMouseMove);
@ -539,9 +550,38 @@ export default {
}
},
/**
* 全局 ESC 捕获仅在 chat 浮窗处于全屏时介入
* AI 浮窗 z-index 恒为最高但其助理 Modal 未必是模态栈顶modalIndex 最大
* 故不能依赖 ViewUI 冒泡 ESC这里在捕获阶段抢先拦截并退出全屏
*/
onGlobalEscFullscreen(e) {
if (e.key !== 'Escape' && e.keyCode !== 27) {
return;
}
if (this.displayMode === 'chat' && this.visible && this.isFullscreen) {
e.stopImmediatePropagation();
e.preventDefault();
this.isFullscreen = false;
}
},
/**
* 窗口助理被全局返回机制removeLast弹出时触发转而关闭 chat 浮窗
* 返回一个不 resolve Promise关闭由 visible 变为 false 后自动驱动与微应用助理一致
*/
onAssistClose() {
return new Promise(() => {
this.onClose()
});
},
/**
* 关闭直接关闭浮窗不区分显示模式由外部控制 visible 变为 false
*/
onClose() {
this.$emit('input', false);
}
},
}
};
</script>