|
|
|
|
@ -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 './HierarchyStructure.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 }) => (
|
|
|
|
|
<span className={styles.treeNodeTitle}>
|
|
|
|
|
<span className={styles.nodeText}>{text}</span>
|
|
|
|
|
{tag ? (
|
|
|
|
|
<span className={`${styles.nodeTag} ${styles[`tag-${tag.type}`] || ''}`}>
|
|
|
|
|
{tag.label}
|
|
|
|
|
</span>
|
|
|
|
|
) : null}
|
|
|
|
|
</span>
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const formatTreeNodes = data =>
|
|
|
|
|
data.map(item => ({
|
|
|
|
|
key: item.key,
|
|
|
|
|
title: <TreeNodeTitle text={item.title} tag={item.tag} />,
|
|
|
|
|
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: () => (
|
|
|
|
|
<>
|
|
|
|
|
<a style={{ marginRight: 12, color: '#006665' }}>查看详情</a>
|
|
|
|
|
<a style={{ color: '#2D9E9D' }}>编辑</a>
|
|
|
|
|
</>
|
|
|
|
|
),
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
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 HierarchyStructure = () => {
|
|
|
|
|
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 (
|
|
|
|
|
<div className={styles.container}>
|
|
|
|
|
<div>待开发</div>
|
|
|
|
|
<section className={styles.leftPanel}>
|
|
|
|
|
<div className={styles.blockHeader}>
|
|
|
|
|
<span className={styles.titleIcon} />
|
|
|
|
|
<span className={styles.blockTitle}>工厂层级结构</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.filters}>
|
|
|
|
|
<Select
|
|
|
|
|
value={buildingType}
|
|
|
|
|
onChange={setBuildingType}
|
|
|
|
|
options={buildingOptions}
|
|
|
|
|
className={styles.filterSelect}
|
|
|
|
|
dropdownMatchSelectWidth={false}
|
|
|
|
|
size="small"
|
|
|
|
|
/>
|
|
|
|
|
<Select
|
|
|
|
|
value={factory}
|
|
|
|
|
onChange={setFactory}
|
|
|
|
|
options={factoryOptions}
|
|
|
|
|
className={styles.filterSelect}
|
|
|
|
|
dropdownMatchSelectWidth={false}
|
|
|
|
|
size="small"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.treeWrapper}>
|
|
|
|
|
<Tree
|
|
|
|
|
showIcon={false}
|
|
|
|
|
showLine={{ showLeafIcon: false }}
|
|
|
|
|
defaultExpandAll
|
|
|
|
|
checkable
|
|
|
|
|
selectable
|
|
|
|
|
treeData={treeData}
|
|
|
|
|
checkedKeys={checkedKeys}
|
|
|
|
|
selectedKeys={selectedKeys}
|
|
|
|
|
onCheck={keys => setCheckedKeys(keys.checked || keys)}
|
|
|
|
|
onSelect={keys => setSelectedKeys(keys)}
|
|
|
|
|
className={styles.tree}
|
|
|
|
|
virtual={false}
|
|
|
|
|
switcherIcon={nodeProps =>
|
|
|
|
|
nodeProps.expanded ? (
|
|
|
|
|
<Icon2 width={14} height={14} />
|
|
|
|
|
) : (
|
|
|
|
|
<Icon1 width={14} height={14} />
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
<section className={styles.rightPanel}>
|
|
|
|
|
<div className={styles.blockHeader}>
|
|
|
|
|
<span className={styles.titleIcon} />
|
|
|
|
|
<span className={styles.blockTitle}>层级结构</span>
|
|
|
|
|
<div className={styles.headerAction}>
|
|
|
|
|
<Button
|
|
|
|
|
className={styles.addLevelButton}
|
|
|
|
|
icon={<PlusOutlined />}
|
|
|
|
|
size="small"
|
|
|
|
|
>
|
|
|
|
|
添加层级
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div className={styles.tableWrapper}>
|
|
|
|
|
<StandardTable
|
|
|
|
|
columns={tableColumns}
|
|
|
|
|
data={tableData}
|
|
|
|
|
rowKey="id"
|
|
|
|
|
isshowAlert={false}
|
|
|
|
|
pagination={{ pageSize: 10 }}
|
|
|
|
|
size="small"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
</section>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|