u
This commit is contained in:
1 parent
15e0ae5b67
commit
e434374db5
71 files changed
+5726
-329
No files matched your search
@@ -0,0 +1,141 @@
|
||||
# CODEBUDDY.md
|
||||
|
||||
给 AI 协作者的项目约定。人看的话直接读 `README.md`(前端)与 `server/README.md`(后端)。
|
||||
|
||||
## 项目速览
|
||||
|
||||
前后端同仓、**独立构建、独立版本,唯一契约是 HTTP 接口**(前端不读后端源码,后端不管前端怎么调)。
|
||||
|
||||
| 目录 | 是什么 | 端口 / 入口 |
|
||||
|---|---|---|
|
||||
| `web/` | 前端(Vue 3 + Vite + Pinia),唯一有 `package.json` 的包 | dev server `5090`,`/api` 代理到 `127.0.0.1:8088` |
|
||||
| `server/` | 后端(Spring Boot 4.1 + Java),多机构 SQL Server | `8088`,context-path `/api` |
|
||||
| `sql/` | 工作流模块 SQL 脚本与演示数据 | 执行顺序见 `sql/README.md` |
|
||||
|
||||
**根目录没有 `package.json`**,前端命令一律在 `web/` 下跑。
|
||||
|
||||
## 启动
|
||||
|
||||
```bash
|
||||
# 1) 组件库必须先有产物(@g3soft/ui 的 exports 指向 dist)
|
||||
# 需要 g3soft-libs 与 g3soft-erp 平级
|
||||
cd ../g3soft-libs && pnpm --filter @g3soft/tokens build && pnpm --filter @g3soft/ui build
|
||||
|
||||
# 2) 前端
|
||||
cd ../g3soft-erp/web && pnpm dev # http://localhost:5090
|
||||
|
||||
# 3) 后端(连只支持 TLS 1.0 的老 SQL Server 时必须这么起,见 server/config/dbconfigs/README.md)
|
||||
cd ../g3soft-erp/server
|
||||
mvn "-Dspring-boot.run.jvmArguments=-Djava.security.properties=./config/legacy-tls.security" spring-boot:run
|
||||
```
|
||||
|
||||
改完组件库要重启 dev server(构建会清空 `dist/`,dev server 会崩或白屏),详见根 `README.md`。
|
||||
|
||||
## 开发期免登录(省掉每次填账号 + 拖滑块)
|
||||
|
||||
`web/.env.development` 里配好了测试账号,`pnpm dev` 打开页面**已是登录态**:
|
||||
|
||||
| 变量 | 值 | 说明 |
|
||||
|---|---|---|
|
||||
| `VITE_DEV_AUTO_LOGIN` | `1` | 设为 `0` 关闭(例如要调登录页本身) |
|
||||
| `VITE_DEV_ORG` | `G3HD` | 机构码,需对应 `server/config/dbconfigs/{机构码}.properties` |
|
||||
| `VITE_DEV_ACCOUNT` | `demo_zhangwei` | 实测可登录,但**只有审批中心权限**(见下) |
|
||||
| `VITE_DEV_PASSWORD` | `demo_zhangwei` | 演示账号密码=账号名 |
|
||||
|
||||
实现见 `web/src/dev/auto-login.ts`:调 `POST /api/auth/login` 拿 token 写进 store,
|
||||
**只在 `import.meta.env.DEV` 下生效**,生产构建里被 tree-shake。
|
||||
滑块验证码是纯前端校验(不发请求),所以走接口登录不需要它。
|
||||
|
||||
覆盖面:入口是 `/login` 时不自动登录;已有 token 时不重复登录。
|
||||
个人覆盖用 `web/.env.development.local`(已被 gitignore,优先级更高)。
|
||||
|
||||
命令行取 token(例如要用 curl 直接打业务接口):
|
||||
|
||||
```bash
|
||||
node scripts/dev-login.mjs --token-only # 只输出 token 一行
|
||||
node scripts/dev-login.mjs # 人看的输出 + curl 示例
|
||||
```
|
||||
|
||||
## E2E(Playwright)
|
||||
|
||||
```bash
|
||||
cd web
|
||||
pnpm test:e2e # 全量,headless
|
||||
pnpm test:e2e:ui # 带 UI 的调试模式
|
||||
```
|
||||
|
||||
前置条件:**后端已在 8088 起来**(前端 dev server 由配置里的 `webServer` 负责,已经在跑就复用)。
|
||||
后端没起会在 globalSetup 阶段直接报「连不上后端」,不会跑到用例里。
|
||||
|
||||
与 Vitest 的分工:`pnpm test` 跑 `tests/**`(happy-dom 单元测试),`pnpm test:e2e` 跑 `e2e/**`(真浏览器 + 真后端)。
|
||||
|
||||
**单元测试放哪儿**:统一放 `web/tests/`,目录**镜像 `src/` 结构**
|
||||
(`src/components/biz-tree/BizTree.vue` → `tests/components/biz-tree/BizTree.spec.ts`)。
|
||||
不要贴源放进组件目录;`vitest.config.ts` 的 `include` 只收 `tests/**`,src 下误放的 spec 不会被执行。
|
||||
测试里引用被测文件一律用 `@/` 别名(如 `@/components/biz-tree/BizTree.vue`),别写相对路径。
|
||||
|
||||
`playwright.config.ts` 的 `testDir` 必须限定 `./e2e`,否则 Playwright 会把 vitest 的用例也收进来。
|
||||
|
||||
### 免登录是怎么做的
|
||||
|
||||
1. `e2e/support/global-setup.ts`:**整轮测试只登录一次**,调 `POST /api/auth/login`,
|
||||
会话落到 `e2e/.auth/session.json`(已 gitignore,里面有可用 token)。
|
||||
2. `e2e/support/fixtures.ts`:覆盖内置 `context` fixture,用 `addInitScript` 在应用脚本
|
||||
执行**之前**把 `sessionStorage['g3erp:login']` 种好,于是守卫直接放行,用例一进站就是登录态。
|
||||
|
||||
**为什么不是 `storageState`**:token 存在 `sessionStorage`,而 Playwright 的 `storageState`
|
||||
只序列化 cookie + localStorage,种不进去。`addInitScript` 是唯一可靠的办法。
|
||||
|
||||
**为什么必须只登录一次**:后端 `ActiveSessionRegistry` 按 (机构码, 账号) 只保留最新会话,
|
||||
重复登录会互踢(业务码 `40101`)。并发 worker 各登录一次就会互相把对方踢下线。
|
||||
|
||||
> 所以:**不要在用例里提交登录表单**。要测登录流程本身,得用一个专用账号,
|
||||
> 并把 `VITE_DEV_AUTO_LOGIN` 设为 `0`(否则应用自己会先把你登录了)。
|
||||
|
||||
账号沿用 `web/.env.development` 的 `VITE_DEV_*`,可用 `E2E_ORG` / `E2E_ACCOUNT` / `E2E_PASSWORD`
|
||||
覆盖;`E2E_BASE_URL` 换前端地址,`E2E_API_TARGET` 换后端地址,`E2E_CHANNEL=msedge|chrome`
|
||||
改用系统已装的浏览器(Chromium 下载不便时)。
|
||||
|
||||
### 写用例时注意
|
||||
|
||||
- 落点别选 `/dashboard`:它**没有任何权限点**(`sql/20_registration/14_dashboard_menu.sql`
|
||||
明确「不建权限点」),只有超管可见;默认账号 `demo_zhangwei` 进它会被守卫送到 `/403`。
|
||||
`e2e/smoke.spec.ts` 用 `/approval/todo`,演示账号和超管都能进。
|
||||
- 断言用 `toHaveURL(/\/approval\/todo$/)` 这种**正向**断言,别用 `not.toHaveURL(/\/login/)`:
|
||||
`goto` 之后 URL 立刻就是目标值,否定断言会在重定向发生之前就通过,等于什么都没断言。
|
||||
- dev server 是按需转译的,某页**第一次**访问要现编依赖图,实测 5-11s。
|
||||
配置里已经把 expect 超时放宽到 15s —— 别在用例里写死更短的值。
|
||||
|
||||
## 测试账号
|
||||
|
||||
| 账号 | 密码 | 权限 | 用途 |
|
||||
|---|---|---|---|
|
||||
| `demo_zhangwei` / `demo_liqiang` / `demo_wangfang` / `demo_liumin` | 同账号名 | 只授了 `menu.approval%` 与 `action.v_b_othercompany.%`(`sql/90_mock/02_*.sql:186`) | 已实测可登录;侧栏只有「审批中心」,其他页面会被守卫拦到 `/403` |
|
||||
| `g3soft` | **未知** | 前后端唯一超管,免查 `s_power`(`permission.ts:61`、`SqlPermissionService.ADMIN_ACCOUNT`) | 测全部页面得用它 |
|
||||
|
||||
机构码统一 `G3HD`。
|
||||
|
||||
**`g3soft` 的密码待确认**:2026-10-14 实测 `G3HD/g3soft/空密码` 返回 `code=401`
|
||||
(`AuthServiceTests` 里「超管空密码」是纯 mock,不代表 G3HD 库的真实数据)。
|
||||
拿到真实密码后填进 `web/.env.development` 的 `VITE_DEV_PASSWORD` 即可——
|
||||
**一次配置,不必每次查库**。另外 `g3soft` 在 `b_user` 里是否存在也需确认:
|
||||
本仓库的 `sql/` 没有任何脚本创建它(只建 `demo_*`),假定它来自 G3HD 核心库。
|
||||
|
||||
账号密码不用去查库。库里没有的账号靠 `sql/` 下的脚本建(执行顺序见 `sql/README.md`);
|
||||
要给 `demo_*` 放开更多菜单,用 `sql/README.md` 里「可选:给普通账号授权」那段。
|
||||
|
||||
## 踩坑备忘
|
||||
|
||||
- **同一账号重复登录会互踢**:每次登录都刷新服务端 session(`ActiveSessionRegistry.activate`),
|
||||
上一个会话的下一次请求会拿到业务码 `40101` 并被踢回登录页。所以**别和正在用 `g3soft` 的人共用一个账号**——
|
||||
否则双方会在「登录 → 被踢 → 重新登录」之间来回。需要并行时用 `.env.development.local`
|
||||
给 AI 换一个账号(`demo_*` 权限窄,测非审批页要另开权限)。
|
||||
- **鉴权失败是 HTTP 200 + `body.code=401`**,不是 HTTP 401,判状态码会漏。
|
||||
- **菜单是动态的**(读 `s_menu` 表):新增页面必须同时加前端静态路由 +`s_menu` 记录,
|
||||
缺一个就表现为「点菜单进 404」。而 Vite 对任意路径都返回 HTTP 200,网络面板里看不出 404,
|
||||
判据是**路由是否匹配**。
|
||||
- **权限是白名单语义**:`s_power` 没授权 → 侧栏不显示该菜单 + 守卫拦到 `/403`。
|
||||
- **token 存 `sessionStorage`**(key `g3erp:login`,pinia-plugin-persistedstate 写的),
|
||||
所以浏览器每个新会话/新 context 都是未登录态 —— 这正是自动登录要解决的问题。
|
||||
- **`docs/` 目录当前不存在**(提交 `15e0ae5b` 删掉了)。文档写进 `README.md` / `server/README.md`
|
||||
或本文件,别再新增指向 `docs/` 的链接。
|
||||
Reference in new issue
Block a user