fix(views): 修复独立页切换时弹窗残留问题

- 独立整页固定使用普通 div 容器,取消动态切换 el-dialog 避免切换时弹窗 DOM 残留
- 删除相关 dialogVisible、dialogTitle、页脚弹窗动态分支代码以简化逻辑
- watch $route 调整,优化独立页初始化流程,避免不必要的关闭弹窗操作
- 新增 closeInnerDialogs 方法,页面卸载或 keep-alive deactivate 时关闭所有二级弹窗
- 对 loading-manage 与 project-apply 两个模块同步改造,统一处理弹窗状态和容器渲染
- 解决 keep-alive 缓存导致旧弹窗一直挂载在 body 上的问题,改善用户切换体验
This commit is contained in:
2026-09-18 10:17:48 +08:00
parent 5bb072223f
commit b4e12a671f
4 changed files with 119 additions and 170 deletions
+27 -63
View File
@@ -140,14 +140,15 @@
@load="onLoad(page, query)"
/>
<component
:is="projectFormContainer"
v-if="projectBox"
v-bind="projectFormContainerProps"
@update:model-value="projectBox = $event"
@closed="resetProjectDialog"
>
<div v-if="isProjectFormPage" class="archive-page-form__title">
<!--
项目新增/编辑/查看/变更/补录全部是独立整页(openProjectDialog 一律 push /business/project-apply/form),
这里固定渲染普通容器,不再按 $route 在 div 与 el-dialog 之间切换。
原因:标签页 keep-alive 会缓存本页实例,若容器在离开本页后又变回 el-dialog,
缓存实例会把 append-to-body 的弹窗渲染进 body 并永久停留(Vue 的 KeepAlive.deactivate →
Teleport.move 不会搬走 append-to-body 的弹窗 DOM),表现为“点左侧菜单又弹出新增项目管理弹窗”。
-->
<div v-if="isProjectFormPage" class="project-apply-page-form">
<div class="archive-page-form__title">
{{ projectDialogTitle }}
</div>
<el-form
@@ -788,8 +789,7 @@
:class="{ 'project-apply-dialog__footer--change': isChangeDialog }"
>
<template v-if="isChangeDialog">
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</el-button>
<el-button @click="closeProjectForm">取消</el-button>
<el-button type="primary" plain :loading="submitLoading" @click="saveChangeProject">
保存
</el-button>
@@ -798,8 +798,7 @@
</el-button>
</template>
<template v-else>
<el-button v-if="!isProjectFormPage" @click="handleCancelProject">取消</el-button>
<el-button v-if="isProjectFormPage" @click="closeProjectForm">取消</el-button>
<el-button @click="closeProjectForm">取消</el-button>
<el-button
v-if="!dialogReadonly"
type="primary"
@@ -819,7 +818,7 @@
</el-button>
</template>
</div>
</component>
</div>
<el-dialog
v-model="attachmentDocumentPreviewVisible"
@@ -1116,7 +1115,6 @@ export default {
total: 0,
},
selectionList: [],
projectBox: false,
dialogType: 'add',
dialogReadonly: false,
submitLoading: false,
@@ -1310,21 +1308,6 @@ export default {
isProjectFormPage() {
return this.$route.path === '/business/project-apply/form';
},
projectFormContainer() {
return this.isProjectFormPage ? 'div' : 'el-dialog';
},
projectFormContainerProps() {
if (this.isProjectFormPage) return { class: 'project-apply-page-form' };
return {
modelValue: this.projectBox,
title: this.projectDialogTitle,
appendToBody: true,
destroyOnClose: true,
width: '1440px',
top: '4vh',
class: 'project-apply-dialog',
};
},
isBasicInfoReadonly() {
return this.dialogReadonly || this.isChangeDialog;
},
@@ -1363,6 +1346,12 @@ export default {
this.openProjectFormPage();
}
},
deactivated() {
this.closeInnerDialogs();
},
beforeUnmount() {
this.closeInnerDialogs();
},
methods: {
buildTableOption() {
return {
@@ -1390,7 +1379,6 @@ export default {
const id = this.$route.query.id;
this.dialogType = type;
this.dialogReadonly = type === 'view';
this.projectBox = true;
if (['add', 'majorSupplement'].includes(type)) {
this.applyProjectDetail({
...emptyForm(),
@@ -1411,11 +1399,15 @@ export default {
});
},
closeProjectForm() {
if (this.isProjectFormPage) {
this.$router.push('/business/project-apply');
} else {
this.projectBox = false;
}
this.$router.push('/business/project-apply');
},
// 页面被 keep-alive 缓存/卸载时,关闭本页所有 append-to-body 的二级弹窗。
// 若不关闭,Teleport 出去的弹窗 DOM 在实例失活时不会被搬离 body,会残留盖在后续页面上。
closeInnerDialogs() {
this.changeRecordDetailVisible = false;
this.attachmentDocumentPreviewVisible = false;
this.attachmentImagePreviewVisible = false;
this.userBox = false;
},
statusValue(row) {
return row[this.config.statusProp || 'status'];
@@ -1634,17 +1626,6 @@ export default {
else if (type === 'change') query.name = '项目变更';
this.$router.push({ path: '/business/project-apply/form', query });
},
resetProjectDialog() {
this.$refs.projectForm?.clearValidate();
this.form = emptyForm();
this.customerRows = [];
this.carrierRows = [];
this.attachmentRows = [];
this.selectedAttachmentRows = [];
this.changeRows = [];
this.selectedCustomerId = [];
this.selectedCarrierIds = [];
},
applyProjectDetail(row) {
const displayRow = {
...row,
@@ -1767,23 +1748,6 @@ export default {
this.submitLoading = false;
});
},
handleCancelProject() {
if (this.isProjectFormPage) {
this.closeProjectForm();
return;
}
if (!['add', 'majorSupplement', 'change'].includes(this.dialogType)) {
this.closeProjectForm();
return;
}
this.$confirm('确认后直接关闭弹窗,列表无数据变更,是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
this.closeProjectForm();
});
},
saveChangeProject() {
this.submitChangeForm(false);
},