main
wangyunfei 1 month ago
parent 373ccbc654
commit b371c4303a

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

@ -1,133 +1,277 @@
import React, { useState, useEffect } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { Card, Table, Button, Modal, Form, Input, Select, message, Space, Tag } from 'antd'; import { Card, Result, CheckCircleOutlined, Button } from 'antd';
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined } from '@ant-design/icons'; import * as echarts from 'echarts';
import './EvaluationReport.less'; import StandardTable from '@/components/StandardTable';
import styles from './EvaluationReport.less';
import img1 from '@/assets/safe_majorHazard/online_monitoring/img1.png';
import img2 from '@/assets/safe_majorHazard/online_monitoring/img2.png';
import img3 from '@/assets/safe_majorHazard/online_monitoring/img3.png';
const { Option } = Select;
const EvaluationReport = () => { const EvaluationReport = () => {
const [form] = Form.useForm(); const trendChartRef = useRef(null);
const [dataSource, setDataSource] = useState([]); const pieChartRef = useRef(null);
const barChartRef = useRef(null);
// 表格相关状态
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [modalVisible, setModalVisible] = useState(false); const [dataSource, setDataSource] = useState([]);
const [editingRecord, setEditingRecord] = useState(null);
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
current: 1, current: 1,
pageSize: 10, pageSize: 5,
total: 0, total: 0,
}); });
// 模拟数据 // 隐患趋势分析折线图
const mockData = [ useEffect(() => {
if (trendChartRef.current) {
const chart = echarts.init(trendChartRef.current);
const option = {
color: ['#FF4D4F', '#FAAD14', '#52C41A'],
legend: {
data: ['重大隐患', '一般隐患', '轻微隐患'],
top: "5px",
left: "center",
itemGap: 20,
textStyle: {
fontSize: 10
}
},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '20%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: 10
}
},
series: [
{ {
id: 1, name: '重大隐患',
reportName: '2024年第一季度安全评估报告', type: 'line',
reportType: '季度评估', smooth: true,
assessmentPeriod: '2024-01-01 至 2024-03-31', symbol: 'circle',
assessor: '张三', symbolSize: 6,
status: '已完成', lineStyle: {
createTime: '2024-04-01 10:00:00', width: 2,
description: '对第一季度安全生产情况进行全面评估', color: '#FF4D4F'
},
itemStyle: {
color: '#FF4D4F',
borderColor: '#FF4D4F',
borderWidth: 2
},
data: [12, 8, 15, 10, 18, 14, 20, 16, 22, 19, 25, 21]
}, },
{ {
id: 2, name: '一般隐患',
reportName: '2024年年度安全评估报告', type: 'line',
reportType: '年度评估', smooth: true,
assessmentPeriod: '2024-01-01 至 2024-12-31', symbol: 'circle',
assessor: '李四', symbolSize: 6,
status: '进行中', lineStyle: {
createTime: '2024-01-15 14:30:00', width: 2,
description: '年度安全生产综合评估', color: '#FAAD14'
}, },
]; itemStyle: {
color: '#FAAD14',
useEffect(() => { borderColor: '#FAAD14',
fetchData(); borderWidth: 2
}, [pagination.current, pagination.pageSize]); },
data: [25, 30, 28, 35, 32, 38, 40, 36, 42, 38, 45, 41]
const fetchData = async () => { },
setLoading(true); {
try { name: '轻微隐患',
// 模拟API调用 type: 'line',
setTimeout(() => { smooth: true,
setDataSource(mockData); symbol: 'circle',
setPagination(prev => ({ ...prev, total: mockData.length })); symbolSize: 6,
setLoading(false); lineStyle: {
}, 500); width: 2,
} catch (error) { color: '#52C41A'
message.error('获取数据失败'); },
setLoading(false); itemStyle: {
color: '#52C41A',
borderColor: '#52C41A',
borderWidth: 2
},
data: [45, 50, 48, 55, 52, 58, 60, 56, 62, 58, 65, 61]
} }
]
}; };
const handleAdd = () => { chart.setOption(option);
setEditingRecord(null);
form.resetFields(); const handleResize = () => {
setModalVisible(true); if (chart && !chart.isDisposed()) {
chart.resize();
}
}; };
const handleEdit = (record) => { window.addEventListener('resize', handleResize);
setEditingRecord(record);
form.setFieldsValue(record); return () => {
setModalVisible(true); window.removeEventListener('resize', handleResize);
if (chart && !chart.isDisposed()) {
chart.dispose();
}
}; };
}
}, []);
// 隐患类型分布玫瑰饼图
useEffect(() => {
if (pieChartRef.current) {
const chart = echarts.init(pieChartRef.current);
const handleDelete = (record) => { const option = {
Modal.confirm({ color: ['#FF4D4F', '#FAAD14', '#52C41A', '#1890FF', '#722ED1', '#13C2C2'],
title: '确认删除', legend: {
content: `确定要删除评估报告"${record.reportName}"吗?`, orient: 'vertical',
onOk: () => { left: 'left',
setDataSource(dataSource.filter(item => item.id !== record.id)); top: 'center',
message.success('删除成功'); textStyle: {
fontSize: 10
}
}, },
}); series: [
{
name: '隐患类型',
type: 'pie',
radius: ['20%', '70%'],
center: ['60%', '50%'],
roseType: 'area',
itemStyle: {
borderRadius: 5,
borderColor: '#fff',
borderWidth: 2
},
label: {
show: true,
formatter: '{b}: {c}',
fontSize: 10
},
data: [
{ value: 35, name: '设备故障' },
{ value: 28, name: '操作失误' },
{ value: 22, name: '环境因素' },
{ value: 18, name: '管理缺陷' },
{ value: 15, name: '设计缺陷' },
{ value: 12, name: '其他' }
]
}
]
}; };
const handleView = (record) => { chart.setOption(option);
Modal.info({
title: '查看评估报告', const handleResize = () => {
content: ( if (chart && !chart.isDisposed()) {
<div> chart.resize();
<p><strong>报告名称</strong>{record.reportName}</p> }
<p><strong>报告类型</strong>{record.reportType}</p>
<p><strong>评估周期</strong>{record.assessmentPeriod}</p>
<p><strong>评估人</strong>{record.assessor}</p>
<p><strong>状态</strong>{record.status}</p>
<p><strong>创建时间</strong>{record.createTime}</p>
<p><strong>描述</strong>{record.description}</p>
</div>
),
width: 600,
});
}; };
const handleSubmit = async (values) => { window.addEventListener('resize', handleResize);
try {
if (editingRecord) { return () => {
// 编辑 window.removeEventListener('resize', handleResize);
setDataSource(dataSource.map(item => if (chart && !chart.isDisposed()) {
item.id === editingRecord.id ? { ...item, ...values } : item chart.dispose();
)); }
message.success('编辑成功');
} else {
// 新增
const newRecord = {
id: Date.now(),
...values,
status: '进行中',
createTime: new Date().toLocaleString(),
}; };
setDataSource([...dataSource, newRecord]);
message.success('添加成功');
} }
setModalVisible(false); }, []);
form.resetFields();
} catch (error) { // 隐患整改情况柱状图
message.error('操作失败'); useEffect(() => {
if (barChartRef.current) {
const chart = echarts.init(barChartRef.current);
const option = {
color: ['#FF4D4F', '#FAAD14', '#1890FF', '#52C41A', '#722ED1'],
grid: {
left: '3%',
right: '4%',
bottom: '3%',
top: '10%',
containLabel: true
},
xAxis: {
type: 'category',
data: ['待处理', '处理中', '待审核', '已完成', '已关闭'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
axisLabel: {
fontSize: 10
}
},
series: [
{
name: '数量',
type: 'bar',
data: [25, 18, 12, 35, 8],
itemStyle: {
borderRadius: [4, 4, 0, 0]
},
barWidth: '60%'
}
]
};
chart.setOption(option);
const handleResize = () => {
if (chart && !chart.isDisposed()) {
chart.resize();
} }
}; };
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
if (chart && !chart.isDisposed()) {
chart.dispose();
}
};
}
}, []);
// 表格列定义
const columns = [ const columns = [
{
title: '编号',
dataIndex: 'id',
key: 'id',
width: 80,
render: (text, record, index) => {
const page = pagination.current || 1;
const pageSize = pagination.pageSize || 5;
const number = (page - 1) * pageSize + index + 1;
return `0${number}`.slice(-2);
}
},
{ {
title: '报告名称', title: '报告名称',
dataIndex: 'reportName', dataIndex: 'reportName',
@ -135,164 +279,354 @@ const EvaluationReport = () => {
width: 200, width: 200,
}, },
{ {
title: '报告类型', title: '类型',
dataIndex: 'reportType', dataIndex: 'type',
key: 'reportType', key: 'type',
width: 120, width: 120,
}, },
{ {
title: '评估周期', title: '上传时间',
dataIndex: 'assessmentPeriod', dataIndex: 'uploadTime',
key: 'assessmentPeriod', key: 'uploadTime',
width: 200, width: 150,
}, },
{ {
title: '评估人', title: '版本',
dataIndex: 'assessor', dataIndex: 'version',
key: 'assessor', key: 'version',
width: 100, width: 80,
}, },
{ {
title: '状态', title: '状态',
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
width: 100, width: 100,
render: (status) => ( render: (text) => {
<Tag color={status === '已完成' ? 'green' : 'orange'}> const statusMap = {
{status} '已完成': { color: '#52C41A', bg: '#F6FFED' },
</Tag> '处理中': { color: '#FAAD14', bg: '#FFFBE6' },
), '待审核': { color: '#1890FF', bg: '#E6F7FF' }
};
const status = statusMap[text] || { color: '#333', bg: '#F5F5F5' };
return (
<span style={{
color: status.color,
backgroundColor: status.bg,
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px'
}}>
{text}
</span>
);
}
}, },
{ {
title: '创建时间', title: '上传人',
dataIndex: 'createTime', dataIndex: 'uploader',
key: 'createTime', key: 'uploader',
width: 150, width: 100,
}, },
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 200, width: 80,
render: (_, record) => ( render: (_, record) => (
<Space size="small"> <div>
<Button <Button type="link" size="small" style={{ padding: 0 }}>
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> </Button>
</Space> </div>
), ),
}, },
]; ];
// 模拟数据
const mockData = [
{
key: '1',
id: '001',
reportName: '2024年第一季度安全评估报告',
type: '季度报告',
uploadTime: '2024-01-15 08:30:25',
version: 'V1.0',
status: '已完成',
uploader: '张三',
},
{
key: '2',
id: '002',
reportName: '重大危险源专项评估报告',
type: '专项报告',
uploadTime: '2024-01-15 09:15:10',
version: 'V2.1',
status: '处理中',
uploader: '李四',
},
{
key: '3',
id: '003',
reportName: '年度安全风险评估报告',
type: '年度报告',
uploadTime: '2024-01-15 10:45:30',
version: 'V1.5',
status: '待审核',
uploader: '王五',
},
{
key: '4',
id: '004',
reportName: '设备安全评估报告',
type: '设备报告',
uploadTime: '2024-01-15 11:20:45',
version: 'V1.2',
status: '已完成',
uploader: '赵六',
},
{
key: '5',
id: '005',
reportName: '应急预案评估报告',
type: '应急报告',
uploadTime: '2024-01-15 12:10:20',
version: 'V3.0',
status: '已完成',
uploader: '孙七',
},
{
key: '6',
id: '006',
reportName: '环境安全评估报告',
type: '环境报告',
uploadTime: '2024-01-15 13:25:15',
version: 'V1.8',
status: '处理中',
uploader: '周八',
},
{
key: '7',
id: '007',
reportName: '人员安全培训评估报告',
type: '培训报告',
uploadTime: '2024-01-15 14:10:30',
version: 'V2.3',
status: '待审核',
uploader: '吴九',
},
{
key: '8',
id: '008',
reportName: '消防安全评估报告',
type: '消防报告',
uploadTime: '2024-01-15 15:45:20',
version: 'V1.1',
status: '已完成',
uploader: '郑十',
},
{
key: '9',
id: '009',
reportName: '化学品安全评估报告',
type: '化学品报告',
uploadTime: '2024-01-15 16:30:45',
version: 'V2.0',
status: '处理中',
uploader: '钱十一',
},
{
key: '10',
id: '010',
reportName: '职业健康安全评估报告',
type: '职业健康报告',
uploadTime: '2024-01-15 17:15:10',
version: 'V1.6',
status: '已完成',
uploader: '陈十二',
},
{
key: '11',
id: '011',
reportName: '安全管理制度评估报告',
type: '制度报告',
uploadTime: '2024-01-15 18:20:35',
version: 'V1.3',
status: '待审核',
uploader: '刘十三',
},
{
key: '12',
id: '012',
reportName: '安全投入评估报告',
type: '投入报告',
uploadTime: '2024-01-15 19:05:50',
version: 'V1.9',
status: '已完成',
uploader: '黄十四',
},
];
// 初始化数据
useEffect(() => {
setPagination(prev => ({ ...prev, total: mockData.length }));
}, []);
// 根据分页获取当前页数据
const getCurrentPageData = () => {
const { current, pageSize } = pagination;
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
return mockData.slice(startIndex, endIndex);
};
// 表格选择变化
const onSelectChange = (newSelectedRowKeys, newSelectedRows) => {
setSelectedRowKeys(newSelectedRowKeys);
setSelectedRows(newSelectedRows);
};
// 分页变化处理
const handleTableChange = (pagination) => {
setPagination(prev => ({
...prev,
current: pagination.current,
pageSize: pagination.pageSize,
}));
};
return ( return (
<div className="evaluation-report"> <div className={styles.Econtainer}>
<Card {/* 第一个大块 - 高度16% */}
title="评估报告管理" <div className={styles.EcontainerTop}>
extra={ <div className={styles.sectionContent}>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}> <div className={styles.blocksContainer}>
新增报告 {/* 块1 */}
</Button> <div className={styles.blockItem}>
} <div className={styles.blockLeft}>
> <div className={styles.blockTitle}>总危险源数量</div>
<Table <div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img1} alt="总危险源数量" className={styles.blockImage} />
</div>
</div>
{/* 块2 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>高风险设备</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img2} alt="高风险设备" className={styles.blockImage} />
</div>
</div>
{/* 块3 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>今日预警次数</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img3} alt="今日预警次数" className={styles.blockImage} />
</div>
</div>
{/* 块4 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>未处理预警</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<span className={styles.arrow}></span>
较昨日 +2
</div>
</div>
<div className={styles.blockRight}>
<img src={img1} alt="未处理预警" className={styles.blockImage} />
</div>
</div>
</div>
</div>
</div>
{/* 第二个大块 - 三个图表块 */}
<div className={styles.EcontainerMiddle}>
<div className={styles.sectionContent}>
{/* 第一个小块 - 隐患趋势分析 */}
<div className={styles.chartBlock}>
<div className={styles.chartTitle}>
<div className={styles.titleIcon}></div>
<div>隐患趋势分析</div>
</div>
<div className={styles.chartContainer} ref={trendChartRef}></div>
</div>
{/* 第二个小块 - 隐患类型分布 */}
<div className={styles.chartBlock}>
<div className={styles.chartTitle}>
<div className={styles.titleIcon}></div>
<div>隐患类型分布</div>
</div>
<div className={styles.chartContainer} ref={pieChartRef}></div>
</div>
{/* 第三小块 - 隐患整改情况 */}
<div className={styles.chartBlock}>
<div className={styles.chartTitle}>
<div className={styles.titleIcon}></div>
<div>隐患整改情况</div>
</div>
<div className={styles.chartContainer} ref={barChartRef}></div>
</div>
</div>
</div>
{/* 第三大块 - 评估报告表格 */}
<div className={styles.EcontainerBottom}>
{/* 首行 左侧标题左对齐 右侧按钮右对齐 */}
<div className={styles.tableHeader}>
<div className={styles.tableTitle}>
<div className={styles.titleIcon}></div>
<div>评估报告</div>
</div>
</div>
{/* 表格 5行8列 带页码 每页5条数据 */}
<div className={styles.tableContainer}>
<StandardTable
columns={columns} columns={columns}
dataSource={dataSource} data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading} loading={loading}
rowKey="id" selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{ pagination={{
...pagination, ...pagination,
showSizeChanger: true, showSizeChanger: false,
showQuickJumper: true, showQuickJumper: true,
showTotal: (total, range) => showTotal: (total, range) =>
`${range[0]}-${range[1]} 条/共 ${total}`, `${total}`,
onChange: (page, pageSize) => {
setPagination(prev => ({
...prev,
current: page,
pageSize: pageSize || prev.pageSize,
}));
},
}} }}
scroll={{ x: 1000 }}
/> />
</Card> </div>
</div>
<Modal
title={editingRecord ? '编辑评估报告' : '新增评估报告'}
open={modalVisible}
onCancel={() => {
setModalVisible(false);
form.resetFields();
}}
onOk={() => form.submit()}
width={600}
>
<Form
form={form}
layout="vertical"
onFinish={handleSubmit}
>
<Form.Item
name="reportName"
label="报告名称"
rules={[{ required: true, message: '请输入报告名称' }]}
>
<Input placeholder="请输入报告名称" />
</Form.Item>
<Form.Item
name="reportType"
label="报告类型"
rules={[{ required: true, message: '请选择报告类型' }]}
>
<Select placeholder="请选择报告类型">
<Option value="季度评估">季度评估</Option>
<Option value="年度评估">年度评估</Option>
<Option value="专项评估">专项评估</Option>
</Select>
</Form.Item>
<Form.Item
name="assessmentPeriod"
label="评估周期"
rules={[{ required: true, message: '请输入评估周期' }]}
>
<Input placeholder="请输入评估周期" />
</Form.Item>
<Form.Item
name="assessor"
label="评估人"
rules={[{ required: true, message: '请输入评估人' }]}
>
<Input placeholder="请输入评估人" />
</Form.Item>
<Form.Item
name="description"
label="描述"
>
<Input.TextArea rows={4} placeholder="请输入描述" />
</Form.Item>
</Form>
</Modal>
</div> </div>
); );
}; };

@ -1,115 +1,225 @@
.evaluation-report { .Econtainer {
padding: 20px; padding: 8px 6px 0px 6px;
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
// 第一个大块 - 高度16%
.EcontainerTop {
height: 16%;
border-radius: 4px;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
flex-direction: column;
.blocksContainer {
flex: 1;
display: flex;
gap: 10px;
height: 100%;
.blockItem {
flex: 1;
height: 100%;
display: flex;
background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 92.55%);
border-radius: 4px;
border: 2px solid #FFFFFF;
.blockLeft {
width: 60%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
padding: 15px;
padding-left: 20px;
gap: 8px;
.blockTitle {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
line-height: 1.2;
}
.blockNumber {
font-family: PingFang SC;
font-weight: 700;
font-size: 24px;
color: #333333;
line-height: 1.2;
}
.ant-card { .blockChange {
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); font-family: PingFang SC;
border-radius: 6px; font-weight: 400;
font-size: 12px;
color: #1269FF;
line-height: 1.2;
display: flex;
align-items: center;
gap: 4px;
.ant-card-head { .arrow {
border-bottom: 1px solid #f0f0f0; font-size: 14px;
font-weight: bold;
}
.ant-card-head-title { .checkIcon {
font-size: 16px; font-size: 16px;
font-weight: 600; color: #1269FF;
color: #262626;
} }
} }
}
.blockRight {
flex: 1;
height: 100%;
background-color: transparent;
border-radius: 0 4px 4px 0;
display: flex;
align-items: center;
justify-content: center;
.ant-card-body { .blockImage {
padding: 20px; height: 130%;
object-fit: contain;
margin-right: -10px;
} }
} }
.ant-table {
.ant-table-thead > tr > th {
background-color: #fafafa;
font-weight: 600;
color: #262626;
border-bottom: 1px solid #f0f0f0;
} }
.ant-table-tbody > tr > td {
border-bottom: 1px solid #f0f0f0;
} }
.ant-table-tbody > tr:hover > td {
background-color: #f5f5f5;
} }
} }
.ant-btn { // 第二个大块 - 三个图表块
.EcontainerMiddle {
height: 30%;
border-radius: 4px; border-radius: 4px;
background-color: #fff;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
flex-direction: row;
gap: 10px;
padding: 10px;
.chartBlock {
flex: 1;
height: 100%;
background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
border: 2px solid #fff;
border-radius: 4px;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
.chartTitle {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
padding: 10px 15px 5px 15px;
&.ant-btn-primary { .titleIcon {
background-color: #1890ff; width: 3px;
border-color: #1890ff; height: 14px;
background-color: #2E4CD4;
&:hover {
background-color: #40a9ff;
border-color: #40a9ff;
} }
} }
&.ant-btn-link { .chartContainer {
padding: 4px 8px; flex: 1;
height: auto; width: 100%;
height: 120%;
&:hover { // // min-height: 200px;
background-color: #f5f5f5;
} }
} }
} }
.ant-tag {
border-radius: 4px;
font-size: 12px;
padding: 2px 8px;
} }
.ant-modal { // 第三大块 - 评估报告表格
.ant-modal-header { .EcontainerBottom {
border-bottom: 1px solid #f0f0f0; flex: 1;
background-color: #fff;
border-radius: 4px;
display: flex;
flex-direction: column;
padding: 10px;
.tableHeader {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
.tableTitle {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.ant-modal-title { .titleIcon {
font-size: 16px; width: 3px;
font-weight: 600; height: 14px;
color: #262626; background-color: #2E4CD4;
} }
} }
.ant-modal-body {
padding: 24px;
} }
.ant-form-item-label > label { .tableContainer {
font-weight: 500; flex: 1;
color: #262626; overflow: hidden;
:global(.ant-table-wrapper) {
height: 100%;
} }
.ant-input, :global(.ant-table) {
.ant-select-selector { height: 100%;
border-radius: 4px; }
border: 1px solid #d9d9d9;
&:hover { :global(.ant-table-container) {
border-color: #40a9ff; height: 100%;
} }
&:focus, :global(.ant-table-body) {
&.ant-select-focused .ant-select-selector { height: calc(100% - 55px); // 减去表头高度
border-color: #40a9ff; overflow-y: auto;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2);
} }
:global(.ant-table-tbody > tr > td) {
padding: 8px 16px;
font-size: 12px;
} }
:global(.ant-table-thead > tr > th) {
padding: 8px 16px;
font-size: 12px;
font-weight: 500;
background-color: #fafafa;
} }
.ant-pagination { :global(.ant-pagination) {
margin-top: 16px; margin-top: 10px;
text-align: right; text-align: right;
}
.ant-pagination-total-text {
color: #8c8c8c;
margin-right: 16px;
} }
} }
} }

@ -1,342 +1,713 @@
import React, { useState, useEffect } from 'react';
import { Card, Table, Button, Modal, Form, Input, Select, message, Space, Tag, Badge } from 'antd';
import { PlusOutlined, EditOutlined, DeleteOutlined, EyeOutlined, PlayCircleOutlined, PauseCircleOutlined } from '@ant-design/icons';
import './OnlineMonitoring.less';
const { Option } = Select; import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button } from 'antd';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './OnlineMonitoring.less';
import alarm0 from '@/assets/safe_majorHazard/online_monitoring/alarm0.png';
import alarm1 from '@/assets/safe_majorHazard/online_monitoring/alarm1.png';
import alarm2 from '@/assets/safe_majorHazard/online_monitoring/alarm2.png';
import alarm3 from '@/assets/safe_majorHazard/online_monitoring/alarm3.png';
import exportIcon from '@/assets/safe_majorHazard/online_monitoring/export.png';
import deleteIcon from '@/assets/safe_majorHazard/online_monitoring/delete.png';
const OnlineMonitoring = () => { const OnlineMonitoring = () => {
const [form] = Form.useForm(); const chartRef = useRef(null);
const [dataSource, setDataSource] = useState([]); const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [modalVisible, setModalVisible] = useState(false); const [dataSource, setDataSource] = useState([]);
const [editingRecord, setEditingRecord] = useState(null);
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
current: 1, current: 1,
pageSize: 10, pageSize: 5,
total: 0, total: 0,
}); });
// 模拟数据 useEffect(() => {
const mockData = [ if (chartRef.current) {
const chart = echarts.init(chartRef.current);
const option = {
color: ['#04A7F3', '#E7C42C', '#EC6941'],
legend: {
data: ['液位', '温度', '压力'],
top: "-3px",
left: "center",
itemGap: 40, // 图例间距
textStyle: {
fontSize: 10
}
},
grid: {
left: '2%',
right: '4%',
bottom: '2%',
top: '12%',
containLabel: true
},
xAxis: {
type: 'category',
boundaryGap: false,
data: ['0:00', '2:00', '4:00', '6:00', '8:00', '10:00', '12:00', '14:00', '16:00', '18:00', '20:00', '22:00', '24:00'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
min: 0,
max: 500,
axisLabel: {
formatter: '{value}',
fontSize: 10
}
},
series: [
{ {
id: 1, name: '液位',
deviceName: '温度传感器-001', type: 'line',
deviceType: '温度传感器', smooth: true,
location: '生产车间A区', lineStyle: {
status: '在线', width: 1.5,
lastUpdate: '2024-01-15 14:30:25', color: '#04A7F3'
value: '25.6°C', },
threshold: '30°C', areaStyle: {
description: '监测生产车间温度变化', color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(4, 167, 243, 0.3)' },
{ offset: 1, color: 'rgba(4, 167, 243, 0)' }
]
}
},
symbol: 'none', // 不显示数据点
data: [120, 200, 150, 300, 250, 400, 350, 280, 320, 180, 220, 160, 140]
}, },
{ {
id: 2, name: '温度',
deviceName: '压力传感器-002', type: 'line',
deviceType: '压力传感器', smooth: true,
location: '储罐区B区', lineStyle: {
status: '离线', width: 1.5,
lastUpdate: '2024-01-15 12:15:30', color: '#E7C42C'
value: '--', },
threshold: '2.5MPa', areaStyle: {
description: '监测储罐压力状态', color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(231, 196, 44, 0.3)' },
{ offset: 1, color: 'rgba(231, 196, 44, 0)' }
]
}
},
symbol: 'none',
data: [80, 120, 100, 180, 160, 220, 200, 150, 170, 90, 110, 85, 75]
}, },
{ {
id: 3, name: '压力',
deviceName: '气体检测器-003', type: 'line',
deviceType: '气体检测器', smooth: true,
location: '危险品仓库', lineStyle: {
status: '在线', width: 1.5,
lastUpdate: '2024-01-15 14:32:10', color: '#EC6941'
value: '正常',
threshold: '50ppm',
description: '监测有害气体浓度',
}, },
]; areaStyle: {
color: {
useEffect(() => { type: 'linear',
fetchData(); x: 0,
}, [pagination.current, pagination.pageSize]); y: 1,
x2: 0,
const fetchData = async () => { y2: 0,
setLoading(true); colorStops: [
try { { offset: 0, color: 'rgba(236, 105, 65, 0)' },
// 模拟API调用 { offset: 1, color: 'rgba(236, 105, 65, 0.3)' }
setTimeout(() => { ]
setDataSource(mockData); }
setPagination(prev => ({ ...prev, total: mockData.length })); },
setLoading(false); symbol: 'none',
}, 500); data: [200, 300, 250, 450, 400, 430, 480, 420, 480, 280, 320, 260, 240]
} catch (error) {
message.error('获取数据失败');
setLoading(false);
} }
]
}; };
const handleAdd = () => { chart.setOption(option);
setEditingRecord(null);
form.resetFields();
setModalVisible(true);
};
const handleEdit = (record) => { // 响应式调整 - 使用ResizeObserver监听容器尺寸变化
setEditingRecord(record); let resizeTimer = null;
form.setFieldsValue(record); const handleResize = () => {
setModalVisible(true); // 防抖处理避免频繁调用resize
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(() => {
chart.resize();
}, 100);
}; };
const handleDelete = (record) => { // 监听窗口大小变化
Modal.confirm({ window.addEventListener('resize', handleResize);
title: '确认删除',
content: `确定要删除监控设备"${record.deviceName}"吗?`,
onOk: () => {
setDataSource(dataSource.filter(item => item.id !== record.id));
message.success('删除成功');
},
});
};
const handleView = (record) => { // 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
Modal.info({ let resizeObserver = null;
title: '查看监控设备详情', if (window.ResizeObserver) {
content: ( resizeObserver = new ResizeObserver(() => {
<div> // 使用setTimeout确保DOM更新完成后再调整图表
<p><strong>设备名称</strong>{record.deviceName}</p> setTimeout(() => {
<p><strong>设备类型</strong>{record.deviceType}</p> handleResize();
<p><strong>安装位置</strong>{record.location}</p> }, 0);
<p><strong>运行状态</strong>
<Badge
status={record.status === '在线' ? 'success' : 'error'}
text={record.status}
/>
</p>
<p><strong>当前数值</strong>{record.value}</p>
<p><strong>阈值设置</strong>{record.threshold}</p>
<p><strong>最后更新</strong>{record.lastUpdate}</p>
<p><strong>设备描述</strong>{record.description}</p>
</div>
),
width: 600,
}); });
}; resizeObserver.observe(chartRef.current);
}
const handleStartStop = (record) => {
const newStatus = record.status === '在线' ? '离线' : '在线';
setDataSource(dataSource.map(item =>
item.id === record.id ? { ...item, status: newStatus } : item
));
message.success(`设备已${newStatus === '在线' ? '启动' : '停止'}`);
};
const handleSubmit = async (values) => { return () => {
try { window.removeEventListener('resize', handleResize);
if (editingRecord) { if (resizeObserver) {
// 编辑 resizeObserver.disconnect();
setDataSource(dataSource.map(item =>
item.id === editingRecord.id ? { ...item, ...values } : item
));
message.success('编辑成功');
} else {
// 新增
const newRecord = {
id: Date.now(),
...values,
status: '离线',
lastUpdate: new Date().toLocaleString(),
value: '--',
};
setDataSource([...dataSource, newRecord]);
message.success('添加成功');
} }
setModalVisible(false); if (resizeTimer) {
form.resetFields(); clearTimeout(resizeTimer);
} catch (error) {
message.error('操作失败');
} }
chart.dispose();
}; };
}
}, []);
// 表格列定义
const columns = [ const columns = [
{ {
title: '设备名称', title: '编号',
dataIndex: 'deviceName', dataIndex: 'id',
key: 'deviceName', key: 'id',
width: 80,
render: (text, record, index) => {
const page = pagination.current || 1;
const pageSize = pagination.pageSize || 5;
const number = (page - 1) * pageSize + index + 1;
return `0${number}`.slice(-2);
}
},
{
title: '报警时间',
dataIndex: 'alarmTime',
key: 'alarmTime',
width: 150,
},
{
title: '报警传感器名称',
dataIndex: 'sensorName',
key: 'sensorName',
width: 150, width: 150,
}, },
{ {
title: '设备类型', title: '报警类型',
dataIndex: 'deviceType', dataIndex: 'alarmType',
key: 'deviceType', key: 'alarmType',
width: 120, width: 120,
}, },
{ {
title: '安装位置', title: '报警内容',
dataIndex: 'location', dataIndex: 'alarmContent',
key: 'location', key: 'alarmContent',
width: 150, width: 200,
}, },
{ {
title: '运行状态', title: '优先级',
dataIndex: 'priority',
key: 'priority',
width: 80,
render: (text) => {
const colorMap = {
'高': '#FF4D4F',
'中': '#FAAD14',
'低': '#52C41A'
};
return <span style={{ color: colorMap[text] || '#333' }}>{text}</span>;
}
},
{
title: '处理状态',
dataIndex: 'status', dataIndex: 'status',
key: 'status', key: 'status',
width: 100, width: 100,
render: (status) => ( render: (text) => {
<Badge const statusMap = {
status={status === '在线' ? 'success' : 'error'} '未处理': { color: '#FF4D4F', bg: '#FFF2F0' },
text={status} '处理中': { color: '#FAAD14', bg: '#FFFBE6' },
/> '已处理': { color: '#52C41A', bg: '#F6FFED' }
), };
const status = statusMap[text] || { color: '#333', bg: '#F5F5F5' };
return (
<span style={{
color: status.color,
backgroundColor: status.bg,
padding: '2px 8px',
borderRadius: '4px',
fontSize: '12px'
}}>
{text}
</span>
);
}
}, },
{ {
title: '当前数值', title: '处理时间',
dataIndex: 'value', dataIndex: 'processTime',
key: 'value', key: 'processTime',
width: 100, width: 150,
}, },
{ {
title: '阈值设置', title: '处理人',
dataIndex: 'threshold', dataIndex: 'processor',
key: 'threshold', key: 'processor',
width: 100, width: 100,
}, },
{
title: '最后更新',
dataIndex: 'lastUpdate',
key: 'lastUpdate',
width: 150,
},
{ {
title: '操作', title: '操作',
key: 'action', key: 'action',
width: 250, width: 120,
render: (_, record) => ( render: (_, record) => (
<Space size="small"> <div>
<Button <Button type="link" size="small" style={{ padding: 0, marginRight: 8 }}>
type="link"
icon={<EyeOutlined />}
onClick={() => handleView(record)}
>
查看 查看
</Button> </Button>
<Button </div>
type="link"
icon={<EditOutlined />}
onClick={() => handleEdit(record)}
>
编辑
</Button>
<Button
type="link"
icon={record.status === '在线' ? <PauseCircleOutlined /> : <PlayCircleOutlined />}
onClick={() => handleStartStop(record)}
>
{record.status === '在线' ? '停止' : '启动'}
</Button>
<Button
type="link"
danger
icon={<DeleteOutlined />}
onClick={() => handleDelete(record)}
>
删除
</Button>
</Space>
), ),
}, },
]; ];
// 模拟数据
const mockData = [
{
key: '1',
id: '001',
alarmTime: '2024-01-15 08:30:25',
sensorName: 'LNG储罐',
alarmType: '温度超限',
alarmContent: '储罐温度超过安全阈值',
priority: '高',
status: '未处理',
processTime: '-',
processor: '-',
},
{
key: '2',
id: '002',
alarmTime: '2024-01-15 09:15:10',
sensorName: 'LNG储罐',
alarmType: '压力异常',
alarmContent: '管道压力异常波动',
priority: '中',
status: '处理中',
processTime: '2024-01-15 09:20:00',
processor: '张三',
},
{
key: '3',
id: '003',
alarmTime: '2024-01-15 10:45:30',
sensorName: 'LNG储罐',
alarmType: '液位异常',
alarmContent: '储罐液位低于警戒线',
priority: '高',
status: '已处理',
processTime: '2024-01-15 11:00:15',
processor: '李四',
},
{
key: '4',
id: '004',
alarmTime: '2024-01-15 11:20:45',
sensorName: 'LNG储罐',
alarmType: '气体泄漏',
alarmContent: '检测到可燃气体泄漏',
priority: '高',
status: '未处理',
processTime: '-',
processor: '-',
},
{
key: '5',
id: '005',
alarmTime: '2024-01-15 12:10:20',
sensorName: 'LNG储罐',
alarmType: '设备振动',
alarmContent: '设备异常振动',
priority: '低',
status: '已处理',
processTime: '2024-01-15 12:30:00',
processor: '王五',
},
{
key: '6',
id: '006',
alarmTime: '2024-01-15 13:25:15',
sensorName: 'LNG管道',
alarmType: '流量异常',
alarmContent: '管道流量异常波动',
priority: '中',
status: '未处理',
processTime: '-',
processor: '-',
},
{
key: '7',
id: '007',
alarmTime: '2024-01-15 14:10:30',
sensorName: 'LNG储罐',
alarmType: '温度异常',
alarmContent: '储罐温度异常升高',
priority: '高',
status: '处理中',
processTime: '2024-01-15 14:15:00',
processor: '赵六',
},
{
key: '8',
id: '008',
alarmTime: '2024-01-15 15:45:20',
sensorName: 'LNG管道',
alarmType: '压力超限',
alarmContent: '管道压力超过安全阈值',
priority: '高',
status: '已处理',
processTime: '2024-01-15 16:00:00',
processor: '孙七',
},
{
key: '9',
id: '009',
alarmTime: '2024-01-15 16:30:45',
sensorName: 'LNG储罐',
alarmType: '液位超限',
alarmContent: '储罐液位超过警戒线',
priority: '中',
status: '未处理',
processTime: '-',
processor: '-',
},
{
key: '10',
id: '010',
alarmTime: '2024-01-15 17:15:10',
sensorName: 'LNG管道',
alarmType: '泄漏检测',
alarmContent: '检测到轻微气体泄漏',
priority: '低',
status: '已处理',
processTime: '2024-01-15 17:30:00',
processor: '周八',
},
{
key: '11',
id: '011',
alarmTime: '2024-01-15 18:20:35',
sensorName: 'LNG储罐',
alarmType: '设备故障',
alarmContent: '储罐阀门异常关闭',
priority: '高',
status: '处理中',
processTime: '2024-01-15 18:25:00',
processor: '吴九',
},
{
key: '12',
id: '012',
alarmTime: '2024-01-15 19:05:50',
sensorName: 'LNG管道',
alarmType: '温度异常',
alarmContent: '管道温度异常下降',
priority: '中',
status: '未处理',
processTime: '-',
processor: '-',
},
];
// 初始化数据
useEffect(() => {
setPagination(prev => ({ ...prev, total: mockData.length }));
}, []);
// 根据分页获取当前页数据
const getCurrentPageData = () => {
const { current, pageSize } = pagination;
const startIndex = (current - 1) * pageSize;
const endIndex = startIndex + pageSize;
return mockData.slice(startIndex, endIndex);
};
// 表格选择变化
const onSelectChange = (newSelectedRowKeys, newSelectedRows) => {
setSelectedRowKeys(newSelectedRowKeys);
setSelectedRows(newSelectedRows);
};
// 分页变化处理
const handleTableChange = (pagination) => {
setPagination(prev => ({
...prev,
current: pagination.current,
pageSize: pagination.pageSize,
}));
};
// 导出功能
const handleExport = () => {
console.log('导出数据');
// 这里可以添加导出逻辑
};
// 批量删除功能
const handleBatchDelete = () => {
if (selectedRowKeys.length === 0) {
console.log('没有选中任何行');
// 可以在这里添加提示用户选择行的逻辑
return;
}
console.log('批量删除', selectedRowKeys);
// 这里可以添加批量删除逻辑
};
return ( return (
<div className="online-monitoring"> <div className={styles.Ocontainer}>
<Card <div className={styles.OcontainerTop}>
title="在线监控管理" <div className={styles.OcontainerTopLeft}>
extra={ <div className={styles.OcontainerTopLeftTop}>
<Button type="primary" icon={<PlusOutlined />} onClick={handleAdd}> <div className={styles.alarmO}>
新增设备 <div className={styles.alarmOLeft}>
<img style={{ width: 58, height: 47 }} src={alarm0} alt='alarm0' />
</div>
<div className={styles.alarmORight}>
<div className={styles.alarmORightText1}>总报警</div>
<div className={styles.alarmORightText2}>1456</div>
<div className={styles.alarmORightText3}>
<div>
未处理 <text style={{ color: '#FF4D4F' }}>6</text>
</div>
<div>
处理中 <text style={{ color: '#2e4cd4' }}>10</text>
</div>
</div>
</div>
</div>
<div className={styles.alarmTw}>
<div className={styles.alarmTwLeft}>
<img style={{ width: 58, height: 47 }} src={alarm1} alt='alarm1' />
</div>
<div className={styles.alarmTwRight}>
<div className={styles.alarmTwRightText1}>一级报警</div>
<div className={styles.alarmTwRightText2}>357</div>
<div className={styles.alarmTwRightText3}>
<div>
未处理 <text style={{ color: '#FF4D4F' }}>6</text>
</div>
<div>
处理中 <text style={{ color: '#2e4cd4' }}>10</text>
</div>
</div>
</div>
</div>
<div className={styles.alarmTh}>
<div className={styles.alarmThLeft}>
<img style={{ width: 58, height: 47 }} src={alarm2} alt='alarm2' />
</div>
<div className={styles.alarmThRight}>
<div className={styles.alarmThRightText1}>二级报警</div>
<div className={styles.alarmThRightText2}>401</div>
<div className={styles.alarmThRightText3}>
<div>
未处理 <text style={{ color: '#FF4D4F' }}>6</text>
</div>
<div>
处理中 <text style={{ color: '#2e4cd4' }}>10</text>
</div>
</div>
</div>
</div>
<div className={styles.alarmF}>
<div className={styles.alarmFLeft}>
<img style={{ width: 58, height: 47 }} src={alarm3} alt='alarm3' />
</div>
<div className={styles.alarmFRight}>
<div className={styles.alarmFRightText1}>三级报警</div>
<div className={styles.alarmFRightText2}>556</div>
<div className={styles.alarmFRightText3}>
<div>
未处理 <text style={{ color: '#FF4D4F' }}>6</text>
</div>
<div>
处理中 <text style={{ color: '#2e4cd4' }}>10</text>
</div>
</div>
</div>
</div>
</div>
<div className={styles.OcontainerTopLeftBottom}>
<div className={styles.OcontainerTopLeftBottomTitle}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>预警看板</div>
</div>
<div className={styles.titleRight}>
<div>检测对象</div>
<Select
style={{ width: 80 }}
defaultValue="储罐"
options={[
{ value: '储罐', label: '储罐' },
{ value: '管道', label: '管道' },
{ value: '设备', label: '设备' }
]}
/>
</div>
</div>
<div className={styles.OcontainerTopLeftBottomChart} ref={chartRef}>
</div>
</div>
</div>
<div className={styles.OcontainerTopRight}>
<div className={styles.realTimeDataHeader}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>实时数据采集</div>
</div>
<div className={styles.totalCount}>
总数 <text style={{ color: '#2e4cd4' }}>1378</text>
</div>
</div>
<div className={styles.dataItem1}>
<div className={styles.dataItemLeft}>
<div className={styles.areaName}>储罐液化装置区</div>
<div className={styles.rValue}>R值: 1765</div>
<div className={styles.codeNumber}>编号:XXXXXXXX</div>
</div>
<div className={styles.dataItemRight}>
<div className={styles.circleContainer}>
<div className={styles.outerCircle}>
<div className={styles.innerCircle}>
<div className={styles.levelText}>三级</div>
<div className={styles.riskText}>危险等级</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.dataItem2}>
<div className={styles.dataItemLeft}>
<div className={styles.areaName}>储罐液化装置区</div>
<div className={styles.rValue}>R值: 1765</div>
<div className={styles.codeNumber}>编号:XXXXXXXX</div>
</div>
<div className={styles.dataItemRight}>
<div className={styles.circleContainer}>
<div className={styles.outerCircle}>
<div className={styles.innerCircle}>
<div className={styles.levelText}>一级</div>
<div className={styles.riskText}>危险等级</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.dataItem3}>
<div className={styles.dataItemLeft}>
<div className={styles.areaName}>储罐液化装置区</div>
<div className={styles.rValue}>R值: 1765</div>
<div className={styles.codeNumber}>编号:XXXXXXXX</div>
</div>
<div className={styles.dataItemRight}>
<div className={styles.circleContainer}>
<div className={styles.outerCircle}>
<div className={styles.innerCircle}>
<div className={styles.levelText}>二级</div>
<div className={styles.riskText}>危险等级</div>
</div>
</div>
</div>
</div>
</div>
<div className={styles.dataItem4}>
<div className={styles.dataItemLeft}>
<div className={styles.areaName}>储罐液化装置区</div>
<div className={styles.rValue}>R值: 1765</div>
<div className={styles.codeNumber}>编号:XXXXXXXX</div>
</div>
<div className={styles.dataItemRight}>
<div className={styles.circleContainer}>
<div className={styles.outerCircle}>
<div className={styles.innerCircle}>
<div className={styles.levelText}>三级</div>
<div className={styles.riskText}>危险等级</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{/* 表格 */}
<div className={styles.OcontainerBottom}>
{/* 首行 左侧标题左对齐 右侧按钮右对齐 */}
<div className={styles.tableHeader}>
<div className={styles.tableTitle}>
<div className={styles.titleIcon}></div>
<div>报警信息列表</div>
</div>
<div className={styles.tableActions}>
<Button
type="primary"
onClick={handleExport}
style={{ marginRight: 8 }}
>
<img src={exportIcon} alt="导出" style={{ width: 16, height: 16, margin: '-2px 6px 0 0px'}} />
导出word 报告
</Button> </Button>
}
<Button
type="primary"
onClick={handleBatchDelete}
> >
<Table <img src={deleteIcon} alt="删除" style={{ width: 16, height: 16, margin: '-2px 6px 0 0px' }} />
批量删除
</Button>
</div>
</div>
{/* 表格 5行10列 带页码 每页5条数据 */}
<div className={styles.tableContainer}>
<StandardTable
columns={columns} columns={columns}
dataSource={dataSource} data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading} loading={loading}
rowKey="id" selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{ pagination={{
...pagination, ...pagination,
showSizeChanger: true, showSizeChanger: false,
showQuickJumper: true, showQuickJumper: true,
showTotal: (total, range) => showTotal: (total, range) =>
`${range[0]}-${range[1]} 条/共 ${total}`, `${total}`,
onChange: (page, pageSize) => {
setPagination(prev => ({
...prev,
current: page,
pageSize: pageSize || prev.pageSize,
}));
},
}} }}
scroll={{ x: 1200 }}
/> />
</Card> </div>
</div>
<Modal
title={editingRecord ? '编辑监控设备' : '新增监控设备'}
open={modalVisible}
onCancel={() => {
setModalVisible(false);
form.resetFields();
}}
onOk={() => form.submit()}
width={600}
>
<Form
form={form}
layout="vertical"
onFinish={handleSubmit}
>
<Form.Item
name="deviceName"
label="设备名称"
rules={[{ required: true, message: '请输入设备名称' }]}
>
<Input placeholder="请输入设备名称" />
</Form.Item>
<Form.Item
name="deviceType"
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="location"
label="安装位置"
rules={[{ required: true, message: '请输入安装位置' }]}
>
<Input placeholder="请输入安装位置" />
</Form.Item>
<Form.Item
name="threshold"
label="阈值设置"
rules={[{ required: true, message: '请输入阈值设置' }]}
>
<Input placeholder="请输入阈值设置" />
</Form.Item>
<Form.Item
name="description"
label="设备描述"
>
<Input.TextArea rows={4} placeholder="请输入设备描述" />
</Form.Item>
</Form>
</Modal>
</div> </div>
); );
}; };

File diff suppressed because it is too large Load Diff

@ -1,13 +1,26 @@
import React from 'react'; import React from 'react';
import { Card, Result, Timeline,Statistic, Table,Row, Input,Button,Col, Select} from 'antd'; import { Card, Statistic, Table,Row, Input,Button,Col, Select} from 'antd';
import { PhoneOutlined, IdcardOutlined } from '@ant-design/icons';
import StandardTable from '@/components/StandardTable'; import StandardTable from '@/components/StandardTable';
import styles from './ResponsibilityImplementation.less'; import styles from './ResponsibilityImplementation.less';
import upload from '@/assets/business_basic/upload.png';
import download from '@/assets/business_basic/download.png';
import fire_fighting1 from '@/assets/business_basic/fire_fighting1.png';
import fire_fighting2 from '@/assets/business_basic/fire_fighting2.png';
import fire_fighting3 from '@/assets/business_basic/fire_fighting3.png';
import frameIcon from '@/assets/business_basic/Frame.png';
import background1 from '@/assets/business_basic/background1.png';
const ResponsibilityImplementation = () => { const ResponsibilityImplementation = () => {
// 搜索处理函数
const onSearch = (value) => {
console.log('搜索内容:', value);
// 这里可以添加实际的搜索逻辑
};
const columns = [ const columns = [
{ {
title:"编号", title:"编号",
@ -108,7 +121,7 @@ const ResponsibilityImplementation = () => {
<div className={styles.containerR}> <div className={styles.containerR}>
{/* 警告提示框 */} {/* 警告提示框 */}
<div className={styles.warningBox}> <div className={styles.warningBox}>
<img src={require('@/assets/business_basic/Frame.png')} alt="警告" className={styles.warningIcon} /> <img src={frameIcon} alt="警告" className={styles.warningIcon} />
<span className={styles.warningText}> <span className={styles.warningText}>
有5个消防设备需要维护3个资质证书即将到期请及时处理 有5个消防设备需要维护3个资质证书即将到期请及时处理
</span> </span>
@ -125,11 +138,11 @@ const ResponsibilityImplementation = () => {
</div> </div>
<div className={styles.buttonGroup}> <div className={styles.buttonGroup}>
<Button className={styles.actionBtn}> <Button className={styles.actionBtn}>
<span className={styles.btnIcon}>📤</span> <img src={upload} alt="上传图表" className={styles.btnIcon} />
上传 上传图表
</Button> </Button>
<Button className={styles.actionBtn}> <Button className={styles.actionBtn}>
<span className={styles.btnIcon}>📥</span> <img src={download} alt="下载" className={styles.btnIcon} />
下载 下载
</Button> </Button>
</div> </div>
@ -138,52 +151,98 @@ const ResponsibilityImplementation = () => {
{/* 第二行:图片占位 */} {/* 第二行:图片占位 */}
<div className={styles.leftBottomSection}> <div className={styles.leftBottomSection}>
<div className={styles.imagePlaceholder}> <div className={styles.imagePlaceholder}>
<div className={styles.imageIcon}>🏢</div> <img src={fire_fighting1} alt="消防1" className={styles.imageIcon1} />
<div className={styles.imageText}>组织架构图</div> <div className={styles.imageRow}>
<img src={fire_fighting2} alt="消防2" className={styles.imageIcon2} />
<img src={fire_fighting3} alt="消防3" className={styles.imageIcon3} />
</div>
</div> </div>
</div> </div>
</div> </div>
<div className={styles.containerOneRight}> <div className={styles.containerOneRight}>
{/* 第一块:标题 + 下拉选择框 + 导出按钮 */} {/* 第一行:标题 + 搜索栏 + 下拉选择框 */}
<div className={styles.rightTopSection}> <div className={styles.rightTopSection}>
<div className={styles.rightTopLeft}> <div className={styles.rightTopLeft}>
<div className={styles.titleLeft}> <div className={styles.titleLeft}>
<div className={styles.titleIcon}></div> <div className={styles.titleIcon}></div>
<div>履职时间轴</div> <div>成员信息管理</div>
</div>
</div> </div>
<div className={styles.rightTopRight}>
<div className={styles.searchGroup}>
<Input.Search placeholder="搜索成员..." onSearch={onSearch} style={{ width: 160}} />
<Select <Select
style={{ width: 100, marginLeft: 15 }} defaultValue="全部组织"
defaultValue="每月" className={styles.organizationSelect}
className={styles.rightTopSelect}
options={[ options={[
{ value: '每月', label: '每月' }, { value: '全部组织', label: '全部组织' },
{ value: '每年', label: '每年' }, { value: '技术部', label: '技术部' },
{ value: '生产部', label: '生产部' },
{ value: '安全部', label: '安全部' },
]} ]}
optionRender={(option) => (
<div className={styles.customOption}>
<span className={styles.optionIcon}>📅</span>
<span className={styles.optionText}>{option.label}</span>
</div>
)}
/> />
</div> </div>
<div className={styles.rightTopRight}>
<Button
type="primary"
className={styles.exportBtn}
icon="📄"
>
导出PDF考核报告
</Button>
</div> </div>
</div> </div>
{/* 第二块:图片内容 */} {/* 第二行:三个小块 */}
<div className={styles.rightBottomSection}> <div className={styles.rightBottomSection}>
<div className={styles.imagePlaceholder}> <div className={styles.threeBlocksContainer}>
<div className={styles.imageIcon}>📊</div> <div className={styles.blockItem}>
<div className={styles.imageText}>数据图表</div> <div className={styles.blockContent}>
<div className={styles.backgroundContainer}>
{/* 第一个块:姓名和单位 */}
<div className={styles.infoBlock}>
<div className={styles.nameText}>张明</div>
<div className={styles.unitText}>东义区消防队</div>
</div>
{/* 第二个块:电话 */}
<div className={styles.infoBlock}>
<PhoneOutlined className={styles.infoIcon} />
<span className={styles.infoText}>132****3847</span>
</div>
{/* 第三个块:身份证 */}
<div className={styles.infoBlock}>
<IdcardOutlined className={styles.infoIcon} />
<span className={styles.infoText}>1304************10</span>
</div>
{/* 第四个块:职位标签 */}
<div className={styles.infoBlock}>
<div className={styles.tagContainer}>
<div className={styles.tagBlue1}>队长</div>
<div className={styles.tagBlue2}>消防工程师</div>
</div>
</div>
{/* 第五个块:证书状态 */}
<div className={styles.infoBlock}>
<div className={styles.tagContainer}>
<div className={styles.tagBlue3}>消防工程师</div>
<div className={styles.tagYellow}>证书3天后到期</div>
</div>
</div>
{/* 第六个块:操作按钮 */}
<div className={styles.actionBlock}>
<div className={styles.buttonContainer}>
<Button className={styles.editBtn}>编辑</Button>
<Button className={styles.deleteBtn}>删除</Button>
</div>
</div>
</div>
</div>
</div>
<div className={styles.blockItem}>
<div className={styles.blockContent}>待开发</div>
</div>
<div className={styles.blockItem}>
<div className={styles.blockContent}>待开发</div>
</div>
</div> </div>
</div> </div>
</div> </div>

@ -39,7 +39,7 @@
width: calc(50% - 5px); width: calc(50% - 5px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 15px; padding: 5px 15px;
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
border-radius: 4px; border-radius: 4px;
@ -47,7 +47,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 15px; // margin-bottom: 15px;
.titleLeft { .titleLeft {
display: flex; display: flex;
@ -73,12 +73,13 @@
display: flex; display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 4px;
height: 28px;
border: 1px solid #DFE4F6; border: 1px solid #DFE4F6;
border-radius: 4px; border-radius: 4px;
color: #2E4CD4; color: #2E4CD4;
font-weight: 500; font-weight: 500;
font-size: 12px; font-size: 12px;
padding: 4px 8px; padding: 0px 8px;
background: transparent; background: transparent;
cursor: pointer; cursor: pointer;
transition: all 0.2s; transition: all 0.2s;
@ -89,7 +90,8 @@
} }
.btnIcon { .btnIcon {
font-size: 12px; width: 12px;
height: 12px;
} }
} }
} }
@ -100,24 +102,46 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background-color: #fafafa;
border: 1px dashed #d9d9d9;
border-radius: 4px;
.imagePlaceholder { .imagePlaceholder {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
gap: 8px;
color: #999999;
.imageIcon { .imageIcon1 {
font-size: 32px; transform: scale(0.9) translateY(-5px); // 稍微向上移动
opacity: 0.6; object-fit: contain;
}
.imageRow {
display: flex;
justify-content: space-between;
// width: 100%;
margin-bottom: 10px;
// padding-bottom: 20px;
// gap: 12px;
.imageIcon2 {
height: 55%;
transform: scale(0.7) translateY(-25%) translateX(20%); // 稍微向上移动
object-fit: contain;
background-color: #EFF5FE;
// padding-bottom: 20px;
}
.imageIcon3 {
height: 40%;
transform: scale(0.65) translateY(-32%) translateX(4%); // 向上移动10px
object-fit: contain;
padding-bottom: 20px;
// background-color: #EFF5FE;
}
} }
.imageText { .imageText {
font-size: 14px; font-size: 12px;
font-weight: 400; font-weight: 400;
} }
} }
@ -129,7 +153,7 @@
width: calc(50% - 5px); width: calc(50% - 5px);
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 15px; padding: 5px 15px;
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
border-radius: 4px; border-radius: 4px;
@ -137,7 +161,7 @@
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
margin-bottom: 15px; margin-bottom: 10px;
.rightTopLeft { .rightTopLeft {
display: flex; display: flex;
@ -161,48 +185,235 @@
} }
.rightTopRight { .rightTopRight {
.exportBtn { .searchGroup {
background-color: #2E4CD4 !important; display: flex;
border-color: #2E4CD4 !important; gap: 8px;
color: #fff !important; align-items: center;
font-size: 14px !important;
font-weight: 500 !important; .searchInput {
width: 200px;
height: 32px; height: 32px;
padding: 0 16px;
:global(.ant-input) {
height: 32px;
border-radius: 4px;
border: 1px solid #d9d9d9;
font-size: 14px;
&:focus {
border-color: #2E4CD4;
box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2);
}
}
:global(.ant-input-suffix) {
color: #999999;
font-size: 14px;
}
}
.organizationSelect {
width: 120px;
height: 32px;
:global(.ant-select-selector) {
height: 32px !important;
border-radius: 4px !important;
border: 1px solid #d9d9d9 !important;
&:hover { &:hover {
background-color: #1e3bb8 !important; border-color: #2E4CD4 !important;
border-color: #1e3bb8 !important; }
&:focus {
border-color: #2E4CD4 !important;
box-shadow: 0 0 0 2px rgba(46, 76, 212, 0.2) !important;
}
}
:global(.ant-select-selection-item) {
line-height: 30px !important;
font-size: 14px !important;
}
} }
} }
} }
} }
.rightBottomSection { .rightBottomSection {
flex: 1;
padding: 5px 15px;
width: 100%;
height: 100%;
.threeBlocksContainer {
display: flex;
gap: 20px;
width: 100%;
height: 100%;
.blockItem {
width: 100%;
height: 100%;
flex: 1; flex: 1;
display: flex; display: flex;
align-items: center;
justify-content: center; justify-content: center;
background: url('@/assets/business_basic/background1.png') no-repeat center center;
background-size: 100% auto;
.imagePlaceholder { .blockContent {
// background-color: pink;
font-size: 12px;
color: #666666;
font-weight: 400;
width: 100%;
height: 100%;
}
// 新的6个横向块样式
.backgroundContainer {
width: 100%;
height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px;
.infoBlock {
width: 100%;
display: flex;
justify-content: flex-start;
white-space: nowrap;
.nameText {
font-size: 12px;
font-weight: 500;
color: #333333;
margin-left: 10px;
margin-right: 10px;
margin-top: 15px;
}
.unitText {
font-size: 10px;
font-weight: 400;
color: #666666;
margin-top: 18px;
}
.infoIcon {
font-size: 10px;
color: #666666;
margin-left: 10px;
margin-right: 10px;
}
.infoText {
font-size: 10px;
font-weight: 400;
color: #666666;
}
}
.tagContainer {
display: flex;
gap: 8px;
align-items: center;
}
.tagBlue1 {
background-color: #D5E5FF;
color: #1269FF;
font-size: 10px;
font-weight: 400;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
margin-left: 10px;
}
.tagBlue2 {
background-color: #D5E5FF;
color: #1269FF;
font-size: 10px;
font-weight: 400;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
}
.tagBlue3 {
background-color: #D5E5FF;
color: #1269FF;
font-size: 10px;
font-weight: 400;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
margin-left: 10px;
}
.tagYellow {
background-color: #FFF8E2;
color: #FFC403;
font-size: 10px;
font-weight: 400;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
}
.actionBlock {
width: 100%;
height: 50%;
background-color: #BDD6FDCC;
display: flex;
align-items: center;
justify-content: center;
}
.buttonContainer {
display: flex;
gap: 15px;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
height: 100%;
background-color: #f5f5f5;
border: 2px dashed #d9d9d9;
border-radius: 4px;
.imageIcon { .editBtn {
font-size: 48px; height: 80%;
margin-bottom: 10px; background-color: #1269FF;
color: #fff;
font-size: 10px;
font-weight: 400;
border: none;
border-radius: 2px;
cursor: pointer;
padding: 2px 15px;
&:hover {
background-color: #0f5ae0;
}
} }
.imageText { .deleteBtn {
font-size: 14px; height: 80%;
color: #999999; background-color: #FF5F60;
color: #fff;
font-size: 10px;
font-weight: 400;
border: none;
border-radius: 2px;
cursor: pointer;
padding: 2px 15px;
&:hover {
background-color: #ff4a4b;
}
}
}
}
} }
} }
} }
@ -215,7 +426,7 @@
background-color: white; background-color: white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
padding: 15px; padding: 5px 15px;
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
border-radius: 4px; border-radius: 4px;
@ -266,7 +477,7 @@
gap: 8px; gap: 8px;
:global(.ant-btn) { :global(.ant-btn) {
height: 32px; height: 28px;
padding: 0 16px; padding: 0 16px;
border-radius: 4px; border-radius: 4px;
font-size: 14px; font-size: 14px;
@ -325,6 +536,7 @@
.rightTopSelect { .rightTopSelect {
// 下拉框本身的样式 // 下拉框本身的样式
:global(.ant-select-selector) { :global(.ant-select-selector) {
background-color: #f8f9fa !important; background-color: #f8f9fa !important;

File diff suppressed because it is too large Load Diff

@ -1,240 +1,417 @@
.risk-assessment { .Rcontainer {
padding: 20px; padding: 8px 6px 0px 6px;
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
.ant-card { // 第一个div - 高度20%
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); .RcontainerTop {
border-radius: 6px; height: 16%;
// background-color: #fff;
border-radius: 4px;
display: flex;
flex-direction: column;
.ant-card-head { .sectionContent {
border-bottom: 1px solid #f0f0f0; height: 100%;
display: flex;
flex-direction: column;
// padding: 15px;
.ant-card-head-title { .blocksContainer {
font-size: 16px; flex: 1;
font-weight: 600; display: flex;
color: #262626; gap: 10px;
} height: 100%;
}
.ant-card-body { .blockItem {
padding: 20px; flex: 1;
} height: 100%;
} display: flex;
background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 92.55%);
border-radius: 4px;
border: 2px solid #FFFFFF;
.ant-table { .blockLeft {
.ant-table-thead > tr > th { width: 60%;
background-color: #fafafa; height: 100%;
font-weight: 600; display: flex;
color: #262626; flex-direction: column;
border-bottom: 1px solid #f0f0f0; justify-content: center;
} padding: 15px;
padding-left: 20px;
gap: 8px;
.ant-table-tbody > tr > td { .blockTitle {
border-bottom: 1px solid #f0f0f0; font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
line-height: 1.2;
} }
.ant-table-tbody > tr:hover > td { .blockNumber {
background-color: #f5f5f5; font-family: PingFang SC;
} font-weight: 700;
font-size: 24px;
color: #333333;
line-height: 1.2;
} }
.ant-btn { .blockChange {
border-radius: 4px; font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #1269FF;
line-height: 1.2;
display: flex;
align-items: center;
gap: 4px;
&.ant-btn-primary { .arrow {
background-color: #1890ff; font-size: 14px;
border-color: #1890ff; font-weight: bold;
}
&:hover { .checkIcon {
background-color: #40a9ff; font-size: 16px;
border-color: #40a9ff; color: #1269FF;
}
} }
} }
&.ant-btn-link { .blockRight {
padding: 4px 8px; flex: 1;
height: auto; height: 100%;
background-color: transparent;
border-radius: 0 4px 4px 0;
display: flex;
align-items: center;
justify-content: center;
&:hover { .blockImage {
background-color: #f5f5f5; // width: 80%;
height: 130%;
// height: 80%;
object-fit: contain;
margin-right: -10px;
}
}
}
} }
} }
} }
.ant-tag { // 第二个div - 高度30%
.RcontainerMiddle {
height: 30%;
border-radius: 4px; border-radius: 4px;
font-size: 12px; display: flex;
padding: 2px 8px; flex-direction: column;
}
.sectionContent {
height: 100%;
display: flex;
display: flex;
gap: 10px;
height: 100%;
.ant-rate {
.middleBlock1 {
flex: 1;
height: 100%;
background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
border: 2px solid #fff;
border-radius: 4px;
position: relative;
padding: 0px 10px 10px 2px;
font-family: PingFang SC;
font-size: 14px; font-size: 14px;
color: #333333;
.ant-rate-star { .block1Header {
margin-right: 2px; position: absolute;
top: 5px;
left: 10px;
right: 10px;
display: flex;
justify-content: space-between;
align-items: center;
z-index: 10;
.block1Title {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
} }
} }
.ant-progress { .block1Select {
.ant-progress-bg { width: 100px;
border-radius: 2px;
:global(.ant-select-selector) {
height: 28px !important;
font-size: 12px !important;
} }
&.ant-progress-small { :global(.ant-select-selection-item) {
.ant-progress-text { line-height: 26px !important;
font-size: 10px; font-size: 12px !important;
} }
} }
} }
.ant-modal { .riskLegend {
.ant-modal-header { position: absolute;
border-bottom: 1px solid #f0f0f0; Top: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
z-index: 10;
.ant-modal-title { .legendItem {
font-size: 16px; display: flex;
font-weight: 600; align-items: center;
color: #262626; gap: 5px;
}
}
.ant-modal-body { .legendDot {
padding: 24px; width: 8px;
height: 8px;
border-radius: 50%;
} }
.ant-form-item-label > label { .legendText {
font-weight: 500; font-size: 12px;
color: #262626; color: #333;
font-weight: 400;
}
} }
.ant-input,
.ant-select-selector {
border-radius: 4px;
border: 1px solid #d9d9d9;
&:hover {
border-color: #40a9ff;
} }
&:focus, .block1Chart {
&.ant-select-focused .ant-select-selector { width: 100%;
border-color: #40a9ff; height: 100%;
box-shadow: 0 0 0 2px rgba(24, 144, 255, 0.2); margin-top: 20px;
.mapImage {
margin-top: 7%;
width: 90%;
height: 77%;
object-fit: cover;
border-radius: 4px;
display: block;
margin-left: auto;
margin-right: auto;
} }
} }
} }
.ant-pagination { .middleBlock2 {
margin-top: 16px; flex: 1;
text-align: right; height: 100%;
// background: linear-gradient(170.5deg, #EBEFF4 6.87%, #FFFFFF 53.01%);
// border: 2px solid #fff;
background-color: #fff;
// border-radius: 4px;
display: flex;
flex-direction: column;
font-family: PingFang SC;
font-size: 14px;
color: #333333;
padding: 5px 10px 5px 10px;
.middleBlock2Title {
display: flex;
justify-content: space-between;
align-items: center;
// margin-bottom: 10px;
.ant-pagination-total-text { .titleLeft {
color: #8c8c8c; display: flex;
margin-right: 16px; align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
} }
} }
// 风险等级颜色 .titleRight {
.risk-level-high { display: flex;
color: #ff4d4f; align-items: center;
font-weight: 600; gap: 8px;
font-size: 12px;
color: #666;
}
} }
.risk-level-medium { .middleBlock2Chart {
color: #faad14; width: 100%;
font-weight: 600; height: 100%;
// min-height: 200px;
}
} }
.risk-level-low {
color: #52c41a;
font-weight: 600;
} }
}
// 第三个div - 占满剩余位置
.RcontainerBottom {
flex: 1; // 占满剩余空间
display: flex;
flex-direction: column;
// 状态指示器 .sectionContent {
.status-indicator { display: flex;
display: inline-flex; flex-direction: row;
gap: 10px;
padding: 0;
.leftBlock {
width: 30%;
height: 100%;
background: url('@/assets/safe_majorHazard/online_monitoring/risk3.png') no-repeat center center;
background-size: cover;
padding: 0;
display: flex;
flex-direction: column;
gap: 10px;
padding: 15px;
.leftBlockTitle {
display: flex;
align-items: center; align-items: center;
gap: 4px; gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
&.processed { .titleIcon {
color: #52c41a; width: 3px;
height: 16px;
background-color: #2E4CD4;
} }
&.pending {
color: #ff4d4f;
} }
&.monitoring { .leftBlockImage {
color: #1890ff; height: 40%;
} width: 100%;
border-radius: 4px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 80%;
} }
// 评分显示 .leftBlockItem {
.score-display { flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; justify-content: center;
gap: 4px; padding: 10px;
// background-color: #f5f5f5;
border-radius: 4px;
font-family: PingFang SC;
.score-value { .itemTitle {
font-weight: 600; font-size: 12px;
font-size: 14px; color: #666666;
margin-bottom: 5px;
} }
.score-label { .itemValue {
font-size: 12px; font-size: 14px;
color: #8c8c8c; color: #333333;
font-weight: 500;
}
} }
} }
// 概率和影响程度显示 .rightBlock {
.rate-display { width: 68%;
height: 100%;
background-color: #fff;
padding: 0;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
.tableHeader {
display: flex;
justify-content: space-between;
align-items: center; align-items: center;
gap: 4px; padding: 8px 15px 5px 15px;
.rate-stars { .tableTitle {
display: flex; display: flex;
align-items: center; align-items: center;
gap: 2px; gap: 8px;
} font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
.rate-text { .titleIcon {
font-size: 12px; width: 3px;
color: #8c8c8c; height: 16px;
background-color: #2E4CD4;
}
} }
} }
// 风险矩阵样式 .tableContainer {
.risk-matrix { flex: 1;
display: grid; overflow: hidden;
grid-template-columns: repeat(5, 1fr);
gap: 8px;
margin: 16px 0;
.matrix-cell { :global(.ant-table) {
padding: 8px;
text-align: center;
border: 1px solid #d9d9d9;
border-radius: 4px;
font-size: 12px; font-size: 12px;
}
:global(.ant-table-thead > tr > th) {
background-color: #f5f5fa;
font-weight: 500;
font-size: 14px;
color: #333333;
border-bottom: 1px solid #f0f0f0;
padding: 8px 12px;
text-align: center;
}
&.high-risk { :global(.ant-table-tbody > tr > td) {
background-color: #fff2f0; padding: 8px 12px;
border-color: #ff4d4f; border-bottom: 1px solid #f0f0f0;
color: #ff4d4f; text-align: center;
} }
&.medium-risk { :global(.ant-table-tbody > tr:hover > td) {
background-color: #fffbe6; background-color: #f5f5f5;
border-color: #faad14;
color: #faad14;
} }
&.low-risk { :global(.ant-pagination) {
background-color: #f6ffed; margin-top: 16px;
border-color: #52c41a; text-align: right;
color: #52c41a; }
}
} }
} }
} }

Loading…
Cancel
Save