|
|
@@ -0,0 +1,483 @@
|
|
|
+"use client"
|
|
|
+
|
|
|
+import {useState} from "react"
|
|
|
+import {
|
|
|
+ Button,
|
|
|
+ Card,
|
|
|
+ Col,
|
|
|
+ DatePicker,
|
|
|
+ Descriptions,
|
|
|
+ Form,
|
|
|
+ Input,
|
|
|
+ Modal,
|
|
|
+ Popconfirm,
|
|
|
+ Progress,
|
|
|
+ Row,
|
|
|
+ Select,
|
|
|
+ Space,
|
|
|
+ Table,
|
|
|
+ Tag,
|
|
|
+} from "antd"
|
|
|
+import {DeleteOutlined, EditOutlined, EyeOutlined, PlusOutlined} from "@ant-design/icons"
|
|
|
+import {Radar} from "@ant-design/plots"
|
|
|
+import dayjs from "dayjs"
|
|
|
+import globalMessage from "@/app/_modules/globalMessage";
|
|
|
+
|
|
|
+const { Option } = Select
|
|
|
+const { TextArea } = Input
|
|
|
+
|
|
|
+// 模拟风险档案数据
|
|
|
+const mockRiskData = [
|
|
|
+ {
|
|
|
+ id: "R001",
|
|
|
+ title: "解放路段高压管线风险",
|
|
|
+ location: "解放路与建设路交叉口",
|
|
|
+ riskType: "管线老化",
|
|
|
+ riskLevel: "高",
|
|
|
+ riskScore: 85,
|
|
|
+ assessmentDate: "2024-01-15",
|
|
|
+ assessor: "张三",
|
|
|
+ status: "待处理",
|
|
|
+ description: "高压管线使用年限超过20年,存在老化风险",
|
|
|
+ impactArea: "500m范围内",
|
|
|
+ affectedPopulation: 2000,
|
|
|
+ economicLoss: 500000,
|
|
|
+ mitigationMeasures: "定期检测,制定更换计划",
|
|
|
+ monitoringFrequency: "每月",
|
|
|
+ lastUpdate: "2024-01-15",
|
|
|
+ factors: {
|
|
|
+ 管线状态: 80,
|
|
|
+ 环境因素: 70,
|
|
|
+ 人员密度: 90,
|
|
|
+ 设备完好性: 75,
|
|
|
+ 管理水平: 85,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: "R002",
|
|
|
+ title: "人民路段泄漏风险",
|
|
|
+ location: "人民路中段",
|
|
|
+ riskType: "泄漏隐患",
|
|
|
+ riskLevel: "中",
|
|
|
+ riskScore: 65,
|
|
|
+ assessmentDate: "2024-01-10",
|
|
|
+ assessor: "李四",
|
|
|
+ status: "监控中",
|
|
|
+ description: "管道接头处存在微量泄漏风险",
|
|
|
+ impactArea: "200m范围内",
|
|
|
+ affectedPopulation: 800,
|
|
|
+ economicLoss: 200000,
|
|
|
+ mitigationMeasures: "加强巡检,安装泄漏检测设备",
|
|
|
+ monitoringFrequency: "每周",
|
|
|
+ lastUpdate: "2024-01-12",
|
|
|
+ factors: {
|
|
|
+ 管线状态: 60,
|
|
|
+ 环境因素: 65,
|
|
|
+ 人员密度: 70,
|
|
|
+ 设备完好性: 80,
|
|
|
+ 管理水平: 75,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ {
|
|
|
+ id: "R003",
|
|
|
+ title: "建设路段压力风险",
|
|
|
+ location: "建设路北段",
|
|
|
+ riskType: "压力异常",
|
|
|
+ riskLevel: "低",
|
|
|
+ riskScore: 35,
|
|
|
+ assessmentDate: "2024-01-08",
|
|
|
+ assessor: "王五",
|
|
|
+ status: "已控制",
|
|
|
+ description: "调压设备运行正常,风险可控",
|
|
|
+ impactArea: "100m范围内",
|
|
|
+ affectedPopulation: 300,
|
|
|
+ economicLoss: 50000,
|
|
|
+ mitigationMeasures: "定期维护调压设备",
|
|
|
+ monitoringFrequency: "每季度",
|
|
|
+ lastUpdate: "2024-01-10",
|
|
|
+ factors: {
|
|
|
+ 管线状态: 40,
|
|
|
+ 环境因素: 35,
|
|
|
+ 人员密度: 30,
|
|
|
+ 设备完好性: 45,
|
|
|
+ 管理水平: 40,
|
|
|
+ },
|
|
|
+ },
|
|
|
+]
|
|
|
+
|
|
|
+export default function RiskArchive() {
|
|
|
+ const [isModalVisible, setIsModalVisible] = useState(false)
|
|
|
+ const [isDetailModalVisible, setIsDetailModalVisible] = useState(false)
|
|
|
+ const [editingRecord, setEditingRecord] = useState(null)
|
|
|
+ const [viewingRecord, setViewingRecord] = useState(null)
|
|
|
+ const [form] = Form.useForm()
|
|
|
+
|
|
|
+ const handleAdd = () => {
|
|
|
+ setEditingRecord(null)
|
|
|
+ form.resetFields()
|
|
|
+ setIsModalVisible(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleEdit = (record: any) => {
|
|
|
+ setEditingRecord(record)
|
|
|
+ form.setFieldsValue({
|
|
|
+ ...record,
|
|
|
+ assessmentDate: record.assessmentDate ? dayjs(record.assessmentDate) : null,
|
|
|
+ })
|
|
|
+ setIsModalVisible(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleView = (record: any) => {
|
|
|
+ setViewingRecord(record)
|
|
|
+ setIsDetailModalVisible(true)
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleDelete = (id: string) => {
|
|
|
+ globalMessage.success("删除成功")
|
|
|
+ }
|
|
|
+
|
|
|
+ const handleModalOk = () => {
|
|
|
+ form.validateFields().then((values) => {
|
|
|
+ if (editingRecord) {
|
|
|
+ globalMessage.success("更新成功")
|
|
|
+ } else {
|
|
|
+ globalMessage.success("添加成功")
|
|
|
+ }
|
|
|
+ setIsModalVisible(false)
|
|
|
+ form.resetFields()
|
|
|
+ })
|
|
|
+ }
|
|
|
+
|
|
|
+ const getRiskLevelColor = (level: string) => {
|
|
|
+ switch (level) {
|
|
|
+ case "高":
|
|
|
+ return "red"
|
|
|
+ case "中":
|
|
|
+ return "orange"
|
|
|
+ case "低":
|
|
|
+ return "blue"
|
|
|
+ default:
|
|
|
+ return "default"
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const getStatusColor = (status: string) => {
|
|
|
+ switch (status) {
|
|
|
+ case "待处理":
|
|
|
+ return "red"
|
|
|
+ case "监控中":
|
|
|
+ return "orange"
|
|
|
+ case "已控制":
|
|
|
+ return "green"
|
|
|
+ default:
|
|
|
+ return "default"
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ const getRiskScoreColor = (score: number) => {
|
|
|
+ if (score >= 80) return "#f5222d"
|
|
|
+ if (score >= 60) return "#faad14"
|
|
|
+ if (score >= 40) return "#52c41a"
|
|
|
+ return "#1890ff"
|
|
|
+ }
|
|
|
+
|
|
|
+ const columns = [
|
|
|
+ { title: "风险编号", dataIndex: "id", key: "id", width: 100 },
|
|
|
+ { title: "风险标题", dataIndex: "title", key: "title", width: 200 },
|
|
|
+ { title: "位置", dataIndex: "location", key: "location", width: 150 },
|
|
|
+ { title: "风险类型", dataIndex: "riskType", key: "riskType", width: 120 },
|
|
|
+ {
|
|
|
+ title: "风险等级",
|
|
|
+ dataIndex: "riskLevel",
|
|
|
+ key: "riskLevel",
|
|
|
+ width: 100,
|
|
|
+ render: (level: string) => <Tag color={getRiskLevelColor(level)}>{level}</Tag>,
|
|
|
+ },
|
|
|
+ {
|
|
|
+ title: "风险评分",
|
|
|
+ dataIndex: "riskScore",
|
|
|
+ key: "riskScore",
|
|
|
+ width: 120,
|
|
|
+ render: (score: number) => (
|
|
|
+ <div>
|
|
|
+ <Progress
|
|
|
+ percent={score}
|
|
|
+ size="small"
|
|
|
+ strokeColor={getRiskScoreColor(score)}
|
|
|
+ format={(percent) => `${percent}`}
|
|
|
+ />
|
|
|
+ </div>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ { title: "评估日期", dataIndex: "assessmentDate", key: "assessmentDate", width: 120 },
|
|
|
+ { title: "评估人", dataIndex: "assessor", key: "assessor", width: 100 },
|
|
|
+ {
|
|
|
+ title: "状态",
|
|
|
+ dataIndex: "status",
|
|
|
+ key: "status",
|
|
|
+ width: 100,
|
|
|
+ render: (status: string) => <Tag color={getStatusColor(status)}>{status}</Tag>,
|
|
|
+ },
|
|
|
+ { title: "影响人口", dataIndex: "affectedPopulation", key: "affectedPopulation", width: 100 },
|
|
|
+ {
|
|
|
+ title: "操作",
|
|
|
+ key: "action",
|
|
|
+ width: 200,
|
|
|
+ fixed: "right",
|
|
|
+ render: (_, record) => (
|
|
|
+ <Space>
|
|
|
+ <Button type="link" icon={<EyeOutlined />} onClick={() => handleView(record)}>
|
|
|
+ 查看
|
|
|
+ </Button>
|
|
|
+ <Button type="link" icon={<EditOutlined />} onClick={() => handleEdit(record)}>
|
|
|
+ 编辑
|
|
|
+ </Button>
|
|
|
+ <Popconfirm title="确定删除吗?" onConfirm={() => handleDelete(record.id)}>
|
|
|
+ <Button type="link" danger icon={<DeleteOutlined />}>
|
|
|
+ 删除
|
|
|
+ </Button>
|
|
|
+ </Popconfirm>
|
|
|
+ </Space>
|
|
|
+ ),
|
|
|
+ },
|
|
|
+ ]
|
|
|
+
|
|
|
+ const radarConfig = viewingRecord
|
|
|
+ ? {
|
|
|
+ data: Object.entries(viewingRecord.factors).map(([key, value]) => ({
|
|
|
+ factor: key,
|
|
|
+ value: value,
|
|
|
+ })),
|
|
|
+ xField: "factor",
|
|
|
+ yField: "value",
|
|
|
+ area: {
|
|
|
+ style: {
|
|
|
+ fill: getRiskScoreColor(viewingRecord.riskScore),
|
|
|
+ fillOpacity: 0.3,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ point: {
|
|
|
+ size: 3,
|
|
|
+ },
|
|
|
+ line: {
|
|
|
+ style: {
|
|
|
+ stroke: getRiskScoreColor(viewingRecord.riskScore),
|
|
|
+ lineWidth: 2,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ }
|
|
|
+ : null
|
|
|
+
|
|
|
+ const highRiskCount = mockRiskData.filter((item) => item.riskLevel === "高").length
|
|
|
+ const mediumRiskCount = mockRiskData.filter((item) => item.riskLevel === "中").length
|
|
|
+ const lowRiskCount = mockRiskData.filter((item) => item.riskLevel === "低").length
|
|
|
+
|
|
|
+ return (
|
|
|
+ <div className="p-6">
|
|
|
+ <Card title="风险档案管理">
|
|
|
+ {/* 风险概览 */}
|
|
|
+ <Row gutter={16} className="mb-6">
|
|
|
+ <Col span={6}>
|
|
|
+ <Card size="small">
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="text-2xl font-bold text-red-600">{highRiskCount}</div>
|
|
|
+ <div className="text-gray-600">高风险</div>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ <Col span={6}>
|
|
|
+ <Card size="small">
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="text-2xl font-bold text-orange-600">{mediumRiskCount}</div>
|
|
|
+ <div className="text-gray-600">中风险</div>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ <Col span={6}>
|
|
|
+ <Card size="small">
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="text-2xl font-bold text-blue-600">{lowRiskCount}</div>
|
|
|
+ <div className="text-gray-600">低风险</div>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ <Col span={6}>
|
|
|
+ <Card size="small">
|
|
|
+ <div className="text-center">
|
|
|
+ <div className="text-2xl font-bold text-gray-600">{mockRiskData.length}</div>
|
|
|
+ <div className="text-gray-600">风险总数</div>
|
|
|
+ </div>
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+
|
|
|
+ {/* 筛选控件 */}
|
|
|
+ <div className="mb-4">
|
|
|
+ <Space>
|
|
|
+ <Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
|
|
|
+ 新增风险
|
|
|
+ </Button>
|
|
|
+ <Input.Search placeholder="搜索风险..." style={{ width: 300 }} />
|
|
|
+ <Select placeholder="风险类型" style={{ width: 120 }}>
|
|
|
+ <Option value="aging">管线老化</Option>
|
|
|
+ <Option value="leak">泄漏隐患</Option>
|
|
|
+ <Option value="pressure">压力异常</Option>
|
|
|
+ <Option value="other">其他</Option>
|
|
|
+ </Select>
|
|
|
+ <Select placeholder="风险等级" style={{ width: 120 }}>
|
|
|
+ <Option value="high">高</Option>
|
|
|
+ <Option value="medium">中</Option>
|
|
|
+ <Option value="low">低</Option>
|
|
|
+ </Select>
|
|
|
+ <Select placeholder="状态" style={{ width: 120 }}>
|
|
|
+ <Option value="pending">待处理</Option>
|
|
|
+ <Option value="monitoring">监控中</Option>
|
|
|
+ <Option value="controlled">已控制</Option>
|
|
|
+ </Select>
|
|
|
+ </Space>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ {/* 风险列表 */}
|
|
|
+ <Table
|
|
|
+ columns={columns}
|
|
|
+ dataSource={mockRiskData}
|
|
|
+ rowKey="id"
|
|
|
+ pagination={{ pageSize: 10 }}
|
|
|
+ scroll={{ x: 1400 }}
|
|
|
+ />
|
|
|
+
|
|
|
+ {/* 编辑/新增模态框 */}
|
|
|
+ <Modal
|
|
|
+ title={editingRecord ? "编辑风险" : "新增风险"}
|
|
|
+ open={isModalVisible}
|
|
|
+ onOk={handleModalOk}
|
|
|
+ onCancel={() => setIsModalVisible(false)}
|
|
|
+ width={800}
|
|
|
+ >
|
|
|
+ <Form form={form} layout="vertical">
|
|
|
+ <Row gutter={16}>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="title" label="风险标题" rules={[{ required: true }]}>
|
|
|
+ <Input />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="location" label="位置" rules={[{ required: true }]}>
|
|
|
+ <Input />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Row gutter={16}>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="riskType" label="风险类型" rules={[{ required: true }]}>
|
|
|
+ <Select>
|
|
|
+ <Option value="管线老化">管线老化</Option>
|
|
|
+ <Option value="泄漏隐患">泄漏隐患</Option>
|
|
|
+ <Option value="压力异常">压力异常</Option>
|
|
|
+ <Option value="其他">其他</Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="riskLevel" label="风险等级" rules={[{ required: true }]}>
|
|
|
+ <Select>
|
|
|
+ <Option value="高">高</Option>
|
|
|
+ <Option value="中">中</Option>
|
|
|
+ <Option value="低">低</Option>
|
|
|
+ </Select>
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Row gutter={16}>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="riskScore" label="风险评分" rules={[{ required: true }]}>
|
|
|
+ <Input type="number" min={0} max={100} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="assessmentDate" label="评估日期" rules={[{ required: true }]}>
|
|
|
+ <DatePicker style={{ width: "100%" }} />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Form.Item name="description" label="风险描述" rules={[{ required: true }]}>
|
|
|
+ <TextArea rows={3} />
|
|
|
+ </Form.Item>
|
|
|
+ <Row gutter={16}>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="affectedPopulation" label="影响人口" rules={[{ required: true }]}>
|
|
|
+ <Input type="number" />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ <Col span={12}>
|
|
|
+ <Form.Item name="economicLoss" label="潜在经济损失" rules={[{ required: true }]}>
|
|
|
+ <Input type="number" />
|
|
|
+ </Form.Item>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ <Form.Item name="mitigationMeasures" label="缓解措施">
|
|
|
+ <TextArea rows={3} />
|
|
|
+ </Form.Item>
|
|
|
+ </Form>
|
|
|
+ </Modal>
|
|
|
+
|
|
|
+ {/* 详情查看模态框 */}
|
|
|
+ <Modal
|
|
|
+ title="风险详情"
|
|
|
+ open={isDetailModalVisible}
|
|
|
+ onCancel={() => setIsDetailModalVisible(false)}
|
|
|
+ footer={[
|
|
|
+ <Button key="close" onClick={() => setIsDetailModalVisible(false)}>
|
|
|
+ 关闭
|
|
|
+ </Button>,
|
|
|
+ ]}
|
|
|
+ width={1000}
|
|
|
+ >
|
|
|
+ {viewingRecord && (
|
|
|
+ <Row gutter={16}>
|
|
|
+ <Col span={14}>
|
|
|
+ <Descriptions column={2} bordered>
|
|
|
+ <Descriptions.Item label="风险编号">{viewingRecord.id}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="风险标题">{viewingRecord.title}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="位置">{viewingRecord.location}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="风险类型">{viewingRecord.riskType}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="风险等级">
|
|
|
+ <Tag color={getRiskLevelColor(viewingRecord.riskLevel)}>{viewingRecord.riskLevel}</Tag>
|
|
|
+ </Descriptions.Item>
|
|
|
+ <Descriptions.Item label="风险评分">
|
|
|
+ <Progress
|
|
|
+ percent={viewingRecord.riskScore}
|
|
|
+ size="small"
|
|
|
+ strokeColor={getRiskScoreColor(viewingRecord.riskScore)}
|
|
|
+ />
|
|
|
+ </Descriptions.Item>
|
|
|
+ <Descriptions.Item label="评估日期">{viewingRecord.assessmentDate}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="评估人">{viewingRecord.assessor}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="影响范围">{viewingRecord.impactArea}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="影响人口">{viewingRecord.affectedPopulation}人</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="潜在损失">¥{viewingRecord.economicLoss.toLocaleString()}</Descriptions.Item>
|
|
|
+ <Descriptions.Item label="监测频率">{viewingRecord.monitoringFrequency}</Descriptions.Item>
|
|
|
+ </Descriptions>
|
|
|
+
|
|
|
+ <div className="mt-4">
|
|
|
+ <h4 className="font-medium mb-2">风险描述</h4>
|
|
|
+ <div className="p-3 bg-gray-50 rounded">{viewingRecord.description}</div>
|
|
|
+ </div>
|
|
|
+
|
|
|
+ <div className="mt-4">
|
|
|
+ <h4 className="font-medium mb-2">缓解措施</h4>
|
|
|
+ <div className="p-3 bg-blue-50 rounded">{viewingRecord.mitigationMeasures}</div>
|
|
|
+ </div>
|
|
|
+ </Col>
|
|
|
+ <Col span={10}>
|
|
|
+ <Card title="风险因子分析" size="small">
|
|
|
+ {radarConfig && <Radar {...radarConfig} height={300} />}
|
|
|
+ </Card>
|
|
|
+ </Col>
|
|
|
+ </Row>
|
|
|
+ )}
|
|
|
+ </Modal>
|
|
|
+ </Card>
|
|
|
+ </div>
|
|
|
+ )
|
|
|
+}
|