在开发家政维修与同城上门服务系统时,经常会遇到服务人员现场随意加价、虚报材料费、私下跳单,以及高并发场景下的恶意刷单套利问题。
本文分享一套在实际生产环境中验证过的工程解法:通过服务端强约束的有限状态机(FSM)结合 Redis 滑动窗口算法,实现服务轨迹强锁定与高并发防刷。
一、 家政维修场景:非标工序与材料费拆分 FSM 设计
水电维修、家电清洗等上门服务,核心卡点在于服务人员上门后坐地起价、私带配件扣差价或诱导客户绕过系统私下交易。
在设计这套 FSM 状态机时,可以将维修流程拆分为“工序流”与“账单流”双轨校验。只要项目未经过客户端二次签名确认,新增费用项目在服务端无法写入结算账单。
1.1 状态流转演进轨迹
Plaintext
┌─── CANCELLED (定损未通过) ◄───┐ │ │ [订单派发] ──► ASSIGNED (已接单) ──► ARRIVED (已到户签到) ──► DIAGNOSED (定损报价中) │ (用户确认报价) ▼ [完工结清] ◄── COMPLETED (已完工) ◄── REPAIRED (施工交接) ◄── WORKING (施工中)1.2 状态转移与物理约束校验矩阵
| 当前状态 | 触发动作 | 目标状态 | 物理约束校验核心逻辑 |
已接单(ASSIGNED) | 到户签到 (ARRIVE) | 已到户(ARRIVED) | 强校验:移动端上传的 LBS 坐标与订单服务地址距离必须小于 200 米,超范围无法签到。 |
已到户(ARRIVED) | 提交定损 (DIAGNOSE) | 定损报价中(DIAGNOSED) | 强校验:人工工时费和材料消耗明细必须分开填,且强制上传至少 2 张现场细节照片。 |
定损报价中(DIAGNOSED) | 用户授权 (CONFIRM_QUOTE) | 施工中(WORKING) | 强校验:必须等客户端签署电子定损单;用户如果拒绝报价,订单直接走取消流退款。 |
施工中(WORKING) | 完成施工 (FINISH_JOB) | 施工交接(REPAIRED) | 强校验:必须上传修复后的效果图,以及替换下来的旧配件照片。 |
施工交接(REPAIRED) | 确认完工 (CONFIRM_PAY) | 已完工(COMPLETED) | 触发底层结算接口,按用户最终确认的账单比例解冻并清算。 |
1.3 材料费与工时费拆分校验核心代码
TypeScript
export interface MaintenanceItem { itemId: string; itemName: string; itemType: 'LABOR' | 'MATERIAL'; // 人工费与材料费强类型隔离 unitPrice: number; // 单位:分 quantity: number; } export interface MaintenanceQuotePayload { orderId: string; workerId: string; items: MaintenanceItem[]; evidencePhotos: string[]; } export class MaintenanceFSMValidator { /** * 校验定损报价合法性,防止随意虚报材料费与加价 */ public static validateQuote(payload: MaintenanceQuotePayload): { isValid: boolean; reason?: string; totalAmount?: number } { if (!payload.evidencePhotos || payload.evidencePhotos.length < 2) { return { isValid: false, reason: "定损失败:必须上传至少2张现场细节照片" }; } let laborTotal = 0; let materialTotal = 0; for (const item of payload.items) { if (item.unitPrice <= 0 || item.quantity <= 0) { return { isValid: false, reason: `明细项 [${item.itemName}] 单价或数量异常` }; } if (item.itemType === 'LABOR') { laborTotal += item.unitPrice * item.quantity; } else if (item.itemType === 'MATERIAL') { materialTotal += item.unitPrice * item.quantity; } } // 材料费上限控制:若材料费超出标准阈值,触发系统人工核验标记 if (materialTotal > 50000 && materialTotal > laborTotal * 3) { return { isValid: false, reason: "材料费比例异常过高,系统已自动提交二次核验" }; } return { isValid: true, totalAmount: laborTotal + materialTotal }; } }二、 上门服务场景:LBS 实时轨迹与紧急告警机制
上门服务场景流动性强,工程难点在于确保轨迹不被作弊软件伪造,以及遇上突发状况时能毫秒级告警。
2.1 双重 LBS 围栏与基站/蓝牙双校验机制
为了防止服务人员使用虚拟定位软件修改 GPS 坐标进行虚假签到或提前点击完工,系统建立以下三重校验机制:
GPS 坐标与基站定位交叉比对:移动端原生 SDK 定期上报运营商 Cell ID 和基站信息,服务端网关随时计算 GPS 和基站经纬度偏差。偏差大于 1.5 公里直接判定为定位作弊。
停留超时异常判定:状态切换到
IN_SERVICE后,服务端开启高频轨迹监听。人员在非目标地点停滞超过 15 分钟且偏离路线时,后台看板自动收到预警工单。一键告警响应网关:移动端内置静默按键,触发后系统绕过常规业务网关,直接通过低延迟 WebSocket 通道把位置坐标和环境音频流推送至值班后台。
2.2 服务生命周期 FSM 规约
Plaintext
┌─── ABORTED (异常终止) ◄───┐ │ │ [派单/抢单] ──► DEPARTED (行程中) ──► ARRIVED (已到户) ──► IN_SERVICE (服务中) │ ▼ [订单完成] ◄── COMPLETED (已完工) ◄── FINISHED (已确认) ◄────────┘三、 基于 Redis 滑动窗口的分布式防刷单与多方结算
平台在推广期容易面临黑产攻击(如刷单骗取补贴),在结算环节也需要高并发下的对账自愈能力。
3.1 基于 Redis Lua 脚本的防刷算法
系统建立设备指纹(Device Fingerprint)、IP 拓扑和 LBS 物理距离结合的实时防刷引擎:
TypeScript
// 基于 Redis Lua 脚本的滑动窗口防刷校验代码 const antiFraudLuaScript = ` local key = KEYS[1] -- 组合 Key: USER_ID + WORKER_ID + LBS_HASH local limit = tonumber(ARGV[1]) -- 允许的最大频次阈值 local window = tonumber(ARGV[2]) -- 时间窗口(秒) local now = tonumber(ARGV[3]) -- 当前时间戳 redis.call('ZREMRANGEBYSCORE', key, 0, now - window) local currentRequests = redis.call('ZCARD', key) if currentRequests >= limit then return 0 -- 判定为高危刷单行为,直接拦截 else redis.call('ZADD', key, now, now) redis.call('EXPIRE', key, window) return 1 -- 校验通过 end `;防刷关键逻辑:
设备与账号绑定检测:同一台手机 24 小时内更换超过 2 个服务账号登录,自动冻结派单权限。
LBS 物理同频拦截:若下单用户坐标和服务人员坐标在派单前 3 分钟内重合率高达 95% 以上,判定为同频刷单,自动拦截补贴。
3.2 多方清分接口 JSON 报文设计
服务完工后,系统通过异步消息队列驱动底层执行多方结算划拨:
JSON
{ "app_id": "app_88888888", "trade_no": "4200000000202607290000123456", "out_order_no": "SETTLE_202607290888", "split_receivers": [ { "account_type": "USER_ID", "account_id": "usr_worker_123", "amount": 24000, "rule_tag": "WORKER_REWARD" }, { "account_type": "MERCHANT_ID", "account_id": "mch_agent_208", "amount": 3000, "rule_tag": "AGENT_COMMISSION" } ], "auto_unfreeze": true }四、 账单自愈与财务对账机制
由于第三方支付渠道结算存在时间差,这里引入自适应动态字典映射引擎,每天深夜 23:30 自动拉取原始对账单与系统的 FSM 状态日志进行比对。对账引擎会自动识别材料费与人工费的差异字段并清洗自愈,一旦有账目异常毫秒级预警,避免坏账死锁。