From 0aee02b2c8bbebe9f8ad032e103fc1448a8a0c13 Mon Sep 17 00:00:00 2001 From: wangyunfei888 <1224056307@qq.com> Date: Fri, 26 Dec 2025 15:54:01 +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=AE=9E=E6=97=B6=E6=95=B0?= =?UTF-8?q?=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../HistoryTrend.js | 321 +++++++++++++++++- .../HistoryTrend.less | 243 ++++++++++++- .../RealtimeData.js | 321 +++++++++++++++++- .../RealtimeData.less | 243 ++++++++++++- 4 files changed, 1122 insertions(+), 6 deletions(-) diff --git a/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.js b/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.js index 8d0943b..10ed672 100644 --- a/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.js +++ b/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.js @@ -1,10 +1,327 @@ -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 './HistoryTrend.less'; +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: '层级', + dataIndex: 'level', + key: 'level', + width: 110, + align: 'center', + }, + { + title: '名称', + dataIndex: 'name', + key: 'name', + width: 120, + align: 'center', + }, + { + title: '代码', + dataIndex: 'code', + key: 'code', + align: 'center', + }, + { + title: '类型', + dataIndex: 'type', + key: 'type', + align: 'center', + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + align: 'center', + }, + { + 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: '已激活', + updatedAt: '2025-10-25 22:30:16', + }, + { + id: 2, + level: '罐区', + name: '汽油罐区', + code: 'GASOLINE-AREA', + type: '成品油', + status: '已激活', + updatedAt: '2025-10-25 10:28:14', + }, + { + id: 3, + level: '罐区', + name: '柴油罐区', + code: 'DIESEL-AREA', + type: '成品油', + status: '已激活', + updatedAt: '2025-10-23 20:58:24', + }, + { + id: 4, + level: '罐组', + name: '92汽油调合罐组', + code: 'G92-GROUP', + type: '调合罐组', + status: '维护中', + updatedAt: '2025-10-23 04:59:13', + }, + { + id: 5, + level: '储罐', + name: 'T-101', + code: 'TANK-101', + type: '浮顶罐', + status: '维护中', + updatedAt: '2025-10-22 03:03:13', + }, + { + id: 6, + level: '设备', + name: 'LT-101', + code: 'LEVEL-101', + type: '液位计', + status: '已激活', + updatedAt: '2025-10-22 03:03:13', + }, +]; + const HistoryTrend = () => { + 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 ? ( + + ) : ( + + ) + } + /> +
+
+ +
+
+ + 层级结构 +
+ +
+
+
+ +
+
); }; diff --git a/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.less b/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.less index b4d4d98..123b70e 100644 --- a/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.less +++ b/src/pages/business_basic/components/second_datamodel_components/HistoryTrend.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: 28px !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 38b05cc..385a484 100644 --- a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js +++ b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.js @@ -1,10 +1,327 @@ -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 './RealtimeData.less'; +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: '层级', + dataIndex: 'level', + key: 'level', + width: 110, + align: 'center', + }, + { + title: '名称', + dataIndex: 'name', + key: 'name', + width: 120, + align: 'center', + }, + { + title: '代码', + dataIndex: 'code', + key: 'code', + align: 'center', + }, + { + title: '类型', + dataIndex: 'type', + key: 'type', + align: 'center', + }, + { + title: '状态', + dataIndex: 'status', + key: 'status', + align: 'center', + }, + { + 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: '已激活', + updatedAt: '2025-10-25 22:30:16', + }, + { + id: 2, + level: '罐区', + name: '汽油罐区', + code: 'GASOLINE-AREA', + type: '成品油', + status: '已激活', + updatedAt: '2025-10-25 10:28:14', + }, + { + id: 3, + level: '罐区', + name: '柴油罐区', + code: 'DIESEL-AREA', + type: '成品油', + status: '已激活', + updatedAt: '2025-10-23 20:58:24', + }, + { + id: 4, + level: '罐组', + name: '92汽油调合罐组', + code: 'G92-GROUP', + type: '调合罐组', + status: '维护中', + updatedAt: '2025-10-23 04:59:13', + }, + { + id: 5, + level: '储罐', + name: 'T-101', + code: 'TANK-101', + type: '浮顶罐', + status: '维护中', + updatedAt: '2025-10-22 03:03:13', + }, + { + id: 6, + level: '设备', + name: 'LT-101', + code: 'LEVEL-101', + type: '液位计', + status: '已激活', + updatedAt: '2025-10-22 03:03:13', + }, +]; + const RealtimeData = () => { + 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 ? ( + + ) : ( + + ) + } + /> +
+
+ +
+
+ + 层级结构 +
+ +
+
+
+ +
+
); }; 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 b4d4d98..123b70e 100644 --- a/src/pages/business_basic/components/second_datamodel_components/RealtimeData.less +++ b/src/pages/business_basic/components/second_datamodel_components/RealtimeData.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: 28px !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