diff --git a/src/api/homeAlarm.ts b/src/api/homeAlarm.ts index 8a056d4..1301f64 100644 --- a/src/api/homeAlarm.ts +++ b/src/api/homeAlarm.ts @@ -12,16 +12,46 @@ export interface AlarmListReq { pageSize?: number } -// 骨架:本期仅锁定接口路径,字段类型联调时修正(spec D7) +// 2026-09-23 联调实测字段(.getList 真实响应): +// - 无 homeId 字段;alarmType 是告警类型字典 ID(非文案),文案在 content +// - 时间字段是 createTime / lastUpdateTime,无 alarmTime +// - status: 0-待处理 1-已忽略 2-已处理 3-自动处理(2026-09-23 后端确认) +// - level: 5(告警级别,语义待字典确认);category: 'DEVICE' export interface HomeAlarm { alarmId: string - homeId: string - roomId: string + content: string // 告警文案,如「跌倒检测器 No.01于2026-09-23 14:19:08发生确认跌倒」 + level?: number + status: number + category?: string + alarmType: string // 告警类型字典 ID,前端不直接展示 deviceId: string - deviceName: string - alarmType: string - alarmTime: string - status: number // 告警状态:0-未处理 1-已处理 2-已忽略(待实测确认枚举) + deviceName: string // 设备序列号 + deviceAlias?: string | null // 设备别名(如「跌倒检测器 No.01」),展示优先于 deviceName + roomId: string + roomName?: string | null + productId?: string + createTime: string + lastUpdateTime?: string + // 详情接口附加的告警扩展信息(列表接口为 null) + otherInfo?: { + appName?: string + description?: string + alarmName?: string // 告警名称,如「跌倒报警」 + deviceSn?: string + installId?: string + deviceName?: string + content?: string + realName?: string + alertTypeName?: string // 告警分类名,如「设备告警消息」 + systemName?: string + cameraId?: string + appId?: string + alertTime?: string + cameraName?: string + deviceLocation?: string + } | null + videoUrl?: string | null + capturePicUrl?: string | null } export function getAlarmList(params: AlarmListReq): Promise { diff --git a/src/app.config.ts b/src/app.config.ts index 13425d5..7c8f54d 100644 --- a/src/app.config.ts +++ b/src/app.config.ts @@ -18,6 +18,10 @@ export default { { root: 'pages/family', pages: ['index', 'detail', 'contact/add', 'contact/detail'] + }, + { + root: 'pages/event/feature', + pages: ['detail'] } ], window: { diff --git a/src/components/list-row/index.module.scss b/src/components/list-row/index.module.scss index c40c964..631acce 100644 --- a/src/components/list-row/index.module.scss +++ b/src/components/list-row/index.module.scss @@ -33,9 +33,11 @@ } .value { - margin-left: 24px; + // 推到行尾紧贴箭头:无箭头时贴右边距;否则三元素 space-between 会把 value 挤到中间 + margin-left: auto; font-size: 28px; color: $color-text; + text-align: right; } .arrow { diff --git a/src/components/list-row/index.tsx b/src/components/list-row/index.tsx index c17e5b0..0ed9975 100644 --- a/src/components/list-row/index.tsx +++ b/src/components/list-row/index.tsx @@ -5,12 +5,13 @@ import styles from './index.module.scss' interface ListRowProps { label: string value?: string + valueClass?: string arrow?: boolean onClick?: () => void danger?: boolean } -export function ListRow({ label, value, arrow, onClick, danger }: ListRowProps) { +export function ListRow({ label, value, valueClass, arrow, onClick, danger }: ListRowProps) { const cls = [styles.row, danger ? styles.rowDanger : ''].filter(Boolean).join(' ') return ( {label} - {value && {value}} + {value && {value}} {arrow && ›} ) diff --git a/src/constants/routes.ts b/src/constants/routes.ts index b720ca0..5b269e8 100644 --- a/src/constants/routes.ts +++ b/src/constants/routes.ts @@ -2,6 +2,7 @@ export const ROUTES = Object.freeze({ LOGIN: '/pages/login/index', HOME: '/pages/index/index', EVENT: '/pages/event/index', + EVENT_DETAIL: '/pages/event/feature/detail', MINE: '/pages/mine/index', DEVICE_LIST: '/pages/device/index', DEVICE_ADD: '/pages/device/feature/add', diff --git a/src/pages/event/feature/detail.module.scss b/src/pages/event/feature/detail.module.scss new file mode 100644 index 0000000..a4d0466 --- /dev/null +++ b/src/pages/event/feature/detail.module.scss @@ -0,0 +1,107 @@ +.page { + min-height: 100vh; + background: $color-bg; + padding-bottom: 40px; +} + +.stateWrap { + margin-top: 120px; + display: flex; + flex-direction: column; + align-items: center; +} + +// 告警头卡:白底渐变浮卡,左侧语义色竖条强调紧急度 +.headCard { + margin: 24px; + padding: 32px; + background: $color-bg-white; + border-radius: $radius-lg; + box-shadow: $shadow-card; + display: flex; + flex-direction: column; +} + +.headTop { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 16px; +} + +.alarmName { + font-size: 34px; + font-weight: 600; + color: $color-text; +} + +// 状态徽章 +.tag { + display: inline-block; + padding: 6px 20px; + border-radius: $radius-pill; + font-size: 22px; + font-weight: 500; + flex-shrink: 0; + margin-left: 16px; +} + +// 待处理:红(需关注) +.tagPending { + background: $color-danger-light-bg; + color: $color-danger; +} + +// 已处理:绿 +.tagDone { + background: $color-success-light-bg; + color: $color-success; +} + +// 已忽略/未知:灰 +.tagIgnored { + background: $color-bg-disabled; + color: $color-text-secondary; +} + +.content { + font-size: 28px; + color: $color-text; + line-height: 1.6; +} + +.headMeta { + margin-top: 16px; + display: flex; + align-items: center; +} + +.metaText { + font-size: 24px; + color: $color-text-secondary; +} + +.metaDot { + margin: 0 12px; + font-size: 24px; + color: $color-text-placeholder; +} + +// 现场抓拍图 +.capture { + margin-top: 24px; + width: 100%; + height: 360px; + border-radius: $radius-md; +} + +.section { + margin: 0 24px 24px; +} + +.sectionTitle { + display: block; + font-size: 26px; + color: $color-text-secondary; + margin: 0 8px 16px; +} diff --git a/src/pages/event/feature/detail.tsx b/src/pages/event/feature/detail.tsx new file mode 100644 index 0000000..53cf5d5 --- /dev/null +++ b/src/pages/event/feature/detail.tsx @@ -0,0 +1,113 @@ +import { useState, useEffect } from 'react' +import { useRouter } from '@tarojs/taro' +import { View, Text, Image } from '@tarojs/components' +import { Navbar } from '@/components/navbar' +import { Loading } from '@/components/loading' +import { StateView } from '@/components/state-view' +import { ListRow, ListRowGroup } from '@/components/list-row' +import { getAlarmDetail, type HomeAlarm } from '@/api/homeAlarm' +import { navigateTo } from '@/utils/navigation' +import { ROUTES } from '@/constants/routes' +import styles from './detail.module.scss' + +// 状态 → 徽章文案与语义色(2026-09-23 后端确认:0-待处理 1-已忽略 2-已处理 3-自动处理) +const STATUS_META: Record = { + 0: { label: '待处理', cls: 'tagPending' }, + 1: { label: '已忽略', cls: 'tagIgnored' }, + 2: { label: '已处理', cls: 'tagDone' }, + 3: { label: '自动处理', cls: 'tagIgnored' } +} + +export default function AlarmDetail() { + const router = useRouter() + const alarmId = router.params.id ?? '' + + const [loading, setLoading] = useState(true) + const [alarm, setAlarm] = useState(null) + + useEffect(() => { + if (!alarmId) { + setLoading(false) + return + } + setLoading(true) + getAlarmDetail(alarmId) + .then(setAlarm) + .catch(() => setAlarm(null)) + .finally(() => setLoading(false)) + }, [alarmId]) + + if (loading) { + return ( + + + + + ) + } + + if (!alarm) { + return ( + + + + + ) + } + + const meta = STATUS_META[alarm.status] ?? { label: '未知状态', cls: 'tagIgnored' } + const deviceLabel = alarm.deviceAlias || alarm.deviceName || alarm.deviceId || '未知设备' + const ext = alarm.otherInfo + + const goDevice = () => { + if (ext?.installId) navigateTo(`${ROUTES.DEVICE_DETAIL}?id=${ext.installId}&name=${encodeURIComponent(deviceLabel)}`) + } + + return ( + + + + {/* 告警头卡:名称 + 状态徽章 + 文案 + 时间 */} + + + {ext?.alarmName || '设备告警'} + {meta.label} + + {alarm.content} + + {ext?.alertTypeName || '设备告警消息'} + · + {alarm.createTime} + + + {/* 现场抓拍:capturePicUrl 存在时展示 */} + {alarm.capturePicUrl && ( + + )} + + + {/* 告警信息组 */} + + 告警信息 + + + + + + + {ext?.deviceLocation && } + + + + {/* 现场视频:videoUrl 存在时提示跳转(视频播放器暂未接入) */} + {alarm.videoUrl && ( + + 现场记录 + + navigateTo(`${ROUTES.DEVICE_DETAIL}?id=${alarm.deviceId}`)} /> + + + )} + + ) +} diff --git a/src/pages/event/index.module.scss b/src/pages/event/index.module.scss index 58bb159..d533f36 100644 --- a/src/pages/event/index.module.scss +++ b/src/pages/event/index.module.scss @@ -78,6 +78,7 @@ border-radius: $radius-lg; box-shadow: $shadow-card; padding: 28px 32px; + border: 1px solid transparent; & + & { margin-top: 20px; } } @@ -90,20 +91,52 @@ } .alarm-type { + flex: 1; + min-width: 0; font-size: 30px; font-weight: 600; color: $color-text; + // 多行文案截断到两行:跌倒类告警 content 常带完整时间戳较长 + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + overflow: hidden; +} + +// 告警类型左侧色条行标:红点提示设备类告警语义 +.alarm-type-dot { display: inline-block; + width: 14px; + height: 14px; + border-radius: $radius-circle; + background: $color-danger; + margin-right: 12px; + flex-shrink: 0; } .alarm-tag { + display: inline-block; font-size: 22px; - padding: 4px 16px; + padding: 6px 16px; border-radius: $radius-pill; color: $color-text-secondary; background: $color-bg-gray; + flex-shrink: 0; } -/* 状态枚举待实测,先按未处理红色、已处理绿色、已忽略灰的常见语义 */ +// 标题行:红点 + 两行截断文案 +.alarmTypeWrap { + flex: 1; + min-width: 0; + margin-right: 16px; + display: flex; + align-items: center; +} + +.alarmCardPressed { + border-color: $color-primary-light-border; +} + +/* 状态语义色:0-待处理红 2-已处理绿 1/3-已忽略/自动处理灰(2026-09-23 后端确认枚举) */ .tag1 { color: $color-danger; background: $color-danger-light-bg; diff --git a/src/pages/event/index.tsx b/src/pages/event/index.tsx index eddcb5c..87500a5 100644 --- a/src/pages/event/index.tsx +++ b/src/pages/event/index.tsx @@ -4,8 +4,11 @@ import { View, Text } from '@tarojs/components' import { Navbar } from '@/components/navbar' import { Empty } from '@/components/empty' import { getHomeList, type HomeInfo } from '@/api/home' +import { resolveCurrentHome } from '@/store/currentHome' import { getRoomList, type HomeRoom } from '@/api/homeRoom' import { getAlarmList, type HomeAlarm } from '@/api/homeAlarm' +import { navigateTo } from '@/utils/navigation' +import { ROUTES } from '@/constants/routes' import { CalendarDrawer } from './calendar-drawer' import styles from './index.module.scss' @@ -14,11 +17,12 @@ interface FilterOption { name: string } -// 告警状态筛选枚举(后端 integer,待实测确认:1-未处理 2-已处理 3-已忽略) +// 告警状态枚举(2026-09-23 后端确认:0-待处理 1-已忽略 2-已处理 3-自动处理) const ALARM_STATUS: Record = { - '1': '未处理', + '0': '待处理', + '1': '已忽略', '2': '已处理', - '3': '已忽略' + '3': '自动处理' } export default function Event() { @@ -37,16 +41,18 @@ export default function Event() { const [roomOptions, setRoomOptions] = useState([{ id: '', name: '全部' }]) const statusOptions: FilterOption[] = [ { id: '', name: '全部' }, - { id: '1', name: '未处理' }, + { id: '0', name: '待处理' }, + { id: '1', name: '已忽略' }, { id: '2', name: '已处理' }, - { id: '3', name: '已忽略' } + { id: '3', name: '自动处理' } ] - // 默认家庭 + 其房间列表:失败时保留"全部"选项不阻塞筛选 + // 当前家庭 + 其房间列表:与智能设备页共享选择(resolveCurrentHome 读持久化), + // 失败时保留"全部"选项不阻塞筛选 useEffect(() => { getHomeList() .then(async (list) => { - const first = list[0] ?? null + const first = resolveCurrentHome(list) setHome(first) if (!first) return const rooms = await getRoomList(first.homeId) @@ -135,9 +141,10 @@ export default function Event() { // CSS Modules 动态 key 映射对象(避免索引签名问题) const tagClsMap: Record = { - '1': styles.tag1, - '2': styles.tag2, - '3': styles.tag3 + '0': styles.tag1, // 待处理-红 + '1': styles.tag3, // 已忽略-灰 + '2': styles.tag2, // 已处理-绿 + '3': styles.tag3 // 自动处理-灰 } return ( @@ -181,18 +188,26 @@ export default function Event() { ) : ( {alarmList.map((alarm) => ( - + navigateTo(`${ROUTES.EVENT_DETAIL}?id=${alarm.alarmId}`)} + > - {alarm.alarmType} + + + {alarm.content || '告警消息'} + {statusTagOf(alarm)} 设备 - {alarm.deviceName || alarm.deviceId} + {alarm.deviceAlias || alarm.deviceName || alarm.deviceId} 时间 - {alarm.alarmTime} + {alarm.createTime} ))} diff --git a/src/pages/family/detail.module.scss b/src/pages/family/detail.module.scss index 4fe9f34..358de08 100644 --- a/src/pages/family/detail.module.scss +++ b/src/pages/family/detail.module.scss @@ -125,6 +125,21 @@ color: $color-text-tertiary; } +// 家庭成员行「群主」徽章:浅绿底胶囊,右贴箭头 +// margin-left:auto 在 flex 行里把它推到最右;Text 需 inline-block 撑高背景 +.valueTag { + display: inline-block; + line-height: 1.4; + padding: 6px 20px; + background: $color-primary-light-bg; + border-radius: $radius-pill; + font-size: 22px; + font-weight: 500; + color: $color-primary-deep; + margin-left: auto; + flex-shrink: 0; +} + // 转让群主选人弹层(Modal 内容) .transferTitle { display: block; diff --git a/src/pages/family/detail.tsx b/src/pages/family/detail.tsx index b74f250..536a3db 100644 --- a/src/pages/family/detail.tsx +++ b/src/pages/family/detail.tsx @@ -9,7 +9,7 @@ import { StateView } from '@/components/state-view' import { FamilyCard } from '@/components/family-card' import { ListRow, ListRowGroup } from '@/components/list-row' import { Modal } from '@/components/modal' -import { getHomeDetail, getHomeMemberList, joinHome, transferOwner, type HomeInfo, type HomeMember } from '@/api/home' +import { getHomeDetail, getHomeMemberList, joinHome, transferOwner, updateMemberNickName, type HomeInfo, type HomeMember } from '@/api/home' import { getCareMemberList, type CareMember } from '@/api/careMember' import { MAX_CARED_PER_FAMILY } from '@/constants/family' import { ROUTES } from '@/constants/routes' @@ -17,8 +17,22 @@ import { navigateBack, navigateTo, reLaunch } from '@/utils/navigation' import { showToast } from '@/utils/toast' import styles from './detail.module.scss' +// Taro 类型未跟进 wx.showModal 的 editable 扩展(微信 2.17.1+),运行时真实存在 +interface EditableModalOption extends Taro.showModal.Option { + editable?: boolean + placeholderText?: string +} + +interface EditableModalResult extends Taro.showModal.SuccessCallbackResult { + content?: string +} + +const showEditableModal = (option: EditableModalOption) => + Taro.showModal(option as Taro.showModal.Option) as Promise + // 成员显示名:家庭内昵称优先,未设置回落微信昵称 -const memberName = (m: HomeMember): string => m.nickName ?? m.userNickName ?? '成员' +// 注意 2026-09-23 实测:清空昵称后端返回空串 '' 而非 null,需按空白处理 +const memberName = (m: HomeMember): string => m.nickName?.trim() || m.userNickName?.trim() || '成员' // 关爱对象联系人摘要:最多显示前 2 位姓名,其余以 +N 概括;未填则不显示 const contactsSummary = (c: CareMember): string => { @@ -45,6 +59,8 @@ export default function FamilyDetail() { // 转让群主:底部入口仅群主可见,点击后弹选人 Modal const [transferOpen, setTransferOpen] = useState(false) const [transferring, setTransferring] = useState(false) + // 改昵称:点击成员行触发 + const [renaming, setRenaming] = useState(false) const load = async () => { // 分享卡直达本页且未登录:先去登录,登录后回跳本页 @@ -114,9 +130,13 @@ export default function FamilyDetail() { // 我在成员列表里的角色:转让入口只对群主开放 const myMember = members.find((m) => m.memberId === myUserId) ?? null const isOwner = myMember?.role === 'OWNER' + // 注意:成员响应无 userId 字段(2026-09-23 实测),memberId 是家庭圈成员记录 ID, + // 与登录 userId 不同源,isOwner 恒为 false——仅作未来后端补字段后的预留,勿用于门禁 + // 转让/改昵称入口全开:前端无法可靠识别自己,由后端权威校验 + // (transferOwner 实测已有 400「不能转让给自己」「成员不存在」等完整校验) const openTransfer = () => { - if (!isOwner || transferring) return + if (transferring) return setTransferOpen(true) } const closeTransfer = () => { @@ -138,6 +158,37 @@ export default function FamilyDetail() { } } + // 点击成员行改昵称:wx.showModal editable 输入框,预填当前昵称 + const renameMember = async (target: HomeMember) => { + if (renaming) return + setRenaming(true) + try { + const { confirm, content } = await showEditableModal({ + title: '修改群昵称', + editable: true, + placeholderText: '请输入新的昵称', + content: target.nickName ?? '' + }) + if (!confirm) return + const next = (content ?? '').trim() + if (!next) { + showToast('昵称不能为空') + return + } + if (next === (target.nickName ?? '').trim()) { + showToast('昵称未变化') + return + } + await updateMemberNickName({ memberId: target.memberId, nickName: next }) + showToast('已修改') + await load() + } catch (e) { + showToast(e instanceof Error ? e.message : '修改失败') + } finally { + setRenaming(false) + } + } + if (loading) { return ( @@ -219,7 +270,14 @@ export default function FamilyDetail() { ) : ( {members.map((m) => ( - + renameMember(m)} + /> ))} )} @@ -237,34 +295,31 @@ export default function FamilyDetail() { 邀请他人 › - - + - {/* 转让群主选人弹层:列出除自己外的成员,选中即调用 transferOwner */} + {/* 转让群主选人弹层:全部成员可选(含自己),后端对「转让给自己」返回 400 由 toast 透出 */} 转让群主给谁? - {members.filter((m) => m.memberId !== myUserId).length === 0 ? ( + {members.length === 0 ? ( 暂无可转让的成员 ) : ( - members - .filter((m) => m.memberId !== myUserId) - .map((m) => ( - doTransfer(m)} - > - {memberName(m)} - - {m.role === 'OWNER' ? '群主' : '成员'} · 群昵称:{m.nickName ?? '未设置'} - - - )) + members.map((m) => ( + doTransfer(m)} + > + {memberName(m)} + + {m.role === 'OWNER' ? '群主' : '成员'} · 群昵称:{m.nickName || '未设置'} + + + )) )} diff --git a/src/pages/index/index.tsx b/src/pages/index/index.tsx index e2cb537..f544ed7 100644 --- a/src/pages/index/index.tsx +++ b/src/pages/index/index.tsx @@ -6,12 +6,12 @@ import { Loading } from '@/components/loading' import { Empty } from '@/components/empty' import { StateView } from '@/components/state-view' import { getHomeList, type HomeInfo } from '@/api/home' +import { resolveCurrentHome } from '@/store/currentHome' import { getAlarmList, type HomeAlarm } from '@/api/homeAlarm' import { store } from '@/store' import { storage } from '@/utils/storage' import { ROUTES } from '@/constants/routes' import { navigateTo, reLaunch } from '@/utils/navigation' -import { showToast } from '@/utils/toast' import { splitAlerts } from './splitAlerts' import styles from './index.module.scss' @@ -26,7 +26,8 @@ export default function Index() { setLoadError(false) try { const homes = await getHomeList() - const first: HomeInfo | undefined = homes[0] + // 与智能设备页共享当前家庭:优先持久化选择,失效回落第一条(resolveCurrentHome 内重新落盘) + const first: HomeInfo | null = resolveCurrentHome(homes) if (!first) { setAlertList([]) return @@ -52,7 +53,7 @@ export default function Index() { const { unhandled, messages } = useMemo(() => splitAlerts(alertList), [alertList]) const goFamily = () => navigateTo(ROUTES.FAMILY) - const goAlertDetail = () => showToast('告警详情即将上线') + const goAlertDetail = (alarmId: string) => navigateTo(`${ROUTES.EVENT_DETAIL}?id=${alarmId}`) return ( @@ -67,13 +68,13 @@ export default function Index() { {unhandled.length > 0 && ( - + goAlertDetail(unhandled[0].alarmId)} /> )} {messages.length > 0 && ( {messages.map((alert) => ( - + goAlertDetail(alert.alarmId)} /> ))} )} @@ -108,19 +109,19 @@ function UnhandledAlert({ alert, onClick }: { alert: HomeAlarm; onClick: () => v ! - {alert.deviceName || alert.deviceId || '未知设备'} + {alert.deviceAlias || alert.deviceName || alert.deviceId || '未知设备'} - 未处理 + 待处理 - {alert.alarmType && ( + {alert.content && ( - {alert.alarmType} + {alert.content} )} - {alert.alarmTime && ( + {alert.createTime && ( - {alert.alarmTime} + {alert.createTime} )} @@ -135,11 +136,11 @@ function AlertMessageItem({ alert, onClick }: { alert: HomeAlarm; onClick: () => - {alert.alarmType || '告警消息'} - {alert.alarmTime && {alert.alarmTime}} + {alert.content || '告警消息'} + {alert.createTime && {alert.createTime}} - {alert.deviceName && ( - {alert.deviceName} + {(alert.deviceAlias || alert.deviceName) && ( + {alert.deviceAlias || alert.deviceName} )} diff --git a/src/pages/index/splitAlerts.ts b/src/pages/index/splitAlerts.ts index 1a87da8..be8bd0a 100644 --- a/src/pages/index/splitAlerts.ts +++ b/src/pages/index/splitAlerts.ts @@ -1,6 +1,7 @@ import type { HomeAlarm } from '@/api/homeAlarm' -// 首页告警分流:status=1 未处理(首页只展示最新一条),其余全部进消息列表 +// 首页告警分流:status=0 待处理(首页只展示最新一条),其余全部进消息列表 +// (2026-09-23 后端确认:0-待处理 1-已忽略 2-已处理 3-自动处理) export function splitAlerts(list: HomeAlarm[]): { unhandled: HomeAlarm[] messages: HomeAlarm[] @@ -8,7 +9,7 @@ export function splitAlerts(list: HomeAlarm[]): { const unhandled: HomeAlarm[] = [] const messages: HomeAlarm[] = [] for (const item of list) { - if (item.status === 1) unhandled.push(item) + if (item.status === 0) unhandled.push(item) else messages.push(item) } return { unhandled, messages } diff --git a/tests/unit/home/splitAlerts.spec.ts b/tests/unit/home/splitAlerts.spec.ts index c5d6e9b..7f49a67 100644 --- a/tests/unit/home/splitAlerts.spec.ts +++ b/tests/unit/home/splitAlerts.spec.ts @@ -2,35 +2,37 @@ import { describe, it, expect } from 'vitest' import { splitAlerts } from '@/pages/index/splitAlerts' import type { HomeAlarm } from '@/api/homeAlarm' +// 字段对齐 2026-09-23 实测响应(content/createTime;status 0-待处理 1-已忽略 2-已处理 3-自动处理) const item = (over: Partial): HomeAlarm => ({ alarmId: '1', - homeId: 'h1', roomId: 'r1', deviceId: 'd1', - deviceName: '体征监测仪', - alarmType: '心率异常', - alarmTime: '2026-09-07 21:22:12', - status: 2, + deviceName: '1463937a07a5', + deviceAlias: '跌倒检测器 No.01', + content: '跌倒检测器 No.01发生确认跌倒', + alarmType: '1299830603847491584', + createTime: '2026-09-23 14:19:08', + status: 1, ...over }) describe('splitAlerts', () => { - it('status=1 进入未处理组,其余进入消息组', () => { + it('status=0 进入待处理组,其余进入消息组', () => { const list = [ - item({ alarmId: '1', status: 1 }), - item({ alarmId: '2', status: 2 }), - item({ alarmId: '3', status: 3 }) + item({ alarmId: '1', status: 0 }), + item({ alarmId: '2', status: 1 }), + item({ alarmId: '3', status: 2 }) ] const { unhandled, messages } = splitAlerts(list) expect(unhandled.map((i) => i.alarmId)).toEqual(['1']) expect(messages.map((i) => i.alarmId)).toEqual(['2', '3']) }) - it('status 异常值(如 0、99)落入消息组不丢弃', () => { - const list = [item({ alarmId: '1', status: 0 }), item({ alarmId: '2', status: 99 })] + it('status 异常值(如 99)落入消息组不丢弃', () => { + const list = [item({ alarmId: '1', status: 99 })] const { unhandled, messages } = splitAlerts(list) expect(unhandled).toEqual([]) - expect(messages.map((i) => i.alarmId)).toEqual(['1', '2']) + expect(messages.map((i) => i.alarmId)).toEqual(['1']) }) it('空列表两组均为空', () => { @@ -41,9 +43,9 @@ describe('splitAlerts', () => { it('两组均保持原有相对顺序', () => { const list = [ - item({ alarmId: '3', status: 2 }), - item({ alarmId: '1', status: 1 }), - item({ alarmId: '2', status: 2 }) + item({ alarmId: '3', status: 1 }), + item({ alarmId: '1', status: 0 }), + item({ alarmId: '2', status: 1 }) ] const { unhandled, messages } = splitAlerts(list) expect(unhandled.map((i) => i.alarmId)).toEqual(['1'])