日期:2026-09-15 | 状态:阶段 1 需求稿,待长官确认后进阶段 2(出图)
来源:2026-09-09 思路稿 + 2026-09-11 梳理稿 + 2026-09-15 长官逐条拍板
技术现状均已物理 grep 核实,附file:line
品牌方出码把家长拉进来 → 家长看见 4L 硬件展示区是灰的 → 想点亮就得问门店 → 倒逼门店买设备、倒逼品牌方接数据。
品牌方生成一个固定二维码,印成卡片塞进镜片盒(不预购名额、不设上限)
↓
家长拆盒扫码 → 微信认人 → 免注册直接进家长端(计入该码开通数)
↓
到店复查 → 门店扫家长码 / 家长扫门店码 → 档案归到这家店(计入机构自己的开通数,不重复计入品牌码开通数)
↓
家长端首页 4 个灰框 → 有设备才点亮 → 家长追问门店 → 门店采购
计费口径(9-15 拍板):不设名额上限、不做充值,按累计开通人数与机构结算,见规则 20。
4L 指四个防控手段:Laser 弥散红光 / Light 室内补光 / Long 远像屏读写台 / Lens 离焦镜
出处:app/services/prompt_templates.py:39("回答必须围绕 4L 防控体系展开(Laser 弥散红光 / Light 室内补光 / Long 远像屏读写台 / Lens 离焦镜 DOT)")
4L 展示区的 4 个框即对应这四项;品牌方通常就是这四类产品的厂家。
Phase 48 为历史空号(grep -rni "phase.\?48" docs/superpowers/ 返 0,对照组 Phase 47 返 23 行,查法有效)。本次占用,拆三个子 Phase:
| Phase | 名称 | 依赖 |
|---|---|---|
| 48A | 品牌机构码 · 扫码免注册进门 | 无(地基) |
| 48B | 家长 ↔ 门店互扫绑定 | 依赖 48A |
| 48C | 4L 设备展示区 | 可与 48A 并行 |
长官 9-15 拍板实施顺序:48A + 48C 一起动,48B 紧跟。48C 能与 48A 并行的原因(规则 17 确认后):4L 展示区依赖的是「家长自己绑定设备」这条新链路,不依赖机构绑定(48B),两条线互不阻塞。
| # | 规则 | 定于 |
|---|---|---|
| 1 | 系统里只有「机构码」一种码,门店和品牌方都是机构,扫谁的码归谁 | 9-09 |
| 2 | 卡片上只印品牌方的码(我们控制不了他发给谁、发多少,只认扫码开通了多少人) | 9-09("只认他买了多少"9-15 随规则 20 改口径) |
| 3 | 改口径(9-15):品牌码带进来的新家长计入该码的开通数;机构认领已在系统内的家长不计入开通数(避免重复计账) | 9-15(改写,原文是"品牌码=拉新,扣1个名额;门店扫=认领,不扣名额") |
| 4 | 一个孩子只绑一个门店;绑定关系挂在档案(孩子)级,不是席位级 | 9-09 |
| 5 | 门店不继承品牌方的 Logo/头图;品牌定制只改外在展示,不碰问答模型和报告秒读 | 9-09 |
| 6 | 扫码进来的家长:已有子席位的合并到原账号,没有的用微信身份新开 | 9-15 |
| 7 | 规则收窄(9-15):家长扫码进来、尚未被机构绑定时,品牌方可见;一旦该儿童档案被机构绑定,品牌方不再可见;机构解绑且无其他机构接手时,归属回落品牌方(技术上即 service_org_id 为空时自动回到 org_id,兜底天然成立)。⚠️ 商务提醒:品牌方续费依据因此只剩"我带进来多少人",签约时需向品牌方说明 |
9-15(改写,原文是"品牌方能看见带进来的孩子及记录,门店端不提示") |
| 8 | 改口径(9-15):家长扫码即算激活,有效期 365 天(从激活日起算),长官内部沟通后拍板 | 9-15(原文"暂按永久不到期"已作废) |
| 9 | 绑定方式:家长扫门店码、门店扫家长码,两边都行 | 9-15 |
| 10 | 换店规则一条通吃:谁现在绑着,谁看全部历史;不绑了,只剩自己当初录的那几条(换回老店 = 又能看全部) | 9-15 |
| 11 | 记录来源标记维持现有两档(机构录入 / 个人录入),不细化到店名 | 9-15 |
| 12 | 家长先扫 A 品牌码、后扫 B 品牌码 —— 两边各自计入各自的开通数,A 统计里算一个、B 统计里也算一个 | 9-15 |
| 13 | 机构扫码后,由机构在该家长名下的孩子中选择要绑定哪一个(绑定挂在儿童档案级,与规则 4 一致) | 9-15 |
| 14 | 机构建档 + 绑定家长原本是两步,现合并为一步 —— 机构扫家长的档案码 → 弹出该家长名下孩子列表供选择 → 没有就现场新建 → 确认即绑定 | 9-15 |
| 15 | 机构只能看到机构自己录入的检查记录,家长自己录入的数据不对机构开放 | 9-15(长官明确:不打开) |
| 16 | 系统里不存在"品牌方"这种特殊类型:不加机构类型字段、不做特殊分支。规则统一写成「谁带进来的机构」和「谁在服务的机构」两个角色,任何机构都能生成自己的码、拉新,也都能扫码认领。文档里写"品牌方""门店"只是行文方便。⚠️ 推翻 2026-09-09 思路稿"品牌方 = 机构类型 kind=brand"的设想 | 9-15 |
| 17 | 4L 四个框由家长自己绑定点亮:家长在家长端点击绑定对应类型的设备。第一版做两级:先选 4L 类型(弥散红光/室内补光/远像屏读写台/离焦镜),再选具体品牌与型号(型号清单先手工维护)。后续演进方向是做成类似小米之家的完整设备库 —— 因为每个 L 下面都有多家厂商和多种机型 | 9-15 |
| 18 | 档案的编辑权跟着归属走(能看=能改):尚未绑定服务机构时,带他进来的那家机构能看也能改;一旦与某机构互扫绑定,编辑权转移给服务机构,带他进来的机构既看不到也改不了;解绑且无人接手,归属与编辑权一起回落给带他进来的机构 | 9-15(此前"品牌方一律不能改"的表述作废,以本条为准) |
| 19 | 机构二维码管理页落在电脑端的机构管理里:机构详情内新增一个标签页「二维码与开通统计」,不单独开菜单。理由:码和开通统计本就是某一家机构的属性,与机构其他信息放一起最好找;日后若需跨机构统计(如各机构开通量排行),再单独做报表页,两者不冲突 | 9-15 |
| 20 | 不设名额上限、不做充值;按累计开通人数与机构结算(推翻早先"名额账户 + 流水"计费模型:规则 2/3/12 原文及 §5.1 名额账户表设计一律作废,改用开通记录表计数) | 9-15 |
| 21 | 4L 展示区排版已选定横排四格:另两版已比选弃用——2×2 网格信息量大但占地方,横滑胶囊在手机端 360px 宽度下只看得见前 2 项 | 9-15 |
| 22 | 任何机构都可开启品牌码,默认不开,由平台管理员在机构管理里开启,需二次确认 | 9-16 |
| 23 | 品牌码管理页为独立整页(非弹窗),导出口统一在页面右上角;openid 平台与品牌方均可见 | 9-16 |
| 事实 | 出处 |
|---|---|
users 表已有 wechat_unionid(唯一索引)/ wechat_openid_h5 / wechat_openid_miniapp / wechat_nickname / wechat_avatar |
app/models/user.py:38-42 |
席位微信绑定字段 seat_bound_unionid / seat_bound_openid / seat_bound_at |
app/models/user.py:94-104 |
公众号 OAuth 两步换取(snsapi_userinfo)+ 小程序 jscode2session 已实现 |
app/services/wechat_oauth_service.py:1-166 |
家长 OAuth 换 token 端点 POST /api/h5/oauth/exchange(拿 unionid → upsert_by_unionid 落库 → 发 JWT) |
app/api/h5_user_auth.py:49-90 |
家长子席位登录强制先做微信授权(seat_type == "parent" 且无 wx_identity_token → 403) |
app/api/seat_auth.py:309-325 |
| 家长端三条登录路径统一分流 | app/auth/middleware.py:157-319 |
推论(规则 6 能落地的根据):家长子席位登录本来就强制绑微信,所以老家长身上一定已经存着 unionid。他扫品牌码进来,拿到的 unionid 与 seat_bound_unionid 一比对就认出是同一个人 → 合并天然成立,不需要让家长手工输手机号找回。
开子席位的端点只有两个,都不在家长侧:
| 端点 | 鉴权 | 出处 |
|---|---|---|
POST /api/h5/store-subseat/provision(一次最多 20 个) |
require_store_seat(门店席位) |
app/api/store_subseat.py:1-70 |
POST /api/admin/parent-seats/provision |
require_role("admin")(平台后台) |
app/api/admin_parent_seats.py:1-40 |
品牌码扫进来的是陌生家长,门店和平台都没人给他开 → 48A 的核心工作量就是加一条「扫码自动开席位」的口子。
patients 表归属字段只有 4 个(app/models/flywheel.py:16-79):
| 字段 | 含义 |
|---|---|
org_id |
所属机构(示范档案为 NULL) |
owner_type |
seat=门店建档 / parent=家长自建 |
owner_seat_id |
家长子席位 id |
is_sample |
示范档案,全机构可见 |
过滤逻辑集中在 app/services/refractive_record_service.py:
- 门店视角:owner_type IN (NULL,'seat') ∪「被本机构家长席位绑定的档案」子查询(:98-106)
- 通用可见性:Patient.org_id == org_id OR is_sample(:142)
- 家长视角:owner_seat_id == 自己(:143-151、:524-555)
✅ 规则 7(已定案):org_id(谁带进来的)必须一直保留、门店认领动作不得改写它——否则解绑后就无法把可见性回落给品牌方,规则 7 的兜底会失效。机构认领只写 service_org_id(谁在服务他)。品牌方可见性判据 = service_org_id 为空时可见、有值时不可见,回落兜底由此天然成立,不需要额外逻辑。
source 不是数据库列,是运行时按 owner_type / creator_seat_type 算出来的值,两档:personal(家长自传)/ org(机构录入)——
app/api/parent_patients.py:316(档案级)、:603、:771(记录级)。⚠️ 别写成"字段已在用",避免后续开发以为能直接 SQL 按 source 查询。规则 11 = 维持不动。
| 方向 | 现状 | 判据 |
|---|---|---|
| 家长自建档案 → 机构可见 | 自动,不需要任何绑定动作 | _store_visible_clause(app/services/refractive_record_service.py:79-108):只要该档案 owner_seat_id 对应用户的 linked_org_id == org_id 且 seat_type=='parent' 即可见 |
| 机构建档案 → 家长可见 | 需要机构手动绑定,机构不绑家长永远看不到 | _patients_filtered_stmt:145-153 / get_org_patient:550-556,include_bound=True 时放宽为 Patient.owner_seat_id == owner_seat_id;该字段只能由 bind_patient_seat(:459-495,只改 owner_seat_id 一个字段)写入 |
| 谁能发起绑定 | 只有机构席位(require_store_seat),家长无入口、无同意/拒绝环节 |
app/api/refractive_records.py:169-182,文件头 :4-8 声明全端点 require_store_seat |
| 检查记录 | 档案可见后,家长能看到机构录的全部记录;机构看不到家长自录记录 | 门店端时间线 patient_timeline:640-646 对家长自录记录做了排除(_parent_created_clause:111-123) |
结论:互扫绑定(48B)本质是把机构手里那个"手动点绑定"换成"扫一下",不是从零造机制;但品牌码进来的家长,其席位属于品牌方(linked_org_id 指向品牌方),上表第一行的"自动可见"对他们不生效,因此扫码绑定对这类家长是必需的。
| 动作 | 内容 | 理由 |
|---|---|---|
| 新增字段 | patients.service_org_id(可空,指向机构) |
把「谁带进来的」和「谁在服务他」分开:org_id=品牌方(不动,保原义),service_org_id=当前绑定门店 |
| 新增表 | 机构码表(机构 id、码值、生成时间、启用状态) | 每个机构一个固定码,长期不变 |
| 新增表 | 开通记录表(哪个机构的码、微信标识 openid/unionid、扫码时间、激活时间、到期时间) | 规则 20 按累计开通人数与机构结算,统计与对账都从这张表出 |
| 新增校验 | 开通计数必须去重(同一微信 unionid + 同一机构码只计一次),防止重复扫码把账算重;仍需防范同一家庭用多个微信号反复扫同一张卡刷开通数;计数时点定在微信授权成功之后,授权失败不计 | 防刷 + 防重复计账 |
| 待明确 | patients.doctor_id 是 NOT NULL(app/models/flywheel.py:27),品牌机构扫码建档时该字段取值需明确(现有逻辑兜底到 Organization.doctor_id or 1) |
建档链路必过的坎,不明确会直接建档失败 |
⚠️ 换店只顶替 service_org_id,不动 org_id,所以「换回老店」天然成立(规则 10)。
refractive_record_service.py)| 角色 | 看得到什么 |
|---|---|
| 当前绑定门店 | 这孩子的全部检查记录(含在别家做的) |
| 曾经绑过、现在没绑的门店 | 只剩自己当初录的那几条 |
品牌方(org_id = 自己) |
他带进来的全部孩子 + 记录 |
| 家长 | 自己孩子的全部 |
⚠️ 改动范围提示:现有可见性过滤硬编码 Patient.org_id == org_id 的地方至少 6 处(refractive_record_service.py 的 get_org_patient:545、bind_patient_seat:470、unbind_patient_seat:511、_patients_filtered_stmt:142、:370、:599),引入 service_org_id 后这些点全部要改写,原方案低估了改动范围。
✅ 写权限已定案(规则 18):能看=能改。品牌方(org_id=自己)在孩子尚未被机构绑定期间能看也能改;一旦被某机构绑定,编辑权转移给当前绑定机构(曾经绑过、现在没绑的机构不能看也不能改);解绑且无人接手时,编辑权随归属回落给品牌方。上表「看得到什么」直接等同「改得了什么」,不再是两套规则。
| 端 | 加什么 |
|---|---|
| 家长端 | 扫码落地页(免注册进门)、「我的二维码」、「扫一扫」、4L 设备展示区(4 个灰框) |
| 门店端 | 「扫一扫」、「门店二维码」、扫到已绑别家时弹「该家长已绑定 XX 店,确认转入本店?」 |
| PC 后台 | 机构码生成/查看、开通统计与台账、扫码开通报表 |
流程:机构默认不开启品牌码。平台管理员在机构管理列表里点「开启品牌码」,弹二次确认(说明:生成专属码长期有效不换码 / 家长扫码微信授权免注册进家长端并计入该机构开通数 / 按实际开通人数结算不预设上限),确认后生成码并进入该机构的「品牌码与开通」整页。列表可按「品牌码状态:全部/已开启/未开启」筛选。
| 模块 | 内容 |
|---|---|
| 开启入口 | 机构管理列表按状态区分操作:已开通显示「品牌码」,点击直接进整页;未开启显示「开启品牌码」,点击先弹二次确认弹窗,确认后才生成码并跳转整页,取消则不生成码、不计入开通数 |
| 整页布局 | 独立整页(非弹窗),不新开菜单,同一套侧边栏 + 顶部面包屑可返回机构管理。左栏:品牌码图 + 下载图片 + 复制链接;右栏:状态(启用中)+ 开通时间 + 码链接 + 四个数字卡片(累计开通 / 本月新增 / 当前有效 / 30 天内到期)+ 近 30 天开通趋势小图;右上角:导出对账表(含 openid,导出格式 xlsx)+ 停用品牌码;下半区为开通名单 |
| 近 30 天开通趋势 | 选配:一期来不及可先不做,不影响主流程 |
| 扫码名单 | 微信头像 + 昵称、openid、开通时间(= 微信授权成功时刻)、到期日、孩子档案数、当前绑定机构、绑定时间、状态;不做手机号列 |
| 筛选与导出 | 按昵称搜索、状态/日期筛选;导出对账表(含 openid,导出格式 xlsx;对账表只统计开通个数,不含单价与金额,9-16 长官定;导出的开通时间与到期日只到年月日,页面名单显示到分钟;电脑端操作) |
| 权限 | 平台可看全部机构;品牌方只能看自己的码。openid 平台与品牌方均可见 |
| 端 | 电脑端,独立整页(非弹窗)。手机端不做该页 |
说明:到期日 = 开通时间 + 365 天。
技术可行性已核实:微信头像昵称能拿到(app/models/user.py:41-42 有 wechat_nickname / wechat_avatar,app/services/wechat_oauth_service.py 走 snsapi_userinfo)。
| # | 事 | 等谁 |
|---|---|---|
| 1 | 品牌方定制化到底定制哪些地方 | 商务先行,之后与客户开会 |
| 2 | 卡片美术统一还是一家一版 | 与品牌方开会后定 |
| 3 | patients.doctor_id 是 NOT NULL,品牌机构扫码建档时该字段取值需明确(见 5.1「待明确」行,现有逻辑兜底到 Organization.doctor_id or 1,能否直接沿用待长官确认) |
长官定,48A 建档链路必过的坎 |
(原「名额到底设不设期限」已由规则 8 拍板为 365 天,本轮从表中移除;原「4L 具体是哪四种」已查明并写入第一节,本轮从表中移除;原「品牌方能不能编辑档案」「写权限」已由规则 18 拍板——能看=能改,本轮从表中移除;原「4L 靠什么点亮」已由规则 17 拍板——家长自己绑定设备,本轮从表中移除;原「48A 和 48C 能否并行」随之解决——4L 展示区依赖"家长绑定设备"这条新链路,不依赖机构绑定,可与 48A 并行开发,本轮从表中移除;原「机构二维码管理页放手机端还是电脑端」已由规则 19 拍板为电脑端,本轮从表中移除)
最新效果图:brand-partner-mockup-v2-20260915.html(六节:扫码进门 / 4L 三方案 / 互扫绑定 / 条件表 / 一步绑定 / 机构管理列表含未开启态 → 开启确认弹窗 → 品牌码与开通整页·电脑端;原手机端机构码管理页节 9-15 已删除,管理页统一定为电脑端,见规则 19)
本方案为阶段 1 需求稿。长官确认后进阶段 2:出效果图 → 确认 → 阶段 3 技术方案 → 阶段 4 实施计划。