From e7efc6e4fd7c9efce57d5af7da23e64193f0c02c Mon Sep 17 00:00:00 2001
From: wangyunfei888 <1224056307@qq.com>
Date: Fri, 26 Dec 2025 16:42:52 +0800
Subject: [PATCH] =?UTF-8?q?=E5=9F=BA=E7=A1=80=E4=BF=A1=E6=81=AF-=E6=95=B0?=
=?UTF-8?q?=E6=8D=AE=E5=BB=BA=E6=A8=A1-=E5=8F=98=E6=9B=B4=E8=AE=B0?=
=?UTF-8?q?=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../ChangeRecord.js | 302 +++++++++++++++++-
.../ChangeRecord.less | 243 +++++++++++++-
.../RealtimeData.js | 179 ++++++-----
.../RealtimeData.less | 153 ++++++++-
4 files changed, 788 insertions(+), 89 deletions(-)
diff --git a/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.js b/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.js
index 7e4c9df..fc32dca 100644
--- a/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.js
+++ b/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.js
@@ -1,13 +1,307 @@
-import React from 'react';
+import React, { useMemo, useState } from 'react';
+import { Select, Tree, Button } from 'antd';
+import { PlusOutlined } from '@ant-design/icons';
+import { ReactComponent as Icon1 } from '@/assets/business_basic/icon1.svg';
+import { ReactComponent as Icon2 } from '@/assets/business_basic/icon2.svg';
+import StandardTable from '@/components/StandardTable';
import styles from './ChangeRecord.less';
-const ChangeRecord = () => {
+const buildingOptions = [
+ { label: '工厂建筑', value: 'plant' },
+ { label: '仓储设施', value: 'warehouse' },
+];
+
+const factoryOptions = [
+ { label: '全部工厂', value: 'all' },
+ { label: '上海油库', value: 'shanghai' },
+ { label: '南京油库', value: 'nanjing' },
+];
+
+const rawTreeData = [
+ {
+ title: '上海油库',
+ key: 'shanghai',
+ tag: { label: '工厂', type: 'depot' },
+ children: [
+ {
+ title: '汽油罐区',
+ key: 'gasoline-area',
+ tag: { label: '罐区', type: 'area' },
+ children: [
+ {
+ title: '汽油调合罐组',
+ key: 'blend-group',
+ tag: { label: '罐组', type: 'group' },
+ children: [
+ {
+ title: 'T-101 汽油储罐',
+ key: 't101',
+ tag: { label: '储罐', type: 'tank' },
+ children: [
+ {
+ title: 'LT-101 液位变送器',
+ key: 'lt101',
+ tag: { label: '测点', type: 'sensor' },
+ },
+ {
+ title: 'TT-101 温度变送器',
+ key: 'tt101',
+ tag: { label: '测点', type: 'sensor' },
+ },
+ {
+ title: 'PT-101 压力变送器',
+ key: 'pt101',
+ tag: { label: '测点', type: 'sensor' },
+ },
+ {
+ title: 'P-101A 输送泵',
+ key: 'p101a',
+ tag: { label: '设备', type: 'device' },
+ },
+ {
+ title: 'P-101B 输送泵',
+ key: 'p101b',
+ tag: { label: '设备', type: 'device' },
+ },
+ {
+ title: 'SP-101 密度计',
+ key: 'sp101',
+ tag: { label: '测点', type: 'sensor' },
+ },
+ ],
+ },
+ {
+ title: 'T-102 汽油储罐',
+ key: 't102',
+ tag: { label: '储罐', type: 'tank' },
+ },
+ {
+ title: 'T-103 汽油储罐',
+ key: 't103',
+ tag: { label: '储罐', type: 'tank' },
+ },
+ ],
+ },
+ ],
+ },
+ {
+ title: '柴油罐区',
+ key: 'diesel-area',
+ tag: { label: '罐区', type: 'area' },
+ },
+ {
+ title: '化危品库',
+ key: 'hazard',
+ tag: { label: '库区', type: 'depot' },
+ },
+ ],
+ },
+];
+
+const TreeNodeTitle = ({ text, tag }) => (
+
+ {text}
+ {tag ? (
+
+ {tag.label}
+
+ ) : null}
+
+);
+
+const formatTreeNodes = data =>
+ data.map(item => ({
+ key: item.key,
+ title: ,
+ children: item.children ? formatTreeNodes(item.children) : undefined,
+ }));
+
+const tableColumns = [
+ {
+ title: '变更 ID',
+ dataIndex: 'changeId',
+ key: 'changeId',
+ width: 140,
+ align: 'center',
+ },
+ {
+ title: '变更内容',
+ dataIndex: 'content',
+ key: 'content',
+ align: 'center',
+ },
+ {
+ title: '申请人',
+ dataIndex: 'applicant',
+ key: 'applicant',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '状态',
+ dataIndex: 'status',
+ key: 'status',
+ width: 100,
+ align: 'center',
+ },
+ {
+ title: '申请时间',
+ dataIndex: 'appliedAt',
+ key: 'appliedAt',
+ width: 180,
+ align: 'center',
+ },
+ {
+ title: '操作',
+ dataIndex: 'operation',
+ key: 'operation',
+ width: 140,
+ align: 'center',
+ render: () => 查看详情,
+ },
+];
+
+const tableDataSource = [
+ {
+ id: 1,
+ changeId: 'MOC-2023-0568',
+ content: '更新安全阀位参数,从85%调整为90%',
+ applicant: '钱筠泽',
+ status: '审批中',
+ appliedAt: '2025-10-25 22:30:16',
+ },
+ {
+ id: 2,
+ changeId: 'MOC-2023-0492',
+ content: '新增液位变送器LT-101A作为备用',
+ applicant: '孙小权',
+ status: '已批准',
+ appliedAt: '2025-10-25 10:28:14',
+ },
+ {
+ id: 3,
+ changeId: 'MOC-2023-0387',
+ content: '更新容积表数据,修正温度补偿系数',
+ applicant: '何引琪',
+ status: '已关闭',
+ appliedAt: '2025-10-23 20:58:24',
+ },
+ {
+ id: 4,
+ changeId: 'MOC-2023-0256',
+ content: '修改罐组用途,从成品油罐组调整为调合罐组',
+ applicant: '钱菲霖',
+ status: '已拒绝',
+ appliedAt: '2025-10-23 04:59:13',
+ },
+ {
+ id: 5,
+ changeId: 'MOC-2023-0319',
+ content: '更新容积表数据,修正温度补偿系数',
+ applicant: '李昭',
+ status: '已批准',
+ appliedAt: '2025-10-22 03:03:13',
+ },
+];
+
+const ChangeReCord = () => {
+ const [buildingType, setBuildingType] = useState('plant');
+ const [factory, setFactory] = useState('all');
+ const [selectedKeys, setSelectedKeys] = useState(['t101']);
+ const [checkedKeys, setCheckedKeys] = useState(['t101']);
+
+ const treeData = useMemo(() => formatTreeNodes(rawTreeData), []);
+
+ const tableData = useMemo(
+ () => ({
+ list: tableDataSource,
+ pagination: {
+ currentPage: 1,
+ pageSize: 10,
+ total: tableDataSource.length,
+ },
+ }),
+ [],
+ );
+
return (
-
变更记录待开发
+
+
+
+ 工厂层级结构
+
+
+
+
+
+
+ setCheckedKeys(keys.checked || keys)}
+ onSelect={keys => setSelectedKeys(keys)}
+ className={styles.tree}
+ virtual={false}
+ switcherIcon={nodeProps =>
+ nodeProps.expanded ? (
+
+ ) : (
+
+ )
+ }
+ />
+
+
+
+
+
+
+
变更记录
+
+ }
+ size="small"
+ >
+ 发起变更
+
+
+
+
+
+
+
);
};
-export default ChangeRecord;
+export default ChangeReCord;
diff --git a/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.less b/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.less
index b4d4d98..cc54993 100644
--- a/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.less
+++ b/src/pages/business_basic/components/second_datamodel_components/ChangeRecord.less
@@ -1,4 +1,245 @@
.container {
- padding: 20px;
+ display: flex;
+ gap: 16px;
+ padding: 16px;
+ background-color: #fff;
+ min-height: 520px;
+
+ .leftPanel {
+ flex: 0 0 320px;
+ background: #e9f3ef;
+ border-radius: 2px;
+ padding: 20px;
+ display: flex;
+ flex-direction: column;
+ box-shadow: 0 4px 20px rgba(21, 32, 66, 0.04);
+ }
+
+ .rightPanel {
+ flex: 1;
+ background: #fff;
+ border-radius: 12px;
+ padding: 15px 20px;
+ box-shadow: 0 4px 20px rgba(21, 32, 66, 0.04);
+ display: flex;
+ flex-direction: column;
+ }
+
+ .blockHeader {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ margin-bottom: 16px;
+
+ .titleIcon {
+ width: 3px;
+ height: 16px;
+ border-radius: 2px;
+ background: rgba(0, 102, 101, 1);
+ display: inline-block;
+ }
+
+ .blockTitle {
+ font-size: 16px;
+ font-weight: 500;
+ color: #333333;
+ }
+
+ .headerAction {
+ margin-left: auto;
+
+ :global(&.ant-btn-sm) {
+ height: 30px !important;
+ line-height: 28px;
+ }
+ }
+ }
+
+ .filters {
+ display: flex;
+ gap: 12px;
+ margin-bottom: 16px;
+
+ .filterSelect {
+ width: 100%;
+
+ :global(.ant-select-selector) {
+ border: 1px solid rgba(45, 158, 157, 1);
+ border-radius: 2px;
+ }
+
+ :global(.ant-select-focused .ant-select-selector) {
+ border-color: rgba(45, 158, 157, 1) !important;
+ box-shadow: 0 0 0 2px rgba(45, 158, 157, 0.2) !important;
+ }
+
+ :global(.ant-select:hover .ant-select-selector) {
+ border-color: rgba(45, 158, 157, 1) !important;
+ }
+ }
+ }
+
+ .treeWrapper {
+ flex: 1;
+ overflow: hidden;
+
+ .tree {
+ background-color: transparent;
+
+ :global(.ant-tree-switcher) {
+ display: flex;
+ align-items: center !important;
+ }
+
+ :global(.ant-tree-indent-unit:before) {
+ border-inline-end: 1px solid rgba(0, 102, 101, 1) !important;
+ }
+
+ :global(.ant-tree-switcher-leaf-line:after) {
+ border-bottom: 1px solid rgba(0, 102, 101, 1) !important;
+ }
+
+ :global(.ant-tree-switcher-leaf-line:before) {
+ border-inline-end: 1px solid rgba(0, 102, 101, 1) !important;
+ }
+
+ :global(.ant-tree-checkbox-inner) {
+ border: 1px solid rgba(0, 102, 101, 1);
+ border-radius: 4px;
+
+ &:hover {
+ background-color: rgba(0, 102, 101, 1);
+ border: 1px solid rgba(0, 102, 101, 1);
+ border-radius: 4px;
+ }
+
+ &:after {
+ background-color: transparent !important;
+ }
+ }
+
+ :global(.ant-tree-checkbox-checked .ant-tree-checkbox-inner),
+ :global(.ant-tree-checkbox-indeterminate .ant-tree-checkbox-inner) {
+ background-color: rgba(0, 102, 101, 1) !important;
+ border-color: rgba(0, 102, 101, 1) !important;
+ border-radius: 4px;
+ }
+
+ :global(.ant-tree) {
+ background-color: transparent;
+ }
+
+ :global(.ant-tree-treenode) {
+ padding: 2px 0;
+ }
+
+ :global(.ant-tree-node-content-wrapper) {
+ padding: 2px 4px;
+ border-radius: 4px;
+ transition: background 0.2s ease;
+
+ &:hover {
+ background: rgba(196, 225, 214, 0.3);
+ }
+ }
+
+ :global(.ant-tree-node-selected) {
+ background: rgba(190, 215, 210, 1) !important;
+ }
+ }
+ }
+
+ .tableWrapper {
+ flex: 1;
+
+ :global {
+ .ant-table-thead>tr>th {
+ text-align: center;
+ background: #f0f7f7;
+ font-weight: 450;
+ color: #333333;
+ }
+
+ .ant-table-tbody>tr>td {
+ text-align: center;
+ font-weight: 400;
+ color: #4e5856;
+ }
+ }
+ }
}
+.treeNodeTitle {
+ display: inline-flex;
+ align-items: center;
+ width: 100%;
+ gap: 12px;
+ position: relative;
+ padding-right: 40px;
+ margin-right: 80px;
+
+ .nodeText {
+ flex: 1;
+ color: rgba(0, 0, 0, 1);
+ font-weight: 400;
+ font-size: 12px;
+ }
+
+ .nodeTag {
+ text-align: center;
+ padding: 0px 6px;
+ border-radius: 2px;
+ font-size: 11px;
+ font-weight: 400;
+ position: absolute;
+ right: 0;
+ margin-right: 0;
+
+ &.tag-depot {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+
+ &.tag-area {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+
+ &.tag-sensor {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+
+ &.tag-tank {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+
+ &.tag-group {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+
+ &.tag-device {
+ background: rgba(196, 225, 214, 1);
+ color: rgba(0, 0, 0, 1);
+ }
+ }
+}
+
+.addLevelButton {
+ padding: 8px 12px;
+ border-radius: 2px;
+ background: #2e6a5e;
+ color: #ffffff;
+ display: inline-flex;
+ align-items: center;
+
+
+
+ &:hover,
+ &:focus {
+ background: #2e6a5e;
+ color: #ffffff;
+ }
+}
\ No newline at end of file
diff --git a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js
index 385a484..f841614 100644
--- a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js
+++ b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js
@@ -1,6 +1,5 @@
import React, { useMemo, useState } from 'react';
-import { Select, Tree, Button } from 'antd';
-import { PlusOutlined } from '@ant-design/icons';
+import { Select, Tree } from 'antd';
import { ReactComponent as Icon1 } from '@/assets/business_basic/icon1.svg';
import { ReactComponent as Icon2 } from '@/assets/business_basic/icon2.svg';
import StandardTable from '@/components/StandardTable';
@@ -118,29 +117,27 @@ const formatTreeNodes = data =>
const tableColumns = [
{
- title: '层级',
- dataIndex: 'level',
- key: 'level',
- width: 110,
- align: 'center',
- },
- {
- title: '名称',
+ title: '测点名称',
dataIndex: 'name',
key: 'name',
- width: 120,
align: 'center',
},
{
- title: '代码',
+ title: '测点编号',
dataIndex: 'code',
key: 'code',
align: 'center',
},
{
- title: '类型',
- dataIndex: 'type',
- key: 'type',
+ title: '测量值',
+ dataIndex: 'value',
+ key: 'value',
+ align: 'center',
+ },
+ {
+ title: '单位',
+ dataIndex: 'unit',
+ key: 'unit',
align: 'center',
},
{
@@ -150,80 +147,86 @@ const tableColumns = [
align: 'center',
},
{
- title: '最后更新',
+ title: '更新时间',
dataIndex: 'updatedAt',
key: 'updatedAt',
align: 'center',
},
- {
- title: '操作',
- dataIndex: 'operation',
- key: 'operation',
- width: 140,
- align: 'center',
- render: () => (
- <>
- 查看详情
- 编辑
- >
- ),
- },
];
const tableDataSource = [
{
id: 1,
- level: '工厂',
- name: '华东油库',
- code: 'CN-EAST-OIL',
- type: '原油存储',
- status: '已激活',
+ name: '液位变送器',
+ code: 'LT-101',
+ value: '78.5',
+ unit: '%',
+ status: '正常',
updatedAt: '2025-10-25 22:30:16',
},
{
id: 2,
- level: '罐区',
- name: '汽油罐区',
- code: 'GASOLINE-AREA',
- type: '成品油',
- status: '已激活',
+ name: '温度传感器',
+ code: 'TT-101',
+ value: '32.6',
+ unit: '℃',
+ status: '正常',
updatedAt: '2025-10-25 10:28:14',
},
{
id: 3,
- level: '罐区',
- name: '柴油罐区',
- code: 'DIESEL-AREA',
- type: '成品油',
- status: '已激活',
+ name: '压力变送器',
+ code: 'PT-101',
+ value: '0.12',
+ unit: 'MPa',
+ status: '正常',
updatedAt: '2025-10-23 20:58:24',
},
{
id: 4,
- level: '罐组',
- name: '92汽油调合罐组',
- code: 'G92-GROUP',
- type: '调合罐组',
- status: '维护中',
+ name: '密度计',
+ code: 'DT-101',
+ value: '735',
+ unit: 'kg/m³',
+ status: '正常',
updatedAt: '2025-10-23 04:59:13',
},
{
id: 5,
- level: '储罐',
- name: 'T-101',
- code: 'TANK-101',
- type: '浮顶罐',
- status: '维护中',
+ name: '进口阀门1状态',
+ code: 'V-101',
+ value: '关闭',
+ unit: '-',
+ status: '正常',
updatedAt: '2025-10-22 03:03:13',
},
+];
+
+const deviceStatusList = [
+ { label: '传感器状态', value: '正常', type: 'ok' },
+ { label: '阀门1状态', value: '正常', type: 'ok' },
+ { label: '录音运行状态', value: '停止', type: 'stop' },
+ { label: '联锁系统', value: '正常', type: 'ok' },
+];
+
+const alarmList = [
{
- id: 6,
- level: '设备',
- name: 'LT-101',
- code: 'LEVEL-101',
- type: '液位计',
- status: '已激活',
- updatedAt: '2025-10-22 03:03:13',
+ id: 1,
+ title: '液位偏高预警',
+ description: '液位达到78.5%,接近安全液位(90%)',
+ time: '2 小时前',
+ },
+ {
+ id: 2,
+ title: '液位偏高预警',
+ description: '液位达到78.5%,接近安全液位(90%)',
+ time: '2 小时前',
+ },
+ {
+ id: 3,
+ title: '液位偏高预警',
+ description: '液位达到78.5%,接近安全液位(90%)',
+ time: '2 小时前',
},
];
@@ -298,19 +301,8 @@ const RealtimeData = () => {
-
-
-
层级结构
-
- }
- size="small"
- >
- 添加层级
-
-
-
+ 实时监测点数据
+
{
size="small"
/>
+
+
+
+
设备状态运行
+
+
+ {deviceStatusList.map(item => (
+
+
+ {item.label}
+ {item.value}
+
+ ))}
+
+
+
+
+
最近报警
+
+ {alarmList.map(item => (
+
+
+
{item.title}
+
{item.description}
+
+
{item.time}
+
+ ))}
+
+
+
);
diff --git a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.less b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.less
index 123b70e..d8a808e 100644
--- a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.less
+++ b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.less
@@ -44,15 +44,6 @@
font-weight: 500;
color: #333333;
}
-
- .headerAction {
- margin-left: auto;
-
- :global(&.ant-btn-sm) {
- height: 28px !important;
- line-height: 28px;
- }
- }
}
.filters {
@@ -150,7 +141,7 @@
}
.tableWrapper {
- flex: 1;
+ margin-bottom: 16px;
:global {
.ant-table-thead>tr>th {
@@ -167,6 +158,148 @@
}
}
}
+
+ .mainTitle {
+ font-size: 16px;
+ font-weight: 500;
+ color: #333333;
+ margin-bottom: 12px;
+ }
+
+ .bottomSection {
+ display: flex;
+ gap: 16px;
+ flex: 1;
+ min-height: 260px;
+ }
+
+ .statusCard,
+ .alertCard {
+ flex: 1;
+ background: #f7fbf9;
+ border-radius: 10px;
+ padding: 16px;
+ border: 1px solid #e3ece7;
+ display: flex;
+ flex-direction: column;
+ }
+
+ .cardHeader {
+ font-size: 15px;
+ font-weight: 500;
+ color: #333333;
+ margin-bottom: 12px;
+ }
+
+ .healthBlock {
+ background: #ffffff;
+ border-radius: 8px;
+ padding: 12px;
+ border: 1px solid #e3ece7;
+ }
+
+ .healthRow {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ margin-bottom: 8px;
+ color: #4e5856;
+ font-size: 14px;
+ }
+
+ .healthLabel {
+ font-weight: 500;
+ }
+
+ .healthValue {
+ color: #2d9e9d;
+ font-weight: 600;
+ }
+
+ .healthBar {
+ width: 100%;
+ height: 12px;
+ background: #e6efec;
+ border-radius: 6px;
+ overflow: hidden;
+ }
+
+ .healthBarInner {
+ height: 100%;
+ background: linear-gradient(90deg, #2d9e9d 0%, #72c6b7 100%);
+ }
+
+ .statusList {
+ margin-top: 12px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
+ }
+
+ .statusItem {
+ display: flex;
+ align-items: center;
+ gap: 10px;
+ color: #4e5856;
+ font-size: 13px;
+ }
+
+ .statusDot {
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ display: inline-block;
+ }
+
+ .status-ok {
+ background: #2d9e9d;
+ }
+
+ .status-stop {
+ background: #b8c0bd;
+ }
+
+ .statusLabel {
+ flex: 1;
+ }
+
+ .statusValue {
+ font-weight: 500;
+ color: #333333;
+ }
+
+ .alertList {
+ display: grid;
+ grid-template-rows: repeat(3, 1fr);
+ gap: 12px;
+ flex: 1;
+ }
+
+ .alertItem {
+ background: #ffffff;
+ border: 1px solid #dbe7e2;
+ border-radius: 8px;
+ padding: 12px;
+ display: flex;
+ justify-content: space-between;
+ align-items: flex-start;
+ }
+
+ .alertTitle {
+ font-weight: 600;
+ color: #333333;
+ margin-bottom: 4px;
+ }
+
+ .alertDesc {
+ color: #4e5856;
+ font-size: 13px;
+ }
+
+ .alertTime {
+ color: #8a9592;
+ font-size: 12px;
+ }
}
.treeNodeTitle {