Files
YelayMaths/docs/课程上线指南.md
T
2026-10-01 07:36:39 +08:00

11 KiB
Raw Permalink Blame History

课程上线指南

面向「要往小程序里上一门新课」的人。按第 7 节的顺序做,每一步都有验证方法。


0. 先理解三件事

  1. 数据分两处:课程 / 课时的文字信息在数据库里(管理后台改的就是它); 视频和图片在数据端,是磁盘上的文件。
  2. 付费课时不是 mp4,是 HLS 目录(一个 playlist.m3u8 + 一堆 .ts 分片)。
  3. 媒体文件不在云服务器上。数据域名整站反代到隧道另一端(NAS),服务端播放视频也走同一条路。 所以文件最终要落到 NAS 上对应的目录里,放对位置就立刻生效。

⚠️ 目前还没有后台上传功能。文件要手工(或打包成 zip)放到 NAS 的对应目录, 再回管理后台填表单。


1. 三个不能随便起的名字

这三个名字一旦定下来就不要改,它们是文件路径的一部分:

名字 同时还是
courses.code 视频目录名 Course/{code}/ 和封面名 Course/{code}.png
lessons.chapter_id 目录中的一级:Course/{code}/{chapter_id}/
lessons.play_id 目录中的二级:Course/{code}/{chapter_id}/{play_id}/

改其中任何一个,已经发出去的播放地址、封面、以及用户端的缓存全部失效。

另外一批名字是拼出来的,由后台填的文字决定,同样不能随手改:

小程序里的地址 由什么拼出来
Course/{code}.png 课程 code
Images/NewCourse/{条目名}.png 首页新课的 course_name
Images/FreeCourse/{条目名}.png 首页试听的 course_name
Images/Banner/{文件名} 轮播图的 filename(含扩展名)
WebPages/{网页id}.png 文章的 legacy_page_id

现网示例:code 是 64 位十六进制,chapter_id 是 1、2、3, play_id 是 13 位十六进制(如 65eefb35e29da)。


2. 要准备的文件

假设新课的 code 是 AbC...(64 位),有三个章节、每章两个课时:

Course/AbC....png                                  ← 课程封面,1 张
Course/AbC.../1/65eefb35e29da/playlist.m3u8        ← 课时 1
Course/AbC.../1/65eefb35e29da/0000.ts  0001.ts ... ← 该课时的分片
Course/AbC.../1/65eefb35e29db/playlist.m3u8        ← 课时 2
Course/AbC.../2/65eefb50f02b5/playlist.m3u8        ← 课时 3
...

如果这门课还要上首页,另外准备:

用途 文件 引用方式
首页「新课上线」列表图 Images/NewCourse/{条目名}.png 按 course_name 拼
首页「新课上线」长图内页 Images/NewCourseWebPages/{分组名}/{n}.png 写在长图 HTML 里
首页「试听」列表图 Images/FreeCourse/{条目名}.png 按 course_name 拼
免费试听视频 FreeVideos/{任意目录}/{任意名}.m3u8 + 分片 路径存在数据库字段里

图片规格参考

  • 课程封面:现网是 900×500(后台卡片按 9:5 显示,整张完整展示不裁剪)。
  • 新课长图:现网每张 800px 宽,高度按内容(实测一张 800×564)。所有图宽度保持一致。
  • 首页列表图:按名称拼 .png,建议和长图同宽或按 2 倍图准备。

3. HLS 打包要求

现网一个真实的 playlist.m3u8:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:4
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:4.166667,
0000.ts
#EXTINF:4.166667,
0001.ts

四条硬要求:

  1. 分片引用必须是相对路径(0000.ts),不能写 http://... 绝对地址。 服务端会给每一行分片单独签名,绝对地址会被跳过——防盗链直接失效,播放器还会绕过服务端直连。
  2. 文件名必须叫 playlist.m3u8。这个名是服务端写死的,不是数据库里的字段。
  3. 目录名只用字母数字。chapter_id / play_id 参与播放地址的拼接与签名,中文和空格容易踩坑。
  4. 目录里不要放无关文件,整棵目录树都在签名保护下。

其余参数(切片时长、编码、加密)没有强制要求,按上面的形状切即可。 如果做了 HLS 加密,.key 文件要放在同一目录树内,EXT-X-KEY 的 URI 也用相对路径。


4. 首页新课长图的内容要求

「长图」不是一张图片文件,而是 home_courses.content 里的一段 HTML, 服务端原样返回,小程序用内置的 Parser 组件渲染。现网真实内容:

<p style="font-size: 0; margin: 0; padding: 0;">
<img src="https://<数据域名>/Images/NewCourseWebPages/几何模型/1.png"/>
<img src="https://<数据域名>/Images/NewCourseWebPages/几何模型/2.png"/>
<img src="https://<数据域名>/Images/NewCourseWebPages/几何模型/3.png"/>
</p>

要求:

  1. 图片必须是绝对 URL(带 https://<数据域名>)。写相对路径会裂图——小程序会把 /xxx.png 当成包内的本地文件。
  2. 外层 <p> 必须带 font-size: 0(通常还带 margin:0; padding:0)。少了它,图与图之间会露出白缝,长图就断了。
  3. 不要给 <img> 写 width / height。渲染时会自动补 width:100% 按屏宽缩放;写死像素宽度会溢出屏幕。
  4. 底部要留白。长图页底部钉着两个悬浮按钮(购买 / 咨询客服),末尾留一段空白,否则按钮压住内容。
  5. 只能放静态标签。<script>、<iframe>、<video> 不会执行。
  6. 长图里的图片路径是手写在 HTML 里的,改名或挪目录内容不会跟着变,会直接 404。所以图片一次定稿再填。

5. 后台要填的表单

课程(管理后台 → 课程)

字段 说明
code 64 位十六进制串,创建后不可改
title 课程名
intro 一句话介绍
price_fen 价格,单位分(1.10 元填 110)
status / sort_order 上架状态、排序

课时(管理后台 → 课时,每个视频一行)

字段 说明
course_id 所属课程
chapter_id / play_id 必须和磁盘目录逐字对应
chapter_title / lesson_title 章节名、视频名
duration 现网存的是分钟数,如 14、21
published_at / sort_order 发布日期、排序

约束:(course_id, chapter_id, play_id) 唯一——同一章里不能有重复的 play_id。

支付商品(管理后台 → 支付商品,要卖就得填)

字段 说明
course_id 对应课程
wx_product_id 微信后台的道具 ID
price_fen 必须和微信后台道具价格完全一致,否则下单会被拒
name / status 商品名、是否启用

首页新课(管理后台 → 首页新课,要上首页才填)

字段 说明
course_name 条目名,决定列表缩略图 Images/NewCourse/{条目名}.png
content 第 4 节那段长图 HTML
course_id 关联到可购买的课程;留空则长图页不显示购买按钮,只剩客服按钮
intro / published_at / sort_order / status 列表展示用

首页试听(管理后台 → 首页试听 + 免费试听课)

  • 首页试听:series_no(要和免费试听课的序号对上)、course_name(决定 Images/FreeCourse/{条目名}.png)、排序、状态。
  • 免费试听课:series_no、course_name、video_title、duration、video_m3u8(如 FreeVideos/9102/9102.m3u8)、cover_image(如 Images/FreeCourse/xxx.png)。 这两个字段是数据库里存的全路径,不是拼出来的,可以自由命名。

注意:课程表 / 首页新课 / 课时表里都有一个「封面文件 / cover_image」字段, 接口目前不使用它们,真正生效的是第 1 节里「拼出来的」那些地址。 只有免费试听课的 cover_image 是真正生效的。


6. 微信小程序后台要先做的

要在小程序里卖这门课,必须先建支付道具:

  1. 【虚拟支付 → 道具管理】新建道具,拿到道具 ID 与价格。
  2. 价格记下来,后台「支付商品」里要填一模一样的分值。
  3. 道具建好后要发布,未发布的道具下不了单。

7. 操作顺序

步骤 做什么 怎么验证
1 微信后台建支付道具,记下道具 ID 和价格 道具状态是已发布
2 定下课程的 code(64 位十六进制) ——
3 把封面和所有课时目录放到数据端对应路径 浏览器直接打开 Course/{code}.png 能显示
4 后台建课程行,code 填上面那个 小程序「知识」页能看到课程、封面正常
5 后台建课时行,chapter_id / play_id 和目录逐字对上 买过课之后能播放;没买时报「尚未拥有该课程」
6 后台建支付商品行,价格与微信一致 走一笔小额真实订单,能下单成功
7 首页要展示的话,建首页新课 / 首页试听并填长图 首页能看到条目、点进去长图完整、底部按钮不挡内容
8 课程 status 改为 1(上架) 小程序下拉刷新后可见

⚠️ 上架前先确认后台左上角的「查看的数据源」是生产库。 后台有两个概念:「查看的数据源」(只影响你自己看到什么)和「线上小程序数据源」(影响所有用户)。 在开发库建的课程,用户在线上是看不到的。


8. 上线后验证清单

  • 首页能看到新课条目,缩略图正常
  • 点进长图页:图片连成一张、没有白缝、底部按钮不挡住内容
  • 长图页的「立即支付」按钮存在(说明 course_id 关联上了)
  • 「知识」页能看到这门课的封面
  • 未购买的账号点课程,看不到课时列表
  • 走一笔小额真实支付:能拉起支付 → 支付成功后课程出现在「已购」里
  • 已购账号能播放每一个课时(不是只测第一个)
  • 后台「订单」页能看到这笔订单,状态「已开通」
  • 后台「数据看板」的累计订单 +1、成交金额增加

9. 常见坑

现象 原因 处理
封面 404 文件名和 code 对不上,或图片没放上去 地址必须是 Course/{code}.png,逐字核对
播放地址 404 / 播不了 chapter_id、play_id 和目录名不一致 三处(数据库、目录、表单)必须逐字相同
长图断了、有白缝 外层 <p> 少了 font-size: 0 见第 4 节
长图裂图 图片用了相对路径 必须写完整的 https://<数据域名>/...
换了同名图片但没变 数据端对图片有 1 分钟缓存 等 1 分钟,或清 Nginx 缓存后 reload
换了同名视频但播还是旧的 播放地址响应头带 5 分钟缓存 等 5 分钟;播放地址本身有效期是 30 分钟
下单提示「该课程尚未配置支付商品」 products 里没有启用的商品行 见第 5 节
下单后拉不起支付 微信道具没发布,或价格与后台不一致 见第 6 节
长图页没有购买按钮 home_courses.course_id 为空 填上关联课程
改完没生效 后台看的是开发库 切回生产库再操作

10. 相关文档