From a218995d098a88c753f89b3864835b0bee6c9a28 Mon Sep 17 00:00:00 2001 From: skycurtain Date: Tue, 12 Aug 2025 19:49:22 +0800 Subject: [PATCH] some updates --- src/apis/requests/device/index.ts | 8 ++ src/components/dashboard/station/index.tsx | 38 +++++- src/hooks/query/use-stations-query.ts | 50 ++++++++ src/layouts/app-layout.tsx | 14 ++- src/routes/_app/dashboard.tsx | 127 ++++++++++++++------- src/store/station.ts | 33 +++++- 6 files changed, 220 insertions(+), 50 deletions(-) create mode 100644 src/apis/requests/device/index.ts create mode 100644 src/hooks/query/use-stations-query.ts diff --git a/src/apis/requests/device/index.ts b/src/apis/requests/device/index.ts new file mode 100644 index 0000000..014d922 --- /dev/null +++ b/src/apis/requests/device/index.ts @@ -0,0 +1,8 @@ +export * from './ndm-camera'; +export * from './ndm-decoder'; +export * from './ndm-keyboard'; +export * from './ndm-media-server'; +export * from './ndm-nvr'; +export * from './ndm-security-box'; +export * from './ndm-switch'; +export * from './ndm-video-server'; \ No newline at end of file diff --git a/src/components/dashboard/station/index.tsx b/src/components/dashboard/station/index.tsx index 3e8d313..f6ee317 100644 --- a/src/components/dashboard/station/index.tsx +++ b/src/components/dashboard/station/index.tsx @@ -2,15 +2,47 @@ import type { FC } from 'react'; import { AlertOutlined, ApiOutlined } from '@ant-design/icons'; import { Card, Col, Row, Statistic, Tag } from 'antd'; +import { useState } from 'react'; + +import type { NdmCameraResultVO, NdmDecoderResultVO, NdmDeviceAlarmLogResultVO, NdmKeyboardResultVO, NdmMediaServerResultVO, NdmNvrResultVO, NdmSecurityBoxResultVO, NdmSwitchResultVO, NdmVideoServerResultVO } from '@/apis/models/device'; interface StationProps { name: string; online: boolean; - offlineDeviceCount: number; - alarmCount: number; + // offlineDeviceCount: number; + // alarmCount: number; + ndmCameraList: NdmCameraResultVO[]; + ndmDecoderList: NdmDecoderResultVO[]; + ndmKeyboardList: NdmKeyboardResultVO[]; + ndmMediaServerList: NdmMediaServerResultVO[]; + ndmNvrList: NdmNvrResultVO[]; + ndmSecurityBoxList: NdmSecurityBoxResultVO[]; + ndmSwitchList: NdmSwitchResultVO[]; + ndmVideoServerList: NdmVideoServerResultVO[]; + ndmDeviceAlarmLogList: NdmDeviceAlarmLogResultVO[]; } -export const Station: FC = ({ name, online, offlineDeviceCount, alarmCount }) => { +export const Station: FC = ({ name, online, ndmCameraList, ndmDecoderList, ndmKeyboardList, ndmMediaServerList, ndmNvrList, ndmSecurityBoxList, ndmSwitchList, ndmVideoServerList, ndmDeviceAlarmLogList }) => { + const [offlineDeviceCount] = useState(12); + const [alarmCount] = useState(3); + + const offlineCameraCount = ndmCameraList.filter(device => device.deviceStatus === '20').length; + const cameraCount = ndmCameraList.length; + const offlineDecoderCount = ndmDecoderList.filter(device => device.deviceStatus === '20').length; + const decoderCount = ndmDecoderList.length; + const offlineKeyboardCount = ndmKeyboardList.filter(device => device.deviceStatus === '20').length; + const keyboardCount = ndmKeyboardList.length; + const offlineMediaServerCount = ndmMediaServerList.filter(device => device.deviceStatus === '20').length; + const mediaServerCount = ndmMediaServerList.length; + const offlineNvrCount = ndmNvrList.filter(device => device.deviceStatus === '20').length; + const nvrCount = ndmNvrList.length; + const offlineSecurityBoxCount = ndmSecurityBoxList.filter(device => device.deviceStatus === '20').length; + const securityBoxCount = ndmSecurityBoxList.length; + const switchOfflineCount = ndmSwitchList.filter(device => device.deviceStatus === '20').length; + const switchCount = ndmSwitchList.length; + const offlineVideoServerCount = ndmVideoServerList.filter(device => device.deviceStatus === '20').length; + const videoServerCount = ndmVideoServerList.length; + return ( { + // 第一步:获取车站基础信息 + const [err, data] = await userClient.post>(`/api/system/defParameter/page`, { + current: 1, + extra: {}, + model: { + key: 'NDM_STATION_', + }, + order: 'ascending', + size: 100, + sort: 'id', + }); + if (err || !data) { + throw err; + } + + // 第二步:获取每个车站的在线状态 + const stations: Station[] = data.records.map(record => ({ + id: record.key ?? '', + code: record.value ?? '', + name: record.name ?? '', + online: false, // 默认离线 + })); + + // 第三步:并发检查所有车站的在线状态 + const pingResultList = await Promise.allSettled(stations.map((station) => { + return ndmClient.post(`/${station.code}/api/ndm/ndmKeepAlive/verify`, {}, { timeout: 5000 }); + })); + + // 第四步:合并状态信息 + const stationsWithStatus: Station[] = stations.map((station, index) => ({ + ...station, + online: pingResultList[index].status === 'fulfilled', + })); + + return stationsWithStatus; + }, + }); +} diff --git a/src/layouts/app-layout.tsx b/src/layouts/app-layout.tsx index 88e22b0..69d3efa 100644 --- a/src/layouts/app-layout.tsx +++ b/src/layouts/app-layout.tsx @@ -4,7 +4,10 @@ import type { FC } from 'react'; import { AlertFilled, AreaChartOutlined, DownOutlined, FileTextFilled, HomeFilled, UserOutlined, VideoCameraFilled } from '@ant-design/icons'; import { Link, Outlet } from '@tanstack/react-router'; import { Avatar, Dropdown, Layout, Menu, Space, theme } from 'antd'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; + +import { useStationListQuery } from '@/hooks/query/use-stations-query'; +import { useStationStore } from '@/store/station'; const { Content, Footer, Header, Sider } = Layout; @@ -12,6 +15,15 @@ export const AppLayout: FC = () => { const { token: { colorBgContainer } } = theme.useToken(); const [menuTheme] = useState('light'); + const { data: stationList } = useStationListQuery(); + const { setStationList } = useStationStore(); + + useEffect(() => { + if (stationList) { + setStationList(stationList); + } + }, [stationList, setStationList]); + const items: MenuProps['items'] = [ { key: 'logout', diff --git a/src/routes/_app/dashboard.tsx b/src/routes/_app/dashboard.tsx index be2b86b..5f4dd4d 100644 --- a/src/routes/_app/dashboard.tsx +++ b/src/routes/_app/dashboard.tsx @@ -1,58 +1,105 @@ import { useQuery } from '@tanstack/react-query'; -import { createFileRoute, useLocation } from '@tanstack/react-router'; +import { createFileRoute } from '@tanstack/react-router'; import { Col, Row } from 'antd'; -import { userClient } from '@/apis/client'; +import { + postNdmCameraPage, + postNdmDecoderPage, + postNdmKeyboardPage, + postNdmMediaServerPage, + postNdmNvrPage, + postNdmSecurityBoxPage, + postNdmSwitchPage, + postNdmVideoServerPage, +} from '@/apis/requests/device'; import { Station } from '@/components/dashboard/station'; +import { useStationStore } from '@/store/station'; export const Route = createFileRoute('/_app/dashboard')({ component: DashboardPage, }); function DashboardPage() { - // const location = useLocation(); - // const { data, isLoading, isFetching, isPending } = useQuery({ - // queryKey: ['station'], - // queryFn: async () => { - // const [err, , resp] = await userClient.get('/api/users'); - // if (err || !resp) { - // throw err; - // } - // console.log(resp); - // return resp; - // }, - // }); + const stationList = useStationStore(state => state.stationList); - const stations = Array.from({ length: 40 }).map((_, i) => ({ - id: i, - name: `测试站点${i + 1}`, - isOnline: true, - offlineDeviceCount: 12, - alarmCount: 3, - })); + const onlineStationList = stationList.filter(station => station.online); + + const { data } = useQuery({ + queryKey: ['device-list', 'all-type', onlineStationList.map(s => s.code)], + queryFn: async () => { + const pageQuery = { model: {}, extra: {}, size: 5000, current: 1, sort: 'id', order: 'ascending' as const }; + + const stationDevicePromises = onlineStationList.map(async (station) => { + const deviceRequests = [ + postNdmCameraPage(station.code, pageQuery), + postNdmDecoderPage(station.code, pageQuery), + postNdmKeyboardPage(station.code, pageQuery), + postNdmMediaServerPage(station.code, pageQuery), + postNdmNvrPage(station.code, pageQuery), + postNdmSecurityBoxPage(station.code, pageQuery), + postNdmSwitchPage(station.code, pageQuery), + postNdmVideoServerPage(station.code, pageQuery), + ]; + + const results = await Promise.all(deviceRequests); + + const [ + [, cameraData], + [, decoderData], + [, keyboardData], + [, mediaServerData], + [, nvrData], + [, securityBoxData], + [, switchData], + [, videoServerData], + ] = results; + + return { + stationCode: station.code, + ndmCameraList: cameraData?.records ?? [], + ndmDecoderList: decoderData?.records ?? [], + ndmKeyboardList: keyboardData?.records ?? [], + ndmMediaServerList: mediaServerData?.records ?? [], + ndmNvrList: nvrData?.records ?? [], + ndmSecurityBoxList: securityBoxData?.records ?? [], + ndmSwitchList: switchData?.records ?? [], + ndmVideoServerList: videoServerData?.records ?? [], + }; + }); + + const allStationsData = await Promise.all(stationDevicePromises); + + return allStationsData.reduce((acc, result) => { + acc[result.stationCode] = result; + return acc; + }, {} as Record); + }, + enabled: onlineStationList.length > 0, + }); return ( - //
- // - //
- //

当前路由信息

- //
{JSON.stringify(location, null, 2)}
- //
- - //
{JSON.stringify(data, null, 2)}
- //
- {stations.map(station => ( - - - - ))} + {stationList.map((station) => { + const deviceData = data?.[station.code]; + return ( + + + + ); + })}
); diff --git a/src/store/station.ts b/src/store/station.ts index cb9b261..4264daf 100644 --- a/src/store/station.ts +++ b/src/store/station.ts @@ -1,17 +1,38 @@ import { create } from 'zustand'; -import type { Station, StationStatusRecord } from '@/apis/domains'; +import type { Station } from '@/apis/domains'; export interface StationState { stationList: Station[]; - stationStatusRecord: StationStatusRecord; setStationList: (stationList: Station[]) => void; - setStationStatusRecord: (stationStatusRecord: StationStatusRecord) => void; + // 获取在线车站 + getOnlineStations: () => Station[]; + // 获取离线车站 + getOfflineStations: () => Station[]; + // 获取指定车站的在线状态 + getStationStatus: (stationCode: string) => boolean; } -export const useStationStore = create(set => ({ +export const useStationStore = create((set, get) => ({ stationList: [], - stationStatusRecord: {}, setStationList: (stationList: Station[]) => set({ stationList }), - setStationStatusRecord: (stationStatusRecord: StationStatusRecord) => set({ stationStatusRecord }), + + // 获取在线车站 + getOnlineStations: () => { + const { stationList } = get(); + return stationList.filter(station => station.online); + }, + + // 获取离线车站 + getOfflineStations: () => { + const { stationList } = get(); + return stationList.filter(station => !station.online); + }, + + // 获取指定车站的在线状态 + getStationStatus: (stationCode: string) => { + const { stationList } = get(); + const station = stationList.find(s => s.code === stationCode); + return station?.online || false; + }, }));