1. 项目概述:当汽修厂遇上微信小程序
去年帮朋友改造他的汽修厂管理系统时,发现传统PC端系统存在两个致命痛点:技师在车间无法实时查看工单,客户离店后完全失联。这促使我开发了这套基于SpringBoot+微信小程序的解决方案——现在他们的客户打开微信就能预约保养,车间大屏自动推送拆装视频,年营业额提升了37%。
这套系统本质上是通过SpringBoot构建RESTful API后端,微信小程序作为移动端入口,实现了维修企业最核心的"客户-服务-库存"三要素的数字化闭环。特别适合中小型汽修厂、4S店快修部门等场景,技术栈选择上我们坚持"够用就好"原则:
- 后端:SpringBoot 2.7 + MyBatis-Plus + Redis
- 前端:微信小程序原生框架 + Vant Weapp组件库
- 数据库:MySQL 8.0(阿里云RDS版)
- 部署:Docker Compose(单机版)/ K8s(连锁店集群版)
经验之谈:千万别被各种微服务架构洗脑,单应用SpringBoot配合合理的模块划分,完全能支撑日均5000订单量级的业务,我们的生产环境稳定运行两年未出现性能瓶颈。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心业务模块设计
2.1 客户端的"三把斧"设计
微信小程序端采用经典的"三栏式"交互架构:
- 预约看板(首页):
- 可视化时间轴选择(防止时间冲突)
- 智能车型识别(拍照上传VIN码自动匹配)
- 预估价格计算器(基于历史工单大数据)
javascript复制// 小程序端车型识别核心逻辑
wx.chooseImage({
success: (res) => {
this.uploadVIN(res.tempFilePaths[0]).then(vin => {
this.setData({
carModel: decodeVIN(vin).model,
engineType: decodeVIN(vin).engine
})
})
}
})
-
工单追踪(核心功能):
- 实时进度推送(WebSocket长连接)
- 电子签名确认(Canvas手写板实现)
- 维修过程直播(车间GoPro推流)
-
个人中心(粘性设计):
- 爱车健康档案(里程保养智能提醒)
- 优惠券裂变系统(社交立减金)
- 技师评价体系(与绩效工资挂钩)
2.2 后端业务中台构建
SpringBoot后端采用领域驱动设计(DDD)划分模块:
java复制// 典型的工单状态机实现
public enum RepairOrderStatus {
@Transitions({
@Transition(from = "PENDING", to = "CONFIRMED"),
@Transition(from = "PENDING", to = "CANCELLED")
})
PENDING,
CONFIRMED,
IN_PROGRESS,
COMPLETED,
CANCELLED
}
关键业务服务包括:
-
智能调度引擎:
- 基于贪心算法的工位分配
- 技师技能矩阵匹配
- 紧急订单插队策略
-
配件库存预警:
- 实时库存水位监控
- 供应商API自动补货
- 同类车型配件替代建议
-
财务对账系统:
- 微信支付自动对账
- 优惠券核销校验
- 技师提成自动计算
踩坑记录:微信支付回调一定要做幂等处理!我们曾因网络抖动导致重复回调,造成财务系统多记账,后来通过redis分布式锁+本地事务表解决。
3. 关键技术实现细节
3.1 微信生态深度集成
3.1.1 模板消息升级版
旧版模板消息已停用,现采用订阅消息+公众号补充的方案:
java复制// SpringBoot中处理订阅消息发送
public void sendRepairProgressMsg(String openid, String status) {
String templateId = getTemplateId("REPAIR_PROGRESS");
WxMaSubscribeMessage message = WxMaSubscribeMessage.builder()
.toUser(openid)
.templateId(templateId)
.data(Arrays.asList(
new WxMaSubscribeMessage.MsgData("thing1", "您的车辆" + licensePlate),
new WxMaSubscribeMessage.MsgData("phrase2", status),
new WxMaSubscribeMessage.MsgData("time3", LocalDateTime.now().toString())
)).build();
wxMaService.getMsgService().sendSubscribeMsg(message);
}
3.1.2 小程序登录优化方案
采用静默登录+手机号二次验证模式:
- 前端调用wx.login获取code
- 后端用code换session_key和openid
- 敏感操作(如支付)需强制手机号验证
java复制// 解密手机号的核心逻辑
public String decryptPhoneNumber(String encryptedData, String iv, String sessionKey) {
AES aes = new AES(Mode.CBC, Padding.PKCS5Padding,
Base64.decode(sessionKey),
Base64.decode(iv));
byte[] result = aes.decrypt(Base64.decode(encryptedData));
return new String(result, StandardCharsets.UTF_8);
}
3.2 性能优化三板斧
3.2.1 缓存策略设计
采用多级缓存架构:
- 本地缓存(Caffeine):存储静态数据如车型配置
- Redis集群:
- 热点数据:工单状态、技师位置
- 分布式锁:库存扣减、支付回调
- MySQL读写分离:
- 写主库:订单创建、状态变更
- 读从库:报表查询、历史记录
java复制// 注解驱动的缓存配置
@CacheConfig(cacheNames = "partsCache")
@Repository
public class PartsDao {
@Cacheable(key = "#partNo", unless = "#result == null")
public Part getByPartNo(String partNo) {
return baseMapper.selectOne(new QueryWrapper<Part>().eq("part_no", partNo));
}
@CacheEvict(key = "#part.partNo")
public void updatePart(Part part) {
baseMapper.updateById(part);
}
}
3.2.2 图片处理方案
针对维修过程图片的特殊需求:
- 小程序端使用we-compressor压缩
- 服务端用Thumbnailator生成三套尺寸:
- 缩略图(200x200)
- 展示图(800x600)
- 原图(保留EXIF信息)
- 存储策略:
- 热数据:阿里云OSS
- 冷数据:MinIO自建存储
4. 生产环境避坑指南
4.1 微信支付对账流程
我们趟过的坑形成的标准流程:
- 每日凌晨2点跑批任务
- 调用微信支付账单API下载对账文件
- 与本系统交易记录逐笔核对
- 异常处理:
- 微信有记录,系统无 → 补单
- 系统有记录,微信无 → 人工核查
- 金额不一致 → 冻结账户并告警
java复制// 对账核心逻辑示例
public void reconcile(Date date) {
List<WxPayBill> wxBills = wxPayService.downloadBill(date);
List<LocalOrder> localOrders = orderMapper.selectByDate(date);
Map<String, BillPair> pairMap = new HashMap<>();
// 匹配逻辑...
pairMap.values().forEach(pair -> {
if (pair.wxBill == null) {
handleMissingWxOrder(pair.localOrder);
} else if (pair.localOrder == null) {
handleGhostOrder(pair.wxBill);
} else if (!pair.isAmountMatch()) {
handleAmountMismatch(pair);
}
});
}
4.2 高并发场景应对
黑色星期五促销时的实战经验:
- 库存预热:
- 活动前1小时加载到Redis
- 采用分段锁扣减(避免大商品锁冲突)
- 排队机制:
- 使用Redis的List实现队列
- 前端轮询排队位置
- 降级方案:
- 超过阈值关闭优惠券使用
- 静态化预约页面
java复制// 分布式锁实现库存扣减
public boolean reduceInventory(String partNo, int num) {
String lockKey = "stock_lock:" + partNo;
String token = UUID.randomUUID().toString();
try {
// 尝试获取锁
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, token, 30, TimeUnit.SECONDS);
if (!locked) return false;
// 实际扣减逻辑
Part part = partsDao.getByPartNo(partNo);
if (part.getStock() >= num) {
part.setStock(part.getStock() - num);
partsDao.updatePart(part);
return true;
}
return false;
} finally {
// 确保释放自己的锁
if (token.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
5. 扩展性设计思考
5.1 多门店支持方案
为连锁店客户设计的架构演进:
- 数据库分片策略:
- 按门店ID分库(ShardingSphere实现)
- 公共数据全局表(如配件目录)
- 分布式事务:
- 调拨单采用TCC模式
- 使用Seata框架保障一致性
- 区域化部署:
- 华北/华东独立集群
- 通过DNS实现智能路由
5.2 物联网集成
正在实施的车间设备联网方案:
- 诊断设备对接:
- OBD-II数据直传
- 故障码自动解析
- 智能工具管理:
- 蓝牙工具使用追踪
- 扭力扳手数据记录
- AR远程协助:
- 技师眼镜直播
- 专家标注指导
java复制// OBD数据解析示例
public DiagnosticResult parseOBDData(byte[] data) {
// 解析标准OBD-II帧
int serviceId = data[0] & 0xFF;
if (serviceId == 0x41) { // 当前数据
int pid = data[1] & 0xFF;
switch (pid) {
case 0x0C: // 发动机转速
int rpm = ((data[2] << 8) | data[3]) / 4;
return new DiagnosticResult("RPM", rpm);
case 0x0D: // 车速
return new DiagnosticResult("SPEED", data[2]);
// 其他PID处理...
}
}
throw new IllegalStateException("Unsupported OBD data");
}
这套系统经过三年迭代,目前已在23家汽修店稳定运行。最大的体会是:技术永远要为业务服务,我们的每个技术决策都必须回答"这能让客户更快取车吗?能让技师少走一步路吗?"——这才是汽修行业数字化的真谛。
