1. 项目背景与核心需求
这个项目本质上是一个面向小儿保健推拿培训领域的在线教育系统。作为一名长期从事医疗健康类应用开发的工程师,我发现传统的小儿推拿培训存在几个痛点:
- 线下培训成本高:家长需要专门请假带孩子参加培训,培训机构场地租金等固定支出大
- 标准化程度低:不同老师的推拿手法存在差异,缺乏统一的教学质量把控
- 学习效果难追踪:学员练习情况无法实时记录和反馈
基于这些观察,我们决定开发这套基于Node.js+Vue的在线培训系统。系统需要实现的核心功能包括:
- 穴位定位三维展示:通过WebGL实现可交互的人体穴位模型
- 推拿手法视频教学:支持慢放、分段学习等教学模式
- 学习进度智能分析:记录学员练习数据并生成改进建议
- 在线考核认证:包含理论测试和实操视频提交评审
提示:在医疗健康类应用开发中,数据准确性和操作安全性是首要考虑因素。所有穴位数据和推拿手法都需要经过专业医师团队的审核。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 前后端分离架构
系统采用典型的前后端分离架构:
code复制[前端Vue应用] <- HTTP/HTTPS -> [Node.js后端API] <- MongoDB
前端技术栈选择Vue 3 + TypeScript的组合主要基于:
- 组件化开发适合复杂的交互界面
- Composition API更利于业务逻辑封装
- TypeScript的静态类型检查能减少运行时错误
后端选择Node.js的考虑因素:
- 高并发I/O场景下的性能优势
- 与MongoDB的天然亲和性(JSON文档结构)
- 丰富的npm生态(如医疗图像处理库)
2.2 核心模块划分
code复制├── 客户端
│ ├── 3D穴位模型展示(Three.js)
│ ├── 视频教学播放器(Video.js)
│ ├── 练习录制组件(MediaRecorder API)
│ └── 学习数据分析看板(ECharts)
└── 服务端
├── 用户认证(JWT)
├── 视频处理(FFmpeg WASM)
├── 学习数据分析(TensorFlow.js)
└── 考核评审系统(WebSocket)
3. 关键技术实现细节
3.1 穴位三维模型交互
使用Three.js实现的主要代码结构:
javascript复制// 初始化场景
const scene = new THREE.Scene();
const loader = new GLTFLoader();
// 加载人体模型
loader.load('human_model.glb', (gltf) => {
const model = gltf.scene;
scene.add(model);
// 添加穴位标记点
acupuncturePoints.forEach(point => {
const marker = createMarker(point);
marker.userData = point; // 存储穴位信息
scene.add(marker);
});
});
// 点击事件处理
raycaster.setFromCamera(mouse, camera);
const intersects = raycaster.intersectObjects(scene.children);
if (intersects.length > 0) {
const pointData = intersects[0].object.userData;
showAcupunctureDetail(pointData);
}
模型交互的几个关键点:
- 使用GLB格式的优化模型(约5MB大小)
- 实现LOD(Level of Detail)分级加载
- 穴位标记点的碰撞体积优化
3.2 推拿视频处理流程
mermaid复制graph TD
A[讲师上传视频] --> B[FFmpeg转码]
B --> C[生成不同清晰度版本]
C --> D[关键帧提取]
D --> E[手势分析标注]
E --> F[存入MinIO存储]
视频处理的核心参数:
bash复制# 转码为H.264格式
ffmpeg -i input.mp4 -c:v libx264 -preset slow -crf 22 -c:a aac -b:a 128k output.mp4
# 生成缩略图
ffmpeg -ss 00:00:05 -i input.mp4 -vframes 1 thumbnail.jpg
3.3 练习动作分析算法
采用MediaPipe的姿势识别模型:
python复制# 伪代码示例
def analyze_movement(video):
with mp_pose.Pose() as pose:
results = pose.process(video)
# 计算关节角度
angles = calculate_joint_angles(results.pose_landmarks)
# 与标准动作对比
deviation = compare_with_standard(angles)
return generate_feedback(deviation)
分析维度包括:
- 手部位置准确性(与标准穴位的偏差)
- 施力方向正确性
- 节奏频率一致性
4. 系统部署方案
4.1 开发环境配置
前端开发环境:
bash复制# 使用Vite创建项目
npm create vite@latest pediatric-massage --template vue-ts
# 添加Three.js依赖
npm install three @types/three gltf-loader
后端开发环境:
bash复制# 初始化Node项目
npm init -y
# 安装核心依赖
npm install express mongoose jsonwebtoken multer ffmpeg-static
4.2 生产环境部署
使用Docker Compose编排:
yaml复制version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
depends_on:
- backend
backend:
build: ./backend
ports:
- "4000:4000"
environment:
- MONGODB_URI=mongodb://mongo:27017/massage
depends_on:
- mongo
mongo:
image: mongo:5.0
volumes:
- mongodb_data:/data/db
volumes:
mongodb_data:
关键配置项:
- 前端静态资源使用Nginx缓存
- MongoDB启用副本集保证数据安全
- Node服务使用PM2进程管理
5. 典型问题与解决方案
5.1 视频上传中断处理
实现断点续传的前端代码:
javascript复制const uploadFile = async (file) => {
const chunkSize = 5 * 1024 * 1024; // 5MB
let offset = 0;
while (offset < file.size) {
const chunk = file.slice(offset, offset + chunkSize);
const formData = new FormData();
formData.append('chunk', chunk);
formData.append('offset', offset);
formData.append('fileId', fileId);
try {
await axios.post('/api/upload', formData);
offset += chunk.size;
} catch (err) {
// 记录失败位置,下次重试
saveUploadState(fileId, offset);
break;
}
}
};
后端对应的处理逻辑:
javascript复制app.post('/api/upload', async (req, res) => {
const { fileId, offset } = req.body;
const chunk = req.files.chunk;
// 创建可写流(追加模式)
const writeStream = fs.createWriteStream(`uploads/${fileId}`, {
flags: 'a',
start: parseInt(offset)
});
chunk.pipe(writeStream);
});
5.2 三维模型加载优化
采取的优化措施:
- 使用Draco压缩(减少70%模型体积)
javascript复制const dracoLoader = new DRACOLoader();
dracoLoader.setDecoderPath('/draco/');
loader.setDRACOLoader(dracoLoader);
- 实现按需加载
javascript复制// 只加载当前教学章节需要的身体部位
const loadBodyPart = (partName) => {
return loader.loadAsync(`models/${partName}.glb`);
};
- 使用WebWorker进行后台解码
6. 安全与合规考量
在医疗健康类应用中,需要特别注意:
-
数据加密:
- 使用TLS 1.3传输加密
- 敏感数据(如用户健康信息)使用AES-256加密存储
-
权限控制:
javascript复制// 路由守卫示例
router.beforeEach((to, from, next) => {
if (to.meta.requiresAuth && !store.getters.isCertified) {
next('/certification');
} else {
next();
}
});
- 医疗内容审核:
- 建立专家审核工作流
- 用户生成内容(UGC)先审后发
- 所有医疗建议标注"仅供参考"提示
7. 性能优化实践
7.1 前端性能指标
优化前后的对比:
| 指标 | 优化前 | 优化后 |
|---|---|---|
| LCP | 4.2s | 1.8s |
| FID | 320ms | 80ms |
| CLS | 0.45 | 0.12 |
关键优化手段:
- 三维模型懒加载
- 视频流自适应码率
- 虚拟滚动长列表
7.2 后端缓存策略
Redis缓存配置示例:
javascript复制const getCourseContent = async (courseId) => {
const cacheKey = `course:${courseId}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const data = await Course.findById(courseId);
await redis.setex(cacheKey, 3600, JSON.stringify(data)); // 缓存1小时
return data;
};
缓存失效策略:
- 课程更新时主动清除缓存
- 高频访问数据延长缓存时间
- 用户个性化数据设置短缓存
8. 项目演进方向
基于现有系统的扩展可能:
-
AR辅助训练:
- 通过ARKit/ARCore实现实时动作指导
- 使用场景:学员在自己孩子身上练习时获得实时反馈
-
智能穿戴设备集成:
- 连接智能手环监测施力大小
- 结合肌电信号分析手法准确性
-
个性化学习路径:
- 基于学习历史推荐课程
- 根据错误模式生成针对性练习
在技术架构上,我们计划:
- 将视频分析模块迁移到WebAssembly提升性能
- 使用GraphQL替代部分REST API实现更灵活的数据查询
- 引入Serverless处理突发流量
这个项目给我的深刻体会是:医疗教育类系统的开发必须坚持"技术为专业服务"的原则。我们花了大量时间与中医专家沟通,确保每个穴位的定位精度在±2mm以内,每种手法的演示视频都经过至少三位专业推拿师的校准。这种对专业性的追求,才是系统真正价值的体现。
