b4e12a671f
- 独立整页固定使用普通 div 容器,取消动态切换 el-dialog 避免切换时弹窗 DOM 残留 - 删除相关 dialogVisible、dialogTitle、页脚弹窗动态分支代码以简化逻辑 - watch $route 调整,优化独立页初始化流程,避免不必要的关闭弹窗操作 - 新增 closeInnerDialogs 方法,页面卸载或 keep-alive deactivate 时关闭所有二级弹窗 - 对 loading-manage 与 project-apply 两个模块同步改造,统一处理弹窗状态和容器渲染 - 解决 keep-alive 缓存导致旧弹窗一直挂载在 body 上的问题,改善用户切换体验
40 lines
4.3 KiB
Markdown
40 lines
4.3 KiB
Markdown
# 项目长期记忆(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`。
|