DataManagement.tsx 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206
  1. "use client"
  2. import {useEffect, useState} from "react"
  3. import {Button, Card, Col, Descriptions, Form, Input, Modal, Row, Select, Space, Statistic, Table, Tabs} from "antd"
  4. import {DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined, SearchOutlined} from "@ant-design/icons"
  5. import globalMessage from "@/app/_modules/globalMessage";
  6. import EChart from "@/components/echarts"
  7. const { Option } = Select
  8. const { TabPane } = Tabs
  9. export default function DataManagement() {
  10. const [selectedTab, setSelectedTab] = useState("drainage-areas")
  11. const [modalVisible, setModalVisible] = useState(false)
  12. const [detailModalVisible, setDetailModalVisible] = useState(false)
  13. const [editingRecord, setEditingRecord] = useState<any>(null)
  14. const [detailRecord, setDetailRecord] = useState<any>(null)
  15. const [form] = Form.useForm()
  16. // 各种数据状态
  17. const [drainageAreas, setDrainageAreas] = useState([
  18. {
  19. key: "1",
  20. id: "DA001",
  21. name: "中心城区雨水分区",
  22. type: "雨水分区",
  23. area: "15.6",
  24. population: "120000",
  25. status: "正常",
  26. },
  27. {
  28. key: "2",
  29. id: "DA002",
  30. name: "工业园区污水分区",
  31. type: "污水分区",
  32. area: "8.3",
  33. population: "45000",
  34. status: "正常",
  35. },
  36. ])
  37. const [pipelineData, setPipelineData] = useState([
  38. {
  39. key: "1",
  40. id: "PL001",
  41. name: "主干道雨水管",
  42. type: "雨水管",
  43. diameter: "1200mm",
  44. length: "2.5km",
  45. material: "钢筋混凝土",
  46. status: "良好",
  47. },
  48. {
  49. key: "2",
  50. id: "PL002",
  51. name: "支线污水管",
  52. type: "污水管",
  53. diameter: "800mm",
  54. length: "1.8km",
  55. material: "HDPE",
  56. status: "良好",
  57. },
  58. ])
  59. const [engineeringFacilities, setEngineeringFacilities] = useState([
  60. {
  61. key: "1",
  62. id: "EF001",
  63. name: "第一泵站",
  64. type: "泵站",
  65. capacity: "500m³/h",
  66. power: "75kW",
  67. status: "运行中",
  68. },
  69. {
  70. key: "2",
  71. id: "EF002",
  72. name: "调蓄池A",
  73. type: "调蓄设施",
  74. capacity: "10000m³",
  75. currentLevel: "30%",
  76. status: "待命",
  77. },
  78. ])
  79. const [waterloggingPoints, setWaterloggingPoints] = useState([
  80. {
  81. key: "1",
  82. id: "WP001",
  83. name: "人民路积水点",
  84. location: "人民路与南京路交叉口",
  85. riskLevel: "高",
  86. historicalDepth: "0.8m",
  87. status: "监控中",
  88. },
  89. {
  90. key: "2",
  91. id: "WP002",
  92. name: "商业区积水点",
  93. location: "淮海路商业广场",
  94. riskLevel: "中",
  95. historicalDepth: "0.5m",
  96. status: "监控中",
  97. },
  98. ])
  99. const [monitoringDevices, setMonitoringDevices] = useState([
  100. {
  101. key: "1",
  102. id: "MD001",
  103. name: "液位计LV002",
  104. type: "液位计",
  105. location: "人民路积水点",
  106. installDate: "2023-06-15",
  107. lastMaintenance: "2024-01-10",
  108. status: "在线",
  109. },
  110. {
  111. key: "2",
  112. id: "MD002",
  113. name: "流量计FL001",
  114. type: "流量计",
  115. location: "主干道管网",
  116. installDate: "2023-08-20",
  117. lastMaintenance: "2024-01-08",
  118. status: "在线",
  119. },
  120. ])
  121. // 查询条件状态
  122. const [searchParams, setSearchParams] = useState({
  123. drainageArea: { name: "", type: "" },
  124. pipeline: { id: "", type: "" },
  125. facility: { name: "", type: "" },
  126. waterlogging: { name: "", riskLevel: "" },
  127. device: { id: "", type: "" }
  128. })
  129. // 过滤后的数据
  130. const [filteredDrainageAreas, setFilteredDrainageAreas] = useState(drainageAreas)
  131. const [filteredPipelineData, setFilteredPipelineData] = useState(pipelineData)
  132. const [filteredEngineeringFacilities, setFilteredEngineeringFacilities] = useState(engineeringFacilities)
  133. const [filteredWaterloggingPoints, setFilteredWaterloggingPoints] = useState(waterloggingPoints)
  134. const [filteredMonitoringDevices, setFilteredMonitoringDevices] = useState(monitoringDevices)
  135. // 当原始数据变化时更新过滤数据
  136. useEffect(() => {
  137. setFilteredDrainageAreas(drainageAreas)
  138. setFilteredPipelineData(pipelineData)
  139. setFilteredEngineeringFacilities(engineeringFacilities)
  140. setFilteredWaterloggingPoints(waterloggingPoints)
  141. setFilteredMonitoringDevices(monitoringDevices)
  142. }, [drainageAreas, pipelineData, engineeringFacilities, waterloggingPoints, monitoringDevices])
  143. const handleEdit = (record: any) => {
  144. setEditingRecord(record)
  145. form.setFieldsValue(record)
  146. setModalVisible(true)
  147. }
  148. const handleViewDetail = (record: any) => {
  149. setDetailRecord(record)
  150. setDetailModalVisible(true)
  151. }
  152. const handleDelete = (record: any, dataType: string) => {
  153. Modal.confirm({
  154. title: "确认删除",
  155. content: `确定要删除 ${record.name} 吗?`,
  156. onOk() {
  157. switch (dataType) {
  158. case "drainage":
  159. setDrainageAreas(prev => prev.filter(item => item.id !== record.id))
  160. break
  161. case "pipeline":
  162. setPipelineData(prev => prev.filter(item => item.id !== record.id))
  163. break
  164. case "facility":
  165. setEngineeringFacilities(prev => prev.filter(item => item.id !== record.id))
  166. break
  167. case "waterlogging":
  168. setWaterloggingPoints(prev => prev.filter(item => item.id !== record.id))
  169. break
  170. case "device":
  171. setMonitoringDevices(prev => prev.filter(item => item.id !== record.id))
  172. break
  173. }
  174. globalMessage.success("删除成功")
  175. },
  176. })
  177. }
  178. const handleAdd = () => {
  179. setEditingRecord(null)
  180. form.resetFields()
  181. setModalVisible(true)
  182. }
  183. const handleSave = () => {
  184. form.validateFields().then(values => {
  185. if (editingRecord) {
  186. // 编辑现有记录
  187. const updatedData = {
  188. ...editingRecord,
  189. ...values
  190. }
  191. switch (selectedTab) {
  192. case "drainage-areas":
  193. setDrainageAreas(prev => prev.map(item =>
  194. item.id === editingRecord.id ? updatedData : item
  195. ))
  196. break
  197. case "pipeline-network":
  198. setPipelineData(prev => prev.map(item =>
  199. item.id === editingRecord.id ? updatedData : item
  200. ))
  201. break
  202. case "engineering-facilities":
  203. setEngineeringFacilities(prev => prev.map(item =>
  204. item.id === editingRecord.id ? updatedData : item
  205. ))
  206. break
  207. case "waterlogging-points":
  208. setWaterloggingPoints(prev => prev.map(item =>
  209. item.id === editingRecord.id ? updatedData : item
  210. ))
  211. break
  212. case "monitoring-devices":
  213. setMonitoringDevices(prev => prev.map(item =>
  214. item.id === editingRecord.id ? updatedData : item
  215. ))
  216. break
  217. }
  218. } else {
  219. // 添加新记录
  220. const newRecord = {
  221. ...values,
  222. key: Date.now().toString(),
  223. id: generateId(selectedTab)
  224. }
  225. switch (selectedTab) {
  226. case "drainage-areas":
  227. setDrainageAreas(prev => [...prev, newRecord])
  228. break
  229. case "pipeline-network":
  230. setPipelineData(prev => [...prev, newRecord])
  231. break
  232. case "engineering-facilities":
  233. setEngineeringFacilities(prev => [...prev, newRecord])
  234. break
  235. case "waterlogging-points":
  236. setWaterloggingPoints(prev => [...prev, newRecord])
  237. break
  238. case "monitoring-devices":
  239. setMonitoringDevices(prev => [...prev, newRecord])
  240. break
  241. }
  242. }
  243. globalMessage.success(editingRecord ? "编辑成功" : "新增成功")
  244. setModalVisible(false)
  245. setEditingRecord(null)
  246. form.resetFields()
  247. })
  248. }
  249. const generateId = (tab: string) => {
  250. const prefixMap: Record<string, string> = {
  251. "drainage-areas": "DA",
  252. "pipeline-network": "PL",
  253. "engineering-facilities": "EF",
  254. "waterlogging-points": "WP",
  255. "monitoring-devices": "MD"
  256. }
  257. const prefix = prefixMap[tab] || "ID"
  258. const timestamp = Date.now().toString().slice(-6)
  259. return `${prefix}${timestamp}`
  260. }
  261. // 查询处理函数
  262. const handleSearch = (dataType: string) => {
  263. switch (dataType) {
  264. case "drainage":
  265. const filteredDrainage = drainageAreas.filter(item => {
  266. return (
  267. (searchParams.drainageArea.name === "" ||
  268. item.name.toLowerCase().includes(searchParams.drainageArea.name.toLowerCase())) &&
  269. (searchParams.drainageArea.type === "" ||
  270. item.type.includes(searchParams.drainageArea.type))
  271. )
  272. })
  273. setFilteredDrainageAreas(filteredDrainage)
  274. break
  275. case "pipeline":
  276. const filteredPipeline = pipelineData.filter(item => {
  277. return (
  278. (searchParams.pipeline.id === "" ||
  279. item.id.toLowerCase().includes(searchParams.pipeline.id.toLowerCase())) &&
  280. (searchParams.pipeline.type === "" ||
  281. item.type.includes(searchParams.pipeline.type))
  282. )
  283. })
  284. setFilteredPipelineData(filteredPipeline)
  285. break
  286. case "facility":
  287. const filteredFacility = engineeringFacilities.filter(item => {
  288. return (
  289. (searchParams.facility.name === "" ||
  290. item.name.toLowerCase().includes(searchParams.facility.name.toLowerCase())) &&
  291. (searchParams.facility.type === "" ||
  292. item.type.includes(searchParams.facility.type))
  293. )
  294. })
  295. setFilteredEngineeringFacilities(filteredFacility)
  296. break
  297. case "waterlogging":
  298. const filteredWaterlogging = waterloggingPoints.filter(item => {
  299. return (
  300. (searchParams.waterlogging.name === "" ||
  301. item.name.toLowerCase().includes(searchParams.waterlogging.name.toLowerCase())) &&
  302. (searchParams.waterlogging.riskLevel === "" ||
  303. item.riskLevel.includes(searchParams.waterlogging.riskLevel))
  304. )
  305. })
  306. setFilteredWaterloggingPoints(filteredWaterlogging)
  307. break
  308. case "device":
  309. const filteredDevice = monitoringDevices.filter(item => {
  310. return (
  311. (searchParams.device.id === "" ||
  312. item.id.toLowerCase().includes(searchParams.device.id.toLowerCase())) &&
  313. (searchParams.device.type === "" ||
  314. item.type.includes(searchParams.device.type))
  315. )
  316. })
  317. setFilteredMonitoringDevices(filteredDevice)
  318. break
  319. }
  320. }
  321. // 更新搜索参数
  322. const updateSearchParams = (dataType: string, field: string, value: string) => {
  323. setSearchParams(prev => ({
  324. ...prev,
  325. [dataType]: {
  326. ...prev[dataType],
  327. [field]: value
  328. }
  329. }))
  330. }
  331. const commonColumns = [
  332. {
  333. title: "操作",
  334. key: "action",
  335. width: 200,
  336. render: (_, record) => (
  337. <Space>
  338. <Button size="small" icon={<EyeOutlined />} onClick={() => handleViewDetail(record)}>
  339. 详情
  340. </Button>
  341. <Button size="small" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
  342. 编辑
  343. </Button>
  344. <Button
  345. size="small"
  346. danger
  347. icon={<DeleteOutlined />}
  348. onClick={() => {
  349. let dataType = ""
  350. switch (selectedTab) {
  351. case "drainage-areas": dataType = "drainage"; break
  352. case "pipeline-network": dataType = "pipeline"; break
  353. case "engineering-facilities": dataType = "facility"; break
  354. case "waterlogging-points": dataType = "waterlogging"; break
  355. case "monitoring-devices": dataType = "device"; break
  356. }
  357. handleDelete(record, dataType)
  358. }}
  359. >
  360. 删除
  361. </Button>
  362. </Space>
  363. ),
  364. },
  365. ]
  366. const drainageAreaColumns = [
  367. { title: "分区编号", dataIndex: "id", key: "id" },
  368. { title: "分区名称", dataIndex: "name", key: "name" },
  369. { title: "分区类型", dataIndex: "type", key: "type" },
  370. { title: "面积(km²)", dataIndex: "area", key: "area" },
  371. { title: "服务人口", dataIndex: "population", key: "population" },
  372. { title: "状态", dataIndex: "status", key: "status" },
  373. ...commonColumns,
  374. ]
  375. const pipelineColumns = [
  376. { title: "管线编号", dataIndex: "id", key: "id" },
  377. { title: "管线名称", dataIndex: "name", key: "name" },
  378. { title: "管线类型", dataIndex: "type", key: "type" },
  379. { title: "管径", dataIndex: "diameter", key: "diameter" },
  380. { title: "长度", dataIndex: "length", key: "length" },
  381. { title: "材质", dataIndex: "material", key: "material" },
  382. { title: "状态", dataIndex: "status", key: "status" },
  383. ...commonColumns,
  384. ]
  385. const facilityColumns = [
  386. { title: "设施编号", dataIndex: "id", key: "id" },
  387. { title: "设施名称", dataIndex: "name", key: "name" },
  388. { title: "设施类型", dataIndex: "type", key: "type" },
  389. { title: "处理能力", dataIndex: "capacity", key: "capacity" },
  390. { title: "功率/当前液位", dataIndex: "power", key: "power" },
  391. { title: "状态", dataIndex: "status", key: "status" },
  392. ...commonColumns,
  393. ]
  394. const waterloggingColumns = [
  395. { title: "点位编号", dataIndex: "id", key: "id" },
  396. { title: "点位名称", dataIndex: "name", key: "name" },
  397. { title: "位置", dataIndex: "location", key: "location" },
  398. { title: "风险等级", dataIndex: "riskLevel", key: "riskLevel" },
  399. { title: "历史最大积水深度", dataIndex: "historicalDepth", key: "historicalDepth" },
  400. { title: "状态", dataIndex: "status", key: "status" },
  401. ...commonColumns,
  402. ]
  403. const deviceColumns = [
  404. { title: "设备编号", dataIndex: "id", key: "id" },
  405. { title: "设备名称", dataIndex: "name", key: "name" },
  406. { title: "设备类型", dataIndex: "type", key: "type" },
  407. { title: "安装位置", dataIndex: "location", key: "location" },
  408. { title: "安装日期", dataIndex: "installDate", key: "installDate" },
  409. { title: "最后维护", dataIndex: "lastMaintenance", key: "lastMaintenance" },
  410. { title: "状态", dataIndex: "status", key: "status" },
  411. ...commonColumns,
  412. ]
  413. const renderTabContent = () => {
  414. switch (selectedTab) {
  415. case "drainage-areas":
  416. return (
  417. <Card title="排水分区基础数据管理">
  418. <div className="mb-4">
  419. <Space>
  420. <Input
  421. placeholder="分区名称"
  422. prefix={<SearchOutlined />}
  423. value={searchParams.drainageArea.name}
  424. onChange={e => updateSearchParams("drainageArea", "name", e.target.value)}
  425. />
  426. <Select
  427. placeholder="分区类型"
  428. style={{ width: 120 }}
  429. value={searchParams.drainageArea.type}
  430. onChange={value => updateSearchParams("drainageArea", "type", value)}
  431. >
  432. <Option value="雨水分区">雨水分区</Option>
  433. <Option value="污水分区">污水分区</Option>
  434. </Select>
  435. <Button
  436. type="primary"
  437. icon={<SearchOutlined />}
  438. onClick={() => handleSearch("drainage")}
  439. >
  440. 查询
  441. </Button>
  442. <Button
  443. type="primary"
  444. icon={<PlusOutlined />}
  445. onClick={handleAdd}
  446. >
  447. 新增
  448. </Button>
  449. </Space>
  450. </div>
  451. <Table columns={drainageAreaColumns} dataSource={filteredDrainageAreas} />
  452. </Card>
  453. )
  454. case "pipeline-network":
  455. return (
  456. <Card title="排水管网基础数据管理">
  457. <div className="mb-4">
  458. <Space>
  459. <Input
  460. placeholder="管线编号"
  461. prefix={<SearchOutlined />}
  462. value={searchParams.pipeline.id}
  463. onChange={e => updateSearchParams("pipeline", "id", e.target.value)}
  464. />
  465. <Select
  466. placeholder="管线类型"
  467. style={{ width: 120 }}
  468. value={searchParams.pipeline.type}
  469. onChange={value => updateSearchParams("pipeline", "type", value)}
  470. >
  471. <Option value="雨水管">雨水管</Option>
  472. <Option value="污水管">污水管</Option>
  473. </Select>
  474. <Button
  475. type="primary"
  476. icon={<SearchOutlined />}
  477. onClick={() => handleSearch("pipeline")}
  478. >
  479. 查询
  480. </Button>
  481. <Button
  482. type="primary"
  483. icon={<PlusOutlined />}
  484. onClick={handleAdd}
  485. >
  486. 新增
  487. </Button>
  488. </Space>
  489. </div>
  490. <Table columns={pipelineColumns} dataSource={filteredPipelineData} />
  491. </Card>
  492. )
  493. case "engineering-facilities":
  494. return (
  495. <Card title="工程设施基础数据管理">
  496. <div className="mb-4">
  497. <Space>
  498. <Input
  499. placeholder="设施名称"
  500. prefix={<SearchOutlined />}
  501. value={searchParams.facility.name}
  502. onChange={e => updateSearchParams("facility", "name", e.target.value)}
  503. />
  504. <Select
  505. placeholder="设施类型"
  506. style={{ width: 120 }}
  507. value={searchParams.facility.type}
  508. onChange={value => updateSearchParams("facility", "type", value)}
  509. >
  510. <Option value="泵站">泵站</Option>
  511. <Option value="调蓄设施">调蓄设施</Option>
  512. <Option value="闸门">闸门</Option>
  513. </Select>
  514. <Button
  515. type="primary"
  516. icon={<SearchOutlined />}
  517. onClick={() => handleSearch("facility")}
  518. >
  519. 查询
  520. </Button>
  521. <Button
  522. type="primary"
  523. icon={<PlusOutlined />}
  524. onClick={handleAdd}
  525. >
  526. 新增
  527. </Button>
  528. </Space>
  529. </div>
  530. <Table columns={facilityColumns} dataSource={filteredEngineeringFacilities} />
  531. </Card>
  532. )
  533. case "waterlogging-points":
  534. return (
  535. <Card title="易积水点管理">
  536. <div className="mb-4">
  537. <Space>
  538. <Input
  539. placeholder="点位名称"
  540. prefix={<SearchOutlined />}
  541. value={searchParams.waterlogging.name}
  542. onChange={e => updateSearchParams("waterlogging", "name", e.target.value)}
  543. />
  544. <Select
  545. placeholder="风险等级"
  546. style={{ width: 120 }}
  547. value={searchParams.waterlogging.riskLevel}
  548. onChange={value => updateSearchParams("waterlogging", "riskLevel", value)}
  549. >
  550. <Option value="高">高</Option>
  551. <Option value="中">中</Option>
  552. <Option value="低">低</Option>
  553. </Select>
  554. <Button
  555. type="primary"
  556. icon={<SearchOutlined />}
  557. onClick={() => handleSearch("waterlogging")}
  558. >
  559. 查询
  560. </Button>
  561. <Button
  562. type="primary"
  563. icon={<PlusOutlined />}
  564. onClick={handleAdd}
  565. >
  566. 新增
  567. </Button>
  568. </Space>
  569. </div>
  570. <Table columns={waterloggingColumns} dataSource={filteredWaterloggingPoints} />
  571. </Card>
  572. )
  573. case "monitoring-devices":
  574. return (
  575. <Card title="监测设备管理">
  576. <div className="mb-4">
  577. <Space>
  578. <Input
  579. placeholder="设备编号"
  580. prefix={<SearchOutlined />}
  581. value={searchParams.device.id}
  582. onChange={e => updateSearchParams("device", "id", e.target.value)}
  583. />
  584. <Select
  585. placeholder="设备类型"
  586. style={{ width: 120 }}
  587. value={searchParams.device.type}
  588. onChange={value => updateSearchParams("device", "type", value)}
  589. >
  590. <Option value="液位计">液位计</Option>
  591. <Option value="流量计">流量计</Option>
  592. <Option value="泵站设备">泵站设备</Option>
  593. </Select>
  594. <Button
  595. type="primary"
  596. icon={<SearchOutlined />}
  597. onClick={() => handleSearch("device")}
  598. >
  599. 查询
  600. </Button>
  601. <Button
  602. type="primary"
  603. icon={<PlusOutlined />}
  604. onClick={handleAdd}
  605. >
  606. 新增
  607. </Button>
  608. </Space>
  609. </div>
  610. <Table columns={deviceColumns} dataSource={filteredMonitoringDevices} />
  611. </Card>
  612. )
  613. default:
  614. return null
  615. }
  616. }
  617. // 获取当前tab的表单字段
  618. const getFormFields = () => {
  619. switch (selectedTab) {
  620. case "drainage-areas":
  621. return (
  622. <>
  623. <Form.Item
  624. name="name"
  625. label="分区名称"
  626. rules={[{ required: true, message: '请输入分区名称' }]}
  627. >
  628. <Input />
  629. </Form.Item>
  630. <Form.Item
  631. name="type"
  632. label="分区类型"
  633. rules={[{ required: true, message: '请选择分区类型' }]}
  634. >
  635. <Select>
  636. <Option value="雨水分区">雨水分区</Option>
  637. <Option value="污水分区">污水分区</Option>
  638. </Select>
  639. </Form.Item>
  640. <Form.Item name="area" label="面积(km²)">
  641. <Input />
  642. </Form.Item>
  643. <Form.Item name="population" label="服务人口">
  644. <Input />
  645. </Form.Item>
  646. <Form.Item name="status" label="状态">
  647. <Select>
  648. <Option value="正常">正常</Option>
  649. <Option value="维护中">维护中</Option>
  650. </Select>
  651. </Form.Item>
  652. </>
  653. )
  654. case "pipeline-network":
  655. return (
  656. <>
  657. <Form.Item
  658. name="name"
  659. label="管线名称"
  660. rules={[{ required: true, message: '请输入管线名称' }]}
  661. >
  662. <Input />
  663. </Form.Item>
  664. <Form.Item
  665. name="type"
  666. label="管线类型"
  667. rules={[{ required: true, message: '请选择管线类型' }]}
  668. >
  669. <Select>
  670. <Option value="雨水管">雨水管</Option>
  671. <Option value="污水管">污水管</Option>
  672. </Select>
  673. </Form.Item>
  674. <Form.Item name="diameter" label="管径">
  675. <Input />
  676. </Form.Item>
  677. <Form.Item name="length" label="长度">
  678. <Input />
  679. </Form.Item>
  680. <Form.Item name="material" label="材质">
  681. <Input />
  682. </Form.Item>
  683. <Form.Item name="status" label="状态">
  684. <Select>
  685. <Option value="良好">良好</Option>
  686. <Option value="一般">一般</Option>
  687. <Option value="需维护">需维护</Option>
  688. </Select>
  689. </Form.Item>
  690. </>
  691. )
  692. case "engineering-facilities":
  693. return (
  694. <>
  695. <Form.Item
  696. name="name"
  697. label="设施名称"
  698. rules={[{ required: true, message: '请输入设施名称' }]}
  699. >
  700. <Input />
  701. </Form.Item>
  702. <Form.Item
  703. name="type"
  704. label="设施类型"
  705. rules={[{ required: true, message: '请选择设施类型' }]}
  706. >
  707. <Select>
  708. <Option value="泵站">泵站</Option>
  709. <Option value="调蓄设施">调蓄设施</Option>
  710. <Option value="闸门">闸门</Option>
  711. </Select>
  712. </Form.Item>
  713. <Form.Item name="capacity" label="处理能力">
  714. <Input />
  715. </Form.Item>
  716. <Form.Item name="power" label="功率/当前液位">
  717. <Input />
  718. </Form.Item>
  719. <Form.Item name="status" label="状态">
  720. <Select>
  721. <Option value="运行中">运行中</Option>
  722. <Option value="待命">待命</Option>
  723. <Option value="维护中">维护中</Option>
  724. </Select>
  725. </Form.Item>
  726. </>
  727. )
  728. case "waterlogging-points":
  729. return (
  730. <>
  731. <Form.Item
  732. name="name"
  733. label="点位名称"
  734. rules={[{ required: true, message: '请输入点位名称' }]}
  735. >
  736. <Input />
  737. </Form.Item>
  738. <Form.Item name="location" label="位置">
  739. <Input />
  740. </Form.Item>
  741. <Form.Item name="riskLevel" label="风险等级">
  742. <Select>
  743. <Option value="高">高</Option>
  744. <Option value="中">中</Option>
  745. <Option value="低">低</Option>
  746. </Select>
  747. </Form.Item>
  748. <Form.Item name="historicalDepth" label="历史最大积水深度">
  749. <Input />
  750. </Form.Item>
  751. <Form.Item name="status" label="状态">
  752. <Select>
  753. <Option value="监控中">监控中</Option>
  754. <Option value="维护中">维护中</Option>
  755. </Select>
  756. </Form.Item>
  757. </>
  758. )
  759. case "monitoring-devices":
  760. return (
  761. <>
  762. <Form.Item
  763. name="name"
  764. label="设备名称"
  765. rules={[{ required: true, message: '请输入设备名称' }]}
  766. >
  767. <Input />
  768. </Form.Item>
  769. <Form.Item
  770. name="type"
  771. label="设备类型"
  772. rules={[{ required: true, message: '请选择设备类型' }]}
  773. >
  774. <Select>
  775. <Option value="液位计">液位计</Option>
  776. <Option value="流量计">流量计</Option>
  777. <Option value="泵站设备">泵站设备</Option>
  778. </Select>
  779. </Form.Item>
  780. <Form.Item name="location" label="安装位置">
  781. <Input />
  782. </Form.Item>
  783. <Form.Item name="installDate" label="安装日期">
  784. <Input type="date" />
  785. </Form.Item>
  786. <Form.Item name="lastMaintenance" label="最后维护">
  787. <Input type="date" />
  788. </Form.Item>
  789. <Form.Item name="status" label="状态">
  790. <Select>
  791. <Option value="在线">在线</Option>
  792. <Option value="离线">离线</Option>
  793. <Option value="维护中">维护中</Option>
  794. </Select>
  795. </Form.Item>
  796. </>
  797. )
  798. default:
  799. return null
  800. }
  801. }
  802. // 获取详情描述项
  803. const getDetailDescriptions = () => {
  804. switch (selectedTab) {
  805. case "drainage-areas":
  806. return (
  807. <Descriptions title="排水分区详情" column={2} bordered>
  808. <Descriptions.Item label="分区编号">{detailRecord?.id}</Descriptions.Item>
  809. <Descriptions.Item label="分区名称">{detailRecord?.name}</Descriptions.Item>
  810. <Descriptions.Item label="分区类型">{detailRecord?.type}</Descriptions.Item>
  811. <Descriptions.Item label="面积">{detailRecord?.area} km²</Descriptions.Item>
  812. <Descriptions.Item label="服务人口">{detailRecord?.population}</Descriptions.Item>
  813. <Descriptions.Item label="状态">{detailRecord?.status}</Descriptions.Item>
  814. </Descriptions>
  815. )
  816. case "pipeline-network":
  817. return (
  818. <Descriptions title="管网设施详情" column={2} bordered>
  819. <Descriptions.Item label="管线编号">{detailRecord?.id}</Descriptions.Item>
  820. <Descriptions.Item label="管线名称">{detailRecord?.name}</Descriptions.Item>
  821. <Descriptions.Item label="管线类型">{detailRecord?.type}</Descriptions.Item>
  822. <Descriptions.Item label="管径">{detailRecord?.diameter}</Descriptions.Item>
  823. <Descriptions.Item label="长度">{detailRecord?.length}</Descriptions.Item>
  824. <Descriptions.Item label="材质">{detailRecord?.material}</Descriptions.Item>
  825. <Descriptions.Item label="状态">{detailRecord?.status}</Descriptions.Item>
  826. </Descriptions>
  827. )
  828. case "engineering-facilities":
  829. return (
  830. <Descriptions title="工程设施详情" column={2} bordered>
  831. <Descriptions.Item label="设施编号">{detailRecord?.id}</Descriptions.Item>
  832. <Descriptions.Item label="设施名称">{detailRecord?.name}</Descriptions.Item>
  833. <Descriptions.Item label="设施类型">{detailRecord?.type}</Descriptions.Item>
  834. <Descriptions.Item label="处理能力">{detailRecord?.capacity}</Descriptions.Item>
  835. <Descriptions.Item label="功率/当前液位">{detailRecord?.power || detailRecord?.currentLevel}</Descriptions.Item>
  836. <Descriptions.Item label="状态">{detailRecord?.status}</Descriptions.Item>
  837. </Descriptions>
  838. )
  839. case "waterlogging-points":
  840. return (
  841. <Descriptions title="易积水点详情" column={2} bordered>
  842. <Descriptions.Item label="点位编号">{detailRecord?.id}</Descriptions.Item>
  843. <Descriptions.Item label="点位名称">{detailRecord?.name}</Descriptions.Item>
  844. <Descriptions.Item label="位置">{detailRecord?.location}</Descriptions.Item>
  845. <Descriptions.Item label="风险等级">{detailRecord?.riskLevel}</Descriptions.Item>
  846. <Descriptions.Item label="历史最大积水深度">{detailRecord?.historicalDepth}</Descriptions.Item>
  847. <Descriptions.Item label="状态">{detailRecord?.status}</Descriptions.Item>
  848. </Descriptions>
  849. )
  850. case "monitoring-devices":
  851. return (
  852. <Descriptions title="监测设备详情" column={2} bordered>
  853. <Descriptions.Item label="设备编号">{detailRecord?.id}</Descriptions.Item>
  854. <Descriptions.Item label="设备名称">{detailRecord?.name}</Descriptions.Item>
  855. <Descriptions.Item label="设备类型">{detailRecord?.type}</Descriptions.Item>
  856. <Descriptions.Item label="安装位置">{detailRecord?.location}</Descriptions.Item>
  857. <Descriptions.Item label="安装日期">{detailRecord?.installDate}</Descriptions.Item>
  858. <Descriptions.Item label="最后维护">{detailRecord?.lastMaintenance}</Descriptions.Item>
  859. <Descriptions.Item label="状态">{detailRecord?.status}</Descriptions.Item>
  860. </Descriptions>
  861. )
  862. default:
  863. return null
  864. }
  865. }
  866. // 生成图表选项
  867. const generateChartOption = () => {
  868. switch (selectedTab) {
  869. case "drainage-areas":
  870. return {
  871. title: {
  872. text: '排水分区统计',
  873. left: 'center'
  874. },
  875. tooltip: {
  876. trigger: 'item'
  877. },
  878. legend: {
  879. orient: 'vertical',
  880. left: 'left'
  881. },
  882. series: [
  883. {
  884. name: '分区类型',
  885. type: 'pie',
  886. radius: '50%',
  887. data: [
  888. { value: drainageAreas.filter(item => item.type === '雨水分区').length, name: '雨水分区' },
  889. { value: drainageAreas.filter(item => item.type === '污水分区').length, name: '污水分区' }
  890. ],
  891. emphasis: {
  892. itemStyle: {
  893. shadowBlur: 10,
  894. shadowOffsetX: 0,
  895. shadowColor: 'rgba(0, 0, 0, 0.5)'
  896. }
  897. }
  898. }
  899. ]
  900. }
  901. case "pipeline-network":
  902. return {
  903. title: {
  904. text: '管网长度统计',
  905. left: 'center'
  906. },
  907. tooltip: {
  908. trigger: 'axis'
  909. },
  910. xAxis: {
  911. type: 'category',
  912. data: pipelineData.map(item => item.name)
  913. },
  914. yAxis: {
  915. type: 'value',
  916. name: '长度(km)'
  917. },
  918. series: [
  919. {
  920. data: pipelineData.map(item => parseFloat(item.length?.replace('km', '') || '0')),
  921. type: 'bar'
  922. }
  923. ]
  924. }
  925. case "engineering-facilities":
  926. return {
  927. title: {
  928. text: '设施状态统计',
  929. left: 'center'
  930. },
  931. tooltip: {
  932. trigger: 'item'
  933. },
  934. legend: {
  935. orient: 'vertical',
  936. left: 'left'
  937. },
  938. series: [
  939. {
  940. name: '设施状态',
  941. type: 'pie',
  942. radius: '50%',
  943. data: [
  944. { value: engineeringFacilities.filter(item => item.status === '运行中').length, name: '运行中' },
  945. { value: engineeringFacilities.filter(item => item.status === '待命').length, name: '待命' },
  946. { value: engineeringFacilities.filter(item => item.status === '维护中').length, name: '维护中' }
  947. ],
  948. emphasis: {
  949. itemStyle: {
  950. shadowBlur: 10,
  951. shadowOffsetX: 0,
  952. shadowColor: 'rgba(0, 0, 0, 0.5)'
  953. }
  954. }
  955. }
  956. ]
  957. }
  958. case "waterlogging-points":
  959. return {
  960. title: {
  961. text: '积水点风险等级统计',
  962. left: 'center'
  963. },
  964. tooltip: {
  965. trigger: 'axis'
  966. },
  967. xAxis: {
  968. type: 'category',
  969. data: ['高', '中', '低']
  970. },
  971. yAxis: {
  972. type: 'value',
  973. name: '数量(个)'
  974. },
  975. series: [
  976. {
  977. data: [
  978. waterloggingPoints.filter(item => item.riskLevel === '高').length,
  979. waterloggingPoints.filter(item => item.riskLevel === '中').length,
  980. waterloggingPoints.filter(item => item.riskLevel === '低').length
  981. ],
  982. type: 'bar',
  983. itemStyle: {
  984. color: (params: any) => {
  985. const colors = ['#ff4d4f', '#faad14', '#52c41a']
  986. return colors[params.dataIndex]
  987. }
  988. }
  989. }
  990. ]
  991. }
  992. case "monitoring-devices":
  993. return {
  994. title: {
  995. text: '设备状态统计',
  996. left: 'center'
  997. },
  998. tooltip: {
  999. trigger: 'item'
  1000. },
  1001. legend: {
  1002. orient: 'vertical',
  1003. left: 'left'
  1004. },
  1005. series: [
  1006. {
  1007. name: '设备状态',
  1008. type: 'pie',
  1009. radius: '50%',
  1010. data: [
  1011. { value: monitoringDevices.filter(item => item.status === '在线').length, name: '在线' },
  1012. { value: monitoringDevices.filter(item => item.status === '离线').length, name: '离线' },
  1013. { value: monitoringDevices.filter(item => item.status === '维护中').length, name: '维护中' }
  1014. ],
  1015. emphasis: {
  1016. itemStyle: {
  1017. shadowBlur: 10,
  1018. shadowOffsetX: 0,
  1019. shadowColor: 'rgba(0, 0, 0, 0.5)'
  1020. }
  1021. }
  1022. }
  1023. ]
  1024. }
  1025. default:
  1026. return {}
  1027. }
  1028. }
  1029. return (
  1030. <div className="space-y-6">
  1031. {/* 统计概览 */}
  1032. <Row gutter={[16, 16]}>
  1033. <Col span={6}>
  1034. <Card>
  1035. <Statistic title="排水分区" value={drainageAreas.length} suffix="个" />
  1036. </Card>
  1037. </Col>
  1038. <Col span={6}>
  1039. <Card>
  1040. <Statistic title="管网长度" value={pipelineData.reduce((sum, item) => {
  1041. const length = parseFloat(item.length?.replace('km', '') || '0')
  1042. return sum + length
  1043. }, 0).toFixed(1)} suffix="km" />
  1044. </Card>
  1045. </Col>
  1046. <Col span={6}>
  1047. <Card>
  1048. <Statistic title="工程设施" value={engineeringFacilities.length} suffix="座" />
  1049. </Card>
  1050. </Col>
  1051. <Col span={6}>
  1052. <Card>
  1053. <Statistic title="监测设备" value={monitoringDevices.length} suffix="台" />
  1054. </Card>
  1055. </Col>
  1056. </Row>
  1057. <Tabs activeKey={selectedTab} onChange={setSelectedTab}>
  1058. <TabPane tab="排水分区" key="drainage-areas">
  1059. <Row gutter={[16, 16]}>
  1060. <Col span={16}>{renderTabContent()}</Col>
  1061. <Col span={8}>
  1062. <Card title="分区统计图" className="h-96">
  1063. <EChart option={generateChartOption()} style={{ height: '20rem' }} />
  1064. </Card>
  1065. </Col>
  1066. </Row>
  1067. </TabPane>
  1068. <TabPane tab="管网设施" key="pipeline-network">
  1069. <Row gutter={[16, 16]}>
  1070. <Col span={16}>{renderTabContent()}</Col>
  1071. <Col span={8}>
  1072. <Card title="管网统计图" className="h-96">
  1073. <EChart option={generateChartOption()} style={{ height: '20rem' }} />
  1074. </Card>
  1075. </Col>
  1076. </Row>
  1077. </TabPane>
  1078. <TabPane tab="工程设施" key="engineering-facilities">
  1079. <Row gutter={[16, 16]}>
  1080. <Col span={16}>{renderTabContent()}</Col>
  1081. <Col span={8}>
  1082. <Card title="设施统计图" className="h-96">
  1083. <EChart option={generateChartOption()} style={{ height: '20rem' }} />
  1084. </Card>
  1085. </Col>
  1086. </Row>
  1087. </TabPane>
  1088. <TabPane tab="易积水点" key="waterlogging-points">
  1089. <Row gutter={[16, 16]}>
  1090. <Col span={16}>{renderTabContent()}</Col>
  1091. <Col span={8}>
  1092. <Card title="积水点统计图" className="h-96">
  1093. <EChart option={generateChartOption()} style={{ height: '20rem' }} />
  1094. </Card>
  1095. </Col>
  1096. </Row>
  1097. </TabPane>
  1098. <TabPane tab="监测设备" key="monitoring-devices">
  1099. {renderTabContent()}
  1100. </TabPane>
  1101. </Tabs>
  1102. {/* 编辑/新增模态框 */}
  1103. <Modal
  1104. title={editingRecord ? "编辑" : "新增"}
  1105. open={modalVisible}
  1106. onCancel={() => {
  1107. setModalVisible(false)
  1108. setEditingRecord(null)
  1109. form.resetFields()
  1110. }}
  1111. onOk={handleSave}
  1112. width={600}
  1113. >
  1114. <Form form={form} layout="vertical">
  1115. {getFormFields()}
  1116. </Form>
  1117. </Modal>
  1118. {/* 详情模态框 */}
  1119. <Modal
  1120. title="详情信息"
  1121. open={detailModalVisible}
  1122. onCancel={() => {
  1123. setDetailModalVisible(false)
  1124. setDetailRecord(null)
  1125. }}
  1126. onOk={() => {
  1127. setDetailModalVisible(false)
  1128. setDetailRecord(null)
  1129. }}
  1130. width={800}
  1131. >
  1132. {getDetailDescriptions()}
  1133. {selectedTab !== "monitoring-devices" && (
  1134. <div className="mt-6" style={{ height: 300 }}>
  1135. <EChart option={generateChartOption()} style={{ height: '20rem' }} />
  1136. </div>
  1137. )}
  1138. </Modal>
  1139. </div>
  1140. )
  1141. }