交付出件箱

← 返回出件箱

品牌方合作 · 正式方案 v1(Phase 48)

日期: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 编号与拆分

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

四、技术现状(已物理核实)

4.1 好消息:微信认人这套已经在生产跑了,不是新造

事实 出处
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 一比对就认出是同一个人 → 合并天然成立,不需要让家长手工输手机号找回。

4.2 真缺口:家长自己开不了席位

开子席位的端点只有两个,都不在家长侧:

端点 鉴权 出处
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 的核心工作量就是加一条「扫码自动开席位」的口子。

4.3 档案归属与可见性现状

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 为空时可见、有值时不可见,回落兜底由此天然成立,不需要额外逻辑。

4.4 记录来源标记已存在

source 不是数据库列,是运行时按 owner_type / creator_seat_type 算出来的值,两档:personal(家长自传)/ org(机构录入)——
app/api/parent_patients.py:316(档案级)、:603、:771(记录级)。⚠️ 别写成"字段已在用",避免后续开发以为能直接 SQL 按 source 查询。规则 11 = 维持不动。

4.5 家长 ↔ 机构 互看档案的现状(已 grep 核实)

方向 现状 判据
家长自建档案 → 机构可见 自动,不需要任何绑定动作 _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 指向品牌方),上表第一行的"自动可见"对他们不生效,因此扫码绑定对这类家长是必需的。


五、要新建 / 要改的东西

5.1 数据层

动作 内容 理由
新增字段 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)。

5.2 可见性规则改写(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=自己)在孩子尚未被机构绑定期间能看也能改;一旦被某机构绑定,编辑权转移给当前绑定机构(曾经绑过、现在没绑的机构不能看也不能改);解绑且无人接手时,编辑权随归属回落给品牌方。上表「看得到什么」直接等同「改得了什么」,不再是两套规则。

5.3 前端

端 加什么
家长端 扫码落地页(免注册进门)、「我的二维码」、「扫一扫」、4L 设备展示区(4 个灰框)
门店端 「扫一扫」、「门店二维码」、扫到已绑别家时弹「该家长已绑定 XX 店,确认转入本店?」
PC 后台 机构码生成/查看、开通统计与台账、扫码开通报表

五之二、机构品牌码管理页(长官 9-15 提出,9-16 补充开启流程与整页排版)

流程:机构默认不开启品牌码。平台管理员在机构管理列表里点「开启品牌码」,弹二次确认(说明:生成专属码长期有效不换码 / 家长扫码微信授权免注册进家长端并计入该机构开通数 / 按实际开通人数结算不预设上限),确认后生成码并进入该机构的「品牌码与开通」整页。列表可按「品牌码状态:全部/已开启/未开启」筛选。

模块 内容
开启入口 机构管理列表按状态区分操作:已开通显示「品牌码」,点击直接进整页;未开启显示「开启品牌码」,点击先弹二次确认弹窗,确认后才生成码并跳转整页,取消则不生成码、不计入开通数
整页布局 独立整页(非弹窗),不新开菜单,同一套侧边栏 + 顶部面包屑可返回机构管理。左栏:品牌码图 + 下载图片 + 复制链接;右栏:状态(启用中)+ 开通时间 + 码链接 + 四个数字卡片(累计开通 / 本月新增 / 当前有效 / 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 实施计划。