1. 项目背景与核心价值
去年接手一个社区养老机构的数字化改造需求时,发现护工排班和管理完全依赖纸质表格。每天早上交接班时,护士长都要花半小时核对排班表,遇到突发请假情况更是手忙脚乱。这促使我开发了这套基于Vue和Node.js的护工管理系统,上线后使排班效率提升60%,意外缺勤响应时间从原来的4小时缩短到15分钟。
这套系统的核心价值在于:
- 可视化排班:通过色块区分早中晚班次,支持拖拽调整
- 智能冲突检测:自动识别同一护工被重复排班的情况
- 移动端适配:护工通过微信小程序即可查看排班、提交请假申请
- 应急替补机制:出现突发请假时,系统自动推荐同资质护工名单
2. 技术架构设计
2.1 前端技术选型
采用Vue 3 + TypeScript组合主要基于:
- 组件复用性:排班日历、护工卡片等高频组件需多处复用
- 状态管理:使用Pinia管理全局的护工数据、排班规则等状态
- 移动适配:Vant UI组件库对移动端友好,省去自适应布局开发成本
关键代码结构:
src/ ├── components/ │ ├── ScheduleCalendar.vue # 核心排班组件 │ └── StaffCard.vue # 护工信息卡片 ├── stores/ │ └── schedule.ts # Pinia排班状态管理 └── views/ ├── mobile/ # 移动端专属页面 └── pc/ # 管理后台页面2.2 后端服务设计
Node.js选用Express框架主要考虑:
- 快速迭代:养老机构需求变更频繁,需要灵活调整API
- 轻量级:护工数据关系简单,无需复杂ORM支持
- 实时性:使用Socket.io实现排班变更实时推送
数据库采用MongoDB因为:
- 护工档案包含动态属性(如新增证书类型)
- 排班记录需要存储版本历史
- 地理查询支持(按距离分配护工)
典型API示例:
// 获取可替补护工列表 router.get('/backup-staff', async (req, res) => { const { excludeIds, skills } = req.query const staff = await Staff.find({ _id: { $nin: excludeIds }, certificates: { $in: skills }, status: 'active' }).sort({ lastWorkDate: 1 }) // 优先选择休息时间长的护工 res.json(staff) })3. 核心功能实现细节
3.1 智能排班算法
排班逻辑主要考虑三个维度:
- 资质匹配:失能老人必须安排持证护工
- 工作时长:单日不超过10小时,周累计≤48小时
- 个人偏好:记录护工不愿排班的日期
核心算法流程:
graph TD A[输入排班需求] --> B{新排班?} B -->|是| C[生成初始方案] B -->|否| D[加载历史模板] C --> E[应用约束规则] D --> E E --> F[冲突检测] F --> G[输出可行方案]实际代码实现时采用权重计分法:
function calculateScore(staff: Staff, shift: Shift): number { let score = 0 // 资质匹配度(40%权重) if (staff.certificates.includes(shift.requiredCert)) { score += 40 } // 工作时长(30%权重) const weeklyHours = getWeeklyHours(staff.id) score += 30 * (1 - weeklyHours / 48) // 个人偏好(20%权重) if (!staff.blacklistDates.includes(shift.date)) { score += 20 } // 距离系数(10%权重) score += 10 * (1 - getDistance(staff.home, shift.location) / 10) return score }3.2 实时通信方案
采用Socket.io实现三大实时场景:
- 排班变更通知:护士长调整排班后,相关护工立即收到微信模板消息
- 紧急呼叫响应:老人按下呼叫按钮后,自动分配最近护工
- 工作交接记录:换班时通过语音转文字生成交接备忘录
关键事件处理逻辑:
io.on('connection', (socket) => { socket.on('scheduleUpdate', (data) => { // 1. 保存变更记录 await ScheduleHistory.create(data) // 2. 通知受影响护工 const affectedStaff = getAffectedStaff(data.changes) sendWechatNotice(affectedStaff) // 3. 广播给所有在线管理端 io.emit('scheduleRefresh', data.version) }) })4. 部署与性能优化
4.1 服务器配置方案
针对养老机构预算有限的特点,推荐配置:
基础版:2核4G云服务器(适合50人以下机构)
- 日均请求量:约3000次
- 数据库:MongoDB 1G内存
- 备份策略:每日全量备份+binlog
企业版:4核8G集群(连锁机构)
- 使用PM2集群模式
- 数据库分片存储
- 负载均衡接入
实测性能数据:
| 场景 | 并发数 | 平均响应时间 |
|---|---|---|
| 排班查询 | 100 | 23ms |
| 批量排班 | 10 | 1.2s |
| 紧急呼叫 | 50 | 58ms |
4.2 移动端优化技巧
- 离线模式实现:
// 使用Service Worker缓存关键API workbox.routing.registerRoute( '/api/schedule', new workbox.strategies.StaleWhileRevalidate() )- 省流策略:
- 护工头像使用WebP格式(体积减少40%)
- 排班数据采用增量更新(每次只同步变更部分)
- 开启Gzip压缩(文本数据体积减少70%)
5. 典型问题解决方案
5.1 排班冲突处理
常见冲突场景及解决方法:
| 冲突类型 | 检测方法 | 自动解决方案 |
|---|---|---|
| 重复排班 | 检查同一护工同时间段排班记录 | 取消后安排的班次 |
| 资质不符 | 验证护工证书有效期 | 替换为同资质护工 |
| 超时工作 | 统计当周已工作时长 | 提示并禁止保存 |
5.2 数据迁移难点
从Excel迁移数据时遇到的主要问题:
历史排班记录日期格式混乱(有2023/1/1也有1-Jan-23)
- 解决方案:编写正则表达式清洗数据
const cleanDate = (raw) => { return raw.replace(/(\d+)[\/\-](\d+)[\/\-](\d+)/, '$3-$1-$2') }护工重名问题(多个"张伟")
- 解决方案:导入时自动添加后缀(如张伟_1)
- 后续通过工号区分
特殊符号处理(如"王芳(产假)")
- 解决方案:自动提取括号内状态信息
const parseStatus = (name) => { const match = name.match(/(.*)\((.*)\)/) return match ? { name: match[1], status: match[2] } : { name } }
6. 扩展功能实践
6.1 智能预警系统
通过分析历史数据实现:
- 疲劳预警:连续工作>5天自动提醒休息
- 证书到期提醒:提前30天通知续证
- 异常行为检测:标记频繁请假的护工
预警规则配置示例:
{ "fatigue": { "threshold": 5, "action": "lock_scheduling" }, "cert_expire": { "advance_notice": 30, "reminder_interval": 7 } }6.2 家属端小程序
开发家属专属功能:
- 服务评价系统(五星评分+文字评价)
- 护理日志查看(每日体温、用药记录)
- 电子支付对接(押金、额外服务费)
关键技术点:
<template> <!-- 评价组件 --> <van-rate v-model="rating" @change="submitRating" :disabled="isRated" /> </template> <script setup> // 防重复提交逻辑 const submitRating = useDebounceFn(() => { if (!isRated.value) { postRating().then(() => isRated.value = true) } }, 1000) </script>这套系统经过6个月的实际运行,目前已在3家养老机构落地,日均处理排班变更20余次,护工满意度提升35%。最大的收获是认识到:在医疗照护领域,技术方案必须保留足够的人工干预入口,完全依赖算法反而会增加管理风险。下一步计划加入AI排班建议功能,但仍保持最终决定权在护士长手中。