
私教频道改成「选课类 → 选教练 → 选商品」三步向导,教练详情页同步;本文是给实现方的完整规格。
先看结论和全流程;所有设计稿、配图和原型都在素材包里。
结论:私教频道从「所有课类和商品平铺在一页」改成三步向导:① 选课程类型 → ② 选教练 → ③ 选具体商品 → 去购买。从教练详情页进来时教练已定,跳过第 ② 步。原则是不删功能,只减信息,现有入口全部保留。

flow-overview.png)| 路径 | 内容 |
|---|---|
phones/*.png | 单屏设计稿 1170×2532(DPR 3),-full 是整页长图。实现以此为像素基准 |
flow-overview.png | 全流程总览 |
stack-swipe.png / .gif | Step 3 叠卡上下滑的分解帧和动图 |
assets/ | 课类场景图 type-*-v2.jpg、顶部大图 hero-gym.jpg、教练照 coach-*.jpg(原型样本)、icons/ 美团/点评/抖音图标 |
src/ | 原型:pages.html(浏览器直接打开,9 屏)、v3.js(组件 + 叠卡参数)、v3.css、common.js(TONES 色值、样本数据)、base.css;渲染脚本 render.js / render-full.js / qa.js / compose.py |
HANDOFF.md | 早一版的 Markdown 接手说明。与本文冲突时以本文为准 |
像素、颜色、圆角等细节以原型 src/v3.css、src/v3.js 为准(CSS px,按 390 宽设计;小程序换算 rpx 时 ×2,按 750 设计宽)。
4 张全宽照片大卡竖排,点卡是选中;底栏「下一步 · 选教练」才进入第 2 步。
| 项 | 规格 |
|---|---|
| 高度 | 236px;照片 hero-gym.jpg,object-fit:cover; object-position:55% 42% |
| 遮罩 | 由上到下加深:linear-gradient(180deg, rgba(10,8,12,.42) 0%, rgba(10,8,12,.55) 45%, rgba(10,8,12,.78) 100%) |
| 进度 | 3 段进度条 .prog,高 4px,激活段白色;旁边 STEP 1 / 3 |
| 标题 | 「想怎么练?」30px / 900 |
| 两个 pill | 「11.11 私教双11价 · 主会场 ›」(有活动才显示,跳现有会场);「已购 8 节 · 去约课 ›」(节数取真实数据,没有就不显示,跳现有约课) |
| 导航 | 返回 + 当前城市/门店切换(沿用现有门店选择弹层) |
| 项 | 规格 |
|---|---|
| 布局 | 竖排、全宽;整个列表 margin-top:-28px 压到 hero 底边上;卡间距 10px |
| 尺寸 | 每张高 156px,圆角 22,阴影 0 8px 20px rgba(40,20,10,.14) |
| 照片 | 铺满整张卡 object-fit:cover,默认 object-position:85% 40%;时长限次课用 85% 18%,否则切到脸 |
| 左色渐隐 | linear-gradient(90deg, fade 0%, fade 38%, rgba(0,0,0,.55) 58%, rgba(0,0,0,.15) 78%, transparent 100%),fade 色见下表 |
| 文字区 | max-width 62%,padding 18,垂直居中。从上到下:标签(高 18,10px/800,白 18% 底)→ 类型名 22px/900 带 text-shadow → 卖点 12px/600 → 起价 20px/900(单位 11px) |
| 选中态 | box-shadow: 0 0 0 2px #fff, 0 0 0 3.5px #e0231c, 0 10px 24px rgba(200,40,30,.2);右上角 24px 白圆钮内红色 ✓(top/right 12) |
| 交互 | 点卡片=选中(单选),不跳转。某类没有商品时整张卡不显示 |
| 列表下方 | 弱链接「为什么选私教?… ›」 |
| 类型名(按顺序) | 标签 | 卖点(暂定) | 价格 |
|---|---|---|---|
| 1. 时长限次课 | 限次划算 | 次数+有效期打包 · 送会员权益 | ¥1,899起 |
| 2. 私教时长卡 | 高频推荐 | 30-360 天 · 一天一节高频练 | ¥2,399起 |
| 3. 1v1单次课 | 灵活约课 | 按节购买 · 时间灵活 越买越省 | ¥88/节起 |
| 4. 私教体验 | 新人专享 | 新人首节 · 含体测与训练方案 | ¥300 |

type-pack-v2.jpg · 位置 85% 18% · 左色 #2a1848
type-pass-v2.jpg · 位置 85% 40% · 左色 #5c1412
type-1v1-v2.jpg · 位置 85% 40% · 左色 #161d2c
type-trial-v2.jpg · 位置 85% 40% · 左色 #7a3a22四张课类配图都是东亚面孔,按产品场景生成(见第 07 章)。排序沿用设计稿:时长限次课 → 私教时长卡 → 1v1单次课 → 私教体验。
| 项 | 规格 |
|---|---|
| 定位 | position:fixed 底部,z-index:20;纯白 #fff,不透明,滚动内容不能从底栏透出 |
| 尺寸 | padding 12px 14px 30px(含安全区,小程序用 env(safe-area-inset-bottom));上沿阴影 0 -8px 24px rgba(120,40,20,.08) |
| 左侧 | 团购券兑换:美团/点评/抖音三个图标 +「团购券 / 去兑换 ›」,照搬现有实现,不改(CDN 图标 + toExchange,位置见第 06 章) |
| 主按钮 | 高 50,圆角 25,linear-gradient(90deg,#ff6a3c,#e0231c),16px/800 白字。Step 1 文案「下一步 · 选教练」 |
3×3 宫格,首格固定「不指定教练 · 门店安排」;选中后可进教练主页。
| 项 | 规格 |
|---|---|
| hero | 高 190(无照片,深色渐变),标题「选教练」+ 已选课类 chip;STEP 2 / 3 |
| 宫格 | grid-template-columns:repeat(3,1fr),gap 12px 10px。不能做成横滑 |
| 头像格 | 高 108,圆角 20,照片 object-position:50% 14%;下方名字 14px/800 + 第一个标签 11px 灰;选中时右上角 22px ✓ + 红环 |
| 第 1 格 | 固定「不指定 · 门店安排教练」:红色渐变底 linear-gradient(160deg,#b8342c,#7e1b17),带「推荐」角标;格下文字「不指定教练 / 到店按时间安排」。用于推不绑定教练的课程 |
| 数量 | 最多显示 8 位教练 + 首格;超过 8 位显示「查看全部 N 位教练 ›」 |
| 已选条 | 选中某位教练后在宫格下方出现:头像 + 名字 + 标签 + 上课节数 + 「教练主页 ›」(跳现有教练详情页)。选「不指定」时不显示 |
| 门店行 | 「上课门店:xxx 切换」,切换沿用现有门店选择弹层 |
| 底栏 | 团购券 +「上一步」幽灵按钮 + 主按钮。主按钮文案跟课类:时长卡 →「下一步 · 选时长」;限次课 →「下一步 · 选套餐」;单次/体验 →「下一步 · 选课程」 |
| 数据 | 现有门店教练列表接口(头像、名字、标签、上课节数),不改接口 |
选「不指定教练」时,第 3 步只列不绑定教练的门店商品;具体取哪个接口、下单参数怎么传,以现有私教频道(不选教练时)的逻辑为准,不新增后端改动。拿不准就停下来问 William。
按课类换不同的选择方式:时长卡用叠卡上下滑,限次课用套餐卡,单次和体验用行卡。

| 项 | 规格 |
|---|---|
| 容器 | 高 STK_H=380;每张卡 left/right 0,高 200(前卡 214),圆角 24,transform-origin:50% 0,边框 1px solid rgba(255,255,255,.5) |
| 后卡 | 只露出 46px 的 peek 条:名称(15px/900)/ 天数 chip / 价格(18px,靠右) |
| 前卡卡面 | 整面铺商品信息,不是空色块:名称 + 活动标签(如「双11」)、「一天一节」、「共约 N 节 · 一天一节」(N=天数)、现价、划线原价、右侧大号「N 天」;选中时右下 ✓ |
| 卡面底色 | TONES 渐变 + 右上柔光 radial-gradient(120% 90% at 92% 0%, rgba(255,255,255,.28) 0, transparent 55%),与 src/pages/card/cardFaceArt.ts 对齐(见下表) |
| 倒计时 | 顶部「⏱ 双11价 … 后失效」,有活动才显示 |
| 提示文案 | 叠卡下方随阶段变:「上下滑动切换 · 当前 X」/「松手吸附 · 即将选中 X」 |
| 底栏 | 「商品名 · 教练名」(最多两行)+ 现价 +「去购买」,实时跟随当前前卡 |
| tone | 渐变(135deg) | 样本商品 |
|---|---|---|
| month | #c8443a → #7e1b17 | 私教月卡 |
| quarter | #4f6a58 → #24322b | 私教季卡 |
| half | #3b4f7a → #1c2540 | 私教半年卡 |
| year | #3d3934 → #121312 | 私教年卡 |
| 阶段 | {卡序号, top px, scale}(来自 v3.js stack()) |
|---|---|
| rest | {3, 0, .92} {2, 46, .95} {1, 92, .98} {0, 148, 1 前卡} |
| mid 上滑中 | {3,0,.92} {2,46,.95};当前卡下沉 {0, 188, .96, 高 200, brightness(.92)};下一张抬起 {1, 108, .99, 高 210, rotate(-1.2deg), 阴影 0 26px 44px rgba(40,20,10,.36)} |
| mid2 将吸附 | {3,0,.92} {2,46,.95} {0, 94, .97 peek};{1, 148, 1, rotate(-.4deg), 阴影 0 22px 40px rgba(40,20,10,.32)} |
| selected | {3,0,.92} {2,46,.95} {0, 92, .98} {1, 156, 1, z-index 9, 前卡右下 ✓} |
transform / opacity,保证 60fps(小程序优先 movable-view 或 WXS 手势,避免每帧 setData)。原型里「私教季卡」卡面还留着一个 IC 芯片小图形(faceFull 里的 .chip),实现时去掉,所有卡面都不要芯片。
| 项 | 规格 |
|---|---|
| 03d 套餐卡 | 每个套餐一张卡:卡面写名称(接口原值)、节数摘要、右侧大数字(节数)+「次」;卡下方现价、「立省 ¥x」、「限购」、「赠 …」(赠品天数取 expireDays 或 days);选中态红环 + ✓ |
| 03e 行卡 | 横向行卡:左侧小卡面写节数,中间 courseName + 摘要,右侧价格(有原价时划线)。私教体验每人限购 1 次,已购或不符合条件时置灰不可选 |
| 底栏 | 「商品名 · 教练名」+ 价格 +「去购买」;点「去购买」走现有下单流程 |
教练已确定:页内直接用 Step 1 的同一种大卡选课类,下一步直达第 3 步。
| 项 | 规格 |
|---|---|
| 头部 | 教练照片 hero 高 248,下方压一张玻璃信息卡:名字、标签、「打电话」、门店、上课节数、证书 |
| 资质 | 资质与介绍折叠成一行「展开 ›」,展开后显示现有内容(不删) |
| 选课区 | 标题「跟 COCO 练」(COCO=教练名),副文案「已选教练,跳过第 2 步」;步骤提示:① 选课程 · |
| 课类卡 | 和 Step 1 同一个组件(156px 大卡,不用 compact 72px 版),只列出该教练有商品的课类,默认选中第一张有商品的 |
| 底栏 | 团购券 + 单行「私教时长卡 · COCO」(white-space:nowrap)+「¥2,399起」+「下一步 · 选时长」;gap:8px,CTA padding:0 16px |
| 跳转 | 点下一步直接进 Step 3,教练带入(不经过 Step 2) |
类型名照 master,商品名照接口原值;页面上所有价格、教练、节数都取接口。
四个类型名只能用下面这几个写法,不要自造(如「超值课包」「季卡」):
| 类型名 | master d216857src/pages/pt/ | 提交 30cc963src/pages/pt/ | coach/index.vue (30cc963) |
|---|---|---|---|
| 时长限次课 | pt/index.vue:77 | pt/index.vue:84 | coach/index.vue:108、:374 |
| 私教时长卡 | :116、CATS :345 | :124、:365 | :368、:375 |
| 1v1单次课 | :126、CATS :344 | :136、:364 | :369、:376 |
| 私教体验 | :136、CATS :343 | :148、:363 | :370、:377 |
master 上 coach/index.vue 对应位置:sec-title :105,courseSections :351-353,catTabs :357-361。路径都相对 src/pages/。
商品名不改写、不缩写、不截断后再拼接,原样显示 pkg.name / course.courseName。样本:60次半年卡(双11)、私教包月限次(月卡)、私教月卡、私教季卡、私教半年卡、私教年卡、私教常规单次课(10节起)、线上平台新用户-私教体验1次。
| 位置 | 字段 / 来源 |
|---|---|
| 01 起价 | 时长限次课:overview.packageList 最低 pkg.price;时长卡:overview.monthlyMinPrice;1v1:overview.timesMinPrice(/节起);体验:overview.trialMinPrice。赋值见 master pt/index.vue:952-954、:972(30cc963 为 :972-974、:992) |
| 01 显隐 | 对应列表或价格为空 → 隐藏该卡 |
| 01 已购节数 | 沿用现有「去约课」的数据来源;没有就不显示 pill |
| 02 教练 | 现有门店教练列表接口:头像、名字、标签、上课节数 |
| 03a-c 叠卡 | 时长卡商品列表(教练页为 info.coachCourseTime):名称、天数、现价、划线价 |
| 03d 套餐 | pkg.name / pkg.price / pkg.originPrice;赠品天数 expireDays 或 days;可买判断沿用 comboBuyable(pkg);教练页为 comboList |
| 03e 课程 | course.courseName / course.coverImg / 价格;教练页 info.coachCourseNum 中 type==1 && isTrial!=1 → 1v1,isTrial==1 → 体验 |
| 底栏兑换 | master pt/index.vue:280-284(30cc963 为 :300-304)原样:CDN 图标 cdn.hellolianer.com/miniapp/user/icon-{meituan,dianping,douyin}.png + @click="toExchange" |
| 下单 | 「去购买」后的下单、支付、双11 名额逻辑全部沿用现有代码,不改 |
原型里的价格、教练、节数、门店都是样本值,实现时全部取接口,不要把样本写死。
卖点文案和配图都按产品真实用途来;下面的规则是 William 定的硬要求。
| 类型 | 用途 / 适合谁 |
|---|---|
| 私教时长卡(包月卡) | 有效期内一天一节。适合刚开始练、希望教练全程带、接下来有大块时间练的人。性价比高、见效快,练得越多越赚。有效期内可随时进场自练 |
| 时长限次课 | 有效期内 X 节(例如 30 天 10 节)。适合时间没那么多、课外自己也练的人。比包月更划算,有效期内可随时进场自练 |
| 1v1单次课 | 买了没有有效期,约课最灵活,适合忙碌人群。不含进场权益,自己进场训练要另买场次会员卡 |
| 私教体验 | 只给从没上过私教的用户,每人限购 1 次 |
双11主会场、已购去约课、团购券兑换、切换门店、教练主页这些入口全部保留;减的是一屏里同时出现的文字和商品数。页面要留白、不密集。
首格固定「不指定教练 · 门店安排」,用来推不绑定教练的课。选中教练后要能进教练主页。
类型名 = master 现有叫法;商品名 = 接口原值。
用素材包 assets/type-*-v2.jpg;不要堆 AI 背景图,课类卡之外的卡面用纯渐变。正式上线换成 CDN 图,路径需 William 确认。
不要 SVG 手绘涂鸦、实线竖线、奇怪底纹、IC 芯片、英文水印或英文装饰词;不要大段纯白、平淡的版式。质量对标「会员卡」页,卡面参考 src/pages/card/cardFaceArt.ts(TONES)。
底栏左下美团/点评/抖音图标和跳转照旧,不改成纯文字。
DPR ≥ 3 的 PNG 真机/模拟器截图,不放大。
从 master 起分支实现;不上传体验版、不合并、不发生产,这些都等 William。
| 项 | 说明 |
|---|---|
| 仓库 | lianer/lianer-user-app(uni-app 微信小程序) |
| 起点 | 从 master 开新分支(基线 d216857)。本文就是需求来源 |
| 已有本地工作 | feat/pt-course-display 有一个本地提交 30cc963(私教频道/教练详情扁平化改版 + 双11引导条,仅 src),还没推到 GitLab。共享电脑上有 git bundle /workspace/pt-redesign.bundle(含 30cc963 和设计稿提交 1eafd79),有权限可以 git fetch 它参考;拿不到就只按本文实现 |
| 改动范围 | src/pages/pt/index.vue(私教频道)、src/pages/coach/index.vue(教练详情)及其组件;课类大卡做成一个共享组件,两页共用 |
| 构建 | test2:pnpm run build:test(= uni build -p mp-weixin --mode test + scripts/trim-mp-dist.js) |
| 原型 | 浏览器打开素材包 src/pages.html;重新渲染:PLAYWRIGHT=<playwright 路径> node src/render.js $PWD/src/pages.html phones/(DSF=3) |
| 事项 | 现状 |
|---|---|
| 卖点文案 | Step 1 卖点可能按第 07 章场景重写(例如单次课写明不含进场),等 William 定稿 |
| 1v1 有效期 | master 上 1v1单次课的角标是「限时两年」,而产品语义是「没有有效期」。设计稿标签用「灵活约课」,不要写「限时两年」;最终说法问 William |
| 角标与单位 | 设计稿标签(限次划算/高频推荐/灵活约课/新人专享)和 master 现有角标(NEW/一天一节/限时两年/新人专享)不同;时长卡价格单位设计稿是「起」,master 是「/月起」。默认按设计稿 |
| 配图 | hero 图和私教时长卡配图都是教练带练深蹲,可能再换;正式 CDN 路径未定 |
| 季卡芯片 | 原型 03c 私教季卡卡面的 IC 芯片,实现时去掉 |
| 叠卡手感 | 吸附阈值、动效时长要真机调 |
phones/ 对比,无溢出、无遮挡、无横向滚动。pnpm run build:test 通过。不要上传体验版、不要推 release、不要合并主干、不要触发生产发布。做完 test2 构建和截图自测后,把截图和改动说明交给 William 确认。