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 ? ( + + ) : ( + + ) + } + /> +
+
+ +
+
+ + 变更记录 +
+ +
+
+
+ +
+
); }; -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" />
+ +
+
+
设备状态运行
+
+
+ 运行健康度 + 98% +
+
+
+
+
+
+ {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 {