b4e12a671f
- 独立整页固定使用普通 div 容器,取消动态切换 el-dialog 避免切换时弹窗 DOM 残留 - 删除相关 dialogVisible、dialogTitle、页脚弹窗动态分支代码以简化逻辑 - watch $route 调整,优化独立页初始化流程,避免不必要的关闭弹窗操作 - 新增 closeInnerDialogs 方法,页面卸载或 keep-alive deactivate 时关闭所有二级弹窗 - 对 loading-manage 与 project-apply 两个模块同步改造,统一处理弹窗状态和容器渲染 - 解决 keep-alive 缓存导致旧弹窗一直挂载在 body 上的问题,改善用户切换体验
4.3 KiB
4.3 KiB
项目长期记忆(tms-erp-web-ws / Saber3)
配套后端:/Users/gxwebsoft/JAVA/tms-api(不是 tms-erp-api-ws,后者功能滞后)。
列表 + 独立表单页 + 独立详情页(同一组件分流)
- 路由:
/xxx(菜单)、/xxx/form、/xxx/detail指向同一 .vue;form/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 翻转。
样式硬规则
- 底栏:
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 必须带字段名。
复用与自检
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类型不兼容时静默跳过(Date createTime→LocalDateTime丢值),须 Service 内DateUtil.fromDate(...)赋值。 - 排查导出文件用 Python
zipfile读xl/worksheets/sheet1.xml。