hazard-archive.tsx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431
  1. "use client"
  2. import {useState} from "react"
  3. import {Button, Card, Col, DatePicker, Form, Input, Modal, Popconfirm, Row, Select, Space, Table, Tag,} from "antd"
  4. import {DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined} from "@ant-design/icons"
  5. import dayjs from "dayjs"
  6. import globalMessage from "@/app/_modules/globalMessage";
  7. const { Option } = Select
  8. const { TextArea } = Input
  9. // 模拟隐患数据
  10. const mockHazardData = [
  11. {
  12. id: "H001",
  13. title: "解放路段管线压力异常",
  14. type: "压力异常",
  15. level: "高",
  16. location: "解放路与建设路交叉口",
  17. description: "管线压力超出正常范围,存在安全隐患",
  18. reportDate: "2024-01-15",
  19. reportPerson: "张三",
  20. status: "处理中",
  21. assignedTo: "李四",
  22. expectedDate: "2024-02-15",
  23. actualDate: null,
  24. treatmentPlan: "更换老化管段,加强压力监测",
  25. progress: 60,
  26. },
  27. {
  28. id: "H002",
  29. name: "人民路窨井盖损坏",
  30. type: "设施损坏",
  31. level: "中",
  32. location: "人民路中段",
  33. description: "窨井盖出现裂纹,影响安全",
  34. reportDate: "2024-01-20",
  35. reportPerson: "王五",
  36. status: "已完成",
  37. assignedTo: "赵六",
  38. expectedDate: "2024-01-25",
  39. actualDate: "2024-01-24",
  40. treatmentPlan: "更换新井盖",
  41. progress: 100,
  42. },
  43. {
  44. id: "H003",
  45. name: "建设路段泄漏检测",
  46. type: "泄漏隐患",
  47. level: "高",
  48. location: "建设路北段",
  49. description: "检测到微量燃气泄漏",
  50. reportDate: "2024-01-25",
  51. reportPerson: "孙七",
  52. status: "待处理",
  53. assignedTo: null,
  54. expectedDate: "2024-02-10",
  55. actualDate: null,
  56. treatmentPlan: "待制定",
  57. progress: 0,
  58. },
  59. ]
  60. export default function HazardArchive() {
  61. const [isModalVisible, setIsModalVisible] = useState(false)
  62. const [isDetailModalVisible, setIsDetailModalVisible] = useState(false)
  63. const [editingRecord, setEditingRecord] = useState(null)
  64. const [viewingRecord, setViewingRecord] = useState(null)
  65. const [form] = Form.useForm()
  66. const handleAdd = () => {
  67. setEditingRecord(null)
  68. form.resetFields()
  69. setIsModalVisible(true)
  70. }
  71. const handleEdit = (record: any) => {
  72. setEditingRecord(record)
  73. form.setFieldsValue({
  74. ...record,
  75. reportDate: record.reportDate ? dayjs(record.reportDate) : null,
  76. expectedDate: record.expectedDate ? dayjs(record.expectedDate) : null,
  77. actualDate: record.actualDate ? dayjs(record.actualDate) : null,
  78. })
  79. setIsModalVisible(true)
  80. }
  81. const handleView = (record: any) => {
  82. setViewingRecord(record)
  83. setIsDetailModalVisible(true)
  84. }
  85. const handleDelete = (id: string) => {
  86. globalMessage.success("删除成功")
  87. }
  88. const handleModalOk = () => {
  89. form.validateFields().then((values) => {
  90. if (editingRecord) {
  91. globalMessage.success("更新成功")
  92. } else {
  93. globalMessage.success("添加成功")
  94. }
  95. setIsModalVisible(false)
  96. form.resetFields()
  97. })
  98. }
  99. const columns = [
  100. { title: "隐患编号", dataIndex: "id", key: "id", width: 100 },
  101. { title: "隐患标题", dataIndex: "title", key: "title", width: 200 },
  102. { title: "隐患类型", dataIndex: "type", key: "type", width: 120 },
  103. {
  104. title: "风险等级",
  105. dataIndex: "level",
  106. key: "level",
  107. width: 100,
  108. render: (level: string) => {
  109. const colorMap = { 高: "red", 中: "orange", 低: "green" }
  110. return <Tag color={colorMap[level as keyof typeof colorMap]}>{level}</Tag>
  111. },
  112. },
  113. { title: "位置", dataIndex: "location", key: "location", width: 150 },
  114. { title: "上报日期", dataIndex: "reportDate", key: "reportDate", width: 120 },
  115. { title: "上报人", dataIndex: "reportPerson", key: "reportPerson", width: 100 },
  116. {
  117. title: "处理状态",
  118. dataIndex: "status",
  119. key: "status",
  120. width: 100,
  121. render: (status: string) => {
  122. const colorMap = {
  123. 待处理: "default",
  124. 处理中: "processing",
  125. 已完成: "success",
  126. 已关闭: "error",
  127. }
  128. return <Tag color={colorMap[status as keyof typeof colorMap]}>{status}</Tag>
  129. },
  130. },
  131. { title: "负责人", dataIndex: "assignedTo", key: "assignedTo", width: 100 },
  132. {
  133. title: "进度",
  134. dataIndex: "progress",
  135. key: "progress",
  136. width: 80,
  137. render: (progress: number) => `${progress}%`,
  138. },
  139. {
  140. title: "操作",
  141. key: "action",
  142. width: 200,
  143. fixed: "right",
  144. render: (_, record) => (
  145. <Space>
  146. <Button type="link" icon={<EyeOutlined />} onClick={() => handleView(record)}>
  147. 查看
  148. </Button>
  149. <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
  150. 编辑
  151. </Button>
  152. <Popconfirm title="确定删除吗?" onConfirm={() => handleDelete(record.id)}>
  153. <Button type="link" danger icon={<DeleteOutlined />}>
  154. 删除
  155. </Button>
  156. </Popconfirm>
  157. </Space>
  158. ),
  159. },
  160. ]
  161. return (
  162. <div className="p-6">
  163. <Card title="隐患台账管理">
  164. <Row gutter={16} className="mb-4">
  165. <Col span={6}>
  166. <Card size="small">
  167. <div className="text-center">
  168. <div className="text-2xl font-bold text-blue-600">156</div>
  169. <div className="text-gray-600">隐患总数</div>
  170. </div>
  171. </Card>
  172. </Col>
  173. <Col span={6}>
  174. <Card size="small">
  175. <div className="text-center">
  176. <div className="text-2xl font-bold text-red-600">23</div>
  177. <div className="text-gray-600">待处理</div>
  178. </div>
  179. </Card>
  180. </Col>
  181. <Col span={6}>
  182. <Card size="small">
  183. <div className="text-center">
  184. <div className="text-2xl font-bold text-orange-600">45</div>
  185. <div className="text-gray-600">处理中</div>
  186. </div>
  187. </Card>
  188. </Col>
  189. <Col span={6}>
  190. <Card size="small">
  191. <div className="text-center">
  192. <div className="text-2xl font-bold text-green-600">88</div>
  193. <div className="text-gray-600">已完成</div>
  194. </div>
  195. </Card>
  196. </Col>
  197. </Row>
  198. <div className="mb-4">
  199. <Space>
  200. <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
  201. 新增隐患
  202. </Button>
  203. <Input.Search placeholder="搜索隐患..." style={{ width: 300 }} />
  204. <Select placeholder="隐患类型" style={{ width: 120 }}>
  205. <Option value="pressure">压力异常</Option>
  206. <Option value="leak">泄漏隐患</Option>
  207. <Option value="damage">设施损坏</Option>
  208. <Option value="other">其他</Option>
  209. </Select>
  210. <Select placeholder="处理状态" style={{ width: 120 }}>
  211. <Option value="pending">待处理</Option>
  212. <Option value="processing">处理中</Option>
  213. <Option value="completed">已完成</Option>
  214. </Select>
  215. </Space>
  216. </div>
  217. <Table
  218. columns={columns}
  219. dataSource={mockHazardData}
  220. rowKey="id"
  221. pagination={{ pageSize: 10 }}
  222. scroll={{ x: 1400 }}
  223. />
  224. {/* 编辑/新增模态框 */}
  225. <Modal
  226. title={editingRecord ? "编辑隐患" : "新增隐患"}
  227. open={isModalVisible}
  228. onOk={handleModalOk}
  229. onCancel={() => setIsModalVisible(false)}
  230. width={800}
  231. >
  232. <Form form={form} layout="vertical">
  233. <Row gutter={16}>
  234. <Col span={12}>
  235. <Form.Item name="title" label="隐患标题" rules={[{ required: true }]}>
  236. <Input />
  237. </Form.Item>
  238. </Col>
  239. <Col span={12}>
  240. <Form.Item name="type" label="隐患类型" rules={[{ required: true }]}>
  241. <Select>
  242. <Option value="压力异常">压力异常</Option>
  243. <Option value="泄漏隐患">泄漏隐患</Option>
  244. <Option value="设施损坏">设施损坏</Option>
  245. <Option value="其他">其他</Option>
  246. </Select>
  247. </Form.Item>
  248. </Col>
  249. </Row>
  250. <Row gutter={16}>
  251. <Col span={12}>
  252. <Form.Item name="level" label="风险等级" rules={[{ required: true }]}>
  253. <Select>
  254. <Option value="高">高</Option>
  255. <Option value="中">中</Option>
  256. <Option value="低">低</Option>
  257. </Select>
  258. </Form.Item>
  259. </Col>
  260. <Col span={12}>
  261. <Form.Item name="location" label="位置" rules={[{ required: true }]}>
  262. <Input />
  263. </Form.Item>
  264. </Col>
  265. </Row>
  266. <Form.Item name="description" label="隐患描述" rules={[{ required: true }]}>
  267. <TextArea rows={3} />
  268. </Form.Item>
  269. <Row gutter={16}>
  270. <Col span={8}>
  271. <Form.Item name="reportDate" label="上报日期" rules={[{ required: true }]}>
  272. <DatePicker style={{ width: "100%" }} />
  273. </Form.Item>
  274. </Col>
  275. <Col span={8}>
  276. <Form.Item name="reportPerson" label="上报人" rules={[{ required: true }]}>
  277. <Input />
  278. </Form.Item>
  279. </Col>
  280. <Col span={8}>
  281. <Form.Item name="assignedTo" label="负责人">
  282. <Input />
  283. </Form.Item>
  284. </Col>
  285. </Row>
  286. <Row gutter={16}>
  287. <Col span={12}>
  288. <Form.Item name="expectedDate" label="预期完成日期">
  289. <DatePicker style={{ width: "100%" }} />
  290. </Form.Item>
  291. </Col>
  292. <Col span={12}>
  293. <Form.Item name="status" label="处理状态" rules={[{ required: true }]}>
  294. <Select>
  295. <Option value="待处理">待处理</Option>
  296. <Option value="处理中">处理中</Option>
  297. <Option value="已完成">已完成</Option>
  298. <Option value="已关闭">已关闭</Option>
  299. </Select>
  300. </Form.Item>
  301. </Col>
  302. </Row>
  303. <Form.Item name="treatmentPlan" label="治理方案">
  304. <TextArea rows={3} />
  305. </Form.Item>
  306. </Form>
  307. </Modal>
  308. {/* 详情查看模态框 */}
  309. <Modal
  310. title="隐患详情"
  311. open={isDetailModalVisible}
  312. onCancel={() => setIsDetailModalVisible(false)}
  313. footer={[
  314. <Button key="close" onClick={() => setIsDetailModalVisible(false)}>
  315. 关闭
  316. </Button>,
  317. ]}
  318. width={800}
  319. >
  320. {viewingRecord && (
  321. <div className="space-y-4">
  322. <Row gutter={16}>
  323. <Col span={12}>
  324. <div>
  325. <strong>隐患编号:</strong>
  326. {viewingRecord.id}
  327. </div>
  328. </Col>
  329. <Col span={12}>
  330. <div>
  331. <strong>隐患标题:</strong>
  332. {viewingRecord.title}
  333. </div>
  334. </Col>
  335. </Row>
  336. <Row gutter={16}>
  337. <Col span={12}>
  338. <div>
  339. <strong>隐患类型:</strong>
  340. {viewingRecord.type}
  341. </div>
  342. </Col>
  343. <Col span={12}>
  344. <div>
  345. <strong>风险等级:</strong>
  346. <Tag
  347. color={viewingRecord.level === "高" ? "red" : viewingRecord.level === "中" ? "orange" : "green"}
  348. >
  349. {viewingRecord.level}
  350. </Tag>
  351. </div>
  352. </Col>
  353. </Row>
  354. <div>
  355. <strong>位置:</strong>
  356. {viewingRecord.location}
  357. </div>
  358. <div>
  359. <strong>隐患描述:</strong>
  360. <div className="mt-2 p-3 bg-gray-50 rounded">{viewingRecord.description}</div>
  361. </div>
  362. <Row gutter={16}>
  363. <Col span={12}>
  364. <div>
  365. <strong>上报日期:</strong>
  366. {viewingRecord.reportDate}
  367. </div>
  368. </Col>
  369. <Col span={12}>
  370. <div>
  371. <strong>上报人:</strong>
  372. {viewingRecord.reportPerson}
  373. </div>
  374. </Col>
  375. </Row>
  376. <Row gutter={16}>
  377. <Col span={12}>
  378. <div>
  379. <strong>处理状态:</strong>
  380. <Tag
  381. color={
  382. viewingRecord.status === "待处理"
  383. ? "default"
  384. : viewingRecord.status === "处理中"
  385. ? "processing"
  386. : viewingRecord.status === "已完成"
  387. ? "success"
  388. : "error"
  389. }
  390. >
  391. {viewingRecord.status}
  392. </Tag>
  393. </div>
  394. </Col>
  395. <Col span={12}>
  396. <div>
  397. <strong>负责人:</strong>
  398. {viewingRecord.assignedTo || "未分配"}
  399. </div>
  400. </Col>
  401. </Row>
  402. <div>
  403. <strong>治理方案:</strong>
  404. <div className="mt-2 p-3 bg-gray-50 rounded">{viewingRecord.treatmentPlan}</div>
  405. </div>
  406. <div>
  407. <strong>处理进度:</strong>
  408. <span className="ml-2">{viewingRecord.progress}%</span>
  409. </div>
  410. </div>
  411. )}
  412. </Modal>
  413. </Card>
  414. </div>
  415. )
  416. }