1. 项目背景与核心价值
最近在帮朋友改造他的家政服务小店,发现很多中小型家政公司还在用Excel记账、微信接单这种原始方式管理业务。订单漏单、阿姨排班冲突、财务对账混乱这些问题几乎天天发生。于是用SpringBoot给他做了个轻量级管理系统,上线两个月后订单处理效率提升了60%,客户投诉率直接降到了零。
这种系统对于5-20人规模的家政团队特别实用——既能解决纸质管理的混乱,又不必承担大型ERP的复杂度和成本。核心功能模块其实就四个:订单流转、阿姨调度、客户管理和财务统计,但每个模块的设计都有不少实战中总结出来的门道。
2. 系统架构设计要点
2.1 技术选型决策
选用SpringBoot 2.7 + MyBatis-Plus组合主要考虑三点:
- 快速迭代:家政业务需求变化快,需要支持今天加个服务类型,明天改个分成规则
- 轻量部署:客户服务器多是1核2G的低配云主机,必须控制内存占用
- 移动适配:70%订单来自手机端,要确保API响应在3G网络下也能流畅
数据库选了MySQL 8.0,关键配置:
sql复制# 必须设置的参数
innodb_buffer_pool_size = 1G # 小内存机器专用配置
innodb_flush_log_at_trx_commit = 2 # 适当牺牲持久性换性能
2.2 领域模型设计
家政业务有四个核心实体:
- 服务订单(核心字段见下表)
- 服务人员(含技能矩阵)
- 客户档案(带黑名单标记)
- 服务项目(动态定价配置)
订单表关键字段设计:
| 字段名 | 类型 | 特殊说明 |
|---|---|---|
| order_status | ENUM | 使用状态机模式:待分配→已派工→服务中→待支付→已完成 |
| emergency_flag | TINYINT | 紧急订单插队逻辑标记 |
| actual_start_time | DATETIME | 记录真实服务开始时间,用于计算阿姨工作时长 |
特别注意:所有时间字段统一采用UTC+8存储,前端按用户时区转换。曾因时区问题导致过阿姨半夜被派工的严重事故。
3. 核心业务逻辑实现
3.1 智能派单算法
家政系统的灵魂在于派单逻辑,我们采用三级匹配策略:
- 基础匹配:服务类型+时间窗口
- 技能加权:阿姨的专项技能评分(如保洁阿姨的擦窗熟练度)
- 动态调整:考虑实时位置(通过微信定位API)、当前负荷、历史投诉记录
核心代码片段:
java复制public List<Worker> matchWorkers(Order order) {
// 第一轮:排除不可用阿姨
List<Worker> candidates = workerMapper.selectAvailableWorkers(
order.getServiceType(),
order.getTimeSlot()
);
// 第二轮:技能评分排序
candidates.sort((w1, w2) -> {
float score1 = calculateMatchScore(w1, order);
float score2 = calculateMatchScore(w2, order);
return Float.compare(score2, score1);
});
// 第三轮:人工干预标记
return candidates.stream()
.filter(w -> !w.isInBlacklist(order.getCustomerId()))
.limit(3)
.collect(Collectors.toList());
}
3.2 服务状态机设计
订单状态流转用状态机模式实现,关键点:
- 定义所有合法状态转移路径
- 记录完整操作日志
- 支持特定条件下的状态回退
状态转移示例:
code复制待分配 →(派单)→ 已派工
已派工 →(阿姨确认)→ 服务中
服务中 →(异常上报)→ 待分配
服务中 →(完成上报)→ 待支付
踩坑提醒:千万不要用简单的Integer表示状态码!我们最早用1/2/3表示状态,结果需求变更三次后代码完全无法维护,后来改用Enum才解决问题。
4. 特色功能实现细节
4.1 动态服务定价引擎
家政服务常有临时加价场景(比如春节溢价),我们设计了规则引擎:
java复制public BigDecimal calculateFinalPrice(Order order) {
BigDecimal basePrice = serviceType.getBasePrice();
// 规则1:时段加成
if (isHoliday(order.getServiceTime())) {
basePrice = basePrice.multiply(new BigDecimal("1.5"));
}
// 规则2:紧急订单加成
if (order.isEmergency()) {
basePrice = basePrice.add(new BigDecimal("50"));
}
// 规则3:老客户折扣
if (customer.getOrderCount() > 5) {
basePrice = basePrice.multiply(new BigDecimal("0.9"));
}
return basePrice.setScale(2, RoundingMode.HALF_UP);
}
4.2 阿姨移动端优化
针对阿姨群体特点做的特殊优化:
- 语音播报新订单(集成阿里云语音合成)
- 一键导航到客户地址(唤起高德地图)
- 简化操作流程:所有重要操作三步内完成
- 离线模式支持:在网络差的楼道也能先记录服务情况
5. 性能优化实战记录
5.1 订单查询加速
当订单量超过10万条时,列表查询明显变慢。通过以下方案优化:
- 添加复合索引:
sql复制ALTER TABLE service_order ADD INDEX idx_search (customer_id, order_status, create_time); - 引入二级缓存:
java复制@Cacheable(value = "orderCache", key = "#customerId+'-'+#status") public List<Order> queryOrders(Long customerId, String status) { //... } - 分页优化:改用游标分页代替传统LIMIT分页
优化效果:查询响应时间从1200ms降至80ms
5.2 定时任务改造
原生的Spring Scheduled在分布式环境下会重复执行,改用Redis分布式锁:
java复制@Scheduled(cron = "0 0/5 * * * ?")
public void autoConfirmOrders() {
String lockKey = "lock:auto_confirm";
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 300, TimeUnit.SECONDS);
if (!locked) return;
// 实际业务逻辑
orderService.processUnconfirmedOrders();
} finally {
redisTemplate.delete(lockKey);
}
}
6. 部署与运维要点
6.1 服务器配置建议
最低配置要求:
- CPU:1核(突发性能实例需预留30%基准)
- 内存:2GB(需设置JVM参数:-Xmx1g -Xms1g)
- 磁盘:40GB SSD(数据库日志单独挂载)
推荐生产环境配置:
yaml复制spring:
datasource:
hikari:
maximum-pool-size: 5 # 小规模家政公司够用了
connection-timeout: 3000
servlet:
multipart:
max-file-size: 10MB # 阿姨上传现场照片用
6.2 监控方案
基础监控三件套:
- Spring Boot Actuator暴露健康检查
- 阿里云云监控(免费版)
- 自定义业务指标看板:
- 订单响应及时率
- 阿姨平均接单时长
- 客户投诉率
关键告警规则设置:
- 订单积压超过20单触发短信告警
- 阿姨接单平均时长>30分钟触发通知
- API错误率>1%时自动重启服务
7. 典型问题排查实录
7.1 阿姨重复接单问题
现象:同一订单被两个阿姨同时接受
排查过程:
- 检查数据库隔离级别(应为REPEATABLE_READ)
- 发现接单接口没有加锁:
java复制// 错误示范 public void acceptOrder(Long orderId) { Order order = orderMapper.selectById(orderId); if (order.getStatus() == WAITING) { order.setStatus(ASSIGNED); orderMapper.updateById(order); } } // 正确方案:使用select...for update @Transactional public void acceptOrder(Long orderId) { Order order = orderMapper.selectByIdForUpdate(orderId); // 后续逻辑... }
7.2 微信支付回调丢失
现象:客户已付款但订单状态未更新
解决方案:
- 增加支付流水表记录所有请求
- 实现补偿查询接口:
java复制@Scheduled(fixedDelay = 300000) public void checkPaymentStatus() { List<Order> unpaidOrders = orderMapper.selectUnpaidOrders(); unpaidOrders.forEach(order -> { PaymentStatus status = wechatPayClient.query(order.getPaymentId()); if (status == PAID) { orderService.confirmPayment(order.getId()); } }); } - 添加对账报表功能
8. 扩展方向建议
- 客户标签系统:给客户打上"爱干净"、"养宠物"等标签,实现精准阿姨匹配
- 智能排班系统:根据历史订单预测忙闲时段,自动调整阿姨上班时间
- 装备管理系统:跟踪阿姨携带的清洁设备状态和耗材余量
- 培训考核模块:在线视频培训+考试,提升阿姨服务水平
这套系统经过三个客户的实际验证,最关键的体会是:家政业务看似简单,但细节特别多。比如同样的"保洁"服务,有的客户要求重点擦窗,有的关注厨房去油,这些业务差异点才是系统需要灵活适应的关键。现在回头来看,当初花两周时间做的动态服务属性配置功能,后来成了客户最认可的价值点。