feat(mp): 小程序端骨架 + 扫码落地页(scene 识别租户)
小程序端从零建起来了,并在微信开发者工具里真机模拟跑通: 扫 scene=t1-k17 → 显示「示范职业学校 / 2026年9月机电专业认定材料收集 / 尚未发布」。 交付: · frontend-mp/(uni-app,官方 uni-preset-vue#vite-ts 模板),appid 已填 · src/pages/index/index.vue 扫码落地页:读 scene → 调后端 → 显示 「哪个学校 / 填什么 / 现在能不能填」 · GET /api/v1/mp/scene-context(匿名):登录前的落地页查询 · 主题色与 PC 管理端同一套(腾讯云 TDesign 色板),两端视觉一致 为什么落地页必然是匿名接口: 学生扫开的第一屏要回答"这是哪个学校、要填什么、能不能填", 而这发生在绑定身份之前。它与契约里的 POST /mp/login(code+scene 换 session) 不是一回事 —— 那个要换 openid,属 M3。 ⚠️ 一个必踩的坑(撞上并绕开了): FillTenantLineHandler.getTenantId() 在**匿名请求下直接抛 40101**, 所以不能用 taskMapper.selectById()。正确写法是专用 Mapper + 每条查询 @InterceptorIgnore(tenantLine="true") 并显式带 tenant_id(项目注释称此为 一次代码审查点)。见 module/mp/mapper/MpSceneMapper.java —— 把这几条集中在 一个文件里,正是为了让"关掉框架保护后由人保证隔离"这件事有地方审。 ⚠️ scene 可穷举(t1-k1、t1-k2…),所以匿名接口: ① 只返回落地页必须的最少信息,不往里加"顺带能查出来"的东西; ② 按 IP 限流(20 次/分钟,Redis INCR,复用项目的 GATE_RATE_LIMITED 40071)。 E2E 专门验了"前 20 次通过、第 21 次起被限、清掉计数器立刻恢复"。 状态文案分五种而不是合并成"当前不可填报":学生的下一步动作完全不同 —— 「已截止」要找班主任、「已暂停」要等通知、「尚未发布」是根本不该现在扫。 顺带记两个环境坑(写进交接摘要): · 微信开发者工具的「服务端口」默认关闭,HBuilderX 运行时报 `IDE service port disabled` 然后退出,**调不起开发者工具**。 解法:开发者工具 → 设置 → 安全设置 → 服务端口 → 开启; 或直接「导入项目」dist/dev/mp-weixin 绕过。 · HBuilderX 把这个项目当 CLI 型项目,产物在 dist/dev/mp-weixin, **不是** unpackage/。模拟扫码要在「编译模式」里设 进入场景=扫描二维码、 启动参数 scene=t1-k17。 · <style lang="scss"> 需要装 sass(模板没带),已 pnpm add -D sass。 ⚠️ 对上线计划最重要的一条结论(已写进交接摘要): 开发版(develop)只有开发者能扫、且会过期;体验版(trial)只有体验成员能扫; **只有正式版(release)学生才能扫**,而它需要提交审核,涉及小程序类目与资质。 所以 C1「小程序资质法务确认」不是"以后再说",它直接决定学生能不能开始填报。 已知缺口: · 填报主流程(/mp/login 门禁核验 表单填写)属 M3; 现在点「开始填报」给的是明确的"开发中"提示,不是静默无反应。 · frontend-mp 还没套项目既有的 ESLint/Stylelint 规范。 验收:e2e-m1-scene.py 31/31;八条 E2E 合计 389 项断言全通过; 微信开发者工具里人工确认页面渲染与 scene 传递正确。
This commit is contained in:
+73
-1
@@ -52,8 +52,9 @@
|
||||
| **M1-04 材料项定义** | ✅ 材料项 CRUD(§7.10)+ 三个内置模板(`TPL_SCHOOL_ROLL`/`TPL_SOCIAL`/`TPL_ZHUANXIANG`)+ 材料目录接口;**`e2e-m1-materials.py` → 68/68** |
|
||||
| **M1-03 表单 schema 版本化** | ✅ `GET/PUT /tasks/{id}/form-schema`(版本只增不改 + `baseVersion` 乐观锁 40025 + 内置字段不可删 40026)+ 官方 21 项内置字段目录;**`e2e-m1-form.py` → 48/48** |
|
||||
| **M1-06 填报二维码** | ✅ `GET /tasks/{id}/qrcode`(真调微信生成小程序码)+ 匿名图片接口 `GET /qrcodes/{scene}`;**`e2e-m1-qrcode.py` → 32/32(唯一打外网的 E2E)** |
|
||||
| **小程序端骨架 + 扫码落地页** | ✅ `frontend-mp/`(uni-app,appid `wxf01d3fa60f87f0b7`)+ 匿名 `GET /mp/scene-context`;**已在微信开发者工具里跑通**;`e2e-m1-scene.py` → 31/31 |
|
||||
| PC 前端 | ✅ 已换 Gi Admin Pro + 腾讯云主题;已实现:登录 / 工作台 / 组织架构 / 租户管理 / 账号管理 / **收集任务(含配置班级)** |
|
||||
| 待做 | M1 剩余(M1-05 规则模板 + **M1-07~M1-10 前端**——表单设计器 M1-07、材料规则界面 M1-09);小程序(uni-app)未创建;CI/CD |
|
||||
| 待做 | M1 剩余(M1-05 规则模板 + **M1-07~M1-10 前端**);**M3 小程序填报主流程**(`/mp/login` 门禁核验 表单);CI/CD;**C1 小程序类目资质(阻塞学生真正开始填报)** |
|
||||
|
||||
---
|
||||
|
||||
@@ -380,6 +381,77 @@ Flyway 迁移 1~6 全部 success。
|
||||
|
||||
---
|
||||
|
||||
## 一·十、小程序端骨架 + 扫码落地页(2026-09-29 上午,未提交)
|
||||
|
||||
> 范围:`frontend-mp/`(uni-app 项目,从官方 `uni-preset-vue#vite-ts` 模板建)、
|
||||
> `GET /api/v1/mp/scene-context`(匿名,登录前的落地页查询)。
|
||||
|
||||
**验收**:`python scripts/e2e-m1-scene.py` → **31/31**;
|
||||
八条 E2E 合计 **389 项断言**全通过。
|
||||
**已在微信开发者工具里真机模拟跑通**:`scene=t1-k17` → 显示「示范职业学校 /
|
||||
2026年9月机电专业认定材料收集 / 尚未发布」。
|
||||
|
||||
### ⚠️ 微信版本与「谁能扫」(这是上线计划的关键约束)
|
||||
|
||||
| 版本 | 谁能扫开 | 有效性与成本 |
|
||||
|---|---|---|
|
||||
| `develop` 开发版 | **只有开发者本人** | 上传/预览后短期有效,**会过期**(实测遇到过「开发版小程序已过期」) |
|
||||
| `trial` 体验版 | **只有体验成员**(后台「成员管理」加人) | 相对稳定,被新版本顶替前一直有效 |
|
||||
| `release` 正式版 | **所有人** | 需**提交审核 + 发布**,涉及小程序类目与资质 |
|
||||
|
||||
> ⚠️ **开发版与体验版,学生都扫不开。** 只有正式发布后学生才能扫 ——
|
||||
> 所以 **C1「小程序资质法务确认」不是"以后再说"的事**,它直接决定学生能不能开始填报。
|
||||
> 建议尽早就"教育类目需要什么资质"问清楚。
|
||||
|
||||
### 两个工具链的产物路径(容易搞混)
|
||||
|
||||
| 工具 | 命令/操作 | 产物目录 |
|
||||
|---|---|---|
|
||||
| CLI(pnpm) | `pnpm dev:mp-weixin` / `build:mp-weixin` | `dist/dev/mp-weixin`、`dist/build/mp-weixin` |
|
||||
| HBuilderX | 「运行到小程序模拟器」 | **`dist/dev/mp-weixin`**(它把这个项目当 CLI 型项目,**不是** `unpackage/`) |
|
||||
|
||||
### 两个必踩的环境坑
|
||||
|
||||
| 坑 | 现象与解法 |
|
||||
|---|---|
|
||||
| **微信开发者工具的「服务端口」默认关闭** | HBuilderX 运行时报 `IDE service port disabled` / `工具的服务端口已关闭`,然后 `[info] 退出` —— **调不起开发者工具**。解法:打开开发者工具 → **设置 → 安全设置 → 服务端口 → 开启**。或绕过:直接「导入项目」`dist/dev/mp-weixin` |
|
||||
| **模拟扫码要手动配编译模式** | 默认进入时 `onLoad` 参数为空(页面会提示"请扫描二维码")。要模拟:工具栏「编译模式」→ 添加 → **进入场景=扫描二维码** → **启动参数 `scene=t1-k17`** |
|
||||
|
||||
另:`<style lang="scss">` 需要装 `sass`(模板里没带),已 `pnpm add -D sass`。
|
||||
|
||||
### 匿名接口 + 多租户拦截器:一个必踩的坑
|
||||
|
||||
`FillTenantLineHandler.getTenantId()` 在**匿名请求下直接抛 `40101`**,
|
||||
所以落地页这种匿名接口**不能**直接用 `taskMapper.selectById()`。
|
||||
|
||||
正确写法(项目注释称此为一次**代码审查点**):建一个专用 Mapper,
|
||||
每条查询 `@InterceptorIgnore(tenantLine = "true")` **并显式带 `tenant_id`**。
|
||||
本项目的做法见 `module/mp/mapper/MpSceneMapper.java` ——
|
||||
把这几条**集中在一个文件**里,正是为了让"关掉框架保护后由人保证隔离"这件事有地方审。
|
||||
|
||||
### scene 的三段式与限流
|
||||
|
||||
```
|
||||
t{tenantId} 租户级(M0 开通租户时约定的形态)
|
||||
t{tenantId}-k{taskId} 任务级
|
||||
t{tenantId}-k{taskId}-o{orgId} 带班级
|
||||
```
|
||||
|
||||
⚠️ **scene 是可穷举的**(`t1-k1`、`t1-k2`…),所以这个匿名接口:
|
||||
① 只返回落地页必须的最少信息(**不要往里加"顺带能查出来"的东西**);
|
||||
② 按 IP 限流(20 次/分钟,用 Redis INCR,复用项目的 `GATE_RATE_LIMITED` 40071)。
|
||||
|
||||
### 已知缺口
|
||||
|
||||
| 项 | 说明 |
|
||||
|---|---|
|
||||
| **填报主流程未做** | `/mp/login`(code+scene 换 openid/session)、门禁核验(`/mp/roster/match`)、表单填写 —— 属 **M3**。现在点「开始填报」给的是明确的"开发中"提示,不是静默无反应 |
|
||||
| 落地页的"开始填报"按钮 | 同上,等 M3 接上 |
|
||||
| 小程序正式发布需人工操作 | ① 服务器域名白名单加 API 域名;② 提交审核(类目/资质);③ 上传并设为体验版 |
|
||||
| 小程序端无 lint/typecheck 配置 | 用的是官方模板自带的(只有 `type-check` 脚本)。项目既有规范(ESLint/Stylelint)还没套到 `frontend-mp/` |
|
||||
|
||||
---
|
||||
|
||||
**关键实现决策(不要在后继开发中改回去)**
|
||||
|
||||
| 决策 | 理由 |
|
||||
|
||||
Reference in New Issue
Block a user