2 Commits

Author SHA1 Message Date
gxwebsoft ff9fb9168b fix(router): 修复运单管理详情路由及合同详情路由重复定义问题
- 为 waybill-manage-page、transport-plan-page 等组件增加 routePathLocked 变量锁定路由路径
- 添加 isOwnedRouteActive 计算属性,防止缓存实例错误读取其它路由的 detailId 导致误请求
- watcher 和 openDetail 方法中添加路由守卫,避免多余的请求和误开详情标签
- 修改宿主视图绑定 detailId,避免直接绑定全局 $route.query 导致缓存污染
- 删除 router/views/index.js 中合同管理详情路由重复定义,防止内容区空白问题
- 优化 waybill-import-dialog 组件样式和结构,增加 section-card 包裹表单区域
- 调整相关组件 data、computed、watch 使用,确保第一次立即 watcher 正确读取路由数据
- 验证所有改动后相关页面 HTTP 200,标签页行为正常,解决「运单管理不存在」和合同详情空白问题
2026-09-18 12:22:25 +08:00
gxwebsoft 986feff7b7 fix(waybill-manage): 修复运单详情弹窗残留问题
- 页面形态状态(列表/独立表单页/独立详情页)在实例创建时锁定,避免随路由变化切换导致弹窗残留
- 模板中形态相关所有判定改为使用锁定状态变量,保证渲染一致性
- 修改 detailContainer、crudContainer、pageFormOption 等方法使用锁定状态,避免缓存实例 option 变形
- 新增 closeInnerDialogs 方法,在组件 deactivated 和 beforeUnmount 生命周期关闭所有 append-to-body 弹窗
- 解决标签页 keep-alive 机制下弹窗 Teleport 持续遗留导致界面异常的问题
- 对运单管理页面多处弹窗和视图控制做统一修复,提升页面稳定性和体验
2026-09-18 11:29:52 +08:00
9 changed files with 179 additions and 53 deletions
+82
View File
@@ -38,3 +38,85 @@
**校验**dev server curl 该 .vue 与 scoped style 均 200。仍未 commit。 **校验**dev server curl 该 .vue 与 scoped style 均 200。仍未 commit。
**未提交**:上述改动 + 上一轮 loading-manage 独立页改造均未 commit。 **未提交**:上述改动 + 上一轮 loading-manage 独立页改造均未 commit。
---
## 排查(未改码):配载单详情页反复弹「运单管理不存在」
用户截图:打开 `/business/loading-manage/detail?id=2097607162718441474&name=配载单详情`,连续弹出 6-7 条红色「运单管理不存在」,标签栏堆了一串「运单管理详情」。
**文案来源**:前端 src 里没有这句话,是后端 `BusinessException` 的 msg,被 `src/axios.js` 的响应拦截器(`status !== 200``ElMessage.error(message)`)统一弹出。
**主因(通道 A**`views/business/waybill-manage-detail.vue` 只有 23 行,写了 `:detail-id="$route.query.id"` —— 直接绑全局 `$route`**没有路径守卫**。`waybill-manage-page.vue``detailId` watcher 是 `immediate` 且对任何非空 id 都 `openDetail({id})`。于是:
1. 之前打开过的每个运单详情标签(`/business/waybill-manage/detail?id=A``?id=B`…)各是一个被 keep-alive 缓存的独立实例;
2. 跳到配载单详情后,这些实例被 deactivate 但仍随 `$route` 重渲染 → `$route.query.id` 变成配载单 id
3. prop 变化 → `openDetail({id: 配载单id})``getDetail(配载单id)` 去查运单 → 后端「运单管理不存在」→ 拦截器弹一次。**几个旧标签就几条提示**;
4. 且被污染实例的 `isStandaloneWaybillDetailPage` 仍是 live computed(false) → `openDetail``$router.push` 分支 → 又生成新的「运单管理详情」标签(标签栏那串的来源)。
同理风险:`waybill-manage.vue:6``transport-plan.vue:6``:detail-id="$route.query.detailId"``business-crud-page.vue:7356` 会 push `/business/loading-manage?detailId=id`,正好会污染运单列表实例)。
**次因(通道 B**`loading-manage.vue``restoreWaybillRows` 会用 `waybillIdsJson` 里的每个运单 id 并发 `getWaybillDetail(id)`,若历史运单已被删/失效,也会报同一句文案且并发多条。单条 `.catch(() => null)` 挡不住拦截器已弹出的提示。
**区分方法**Network 里看报错请求的 `id` —— 等于 `2097607162718441474`(配载单 id)→ 通道 A;是别的数字(运单 id)→ 通道 B。或先关掉所有「运单管理详情」标签再复现,通道 A 会消失。
**待确认的修法**(用户要求先报不改):
1. `waybill-manage-page.vue``created()``routePathLocked = this.$route.path``detailId` watcher 首行加 `if (this.$route.path !== this.routePathLocked) return;`
2. `openDetail()` 的 push 分支加同样守卫(防其它调用路径)。
3. 宿主 view 绑定加路径守卫(`waybill-manage-detail.vue` / `waybill-manage.vue` / `transport-plan.vue`)双保险。
4. 可选:`getWaybillDetail` 支持静默模式,供 `restoreWaybillRows` 用,避免历史脏数据刷屏。
## 修复(已执行):「运单管理不存在」误报 + 误开标签
用户确认后按上方案落地,5 个文件:
1. `src/views/business/components/waybill-manage-page.vue`
- `data()` 新增 `routePathLocked: this.$route.path` —— **必须放 data,不能放 created**Vue Options API 顺序是 data → computed → watch(immediate) → created(已在 runtime-core `applyOptions` 源码中核实)。放 created 会让首个 immediate watcher 读到空值。
- 新增 computed `isOwnedRouteActive() { return this.$route.path === this.routePathLocked; }`
- `detailId` watcher 首行加 `if (!this.isOwnedRouteActive) return;`
- `openDetail``$router.push` 分支同样加守卫。
2. `src/views/business/components/transport-plan-page.vue`:完全同构的写法(`:detail-id` host 一致),加同样的 `routePathLocked` + `isOwnedRouteActive` + watcher 守卫。
3. `src/views/business/waybill-manage-detail.vue``:detail-id="$route.query.id"``:detail-id="detailId"`computed 做 `this.$route.path === '/business/waybill-manage/detail'` 守卫。
4. `src/views/business/waybill-manage.vue`:同上,守卫 `/business/waybill-manage`(保留旧链接 `?detailId=` 兼容)。
5. `src/views/business/transport-plan.vue`:同上,守卫 `/business/transport-plan`
**验证**
- dev server curl 5 个 .vue + 2 个 scoped style 全部 HTTP 200。
-`@vue/server-renderer` 写了临时 mjs(已删)模拟带 `$route` 的 app,确认 **data() 里访问 `this.$route` 可行**immediate watcher 触发时 `routePathLocked` 已是正确路径、首次加载不被拦截。
- `$route` 是 vue-router 挂在 `app.config.globalProperties` 上的 gettervue-router.mjs:1498),组件实例化时已就绪。
**未做(第 4 条可选)**:给 `getWaybillDetail` 加静默模式供 `restoreWaybillRows` 使用(历史失效运单仍会刷多条红字),待用户定夺。
**另注**`business-crud-page.vue:6651` 有同构的 `detailId` immediate watcher,但全项目只有上述 3 个宿主 view 传 `:detail-id`,它暂无调用方,未动。
**仍未 commit。**
## 修复(已执行):合同详情页整页空白 —— 路由表重复定义
**现象**:主订单详情点合同编号 → `/business/contract-manage/detail?id=...&name=合同详情` 内容区空白(侧栏/标签正常)。
**定位过程(关键:真实浏览器复现,不猜)**
1. 静态排查全部排除:`contract-manage.vue` 及其 26 个依赖 HTTP 200、模块 `import()` 成功、无循环依赖、详情分支引用的 24 个成员全部有定义。
2. dev 环境登录态无法直接拿(验证码 + `admin/admin``error_code 2004 用户密码强度过低`),改为**注入式复现**
- `agent-browser open <目标 URL>`(落 `/login`);
- eval 取 `document.getElementById('app').__vue_app__.config.globalProperties``$router` / `$store`
- 写 cookie `saber3-access-token`(注意 token 走 **js-cookie**,不是 localStorage+ `$store.state.user.token`
- 覆写 `XMLHttpRequest.prototype.open/send` 让所有 `/api/**` 返回 `{code:200,data:{...}}`defineProperty 伪造 readyState/status/responseText 后手动触发 `onloadend`)。
-`$router.push(...)` 做 SPA 跳转。
3. 复现出空白,并拿到决定性证据:
- `/business/contract-manage/detail``$route.matched.length === 1`(只有 Layoutname undefined),`#avue-view.children.length === 0`innerHTML 为 `<!---->`
- 对照 `/business/contract-manage/change`(结构相同但未重复定义)→ `matched.length === 2`(Layout + 合同变更),内容完整渲染。
- `$router.getRoutes()` 里 detail 有 **3 条**记录:2 个 Layout 父记录 + 1 个子记录(`合同详情`)。
**根因**`src/router/views/index.js``/business/contract-manage/detail` **被复制粘贴定义了两次**,两次的子路由都叫 `合同详情`。vue-router 的 `addRoute` 遇到重名会 `removeRoute(name)` 把先注册的子记录删掉,但**不会把它从父记录的 `children` 数组里摘除**;于是第一条 Layout 壳记录留在 matcher 列表里且排在前面,`resolve('/business/contract-manage/detail')` 命中这个"无有效子路由"的壳 → matched 只有 1 层 → `page/index/index.vue``#avue-view` 的二级 `<router-view>` 无匹配 → 内容区空白。
`getRoutes()` 计数是判据:form / change 都是 2 条 = 父 + 子(健康),detail 是 3 条 = 2 父 + 1 子(坏)。)
**修复**:删除重复块(原 314-325 行),只保留 159-169 行那一份。
**验证**
- 重复扫描脚本(正则匹配「顶层 path + `component: Layout` + 首个子路由 name」):views/index.js 27 条 Layout 子路由中仅 `合同详情` 重复;page/index.js 无重复 → 已清零。
- 修复后浏览器复验:detail → `matched.length === 2`Layout + 合同详情)、`#avue-view.children.length === 1`,正文完整渲染「基本信息 / 签约类型 / 合同编号 HT-2026-001 / … / 变更记录」。
- 全量回归:48 条 business/vehicle/payment/settlement 路由 `resolve()``matched.length` 全部 ≥ 2`bad: []`
- `curl` 校验:`views/index.js``contract-manage.vue` 均 200。
- 残留报错均为 mock 数据形状不符所致(所有接口都返回同一个合同对象,导致 `tree.reduce` / `feeCategories.find` 之类失败),非真实缺陷。
**未 commit**(连同 1、2 轮改动一起待确认)。
+20 -33
View File
@@ -1,40 +1,27 @@
# 项目长期记忆(tms-erp-web-ws / Saber3 # 项目长期记忆(tms-erp-web-ws / Saber3
配套后端:`/Users/gxwebsoft/JAVA/tms-api`不是 tms-erp-api-ws,后者功能滞后)。 后端:`/Users/gxwebsoft/JAVA/tms-api``tms-erp-api-ws` 滞后,别看错仓库)。
## 列表 + 独立表单页 + 独立详情页(同一组件分流 ## 列表 / 表单 / 详情三态同组件分流
- 路由:`/xxx`(菜单)`/xxx/form``/xxx/detail` 指向同一 .vueform/detail `component: Layout` + 空 children`meta:{keepAlive:false}`detail 带 `activeMenu:'/xxx'` `/xxx``/xxx/form``/xxx/detail` 指向同一 `.vue`form/detail `src/router/views/index.js` `component: Layout` + 空 `children.path` + `meta:{keepAlive:false}`detail `activeMenu`)。组件内按 `$route.path` 分流,必须 `watch:{$route}` 重新 init;标签标题取 `query.name`;独立页容器固定 `<div v-if>`,不用 `el-dialog`
- 组件内按 `$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 间切换 ## ⚠️ keep-alive 三坑
- **现象**:改成独立整页后,点左侧菜单又弹出旧弹窗,且永久盖在页面上 背景(`router/tab.js` + `page/index/index.vue`):按 `fullPath` 建 wrapper`<keep-alive :include="tagsKeep">` 缓存,**每标签一实例、永不销毁**,deactivate 后**仍随全局 `$route` 重渲染**
- **根因**`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;列表页分支另写或只保留弹窗一种形态 **坑一:独立页容器禁用 `<component :is>` 在 div / el-dialog 间切换。** `append-to-body` 走 Teleport`TeleportImpl.move` 忽略 `moveType`,不会把 DOM 搬回缓存容器 → 切菜单冒出旧弹窗。修法:固定 `<div v-if>` + `deactivated(){closeInnerDialogs()}` + `beforeUnmount()`(写在子组件也生效)。已修 loading-manage / project-apply / waybill-manage-page;未修 `settlement/components/{pre,formal}-settlement-editor.vue``transport-reconciliation-editor.vue``waybill-import-dialog.vue`
- **兜底**:页面内其它 `append-to-body` 的二级弹窗,加 `deactivated(){closeInnerDialogs()}` + `beforeUnmount(){closeInnerDialogs()}` 把 v-model 置 false。
- 已按此修法落地:loading-manage、project-apply2026-09-18)、waybill-manage-page(同日,锁 detailPage/formPage/formMode 三个标志) **坑二:宿主 view 直绑全局 `$route.query.*` 给子组件 prop。** 缓存实例被灌入当前页 id → 拿错 id 查后端(批量弹「运单管理不存在」),live computed 还会误 push 标签。修法:`routePathLocked` 锁路径 + watcher / push 前判 `isOwnedRouteActive` + 宿主绑定加路径守卫。⚠️ `routePathLocked` **必须放 `data()`**Options API 顺序 data → computed → watch(immediate) → created;放 created 会读到空值、挡掉首次加载)。已修 waybill-manage-page / transport-plan-page + 三个宿主 view
- 未修同类风险:`settlement/components/{pre,formal}-settlement-editor.vue``transport-reconciliation-editor.vue``pageMode ? 'div':'el-dialog'`)、`waybill-import-dialog.vue``standalone`/`createPage`)。
**坑三:路由表重复定义 → 内容区整页空白(2026-09-18)。** `/business/contract-manage/detail``router/views/index.js` 定义两次、子路由同名 `合同详情`。重名 `addRoute``removeRoute(name)` 移除旧子记录,但**不从父记录 children 里摘除**,第一条 Layout 壳记录留在 matcher 且靠前 → `resolve()` 命中它 → `$route.matched.length === 1` → 二级 router-view 无匹配 → 侧栏/标签正常但内容空白。修法:删重复定义。排查:扫「顶层 path + 首个子路由 name」重复项。
## 样式硬规则 ## 样式硬规则
- 底栏`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()` 要包整个选择器。 - 底栏 `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`(禁绿、禁两个蓝实心)。顺序 `[辅助][取消][保存草稿][提交]` - 按钮层级:次要= type;中间步骤=`primary plain`;主操作=`primary`(禁绿、禁两个蓝实心)。顺序 `[辅助][取消][保存草稿][提交]`
- 独立页标题 `.archive-page-form__title`18px/600 + 4px 主色竖条);分组用全局 `<section-card>`弹窗灰底 `#f5f6fa` - 独立页标题 `.archive-page-form__title`;分组用全局 `<section-card>`上传证件区 `width:100%; max-width:240px` + `.el-upload{height:151px}`
- 上传证件区:`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
- ⚠️ `<style scoped lang="scss">` **顶层禁 `//` 注释**Vite5+sass 报 `Unexpected '/'` → 样式模块 500),顶层用 `/* */`
- 其余全站细则见 `src/styles/element-ui.scss` 与 AGENTS.md 4.4。
## 表单文案 ## 表单 / 自检 / 导出
- placeholder 只写 `请输入`/`请选择`;例外保留`请输入或选择车辆`、日期区间 `起/止`、示例值`如:京A12345`。校验 message 须带字段名。 - placeholder 只写 `请输入`/`请选择`;例外:`请输入或选择车辆`、日期区间 `起`/`止`、示例值。校验 message 须带字段名。
- `business-crud-page.vue`option 经 `cloneOption` 克隆,独立表单页走 `PageAvueForm`
## 复用与自检 - 自检:`curl "localhost:2889/src/xxx.vue"``"...?vue&type=style&index=0&scoped=true&lang.scss"`200 / 500)。`vite build``facelogin.vue` 被沙箱中断,不能作唯一校验。dev `VITE_APP_API=/api` 代理 `172.16.203.228:8000`
- `business/components/business-crud-page.vue`option 经 `cloneOption` 克隆;独立表单页走 `PageAvueForm`;详情弹窗 `detailButton + detailSections` - 导出:前端 `exportColumns` 后端未用,以 `XxxExportExcel.java` 为准;BladeX `BeanUtil` 类型不兼容静默跳过(`Date``LocalDateTime` 丢值,用 `DateUtil.fromDate`
- 自检: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` 类型不兼容时静默跳过(`Date createTime``LocalDateTime` 丢值),须 Service 内 `DateUtil.fromDate(...)` 赋值。
- 排查导出文件用 Python `zipfile``xl/worksheets/sheet1.xml`
-12
View File
@@ -311,18 +311,6 @@ export default [
}, },
], ],
}, },
{
path: '/business/contract-manage/detail',
component: Layout,
children: [
{
path: '',
name: '合同详情',
meta: { keepAlive: false, activeMenu: '/business/contract-manage' },
component: () => import('@/views/business/contract-manage.vue'),
},
],
},
{ {
path: '/business/contract-manage/change', path: '/business/contract-manage/change',
component: Layout, component: Layout,
@@ -3020,6 +3020,10 @@ export default {
Location, Location,
OfficeBuilding, OfficeBuilding,
Search, Search,
// watcher /
// dataOptions API data computed watch(immediate) created
// created immediate watcher
routePathLocked: this.$route.path,
form: {}, form: {},
suppressTransportTypeClear: false, suppressTransportTypeClear: false,
query: {}, query: {},
@@ -3596,6 +3600,11 @@ export default {
!this.dialogReadonly !this.dialogReadonly
); );
}, },
// tab.js fullPath path
// keep-alive $route id
isOwnedRouteActive() {
return this.$route.path === this.routePathLocked;
},
billingCargoTypeCascaderProps() { billingCargoTypeCascaderProps() {
return { return {
label: 'cargoName', label: 'cargoName',
@@ -3673,6 +3682,9 @@ export default {
detailId: { detailId: {
immediate: true, immediate: true,
handler(id) { handler(id) {
// 宿 view $route.query.detailId
// id
if (!this.isOwnedRouteActive) return;
if (id !== undefined && id !== null && id !== '') { if (id !== undefined && id !== null && id !== '') {
this.$nextTick(() => this.openDetail({ id })); this.$nextTick(() => this.openDetail({ id }));
} }
@@ -199,13 +199,17 @@
</el-dialog> </el-dialog>
<el-dialog v-model="detailVisible" title="导入运单详情" width="90%" append-to-body> <el-dialog v-model="detailVisible" title="导入运单详情" width="90%" append-to-body>
<el-form :inline="true" :model="detailQuery" <section-card class="waybill-search">
><el-form-item label="车牌号/船号" <el-form :inline="true" :model="detailQuery"
>
<el-form-item label="车牌号/船号"
><el-input v-model="detailQuery.vehicleNo" clearable /></el-form-item ><el-input v-model="detailQuery.vehicleNo" clearable /></el-form-item
><el-form-item label="司机/船长姓名" ><el-form-item label="司机/船长姓名"
><el-input v-model="detailQuery.driverName" clearable placeholder="请输入" /></el-form-item ><el-input v-model="detailQuery.driverName" clearable placeholder="请输入" /></el-form-item
><el-button type="primary" @click="loadDetails">查询</el-button></el-form ><el-button type="primary" @click="loadDetails">查询</el-button></el-form
> >
</section-card>
<el-table :data="details" border <el-table :data="details" border
><el-table-column type="index" label="序号" width="65" /><el-table-column ><el-table-column type="index" label="序号" width="65" /><el-table-column
prop="batchNo" prop="batchNo"
@@ -593,6 +597,7 @@ import { getList as getDriverList } from '@/api/transportCapacity/driver';
import { getDictionary } from '@/api/system/dictbiz'; import { getDictionary } from '@/api/system/dictbiz';
import * as api from '@/api/business/waybill-manage'; import * as api from '@/api/business/waybill-manage';
import { downloadXls } from '@/utils/util'; import { downloadXls } from '@/utils/util';
import SectionCard from '@/components/section-card/main.vue';
const props = defineProps({ modelValue: Boolean, standalone: Boolean, createPage: Boolean }); const props = defineProps({ modelValue: Boolean, standalone: Boolean, createPage: Boolean });
const emit = defineEmits(['update:modelValue', 'closed']); const emit = defineEmits(['update:modelValue', 'closed']);
@@ -1617,4 +1622,7 @@ const confirmImport = async () => {
:global(.avue-layout--horizontal .waybill-import-create__footer) { :global(.avue-layout--horizontal .waybill-import-create__footer) {
left: 0; left: 0;
} }
.waybill-search .el-form-item{
margin-bottom: 0 !important;
}
</style> </style>
@@ -3518,6 +3518,11 @@ export default {
selectionList: [], selectionList: [],
attachmentUploadMode: false, attachmentUploadMode: false,
standaloneFormKey: '', standaloneFormKey: '',
// $route
// data created Vue Options API
// data computed watch(immediate) created created
// immediate watcher
routePathLocked: this.$route.path,
// / / $route // / / $route
// keep-alive deactivate $route // keep-alive deactivate $route
// / append-to-body el-dialog // / append-to-body el-dialog
@@ -3600,6 +3605,12 @@ export default {
return this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute; return this.standaloneDetailPage && this.$route.path === standaloneWaybillDetailRoute;
}, },
// $route data formPageLocked // $route data formPageLocked
// tab.js fullPath path
// keep-alive $route id
// id
isOwnedRouteActive() {
return this.$route.path === this.routePathLocked;
},
detailContainer() { detailContainer() {
return this.detailPageLocked ? 'PageDetail' : 'el-dialog'; return this.detailPageLocked ? 'PageDetail' : 'el-dialog';
}, },
@@ -3867,6 +3878,10 @@ export default {
detailId: { detailId: {
immediate: true, immediate: true,
handler(id) { handler(id) {
// 宿 view $route.query.id / detailId
// id
// openDetail id
if (!this.isOwnedRouteActive) return;
if (id !== undefined && id !== null && id !== '') { if (id !== undefined && id !== null && id !== '') {
this.$nextTick(() => this.openDetail({ id })); this.$nextTick(() => this.openDetail({ id }));
} }
@@ -4449,6 +4464,9 @@ export default {
}, },
openDetail(row) { openDetail(row) {
if (!this.isStandaloneWaybillDetailPage) { if (!this.isStandaloneWaybillDetailPage) {
// row.id id
// push
if (!this.isOwnedRouteActive) return;
this.$router.push({ path: standaloneWaybillDetailRoute, query: { id: row.id } }); this.$router.push({ path: standaloneWaybillDetailRoute, query: { id: row.id } });
return; return;
} }
+10 -1
View File
@@ -1,9 +1,11 @@
<template> <template>
<!-- waybill-manage-detail.vue只在当前路由属于本页时才透传 detailId
避免标签页缓存的实例被其它页面的 detailId 污染后误开详情 -->
<transport-plan-page <transport-plan-page
:api="api" :api="api"
:config="config" :config="config"
:crud-option="option" :crud-option="option"
:detail-id="$route.query.detailId" :detail-id="detailId"
:menu-width="220" :menu-width="220"
standalone-form-page standalone-form-page
/> />
@@ -14,6 +16,8 @@ import TransportPlanPage from './components/transport-plan-page.vue';
import * as api from '@/api/business/transport-plan'; import * as api from '@/api/business/transport-plan';
import { config, option } from '@/option/business/transport-plan'; import { config, option } from '@/option/business/transport-plan';
const listRoutePath = '/business/transport-plan';
export default { export default {
components: { TransportPlanPage }, components: { TransportPlanPage },
data() { data() {
@@ -23,5 +27,10 @@ export default {
option, option,
}; };
}, },
computed: {
detailId() {
return this.$route.path === listRoutePath ? this.$route.query.detailId : '';
},
},
}; };
</script> </script>
+14 -1
View File
@@ -1,9 +1,15 @@
<template> <template>
<!--
detailId 必须做路由守卫本组件对应 /business/waybill-manage/detail
$route 是全局响应式的标签页 keep-alive 会缓存本实例路由切到别的详情页后
实例仍会重渲染若无守卫就会把当前页面的 id灌进子组件导致它拿别的单据 id
去查运单 运单管理不存在并误生成一个又一个运单详情标签
-->
<waybill-manage-page <waybill-manage-page
:api="api" :api="api"
:config="config" :config="config"
:crud-option="option" :crud-option="option"
:detail-id="$route.query.id" :detail-id="detailId"
:menu-width="250" :menu-width="250"
standalone-detail-page standalone-detail-page
/> />
@@ -14,10 +20,17 @@ import WaybillManagePage from './components/waybill-manage-page.vue';
import * as api from '@/api/business/waybill-manage'; import * as api from '@/api/business/waybill-manage';
import { config, option } from '@/option/business/waybill-manage'; import { config, option } from '@/option/business/waybill-manage';
const detailRoutePath = '/business/waybill-manage/detail';
export default { export default {
components: { WaybillManagePage }, components: { WaybillManagePage },
data() { data() {
return { api, config, option }; return { api, config, option };
}, },
computed: {
detailId() {
return this.$route.path === detailRoutePath ? this.$route.query.id : '';
},
},
}; };
</script> </script>
+10 -1
View File
@@ -1,9 +1,11 @@
<template> <template>
<!-- waybill-manage-detail.vue保留旧链接 /business/waybill-manage?detailId=xxx 的能力
但只在当前路由确实属于本页时才透传避免被其它页面的 detailId 污染 -->
<waybill-manage-page <waybill-manage-page
:api="api" :api="api"
:config="config" :config="config"
:crud-option="option" :crud-option="option"
:detail-id="$route.query.detailId" :detail-id="detailId"
:menu-width="250" :menu-width="250"
standalone-form-page standalone-form-page
/> />
@@ -14,6 +16,8 @@ import WaybillManagePage from './components/waybill-manage-page.vue';
import * as api from '@/api/business/waybill-manage'; import * as api from '@/api/business/waybill-manage';
import { config, option } from '@/option/business/waybill-manage'; import { config, option } from '@/option/business/waybill-manage';
const listRoutePath = '/business/waybill-manage';
export default { export default {
components: { WaybillManagePage }, components: { WaybillManagePage },
data() { data() {
@@ -23,5 +27,10 @@ export default {
option, option,
}; };
}, },
computed: {
detailId() {
return this.$route.path === listRoutePath ? this.$route.query.detailId : '';
},
},
}; };
</script> </script>