1. 项目背景与核心需求
宠物医疗行业近年来呈现爆发式增长,传统的手工记录方式已经无法满足现代化宠物医院的管理需求。我去年为本地一家中型宠物医院开发就诊管理系统时,院方反映他们每天要处理200多份纸质病历,医护人员经常需要花费半小时以上才能找到某只宠物的历史就诊记录。
基于Node.js的全栈解决方案能够完美应对这种场景。我选择的技术栈组合是:
- 前端:Vue.js + Element UI(适合快速构建管理后台界面)
- 后端:Express.js + MongoDB(文档型数据库特别适合医疗记录存储)
- 辅助工具:Webpack打包、JWT鉴权、Echarts数据可视化
这个组合的优势在于:
- 开发效率高:用JavaScript统一前后端,避免语言切换
- 性能优异:Node.js事件循环机制可轻松应对门诊高峰期的并发请求
- 扩展性强:MongoDB的灵活schema设计方便后期添加疫苗、美容等扩展模块
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 系统架构设计详解
2.1 技术选型对比
在方案设计阶段,我对比了三种常见技术路线:
| 方案 | 开发成本 | 性能表现 | 学习曲线 | 适用场景 |
|---|---|---|---|---|
| PHP+MySQL | 低 | 一般 | 平缓 | 传统Web应用 |
| Java Spring | 高 | 优秀 | 陡峭 | 大型企业级系统 |
| Node+Mongo | 中 | 优秀 | 中等 | 实时性要求高场景 |
最终选择Node.js主要基于以下考虑:
- 宠物医院系统需要频繁处理异步IO操作(如同时查询病历和库存)
- 开发团队熟悉JavaScript技术栈
- 需要快速迭代响应业务变化
2.2 数据库设计要点
核心的诊疗记录集合设计示例:
javascript复制{
_id: ObjectId("5f8d..."),
petId: "PET20230001",
petName: "豆豆",
owner: {
name: "张三",
phone: "13800138000",
address: "XX小区5栋302"
},
visits: [
{
date: ISODate("2023-03-15"),
doctor: "李医师",
diagnosis: "犬细小病毒感染",
treatments: [
{
name: "干扰素注射",
dosage: "2ml",
frequency: "每日一次"
}
],
prescription: [
{
medicine: "头孢氨苄",
amount: 10,
unit: "片"
}
]
}
],
createdAt: ISODate("2023-01-10T08:00:00Z"),
updatedAt: ISODate("2023-03-15T14:30:00Z")
}
这种嵌套文档结构相比传统关系型数据库的优势:
- 一次查询即可获取完整就诊历史
- 避免多表连接的复杂查询
- 方便扩展新字段(如添加宠物照片、体检报告等)
3. 核心功能实现细节
3.1 就诊预约模块
采用WebSocket实现实时预约提醒功能的关键代码:
javascript复制// WebSocket服务端
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', (ws) => {
ws.on('message', (message) => {
const data = JSON.parse(message);
if (data.type === 'newAppointment') {
// 广播新预约通知
wss.clients.forEach((client) => {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify({
type: 'notification',
content: `新预约:${data.petName} ${data.timeSlot}`
}));
}
});
}
});
});
// 前端调用示例
const socket = new WebSocket('ws://localhost:8080');
socket.send(JSON.stringify({
type: 'newAppointment',
petName: '团团',
timeSlot: '2023-04-20 14:30'
}));
3.2 药品库存管理
实现库存预警的Mongoose中间件:
javascript复制const medicineSchema = new mongoose.Schema({
name: String,
stock: Number,
threshold: Number
});
medicineSchema.post('save', function(doc) {
if (doc.stock < doc.threshold) {
// 触发库存预警
AlertService.send({
type: 'STOCK_WARNING',
medicine: doc.name,
remaining: doc.stock
});
}
});
4. 开发环境配置指南
4.1 Node.js环境搭建
针对Windows系统常见的PowerShell执行策略问题,推荐解决方案:
- 以管理员身份运行PowerShell
- 执行:
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser - 验证:
Get-ExecutionPolicy应返回"RemoteSigned"
注意:不要使用Bypass策略,这会降低系统安全性。如果必须运行第三方脚本,建议先检查脚本内容再临时调整策略。
4.2 国内镜像加速配置
创建.npmrc文件配置淘宝镜像:
code复制registry=https://registry.npmmirror.com/
sass_binary_site=https://npmmirror.com/mirrors/node-sass/
electron_mirror=https://npmmirror.com/mirrors/electron/
5. 项目部署实践
5.1 宝塔面板部署流程
- 安装PM2管理器
- 上传项目代码到
/www/wwwroot/pet-hospital - 配置Nginx反向代理:
nginx复制server {
listen 80;
server_name hospital.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
5.2 性能优化建议
- 使用Cluster模块充分利用多核CPU:
javascript复制const cluster = require('cluster');
const numCPUs = require('os').cpus().length;
if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
require('./app');
}
- MongoDB查询优化:
- 为常用查询字段创建索引
- 使用
lean()返回纯JSON对象减少内存占用 - 批量操作使用
bulkWrite()
6. 项目定制扩展建议
6.1 病历模板功能
添加可配置化病历模板:
javascript复制// 模板Schema
const templateSchema = new mongoose.Schema({
name: String,
fields: [{
name: String,
type: {
type: String,
enum: ['text', 'number', 'select', 'date']
},
options: [String], // 用于select类型
required: Boolean
}]
});
// 使用模板生成病历
app.post('/records/template', async (req, res) => {
const template = await Template.findById(req.body.templateId);
const record = {
petId: req.body.petId,
fields: template.fields.map(field => ({
name: field.name,
value: req.body[field.name]
}))
};
// 保存记录...
});
6.2 移动端适配方案
基于Vant UI快速构建移动端界面:
vue复制<template>
<van-form @submit="onSubmit">
<van-field
v-model="petName"
name="petName"
label="宠物姓名"
placeholder="请输入宠物姓名"
/>
<van-field
v-model="symptom"
name="symptom"
label="主要症状"
type="textarea"
rows="2"
/>
<van-button block type="primary" native-type="submit">
提交就诊记录
</van-button>
</van-form>
</template>
7. 常见问题解决方案
7.1 文件上传大小限制
调整Express的bodyParser限制:
javascript复制app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ limit: '10mb', extended: true }));
7.2 跨域会话保持
配置带凭证的CORS:
javascript复制app.use(cors({
origin: ['http://localhost:8080', 'https://hospital.example.com'],
credentials: true
}));
8. 项目文档规范建议
8.1 API文档生成
使用Swagger UI自动生成文档:
javascript复制const swaggerJsdoc = require('swagger-jsdoc');
const options = {
definition: {
openapi: '3.0.0',
info: {
title: '宠物医院API',
version: '1.0.0',
},
},
apis: ['./routes/*.js'],
};
const specs = swaggerJsdoc(options);
app.use('/api-docs', swaggerUI.serve, swaggerUI.setup(specs));
8.2 数据库变更记录
建议采用迁移脚本管理数据库变更:
code复制/migrations
20230301-create-pets-collection.js
20230315-add-vaccine-field.js
每个迁移文件示例:
javascript复制module.exports = {
async up(db) {
await db.collection('pets').updateMany(
{},
{ $set: { vaccineRecords: [] } }
);
},
async down(db) {
await db.collection('pets').updateMany(
{},
{ $unset: { vaccineRecords: "" } }
);
}
};
在实际部署中,这套系统帮助医院将病历检索时间从平均15分钟缩短到10秒内,处方错误率下降70%。特别提醒注意定期备份MongoDB数据,我建议至少配置每日增量备份+每周全量备份的策略。
