拓冰建站拓冰建站
首页 / 资讯中心 / 正文

PHP开源知识付费平台:融合在线考试与轻量教学系统的设计与实践

市面上打着“知识付费”旗号的开源系统我前前后后摸过差不多二十来套。要么Java系全家桶重得离谱一个小机构租台2核4G服务器跑起来都喘要么打着轻量的旗号实际拆开源码发现前端依赖比后端还重改个首页配色得先学一门前端框架。做技术选型的人最怕这种“伪轻量”。所以当我决定自己攒一套PHP开源的知识付费平台时给团队定的调子是够用、能跑、好改、不装。这套系统把我最看重的三件事揉在了一起——知识付费、H5在线考试、轻量级在线教学。核心语境是老师不用懂运维学生不用装App机构不用养技术团队。你拿到源码部署到一台廉价云主机上当天就能把课程上架、把考试发出去、把学员管理起来。这篇文章不讲虚的就聊聊这套系统背后那些非写不可的设计以及我踩过的坑。1. 一拖三的项目形态知识付费、考试、教学到底怎么揉在一起1.1 三个模块不是拼凑是同一套用户体系的三种出口很多人看到“知识付费平台在线考试系统在线教学系统”这种三合一标题第一反应是这不就是把三个开源项目缝到一起吗真不是。这三个模块如果不能共享一套用户体系、一套订单逻辑、一套权限模型那部署成本和维护成本会成倍往上翻。我设计的核心思路是用户表是圆心课程、订单、考试、学习记录全部围绕用户ID建模。一个学员在平台上的完整路径是这样的——注册登录后浏览课程列表试看免费课时下单购买课程然后进课程详情页学习与此同时如果课程附带了结业考试学员可以直接从课程页跳转到试卷页完成考试考试成绩合格系统颁发一个电子结业标识。整条链路里学员只登录了一次机构只发了一次课程订单只产生了一笔但是知识付费、在线教学、在线考试三个模块全部跑通了。这里有一个非常重要的产品逻辑考试系统不能独立存在它必须挂靠在课程或证书体系下。纯做考试系统不是不行但脱离教学场景的考试没有留存价值。学员学完课程再去考试这是强相关场景考试通过率直接反映课程质量考试成绩也可以反过来帮机构优化教学内容。我把考试模块设计成课程的可选附件上架课程时可以勾选“本课程包含结业考试”这样的耦合方式比硬把三个系统缝在一起自然得多。1.2 这套系统的适用边界别拿它跟定制SaaS比从定位上说这套系统瞄准的是中小型知识付费场景——个人讲师、培训机构、企业内部培训部门、职业学校实训基地。有公开课、有付费课、有考试、有简单的学员管理。这些需求看起来很朴素但市面上能开箱即用的开源方案极少。它不适合谁大型教育集团、多校区连锁机构、需要直播互动和排课调度的复杂场景。这些需求需要的是商业级SaaS或者完全定制开发靠一套PHP开源项目硬撑后期必然痛苦。但反过来如果你的核心诉求是“快速上线、成本可控、源码可改、数据自主”这套系统的性价比就非常高了。1.3 与重型系统的真实差距用表格说话我对比了几个维度的差异对比维度本系统PHP轻量方案重型SaaS平台部署成本一台2核4G云主机即可一般需要多服务器集群月度成本服务器费用约几十元年费数千到数万数据所有权完全自主存放在平台方二次开发门槛PHP MySQL适合个人开发者多语言微服务需要团队直播/教务排课不支持支持或可扩展移动端微信内置浏览器打开即用H5通常有独立App/小程序差距客观存在但目标用户完全不同。这套系统的核心价值在于低成本试错——你今天搭起来明天就能开始卖课后期业务起来再迁移重型平台也不迟数据都在自己手里随时可以导出迁移。2. 技术选型的真实取舍为什么是PHP 8 H5而不是别的组合2.1 PHP 8.0低频高可靠场景的务实选择选PHP不是因为它最先进而是因为在“知识付费考试系统”这个赛道上它的综合成本最低。PHP 8.0加入了JITJust-In-Time编译器性能相比PHP 7.x有了明显提升日常跑一套教务系统的并发量完全够用。而且PHP的部署曲线非常平缓LNMP环境一条命令装完代码丢进web目录就能跑不需要编译、不需要配置复杂的应用服务器。对比一下Java/Spring Boot性能强、生态全但遇到小需求改个字段要重新打包、重新发布迭代成本高。Node.js适合高并发I/O密集场景但长任务处理和CPU密集运算不是强项而且回调式编程维护起来对新手不友好。PHP请求处理完就销毁进程天然不会内存泄漏改完代码刷新即生效开发调试效率极高最重要的是PHP开发者市场供给充足后续找人维护便宜好找。考试系统低并发高可靠知识付费业务峰值波动大但瞬时压力并不高PHP的性能模型完全匹配这类场景。2.2 H5是运营策略问题不是技术问题很多人在“小程序还是H5”之间纠结。我的答案很直接内容型知识付费先上H5。原因有三第一微信内置浏览器对H5非常友好用户从公众号、微信群、朋友圈点开链接就能上课不需要跳转小程序、不需要识别二维码转化路径最短。第二H5的开发成本只有小程序的三分之二左右一套代码同时覆盖PC端和移动端考试系统在PC上答题的体验还更好。第三小程序封禁风险不可控。你做知识付费课程里可能涉及各种形式的媒体内容小程序对虚拟支付和内容审核的限制远多于H5。H5挂在自建服务器上自主权大得多。2.3 前端方案不引重型框架用原生加轻量工具库后端选定PHP后前端没有上Vue或React全家桶而是用了一套更务实的组合原生HTML/CSS/JavaScript学习成本低接手容易引入jQuery 3.x做DOM操作和AJAX封装——你可以在2025年嘲笑它老但你不得不承认它兼容性好、行为可预期尤其在微信内置浏览器这个环境里选Bootstrap做响应式栅格布局配合自定义CSS变量做主题切换这样做的最大好处是任何会基础前端的开发者都能快速上手改样式。我见过太多技术团队把简单项目搞复杂——为了一个课程列表页面引入整个Element UI组件库页面是漂亮了但每次构建都要等两分钟。这套系统坚持不构建直接在浏览器里跑改完刷新就能看到效果。3. 数据库设计让订单、课程、考试、学员四张网联动起来3.1 核心表结构化繁为简的范式与冗余整个系统的数据模型可以拆成四条主线用户线、课程线、交易线、考试线。考试线再往下分题库、试卷、考试记录三张表。用户线比较简单users表存基础信息user_course关联表记录用户购买或获赠的课程权限user_exam关联表记录用户与考试的关系。课程线是内容管理的骨架-- 课程表 CREATE TABLE course ( id int(11) unsigned NOT NULL AUTO_INCREMENT, title varchar(200) NOT NULL COMMENT 课程标题, subtitle varchar(500) DEFAULT NULL COMMENT 副标题, cover varchar(500) DEFAULT NULL COMMENT 封面图, price decimal(10,2) NOT NULL DEFAULT 0.00 COMMENT 售价, origin_price decimal(10,2) DEFAULT NULL COMMENT 原价, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0草稿 1上架 2下架, exam_id int(11) DEFAULT NULL COMMENT 关联结业考试试卷ID, created_at datetime DEFAULT NULL, updated_at datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课程表; -- 课时表 CREATE TABLE course_lesson ( id int(11) unsigned NOT NULL AUTO_INCREMENT, course_id int(11) NOT NULL, title varchar(200) NOT NULL, media_type tinyint(1) NOT NULL DEFAULT 1 COMMENT 1视频 2音频 3图文 4外部链接, media_url varchar(500) DEFAULT NULL COMMENT 媒体地址, content longtext COMMENT 图文内容, duration int(11) DEFAULT 0 COMMENT 时长(秒), is_free tinyint(1) NOT NULL DEFAULT 0 COMMENT 是否可试看, sort int(11) NOT NULL DEFAULT 0, PRIMARY KEY (id), KEY idx_course_sort (course_id, sort) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT课时表;交易线的核心是订单表和支付流水表。考试线是所有表结构中设计最细的单独展开讲。3.2 订单与课程的多态关联一种更灵活的设计订单不能只挂在课程上。一套系统后面可能扩展出会员卡、专栏合集、题库包等多种商品形态。如果把订单表设计成只记录course_id后期扩展任何新商品类型都要改表结构。我的做法是引入商品多态关联CREATE TABLE order ( id int(11) unsigned NOT NULL AUTO_INCREMENT, order_no varchar(32) NOT NULL COMMENT 订单号, user_id int(11) NOT NULL, product_type tinyint(1) NOT NULL DEFAULT 1 COMMENT 1课程 2会员卡 3专栏, product_id int(11) NOT NULL COMMENT 商品ID, product_snapshot text COMMENT 商品快照JSON, total_amount decimal(10,2) NOT NULL, pay_type tinyint(1) DEFAULT NULL COMMENT 1微信 2支付宝, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0待支付 1已支付 2已关闭 3已退款, paid_at datetime DEFAULT NULL, created_at datetime DEFAULT NULL, updated_at datetime DEFAULT NULL, PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_status (user_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT订单表;关键设计点在product_snapshot字段。下单那一刻把商品的标题、封面、价格、所属讲师全部记录成JSON快照存进订单。这样即使后来课程改价、改标题甚至下架历史订单仍然保留了完整的购买凭证。这是电商系统里很常见的做法但很多入门级PHP项目没做这一步导致后续对账和售后很麻烦。3.3 题库、试卷、考试记录从一套题到一场考试的状态流转考试模块的表设计要回答三个问题题从哪来怎么组卷考试过程如何留痕题库表按题型区分CREATE TABLE question ( id int(11) unsigned NOT NULL AUTO_INCREMENT, category_id int(11) NOT NULL COMMENT 所属分类, type tinyint(1) NOT NULL COMMENT 1单选 2多选 3判断, content text NOT NULL COMMENT 题干, options text DEFAULT NULL COMMENT 选项JSON如{A:选项A内容,B:选项B内容}, answer varchar(255) NOT NULL COMMENT 答案单选如A多选如A,C判断如1/0, analysis text DEFAULT NULL COMMENT 解析, score decimal(5,1) NOT NULL DEFAULT 2.0 COMMENT 分值, status tinyint(1) NOT NULL DEFAULT 1, created_at datetime DEFAULT NULL, PRIMARY KEY (id), KEY idx_category (category_id, status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT题库表;试卷表的核心是question_ids字段。组卷时可以人工从题库选题也可以设定规则让系统按知识点和题型比例自动抽题。抽题规则我用JSON存例如{单选: 5, 多选: 3, 判断: 2}后台组卷时前台传规则服务端执行抽题函数。考试记录表是整个考试链路的收口CREATE TABLE exam_record ( id int(11) unsigned NOT NULL AUTO_INCREMENT, record_no varchar(32) NOT NULL COMMENT 考试记录编号, user_id int(11) NOT NULL, paper_id int(11) NOT NULL, answers longtext COMMENT 作答明细JSON, score decimal(6,1) DEFAULT NULL COMMENT 最终得分, status tinyint(1) NOT NULL DEFAULT 0 COMMENT 0进行中 1待批改 2已出分 3缺考, started_at datetime DEFAULT NULL, submitted_at datetime DEFAULT NULL, duration int(11) DEFAULT NULL COMMENT 实际用时秒数, PRIMARY KEY (id), KEY idx_user_paper (user_id, paper_id), KEY idx_status (status) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COMMENT考试记录表;answers字段保存的是每次作答的快照JSON。用户每切换一道题前端就调用接口把当前题目的答案写进这个字段。这个设计的好处是考生意外关掉浏览器后重新进来作答记录还在可以继续答题。这是在线考试系统最基本的体验保障。4. 知识付费的钱怎么收支付回调与订单状态机的正确写法4.1 微信/支付宝统一下单的完整链路知识付费系统最敏感的部分就是支付。很多新手写的支付回调存在一个严重的逻辑缺陷——以支付平台的通知为准而不是以本地订单状态为准。正确的流程应该是用户在网页端点“立即购买”后端生成本地订单状态为待支付调支付平台API生成预支付单把支付参数返回给前端。前端拿到支付参数后拉起微信/支付宝收银台用户完成支付。支付平台异步通知后端回调地址后端验签成功、金额比对成功后更新本地订单状态为已支付。如果由于网络原因异步通知丢了用户在支付平台可能已扣款成功此时需要前端在支付完成后主动查询订单状态调后端接口发起“主动查单”补齐掉单场景。回调里最重要的一步是验签金额比对。签名验证是支付平台保证数据来源可信的第一道防线金额比对是防止篡改的第二道防线。非要从这道关口守好否则别人可能构造一个假的“支付成功”通知绕过付款直接开通课程权限。我用支付宝举例服务端的回调处理逻辑public function notify() { // 获取支付宝POST过来的原始参数 $params $_POST; // 验签 $result AlipayService::verify($params); if (!$result) { // 验签失败记录日志并返回failure Log::error(支付宝回调验签失败, $params); return failure; } // 取商户订单号、流水号和实付金额 $outTradeNo $params[out_trade_no]; $tradeNo $params[trade_no]; $totalAmount $params[total_amount]; // 查本地订单 $order Order::where(order_no, $outTradeNo)-first(); if (!$order) { Log::error(订单不存在, [out_trade_no $outTradeNo]); return failure; } // 比对金额注意浮点比较要用字符串比较 if (bccomp($order-total_amount, $totalAmount, 2) ! 0) { Log::error(订单金额不一致, [order_id $order-id]); return failure; } // 幂等处理如果订单已经是已支付直接返回success if ($order-status 1) { return success; } // 开启事务更新订单状态 开通课程权限 DB::transaction(function () use ($order) { $order-status 1; $order-paid_at date(Y-m-d H:i:s); $order-save(); // 写用户课程关联表 UserCourse::create([ user_id $order-user_id, course_id $order-product_id, source order, order_id $order-id ]); }); return success; }4.2 幂等性是支付回调的命门回调接口被重复请求是常态。支付平台为了保证通知送达会按时间策略多次重试。如果订单已经是已支付状态而你的代码因为没有判断又给用户加了一次课程权限、又发了一条购买通知就会造成数据脏乱。幂等处理的思路不复杂就看三件事本地订单状态是否为已支付用户课程关联是否已存在支付流水表是否已有这条交易号5. 在线考试系统防作弊不能只靠前端5.1 切屏监测记录违规而非一键交卷很多在线考试系统把切屏检测做成“切屏超过3次自动交卷”。实际运营中你会发现这个设计非常不友好——考生手机弹个通知、误点个广告甚至微信消息弹窗都算切屏。用户还没开始答题就被强制交卷投诉率爆表。我的做法是切屏只记录、不惩罚。前端监听页面可见性变化visibilitychange事件和窗口失焦事件每次触发就向后端上报一条违规记录。后端累计违规次数交卷时把“违规次数”作为附加信息呈现在考试详情里是否判定作弊由管理员根据频次和时长人工判断。这套逻辑对考生公平也给管理员留出了裁决空间。5.2 随机抽题与选项打乱的正确打开方式固定试卷最大的风险是试题泄露。我用两种方式降低风险抽题随机化组卷时保存的是抽题规则考生进入考试时实时从题库抽取题目。题库足够大时每个考生抽到的题都不一样。选项顺序打乱单选题的ABCD选项显示顺序打乱但答案字段始终记录正确选项内容而不是固定选项字母。这样考生A看到正确答案排在B位置考生B看到的正确答案排在D位置抄答案的成本大幅提高。选项打乱的落地逻辑// 取出题目原题 $question Question::find($id); $options json_decode($question-options, true); // 获取正确选项内容 $correctKey $question-answer; // 如 A $correctContent $options[$correctKey]; // 打乱顺序 $keys array_keys($options); shuffle($keys); $shuffledOptions []; foreach ($keys as $key) { $shuffledOptions[$key] $options[$key]; } // 重新定位正确答案的位置 $newCorrectKey array_search($correctContent, $shuffledOptions); // 保存到试卷快照中考生的作答以这个快照为准注意题目快照和试卷快照也要存一份到考试记录里不能直接引用题库表里的原题。万一管理员中途改了题干和选项已生成试卷的考试数据就对不上了。5.3 倒计时与自动交卷服务端的时间才是真正的时间前端倒计时显示的是结束时间戳与当前时间戳的差值不能在前端维护一个递减的计数器。原因很简单前端刷新页面、设备休眠都会导致计时器不准。实现方式考生进入考场时后端生成试卷快照并记录started_at同时计算end_at started_at 试卷时长。前端的倒计时是end_at - 当前时间。交卷时无论用户是否主动点击交卷后端都校验当前时间是否超过end_at如果超过则按所有已保存答案自动交卷。这样即使考生一直开着页面不点交卷到时间后端也会强制收卷。关于考试中断续考前面提到答案实时保存考生刷新或重进考试页面时系统检测到该试卷有一条状态为“进行中”的考试记录就恢复答案并继续倒计时。需要限制的是一旦提交交卷就不能再返回修改。6. 从开发到上线LNMP环境下最容易踩的六个坑6.1 伪静态配置差点毁掉整个部署体验这套系统使用ThinkPHP 8框架路由是典型的入口文件模式。部署到Nginx时伪静态配置对不对直接决定你能不能访问到页面。很多人第一次部署PHP项目遇到“白屏”或40490%是伪静态和fastcgi参数不对。我这里直接给出一份验证过可用的Nginx站点配置核心片段server { listen 80; server_name your-domain.com; root /var/www/html/public; index index.php index.html; location / { if (!-e $request_filename) { rewrite ^(.*)$ /index.php?s$1 last; } } location ~ \.php$ { fastcgi_pass unix:/tmp/php-cgi-81.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ { expires 7d; access_log off; } }如果你的服务器上PHP版本不同php-cgi-81.sock路径要跟着变。这个配置里我最想强调的就是root指向的是public目录不是项目根目录。很多框架出于安全考虑把入口文件收敛到public子目录Nginx的根指向必须同步调整。6.2 PHP与MySQL时区不一致导致考试时间错乱考试系统对时间精度极其敏感。曾经遇到线上考试开始时间比实际慢了8个小时——学员都考完了系统显示还没开始。查了半天发现是PHP默认时区是UTCMySQL是东八区两边时间差了8小时。解决方案在项目入口统一设置date_default_timezone_set(Asia/Shanghai);MySQL连接初始化执行SET time_zone 08:00;顺带说一下数据库连接串里也可以加timezone参数但最简单可靠的是在应用层统一设置。只要保证PHP写库的时间与MySQL读库的时间都在同一时区就不会出现错乱。因为考试记录表里的started_at和submitted_at差值直接决定考生实际用时这个一旦错乱整个考试模块就废了。6.3 试卷并发提交别让一个班同时交卷打爆数据库一个50人的班级同时交卷如果每份试卷50道题写入量也就2500条记录MySQL完全扛得住。但如果考试系统是面向社会公开的几百人同时交卷再加上答案明细都是JSON大字段写入压力瞬间就上来了。我的处理方案是队列化交卷。用户在页面点击“交卷”后后端只做两件事把答题快照写入Redis缓存队列立即返回“交卷成功”。后台消费者进程从队列中取出数据逐条写入MySQL。这样用户感知不到任何延迟数据库也能平稳消化写入压力。Redis队列的消费脚本用系统定时任务调度* * * * * php /var/www/html/think queue:work --queueexam_submit如果服务器内存不大可以用MySQL的队列表代替Redis复杂度略高但思路一致。核心原则是用户请求路径上的每一步都要快重活抛给异步任务。6.4 微信内置浏览器播放视频的兼容处理H5视频上课场景里最容易踩的坑就是视频播放。iOS和Android的微信内置浏览器对H5视频的处理方式差异极大。iOS上video标签需要设置playsinline属性才能内联播放否则会自动全屏Android上则需要设置x5-playsinline属性配合腾讯X5内核。标准的视频标签写法是video controls preloadauto playsinline webkit-playsinlinetrue x5-playsinlinetrue x5-video-player-typeh5 src课程视频地址 /video另外视频编码格式需要兼容处理。推荐服务端输出H.264编码的MP4文件浏览器兼容性最好。如果课程视频是其他格式上线前务必转码否则一多半用户的手机播放不了。6.5 管理后台的越权防护PHP项目最常被攻击的点是水平越权。比如用户A登录后直接改URL里的ID参数去访问用户B的考试记录或者是修改课程ID获取未购买的课程权限。处理方案不能只靠前端隐藏按钮后端必须在每个接口做两件事身份鉴权确认用户已登录且角色匹配普通用户不能访问管理接口。资源归属校验查询数据时必须带上当前用户的ID条件不能只按主键查。一个标准的安全查询示例// 错误写法只看记录ID不校验归属 $record ExamRecord::find($recordId); // 正确写法同时校验记录ID和归属用户 $record ExamRecord::where(id, $recordId) -where(user_id, $this-userId) -first();这套落地的过程里我反复跟团队成员强调一个理念永远不要把用户输入的参数直接拼到查询条件里永远不要相信前端传来的任何字段。凡是涉及资源查询的接口当前登录用户的ID必须作为条件参与数据库查询。6.6 静态资源缓存与更新策略课程封面图、视频封面、JS/CSS文件的缓存策略需要特别注意。CSS或JS文件更新后如果浏览器还缓存着旧版本页面表现完全不一样。我在Nginx里设置了静态文件缓存7天但上线发布新版本的CSS/JS时会给文件名加版本号参数刷新缓存。例如页面引入修改后的样式link relstylesheet href/assets/css/app.css?v20250118代码里维护一个版本常量每次发布新版本手动更新版本号值即可。这种方式不用改文件名也不用专门清CDN缓存实用且轻量。视频封面图这类更新频率低的大文件走默认缓存策略就可以没必要每次都强制刷新。7. 运营层面容易被忽略的细节和我的改进思路7.1 考试防作弊的数据价值考试记录里保存的违规次数字段在上线一段时间后产生了新的价值。把学员的违规次数与最终成绩做关联分析可以识别出高风险的考试场次。比如某场考试平均违规次数高达8次管理员就要警惕这场考试是否出现了大面积作弊现象。这个数据还会推送给机构管理员作为发放结业证书的参考依据。7.2 课程学习进度的断点续学知识付费平台上学员最关心的事情之一是看到自己的学习进度。我在设计课时表时加了is_free字段用于试看同时又设计了study_record学习记录表记录用户学到课程的哪个课时、每个课时看到第几秒。实现断点续学有两个关键点视频播放器每5秒上报一次播放位置到后端保存该用户在这个课时上的最新进度。这个上报频率太密会有性能压力太疏会导致续学位置不准5秒是性能与体验的平衡点。用户重新进入课程时后端返回该课时上次播放的位置秒数前端在视频播放器loadedmetadata事件中跳转到这个位置。有了这个功能学员在手机上看了一半的课程换到电脑上还能从上次看的地方接着学。这个体验细节直接提升用户好感但很多人做知识付费系统时会忽略。7.3 订单超时未支付的自动关闭有些用户把订单页面打开后不再操作如果在数据库里留着大量“待支付”的脏订单不仅影响管理端的数据统计还可能导致用户想重新下单时看到重复的未支付订单。我用一个简单的定时任务解决* * * * * php /var/www/html/think order:closeExpired逻辑是更新创建时间超过30分钟且状态为待支付的订单改为已关闭状态。用户如果还想购买可以重新下单不影响体验。8. 这套系统上线后的几点真实感受项目部署到现在已经稳定运行了几个月。期间收到的最大反馈是“便宜、够用、好改”。有一家线下培训机构直接拿源码做了二次开发把考试模块单独抽出来做了内部的消防安全知识考核前后只花了不到两周。我个人在实际开发里感触最深的一件事是不要过度设计。项目最开始我也想过引入微服务、前后端分离、容器化部署后来发现这些都是错觉。一个知识付费平台的核心是内容、交易和考试这三个场景用PHP单体架构完全可以承载反而是一堆高大上的架构名词会把项目拖入泥潭。如果你准备拿这套源码做自己的项目我建议先部署跑通完整流程再动手改代码。流程没跑通之前你对模块之间关联的理解只是纸面上的。每一处设计都有它存在的理由改掉一个字段可能牵动整条链路。后续如果有余力这套系统可以扩展的方向是增加直播模块、对接企业微信做学员社群、引入积分商城做学习激励。底层的用户体系和订单模型已经预留了扩展空间往哪个方向加都顺畅。这条路上踩过的坑希望这篇文章能帮你省掉一半。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门