page.tsx 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787
  1. "use client"
  2. import {useState} from "react"
  3. import {
  4. Alert,
  5. Badge,
  6. Button,
  7. Card,
  8. Col,
  9. Form,
  10. Input,
  11. Layout,
  12. Menu,
  13. message,
  14. Modal,
  15. Row,
  16. Select,
  17. Space,
  18. Statistic,
  19. Table,
  20. Tabs,
  21. Tag,
  22. } from "antd"
  23. import {
  24. AlertOutlined,
  25. BarChartOutlined,
  26. DashboardOutlined,
  27. EditOutlined,
  28. EnvironmentOutlined,
  29. EyeOutlined,
  30. PlusOutlined,
  31. SettingOutlined,
  32. } from "@ant-design/icons"
  33. import dynamic from "next/dynamic"
  34. import EChart from "@/components/echarts"
  35. import GisMapBaidu from "@/components/gisMapBaidu";
  36. const { Header, Sider, Content } = Layout
  37. const { TabPane } = Tabs
  38. const { Option } = Select
  39. // 动态导入地图组件避免SSR问题
  40. const MapView = dynamic(() => import("./components/map-view"), { ssr: false })
  41. export default function ManholeMonitoringSystem() {
  42. const [selectedMenu, setSelectedMenu] = useState("dashboard")
  43. const [deviceModalVisible, setDeviceModalVisible] = useState(false)
  44. const [selectedDevice, setSelectedDevice] = useState(null)
  45. const [addDeviceModalVisible, setAddDeviceModalVisible] = useState(false)
  46. const [editDeviceModalVisible, setEditDeviceModalVisible] = useState(false)
  47. const [editingDevice, setEditingDevice] = useState(null)
  48. const [devices, setDevices] = useState([
  49. {
  50. id: 1,
  51. name: "设备001",
  52. type: "智能井盖",
  53. status: "normal",
  54. location: "朝阳区建国路",
  55. lat: 39.9042,
  56. lng: 116.4074,
  57. battery: 85,
  58. signal: 90,
  59. },
  60. {
  61. id: 2,
  62. name: "设备002",
  63. type: "智能井盖",
  64. status: "warning",
  65. location: "海淀区中关村",
  66. lat: 39.9826,
  67. lng: 116.3186,
  68. battery: 45,
  69. signal: 75,
  70. },
  71. {
  72. id: 3,
  73. name: "设备003",
  74. type: "智能井盖",
  75. status: "error",
  76. location: "西城区金融街",
  77. lat: 39.926,
  78. lng: 116.3663,
  79. battery: 20,
  80. signal: 60,
  81. },
  82. {
  83. id: 4,
  84. name: "设备004",
  85. type: "智能井盖",
  86. status: "normal",
  87. location: "东城区王府井",
  88. lat: 39.9097,
  89. lng: 116.4109,
  90. battery: 92,
  91. signal: 95,
  92. },
  93. {
  94. id: 5,
  95. name: "设备005",
  96. type: "智能井盖",
  97. status: "maintenance",
  98. location: "丰台区丽泽",
  99. lat: 39.8584,
  100. lng: 116.3135,
  101. battery: 78,
  102. signal: 80,
  103. },
  104. ])
  105. const [alerts, setAlerts] = useState([
  106. {
  107. id: 1,
  108. deviceName: "设备002",
  109. type: "位移异常",
  110. level: "warning",
  111. time: "2024-01-15 14:30:25",
  112. location: "海淀区中关村",
  113. status: "pending", // pending, processed, ignored
  114. },
  115. {
  116. id: 2,
  117. deviceName: "设备003",
  118. type: "电池电压低",
  119. level: "error",
  120. time: "2024-01-15 14:25:10",
  121. location: "西城区金融街",
  122. status: "pending",
  123. },
  124. {
  125. id: 3,
  126. deviceName: "设备001",
  127. type: "震动异常",
  128. level: "info",
  129. time: "2024-01-15 14:20:15",
  130. location: "朝阳区建国路",
  131. status: "processed",
  132. },
  133. ])
  134. const [addDeviceForm] = Form.useForm()
  135. const [editDeviceForm] = Form.useForm()
  136. const handleAddDevice = (values: any) => {
  137. const newDevice = {
  138. id: devices.length + 1,
  139. name: values.name,
  140. type: values.type,
  141. status: values.status,
  142. location: values.location,
  143. lat: Number.parseFloat(values.lat),
  144. lng: Number.parseFloat(values.lng),
  145. battery: Number.parseInt(values.battery),
  146. signal: Number.parseInt(values.signal),
  147. }
  148. setDevices([...devices, newDevice])
  149. setAddDeviceModalVisible(false)
  150. addDeviceForm.resetFields()
  151. message.success("设备添加成功!")
  152. }
  153. const handleEditDevice = (values: any) => {
  154. const updatedDevices = devices.map((device) =>
  155. device.id === editingDevice.id
  156. ? {
  157. ...device,
  158. ...values,
  159. lat: Number.parseFloat(values.lat),
  160. lng: Number.parseFloat(values.lng),
  161. battery: Number.parseInt(values.battery),
  162. signal: Number.parseInt(values.signal),
  163. }
  164. : device,
  165. )
  166. setDevices(updatedDevices)
  167. setEditDeviceModalVisible(false)
  168. setEditingDevice(null)
  169. editDeviceForm.resetFields()
  170. message.success("设备信息更新成功!")
  171. }
  172. const openEditModal = (device: any) => {
  173. setEditingDevice(device)
  174. editDeviceForm.setFieldsValue(device)
  175. setEditDeviceModalVisible(true)
  176. }
  177. const handleProcessAlert = (alertId: number) => {
  178. const updatedAlerts = alerts.map((alert) => (alert.id === alertId ? { ...alert, status: "processed" } : alert))
  179. setAlerts(updatedAlerts)
  180. message.success("报警已处理!")
  181. }
  182. const handleIgnoreAlert = (alertId: number) => {
  183. const updatedAlerts = alerts.map((alert) => (alert.id === alertId ? { ...alert, status: "ignored" } : alert))
  184. setAlerts(updatedAlerts)
  185. message.success("报警已忽略!")
  186. }
  187. // 设备状态统计
  188. const deviceStats = {
  189. total: devices.length,
  190. normal: devices.filter((d) => d.status === "normal").length,
  191. warning: devices.filter((d) => d.status === "warning").length,
  192. error: devices.filter((d) => d.status === "error").length,
  193. maintenance: devices.filter((d) => d.status === "maintenance").length,
  194. }
  195. // 区域分布图表配置
  196. const regionChartOption = {
  197. title: { text: "设备区域分布", left: "center" },
  198. tooltip: { trigger: "item" },
  199. series: [
  200. {
  201. type: "pie",
  202. radius: "50%",
  203. data: [
  204. { value: 1, name: "朝阳区" },
  205. { value: 1, name: "海淀区" },
  206. { value: 1, name: "西城区" },
  207. { value: 1, name: "东城区" },
  208. { value: 1, name: "丰台区" },
  209. ],
  210. },
  211. ],
  212. }
  213. // 设备状态分布图表配置
  214. const statusChartOption = {
  215. title: { text: "设备状态分布", left: "center" },
  216. tooltip: { trigger: "item" },
  217. series: [
  218. {
  219. type: "pie",
  220. radius: "50%",
  221. data: [
  222. { value: deviceStats.normal, name: "正常", itemStyle: { color: "#52c41a" } },
  223. { value: deviceStats.warning, name: "告警", itemStyle: { color: "#faad14" } },
  224. { value: deviceStats.error, name: "故障", itemStyle: { color: "#f5222d" } },
  225. { value: deviceStats.maintenance, name: "维修中", itemStyle: { color: "#722ed1" } },
  226. ],
  227. },
  228. ],
  229. }
  230. // 实时监测数据图表配置
  231. const monitoringChartOption = {
  232. title: { text: "实时监测数据趋势", left: "center" },
  233. tooltip: { trigger: "axis" },
  234. legend: { data: ["倾斜角度", "位移距离", "震动强度"], top: 30 },
  235. xAxis: {
  236. type: "category",
  237. data: ["00:00", "04:00", "08:00", "12:00", "16:00", "20:00"],
  238. },
  239. yAxis: { type: "value" },
  240. series: [
  241. {
  242. name: "倾斜角度",
  243. type: "line",
  244. data: [2.1, 2.3, 2.0, 2.5, 2.8, 2.4],
  245. itemStyle: { color: "#1890ff" },
  246. },
  247. {
  248. name: "位移距离",
  249. type: "line",
  250. data: [0.5, 0.7, 0.4, 0.9, 1.2, 0.8],
  251. itemStyle: { color: "#52c41a" },
  252. },
  253. {
  254. name: "震动强度",
  255. type: "line",
  256. data: [15, 18, 12, 22, 28, 20],
  257. itemStyle: { color: "#faad14" },
  258. },
  259. ],
  260. }
  261. const deviceColumns = [
  262. { title: "设备编号", dataIndex: "name", key: "name" },
  263. { title: "设备类型", dataIndex: "type", key: "type" },
  264. {
  265. title: "运维状态",
  266. dataIndex: "status",
  267. key: "status",
  268. render: (status: string) => {
  269. const statusMap = {
  270. normal: { color: "success", text: "正常" },
  271. warning: { color: "warning", text: "告警" },
  272. error: { color: "error", text: "故障" },
  273. maintenance: { color: "processing", text: "维修中" },
  274. }
  275. const config = statusMap[status as keyof typeof statusMap]
  276. return <Badge status={config.color as any} text={config.text} />
  277. },
  278. },
  279. { title: "所在位置", dataIndex: "location", key: "location" },
  280. {
  281. title: "电池电量",
  282. dataIndex: "battery",
  283. key: "battery",
  284. render: (battery: number) => `${battery}%`,
  285. },
  286. {
  287. title: "信号强度",
  288. dataIndex: "signal",
  289. key: "signal",
  290. render: (signal: number) => `${signal}%`,
  291. },
  292. {
  293. title: "操作",
  294. key: "action",
  295. render: (_, record: any) => (
  296. <Space>
  297. <Button
  298. type="link"
  299. icon={<EyeOutlined />}
  300. onClick={() => {
  301. setSelectedDevice(record)
  302. setDeviceModalVisible(true)
  303. }}
  304. >
  305. 查看
  306. </Button>
  307. <Button type="link" icon={<EditOutlined />} onClick={() => openEditModal(record)}>
  308. 编辑
  309. </Button>
  310. </Space>
  311. ),
  312. },
  313. ]
  314. const alertColumns = [
  315. { title: "设备名称", dataIndex: "deviceName", key: "deviceName" },
  316. { title: "报警类型", dataIndex: "type", key: "type" },
  317. {
  318. title: "报警级别",
  319. dataIndex: "level",
  320. key: "level",
  321. render: (level: string) => {
  322. const levelMap = {
  323. info: { color: "blue", text: "信息" },
  324. warning: { color: "orange", text: "警告" },
  325. error: { color: "red", text: "严重" },
  326. }
  327. const config = levelMap[level as keyof typeof levelMap]
  328. return <Tag color={config.color}>{config.text}</Tag>
  329. },
  330. },
  331. { title: "报警时间", dataIndex: "time", key: "time" },
  332. { title: "设备位置", dataIndex: "location", key: "location" },
  333. {
  334. title: "状态",
  335. dataIndex: "status",
  336. key: "status",
  337. render: (status: string) => {
  338. const statusMap = {
  339. pending: { color: "orange", text: "待处理" },
  340. processed: { color: "green", text: "已处理" },
  341. ignored: { color: "gray", text: "已忽略" },
  342. }
  343. const config = statusMap[status as keyof typeof statusMap]
  344. return <Tag color={config.color}>{config.text}</Tag>
  345. },
  346. },
  347. {
  348. title: "操作",
  349. key: "action",
  350. render: (_, record: any) => (
  351. <Space>
  352. {record.status === "pending" && (
  353. <>
  354. <Button type="link" onClick={() => handleProcessAlert(record.id)}>
  355. 处理
  356. </Button>
  357. <Button type="link" onClick={() => handleIgnoreAlert(record.id)}>
  358. 忽略
  359. </Button>
  360. </>
  361. )}
  362. {record.status !== "pending" && <span className="text-gray-400">已处理</span>}
  363. </Space>
  364. ),
  365. },
  366. ]
  367. const renderContent = () => {
  368. switch (selectedMenu) {
  369. case "dashboard":
  370. return (
  371. <div className="space-y-6">
  372. {/* 统计卡片 */}
  373. <Row gutter={16}>
  374. <Col span={6}>
  375. <Card>
  376. <Statistic title="设备总数" value={deviceStats.total} valueStyle={{ color: "#1890ff" }} />
  377. </Card>
  378. </Col>
  379. <Col span={6}>
  380. <Card>
  381. <Statistic title="正常设备" value={deviceStats.normal} valueStyle={{ color: "#52c41a" }} />
  382. </Card>
  383. </Col>
  384. <Col span={6}>
  385. <Card>
  386. <Statistic title="告警设备" value={deviceStats.warning} valueStyle={{ color: "#faad14" }} />
  387. </Card>
  388. </Col>
  389. <Col span={6}>
  390. <Card>
  391. <Statistic title="故障设备" value={deviceStats.error} valueStyle={{ color: "#f5222d" }} />
  392. </Card>
  393. </Col>
  394. </Row>
  395. {/* 图表展示 */}
  396. <Row gutter={16}>
  397. <Col span={12}>
  398. <Card title="设备区域分布">
  399. <EChart option={regionChartOption} />
  400. </Card>
  401. </Col>
  402. <Col span={12}>
  403. <Card title="设备状态分布">
  404. <EChart option={statusChartOption} />
  405. </Card>
  406. </Col>
  407. </Row>
  408. {/* 实时监测趋势 */}
  409. <Card title="实时监测数据趋势">
  410. <EChart option={monitoringChartOption} />
  411. </Card>
  412. </div>
  413. )
  414. case "devices":
  415. return (
  416. <div className="space-y-6">
  417. <Card
  418. title="监测设备台账"
  419. extra={
  420. <Button type="primary" icon={<PlusOutlined />} onClick={() => setAddDeviceModalVisible(true)}>
  421. 添加设备
  422. </Button>
  423. }
  424. >
  425. <Table columns={deviceColumns} dataSource={devices} rowKey="id" pagination={{ pageSize: 10 }} />
  426. </Card>
  427. </div>
  428. )
  429. case "map":
  430. return (
  431. <div className="space-y-6">
  432. <Card title="监测设备 GIS 一张图">
  433. <div style={{ height: "600px" }}>
  434. <GisMapBaidu height={'50'} />
  435. </div>
  436. </Card>
  437. </div>
  438. )
  439. case "monitoring":
  440. return (
  441. <div className="space-y-6">
  442. <Row gutter={16}>
  443. <Col span={24}>
  444. <Alert
  445. message="实时监测状态"
  446. description="系统正在实时监测所有窨井盖设备状态,包括开启、位移、倾斜、震动、溢水等情况"
  447. type="info"
  448. showIcon
  449. className="mb-4"
  450. />
  451. </Col>
  452. </Row>
  453. <Tabs defaultActiveKey="realtime">
  454. <TabPane tab="实时监测" key="realtime">
  455. <Row gutter={16}>
  456. <Col span={24}>
  457. <Card title="实时监测一张图">
  458. <div style={{ height: "500px" }}>
  459. <MapView devices={devices} showRealTimeData />
  460. </div>
  461. </Card>
  462. </Col>
  463. </Row>
  464. </TabPane>
  465. <TabPane tab="监测数据" key="data">
  466. <Card title="实时监测数据">
  467. <EChart option={monitoringChartOption} />
  468. </Card>
  469. </TabPane>
  470. </Tabs>
  471. </div>
  472. )
  473. case "alerts":
  474. return (
  475. <div className="space-y-6">
  476. <Row gutter={16}>
  477. <Col span={6}>
  478. <Card>
  479. <Statistic title="今日告警" value={alerts.length} valueStyle={{ color: "#f5222d" }} />
  480. </Card>
  481. </Col>
  482. <Col span={6}>
  483. <Card>
  484. <Statistic
  485. title="待处理"
  486. value={alerts.filter((a) => a.status === "pending").length}
  487. valueStyle={{ color: "#faad14" }}
  488. />
  489. </Card>
  490. </Col>
  491. <Col span={6}>
  492. <Card>
  493. <Statistic
  494. title="已处理"
  495. value={alerts.filter((a) => a.status === "processed").length}
  496. valueStyle={{ color: "#52c41a" }}
  497. />
  498. </Card>
  499. </Col>
  500. <Col span={6}>
  501. <Card>
  502. <Statistic
  503. title="已忽略"
  504. value={alerts.filter((a) => a.status === "ignored").length}
  505. valueStyle={{ color: "#d9d9d9" }}
  506. />
  507. </Card>
  508. </Col>
  509. </Row>
  510. <Card title="监测报警记录">
  511. <Table columns={alertColumns} dataSource={alerts} rowKey="id" pagination={{ pageSize: 10 }} />
  512. </Card>
  513. </div>
  514. )
  515. default:
  516. return <div>页面开发中...</div>
  517. }
  518. }
  519. return (
  520. <Layout className="min-h-screen">
  521. <Header className="bg-blue-600 text-white" style={{backgroundColor:'white'}}>
  522. <div className="flex items-center justify-between">
  523. <h1 className="text-xl font-bold">窨井盖安全运行监测子系统</h1>
  524. <div className="text-sm">当前时间: {new Date().toLocaleString("zh-CN")}</div>
  525. </div>
  526. </Header>
  527. <Layout>
  528. <Sider width={200} className="bg-white">
  529. <Menu
  530. mode="inline"
  531. selectedKeys={[selectedMenu]}
  532. onClick={({ key }) => setSelectedMenu(key)}
  533. className="h-full border-r"
  534. >
  535. <Menu.Item key="dashboard" icon={<DashboardOutlined />}>
  536. 监控面板
  537. </Menu.Item>
  538. <Menu.Item key="devices" icon={<SettingOutlined />}>
  539. 设备管理
  540. </Menu.Item>
  541. <Menu.Item key="map" icon={<EnvironmentOutlined />}>
  542. GIS地图
  543. </Menu.Item>
  544. <Menu.Item key="monitoring" icon={<BarChartOutlined />}>
  545. 实时监测
  546. </Menu.Item>
  547. <Menu.Item key="alerts" icon={<AlertOutlined />}>
  548. 报警管理
  549. </Menu.Item>
  550. </Menu>
  551. </Sider>
  552. <Layout className="p-6">
  553. <Content className="bg-gray-50 min-h-full">{renderContent()}</Content>
  554. </Layout>
  555. </Layout>
  556. {/* 设备详情弹窗 */}
  557. <Modal
  558. title="设备详情"
  559. open={deviceModalVisible}
  560. onCancel={() => setDeviceModalVisible(false)}
  561. footer={null}
  562. width={600}
  563. >
  564. {selectedDevice && (
  565. <div className="space-y-4">
  566. <Row gutter={16}>
  567. <Col span={12}>
  568. <div>
  569. <strong>设备编号:</strong> {selectedDevice.name}
  570. </div>
  571. </Col>
  572. <Col span={12}>
  573. <div>
  574. <strong>设备类型:</strong> {selectedDevice.type}
  575. </div>
  576. </Col>
  577. </Row>
  578. <Row gutter={16}>
  579. <Col span={12}>
  580. <div>
  581. <strong>所在位置:</strong> {selectedDevice.location}
  582. </div>
  583. </Col>
  584. <Col span={12}>
  585. <div>
  586. <strong>运维状态:</strong>
  587. <Badge
  588. status={selectedDevice.status === "normal" ? "success" : "error"}
  589. text={selectedDevice.status === "normal" ? "正常" : "异常"}
  590. />
  591. </div>
  592. </Col>
  593. </Row>
  594. <Row gutter={16}>
  595. <Col span={12}>
  596. <div>
  597. <strong>电池电量:</strong> {selectedDevice.battery}%
  598. </div>
  599. </Col>
  600. <Col span={12}>
  601. <div>
  602. <strong>信号强度:</strong> {selectedDevice.signal}%
  603. </div>
  604. </Col>
  605. </Row>
  606. </div>
  607. )}
  608. </Modal>
  609. {/* 添加设备弹窗 */}
  610. <Modal
  611. title="添加设备"
  612. open={addDeviceModalVisible}
  613. onCancel={() => {
  614. setAddDeviceModalVisible(false)
  615. addDeviceForm.resetFields()
  616. }}
  617. onOk={() => addDeviceForm.submit()}
  618. width={600}
  619. >
  620. <Form form={addDeviceForm} layout="vertical" onFinish={handleAddDevice}>
  621. <Row gutter={16}>
  622. <Col span={12}>
  623. <Form.Item name="name" label="设备编号" rules={[{ required: true, message: "请输入设备编号" }]}>
  624. <Input placeholder="请输入设备编号" />
  625. </Form.Item>
  626. </Col>
  627. <Col span={12}>
  628. <Form.Item name="type" label="设备类型" rules={[{ required: true, message: "请选择设备类型" }]}>
  629. <Select placeholder="请选择设备类型">
  630. <Option value="智能井盖">智能井盖</Option>
  631. <Option value="传感器">传感器</Option>
  632. <Option value="监控设备">监控设备</Option>
  633. </Select>
  634. </Form.Item>
  635. </Col>
  636. </Row>
  637. <Row gutter={16}>
  638. <Col span={12}>
  639. <Form.Item name="status" label="运维状态" rules={[{ required: true, message: "请选择运维状态" }]}>
  640. <Select placeholder="请选择运维状态">
  641. <Option value="normal">正常</Option>
  642. <Option value="warning">告警</Option>
  643. <Option value="error">故障</Option>
  644. <Option value="maintenance">维修中</Option>
  645. </Select>
  646. </Form.Item>
  647. </Col>
  648. <Col span={12}>
  649. <Form.Item name="location" label="所在位置" rules={[{ required: true, message: "请输入所在位置" }]}>
  650. <Input placeholder="请输入所在位置" />
  651. </Form.Item>
  652. </Col>
  653. </Row>
  654. <Row gutter={16}>
  655. <Col span={12}>
  656. <Form.Item name="lat" label="纬度" rules={[{ required: true, message: "请输入纬度" }]}>
  657. <Input placeholder="请输入纬度" type="number" step="0.000001" />
  658. </Form.Item>
  659. </Col>
  660. <Col span={12}>
  661. <Form.Item name="lng" label="经度" rules={[{ required: true, message: "请输入经度" }]}>
  662. <Input placeholder="请输入经度" type="number" step="0.000001" />
  663. </Form.Item>
  664. </Col>
  665. </Row>
  666. <Row gutter={16}>
  667. <Col span={12}>
  668. <Form.Item name="battery" label="电池电量(%)" rules={[{ required: true, message: "请输入电池电量" }]}>
  669. <Input placeholder="请输入电池电量" type="number" min="0" max="100" />
  670. </Form.Item>
  671. </Col>
  672. <Col span={12}>
  673. <Form.Item name="signal" label="信号强度(%)" rules={[{ required: true, message: "请输入信号强度" }]}>
  674. <Input placeholder="请输入信号强度" type="number" min="0" max="100" />
  675. </Form.Item>
  676. </Col>
  677. </Row>
  678. </Form>
  679. </Modal>
  680. {/* 编辑设备弹窗 */}
  681. <Modal
  682. title="编辑设备"
  683. open={editDeviceModalVisible}
  684. onCancel={() => {
  685. setEditDeviceModalVisible(false)
  686. setEditingDevice(null)
  687. editDeviceForm.resetFields()
  688. }}
  689. onOk={() => editDeviceForm.submit()}
  690. width={600}
  691. >
  692. <Form form={editDeviceForm} layout="vertical" onFinish={handleEditDevice}>
  693. <Row gutter={16}>
  694. <Col span={12}>
  695. <Form.Item name="name" label="设备编号" rules={[{ required: true, message: "请输入设备编号" }]}>
  696. <Input placeholder="请输入设备编号" />
  697. </Form.Item>
  698. </Col>
  699. <Col span={12}>
  700. <Form.Item name="type" label="设备类型" rules={[{ required: true, message: "请选择设备类型" }]}>
  701. <Select placeholder="请选择设备类型">
  702. <Option value="智能井盖">智能井盖</Option>
  703. <Option value="传感器">传感器</Option>
  704. <Option value="监控设备">监控设备</Option>
  705. </Select>
  706. </Form.Item>
  707. </Col>
  708. </Row>
  709. <Row gutter={16}>
  710. <Col span={12}>
  711. <Form.Item name="status" label="运维状态" rules={[{ required: true, message: "请选择运维状态" }]}>
  712. <Select placeholder="请选择运维状态">
  713. <Option value="normal">正常</Option>
  714. <Option value="warning">告警</Option>
  715. <Option value="error">故障</Option>
  716. <Option value="maintenance">维修中</Option>
  717. </Select>
  718. </Form.Item>
  719. </Col>
  720. <Col span={12}>
  721. <Form.Item name="location" label="所在位置" rules={[{ required: true, message: "请输入所在位置" }]}>
  722. <Input placeholder="请输入所在位置" />
  723. </Form.Item>
  724. </Col>
  725. </Row>
  726. <Row gutter={16}>
  727. <Col span={12}>
  728. <Form.Item name="lat" label="纬度" rules={[{ required: true, message: "请输入纬度" }]}>
  729. <Input placeholder="请输入纬度" type="number" step="0.000001" />
  730. </Form.Item>
  731. </Col>
  732. <Col span={12}>
  733. <Form.Item name="lng" label="经度" rules={[{ required: true, message: "请输入经度" }]}>
  734. <Input placeholder="请输入经度" type="number" step="0.000001" />
  735. </Form.Item>
  736. </Col>
  737. </Row>
  738. <Row gutter={16}>
  739. <Col span={12}>
  740. <Form.Item name="battery" label="电池电量(%)" rules={[{ required: true, message: "请输入电池电量" }]}>
  741. <Input placeholder="请输入电池电量" type="number" min="0" max="100" />
  742. </Form.Item>
  743. </Col>
  744. <Col span={12}>
  745. <Form.Item name="signal" label="信号强度(%)" rules={[{ required: true, message: "请输入信号强度" }]}>
  746. <Input placeholder="请输入信号强度" type="number" min="0" max="100" />
  747. </Form.Item>
  748. </Col>
  749. </Row>
  750. </Form>
  751. </Modal>
  752. </Layout>
  753. )
  754. }