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
+24
View File
@@ -0,0 +1,24 @@
# 2026-09-18
## 修复:改成独立整页后点左侧菜单仍弹出旧弹窗(loading-manage / project-apply
**现象**:配载单管理、项目管理已改为「新增/编辑/详情走独立整页」,但从独立页返回或直接点左侧菜单时,页面上仍会盖出一个老的 `el-dialog`(新增项目管理 / 配载单)。
**根因**(已读 Vue runtime-core 源码确认):
- `src/router/tab.js``tabKey`(默认 fullPath)为每个标签建一个具名 wrapper 组件放进 `wrapperMap``src/page/index/layout.vue``<keep-alive :include="$store.getters.tagsKeep">` 缓存 —— 每个标签页一个实例,全部缓存不销毁。
- 组件被 deactivate 后**仍会随 `$route`(全局响应式)重新渲染**;此时 `isStandalonePage` 变 false`<component :is="isStandalonePage ? 'div' : 'el-dialog'">` 由 div 翻回 `el-dialog`,而 `v-model``projectBox`/`dialogVisible`)仍是 true`append-to-body` 使弹窗 Teleport 到 body。
- `KeepAlive.deactivate``move(vnode, storageContainer, ..., moveType=OUT)`,但 `TeleportImpl.move``moveTeleport`)忽略传入的 moveType、一律按 REORDER 处理 → **teleport 出去的 DOM 不会被搬回 storage container**,永久残留在 `document.body` 上并显示出来。
**修法**(不回退 tab.js 的 `return wrapper` 提交 c1c4fa1,改修根因):
- 独立页容器固定为 `<div v-if="isXxxPage">`,不再按路由回退成 `el-dialog`
- 页内其它 `append-to-body` 二级弹窗加 `deactivated()` / `beforeUnmount()``closeInnerDialogs()` 把 v-model 置 false。
**改动文件**
- `src/views/business/loading-manage.vue`:容器改 `<div v-if="isStandalonePage">`;删 `dialogVisible``dialogTitle``resetLoadingDialog``clearLoadingDialog`、页脚弹窗分支(含「清空」);`watch.$route` 简化;新增 `closeInnerDialogs()`routeChange / commonAddress / candidateSearch+ `deactivated`/`beforeUnmount`
- `src/views/business/project-apply.vue`:容器改 `<div v-if="isProjectFormPage">`;删 `projectFormContainer`/`projectFormContainerProps``projectBox``resetProjectDialog``handleCancelProject``closeProjectForm` 简化为直接 push 列表;新增 `closeInnerDialogs()`changeRecordDetail / 附件文档预览 / 图片预览 / 选人)+ `deactivated`/`beforeUnmount`
**校验**dev server(2889) curl 两个 .vue 及其 scoped style 模块,均 HTTP 200500 才是编译失败)。`vite build` 因沙箱敏感内容保护会在 facelogin.vue 中断,未用。
**遗留同类风险(未改,已告知用户)**`business/components/waybill-manage-page.vue``detailContainer` 在 PageDetail / el-dialog 间切)、`settlement/components/{pre,formal}-settlement-editor.vue``transport-reconciliation-editor.vue``pageMode ? 'div':'el-dialog'`)、`business/components/waybill-import-dialog.vue``standalone`/`createPage`)。统一修法:容器类型在 `created()` 锁定,不随路由/prop 翻转。
**未提交**:上述改动 + 上一轮 loading-manage 独立页改造均未 commit。
+27 -26
View File
@@ -2,37 +2,38 @@
配套后端:`/Users/gxwebsoft/JAVA/tms-api`(不是 tms-erp-api-ws,后者功能滞后)。
## 页面结构:列表 + 独立表单页 + 独立详情页(同一组件分流)
- `src/router/views/index.js` 里三条静态/菜单路由指向同一个 .vue`/xxx`后端菜单)、`/xxx/form``/xxx/detail`form/detail 都是 `component: Layout` + 空 children`meta: { keepAlive: false }`detail 额外`activeMenu: '/xxx'`
- 组件内按 `$route.path` 分流(如 `isFormPage` / `isDetailPage` / `isListPage`,列表部分统一 `v-if="!isStandalonePage"` 隐藏搜索栏/工具栏/表格/分页
- 路由记录不同但组件相同 → Vue 复用实例,所以**必须**在 `watch: { $route(to, from) }` 里重新 init`mounted` 只覆盖直接打开/刷新」场景。切换详情与表单时不要只比 id,还要看当前 `dialogMode` 是否匹配
- 跳转`this.$router.push({ path: '/xxx/form', query: { mode, id, name: '新增xxx' } })`标签标题由 avue-router `query.name`关闭:`this.$router.$avueRouter?.closeTag?.()` + push 列表。
- 已按此模式:contract-manageform+detail)、waybill-manage、loading-manage(新增/编辑/重新派单/详情,2026-09-17 完成)
- 底栏文案:只读详情页用「关闭」;表单页沿用「关闭/暂存/确认」。
## 列表 + 独立表单页 + 独立详情页(同一组件分流)
- 路由`/xxx`(菜单)、`/xxx/form``/xxx/detail` 指向同一 .vueform/detail `component: Layout` + 空 children`meta:{keepAlive:false}`detail 带 `activeMenu:'/xxx'`
- 组件内按 `$route.path` 分流,列表部分统一 `v-if="!isStandalonePage"` 隐藏。
- 路由记录不同但组件相同 → 必须 `watch:{$route}` 里重新 init`mounted` 只覆盖直接打开/刷新。
- 跳转 `push({path:'/xxx/form',query:{mode,id,name:'新增xxx'}})`标签标题取 `query.name`
- 底栏:只读详情页「关闭」;表单页「关闭/暂存/确认」
## ⚠️ 独立页容器禁止用 `<component :is>` 在 div 与 el-dialog 间切换
- **现象**:改成独立整页后,点左侧菜单又弹出旧弹窗,且永久盖在页面上。
- **根因**`src/router/tab.js` 按 fullPath 建 wrapper 组件,`layout.vue``<keep-alive :include="tagsKeep">` 缓存,每个标签一个实例。实例被 deactivate 后**仍会随 `$route` 重新渲染**;此时 `:is` 由 div 变回 `el-dialog``v-model` 仍为 true`append-to-body` 的弹窗经 Teleport 渲染进 body——而 `KeepAlive.deactivate → Teleport.move` 只做 reorder**不会把 teleport 出去的 DOM 搬回 storage container**,于是弹窗永久残留。
- **正确写法**:独立页固定 `<div v-if="isXxxPage">` 普通容器,绝不按路由回退成 el-dialog;列表页分支另写或只保留弹窗一种形态。
- **兜底**:页面内其它 `append-to-body` 的二级弹窗,加 `deactivated(){closeInnerDialogs()}` + `beforeUnmount(){closeInnerDialogs()}` 把 v-model 置 false。
- 同类风险未修:`business/components/waybill-manage-page.vue``detailContainer` 在 PageDetail/el-dialog 间切)、`settlement/components/{pre,formal}-settlement-editor.vue``transport-reconciliation-editor.vue``pageMode ? 'div':'el-dialog'`)、`business/components/waybill-import-dialog.vue``standalone`/`createPage`)。修法同上:容器类型在 `created()` 锁定,不随路由/prop 翻转。
## 样式硬规则
-部操作栏:`display:flex; justify-content:flex-end;`**不写 gap**(间距 Element Plus 默认 `.el-button+.el-button{margin-left:12px}` 提供)。⚠️ 浮动底栏必须 `position:fixed`(祖先 overflow:hidden sticky 失效),配套 `:global(.avue--collapse .x){left:60px}``:global(.avue-layout--horizontal .x){left:0}``:global()` 要包住整个选择器。
- 按钮层级:次要 = 不写 type;中间步骤 = `type="primary" plain`;主操作 = `type="primary"`(禁绿色 success禁两个蓝实心)。顺序 `[辅助工具][取消][保存草稿][提交]`
- ⚠️ **`<style scoped lang="scss">` 顶层禁止 `//` 行注释**Vite5 + sass modern-compiler + scoped 会报 `Unexpected '/'.`,样式模块直接 HTTP 500(块内的 `//` 正常)。顶层统一用 `/* */`
- 独立页顶部标题用 `.archive-page-form__title`(全局:18px/600 + 4px 主色竖条),或 business-crud-page 的 `formPageTitle` prop
- 弹窗分组统一全局 `<section-card>`(白卡 + 4px 主色竖条);弹窗灰底 `#f5f6fa` 由全局 `.el-dialog__body` 提供
- 上传证件区:`width:100%; max-width:240px` + `.el-upload{height:151px}`,禁止写死 px
- 其他全站细则(表格线 #EFF1F7、偶数行 #FAFAFA、搜索栏 8px 行距 / label≥160px / `searchIndex:4`、操作列宽度与纯文字链接、表格内嵌控件全宽、`.el-tag.status-text` 文字化)见 `src/styles/element-ui.scss` 与 AGENTS.md 4.4。
- 底栏:`flex; justify-content:flex-end`**不写 gap**(间距 EP 默认 `.el-button+.el-button{margin-left:12px}`)。浮动底栏必须 `position:fixed`(祖先 overflow:hidden 使 sticky 失效)+ `:global(.avue--collapse .x){left:60px}``:global(.avue-layout--horizontal .x){left:0}``:global()` 要包住整个选择器。
- 按钮层级:次要=不写 type;中间步骤=`primary plain`;主操作=`primary`(禁绿色禁两个蓝实心)。顺序 `[辅助][取消][保存草稿][提交]`
- 独立页标题 `.archive-page-form__title`18px/600 + 4px 主色竖条);分组用全局 `<section-card>`;弹窗灰底 `#f5f6fa`
- 上传证件区:`width:100%; max-width:240px` + `.el-upload{height:151px}`,禁写死 px
- ⚠️ `<style scoped lang="scss">` **顶层禁 `//` 注释**Vite5+sass 报 `Unexpected '/'` → 样式模块 500),顶层用 `/* */`
- 其余全站细则见 `src/styles/element-ui.scss` 与 AGENTS.md 4.4
## 表单文案
- placeholder 只写 `请输入` / `请选择`,不带字段名;必须保留的例外`请输入或选择车辆`、日期区间 `起/止`、示例值(`如:京A12345`)。
- 校验 message 必须带字段名(`请选择准驾车型`)。
- Avue 配置化表单:option 各列加 `placeholder`;搜索栏可用 `withSearchPlaceholders([...])`
- 存量的独立页 `max-height:78vh` 内嵌滚动盒写法是历史遗留,新做页面应让内容随 `#avue-view`(自身 `overflow-y:auto`)自然滚动 + 固定底栏。
- placeholder 只写 `请输入`/`请选择`;例外保留`请输入或选择车辆`、日期区间 `起/止`、示例值(`如:京A12345`)。校验 message 必须带字段名。
## 复用与工具
- `business/components/business-crud-page.vue`option `crudOption` prop `cloneOption` 克隆;独立表单页走 `PageAvueForm`自定义详情弹窗 `detailButton + detailSections`
- SFC 自检:项目根目录写临时脚本用 `@vue/compiler-sfc` 的 parse + compileScript + compileTemplate(脚本必须放根目录,放 /tmp 找不到 node_modules
- 更快的改后自检(dev server 已在 2889 时):`curl "localhost:2889/src/xxx.vue"`(模板+脚本)与 `curl "localhost:2889/src/xxx.vue?vue&type=style&index=0&scoped=true&lang.scss"`(样式),HTTP 200 即编译通过、500 会返回带堆栈的错误页
- ⚠️ `vite build` 会在 `src/page/login/facelogin.vue` 处被 WorkBuddy 沙箱的敏感内容保护中断(环境问题,非代码问题),不能作为唯一校验手段
- dev`VITE_APP_API=/api`vite 代理 `172.16.203.228:8000`;改 .env / vite.config.mjs 须重启。
## 复用与自检
- `business/components/business-crud-page.vue`option 经 `cloneOption` 克隆;独立表单页走 `PageAvueForm`;详情弹窗 `detailButton + detailSections`
- 自检:dev(2889) 时 `curl "localhost:2889/src/xxx.vue"``curl "...?vue&type=style&index=0&scoped=true&lang.scss"`,200 通过、500 返回带堆栈错误页
- ⚠️ `vite build` 会在 `src/page/login/facelogin.vue` 被沙箱敏感内容保护中断(环境问题),不能作为唯一校验手段
- dev`VITE_APP_API=/api`,代理 `172.16.203.228:8000`
## 导出(后端 FastExcel
- 前端 `exportColumns` 后端未使用,导出列以 `XxxExportExcel.java` 为准。
- BladeX `BeanUtil`(继承 Spring BeanUtils)字段类型不兼容时**静默跳过**:实体 `Date createTime` Excel `LocalDateTime` 丢值,须 Service 手动 `DateUtil.fromDate(...)` 赋值(参考 Waybill / InsuranceRecord
- 排查导出文件用 Python `zipfile``xl/worksheets/sheet1.xml` 看有无 `<v>` 与 numFmt,无需 openpyxl
- BladeX `BeanUtil` 类型不兼容时静默跳过`Date createTime``LocalDateTime` 丢值,须 Service `DateUtil.fromDate(...)` 赋值。
- 排查导出文件用 Python `zipfile``xl/worksheets/sheet1.xml`
+26 -66
View File
@@ -376,27 +376,17 @@
/>
</div>
<component
:is="isStandalonePage ? 'div' : 'el-dialog'"
:model-value="isStandalonePage ? undefined : dialogVisible"
:title="isStandalonePage ? undefined : dialogTitle"
:append-to-body="isStandalonePage ? undefined : true"
:destroy-on-close="isStandalonePage ? undefined : true"
:width="isStandalonePage ? undefined : '96%'"
:top="isStandalonePage ? undefined : '3vh'"
:class="[
'loading-manage-dialog',
{ 'loading-manage-form-dialog': isStandalonePage },
{ 'loading-manage-form-page': isStandalonePage },
]"
:modal="isStandalonePage ? undefined : true"
:show-close="isStandalonePage ? undefined : true"
:close-on-click-modal="isStandalonePage ? undefined : true"
:close-on-press-escape="isStandalonePage ? undefined : true"
@update:model-value="value => !isStandalonePage && (dialogVisible = value)"
@closed="resetLoadingDialog"
<!--
配载单的新增/编辑/重新派单/详情全部是独立整页,这里固定渲染普通容器,不再按路由切换 el-dialog
原因:标签页 keep-alive 会把本页实例缓存下来,若容器随 $route 由 div 变回 el-dialog
被缓存的实例会在离开本页后渲染出 append-to-body 的弹窗并永久停留在 body 上(Vue 的
KeepAlive.deactivate → Teleport.move 不会搬走 append-to-body 的弹窗 DOM),表现为“点左侧菜单又弹出弹窗”。
-->
<div
v-if="isStandalonePage"
class="loading-manage-dialog loading-manage-form-dialog loading-manage-form-page"
>
<div v-if="isStandalonePage" class="archive-page-form__title">{{
<div class="archive-page-form__title">{{
isStandaloneDetailPage ? detailPageTitle : formPageTitle
}}</div>
<div v-loading="dialogLoading" class="loading-manage-dialog__body">
@@ -1231,27 +1221,12 @@
</el-form>
</div>
<div v-if="isStandalonePage" class="loading-manage-dialog__footer">
<template v-if="dialogReadonly">
<el-button @click="closeLoadingDialog">关闭</el-button>
</template>
<template v-else>
<el-button @click="closeLoadingDialog">关闭</el-button>
<el-button type="primary" plain :loading="dialogSaving === 'draft'" @click="saveDraft">
暂存
</el-button>
<el-button type="primary" :loading="dialogSaving === 'submit'" @click="submitLoading">
{{ dialogMode === 'reassign' ? '确认派单' : '确认' }}
</el-button>
</template>
</div>
<template v-if="!isStandalonePage" #footer>
<div class="loading-manage-dialog__footer">
<template v-if="dialogReadonly">
<el-button @click="closeLoadingDialog">关闭</el-button>
</template>
<template v-else>
<el-button @click="clearLoadingDialog">清空</el-button>
<el-button @click="closeLoadingDialog">关闭</el-button>
<el-button type="primary" plain :loading="dialogSaving === 'draft'" @click="saveDraft">
暂存
</el-button>
@@ -1260,8 +1235,7 @@
</el-button>
</template>
</div>
</template>
</component>
</div>
<el-dialog
v-model="routeChangeVisible"
title="变更运输路线"
@@ -1636,7 +1610,6 @@ export default {
searchExpanded: false,
searchForm: createSearchForm(),
selectionRows: [],
dialogVisible: false,
dialogMode: 'add',
dialogLoading: false,
dialogSaving: '',
@@ -1706,15 +1679,6 @@ export default {
if (!this.taskCarrierLoading && !this.taskCarrierOptions.length) return '暂无可用承运商合同';
return '请选择';
},
dialogTitle() {
const titleMap = {
add: '新建配载',
edit: '编辑配载单',
view: '配载单详情',
reassign: '重新派单',
};
return titleMap[this.dialogMode] || '配载管理';
},
detailStatusType() {
const typeMap = {
pending: 'success',
@@ -1785,9 +1749,16 @@ export default {
const detailId = this.$route.query.detailId;
if (detailId) this.gotoLoadingDetail({ id: detailId });
},
// 标签切走(实例被 keep-alive 缓存)或销毁时,先收起页内子弹窗
deactivated() {
this.closeInnerDialogs();
},
beforeUnmount() {
this.closeInnerDialogs();
},
watch: {
$route(to, from) {
if (this.isStandalonePage) {
if (!this.isStandalonePage) return;
this.syncStandaloneTagTitle();
if (this.isStandaloneDetailPage) {
// 记录变化或上一个页面不是详情态(例如从表单页/列表页进来)时重新拉取详情
@@ -1802,9 +1773,6 @@ export default {
) {
this.initStandaloneFormPage();
}
} else if (from?.query?.mode && this.dialogVisible) {
this.closeLoadingDialog();
}
},
'$route.query.detailId'(detailId) {
if (detailId) this.gotoLoadingDetail({ id: detailId });
@@ -2302,7 +2270,6 @@ export default {
return;
}
this.dialogMode = mode;
this.dialogVisible = true;
this.dialogLoading = true;
this.resetDialogData();
if (mode === 'add') this.candidateQuery.transportType = 'road';
@@ -2335,17 +2302,9 @@ export default {
}
},
closeLoadingDialog() {
if (this.isStandalonePage) {
if (!this.isStandalonePage) return;
this.$router.$avueRouter?.closeTag?.();
this.$router.push({ path: '/business/loading-manage', query: {} });
return;
}
this.dialogVisible = false;
},
resetLoadingDialog() {
this.resetDialogData();
this.dialogSaving = '';
this.dialogLoading = false;
},
resetDialogData() {
this.detailAmap?.destroy?.();
@@ -2367,10 +2326,11 @@ export default {
this.processProjectId = '';
this.processProjectOptions = [];
},
clearLoadingDialog() {
this.resetDialogData();
if (this.dialogMode === 'add') this.candidateQuery.transportType = 'road';
this.loadCandidateWaybills();
// 离开本页(标签缓存/卸载)时收起页内子弹窗,避免 append-to-body 的弹窗 DOM 残留在 body 上
closeInnerDialogs() {
this.routeChangeVisible = false;
this.commonAddressVisible = false;
this.candidateSearchVisible = false;
},
restoreRouteAndCargo() {
const routeRows = parseJsonArray(this.dialogForm.routeJson);
+26 -62
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;
}
},
// 页面被 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);
},