some updates
This commit is contained in:
8
src/apis/requests/device/index.ts
Normal file
8
src/apis/requests/device/index.ts
Normal file
@@ -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';
|
||||
@@ -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<StationProps> = ({ name, online, offlineDeviceCount, alarmCount }) => {
|
||||
export const Station: FC<StationProps> = ({ 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 (
|
||||
<Card
|
||||
size='small'
|
||||
|
||||
50
src/hooks/query/use-stations-query.ts
Normal file
50
src/hooks/query/use-stations-query.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
|
||||
import type { Station } from '@/apis/domains';
|
||||
import type { PageResult } from '@/apis/models/base/page';
|
||||
import type { DefParameterResultVO } from '@/apis/models/system';
|
||||
|
||||
import { ndmClient, userClient } from '@/apis/client';
|
||||
|
||||
export function useStationListQuery() {
|
||||
return useQuery({
|
||||
queryKey: ['station-list'],
|
||||
queryFn: async () => {
|
||||
// 第一步:获取车站基础信息
|
||||
const [err, data] = await userClient.post<PageResult<DefParameterResultVO>>(`/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;
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -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<MenuTheme>('light');
|
||||
|
||||
const { data: stationList } = useStationListQuery();
|
||||
const { setStationList } = useStationStore();
|
||||
|
||||
useEffect(() => {
|
||||
if (stationList) {
|
||||
setStationList(stationList);
|
||||
}
|
||||
}, [stationList, setStationList]);
|
||||
|
||||
const items: MenuProps['items'] = [
|
||||
{
|
||||
key: 'logout',
|
||||
|
||||
@@ -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<any[]>('/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<string, typeof allStationsData[number]>);
|
||||
},
|
||||
enabled: onlineStationList.length > 0,
|
||||
});
|
||||
|
||||
return (
|
||||
// <div>
|
||||
// <Station name='测试站点' isOnline={true} offlineDeviceCount={12} alarmCount={3} />
|
||||
// <div>
|
||||
// <h2>当前路由信息</h2>
|
||||
// <pre>{JSON.stringify(location, null, 2)}</pre>
|
||||
// </div>
|
||||
|
||||
// <pre>{JSON.stringify(data, null, 2)}</pre>
|
||||
// </div>
|
||||
<div style={{ padding: '6px' }}>
|
||||
<Row gutter={[6, 6]}>
|
||||
{stations.map(station => (
|
||||
<Col key={station.id} span={3}>
|
||||
<Station
|
||||
name={station.name}
|
||||
online={station.isOnline}
|
||||
offlineDeviceCount={station.offlineDeviceCount}
|
||||
alarmCount={station.alarmCount}
|
||||
/>
|
||||
</Col>
|
||||
))}
|
||||
{stationList.map((station) => {
|
||||
const deviceData = data?.[station.code];
|
||||
return (
|
||||
<Col key={station.id} span={3}>
|
||||
<Station
|
||||
name={station.name}
|
||||
online={station.online}
|
||||
ndmCameraList={deviceData?.ndmCameraList ?? []}
|
||||
ndmDecoderList={deviceData?.ndmDecoderList ?? []}
|
||||
ndmKeyboardList={deviceData?.ndmKeyboardList ?? []}
|
||||
ndmMediaServerList={deviceData?.ndmMediaServerList ?? []}
|
||||
ndmNvrList={deviceData?.ndmNvrList ?? []}
|
||||
ndmSecurityBoxList={deviceData?.ndmSecurityBoxList ?? []}
|
||||
ndmSwitchList={deviceData?.ndmSwitchList ?? []}
|
||||
ndmVideoServerList={deviceData?.ndmVideoServerList ?? []}
|
||||
ndmDeviceAlarmLogList={[]}
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -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<StationState>(set => ({
|
||||
export const useStationStore = create<StationState>((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;
|
||||
},
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user