Compare commits

...

20 Commits

Author SHA1 Message Date
wangyunfei 6ca46c43ae Merge commit '3ba0223' 1 month ago
wangyunfei 3ba0223f85 提交 1 month ago
wangyunfei 260445d936 提交 1 month ago
wangyunfei 3edb0804ae 1 1 month ago
wangyunfei 44f658e032 图表 1 month ago
wangyunfei 653a9dac0b 风险管控 1 month ago
wangyunfei 4d91bf0039 页面 1 month ago
wangyunfei bb60fcc834 Merge branch 'main' of http://39.174.50.29:15300/jiangxucong/dq-sms into HEAD 1 month ago
wangyunfei 01c7b3694d 1 1 month ago
wangyunfei 868d62b4d5 上传 1 month ago
wangyunfei 64ca98f4e1 1 1 month ago
wangyunfei 0ca0c0d490 在线监测预警页面开发 1 month ago
wangyunfei e99dce364a 图表样式 1 month ago
wangyunfei 2b91701228 图表 1 month ago
wangyunfei 82b1d1d7bf 样式修改 1 month ago
wangyunfei 3b41e0031f 监测 1 month ago
wangyunfei c0141e56cf 责任落实页面开发 1 month ago
wangyunfei 280b691256 重大危险源框架 1 month ago
wangyunfei 09999716dc 重大危险源 1 month ago
wangyunfei f243a9d7de 重大危险源顶部 1 month ago

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 485 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

@ -27,7 +27,7 @@ class StandardTable extends PureComponent {
static getDerivedStateFromProps(nextProps) {
// clean state
if (nextProps.selectedRows.length === 0) {
if (nextProps.selectedRows && nextProps.selectedRows.length === 0) {
const needTotalList = initTotalList(nextProps.columns);
return {
selectedRowKeys: [],

@ -1,860 +1,66 @@
import React, {Fragment, PureComponent} from 'react';
import {
DeleteOutlined,
EditOutlined,
PlusOutlined,
SearchOutlined,
RedoOutlined,
DownOutlined,
ExclamationCircleFilled,
UpOutlined,
} from '@ant-design/icons';
import {connect, history} from '@umijs/max';
import {Button, Card, Divider, Dropdown, message, Modal, Popconfirm, Space, Switch, Tag,Row,Col} from 'antd';
import StandardTable from '@/components/StandardTable';
import React, { useState } from 'react';
import { Card, Row, Col, Statistic, Progress, Button, Space } from 'antd';
import styles from './SafeMajorHazardList.less';
import ResponsibilityImplementation from './module/ResponsibilityImplementation'; //责任落实
import OnlineMonitoring from './module/OnlineMonitoring'; //在线监测预警
import RiskAssessment from './module/RiskAssessment'; //风险管控
import EvaluationReport from './module/EvaluationReport'; //评估报告
import { MyIcon } from "@/components/Icon"
import style from "@/global.less";
import StaffSheetCreateForm from './form/StaffSheetCreateForm'; //新增表单
import StaffSheetUpdateForm from './form/StaffSheetUpdateForm'; //修改表单
import StaffSheetViewForm from './form/StaffSheetViewForm'; //查看表单
import StaffSheetRenderSimpleForm from './form/StaffSheetRenderSimpleForm'; //简单查询表单
import StaffSheetRenderAdvancedForm from './form/StaffSheetRenderAdvancedForm'; //高级查询表单
import styles from './StaffSheetList.less';
import datadictionary from "@/utils/dataDictionary";
import {formatDate} from "@/utils/formatUtils";
import { formatDictText, checkButtonAuthority } from "@/utils/globalCommon";
const { confirm } = Modal;
//预约类型
const sex_type = datadictionary.sex
const user_status = datadictionary.user_status
const sys_user_post = datadictionary.sys_user_post
const mockData = {
list: [
{
gx: "--",
gslx: "排班",
ks: "中医科",
lc: "11",
kssj: "08:00",
jssj: "18:00",
cxsc: "8",
sjly: ""
},
{
gx: "--",
gslx: "考勤",
ks: "中医科",
lc: "11",
kssj: "07:00",
jssj: "20:00",
cxsc: "11",
sjly: ""
},
{
gx: "照顾A",
gslx: "照顾",
ks: "中医科",
lc: "11",
kssj: "09:00",
jssj: "10:00",
cxsc: "1",
sjly: "人工上传"
},
{
gx: "照顾B",
gslx: "照顾",
ks: "中医科",
lc: "11",
kssj: "10:00",
jssj: "11:00",
cxsc: "1",
sjly: "人工上传"
},
{
gx: "照顾C",
gslx: "照顾",
ks: "中医科",
lc: "11",
kssj: "11:00",
jssj: "13:00",
cxsc: "2",
sjly: "人工上传"
},
{
gx: "接病人D",
gslx: "接送",
ks: "急诊",
lc: "1",
kssj: "14:00",
jssj: "16:00",
cxsc: "2",
sjly: "his"
},
{
gx: "照顾A",
gslx: "照顾",
ks: "心脏内科",
lc: "9",
kssj: "16:00",
jssj: "18:00",
cxsc: "2",
sjly: "his"
},
{
gx: "送病人B",
gslx: "接送",
ks: "急诊",
lc: "1",
kssj: "18:00",
jssj: "20:00",
cxsc: "2",
sjly: "his"
},
{
gx: "照顾C",
gslx: "照顾",
ks: "中医科",
lc: "11",
kssj: "20:00",
jssj: "21:00",
cxsc: "1",
sjly: "系统采集"
},
],
pagination: {},
}
@connect(({ staffsheet, loading }) => ({
staffsheet,
loading: loading.models.staffsheet,
}))
const SafeMajorHazardList = () => {
const [activeModule, setActiveModule] = useState('responsibility');
class StaffSheetList extends PureComponent {
state = {
modalVisible: false,
updateModalVisible: false,
viewModalVisible: false,
expandForm: false,
selectedRows: [],
formValues: {},
updateFormValues: {},
viewFormValues: {},
toggleExpand: false,
const handleModuleClick = (module) => {
setActiveModule(module)
}
columns = [
{
title: '工序',
dataIndex: 'gx',
key: 'gx',
width: 80,
fixed: 'left',
}, {
title: '工时类型',
dataIndex: 'gslx',
key: 'gslx',
width: 100,
fixed: 'left',
},{
title: '科室',
dataIndex: 'ks',
key: 'ks',
width: 80,
}, {
title: '楼层',
dataIndex: 'lc',
key: 'lc',
width: 80,
},{
title: '开始时间',
dataIndex: 'kssj',
key: 'kssj',
width: 100,
}, {
title: '结束时间',
dataIndex: 'jssj',
key: 'jssj',
width: 100,
}, {
title: '持续时长(小时)',
dataIndex: 'cxsc',
key: 'cxsc',
width: 100,
},
{
title: <div className={styles.timeGraphic}>
<span>6</span>
<span>7</span>
<span>8</span>
<span>9</span>
<span>10</span>
<span>11</span>
<span>12</span>
<span>13</span>
<span>14</span>
<span>15</span>
<span>16</span>
<span>17</span>
<span>18</span>
<span>19</span>
<span>20</span>
<span>21</span>
<span>22</span>
<span>23</span>
<span>0</span>
<span>1</span>
<span>2</span>
<span>3</span>
<span>4</span>
<span>5</span>
</div>,
dataIndex: 'tj',
key: 'tj',
width: 750,
render: (text, record,index) => {
console.log(record,77777)
if(index == 0) {
return (
<Fragment>
<div className={styles.pbsjStyle}></div>
<div className={styles.pbsjStyle} style={{marginLeft: 73}}></div>
</Fragment>
)
} else if(index == 1) {
return (
<Fragment>
<div className={styles.kqsjStyle}></div>
<div className={styles.kqsjStyle} style={{marginLeft: 36,width: 232}}></div>
</Fragment>
)
} else if(index == 2) {
return (
<Fragment>
<div className={styles.xzStyle}></div>
<div className={styles.zjgsStyle}></div>
</Fragment>
)
} else if(index == 3) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 118}}></div>
</Fragment>
)
} else if(index == 4) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 148, width: 60}}></div>
</Fragment>
)
} else if(index == 5) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 246, width: 60}}></div>
</Fragment>
)
} else if(index == 6) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 310, width: 60}}></div>
</Fragment>
)
} else if(index == 7) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 370, width: 60}}></div>
</Fragment>
)
} else if(index == 8) {
return (
<Fragment>
<div className={styles.zjgsStyle} style={{marginLeft: 430, width: 30}}></div>
</Fragment>
)
}
}
},
{
title: '数据来源',
dataIndex: 'sjly',
key: 'sjly',
width: 100,
},
{
title: '操作',
fixed: 'right',
width: 100,
render: (text, record) => {
return (
<Fragment>
<a className={style.iconstyle}> 修改 </a>
</Fragment>
)
}
},
]
componentDidMount() {
// const { dispatch, staffsheet: { params } } = this.props
// dispatch({
// type: 'timesheet/query_page_for_prouser',
// })
// this.setState({
// expandForm: params?.expandForm || false,
// })
}
handleStandardTableChange = (pagination, sorter) => {
const { dispatch } = this.props
const { formValues } = this.state
const params = {
currentPage: pagination.current,
pageSize: pagination.pageSize,
...formValues
}
sorter.field && (params.sorter = `${sorter.field}_${sorter.order}`)
// dispatch({
// type: 'prouser/query_page_for_prouser',
// payload: params
// })
}
handleFormReset = () => {
const { dispatch } = this.props
this.setState({
formValues: {}
})
// dispatch({
// type: 'prouser/query_page_for_prouser',
// payload: {
// resetFlag: true
// }
// })
}
toggleForm = () => {
const { expandForm } = this.state
this.setState({
expandForm: !expandForm
})
}
handleSelectRows = rows => {
this.setState({
selectedRows: rows
})
}
handleSearch = values => {
const { dispatch } = this.props
const { expandForm } = this.state
this.setState({
formValues: values
})
// dispatch({
// type: 'prouser/query_page_for_prouser',
// payload: {
// ...values,
// resetFlag: true,
// expandForm
// }
// })
}
handleModalVisible = flag => {
this.setState({
modalVisible: !!flag
})
}
handleUpdateModalVisible = (flag, record) => {
this.setState({
updateModalVisible: !!flag,
updateFormValues: record || {}
})
}
handleViewModalVisible = (flag, record) => {
this.setState({
viewModalVisible: !!flag,
viewFormValues: record || {}
})
}
handleAdd = fields => {
const { dispatch } = this.props
dispatch({
type: 'prouser/insert_for_prouser',
payload: {
user_id: fields.user_id,
user_name: fields.user_name,
user_name_cn: fields.user_name_cn,
user_name_en: fields.user_name_en,
password: fields.password,
email: fields.email,
phone: fields.phone,
landline: fields.landline,
sex: fields.sex,
avatar: fields.avatar,
sign: fields.sign,
tags: fields.tags,
id_card: fields.id_card,
birthday: fields.birthday,
job_status: fields.job_status,
hiredate: fields.hiredate,
departure_time: fields.departure_time,
user_type: fields.user_type,
emp_no: fields.emp_no,
access_card_no: fields.access_card_no,
country: fields.country,
province: fields.province,
city: fields.city,
address: fields.address,
work_addr: fields.work_addr,
floor: fields.floor,
inprovince: fields.inprovince,
// dept_code: fields.dept_code,
// dept_name: fields.dept_name,
inner_dept_code: fields.inner_dept_code,
org_code: fields.org_code,
org_name: fields.org_name,
inner_org_code: fields.inner_org_code,
posts: fields.posts,
wx_openid: fields.wx_openid,
wx_mpopenid: fields.wx_mpopenid,
wx_miniopenid: fields.wx_miniopenid,
wx_unionid: fields.wx_unionid,
mobile_imei: fields.mobile_imei,
device_num: fields.device_num,
al_taobao: fields.al_taobao,
al_alipay: fields.al_alipay,
al_dingding: fields.al_dingding,
is_system_user: fields.is_system_user,
mgr_type: fields.mgr_type,
pwd_security_level: fields.pwd_security_level,
pwd_update_date: fields.pwd_update_date,
last_login_ip: fields.last_login_ip,
last_login_date: fields.last_login_date,
freeze_date: fields.freeze_date,
freeze_cause: fields.freeze_cause,
zindex: fields.zindex,
wx_msg: fields.wx_msg,
email_msg: fields.email_msg,
system_msg: fields.system_msg,
remarks: fields.remarks,
status: fields.status,
creator: fields.creator,
create_date: fields.create_date,
updater: fields.updater,
update_date: fields.update_date
},
callback: (res) => {
if(res.success == true) {
message.success('添加成功')
this.handleModalVisible()
}
}
})
}
handleDeleteRecord = record => {
const { dispatch } = this.props
dispatch({
type: 'prouser/delete_by_primarykey_for_prouser',
payload: {
recordid: record.user_id
},
callback: res => {
if (res.success) {
message.success('删除成功')
this.setState({
selectedRows: []
})
}
}
})
}
handleUpdate = fields => {
const { dispatch } = this.props
dispatch({
type: 'prouser/update_for_prouser',
payload: {
user_id: fields.user_id,
user_name: fields.user_name,
user_name_cn: fields.user_name_cn,
user_name_en: fields.user_name_en,
password: fields.password,
email: fields.email,
phone: fields.phone,
landline: fields.landline,
sex: fields.sex,
avatar: fields.avatar,
sign: fields.sign,
tags: fields.tags,
id_card: fields.id_card,
birthday: fields.birthday,
job_status: fields.job_status,
hiredate: fields.hiredate,
departure_time: fields.departure_time,
user_type: fields.user_type,
emp_no: fields.emp_no,
access_card_no: fields.access_card_no,
country: fields.country,
province: fields.province,
city: fields.city,
address: fields.address,
work_addr: fields.work_addr,
floor: fields.floor,
inprovince: fields.inprovince,
// dept_code: fields.dept_code,
// dept_name: fields.dept_name,
inner_dept_code: fields.inner_dept_code,
org_code: fields.org_code,
org_name: fields.org_name,
inner_org_code: fields.inner_org_code,
posts: fields.posts,
wx_openid: fields.wx_openid,
wx_mpopenid: fields.wx_mpopenid,
wx_miniopenid: fields.wx_miniopenid,
wx_unionid: fields.wx_unionid,
mobile_imei: fields.mobile_imei,
device_num: fields.device_num,
al_taobao: fields.al_taobao,
al_alipay: fields.al_alipay,
al_dingding: fields.al_dingding,
is_system_user: fields.is_system_user,
mgr_type: fields.mgr_type,
pwd_security_level: fields.pwd_security_level,
pwd_update_date: fields.pwd_update_date,
last_login_ip: fields.last_login_ip,
last_login_date: fields.last_login_date,
freeze_date: fields.freeze_date,
freeze_cause: fields.freeze_cause,
zindex: fields.zindex,
wx_msg: fields.wx_msg,
email_msg: fields.email_msg,
system_msg: fields.system_msg,
remarks: fields.remarks,
status: fields.status,
creator: fields.creator,
create_date: fields.create_date,
updater: fields.updater,
update_date: fields.update_date
},
callback: (res) => {
if(res.success === true) {
message.success('修改成功')
this.handleUpdateModalVisible()
}
}
})
}
// 修改用户状态
handleUpdateUserStatus = (fields, status, msg) => {
const { dispatch } = this.props
confirm({
title: `确定要 ${ msg } 当前用户的吗?`,
icon: <ExclamationCircleFilled />,
onOk() {
dispatch({
type: 'prouser/update_for_prouser',
payload: {
user_id: fields.user_id,
status: status,
},
callback: (res) => {
if(res.success === true) {
message.success('修改成功')
}
}
})
}
})
}
// 修改用户密码
handleUpdateUserPassword = fields => {
const { dispatch } = this.props
confirm({
title: '确定要重置当前用户的密码吗?',
icon: <ExclamationCircleFilled />,
onOk() {
dispatch({
type: 'prouser/resetpwd_for_prouser',
payload: {
user_id: fields.user_id
},
callback: (res) => {
if(res.success === true) {
message.success('重置成功')
}
}
})
}
})
}
renderSimpleForm() {
const { staffsheet: { params } } = this.props
const parentMethods = {
handleSearch: this.handleSearch,
handleFormReset: this.handleFormReset,
toggleForm: this.toggleForm,
params
}
return <StaffSheetRenderSimpleForm {...parentMethods} />
}
renderAdvancedForm() {
const { dispatch, prouser: { selectDeptTree, selectOrganTree, params } } = this.props
const parentMethods = {
handleSearch: this.handleSearch,
handleFormReset: this.handleFormReset,
toggleForm: this.toggleForm,
dispatch: dispatch,
selectDeptTree: selectDeptTree,
selectOrganTree: selectOrganTree,
params
const renderModule = () => {
switch (activeModule) {
case 'responsibility':
return <ResponsibilityImplementation />;
case 'monitoring':
return <OnlineMonitoring />;
case 'risk':
return <RiskAssessment />;
case 'evaluation':
return <EvaluationReport />;
default:
return <ResponsibilityImplementation />;
}
return <StaffSheetRenderAdvancedForm {...parentMethods} />
}
renderForm() {
const { expandForm } = this.state
return expandForm ? this.renderAdvancedForm() : this.renderSimpleForm()
}
handleCollapse = () => {
const { toggleExpand } = this.state
this.setState({
toggleExpand: !toggleExpand
})
}
render() {
const {
staffsheet: {
data,
selectDeptTree,
selectOrganTree
},
loading,
dispatch
} = this.props
const {
selectedRows,
modalVisible,
updateModalVisible,
viewModalVisible,
updateFormValues,
viewFormValues,
toggleExpand
} = this.state
const parentMethods = {
handleAdd: this.handleAdd,
handleModalVisible: this.handleModalVisible,
dispatch: dispatch,
loading,
selectDeptTree: selectDeptTree,
selectOrganTree: selectOrganTree
}
const updateMethods = {
handleUpdateModalVisible: this.handleUpdateModalVisible,
handleUpdate: this.handleUpdate,
dispatch: dispatch,
loading,
selectDeptTree: selectDeptTree,
selectOrganTree: selectOrganTree
}
const viewMethods = {
handleViewModalVisible: this.handleViewModalVisible
}
return (
<>
<Card bordered={false}>
<div className={styles.proUsertableList}>
<div className={styles.proUsertableListForm}>{this.renderForm()}</div>
<Divider style={{ borderColor: '#cccccc',margin:0 }}>
<div className={styles.summaryButton} onClick={() => this.handleCollapse()}>
{toggleExpand ? <><UpOutlined /> 收起</> : <><DownOutlined /> 展开</>}
</div>
</Divider>
<div style={{display: toggleExpand?'block':'none'}}>
<div className={styles.summaryContent}>
<div style={{paddingLeft: 0}}>
<div className={styles.titleLabel}>名称</div>
<div className={styles.titleVal}>张三</div>
</div>
<div>
<div className={styles.titleLabel}>考勤类型</div>
<div className={styles.titleVal}>排班制</div>
</div>
<div>
<div className={styles.titleLabel}>出勤人效(/小时)</div>
<div className={styles.titleVal}>10000</div>
</div>
<div>
<div className={styles.titleLabel}>作业人效(/小时)</div>
<div className={styles.titleVal}>12000</div>
</div>
<div>
<div className={styles.titleLabel}>人效出勤工时(小时)</div>
<div className={styles.titleVal}>8</div>
</div>
<div>
<div className={styles.titleLabel}>出勤工时占比(%)</div>
<div className={styles.titleVal}>100%</div>
</div>
</div>
<div className={styles.summaryContent}>
<div style={{paddingLeft: 0}}>
<div className={styles.titleLabel}>工号</div>
<div className={styles.titleVal}>123456</div>
</div>
<div>
<div className={styles.titleLabel}>在职时长(小时)</div>
<div className={styles.titleVal}>1200</div>
</div>
<div>
<div className={styles.titleLabel}>外出就餐时长(小时)</div>
<div className={styles.titleVal}>0</div>
</div>
<div>
<div className={styles.titleLabel}>直接作业工时(小时)</div>
<div className={styles.titleVal}>7</div>
</div>
<div>
<div className={styles.titleLabel}>间接作业工时(小时)</div>
<div className={styles.titleVal}>1</div>
</div>
<div>
<div className={styles.titleLabel}>闲置工时(小时)</div>
<div className={styles.titleVal}>0</div>
</div>
</div>
<div className={styles.summaryContent}>
<div style={{paddingLeft: 0}}>
<div className={styles.titleLabel}>工作性质</div>
<div className={styles.titleVal}>外包</div>
</div>
<div>
<div className={styles.titleLabel}>总件数()</div>
<div className={styles.titleVal}>9000</div>
</div>
<div>
<div className={styles.titleLabel}>离岗休息时长(小时)</div>
<div className={styles.titleVal}>0</div>
</div>
<div>
<div className={styles.titleLabel}>直接作业工时占比(%)</div>
<div className={styles.titleVal}>84</div>
</div>
<div>
<div className={styles.titleLabel}>闲置工时占比(%)</div>
<div className={styles.titleVal}>0</div>
</div>
<div>
<div className={styles.titleLabel}>闲置工时(小时)</div>
<div className={styles.titleVal}>0</div>
</div>
</div>
</div>
<div className={styles.operateContent}>
<div>
<Button type='primary' style={{marginRight: 50}}>
同步
</Button>
<Button type='primary' danger>
考勤排查
</Button>
</div>
<div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#faf07a'}}></div>
排班时间
</div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#9cc5fc'}}></div>
考勤时间
</div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#aa02cf'}}></div>
修改状态
</div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#454545'}}></div>
闲置工时
</div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#8ddd15'}}></div>
直接工时
</div>
<div style={{display: 'inline-block'}}>
<div className={styles.workClass} style={{background: '#cecece'}}></div>
离岗休息
</div>
</div>
</div>
<div style={{display: 'flex',justifyContent: "space-between"}}>
<div>共20项</div>
</div>
<StandardTable
rowKey={'user_id'}
selectedRows={selectedRows}
loading={loading}
data={mockData}
columns={this.columns}
onSelectRow={this.handleSelectRows}
onChange={this.handleStandardTableChange}
scroll={{ x: 1000,y: 600 }}
showTotal={(total, range) => total}
/>
</div>
</Card>
{modalVisible && <StaffSheetCreateForm {...parerntMethods} modalVisible={modalVisible} />}
{updateFormValues && Object.keys(updateFormValues).length ? (
<StaffSheetUpdateForm
{...updateMethods}
updateModalVisible={updateModalVisible}
values={updateFormValues}
/>
) : null}
{viewFormValues && Object.keys(viewFormValues).length ? (
<StaffSheetViewForm
{...viewMethods}
viewModalVisible={viewModalVisible}
values={viewFormValues}
/>
) : null}
</>
)
}
}
export default StaffSheetList
};
return (
<div className={styles.container}>
<div className={styles.TopButton}>
<Button
className={`${styles.TopButtonItem} ${activeModule === "responsibility" ? styles.active : ""}`}
onClick={() => handleModuleClick("responsibility")}
>责任落实
</Button>
<Button
className={`${styles.TopButtonItem} ${activeModule === "monitoring" ? styles.active : ""}`}
onClick={() => handleModuleClick("monitoring")}
>在线监测预警
</Button>
<Button
className={`${styles.TopButtonItem} ${activeModule === "risk" ? styles.active : ""}`}
onClick={() => handleModuleClick("risk")}
>风险管控
</Button>
<Button
className={`${styles.TopButtonItem} ${activeModule === "evaluation" ? styles.active : ""}`}
onClick={() => handleModuleClick("evaluation")}
>评估报告及隐患处理
</Button>
</div>
<div className={styles.content}>
{renderModule()}
</div>
</div>
);
};
export default SafeMajorHazardList;

@ -0,0 +1,48 @@
.container {
background-color: transparent;
width: 100%;
height: 89vh;
overflow: hidden;
display: flex;
flex-direction: column;
.TopButton {
display: flex;
gap: 24px;
margin-left: 6px;
.TopButtonItem {
background-color: transparent !important;
color: #333333 !important;
font-size: 14px !important;
border-radius: 8px !important;
padding: 6px 10px !important;
height: auto !important;
border: none !important;
line-height: 1.2 !important;
box-shadow: none !important;
&:hover {
color: #333333 !important;
border: none !important;
}
&:focus {
background-color: #2E4CD4 !important;
color: #fff !important;
}
&.active {
background-color: #2E4CD4 !important;
color: #fff !important;
}
}
}
.content {
// ======== 内容区域样式 ========
flex: 1; // ======== 占据剩余空间 ========
overflow-y: auto; // ======== 允许垂直滚动 ========
padding: 0; // ======== 无内边距 ========
}
}

@ -1,128 +0,0 @@
@import '~@/utils/utils.less';
.proUsertableList {
.proUsertableListOperator {
margin-bottom: 16px;
button {
margin-right: 8px;
}
}
.editColumn {
> div:last-child {
display: none;
}
}
}
.proUsertableListForm {
height: 45px;
:global {
.ant-form-item {
display: flex;
margin-right: 0;
margin-bottom: 24px;
.ant-form-item-label {
// width: 80px;
// padding-right: 8px;
line-height: 32px;
text-align: left;
}
.ant-form-item-control {
line-height: 32px;
width: calc(100% - 80px);
.ant-form-item-control-input-content {
height: 32px;
}
}
> .ant-row {
flex-wrap: nowrap;
}
}
.ant-form-item-control-wrapper {
flex: 1;
}
}
}
.summaryButton {
width: 80px;
height: 30px;
line-height: 30px;
font-size: 12px;
background-color: #eff1f3;
border-radius: 20px;
cursor: pointer;
}
.summaryContent {
display: flex;
margin-top: 10px;
> div {
flex: 2;
height: 60px;
border-right: 2px solid #eeeeee;
padding-left: 10px;
// background-color: #1890FF
}
.titleLabel {
color: #b2b2b2;
font-weight: 500;
margin-bottom: 10px;
}
.titleVal {
font-weight: 500;
}
}
.operateContent {
display: flex;
margin: 20px 0;
justify-content: space-between;
.workClass {
display: inline-block;
width: 10px;
height: 10px;
margin-left: 10px;
}
}
.pbsjStyle {
display: inline-block;
width: 120px;
height: 40px;
margin-left: 56px;
background-color: #faf07a;
}
.kqsjStyle {
display: inline-block;
width: 180px;
height: 40px;
margin-left: 29px;
background-color: #9cc5fc;
}
.xzStyle {
display: inline-block;
width: 60px;
height: 40px;
margin-left: 29px;
background-color: #454545;
}
.zjgsStyle {
display: inline-block;
width: 30px;
height: 40px;
background-color: #8ddd15;
}
.timeGraphic {
span {
padding: 0 10px;
}
}

@ -0,0 +1,634 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, CheckCircleOutlined, Button } from 'antd';
import * as echarts from 'echarts';
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 EvaluationReport = () => {
const trendChartRef = useRef(null);
const pieChartRef = useRef(null);
const barChartRef = useRef(null);
// 表格相关状态
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 5,
total: 0,
});
// 隐患趋势分析折线图
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: [
{
name: '重大隐患',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: '#FF4D4F'
},
itemStyle: {
color: '#FF4D4F',
borderColor: '#FF4D4F',
borderWidth: 2
},
data: [12, 8, 15, 10, 18, 14, 20, 16, 22, 19, 25, 21]
},
{
name: '一般隐患',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: '#FAAD14'
},
itemStyle: {
color: '#FAAD14',
borderColor: '#FAAD14',
borderWidth: 2
},
data: [25, 30, 28, 35, 32, 38, 40, 36, 42, 38, 45, 41]
},
{
name: '轻微隐患',
type: 'line',
smooth: true,
symbol: 'circle',
symbolSize: 6,
lineStyle: {
width: 2,
color: '#52C41A'
},
itemStyle: {
color: '#52C41A',
borderColor: '#52C41A',
borderWidth: 2
},
data: [45, 50, 48, 55, 52, 58, 60, 56, 62, 58, 65, 61]
}
]
};
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();
}
};
}
}, []);
// 隐患类型分布玫瑰饼图
useEffect(() => {
if (pieChartRef.current) {
const chart = echarts.init(pieChartRef.current);
const option = {
color: ['#FF4D4F', '#FAAD14', '#52C41A', '#1890FF', '#722ED1', '#13C2C2'],
legend: {
orient: 'vertical',
left: 'left',
top: 'center',
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: '其他' }
]
}
]
};
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();
}
};
}
}, []);
// 隐患整改情况柱状图
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 = [
{
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: '报告名称',
dataIndex: 'reportName',
key: 'reportName',
width: 200,
},
{
title: '类型',
dataIndex: 'type',
key: 'type',
width: 120,
},
{
title: '上传时间',
dataIndex: 'uploadTime',
key: 'uploadTime',
width: 150,
},
{
title: '版本',
dataIndex: 'version',
key: 'version',
width: 80,
},
{
title: '状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text) => {
const statusMap = {
'已完成': { color: '#52C41A', bg: '#F6FFED' },
'处理中': { 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: '上传人',
dataIndex: 'uploader',
key: 'uploader',
width: 100,
},
{
title: '操作',
key: 'action',
width: 80,
render: (_, record) => (
<div>
<Button type="link" size="small" style={{ padding: 0 }}>
下载
</Button>
</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 (
<div className={styles.Econtainer}>
{/* 第一个大块 - 高度16% */}
<div className={styles.EcontainerTop}>
<div className={styles.sectionContent}>
<div className={styles.blocksContainer}>
{/* 块1 */}
<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>
{/* 块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}
data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading}
selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{
...pagination,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total, range) =>
`${total}`,
}}
scroll={{ x: 1000 }}
/>
</div>
</div>
</div>
);
};
export default EvaluationReport;

@ -0,0 +1,225 @@
.Econtainer {
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;
}
.blockChange {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #1269FF;
line-height: 1.2;
display: flex;
align-items: center;
gap: 4px;
.arrow {
font-size: 14px;
font-weight: bold;
}
.checkIcon {
font-size: 16px;
color: #1269FF;
}
}
}
.blockRight {
flex: 1;
height: 100%;
background-color: transparent;
border-radius: 0 4px 4px 0;
display: flex;
align-items: center;
justify-content: center;
.blockImage {
height: 130%;
object-fit: contain;
margin-right: -10px;
}
}
}
}
}
}
// 第二个大块 - 三个图表块
.EcontainerMiddle {
height: 30%;
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;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.chartContainer {
flex: 1;
width: 100%;
height: 120%;
// // min-height: 200px;
}
}
}
}
// 第三大块 - 评估报告表格
.EcontainerBottom {
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;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
}
.tableContainer {
flex: 1;
overflow: hidden;
:global(.ant-table-wrapper) {
height: 100%;
}
:global(.ant-table) {
height: 100%;
}
:global(.ant-table-container) {
height: 100%;
}
:global(.ant-table-body) {
height: calc(100% - 55px); // 减去表头高度
overflow-y: auto;
}
: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;
}
:global(.ant-pagination) {
margin-top: 10px;
text-align: right;
}
}
}
}

@ -0,0 +1,715 @@
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 chartRef = useRef(null);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 5,
total: 0,
});
useEffect(() => {
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: [
{
name: '液位',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#04A7F3'
},
areaStyle: {
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]
},
{
name: '温度',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#E7C42C'
},
areaStyle: {
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]
},
{
name: '压力',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#EC6941'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 1,
x2: 0,
y2: 0,
colorStops: [
{ offset: 0, color: 'rgba(236, 105, 65, 0)' },
{ offset: 1, color: 'rgba(236, 105, 65, 0.3)' }
]
}
},
symbol: 'none',
data: [200, 300, 250, 450, 400, 430, 480, 420, 480, 280, 320, 260, 240]
}
]
};
chart.setOption(option);
// 响应式调整 - 使用ResizeObserver监听容器尺寸变化
let resizeTimer = null;
const handleResize = () => {
// 防抖处理避免频繁调用resize
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(() => {
chart.resize();
}, 100);
};
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
// 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
let resizeObserver = null;
if (window.ResizeObserver) {
resizeObserver = new ResizeObserver(() => {
// 使用setTimeout确保DOM更新完成后再调整图表
setTimeout(() => {
handleResize();
}, 0);
});
resizeObserver.observe(chartRef.current);
}
return () => {
window.removeEventListener('resize', handleResize);
if (resizeObserver) {
resizeObserver.disconnect();
}
if (resizeTimer) {
clearTimeout(resizeTimer);
}
chart.dispose();
};
}
}, []);
// 表格列定义
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: '报警时间',
dataIndex: 'alarmTime',
key: 'alarmTime',
width: 150,
},
{
title: '报警传感器名称',
dataIndex: 'sensorName',
key: 'sensorName',
width: 150,
},
{
title: '报警类型',
dataIndex: 'alarmType',
key: 'alarmType',
width: 120,
},
{
title: '报警内容',
dataIndex: 'alarmContent',
key: 'alarmContent',
width: 200,
},
{
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',
key: 'status',
width: 100,
render: (text) => {
const statusMap = {
'未处理': { color: '#FF4D4F', bg: '#FFF2F0' },
'处理中': { 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: '处理时间',
dataIndex: 'processTime',
key: 'processTime',
width: 150,
},
{
title: '处理人',
dataIndex: 'processor',
key: 'processor',
width: 100,
},
{
title: '操作',
key: 'action',
width: 120,
render: (_, record) => (
<div>
<Button type="link" size="small" style={{ padding: 0, marginRight: 8 }}>
查看
</Button>
</div>
),
},
];
// 模拟数据
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 (
<div className={styles.Ocontainer}>
<div className={styles.OcontainerTop}>
<div className={styles.OcontainerTopLeft}>
<div className={styles.OcontainerTopLeftTop}>
<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
type="primary"
onClick={handleBatchDelete}
>
<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}
data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading}
selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{
...pagination,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total, range) =>
`${total}`,
}}
scroll={{ x: 1200 }}
/>
</div>
</div>
</div>
);
};
export default OnlineMonitoring;

@ -0,0 +1,919 @@
.Ocontainer {
padding: 8px 6px 0px 6px;
height: 100%;
display: flex;
flex-direction: column;
.OcontainerTop {
display: flex;
height: 50%;
margin-bottom: 5px;
.OcontainerTopLeft {
width: 72%;
height: 100%;
// background-color: pink;
margin-right: 10px;
// display: flex;
.OcontainerTopLeftTop {
width: 100%;
height: 35%;
display: flex;
gap: 12px;
.alarmO {
flex: 1;
height: 100%;
background-color: #F4F7FF;
border: 1px solid #AED3FF;
border-bottom: 0px solid #AED3FF;
border-radius: 4px;
box-shadow: 0px 2px 31px 0px #5382FE33 inset;
display: flex;
.alarmOLeft {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.alarmORight {
flex: 1;
width: 35%;
height: 100%;
display: flex;
flex-direction: column;
margin-left: 2px;
gap: 18px;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 12px;
line-height: 100%;
letter-spacing: 0%;
color: #333333;
.alarmORightText1 {
margin-top: 15px;
}
.alarmORightText2 {
font-weight: 700;
font-size: 16px;
}
.alarmORightText3 {
display: flex;
gap: 22px;
}
}
}
.alarmTw {
flex: 1;
height: 100%;
background-color: #FFF5f4;
border: 1px solid #FFC5BC;
border-bottom: 0px solid #FFC5BC;
border-radius: 4px;
box-shadow: 0px 2px 31px 0px #FE5F4C33 inset;
display: flex;
.alarmTwLeft {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.alarmTwRight {
flex: 1;
width: 35%;
height: 100%;
display: flex;
flex-direction: column;
margin-left: 2px;
gap: 18px;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 12px;
line-height: 100%;
letter-spacing: 0%;
color: #333333;
.alarmTwRightText1 {
margin-top: 15px;
}
.alarmTwRightText2 {
font-weight: 700;
font-size: 16px;
}
.alarmTwRightText3 {
display: flex;
gap: 22px;
}
}
}
.alarmTh {
flex: 1;
height: 100%;
background-color: #FFF7F2;
border: 1px solid #FFD9B2;
border-bottom: 0px solid #FFD9B2;
border-radius: 4px;
box-shadow: 0px 2px 31px 0px #FD883C33 inset;
display: flex;
.alarmThLeft {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.alarmThRight {
flex: 1;
width: 35%;
height: 100%;
display: flex;
flex-direction: column;
margin-left: 2px;
gap: 18px;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 12px;
line-height: 100%;
letter-spacing: 0%;
color: #333333;
.alarmThRightText1 {
margin-top: 15px;
}
.alarmThRightText2 {
font-weight: 700;
font-size: 16px;
}
.alarmThRightText3 {
display: flex;
gap: 22px;
}
}
}
.alarmF {
flex: 1;
height: 100%;
background-color: #EFF9FF;
border: 1px solid #89E1FF;
border-bottom: 0px solid #89E1FF;
border-radius: 4px;
box-shadow: 0px 2px 31px 0px #22A4FD33 inset;
display: flex;
.alarmFLeft {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
.alarmFRight {
flex: 1;
width: 35%;
height: 100%;
display: flex;
flex-direction: column;
margin-left: 2px;
gap: 18px;
font-family: PingFang SC;
font-weight: 400;
font-style: Regular;
font-size: 12px;
line-height: 100%;
letter-spacing: 0%;
color: #333333;
.alarmFRightText1 {
margin-top: 15px;
}
.alarmFRightText2 {
font-weight: 700;
font-size: 16px;
}
.alarmFRightText3 {
display: flex;
gap: 22px;
}
}
}
}
.OcontainerTopLeftBottom {
margin-top: 12px;
background-color: #fff;
width: 100%;
height: 60%;
.OcontainerTopLeftBottomTitle {
display: flex;
justify-content: space-between;
align-items: center;
// padding: 8px 15px;
padding: 8px 15px 0px 15px;
.titleLeft {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-style: Medium;
font-size: 14px;
line-height: 100%;
letter-spacing: 0%;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
.titleRight {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-style: Medium;
font-size: 13px;
line-height: 100%;
letter-spacing: 0%;
.selectBox {
padding: 4px 8px;
border: 1px solid #d9d9d9;
border-radius: 4px;
background-color: #fff;
font-size: 12px;
color: #333;
outline: none;
&:focus {
border-color: #2E4CD4;
}
}
}
}
.OcontainerTopLeftBottomChart {
flex: 1;
width: 100%;
height: 75%;
}
}
}
.OcontainerTopRight {
flex: 1;
height: calc(100% - 3.3px);
background-color: #fff;
background-image: url('@/assets/safe_majorHazard/online_monitoring/backTopRight.png');
background-size: 100% auto;
display: flex;
flex-direction: column;
overflow-y: auto;
.realTimeDataHeader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 15px;
margin-bottom: 10px;
.titleLeft {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-style: Medium;
font-size: 14px;
line-height: 100%;
letter-spacing: 0%;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
.totalCount {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
color: #333333;
}
}
.dataItem {
height: 23%;
flex-shrink: 0;
border: 1px solid #89E1FF;
border-radius: 2px;
margin: 0 15px;
margin-bottom: 6px;
display: flex;
align-items: center;
justify-content: center;
font-family: PingFang SC;
font-size: 14px;
// color: #666;
background-color: #EFF9FF;
&:last-child {
// margin-bottom: 1px;
}
}
.dataItem1 {
height: 25%;
flex-shrink: 0;
border: 1px solid #89E1FF;
border-radius: 4px;
margin: 0 15px;
margin-bottom: 6px;
display: flex;
align-items: center;
padding: 0px 15px;
background-color: #EFF9FF;
.dataItemLeft {
width: 65%;
display: flex;
flex-direction: column;
gap: 8px;
.areaName {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
color: #333333;
line-height: 2.2;
}
.rValue {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #666666;
line-height: 0.2;
}
.codeNumber {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
}
}
.dataItemRight {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.circleContainer {
position: relative;
height: 80%;
aspect-ratio: 1; // 强制宽高比1:1
.outerCircle {
width: 100%;
height: 100%;
background-color: rgba(51, 176, 253, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
.innerCircle {
width: 70%;
height: 70%;
background-color: rgba(4, 128, 251, 0.8);
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.levelText {
font-family: PingFang SC;
font-weight: 500;
font-size: 11px;
color: #FFFFFF;
line-height: 1.4;
margin-top: -4px;
}
.riskText {
font-family: PingFang SC;
font-weight: 300;
font-size: 8px;
color: #FFFFFF;
line-height: 1;
}
}
}
}
}
}
.dataItem2 {
height: 25%;
flex-shrink: 0;
border: 1px solid rgba(255, 197, 188, 1);
border-radius: 4px;
margin: 0 15px;
margin-bottom: 6px;
display: flex;
align-items: center;
padding: 0px 15px;
background-color: #fff5f4;
.dataItemLeft {
width: 65%;
display: flex;
flex-direction: column;
gap: 8px;
.areaName {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
color: #333333;
line-height: 2.2;
}
.rValue {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #666666;
line-height: 0.2;
}
.codeNumber {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
}
}
.dataItemRight {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.circleContainer {
position: relative;
height: 80%;
aspect-ratio: 1;
.outerCircle {
width: 100%;
height: 100%;
background-color: rgba(254, 214, 209, 1);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
.innerCircle {
width: 70%;
height: 70%;
background-color: rgba(253, 41, 14, 1);
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.levelText {
font-family: PingFang SC;
font-weight: 500;
font-size: 11px;
color: #FFFFFF;
line-height: 1.4;
margin-top: -4px;
}
.riskText {
font-family: PingFang SC;
font-weight: 300;
font-size: 8px;
color: #FFFFFF;
line-height: 1;
}
}
}
}
}
}
.dataItem3 {
height: 25%;
flex-shrink: 0;
border: 1px solid rgba(255, 217, 178, 1);
border-radius: 4px;
margin: 0 15px;
margin-bottom: 6px;
display: flex;
align-items: center;
padding: 0px 15px;
background-color: #fef6f1;
.dataItemLeft {
width: 65%;
display: flex;
flex-direction: column;
gap: 8px;
.areaName {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
color: #333333;
line-height: 2.2;
}
.rValue {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #666666;
line-height: 0.2;
}
.codeNumber {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
}
}
.dataItemRight {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.circleContainer {
position: relative;
height: 80%;
aspect-ratio: 1;
.outerCircle {
width: 100%;
height: 100%;
background-color: rgba(255, 234, 218, 1);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
.innerCircle {
width: 70%;
height: 70%;
background-color: rgba(252, 103, 18, 1);
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.levelText {
font-family: PingFang SC;
font-weight: 500;
font-size: 11px;
color: #FFFFFF;
line-height: 1.4;
margin-top: -4px;
}
.riskText {
font-family: PingFang SC;
font-weight: 300;
font-size: 8px;
color: #FFFFFF;
line-height: 1;
}
}
}
}
}
}
.dataItem4 {
height: 25%;
flex-shrink: 0;
border: 1px solid #89E1FF;
border-radius: 4px;
margin: 0 15px;
margin-bottom: 6px;
display: flex;
align-items: center;
padding: 0px 15px;
background-color: #EFF9FF;
.dataItemLeft {
width: 65%;
display: flex;
flex-direction: column;
gap: 8px;
.areaName {
font-family: PingFang SC;
font-weight: 400;
font-size: 13px;
color: #333333;
line-height: 2.2;
}
.rValue {
font-family: PingFang SC;
font-weight: 400;
font-size: 14px;
color: #666666;
line-height: 0.2;
}
.codeNumber {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #666666;
}
}
.dataItemRight {
width: 35%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
.circleContainer {
position: relative;
height: 80%;
aspect-ratio: 1;
.outerCircle {
width: 100%;
height: 100%;
background-color: rgba(51, 176, 253, 0.3);
border-radius: 50%;
display: flex;
justify-content: center;
align-items: center;
.innerCircle {
width: 70%;
height: 70%;
background-color: rgba(4, 128, 251, 0.8);
border-radius: 50%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.levelText {
font-family: PingFang SC;
font-weight: 500;
font-size: 11px;
color: #FFFFFF;
line-height: 1.4;
margin-top: -4px;
}
.riskText {
font-family: PingFang SC;
font-weight: 300;
font-size: 8px;
color: #FFFFFF;
line-height: 1;
}
}
}
}
}
}
}
}
.OcontainerBottom {
background-color: #fff;
flex: 1;
padding: 8px 15px 5px 15px;
display: flex;
flex-direction: column;
.tableHeader {
display: flex;
justify-content: space-between;
align-items: center;
// margin-bottom: 15px;
padding-bottom: 5px;
// border-bottom: 1px solid #f0f0f0;
.tableTitle {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
.tableActions {
display: flex;
gap: 8px;
// 自定义按钮样式
:global(.ant-btn) {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
&:hover {
background-color: #f5f5f5 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:focus {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:active {
background-color: #e6e6e6 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
// 主要按钮样式
&.ant-btn-primary {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
&:hover {
background-color: #f5f5f5 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:focus {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:active {
background-color: #e6e6e6 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
}
// 危险按钮样式
&.ant-btn-dangerous {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
&:hover {
background-color: #f5f5f5 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:focus {
background-color: #ffffff !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
&:active {
background-color: #e6e6e6 !important;
border-color: #DFE4F6 !important;
color: #333333 !important;
box-shadow: none !important;
}
}
// 禁用状态
&:disabled {
background-color: #f5f5f5 !important;
border-color: #d9d9d9 !important;
color: #bfbfbf !important;
box-shadow: none !important;
}
}
}
}
.tableContainer {
flex: 1;
overflow: hidden;
:global(.ant-table) {
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;
}
:global(.ant-table-tbody > tr > td) {
padding: 8px 12px;
border-bottom: 1px solid #f0f0f0;
text-align: center;
}
:global(.ant-table-tbody > tr:hover > td) {
background-color: #f5f5f5;
}
:global(.ant-pagination) {
margin-top: 16px;
text-align: right;
}
}
}
}

@ -0,0 +1,139 @@
import React from 'react';
import { Card, Result, Timeline,Statistic, Table,Row, Input,Button,Col} from 'antd';
import StandardTable from '@/components/StandardTable';
import styles from './ResponsibilityImplementation.less';
const ResponsibilityImplementation = () => {
const columns = [
{
title:"编号",
dataIndex:"id",
key:"id",
width:60,
},
{
title:"责任区域",
dataIndex:"zrqy",
key:"zrqy",
width:120,
},
{
title:"设备型号",
dataIndex:"sbxh",
key:"sbxh",
width:120,
},
{
title:"危险源类型",
dataIndex:"wxlylx",
key:"wxlylx",
width:120,
},
{
title:"责任人",
dataIndex:"zrr",
key:"zrr",
width:120,
},
{
title:"联系方式",
dataIndex:"lxfs",
key:"lxfs",
width:120,
},
{
title:"巡检频率",
dataIndex:"xjpl",
key:"xjpl",
width:120,
},
{
title:"最近巡检",
dataIndex:"zjxj",
key:"zjxj",
width:120,
},
{
title:"状态",
dataIndex:"zt",
key:"zt",
width:120,
},
{
title:"操作",
dataIndex:"cz",
key:"cz",
width:120,
render: (text, record) => { // ======== 渲染操作列 ========
const handleView = (record) => { // ======== 定义查看函数 ========
console.log('查看记录:', record); // ======== 打印记录信息到控制台 ========
// 这里可以添加查看详情的逻辑 // ======== 注释:可以添加查看详情的逻辑 ========
}; // ======== 函数结束 ========
return ( // ======== 返回按钮组件 ========
<Button type="link" onClick={() => handleView(record)}>查看</Button> // ======== 查看按钮点击时调用handleView函数 ========
); // ======== return语句结束 ========
} // ======== render函数结束 ========
}
];
// 生成20条假数据
const generateMockData = () => { // ======== 定义生成假数据的函数 ========
const data = []; // ======== 创建空数组存储数据 ========
const areas = ['生产车间A区', '生产车间B区', '储罐区', '配电室', '锅炉房', '化学品仓库', '实验室', '办公区']; // ======== 责任区域选项 ========
const devices = ['压力容器', '储罐', '反应釜', '压缩机', '泵类设备', '电气设备', '管道系统', '安全阀']; // ======== 设备型号选项 ========
const statuses = ['正常', '维护中', '故障', '停用', '检修']; // ======== 状态选项 ========
const names = ['张三', '李四', '王五', '赵六', '孙七', '周八', '吴九', '郑十', '钱十一', '陈十二']; // ======== 责任人姓名选项 ========
for (let i = 1; i <= 20; i++) { // ======== 循环生成20条数据 ========
data.push({ // ======== 添加一条数据到数组 ========
key: i.toString(), // ======== 唯一标识 ========
id: `WX${String(i).padStart(3, '0')}`, // ======== 编号WX001, WX002... ========
zrqy: areas[Math.floor(Math.random() * areas.length)], // ======== 随机选择责任区域 ========
sbxh: devices[Math.floor(Math.random() * devices.length)], // ======== 随机选择设备型号 ========
zrr: names[Math.floor(Math.random() * names.length)], // ======== 随机选择责任人 ========
zt: statuses[Math.floor(Math.random() * statuses.length)], // ======== 随机选择状态 ========
}); // ======== 数据对象结束 ========
} // ======== 循环结束 ========
return data; // ======== 返回生成的数据数组 ========
}; // ======== 函数结束 ========
const tableData = generateMockData(); // ======== 调用函数生成假数据 ========
return (
<div className={styles.containerR}>
<div className={styles.containerOne}>
<div className={styles.containerOneLeft}>1</div>
<div className={styles.containerOneRight}>2</div>
</div>
<div className={styles.containerTwo}>
<div>重大危险源安全包信息库</div>
<div>
<Input placeholder="搜索危险源编号" />
<Button>新增责任人</Button>
<Button>导出清单</Button>
<StandardTable
columns={columns} // ======== 表格列配置 ========
data={{ // ======== 数据对象包含list和pagination ========
list: tableData, // ======== 表格数据列表 ========
pagination: { // ======== 分页配置 ========
currentPage: 1, // ======== 当前页码 ========
pageSize: 5, // ======== 每页显示10条数据 ========
total: tableData.length, // ======== 总数据条数 ========
} // ======== 分页配置结束 ========
}} // ======== 数据对象结束 ========
selectedRows={[]} // ======== 选中的行数据,初始为空数组 ========
onSelectRow={() => {}} // ======== 行选择事件处理函数 ========
onChange={() => {}} // ======== 表格变化事件处理函数 ========
/>
</div>
</div>
</div>
);
};
export default ResponsibilityImplementation;

@ -0,0 +1,30 @@
.containerR {
padding: 8px 6px;
height: 100%;
display: flex;
flex-direction: column;
.containerOne {
height: 30%;
display: flex;
margin-bottom: 12px;
background-color: aqua;
gap: 12px;
.containerOneLeft{
background-color: #999;
width:58%;
// margin-right: 12px;
}
.containerOneRight{
background-color: #999;
width:42%;
}
}
.containerTwo{
flex: 1;
background-color: blue;
}
}

@ -0,0 +1,719 @@
import React, { useEffect, useRef, useState } from 'react';
import { Card, Result, Select, Button } from 'antd';
import { CheckCircleOutlined } from '@ant-design/icons';
import * as echarts from 'echarts';
import StandardTable from '@/components/StandardTable';
import styles from './RiskAssessment.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';
import map1 from '@/assets/safe_majorHazard/online_monitoring/map.png';
import risk1 from '@/assets/safe_majorHazard/online_monitoring/risk1.png';
import risk2 from '@/assets/safe_majorHazard/online_monitoring/risk2.png';
import risk3 from '@/assets/safe_majorHazard/online_monitoring/risk3.png';
const RiskAssessment = () => {
const chartRef = useRef(null);
const [selectedRowKeys, setSelectedRowKeys] = useState([]);
const [selectedRows, setSelectedRows] = useState([]);
const [loading, setLoading] = useState(false);
const [dataSource, setDataSource] = useState([]);
const [pagination, setPagination] = useState({
current: 1,
pageSize: 5,
total: 0,
});
useEffect(() => {
if (chartRef.current) {
const chart = echarts.init(chartRef.current);
// 强制初始化时调整大小
setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 100);
const option = {
color: ['#FF2526', '#FF8800', '#FFC403', '#65E5F9'],
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: ['9/22', '9/23', '9/24', '9/25', '9/26', '9/27', '9/28'],
axisLabel: {
fontSize: 10
}
},
yAxis: {
type: 'value',
min: 0,
max: 30,
axisLabel: {
formatter: '{value}',
fontSize: 10
}
},
series: [
{
name: '重大风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FF2526'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(38, 12, 12, 0.4)' },
{ offset: 1, color: 'rgba(255, 37, 38, 0)' }
]
}
},
symbol: 'none',
data: [8, 15, 12, 22, 18, 26, 20]
},
{
name: '较高风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FF8800'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 136, 0, 0.4)' },
{ offset: 1, color: 'rgba(255, 136, 0, 0)' }
]
}
},
symbol: 'none',
data: [5, 8, 6, 12, 10, 15, 13]
},
{
name: '一般风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#FFC403'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(255, 196, 3, 0.4)' },
{ offset: 1, color: 'rgba(255, 196, 3, 0)' }
]
}
},
symbol: 'none',
data: [12, 18, 15, 25, 22, 24, 26]
},
{
name: '低风险',
type: 'line',
smooth: true,
lineStyle: {
width: 1.5,
color: '#65E5F9'
},
areaStyle: {
color: {
type: 'linear',
x: 0,
y: 0,
x2: 0,
y2: 1,
colorStops: [
{ offset: 0, color: 'rgba(101, 229, 249, 0.4)' },
{ offset: 1, color: 'rgba(101, 229, 249, 0)' }
]
}
},
symbol: 'none',
data: [3, 5, 7, 9, 6, 8, 4]
}
]
};
chart.setOption(option);
// 响应式调整 - 使用多种方式监听容器尺寸变化
let resizeTimer = null;
const handleResize = () => {
// 防抖处理避免频繁调用resize
if (resizeTimer) {
clearTimeout(resizeTimer);
}
resizeTimer = setTimeout(() => {
if (chart && !chart.isDisposed()) {
chart.resize();
}
}, 50); // 减少延迟时间
};
// 监听窗口大小变化
window.addEventListener('resize', handleResize);
// 监听容器尺寸变化(解决菜单栏伸缩时的自适应问题)
let resizeObserver = null;
if (window.ResizeObserver) {
resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
// 使用requestAnimationFrame确保在下一帧执行
requestAnimationFrame(() => {
handleResize();
});
}
});
resizeObserver.observe(chartRef.current);
}
// 额外监听父容器的尺寸变化
const parentContainer = chartRef.current?.parentElement;
let parentObserver = null;
if (parentContainer && window.ResizeObserver) {
parentObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
requestAnimationFrame(() => {
handleResize();
});
}
});
parentObserver.observe(parentContainer);
}
// 使用MutationObserver监听DOM结构变化菜单展开收起时
const mutationObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'attributes' &&
(mutation.attributeName === 'class' || mutation.attributeName === 'style')) {
// 延迟执行确保DOM更新完成
setTimeout(() => {
handleResize();
}, 200);
}
});
});
// 监听整个页面的class和style变化
mutationObserver.observe(document.body, {
attributes: true,
attributeFilter: ['class', 'style'],
subtree: true
});
return () => {
window.removeEventListener('resize', handleResize);
if (resizeObserver) {
resizeObserver.disconnect();
}
if (parentObserver) {
parentObserver.disconnect();
}
if (mutationObserver) {
mutationObserver.disconnect();
}
if (resizeTimer) {
clearTimeout(resizeTimer);
}
if (chart && !chart.isDisposed()) {
chart.dispose();
}
};
}
}, []);
// 表格列定义
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: '设备编号',
dataIndex: 'deviceId',
key: 'deviceId',
width: 120,
},
{
title: '风险等级',
dataIndex: 'riskLevel',
key: 'riskLevel',
width: 100,
render: (text) => {
const colorMap = {
'高': '#FF4D4F',
'中': '#FAAD14',
'低': '#52C41A'
};
return <span style={{ color: colorMap[text] || '#333' }}>{text}</span>;
}
},
{
title: '预警时间',
dataIndex: 'warningTime',
key: 'warningTime',
width: 150,
},
{
title: '主要原因',
dataIndex: 'mainReason',
key: 'mainReason',
width: 200,
},
{
title: '处理状态',
dataIndex: 'status',
key: 'status',
width: 100,
render: (text) => {
const statusMap = {
'未处理': { color: '#FF4D4F', bg: '#FFF2F0' },
'处理中': { 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: '操作',
key: 'action',
width: 120,
render: (_, record) => (
<div>
<Button type="link" size="small" style={{ padding: 0, marginRight: 8 }}>
查看
</Button>
<Button type="link" size="small" style={{ padding: 0 }}>
详情
</Button>
</div>
),
},
];
// 模拟数据
const mockData = [
{
key: '1',
id: '001',
deviceId: 'DEV-001',
riskLevel: '高',
warningTime: '2024-01-15 08:30:25',
mainReason: '设备温度异常升高',
status: '未处理',
},
{
key: '2',
id: '002',
deviceId: 'DEV-002',
riskLevel: '中',
warningTime: '2024-01-15 09:15:10',
mainReason: '压力波动超出正常范围',
status: '处理中',
},
{
key: '3',
id: '003',
deviceId: 'DEV-003',
riskLevel: '高',
warningTime: '2024-01-15 10:45:30',
mainReason: '液位传感器故障',
status: '已处理',
},
{
key: '4',
id: '004',
deviceId: 'DEV-004',
riskLevel: '高',
warningTime: '2024-01-15 11:20:45',
mainReason: '检测到气体泄漏',
status: '未处理',
},
{
key: '5',
id: '005',
deviceId: 'DEV-005',
riskLevel: '低',
warningTime: '2024-01-15 12:10:20',
mainReason: '设备振动异常',
status: '已处理',
},
{
key: '6',
id: '006',
deviceId: 'DEV-006',
riskLevel: '中',
warningTime: '2024-01-15 13:25:15',
mainReason: '流量传感器读数异常',
status: '未处理',
},
{
key: '7',
id: '007',
deviceId: 'DEV-007',
riskLevel: '高',
warningTime: '2024-01-15 14:10:30',
mainReason: '储罐压力超限',
status: '处理中',
},
{
key: '8',
id: '008',
deviceId: 'DEV-008',
riskLevel: '中',
warningTime: '2024-01-15 15:45:20',
mainReason: '管道温度异常',
status: '已处理',
},
{
key: '9',
id: '009',
deviceId: 'DEV-009',
riskLevel: '高',
warningTime: '2024-01-15 16:30:45',
mainReason: '阀门控制系统故障',
status: '未处理',
},
{
key: '10',
id: '010',
deviceId: 'DEV-010',
riskLevel: '低',
warningTime: '2024-01-15 17:15:10',
mainReason: '轻微泄漏检测',
status: '已处理',
},
{
key: '11',
id: '011',
deviceId: 'DEV-011',
riskLevel: '高',
warningTime: '2024-01-15 18:20:35',
mainReason: '安全阀异常开启',
status: '处理中',
},
{
key: '12',
id: '012',
deviceId: 'DEV-012',
riskLevel: '中',
warningTime: '2024-01-15 19:05:50',
mainReason: '液位计读数不稳定',
status: '未处理',
},
];
// 初始化数据
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 (
<div className={styles.Rcontainer}>
{/* 第一个div - 高度20% */}
<div className={styles.RcontainerTop}>
<div className={styles.sectionContent}>
<div className={styles.blocksContainer}>
{/* 块1 */}
<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>
{/* 块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>
{/* 块5 */}
<div className={styles.blockItem}>
<div className={styles.blockLeft}>
<div className={styles.blockTitle}>已处理预警</div>
<div className={styles.blockNumber}>65</div>
<div className={styles.blockChange}>
<CheckCircleOutlined className={styles.checkIcon} />
已完成
</div>
</div>
<div className={styles.blockRight}>
<img src={img2} alt="已处理预警" className={styles.blockImage} />
</div>
</div>
</div>
</div>
</div>
<div className={styles.RcontainerMiddle}>
<div className={styles.sectionContent}>
<div className={styles.middleBlock1}>
<div className={styles.block1Header}>
<div className={styles.block1Title}>
<div className={styles.titleIcon}></div>
危险源风险热力分布
</div>
<Select
className={styles.block1Select}
defaultValue="全部区域"
options={[
{ value: '全部区域', label: '全部区域' },
{ value: '区域A', label: '区域A' },
{ value: '区域B', label: '区域B' },
{ value: '区域C', label: '区域C' }
]}
/>
</div>
{/* 风险等级图例 */}
<div className={styles.riskLegend}>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#F53F3F' }}></div>
<span className={styles.legendText}>重大风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#FF7D00' }}></div>
<span className={styles.legendText}>较大风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#FFAA01' }}></div>
<span className={styles.legendText}>一般风险</span>
</div>
<div className={styles.legendItem}>
<div className={styles.legendDot} style={{ backgroundColor: '#65E5F9' }}></div>
<span className={styles.legendText}>低风险</span>
</div>
</div>
<div className={styles.block1Chart}>
<img src={map1} alt="地图" className={styles.mapImage} />
</div>
</div>
<div className={styles.middleBlock2}>
<div className={styles.middleBlock2Title}>
<div className={styles.titleLeft}>
<div className={styles.titleIcon}></div>
<div>风险等级趋势</div>
</div>
<div className={styles.titleRight}>
<Select
style={{ width: 100 }}
defaultValue="近七天"
options={[
{ value: '近三天', label: '近3天' },
{ value: '近30天', label: '近30天' },
]}
/>
</div>
</div>
<div className={styles.middleBlock2Chart} ref={chartRef}>
</div>
</div>
</div>
</div>
{/* 第三个div - 占满剩余位置 */}
<div className={styles.RcontainerBottom}>
<div className={styles.sectionContent}>
<div className={styles.leftBlock}>
{/* 第一行块 - 蓝色方块加标题 */}
<div className={styles.leftBlockTitle}>
<div className={styles.titleIcon}></div>
<div>风险评估参数</div>
</div>
{/* 第二行块 - 图片 */}
<div className={styles.leftBlockImage}>
{/* <img src={risk2} alt="风险评估图" style={{ width: '40%', height: '40%', objectFit: 'cover' }} /> */}
</div>
{/* 第三行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>风险等级</div>
<div className={styles.itemValue}>高风险</div>
</div>
{/* 第四行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>评估时间</div>
<div className={styles.itemValue}>2024-01-15</div>
</div>
{/* 第五行块 */}
<div className={styles.leftBlockItem}>
<div className={styles.itemTitle}>评估人员</div>
<div className={styles.itemValue}>张三</div>
</div>
</div>
<div className={styles.rightBlock}>
{/* 表格 */}
<div className={styles.tableHeader}>
<div className={styles.tableTitle}>
<div className={styles.titleIcon}></div>
<div>最新预警信息</div>
</div>
</div>
{/* 表格 */}
<div className={styles.tableContainer}>
<StandardTable
columns={columns}
data={{
list: getCurrentPageData(),
pagination: pagination
}}
loading={loading}
selectionType="checkbox"
onSelectRow={onSelectChange}
onChange={handleTableChange}
pagination={{
...pagination,
showSizeChanger: false,
showQuickJumper: true,
showTotal: (total, range) =>
`${total}`,
}}
scroll={{ x: 1200 }}
/>
</div>
</div>
</div>
</div>
</div>
);
};
export default RiskAssessment;

@ -0,0 +1,418 @@
.Rcontainer {
padding: 8px 6px 0px 6px;
height: 100%;
display: flex;
flex-direction: column;
gap: 10px;
// 第一个div - 高度20%
.RcontainerTop {
height: 16%;
// background-color: #fff;
border-radius: 4px;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
flex-direction: column;
// padding: 15px;
.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;
}
.blockChange {
font-family: PingFang SC;
font-weight: 400;
font-size: 12px;
color: #1269FF;
line-height: 1.2;
display: flex;
align-items: center;
gap: 4px;
.arrow {
font-size: 14px;
font-weight: bold;
}
.checkIcon {
font-size: 16px;
color: #1269FF;
}
}
}
.blockRight {
flex: 1;
height: 100%;
background-color: transparent;
border-radius: 0 4px 4px 0;
display: flex;
align-items: center;
justify-content: center;
.blockImage {
// width: 80%;
height: 130%;
// height: 80%;
object-fit: contain;
margin-right: -10px;
}
}
}
}
}
}
// 第二个div - 高度30%
.RcontainerMiddle {
height: 30%;
border-radius: 4px;
display: flex;
flex-direction: column;
.sectionContent {
height: 100%;
display: flex;
display: flex;
gap: 10px;
height: 100%;
.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;
color: #333333;
.block1Header {
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;
}
}
.block1Select {
width: 100px;
:global(.ant-select-selector) {
height: 28px !important;
font-size: 12px !important;
}
:global(.ant-select-selection-item) {
line-height: 26px !important;
font-size: 12px !important;
}
}
}
.riskLegend {
position: absolute;
Top: 18px;
left: 50%;
transform: translateX(-50%);
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
z-index: 10;
.legendItem {
display: flex;
align-items: center;
gap: 5px;
.legendDot {
width: 8px;
height: 8px;
border-radius: 50%;
}
.legendText {
font-size: 12px;
color: #333;
font-weight: 400;
}
}
}
.block1Chart {
width: 100%;
height: 100%;
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;
}
}
}
.middleBlock2 {
flex: 1;
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;
.titleLeft {
display: flex;
align-items: center;
gap: 8px;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 14px;
background-color: #2E4CD4;
}
}
.titleRight {
display: flex;
align-items: center;
gap: 8px;
font-size: 12px;
color: #666;
}
}
.middleBlock2Chart {
width: 100%;
height: 100%;
// min-height: 200px;
}
}
}
}
// 第三个div - 占满剩余位置
.RcontainerBottom {
flex: 1; // 占满剩余空间
display: flex;
flex-direction: column;
.sectionContent {
display: 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;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
.leftBlockImage {
height: 40%;
width: 100%;
border-radius: 4px;
overflow: hidden;
display: flex;
justify-content: center;
align-items: center;
height: 80%;
}
.leftBlockItem {
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
padding: 10px;
// background-color: #f5f5f5;
border-radius: 4px;
font-family: PingFang SC;
.itemTitle {
font-size: 12px;
color: #666666;
margin-bottom: 5px;
}
.itemValue {
font-size: 14px;
color: #333333;
font-weight: 500;
}
}
}
.rightBlock {
width: 68%;
height: 100%;
background-color: #fff;
padding: 0;
display: flex;
flex-direction: column;
.tableHeader {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 15px 5px 15px;
.tableTitle {
display: flex;
align-items: center;
gap: 8px;
font-family: PingFang SC;
font-weight: 500;
font-size: 14px;
color: #333333;
.titleIcon {
width: 3px;
height: 16px;
background-color: #2E4CD4;
}
}
}
.tableContainer {
flex: 1;
overflow: hidden;
:global(.ant-table) {
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;
}
:global(.ant-table-tbody > tr > td) {
padding: 8px 12px;
border-bottom: 1px solid #f0f0f0;
text-align: center;
}
:global(.ant-table-tbody > tr:hover > td) {
background-color: #f5f5f5;
}
:global(.ant-pagination) {
margin-top: 16px;
text-align: right;
}
}
}
}
}
}

@ -42,6 +42,11 @@ const menuItem = [
label: '安全管理基础信息',
key: '/topnavbar00/hrefficiency/basicinformation',
// icon: <SettingOutlined />,
},
{
label: '重大危险源管理',
key: '/topnavbar00/hrefficiency/staffsheet',
// icon: <SettingOutlined />,
},
{
label: '隐患排查',

Loading…
Cancel
Save