pages_device_monitor.tsx 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. import React, { useState, useEffect } from 'react';
  2. import {
  3. Button, Table, Form, Input, Select, message, Card, Badge,
  4. } from 'antd';
  5. import dayjs from 'dayjs';
  6. import 'dayjs/locale/zh-cn';
  7. // 从share/types.ts导入所有类型,包括MapMode
  8. import type {
  9. DeviceMonitorData,
  10. } from '../share/monitorTypes.ts';
  11. import {
  12. DeviceStatus, DeviceProtocolType, MetricType, DeviceStatusNameMap, DeviceProtocolTypeNameMap,
  13. MetricTypeNameMap
  14. } from '../share/monitorTypes.ts';
  15. import { getEnumOptions } from './utils.ts';
  16. import { DeviceInstanceAPI, MonitorAPI } from './api/index.ts';
  17. // 设备实时监控页面
  18. export const DeviceMonitorPage = () => {
  19. const [loading, setLoading] = useState(false);
  20. const [monitorData, setMonitorData] = useState<DeviceMonitorData[]>([]);
  21. const [pagination, setPagination] = useState({
  22. current: 1,
  23. pageSize: 10,
  24. total: 0,
  25. });
  26. const [deviceOptions, setDeviceOptions] = useState<{label: string, value: number}[]>([]);
  27. const [formRef] = Form.useForm();
  28. // 监控数据刷新间隔(毫秒)
  29. const REFRESH_INTERVAL = 30000;
  30. useEffect(() => {
  31. fetchDeviceOptions();
  32. fetchMonitorData();
  33. // 设置定时刷新
  34. const intervalId = setInterval(() => {
  35. fetchMonitorData();
  36. }, REFRESH_INTERVAL);
  37. return () => clearInterval(intervalId);
  38. }, [pagination.current, pagination.pageSize]);
  39. const fetchDeviceOptions = async () => {
  40. try {
  41. const response = await DeviceInstanceAPI.getDeviceInstances();
  42. if (response && response.data) {
  43. const options = response.data.map((device) => ({
  44. label: device.asset_name || `设备${device.id}`,
  45. value: device.id
  46. }));
  47. setDeviceOptions(options);
  48. }
  49. } catch (error) {
  50. console.error('获取设备列表失败:', error);
  51. message.error('获取设备列表失败');
  52. }
  53. };
  54. const fetchMonitorData = async () => {
  55. setLoading(true);
  56. try {
  57. const values = formRef.getFieldsValue();
  58. const params = {
  59. page: pagination.current,
  60. pageSize: pagination.pageSize,
  61. device_id: values.device_id,
  62. device_name: values.device_name,
  63. protocol: values.protocol,
  64. address: values.address,
  65. metric_type: values.metric_type,
  66. status: values.status,
  67. };
  68. const response = await MonitorAPI.getMonitorData(params);
  69. if (response) {
  70. setMonitorData(response.data || []);
  71. setPagination({
  72. ...pagination,
  73. total: response.total || 0,
  74. });
  75. }
  76. } catch (error) {
  77. console.error('获取监控数据失败:', error);
  78. message.error('获取监控数据失败');
  79. } finally {
  80. setLoading(false);
  81. }
  82. };
  83. const handleSearch = (values: any) => {
  84. setPagination({
  85. ...pagination,
  86. current: 1,
  87. });
  88. fetchMonitorData();
  89. };
  90. const handleTableChange = (newPagination: any) => {
  91. setPagination({
  92. ...pagination,
  93. current: newPagination.current,
  94. pageSize: newPagination.pageSize,
  95. });
  96. };
  97. const metricTypeOptions = getEnumOptions(MetricType, MetricTypeNameMap);
  98. const statusOptions = getEnumOptions(DeviceStatus, DeviceStatusNameMap);
  99. const protocolOptions = getEnumOptions(DeviceProtocolType, DeviceProtocolTypeNameMap);
  100. const getStatusBadge = (status?: DeviceStatus) => {
  101. switch (status) {
  102. case DeviceStatus.NORMAL:
  103. return <Badge status="success" text="正常" />;
  104. case DeviceStatus.MAINTAIN:
  105. return <Badge status="processing" text="维护中" />;
  106. case DeviceStatus.FAULT:
  107. return <Badge status="error" text="故障" />;
  108. case DeviceStatus.OFFLINE:
  109. return <Badge status="default" text="下线" />;
  110. default:
  111. return <Badge status="default" text="未知" />;
  112. }
  113. };
  114. const columns = [
  115. {
  116. title: '设备ID',
  117. dataIndex: 'device_id',
  118. key: 'device_id',
  119. width: 80,
  120. },
  121. {
  122. title: '设备名称',
  123. dataIndex: 'device_name',
  124. key: 'device_name',
  125. },
  126. {
  127. title: '通信协议',
  128. dataIndex: 'protocol',
  129. key: 'protocol',
  130. render: (text: string) => {
  131. const option = protocolOptions.find(opt => opt.value === text);
  132. return option ? option.label : text;
  133. },
  134. },
  135. {
  136. title: '通信地址',
  137. dataIndex: 'address',
  138. key: 'address',
  139. },
  140. {
  141. title: '监控指标',
  142. dataIndex: 'metric_type',
  143. key: 'metric_type',
  144. render: (text: string) => {
  145. const option = metricTypeOptions.find(opt => opt.value === text);
  146. return option ? option.label : text;
  147. },
  148. },
  149. {
  150. title: '监控值',
  151. dataIndex: 'metric_value',
  152. key: 'metric_value',
  153. render: (value: number, record: DeviceMonitorData) => {
  154. return `${value} ${record.unit || ''}`;
  155. },
  156. },
  157. {
  158. title: '状态',
  159. dataIndex: 'status',
  160. key: 'status',
  161. render: (status: DeviceStatus) => getStatusBadge(status),
  162. },
  163. {
  164. title: '采集时间',
  165. dataIndex: 'collect_time',
  166. key: 'collect_time',
  167. render: (text: Date) => dayjs(text).format('YYYY-MM-DD HH:mm:ss'),
  168. },
  169. ];
  170. return (
  171. <div>
  172. <Card title="设备实时监控" style={{ marginBottom: 16 }}>
  173. <Form
  174. form={formRef}
  175. layout="inline"
  176. onFinish={handleSearch}
  177. style={{ marginBottom: 16 }}
  178. >
  179. <Form.Item name="device_id" label="设备">
  180. <Select
  181. placeholder="选择设备"
  182. style={{ width: 200 }}
  183. allowClear
  184. options={deviceOptions}
  185. />
  186. </Form.Item>
  187. <Form.Item name="device_name" label="设备名称">
  188. <Input placeholder="输入设备名称" style={{ width: 200 }} />
  189. </Form.Item>
  190. <Form.Item name="protocol" label="通信协议">
  191. <Select
  192. placeholder="选择通信协议"
  193. style={{ width: 200 }}
  194. allowClear
  195. options={protocolOptions}
  196. />
  197. </Form.Item>
  198. <Form.Item name="address" label="通信地址">
  199. <Input placeholder="输入通信地址" style={{ width: 200 }} />
  200. </Form.Item>
  201. <Form.Item name="metric_type" label="监控指标">
  202. <Select
  203. placeholder="选择监控指标"
  204. style={{ width: 200 }}
  205. allowClear
  206. options={metricTypeOptions}
  207. />
  208. </Form.Item>
  209. <Form.Item name="status" label="状态">
  210. <Select
  211. placeholder="选择状态"
  212. style={{ width: 120 }}
  213. allowClear
  214. options={statusOptions}
  215. />
  216. </Form.Item>
  217. <Form.Item>
  218. <Button type="primary" htmlType="submit">
  219. 查询
  220. </Button>
  221. </Form.Item>
  222. </Form>
  223. <Table
  224. columns={columns}
  225. dataSource={monitorData}
  226. rowKey="id"
  227. pagination={pagination}
  228. loading={loading}
  229. onChange={handleTableChange}
  230. />
  231. </Card>
  232. </div>
  233. );
  234. };