// 告警消息解析工具 // 参考 doc_eldercare/alert.md 设计 export type AlertParseResult { type : string; // 解析后的类型,如 'SOS', '健康数据', '定位', '通知', '计步', '围栏', '语音', '睡眠', '手表', '未知' title : string; // 简要标题 content : string; // 展示内容 time ?: string; // 时间 raw : any; // 原始数据 level ?: 'normal' | 'warn' | 'danger'; // 可选,紧急等级 mid ?: string; // 设备ID smid ?: string; // 消息ID extra ?: UTSJSONObject; // 其它解析字段 } /** * 解析推送消息主入口 * @param msg 传入ps_push_msg_raw的raw_data对象或完整record */ export const parseAlertMessage = (msg : UTSJSONObject) : AlertParseResult => { // 兼容 record/raw_data let data : UTSJSONObject = msg.getJSON('raw_data') ?? {}; const pushType = data.getNumber('pushType') ?? 0; const action = data.getNumber('actionRaw') ?? 0; const time = data.getString('Time') ?? data.getString('time') ?? data.getString('created_at') ?? ''; // 1. SOS if (pushType === 1) { return { type: 'SOS', title: 'SOS求救', content: `${data.getString('Name') ?? ''}(${data.getString('MID') ?? ''}) 向您发出求救`, time, raw: msg, level: 'danger', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { lon: data.getNumber('Lon'), lat: data.getNumber('Lat'), address: data.getString('Str') } }; } // 2. 健康数据 if (pushType === 2) { let arr : string[] = []; const h = data.getNumber('H'); const o = data.getNumber('O'); const w = data.getNumber('W'); const x = data.getNumber('X'); const y = data.getNumber('Y'); if (h != null) arr.push(`心率:${h}`); if (o != null) arr.push(`血氧:${o}`); if (w != null) arr.push(`体温:${w}`); if (x != null) arr.push(`高压:${x}`); if (y != null) arr.push(`低压:${y}`); return { type: '健康数据', title: '健康数据推送', content: arr.length > 0 ? arr.join(',') : JSON.stringify(data), time, raw: msg, level: 'normal', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { mid: data.getString('MID') ?? data.getString('mid') } }; } // 3. 定位 if (pushType === 3) { return { type: '定位', title: '定位推送', content: `${data.getString('Pro') ?? ''}${data.getString('City') ?? ''}${data.getString('Dist') ?? ''}${data.getString('Str') ?? ''} (${data.getNumber('Lon')},${data.getNumber('Lat')})`, time: data.getString('CT') ?? data.getString('UT') ?? time, raw: msg, level: 'normal', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { lon: data.getNumber('Lon'), lat: data.getNumber('Lat') } }; } // 4. 通知 if (pushType === 4) { const actionMapObj = { '-1': '设备在线离线', '4': '围栏内停留', '5': '离开围栏', '6': '进入围栏', '9': '低电报警', '11': '跌倒报警', '23': '高温报警', '26': '断开wifi', '28': 'wifi离线', '36': '防盗报警', '42': '布防告警', '44': '在家布防告警', '7': 'SOS报警', '10': '摘除报警', '22': '低温报警', '24': '更换SIM卡', '27': '连接wifi', '35': '社区养老报警', '37': '状态通知', '43': '撤防告警', '45': '八件套报警', '47': 'wifi不一致报警', '49': '红外报警', '50': 'NB按键报警', '51': 'NB防拆报警', '52': 'NB报警复位', '61': 'NB设备报警', '63': '人体存在报警', '67': 'NB测试报警', '85': '网关上线', '87': '删除子设备', '114': '烟感/气感/门磁事件', '116': 'SCA事件', '118': '防跌倒雷达', '121': '智能胸牌告警', '84': '网关离线', '86': '添加子设备', '113': '门磁事件', '115': '拉绳SOS', '117': '4G视频门磁', '119': 'd5网关子设备报警', '122': 'NB温湿度报警', '123': '气感报警', '125': '水浸报警', '127': '跌倒报警', '129': '燃气报警', '131': '对讲SOS', '134': 'AI智能报警', '124': '烟感报警', '126': '摄像头报警', '128': '井盖报警', '130': '红外报警', '132': 'ZML_SOS报警', '200': '设备信息变更' }; let actionStr:string = actionMapObj.getString(action.toString()) ?? `通知类型:${action}`; return { type: '通知', title: actionStr, content: `${data.getString('Name') ?? ''} ${data.getString('Content') ?? ''}`.trim() ?? JSON.stringify(data), time, raw: msg, level: (action === 9 || action === 11 || action === 23 || action === 7) ? 'danger' : 'warn', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { action } }; } // 5. 计步/翻转(pushType=5 或有 Step/Roll 字段) if (pushType === 6) { return { type: '计步', title: '计步/翻转', content: `步数:${data.getNumber('Step') ?? '-'} 翻转:${data.getNumber('Roll') ?? '-'}`, time, raw: msg, level: 'normal', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { step: data.getNumber('Step'), roll: data.getNumber('Roll'), mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid') } }; } // 6. 围栏(进出围栏、进入围栏、离开围栏等) if (pushType === 7 || (pushType === 4 && (action === 6 || action === 5))) { let actionStr = ''; if (pushType === 4) { if (action === 6) actionStr = '进入围栏'; else if (action === 5) actionStr = '离开围栏'; else actionStr = '围栏事件'; } else { actionStr = '进出围栏'; } return { type: '围栏', title: actionStr, content: data.getString('Content') ?? JSON.stringify(data), time, raw: msg, level: 'warn', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { lon: data.getNumber('Lon'), lat: data.getNumber('Lat'), action } }; } // 7. 微聊语音 if (pushType === 8) { let msgType = data.getNumber('msgType') ?? data.getNumber('MType') ?? 0; let typeStr = msgType === 2 ? '语音' : '文字'; return { type: '微聊', title: `微聊${typeStr}消息`, content: data.getString('content') ?? JSON.stringify(data), time, raw: msg, level: 'normal', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { msgType } }; } // 8. 睡眠带报警 if (pushType === 9) { return { type: '睡眠报警', title: '睡眠带报警', content: data.getString('Content') ?? JSON.stringify(data), time, raw: msg, level: 'warn', mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid'), extra: { action } }; } // 9. 其它类型可继续补充... // 默认 return { type: '未知', title: '未知推送', content: JSON.stringify(data), time, raw: msg, mid: data.getString('MID') ?? data.getString('mid'), smid: data.getString('SMID') ?? data.getString('smid') }; };