|
|
import React, { useState, useEffect } from 'react';
|
|
|
import { Card, Table, Button, Modal, Form, Input, Select, message, Space, Tag, Rate, Progress } from 'antd';
|
|
|
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, ExclamationCircleOutlined } from '@ant-design/icons';
|
|
|
import './RiskAssessment.less';
|
|
|
|
|
|
const { Option } = Select;
|
|
|
|
|
|
const RiskAssessment = () => {
|
|
|
const [form] = Form.useForm();
|
|
|
const [dataSource, setDataSource] = useState([]);
|
|
|
const [loading, setLoading] = useState(false);
|
|
|
const [modalVisible, setModalVisible] = useState(false);
|
|
|
const [editingRecord, setEditingRecord] = useState(null);
|
|
|
const [pagination, setPagination] = useState({
|
|
|
current: 1,
|
|
|
pageSize: 10,
|
|
|
total: 0,
|
|
|
});
|
|
|
|
|
|
// 模拟数据
|
|
|
const mockData = [
|
|
|
{
|
|
|
id: 1,
|
|
|
riskName: '化学品泄漏风险',
|
|
|
riskType: '环境风险',
|
|
|
riskLevel: '高',
|
|
|
probability: 4,
|
|
|
impact: 5,
|
|
|
riskScore: 20,
|
|
|
assessor: '张三',
|
|
|
assessDate: '2024-01-15',
|
|
|
status: '待处理',
|
|
|
description: '生产过程中化学品可能发生泄漏,造成环境污染',
|
|
|
controlMeasures: '加强设备维护,安装泄漏检测装置',
|
|
|
},
|
|
|
{
|
|
|
id: 2,
|
|
|
riskName: '设备故障风险',
|
|
|
riskType: '设备风险',
|
|
|
riskLevel: '中',
|
|
|
probability: 3,
|
|
|
impact: 3,
|
|
|
riskScore: 9,
|
|
|
assessor: '李四',
|
|
|
assessDate: '2024-01-10',
|
|
|
status: '已处理',
|
|
|
description: '关键设备可能发生故障,影响生产安全',
|
|
|
controlMeasures: '定期维护保养,建立备件库存',
|
|
|
},
|
|
|
{
|
|
|
id: 3,
|
|
|
riskName: '人员操作风险',
|
|
|
riskType: '人员风险',
|
|
|
riskLevel: '低',
|
|
|
probability: 2,
|
|
|
impact: 2,
|
|
|
riskScore: 4,
|
|
|
assessor: '王五',
|
|
|
assessDate: '2024-01-08',
|
|
|
status: '监控中',
|
|
|
description: '操作人员误操作可能导致安全事故',
|
|
|
controlMeasures: '加强培训,完善操作规程',
|
|
|
},
|
|
|
];
|
|
|
|
|
|
useEffect(() => {
|
|
|
fetchData();
|
|
|
}, [pagination.current, pagination.pageSize]);
|
|
|
|
|
|
const fetchData = async () => {
|
|
|
setLoading(true);
|
|
|
try {
|
|
|
// 模拟API调用
|
|
|
setTimeout(() => {
|
|
|
setDataSource(mockData);
|
|
|
setPagination(prev => ({ ...prev, total: mockData.length }));
|
|
|
setLoading(false);
|
|
|
}, 500);
|
|
|
} catch (error) {
|
|
|
message.error('获取数据失败');
|
|
|
setLoading(false);
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const handleAdd = () => {
|
|
|
setEditingRecord(null);
|
|
|
form.resetFields();
|
|
|
setModalVisible(true);
|
|
|
};
|
|
|
|
|
|
const handleEdit = (record) => {
|
|
|
setEditingRecord(record);
|
|
|
form.setFieldsValue(record);
|
|
|
setModalVisible(true);
|
|
|
};
|
|
|
|
|
|
const handleDelete = (record) => {
|
|
|
Modal.confirm({
|
|
|
title: '确认删除',
|
|
|
content: `确定要删除风险评估"${record.riskName}"吗?`,
|
|
|
onOk: () => {
|
|
|
setDataSource(dataSource.filter(item => item.id !== record.id));
|
|
|
message.success('删除成功');
|
|
|
},
|
|
|
});
|
|
|
};
|
|
|
|
|
|
const handleView = (record) => {
|
|
|
Modal.info({
|
|
|
title: '查看风险评估详情',
|
|
|
content: (
|
|
|
<div>
|
|
|
<p><strong>风险名称:</strong>{record.riskName}</p>
|
|
|
<p><strong>风险类型:</strong>{record.riskType}</p>
|
|
|
<p><strong>风险等级:</strong>
|
|
|
<Tag color={record.riskLevel === '高' ? 'red' : record.riskLevel === '中' ? 'orange' : 'green'}>
|
|
|
{record.riskLevel}
|
|
|
</Tag>
|
|
|
</p>
|
|
|
<p><strong>发生概率:</strong>
|
|
|
<Rate disabled value={record.probability} />
|
|
|
<span style={{ marginLeft: 8 }}>({record.probability}/5)</span>
|
|
|
</p>
|
|
|
<p><strong>影响程度:</strong>
|
|
|
<Rate disabled value={record.impact} />
|
|
|
<span style={{ marginLeft: 8 }}>({record.impact}/5)</span>
|
|
|
</p>
|
|
|
<p><strong>风险评分:</strong>{record.riskScore}</p>
|
|
|
<p><strong>评估人:</strong>{record.assessor}</p>
|
|
|
<p><strong>评估日期:</strong>{record.assessDate}</p>
|
|
|
<p><strong>处理状态:</strong>
|
|
|
<Tag color={record.status === '已处理' ? 'green' : record.status === '待处理' ? 'red' : 'blue'}>
|
|
|
{record.status}
|
|
|
</Tag>
|
|
|
</p>
|
|
|
<p><strong>风险描述:</strong>{record.description}</p>
|
|
|
<p><strong>控制措施:</strong>{record.controlMeasures}</p>
|
|
|
</div>
|
|
|
),
|
|
|
width: 700,
|
|
|
});
|
|
|
};
|
|
|
|
|
|
const handleSubmit = async (values) => {
|
|
|
try {
|
|
|
const riskScore = values.probability * values.impact;
|
|
|
const riskLevel = riskScore >= 16 ? '高' : riskScore >= 9 ? '中' : '低';
|
|
|
|
|
|
const formData = {
|
|
|
...values,
|
|
|
riskScore,
|
|
|
riskLevel,
|
|
|
};
|
|
|
|
|
|
if (editingRecord) {
|
|
|
// 编辑
|
|
|
setDataSource(dataSource.map(item =>
|
|
|
item.id === editingRecord.id ? { ...item, ...formData } : item
|
|
|
));
|
|
|
message.success('编辑成功');
|
|
|
} else {
|
|
|
// 新增
|
|
|
const newRecord = {
|
|
|
id: Date.now(),
|
|
|
...formData,
|
|
|
assessor: '当前用户',
|
|
|
assessDate: new Date().toISOString().split('T')[0],
|
|
|
status: '待处理',
|
|
|
};
|
|
|
setDataSource([...dataSource, newRecord]);
|
|
|
message.success('添加成功');
|
|
|
}
|
|
|
setModalVisible(false);
|
|
|
form.resetFields();
|
|
|
} catch (error) {
|
|
|
message.error('操作失败');
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const getRiskLevelColor = (level) => {
|
|
|
switch (level) {
|
|
|
case '高': return 'red';
|
|
|
case '中': return 'orange';
|
|
|
case '低': return 'green';
|
|
|
default: return 'default';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const getStatusColor = (status) => {
|
|
|
switch (status) {
|
|
|
case '已处理': return 'green';
|
|
|
case '待处理': return 'red';
|
|
|
case '监控中': return 'blue';
|
|
|
default: return 'default';
|
|
|
}
|
|
|
};
|
|
|
|
|
|
const columns = [
|
|
|
{
|
|
|
title: '风险名称',
|
|
|
dataIndex: 'riskName',
|
|
|
key: 'riskName',
|
|
|
width: 150,
|
|
|
},
|
|
|
{
|
|
|
title: '风险类型',
|
|
|
dataIndex: 'riskType',
|
|
|
key: 'riskType',
|
|
|
width: 120,
|
|
|
},
|
|
|
{
|
|
|
title: '风险等级',
|
|
|
dataIndex: 'riskLevel',
|
|
|
key: 'riskLevel',
|
|
|
width: 100,
|
|
|
render: (level) => (
|
|
|
<Tag color={getRiskLevelColor(level)}>
|
|
|
{level}
|
|
|
</Tag>
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
title: '风险评分',
|
|
|
dataIndex: 'riskScore',
|
|
|
key: 'riskScore',
|
|
|
width: 100,
|
|
|
render: (score) => (
|
|
|
<div>
|
|
|
<Progress
|
|
|
percent={(score / 25) * 100}
|
|
|
size="small"
|
|
|
status={score >= 16 ? 'exception' : score >= 9 ? 'active' : 'success'}
|
|
|
showInfo={false}
|
|
|
/>
|
|
|
<span style={{ fontSize: '12px' }}>{score}</span>
|
|
|
</div>
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
title: '发生概率',
|
|
|
dataIndex: 'probability',
|
|
|
key: 'probability',
|
|
|
width: 120,
|
|
|
render: (probability) => (
|
|
|
<div>
|
|
|
<Rate disabled value={probability} style={{ fontSize: '12px' }} />
|
|
|
<span style={{ marginLeft: 4, fontSize: '12px' }}>({probability}/5)</span>
|
|
|
</div>
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
title: '影响程度',
|
|
|
dataIndex: 'impact',
|
|
|
key: 'impact',
|
|
|
width: 120,
|
|
|
render: (impact) => (
|
|
|
<div>
|
|
|
<Rate disabled value={impact} style={{ fontSize: '12px' }} />
|
|
|
<span style={{ marginLeft: 4, fontSize: '12px' }}>({impact}/5)</span>
|
|
|
</div>
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
title: '处理状态',
|
|
|
dataIndex: 'status',
|
|
|
key: 'status',
|
|
|
width: 100,
|
|
|
render: (status) => (
|
|
|
<Tag color={getStatusColor(status)}>
|
|
|
{status}
|
|
|
</Tag>
|
|
|
),
|
|
|
},
|
|
|
{
|
|
|
title: '评估人',
|
|
|
dataIndex: 'assessor',
|
|
|
key: 'assessor',
|
|
|
width: 100,
|
|
|
},
|
|
|
{
|
|
|
title: '评估日期',
|
|
|
dataIndex: 'assessDate',
|
|
|
key: 'assessDate',
|
|
|
width: 120,
|
|
|
},
|
|
|
{
|
|
|
title: '操作',
|
|
|
key: 'action',
|
|
|
width: 200,
|
|
|
render: (_, record) => (
|
|
|
<Space size="small">
|
|
|
<Button
|
|
|
type="link"
|
|
|
icon={<EyeOutlined />}
|
|
|
onClick={() => handleView(record)}
|
|
|
>
|
|
|
查看
|
|
|
</Button>
|
|
|
<Button
|
|
|
type="link"
|
|
|
icon={<EditOutlined />}
|
|
|
onClick={() => handleEdit(record)}
|
|
|
>
|
|
|
编辑
|
|
|
</Button>
|
|
|
<Button
|
|
|
type="link"
|
|
|
danger
|
|
|
icon={<DeleteOutlined />}
|
|
|
onClick={() => handleDelete(record)}
|
|
|
>
|
|
|
删除
|
|
|
</Button>
|
|
|
</Space>
|
|
|
),
|
|
|
},
|
|
|
];
|
|
|
|
|
|
return (
|
|
|
<div className="risk-assessment">
|
|
|
<Card
|
|
|
title="风险评估管理"
|
|
|
extra={
|
|
|
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}>
|
|
|
新增评估
|
|
|
</Button>
|
|
|
}
|
|
|
>
|
|
|
<Table
|
|
|
columns={columns}
|
|
|
dataSource={dataSource}
|
|
|
loading={loading}
|
|
|
rowKey="id"
|
|
|
pagination={{
|
|
|
...pagination,
|
|
|
showSizeChanger: true,
|
|
|
showQuickJumper: true,
|
|
|
showTotal: (total, range) =>
|
|
|
`第 ${range[0]}-${range[1]} 条/共 ${total} 条`,
|
|
|
onChange: (page, pageSize) => {
|
|
|
setPagination(prev => ({
|
|
|
...prev,
|
|
|
current: page,
|
|
|
pageSize: pageSize || prev.pageSize,
|
|
|
}));
|
|
|
},
|
|
|
}}
|
|
|
/>
|
|
|
</Card>
|
|
|
|
|
|
<Modal
|
|
|
title={editingRecord ? '编辑风险评估' : '新增风险评估'}
|
|
|
open={modalVisible}
|
|
|
onCancel={() => {
|
|
|
setModalVisible(false);
|
|
|
form.resetFields();
|
|
|
}}
|
|
|
onOk={() => form.submit()}
|
|
|
width={700}
|
|
|
>
|
|
|
<Form
|
|
|
form={form}
|
|
|
layout="vertical"
|
|
|
onFinish={handleSubmit}
|
|
|
>
|
|
|
<Form.Item
|
|
|
name="riskName"
|
|
|
label="风险名称"
|
|
|
rules={[{ required: true, message: '请输入风险名称' }]}
|
|
|
>
|
|
|
<Input placeholder="请输入风险名称" />
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
name="riskType"
|
|
|
label="风险类型"
|
|
|
rules={[{ required: true, message: '请选择风险类型' }]}
|
|
|
>
|
|
|
<Select placeholder="请选择风险类型">
|
|
|
<Option value="环境风险">环境风险</Option>
|
|
|
<Option value="设备风险">设备风险</Option>
|
|
|
<Option value="人员风险">人员风险</Option>
|
|
|
<Option value="管理风险">管理风险</Option>
|
|
|
<Option value="技术风险">技术风险</Option>
|
|
|
</Select>
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
name="probability"
|
|
|
label="发生概率 (1-5分)"
|
|
|
rules={[{ required: true, message: '请选择发生概率' }]}
|
|
|
>
|
|
|
<Rate />
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
name="impact"
|
|
|
label="影响程度 (1-5分)"
|
|
|
rules={[{ required: true, message: '请选择影响程度' }]}
|
|
|
>
|
|
|
<Rate />
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
name="description"
|
|
|
label="风险描述"
|
|
|
rules={[{ required: true, message: '请输入风险描述' }]}
|
|
|
>
|
|
|
<Input.TextArea rows={3} placeholder="请输入风险描述" />
|
|
|
</Form.Item>
|
|
|
|
|
|
<Form.Item
|
|
|
name="controlMeasures"
|
|
|
label="控制措施"
|
|
|
rules={[{ required: true, message: '请输入控制措施' }]}
|
|
|
>
|
|
|
<Input.TextArea rows={3} placeholder="请输入控制措施" />
|
|
|
</Form.Item>
|
|
|
</Form>
|
|
|
</Modal>
|
|
|
</div>
|
|
|
);
|
|
|
};
|
|
|
|
|
|
export default RiskAssessment;
|