SNAPSHOT W7 已部署稳定态 — 凯迪ERP+OA一体化平台 (MET 73.3%)

恢复点(restore point)。别人改崩后可 git reset --hard 回到此提交。

== 此快照内容 ==
- 后端 oa-backend: 734 控制器 / 711 实体 (Spring Boot 3.2.5 + SQLite, 端口8091)
- 前端 modern-ui/app: Vue3+Vite, 约700页 (构建产物已在 oa-backend/src/main/resources/static)
- 数据库 oa-backend/data/oa.db: 含全部演示数据 (强制入库, 6.6MB)
- 交接文档 go.md + go-code-reference/endpoints/entities/database.md
- 多代理建设脚本 .claude/wf-*.js

== 状态 ==
- 对 凯迪科技ERP_20260507.xlsx 合规 MET ~73.3% (PARTIAL 75: 34可建+6种子/bug+35外部硬天花板)
- 安全: 5轮红队+5轮复检, default-deny分级鉴权, 连续零可利用
- W3~W7 累计补完436缺口; W8末轮(40缺口)为半成品(源码树可编译但未集成)
- 运行: cd oa-backend; java -jar build/libs/oa-backend-0.1.0.jar --server.port=8091; admin/123456

== 排除(gitignore, 可再生) ==
node_modules / oa-backend/build / .jdks / *.log / Backup-ERP-* / 弃用的OFBiz核心(只保留modern-ui)
完整文件夹备份见同目录 Backup-ERP-20260615-191517/ (含上述全部, 仅缺 node_modules)

时间戳: 20260615-191517

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Qiufeng
2026-06-15 19:19:15 +08:00
co-authored by Claude Opus 4.8
commit 5e51dc3f56
10584 changed files with 2501339 additions and 0 deletions
+93
View File
@@ -0,0 +1,93 @@
# 路由规范(凯迪 ERP+OA 一体化平台)
> 本平台融合了致远 OA 复刻 + 凯迪 ERP 扩建 + 多套部门系统。为避免「层级套用、前缀冗余」,
> 统一收敛为一套**两段式扁平路由**体系。本文档是唯一规范,新增页面必须遵守。
## 1. 顶层约定
| 项 | 取值 | 说明 |
|----|------|------|
| 路由模式 | `createWebHistory()` | HTML5 history,干净 `/...` 网址,**无 `#` 片段** |
| 站点 base | `/` | 原 `/modern/app/`OFBiz 遗留)已废弃 |
| 路由前缀 | 无 | 原 `/oa/` 前缀已全量去除 |
| 命名层级 | **两段** `/<module>/<page>` | 不允许第三段嵌套 |
| 路由 name | `oa:<moduleId>:<key>` | 由目录自动生成,全局唯一 |
历史层级 `/<base>/#/oa/<module>/<page>`(三~四段 + `#`-> 规范后 `/<module>/<page>`(两段,无 `#`)。
> **去掉 `#` 的前提(已满足)**:history 模式要求服务端把「任意未知路径」回退到 `index.html`
> 否则直接刷新内页会 404。vite dev/preview 服务器**默认自带**该 SPA fallback,当前运行环境即此。
> 若将来把构建产物部署到裸静态服务器/nginx,需补一条 `try_files $uri /index.html` 之类的回退规则。
## 2. 单一数据源
路由**不手写**。`src/data/oaModules.ts` 是唯一权威目录,每个页面一条记录:
```ts
{ key: 'accounts', label: '会计科目', kind: 'list', path: '/finance/accounts' }
```
`src/router/index.ts``oaAllPages` 自动生成路由表:
- `path` 直接取 `page.path`
- `name` = `oa:${moduleId}:${key}`
- 组件解析 `pageComponent(moduleId, key)` -> `import.meta.glob('../oa/pages/**/*.vue')`
命中 `pages/<moduleId>/<key>.vue` 则用真实页面,否则回退 `OaGenericPage``kind` 渲染原型。
> **关键解耦**:组件解析走 `moduleId+key`,与 `path` 无关。改 `path` 不需要改页面文件名/目录。
## 3. 顶层模块段(module
业务域即顶层段,扁平并列,互不嵌套:
```
collab goal rd meeting masterdata knowledge hr budget culture report
payment ehs archive appdev sealcenter ops intel contract mfg lab
finance doccollab design crm bidding supervision mobile itasset audit
```
特殊页(不入顶部导航):
- `/` 个人空间门户(portal
- `/contacts` 通讯录
- `/org-space``/template-space` 空间占位
- `/collab/handle?id=…` 事项办理详情(由待办行点击进入)
- `/login` 登录跳转
- `/:pathMatch(.*)*` -> NotFoundView
## 4. 命名规则
- module 段:小写、业务域语义(`finance` 而非 `cw`),多词用连字符。
- page 段(key):小写、动作或视图语义(`ledger` 台账 / `board` 看板 / `cockpit` 驾驶舱 / `accounts` 列表)。
- 同一业务概念只允许一条规范路由。**禁止重复**:如「合同台账」统一为 `/contract/ledger`
已删除原 `/masterdata/contract` 重复路由(`pages/contract/ledger.vue` 以 import 复用
`pages/masterdata/contract.vue` 的组件,属文件级复用,非第二条路由)。
## 5. 后端 API 命名(不随前端路由变动)
后端 API 是**独立命名空间**,与前端路由解耦,不参与本次重构:
| 项 | 取值 |
|----|------|
| Base | `/api/oa`dev 由 vite proxy 转发到 :8090 |
| 客户端 | `http.get('/contracts')` -> 实际 `/api/oa/contracts` |
| 风格 | 资源复数名词,统一 `ApiResp{code,message,data}`code 0 = 成功) |
> 前端路由用「业务域/视图」语义(给人看),后端 API 用「资源」语义(给程序用),两者各自规范、互不耦合。
> 改前端路由**不影响** API 调用——API 客户端 base 路径未动。
## 6. 新增页面流程(务必遵守)
1.`oaModules.ts` 对应模块的 `pages[]` 加一条 `{ key, label, kind, path: '/<module>/<key>' }`
2.`src/oa/pages/<moduleId>/<key>.vue` 放真实页面(文件名 = key)。
3. 路由自动生成,**无需改 `router/index.ts`**。
4. 跨页跳转、搜索命中映射(`api/search.ts``HIT_ROUTE`)、移动端快捷入口
一律引用规范 `path`,不得硬编码旧 `/oa/...`
## 7. 验收基线(本次重构已达成)
- 路由总数 118;其中 `oa:*` 命名路由 112**112/112 自映射通过**0 冲突、0 被遮蔽、0 落到 not-found。
- 伪造路径正确落 not-found;6 个特殊路由全部解析正常。
- `vue-tsc --noEmit` 通过(0 error);全量 emoji/箭头扫描 0。
- 无残留 `/oa/` 路由字面量(仅余 `/api/oa/` 与文件级 import,均正确)。
- **history 模式(去 `#`)实测**:直接加载/刷新深链 `/contract/ledger` 正常渲染(vite SPA fallback 生效,
5 条数据);裸输 `/zzz/...` 落 in-app NotFound;全站 live 导航网址均无 `#``anyHashAnywhere=false`)。
全代码仅 1 处 `createWebHashHistory->createWebHistory` + 2 处 `href="#/"` 锚点改为路由跳转;无 `location.hash` 逻辑。