feat(event): 首页/消息中心接入告警列表真实接口,移除事件 mock 层

This commit is contained in:
ozh 2026-09-17 14:30:53 +08:00
parent 7bef729e93
commit 5761a5fed2
8 changed files with 247 additions and 130 deletions

View File

@ -1,26 +0,0 @@
import { request } from '@/http'
const USE_MOCK = true
export interface EventItem {
id: number
sceneName: string
deviceName: string
status: number
time: string
}
export interface EventQuery {
sceneId: number
status: number
startDate: string
endDate: string
}
// 事件列表接口未定:mock 返回空数组,页面保持空态
export function getEventList(_query: EventQuery): Promise<EventItem[]> {
if (USE_MOCK) {
return Promise.resolve([])
}
return request.get<EventItem[]>('/event/list', { ..._query })
}

View File

@ -1,16 +1,30 @@
import { request } from '@/http' import { request } from '@/http'
// 入参对齐 apifox YlHomeAlarmListReq(homeId 必填,其余可选筛选)
export interface AlarmListReq {
homeId: string
roomId?: string // 传入则只查该房间告警
status?: number // 告警状态,不传则不筛选
beginTime?: string // yyyy-MM-dd HH:mm:ss
endTime?: string
pageIndex?: number
pageSize?: number
}
// 骨架:本期仅锁定接口路径,字段类型联调时修正(spec D7) // 骨架:本期仅锁定接口路径,字段类型联调时修正(spec D7)
export interface HomeAlarm { export interface HomeAlarm {
alarmId: string alarmId: string
homeId: string
roomId: string
deviceId: string deviceId: string
deviceName: string
alarmType: string alarmType: string
alarmTime: string alarmTime: string
handled: boolean status: number // 告警状态:0-未处理 1-已处理 2-已忽略(待实测确认枚举)
} }
export function getAlarmList(params: Record<string, unknown>): Promise<HomeAlarm[]> { export function getAlarmList(params: AlarmListReq): Promise<HomeAlarm[]> {
return request.get('/yanglao/app/ylHomeAlarm/getList', params) return request.post('/yanglao/app/ylHomeAlarm/getList', params as unknown as Record<string, unknown>)
} }
export function getAlarmDetail(alarmId: string): Promise<HomeAlarm> { export function getAlarmDetail(alarmId: string): Promise<HomeAlarm> {

View File

@ -7,8 +7,9 @@ export interface HomeRoom {
roomName: string roomName: string
} }
// 文档路径为 POST + body { homeId }(YlHomeRoomListReq)
export function getRoomList(homeId: string): Promise<HomeRoom[]> { export function getRoomList(homeId: string): Promise<HomeRoom[]> {
return request.get('/yanglao/app/ylHomeRoom/getList', { homeId }) return request.post('/yanglao/app/ylHomeRoom/getList', { homeId })
} }
export function addRoom(params: Record<string, unknown>): Promise<void> { export function addRoom(params: Record<string, unknown>): Promise<void> {

View File

@ -68,6 +68,78 @@
color: $color-text-tertiary; color: $color-text-tertiary;
} }
/* 告警卡片列表 */
.alarm-list {
padding: 24px;
}
.alarm-card {
background: $color-bg-white;
border-radius: $radius-lg;
box-shadow: $shadow-card;
padding: 28px 32px;
& + & { margin-top: 20px; }
}
.alarm-head {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 16px;
}
.alarm-type {
font-size: 30px;
font-weight: 600;
color: $color-text;
}
.alarm-tag {
font-size: 22px;
padding: 4px 16px;
border-radius: $radius-pill;
color: $color-text-secondary;
background: $color-bg-gray;
}
/* 状态枚举待实测,先按未处理红色、已处理绿色、已忽略灰的常见语义 */
.tag1 {
color: $color-danger;
background: $color-danger-light-bg;
}
.tag2 {
color: $color-primary-deep;
background: $color-primary-light-bg;
}
.tag3 {
color: $color-text-tertiary;
background: $color-bg-gray;
}
.alarm-row {
display: flex;
align-items: flex-start;
min-height: 48px;
}
.alarm-label {
width: 120px;
flex-shrink: 0;
font-size: 26px;
color: $color-text-secondary;
}
.alarm-value {
flex: 1;
min-width: 0;
font-size: 26px;
color: $color-text;
word-break: break-all;
}
/* 数据层:三抽屉的定位锚点 */ /* 数据层:三抽屉的定位锚点 */
.content-area { .content-area {
position: relative; position: relative;

View File

@ -1,92 +1,112 @@
import { useState, useCallback, useEffect } from 'react' import { useState, useCallback, useEffect } from 'react'
import { useDidShow } from '@tarojs/taro'
import { View, Text } from '@tarojs/components' import { View, Text } from '@tarojs/components'
import { Navbar } from '@/components/navbar' import { Navbar } from '@/components/navbar'
import { Empty } from '@/components/empty' import { Empty } from '@/components/empty'
import { getSceneList } from '@/api/scene' import { getHomeList, type HomeInfo } from '@/api/home'
import { getEventList, type EventItem } from '@/api/event' import { getRoomList, type HomeRoom } from '@/api/homeRoom'
import { getAlarmList, type HomeAlarm } from '@/api/homeAlarm'
import { CalendarDrawer } from './calendar-drawer' import { CalendarDrawer } from './calendar-drawer'
import styles from './index.module.scss' import styles from './index.module.scss'
interface FilterOption { interface FilterOption {
id: number id: string // '' 表示全部
name: string name: string
} }
// 告警状态筛选枚举(后端 integer,待实测确认:1-未处理 2-已处理 3-已忽略)
const ALARM_STATUS: Record<string, string> = {
'1': '未处理',
'2': '已处理',
'3': '已忽略'
}
export default function Event() { export default function Event() {
// '' | 'scene' | 'status' | 'time' // '' | 'room' | 'status' | 'time'
const [drawer, setDrawer] = useState<'' | 'scene' | 'status' | 'time'>('') const [drawer, setDrawer] = useState<'' | 'room' | 'status' | 'time'>('')
// 事件列表:后端接口定型前 mock 返回空数组 → 空态 const [alarmList, setAlarmList] = useState<HomeAlarm[]>([])
const [eventList, setEventList] = useState<EventItem[]>([]) const [loading, setLoading] = useState(true)
const [filters, setFilters] = useState({ const [filters, setFilters] = useState({
sceneId: 0, // 0 表示全部 roomId: '',
status: 0, status: '',
startDate: '', startDate: '',
endDate: '', endDate: '',
timeText: '' timeText: ''
}) })
const [sceneOptions, setSceneOptions] = useState<FilterOption[]>([{ id: 0, name: '全部' }]) const [home, setHome] = useState<HomeInfo | null>(null)
const [roomOptions, setRoomOptions] = useState<FilterOption[]>([{ id: '', name: '全部' }])
const statusOptions: FilterOption[] = [ const statusOptions: FilterOption[] = [
{ id: 0, name: '全部' }, { id: '', name: '全部' },
{ id: 1, name: '未处理' }, { id: '1', name: '未处理' },
{ id: 2, name: '已处理' }, { id: '2', name: '已处理' },
{ id: 3, name: '已忽略' } { id: '3', name: '已忽略' }
] ]
// 场所列表:复用场景接口;失败时保留"全部"不阻塞筛选 // 默认家庭 + 其房间列表:失败时保留"全部"选项不阻塞筛选
useEffect(() => { useEffect(() => {
getSceneList() getHomeList()
.then((data) => { .then(async (list) => {
setSceneOptions([{ id: 0, name: '全部' }, ...(data ?? [])]) const first = list[0] ?? null
setHome(first)
if (!first) return
const rooms = await getRoomList(first.homeId)
setRoomOptions([{ id: '', name: '全部' }, ...rooms.map(toRoomOption)])
}) })
.catch(() => setSceneOptions([{ id: 0, name: '全部' }])) .catch(() => setRoomOptions([{ id: '', name: '全部' }]))
}, []) }, [])
useDidShow(() => {
// 进页首拉:home 就绪与否都调一次,home 为空时后端会报错并保持空态
if (home) loadAlarms(filters)
})
const toRoomOption = (r: HomeRoom): FilterOption => ({ id: r.roomId, name: r.roomName })
const closeDrawer = useCallback(() => setDrawer(''), []) const closeDrawer = useCallback(() => setDrawer(''), [])
const sceneLabel = sceneOptions.find((o) => o.id === filters.sceneId)?.name ?? '全部场所' const roomLabel = roomOptions.find((o) => o.id === filters.roomId)?.name ?? '全部场所'
const statusLabel = statusOptions.find((o) => o.id === filters.status)?.name ?? '全部状态' const statusLabel = statusOptions.find((o) => o.id === filters.status)?.name ?? '全部状态'
// 筛选变化:拉取事件列表(当前 mock 空,保持空态展示) // 拉取告警列表:home 未就绪时跳过(useEffect 到达后由 loadAlarms 首拉兜底)
const handleFilter = useCallback(async (next: typeof filters) => { const loadAlarms = useCallback(async (next: typeof filters, homeId?: string) => {
const targetHomeId = homeId ?? home?.homeId
if (!targetHomeId) return
setLoading(true)
try { try {
const list = await getEventList({ const list = await getAlarmList({
sceneId: next.sceneId, homeId: targetHomeId,
status: next.status, roomId: next.roomId || undefined,
startDate: next.startDate, status: next.status ? Number(next.status) : undefined,
endDate: next.endDate // 接口要求完整时分秒:起止日拼边界值覆盖整天
beginTime: next.startDate ? `${next.startDate} 00:00:00` : undefined,
endTime: next.endDate ? `${next.endDate} 23:59:59` : undefined
}) })
setEventList(list) setAlarmList(list ?? [])
} catch { } catch {
// 失败保持现有列表,toast 由请求封装统一处理 // 失败保持现有列表,toast 由请求封装统一处理
} finally {
setLoading(false)
} }
}, []) }, [home?.homeId])
const selectScene = (id: number) => { // home 就绪后的首拉(初始 useDidShow 时 home 可能还没到)
const next = { ...filters, sceneId: id } useEffect(() => {
if (home) loadAlarms(filters, home.homeId)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [home?.homeId])
const applyFilter = (next: typeof filters) => {
setFilters(next) setFilters(next)
closeDrawer() closeDrawer()
handleFilter(next) loadAlarms(next)
} }
const selectStatus = (id: number) => { const renderOptionDrawer = (kind: 'room' | 'status') => {
const next = { ...filters, status: id } const opts = kind === 'room' ? roomOptions : statusOptions
setFilters(next) const currentId = kind === 'room' ? filters.roomId : filters.status
closeDrawer() const title = kind === 'room' ? '选择场所' : '选择状态'
handleFilter(next) const onSelect = (id: string) =>
} applyFilter(kind === 'room' ? { ...filters, roomId: id } : { ...filters, status: id })
const onTimeConfirm = (start: string, end: string) => {
const next = { ...filters, startDate: start, endDate: end, timeText: `${start} 至 ${end}` }
setFilters(next)
closeDrawer()
handleFilter(next)
}
const renderOptionDrawer = (kind: 'scene' | 'status') => {
const opts = kind === 'scene' ? sceneOptions : statusOptions
const currentId = kind === 'scene' ? filters.sceneId : filters.status
const title = kind === 'scene' ? '选择场所' : '选择状态'
const onSelect = kind === 'scene' ? selectScene : selectStatus
return ( return (
<View className={styles.dropPanelOptions}> <View className={styles.dropPanelOptions}>
<View className={styles.drawerHeader}> <View className={styles.drawerHeader}>
@ -111,20 +131,29 @@ export default function Event() {
) )
} }
const statusTagOf = (alarm: HomeAlarm) => ALARM_STATUS[String(alarm.status)] ?? '未知'
// CSS Modules 动态 key 映射对象(避免索引签名问题)
const tagClsMap: Record<string, string> = {
'1': styles.tag1,
'2': styles.tag2,
'3': styles.tag3
}
return ( return (
<View className={styles.page}> <View className={styles.page}>
<Navbar title="消息中心" autoBack={false} variant="hero" /> <Navbar title="消息中心" autoBack={false} variant="hero" />
{/* 筛选栏:三格等分 */} {/* 筛选栏:三格等分 */}
<View className={styles.filters}> <View className={styles.filters}>
<View className={styles.filterCell} onClick={() => setDrawer(drawer === 'scene' ? '' : 'scene')}> <View className={styles.filterCell} onClick={() => setDrawer(drawer === 'room' ? '' : 'room')}>
<View className={`${styles.filterTrigger} ${filters.sceneId !== 0 ? styles.filterTriggerActive : ''}`}> <View className={`${styles.filterTrigger} ${filters.roomId ? styles.filterTriggerActive : ''}`}>
<Text className={styles.filterText}>{sceneLabel}</Text> <Text className={styles.filterText}>{roomLabel}</Text>
<Text className={styles.filterArrow}>▾</Text> <Text className={styles.filterArrow}>▾</Text>
</View> </View>
</View> </View>
<View className={styles.filterCell} onClick={() => setDrawer(drawer === 'status' ? '' : 'status')}> <View className={styles.filterCell} onClick={() => setDrawer(drawer === 'status' ? '' : 'status')}>
<View className={`${styles.filterTrigger} ${filters.status !== 0 ? styles.filterTriggerActive : ''}`}> <View className={`${styles.filterTrigger} ${filters.status ? styles.filterTriggerActive : ''}`}>
<Text className={styles.filterText}>{statusLabel}</Text> <Text className={styles.filterText}>{statusLabel}</Text>
<Text className={styles.filterArrow}>▾</Text> <Text className={styles.filterArrow}>▾</Text>
</View> </View>
@ -140,32 +169,49 @@ export default function Event() {
{/* 数据层:抽屉锚点(筛选栏下缘展开,遮罩盖住本层全部) */} {/* 数据层:抽屉锚点(筛选栏下缘展开,遮罩盖住本层全部) */}
<View className={styles.contentArea}> <View className={styles.contentArea}>
<View className={styles.contentBody}> <View className={styles.contentBody}>
{eventList.length === 0 ? ( {alarmList.length === 0 ? (
<> <>
<View className={styles.emptyArea}> <View className={styles.emptyArea}>
<Empty text="暂无事件数据" mode="message" /> <Empty text="暂无告警数据" mode="message" />
</View> </View>
<View className={styles.emptyHint}> <View className={styles.emptyHint}>
<Text>调整筛选条件后的事件列表将在此展示</Text> <Text>调整筛选条件后的告警列表将在此展示</Text>
</View> </View>
</> </>
) : ( ) : (
<View className={styles.eventList}> <View className={styles.alarmList}>
{/* 事件卡片列表:布局等后端接口定型后补(Task 5.1.c 说明) */} {alarmList.map((alarm) => (
<View key={alarm.alarmId} className={styles.alarmCard}>
<View className={styles.alarmHead}>
<Text className={styles.alarmType}>{alarm.alarmType}</Text>
<Text className={`${styles.alarmTag} ${tagClsMap[String(alarm.status)] ?? ''}`}>{statusTagOf(alarm)}</Text>
</View>
<View className={styles.alarmRow}>
<Text className={styles.alarmLabel}>设备</Text>
<Text className={styles.alarmValue}>{alarm.deviceName || alarm.deviceId}</Text>
</View>
<View className={styles.alarmRow}>
<Text className={styles.alarmLabel}>时间</Text>
<Text className={styles.alarmValue}>{alarm.alarmTime}</Text>
</View>
</View>
))}
</View> </View>
)} )}
</View> </View>
{drawer !== '' && <View className={styles.contentMask} onClick={closeDrawer} catchMove />} {drawer !== '' && <View className={styles.contentMask} onClick={closeDrawer} catchMove />}
{drawer === 'scene' && renderOptionDrawer('scene')} {drawer === 'room' && renderOptionDrawer('room')}
{drawer === 'status' && renderOptionDrawer('status')} {drawer === 'status' && renderOptionDrawer('status')}
{drawer === 'time' && ( {drawer === 'time' && (
<CalendarDrawer <CalendarDrawer
initialStart={filters.startDate} initialStart={filters.startDate}
initialEnd={filters.endDate} initialEnd={filters.endDate}
onClose={closeDrawer} onClose={closeDrawer}
onConfirm={onTimeConfirm} onConfirm={(start, end) =>
applyFilter({ ...filters, startDate: start, endDate: end, timeText: `${start} 至 ${end}` })
}
/> />
)} )}
</View> </View>

View File

@ -5,7 +5,8 @@ import { Navbar } from '@/components/navbar'
import { Loading } from '@/components/loading' import { Loading } from '@/components/loading'
import { Empty } from '@/components/empty' import { Empty } from '@/components/empty'
import { StateView } from '@/components/state-view' import { StateView } from '@/components/state-view'
import { getEventList, type EventItem } from '@/api/event' import { getHomeList, type HomeInfo } from '@/api/home'
import { getAlarmList, type HomeAlarm } from '@/api/homeAlarm'
import { store } from '@/store' import { store } from '@/store'
import { storage } from '@/utils/storage' import { storage } from '@/utils/storage'
import { ROUTES } from '@/constants/routes' import { ROUTES } from '@/constants/routes'
@ -15,17 +16,23 @@ import { splitAlerts } from './splitAlerts'
import styles from './index.module.scss' import styles from './index.module.scss'
export default function Index() { export default function Index() {
const [alertList, setAlertList] = useState<EventItem[]>([]) const [alertList, setAlertList] = useState<HomeAlarm[]>([])
const [loading, setLoading] = useState(true) const [loading, setLoading] = useState(true)
const [loadError, setLoadError] = useState(false) const [loadError, setLoadError] = useState(false)
// 每次进入页面重拉全量告警(与事件页"全部"筛选同参数) // 每次进入页面重拉默认家庭的全部告警(与事件页"全部"筛选同参数)
const loadAlerts = useCallback(async () => { const loadAlerts = useCallback(async () => {
setLoading(true) setLoading(true)
setLoadError(false) setLoadError(false)
try { try {
const list = await getEventList({ sceneId: 0, status: 0, startDate: '', endDate: '' }) const homes = await getHomeList()
setAlertList(list) const first: HomeInfo | undefined = homes[0]
if (!first) {
setAlertList([])
return
}
const list = await getAlarmList({ homeId: first.homeId })
setAlertList(list ?? [])
} catch { } catch {
setLoadError(true) setLoadError(true)
} finally { } finally {
@ -66,7 +73,7 @@ export default function Index() {
{messages.length > 0 && ( {messages.length > 0 && (
<View className={styles.messageList}> <View className={styles.messageList}>
{messages.map((alert) => ( {messages.map((alert) => (
<AlertMessageItem key={alert.id} alert={alert} onClick={goAlertDetail} /> <AlertMessageItem key={alert.alarmId} alert={alert} onClick={goAlertDetail} />
))} ))}
</View> </View>
)} )}
@ -94,33 +101,33 @@ function FamilyEntry({ onClick }: { onClick: () => void }) {
) )
} }
function UnhandledAlert({ alert, onClick }: { alert: EventItem; onClick: () => void }) { function UnhandledAlert({ alert, onClick }: { alert: HomeAlarm; onClick: () => void }) {
return ( return (
<View className={styles.unhandledCard} onClick={onClick}> <View className={styles.unhandledCard} onClick={onClick}>
<View className={styles.unhandledHead}> <View className={styles.unhandledHead}>
<View className={styles.unhandledIcon}> <View className={styles.unhandledIcon}>
<Text className={styles.unhandledIconText}>!</Text> <Text className={styles.unhandledIconText}>!</Text>
</View> </View>
<Text className={styles.unhandledTitle}>{alert.deviceName || '未知设备'}</Text> <Text className={styles.unhandledTitle}>{alert.deviceName || alert.deviceId || '未知设备'}</Text>
<View className={styles.unhandledTag}> <View className={styles.unhandledTag}>
<Text className={styles.unhandledTagText}>未处理</Text> <Text className={styles.unhandledTagText}>未处理</Text>
</View> </View>
</View> </View>
{alert.sceneName && ( {alert.alarmType && (
<View className={styles.unhandledMeta}> <View className={styles.unhandledMeta}>
<Text className={styles.unhandledMetaText}>{alert.sceneName}</Text> <Text className={styles.unhandledMetaText}>{alert.alarmType}</Text>
</View> </View>
)} )}
{alert.time && ( {alert.alarmTime && (
<View className={styles.unhandledMeta}> <View className={styles.unhandledMeta}>
<Text className={styles.unhandledMetaText}>{alert.time}</Text> <Text className={styles.unhandledMetaText}>{alert.alarmTime}</Text>
</View> </View>
)} )}
</View> </View>
) )
} }
function AlertMessageItem({ alert, onClick }: { alert: EventItem; onClick: () => void }) { function AlertMessageItem({ alert, onClick }: { alert: HomeAlarm; onClick: () => void }) {
return ( return (
<View className={styles.messageCard} onClick={onClick}> <View className={styles.messageCard} onClick={onClick}>
<View className={styles.messageIcon}> <View className={styles.messageIcon}>
@ -128,8 +135,8 @@ function AlertMessageItem({ alert, onClick }: { alert: EventItem; onClick: () =>
</View> </View>
<View className={styles.messageBody}> <View className={styles.messageBody}>
<View className={styles.messageHead}> <View className={styles.messageHead}>
<Text className={styles.messageTitle}>告警消息</Text> <Text className={styles.messageTitle}>{alert.alarmType || '告警消息'}</Text>
{alert.time && <Text className={styles.messageTime}>{alert.time}</Text>} {alert.alarmTime && <Text className={styles.messageTime}>{alert.alarmTime}</Text>}
</View> </View>
{alert.deviceName && ( {alert.deviceName && (
<Text className={styles.messageDevice}>{alert.deviceName}</Text> <Text className={styles.messageDevice}>{alert.deviceName}</Text>

View File

@ -1,12 +1,12 @@
import type { EventItem } from '@/api/event' import type { HomeAlarm } from '@/api/homeAlarm'
// 首页告警分流:status=1 未处理(首页只展示最新一条),其余全部进消息列表 // 首页告警分流:status=1 未处理(首页只展示最新一条),其余全部进消息列表
export function splitAlerts(list: EventItem[]): { export function splitAlerts(list: HomeAlarm[]): {
unhandled: EventItem[] unhandled: HomeAlarm[]
messages: EventItem[] messages: HomeAlarm[]
} { } {
const unhandled: EventItem[] = [] const unhandled: HomeAlarm[] = []
const messages: EventItem[] = [] const messages: HomeAlarm[] = []
for (const item of list) { for (const item of list) {
if (item.status === 1) unhandled.push(item) if (item.status === 1) unhandled.push(item)
else messages.push(item) else messages.push(item)

View File

@ -1,33 +1,36 @@
import { describe, it, expect } from 'vitest' import { describe, it, expect } from 'vitest'
import { splitAlerts } from '@/pages/index/splitAlerts' import { splitAlerts } from '@/pages/index/splitAlerts'
import type { EventItem } from '@/api/event' import type { HomeAlarm } from '@/api/homeAlarm'
const item = (over: Partial<EventItem>): EventItem => ({ const item = (over: Partial<HomeAlarm>): HomeAlarm => ({
id: 1, alarmId: '1',
sceneName: '客厅', homeId: 'h1',
roomId: 'r1',
deviceId: 'd1',
deviceName: '体征监测仪', deviceName: '体征监测仪',
alarmType: '心率异常',
alarmTime: '2026-09-07 21:22:12',
status: 2, status: 2,
time: '2026-09-07 21:22:12',
...over ...over
}) })
describe('splitAlerts', () => { describe('splitAlerts', () => {
it('status=1 进入未处理组,其余进入消息组', () => { it('status=1 进入未处理组,其余进入消息组', () => {
const list = [ const list = [
item({ id: 1, status: 1 }), item({ alarmId: '1', status: 1 }),
item({ id: 2, status: 2 }), item({ alarmId: '2', status: 2 }),
item({ id: 3, status: 3 }) item({ alarmId: '3', status: 3 })
] ]
const { unhandled, messages } = splitAlerts(list) const { unhandled, messages } = splitAlerts(list)
expect(unhandled.map((i) => i.id)).toEqual([1]) expect(unhandled.map((i) => i.alarmId)).toEqual(['1'])
expect(messages.map((i) => i.id)).toEqual([2, 3]) expect(messages.map((i) => i.alarmId)).toEqual(['2', '3'])
}) })
it('status 异常值(如 0、99)落入消息组不丢弃', () => { it('status 异常值(如 0、99)落入消息组不丢弃', () => {
const list = [item({ id: 1, status: 0 }), item({ id: 2, status: 99 })] const list = [item({ alarmId: '1', status: 0 }), item({ alarmId: '2', status: 99 })]
const { unhandled, messages } = splitAlerts(list) const { unhandled, messages } = splitAlerts(list)
expect(unhandled).toEqual([]) expect(unhandled).toEqual([])
expect(messages.map((i) => i.id)).toEqual([1, 2]) expect(messages.map((i) => i.alarmId)).toEqual(['1', '2'])
}) })
it('空列表两组均为空', () => { it('空列表两组均为空', () => {
@ -38,12 +41,12 @@ describe('splitAlerts', () => {
it('两组均保持原有相对顺序', () => { it('两组均保持原有相对顺序', () => {
const list = [ const list = [
item({ id: 3, status: 2 }), item({ alarmId: '3', status: 2 }),
item({ id: 1, status: 1 }), item({ alarmId: '1', status: 1 }),
item({ id: 2, status: 2 }) item({ alarmId: '2', status: 2 })
] ]
const { unhandled, messages } = splitAlerts(list) const { unhandled, messages } = splitAlerts(list)
expect(unhandled.map((i) => i.id)).toEqual([1]) expect(unhandled.map((i) => i.alarmId)).toEqual(['1'])
expect(messages.map((i) => i.id)).toEqual([3, 2]) expect(messages.map((i) => i.alarmId)).toEqual(['3', '2'])
}) })
}) })