feat():全周期开发
parent
6fd8692b8d
commit
34546864f4
|
|
@ -25,7 +25,7 @@
|
|||
"craco-less": "2.1.0-alpha.0",
|
||||
"crypto-js": "^4.1.1",
|
||||
"echarts": "^4.9.0",
|
||||
"echarts-for-react": "^3.0.2",
|
||||
"echarts-for-react": "3.0.2",
|
||||
"http-proxy-middleware": "^2.0.6",
|
||||
"moment": "^2.29.4",
|
||||
"react": "^18.2.0",
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
|
|
@ -38,11 +38,11 @@ code {
|
|||
background: transparent; // Override white background
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #ECF2F9;
|
||||
background: rgba(0, 160, 233, 0.5);
|
||||
border-radius: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
background: #ECF2F9;
|
||||
background: rgba(0, 160, 233, 0.8);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -58,10 +58,10 @@ code {
|
|||
}
|
||||
}
|
||||
.ant-table-content::-webkit-scrollbar-thumb,.ant-table-body::-webkit-scrollbar-thumb {
|
||||
background: #C1C1C1;//#ECF2F9;
|
||||
background: rgba(0, 160, 233, 0.5);//#ECF2F9;
|
||||
}
|
||||
.ant-table-content::-webkit-scrollbar-thumb,.ant-table-body::-webkit-scrollbar-thumb:hover {
|
||||
background: #C1C1C1;//#ECF2F9;
|
||||
background: rgba(0, 160, 233, 0.8);//#ECF2F9;
|
||||
}
|
||||
|
||||
.ant-modal-title{
|
||||
|
|
@ -70,68 +70,7 @@ code {
|
|||
}
|
||||
|
||||
|
||||
.adcdTreeSelectorBox{
|
||||
width: 230px;
|
||||
height:calc( 100vh - 145px );
|
||||
margin:0 20px 0 0;
|
||||
background: #fff;
|
||||
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||
position:relative;
|
||||
border: 1px solid #d9d9d9;
|
||||
box-sizing: border-box;
|
||||
|
||||
.treeBox{
|
||||
//height:calc( 100vh - 158px );
|
||||
overflow: hidden auto;
|
||||
padding: 8px 0 0 2px;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
}
|
||||
.ant-input-group .ant-input,.ant-btn{
|
||||
border:0;
|
||||
}
|
||||
.ant-input-affix-wrapper{
|
||||
border:0;
|
||||
//border-right: 2px solid #d9d9d9;
|
||||
}
|
||||
.checkboxBox{
|
||||
position:absolute;
|
||||
top:34px;
|
||||
width:100%;
|
||||
height:30px;
|
||||
background:#fff;
|
||||
border-top: 1px solid #d9d9d9;
|
||||
padding-top:4px;
|
||||
}
|
||||
}
|
||||
|
||||
.adcdTreeTableBox{
|
||||
width:calc( 100vw - 602px );
|
||||
height:calc( 100vh - 143px );
|
||||
background: #fff;
|
||||
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.CrudAdcdTreeTableBox{
|
||||
width:calc( 100vw - 602px );
|
||||
height:calc( 100vh - 143px );
|
||||
background: #fff;
|
||||
//box-shadow: 5px 5px 10px rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.radarVideoModal{
|
||||
.ant-modal-content{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
.ant-modal-body{
|
||||
width: 100%;
|
||||
height: calc( 100% - 120px );
|
||||
padding: 0 30px;
|
||||
}
|
||||
.ant-tabs-tabpane{
|
||||
height: calc( 76vh - 120px );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.toolbarBox{
|
||||
.ant-form-item{
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ const apiurl = {
|
|||
yhjmhPage:service + '/iaCFlrvvlg/page',
|
||||
qsydwPage:service + '/iaCBsnssinfo/page',
|
||||
wxqPage: service + '/iaCDanad/page',
|
||||
gcys: {
|
||||
buildInfo: service + '/attResBuilding/info',
|
||||
krlineList:service + '/stZvarlB/list',
|
||||
xllineList:service + '/stZqrlB/list',
|
||||
}
|
||||
},
|
||||
qth: {
|
||||
rainList: {
|
||||
list:service + '/attResBase/rainBasinDivision/queryStPptnDetails/list',
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,138 @@
|
|||
import React,{useState,useEffect} from 'react';
|
||||
import { Table } from 'antd';
|
||||
import arrowIcon from '@/assets/images/card/arrow.png';
|
||||
import smallCard from '@/assets/images/card/smallCard.png';
|
||||
import wrj from '@/assets/images/card/wrj.png';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import { httpget,httppost } from '@/utils/request';
|
||||
import './index.less';
|
||||
|
||||
const AllWeatherControl = () => {
|
||||
const [rainList, setRainList] = useState([])
|
||||
const rainColumns = [
|
||||
{
|
||||
title: '站名',
|
||||
dataIndex: 'stnm',
|
||||
key: 'stnm',
|
||||
align: 'center',
|
||||
width: 140,
|
||||
ellipsis:true
|
||||
},
|
||||
{
|
||||
title: '今日',
|
||||
dataIndex: 'today',
|
||||
key: 'today',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '昨日',
|
||||
dataIndex: 'yesterdayDrp',
|
||||
key: 'yesterdayDrp',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '24h预报',
|
||||
dataIndex: 'h24',
|
||||
key: 'h24',
|
||||
align: 'h24',
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
// Reservoir Data
|
||||
const reservoirData = [
|
||||
{ label: '主坝坝前', value: '103.17', unit: 'm', isPrimary: true, showArrow: true, underline: true },
|
||||
{ label: '汛限水位', value: '104.50', unit: 'm' },
|
||||
{ label: '距汛限', value: '-1.67', unit: 'm', isNegative: true },
|
||||
{ label: '副坝坝前', value: '104.17', unit: 'm' },
|
||||
{ label: '当前库容', value: '3867.0', unit: '万m³', isPrimary: true },
|
||||
{ label: '有效库容', value: '2867.0', unit: '万m³', isPrimary: true },
|
||||
];
|
||||
|
||||
const getRainList = async () => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sq.qth.rainList);
|
||||
if (result.code == 200) {
|
||||
setRainList(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
getRainList()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="all-weather-control">
|
||||
{/* 雨情 Section */}
|
||||
<div className="section rain-section">
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span className="section-title">雨情</span>
|
||||
</div>
|
||||
</div>
|
||||
<Table
|
||||
columns={rainColumns}
|
||||
dataSource={rainList}
|
||||
pagination={false}
|
||||
size="small"
|
||||
rowKey={'stcd'}
|
||||
rowClassName={(record) => record.isTotal ? 'total-row' : ''}
|
||||
bordered={false}
|
||||
scroll={{y:300}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* 水库水情 Section */}
|
||||
<div className="section reservoir-section">
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span className="section-title">水库水情</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="reservoir-cards">
|
||||
{reservoirData.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="reservoir-card"
|
||||
style={{ backgroundImage: `url(${smallCard})` }}
|
||||
>
|
||||
<div className={`value ${item.isPrimary ? 'primary' : ''} ${item.isNegative ? 'negative' : ''}`}>
|
||||
<span className={`num ${item.underline ? 'underline' : ''}`}>{item.value}</span>
|
||||
<span className="unit">{item.unit}</span>
|
||||
</div>
|
||||
<div className="label">{item.label}</div>
|
||||
{item.showArrow && <span className="arrow-up">↑</span>}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 无人机 Section */}
|
||||
<div className="section uav-section">
|
||||
<div className="section-header">
|
||||
<div className="title-wrapper">
|
||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||
<span className="section-title">无人机</span>
|
||||
</div>
|
||||
<span className="link">视频墙</span>
|
||||
</div>
|
||||
<div className="uav-content">
|
||||
<div
|
||||
className="uav-image"
|
||||
style={{ backgroundImage: `url(${wrj})` }}
|
||||
/>
|
||||
<div className="uav-actions">
|
||||
<div className="uav-button">直播画面</div>
|
||||
<div className="uav-button">巡查任务</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default AllWeatherControl;
|
||||
|
|
@ -0,0 +1,211 @@
|
|||
.all-weather-control {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
color: #fff;
|
||||
padding: 5px;
|
||||
overflow-y: auto;
|
||||
|
||||
// Global Scrollbar
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.section {
|
||||
margin-bottom: 10px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 5px;
|
||||
|
||||
.title-wrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.arrow-icon {
|
||||
width: 20px;
|
||||
height: 18px;
|
||||
margin-right: 8px;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-size: 16px;
|
||||
color: #fff; // Matches the orange/gold color in screenshot
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
color: #00eaff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Rain Table Styling
|
||||
.rain-section {
|
||||
.ant-table-wrapper {
|
||||
.ant-table {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
|
||||
.ant-table-thead > tr > th {
|
||||
background: rgba(0, 70, 110, 0.6);
|
||||
color: #fff;
|
||||
border-bottom: none;
|
||||
padding: 8px 4px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr > td {
|
||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||
color: #fff;
|
||||
padding: 8px 4px;
|
||||
text-align: center;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.ant-table-tbody > tr:hover > td {
|
||||
background: rgba(255, 255, 255, 0.1) !important;
|
||||
}
|
||||
|
||||
// Zebra striping if needed, or just transparent
|
||||
.ant-table-tbody > tr.ant-table-row:nth-child(even) {
|
||||
background-color: rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.ant-table-placeholder {
|
||||
background: transparent;
|
||||
.ant-empty-description {
|
||||
color: rgba(255,255,255,0.5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reservoir-section {
|
||||
.reservoir-cards {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.reservoir-card {
|
||||
width: calc((100% - 20px) / 3);
|
||||
margin-bottom: 5px;
|
||||
margin-right: 10px;
|
||||
&:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
height: 60px; // Adjust based on design
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
position: relative;
|
||||
|
||||
.value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #00D8FF;
|
||||
.num {
|
||||
display: inline-block;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
.num.underline {
|
||||
border-bottom: 1px solid #00a0e9;
|
||||
}
|
||||
.unit {
|
||||
font-size: 12px;
|
||||
font-weight: normal;
|
||||
margin-left: 2px;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&.primary { color: #00eaff; }
|
||||
&.negative { color: #68c639; }
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #9DD2E4;
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.arrow-up {
|
||||
color: #ff4d4f;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// UAV Styling
|
||||
.uav-section {
|
||||
.uav-content {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
height: 100px;
|
||||
position: relative;
|
||||
|
||||
.uav-image {
|
||||
flex: 1;
|
||||
height: 100%;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.uav-actions {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
margin-left: 10px;
|
||||
|
||||
.uav-button {
|
||||
width: 120px;
|
||||
height: 36px;
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
background: rgba(18, 56, 102, 0.6);
|
||||
border: 1px solid #00a0e9;
|
||||
border-radius: 4px;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s;
|
||||
box-shadow: 0 0 5px rgba(0, 160, 233, 0.3);
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 160, 233, 0.4);
|
||||
box-shadow: 0 0 10px rgba(0, 160, 233, 0.6);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Connecting lines visualization (optional, if needed to match 1:1 perfectly)
|
||||
.connection-line {
|
||||
// ...
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import React from 'react';
|
||||
import smallCard from '@/assets/images/card/smallCard.png';
|
||||
import './index.less';
|
||||
|
||||
const ManagementCycle = () => {
|
||||
const data = [
|
||||
{ label: '安全鉴定', value: '三类坝' },
|
||||
{ label: '病险水库', value: '是' },
|
||||
{ label: '除险加固', value: '2024年11月' },
|
||||
{ label: '降等报废', value: '无' },
|
||||
{ label: '调度规则', value: '2023年12月', underline: true },
|
||||
{ label: '应急预案', value: '2023年12月', underline: true },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="management-cycle">
|
||||
<div className="card-grid">
|
||||
{data.map((item, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="cycle-card"
|
||||
style={{ backgroundImage: `url(${smallCard})` }}
|
||||
>
|
||||
<div className={`value-wrapper ${item.underline ? 'underlined' : ''}`}>
|
||||
<span className="value">{item.value}</span>
|
||||
</div>
|
||||
<div className="label">{item.label}</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManagementCycle;
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
.management-cycle {
|
||||
height: 100%;
|
||||
padding: 10px;
|
||||
overflow-y: auto;
|
||||
|
||||
// Global Scrollbar
|
||||
&::-webkit-scrollbar {
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
.card-grid {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
height: 100%;
|
||||
align-content: flex-start;
|
||||
|
||||
.cycle-card {
|
||||
width: calc((100% - 20px) / 3);
|
||||
height: 80px; // Slightly taller to accommodate text comfortably
|
||||
margin-bottom: 15px;
|
||||
margin-right: 10px;
|
||||
|
||||
&:nth-child(3n) {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
background-size: 100% 100%;
|
||||
background-repeat: no-repeat;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 5px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.value-wrapper {
|
||||
margin-bottom: 5px;
|
||||
|
||||
&.underlined {
|
||||
border-bottom: 1px solid #00a0e9; // Match the blue theme
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #00D8FF;
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
import React, { useMemo } from 'react';
|
||||
import ReactEcharts from 'echarts-for-react';
|
||||
import { Table } from 'antd';
|
||||
import { GetInterval } from '@/utils/tools';
|
||||
const CapacityCurve = ({data=[]}) => {
|
||||
const dataSource = (data && data.length > 0) ? data : [];
|
||||
|
||||
// Robust data parsing
|
||||
const validData = dataSource.map(item => ({
|
||||
...item,
|
||||
rz: parseFloat(item.rz),
|
||||
w: parseFloat(item.w)
|
||||
})).filter(item => !isNaN(item.rz) && !isNaN(item.w));
|
||||
|
||||
const hasData = validData.length > 0;
|
||||
|
||||
let maxVal = hasData ? Math.ceil(Math.max(...validData.map(obj => obj.rz))) : 100;
|
||||
let minVal = hasData ? Math.floor(Math.min(...validData.map(obj => obj.rz))) : 0;
|
||||
let maxValX = hasData ? Math.max(...validData.map(obj => obj.w)) : 100;
|
||||
let minValX = hasData ? Math.min(...validData.map(obj => obj.w)) : 0;
|
||||
|
||||
// Prevent min === max for axes
|
||||
if (minVal === maxVal) {
|
||||
maxVal += 1;
|
||||
minVal -= 1;
|
||||
}
|
||||
if (minValX === maxValX) {
|
||||
maxValX += 10;
|
||||
minValX -= 10;
|
||||
if (minValX < 0) minValX = 0;
|
||||
}
|
||||
|
||||
// Calculate safe interval
|
||||
let intervalX = GetInterval(minValX, maxValX);
|
||||
if (intervalX <= 0 || isNaN(intervalX)) intervalX = 20;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
render: (text, record, index) => index + 1,
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '水位(m)',
|
||||
dataIndex: 'rz',
|
||||
key: 'rz',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '库容(万m³)',
|
||||
dataIndex: 'w',
|
||||
key: 'w',
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
const option = useMemo(() => {
|
||||
return {
|
||||
toolbox: {
|
||||
show: true,
|
||||
feature: {
|
||||
saveAsImage: {
|
||||
show: true,
|
||||
excludeComponents: ['toolbox'],
|
||||
pixelRatio: 2,
|
||||
name:"库容曲线图"
|
||||
}
|
||||
},
|
||||
right: "14%",
|
||||
top:"5%"
|
||||
},
|
||||
title: {
|
||||
text: "库容曲线图",
|
||||
left: "40%",
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
grid: [
|
||||
{
|
||||
top: "10%",
|
||||
left: "15%",
|
||||
right: "15%",
|
||||
bottom: "8%"
|
||||
},
|
||||
],
|
||||
xAxis: [
|
||||
{
|
||||
name: "库容(万m³)",
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
nameGap: 5,
|
||||
type: 'value',
|
||||
min:Math.floor(minValX / 5) *5,
|
||||
max:Math.ceil(maxValX / 5) *5,
|
||||
interval: intervalX,
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
},
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: "库水位(m)",
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
minInterval:1,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
width: 0.25,
|
||||
type: 'dotted'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
min: minVal,
|
||||
max: maxVal
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
color: "#007AFD",
|
||||
data: validData.map(item=>[item.w,item.rz]),
|
||||
smooth: true
|
||||
},
|
||||
]
|
||||
};
|
||||
}, [minVal, maxVal, minValX, maxValX, intervalX, validData]);
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', height: '100%', gap: '20px' }}>
|
||||
<div style={{ flex: '0 0 400px', height: '100%', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
||||
<Table
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
scroll={{ y: 'calc(100vh - 300px)' }} // Estimate height, will adjust if needed
|
||||
size="small"
|
||||
bordered={false}
|
||||
className="custom-table"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: 1, height: '100%', minWidth: 0, paddingRight: 20 }}>
|
||||
<ReactEcharts option={option} style={{ height: '100%', width: '100%' }} notMerge={true} lazyUpdate={true} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CapacityCurve;
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
import React from 'react';
|
||||
import React,{useState,useEffect} from 'react';
|
||||
import { Descriptions } from 'antd';
|
||||
|
||||
const MainBuildingInfo = ({data={}}) => {
|
||||
const [info, setInfo] = useState({})
|
||||
|
||||
const commonLabelStyle = {
|
||||
width: '200px',
|
||||
textAlign: 'right',
|
||||
|
|
@ -21,63 +22,68 @@ const MainBuildingInfo = ({ data = {} }) => {
|
|||
style: descriptionStyle,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setInfo(data)
|
||||
}, [data])
|
||||
|
||||
|
||||
return (
|
||||
<div className="form-container">
|
||||
{/* 主坝 */}
|
||||
<Descriptions {...getDescriptionsProps('主坝')}>
|
||||
<Descriptions.Item label="坝型">{data.mainDamType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶高程(m)">{data.mainDamCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶长度(m)">{data.mainDamLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶宽度(m)">{data.mainDamWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大坝高(m)">{data.mainDamMaxHeight || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝型">{info.mainType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶高程(m)">{info.mainCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶长度(m)">{info.mainCrestLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶宽度(m)">{info.mainCrestWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大坝高(m)">{info.mainMaxHeight || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 副坝 */}
|
||||
<Descriptions {...getDescriptionsProps('副坝')}>
|
||||
<Descriptions.Item label="坝型">{data.auxDamType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶高程(m)">{data.auxDamCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶长度(m)">{data.auxDamLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶宽度(m)">{data.auxDamWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大坝高(m)">{data.auxDamMaxHeight || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝型">{info.auxType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶高程(m)">{info.auxCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶长度(m)">{info.auxCrestLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝顶宽度(m)">{info.auxCrestWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大坝高(m)">{info.auxMaxHeight || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 溢洪道 */}
|
||||
<Descriptions {...getDescriptionsProps('溢洪道')}>
|
||||
<Descriptions.Item label="型式">{data.spillwayType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="堰顶型式">{data.spillwayCrestType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{data.spillwayFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="溢流堰顶高程(m)">{data.spillwayCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="溢流堰净宽(m)">{data.spillwayNetWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="消能型式">{data.spillwayDissipationType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="校核洪水下泄流量(m³/s)">{data.spillwayCheckFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计洪水下泄流量(m³/s)">{data.spillwayDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="消能防冲下泄流量(m³/s)">{data.spillwayDissipationFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="型式">{info.spillwayType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="堰顶型式">{info.spillwayCrestType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{info.spillwayFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="溢流堰顶高程(m)">{info.spillwayCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="溢流堰净宽(m)">{info.spillwayNetWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="消能型式">{info.spillwayEnergyDissipation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="校核洪水下泄流量(m³/s)">{info.spillwayCheckFloodDischarge || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计洪水下泄流量(m³/s)">{info.spillwayDesignFloodDischarge || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="消能防冲下泄流量(m³/s)">{info.spillwayScouringDischarge || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 灌溉发电洞 */}
|
||||
<Descriptions {...getDescriptionsProps('灌溉发电洞')}>
|
||||
<Descriptions.Item label="型式">{data.irrigationTunnelType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="衬砌型式">{data.irrigationTunnelLining || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{data.irrigationTunnelFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{data.irrigationTunnelInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{data.irrigationTunnelSectionSize || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="洞长(m)">{data.irrigationTunnelLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计流量(m³/s)">{data.irrigationTunnelDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口闸门型式">{data.irrigationTunnelGateType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口启闭机型式">{data.irrigationTunnelHoistType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="型式">{info.irrigationType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="衬砌型式">{info.irrigationLiningType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{info.irrigationFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{info.irrigationInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{info.irrigationCrossSection || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="洞长(m)">{info.irrigationLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计流量(m³/s)">{info.irrigationDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口闸门型式">{info.irrigationGateType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口启闭机型式">{info.irrigationHoistType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 放空洞 */}
|
||||
<Descriptions {...getDescriptionsProps('放空洞')}>
|
||||
<Descriptions.Item label="型式">{data.outletTunnelType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="衬砌型式">{data.outletTunnelLining || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{data.outletTunnelFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{data.outletTunnelInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{data.outletTunnelSectionSize || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="洞长(m)">{data.outletTunnelLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计流量(m³/s)">{data.outletTunnelDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口闸门型式">{data.outletTunnelGateType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口启闭机型式">{data.outletTunnelHoistType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="型式">{info.emptyingType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="衬砌型式">{info.emptyingLiningType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基特性">{info.emptyingFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{info.emptyingInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{info.emptyingCrossSection || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="洞长(m)">{info.emptyingLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计流量(m³/s)">{info.emptyingDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口闸门型式">{info.emptyingGateType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口启闭机型式">{info.emptyingHoistType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,159 @@
|
|||
import React, { useMemo,useEffect,useState } from 'react';
|
||||
import ReactEcharts from 'echarts-for-react';
|
||||
import { Table,Empty } from 'antd';
|
||||
import { GetInterval } from '@/utils/tools';
|
||||
const XlCurve = ({data=[]}) => {
|
||||
|
||||
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: '序号',
|
||||
dataIndex: 'index',
|
||||
key: 'index',
|
||||
render: (text, record, index) => index + 1,
|
||||
width: 80,
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '水位(m)',
|
||||
dataIndex: 'z',
|
||||
key: 'z',
|
||||
align: 'center',
|
||||
},
|
||||
{
|
||||
title: '流量(m³/s)',
|
||||
dataIndex: 'q',
|
||||
key: 'q',
|
||||
align: 'center',
|
||||
},
|
||||
];
|
||||
|
||||
const option = useMemo(() => {
|
||||
if (data.length > 0) {
|
||||
const maxVal = Math.ceil(Math.max(...data.map(obj => obj.q)))
|
||||
const minVal = Math.floor(Math.min(...data.map(obj => obj.q)))
|
||||
const maxValX = Math.max(...data.map(obj => obj.z))
|
||||
const minValX = Math.min(...data.map(obj => obj.z))
|
||||
return {
|
||||
toolbox: {
|
||||
show: true,
|
||||
feature: {
|
||||
saveAsImage: {
|
||||
show: true,
|
||||
excludeComponents: ['toolbox'],
|
||||
pixelRatio: 2,
|
||||
name:"泄流曲线图"
|
||||
}
|
||||
},
|
||||
right: "14%",
|
||||
top:"5%"
|
||||
},
|
||||
title: {
|
||||
text: "泄流曲线图",
|
||||
left: "40%",
|
||||
textStyle: {
|
||||
color: '#fff',
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
grid: [
|
||||
{
|
||||
top: "10%",
|
||||
left: "15%",
|
||||
right: "15%",
|
||||
bottom: "8%"
|
||||
},
|
||||
],
|
||||
xAxis: [
|
||||
{
|
||||
name: "库水位(m)",
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
nameGap: 5,
|
||||
type: 'value',
|
||||
min:Math.floor(minValX / 5) *5,
|
||||
max:Math.ceil(maxValX / 5) *5,
|
||||
interval: GetInterval(minValX,maxValX),
|
||||
splitLine: {
|
||||
show: false
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
},
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: "流量(m³/s)",
|
||||
nameTextStyle: {
|
||||
color: '#fff',
|
||||
},
|
||||
minInterval:1,
|
||||
splitLine: {
|
||||
show: true,
|
||||
lineStyle: {
|
||||
color: '#fff',
|
||||
width: 0.25,
|
||||
type: 'dotted'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
},
|
||||
axisLine: {
|
||||
show: false
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
min: minVal,
|
||||
max: maxVal
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'line',
|
||||
color: "#007AFD",
|
||||
data: data.map(item=>[item.z,item.q]),
|
||||
smooth: true
|
||||
},
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
}, [data]);
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div style={{ display: 'flex', height: '100%', gap: '20px' }}>
|
||||
<div style={{ flex: '0 0 400px', height: '100%', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
|
||||
<Table
|
||||
dataSource={data}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
pagination={false}
|
||||
scroll={{ y: 'calc(100vh - 300px)' }} // Estimate height, will adjust if needed
|
||||
size="small"
|
||||
bordered={false}
|
||||
className="custom-table"
|
||||
/>
|
||||
</div>
|
||||
<div style={{ flex: 1, height: '100%', minWidth: 0, paddingRight: 20 }}>
|
||||
{data.length > 0 ? <ReactEcharts option={option} style={{ height: '100%', width: '100%' }} notMerge={true} /> :
|
||||
<Empty description={"暂无数据"} />
|
||||
}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default XlCurve;
|
||||
|
|
@ -1,16 +1,22 @@
|
|||
import React, { useState } from 'react';
|
||||
import React, { useState,useEffect } from 'react';
|
||||
import { PaperClipOutlined } from '@ant-design/icons';
|
||||
import PdfView from '@/views/Home/components/UI/PdfView'
|
||||
import BasicInfo from './components/BasicInfo';
|
||||
import MainFeatureParams from './components/MainFeatureParams';
|
||||
import MainBuildingInfo from './components/MainBuildingInfo';
|
||||
import CapacityCurve from './components/CapacityCurve';
|
||||
import XlCurve from './components/XlCurve';
|
||||
import { httpget,httppost } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import './index.less';
|
||||
|
||||
const EngineeringElements = ({ data }) => {
|
||||
const [activeButton, setActiveButton] = useState('basic');
|
||||
const [pdfOpen, setPdfOpen] = useState(false)
|
||||
const [filesItem, setFilesItem] = useState({})
|
||||
|
||||
const [info, setInfo] = useState({}) //主要建筑物信息
|
||||
const [krLineList, setKrLineList] = useState([]) //库容曲线
|
||||
const [xrLineList, setXrLineList] = useState([]) //泄流曲线
|
||||
const buttons = [
|
||||
{ label: '工程基础信息', value: 'basic' },
|
||||
{ label: '主要特征参数', value: 'params' },
|
||||
|
|
@ -19,6 +25,41 @@ const EngineeringElements = ({ data }) => {
|
|||
{ label: '水库泄流曲线', value: 'discharge-curve' },
|
||||
];
|
||||
|
||||
// 建筑物信息
|
||||
const getBuildInfo = async () => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sq.qys.gcys.buildInfo);
|
||||
if (result.code == 200) {
|
||||
setInfo(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 库容曲线
|
||||
const getKrList = async () => {
|
||||
try {
|
||||
const result = await httppost(apiurl.sq.qys.gcys.krlineList);
|
||||
if (result.code == 200) {
|
||||
setKrLineList(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
// 泄流曲线
|
||||
const getXlList = async () => {
|
||||
try {
|
||||
const result = await httppost(apiurl.sq.qys.gcys.xllineList);
|
||||
if (result.code == 200) {
|
||||
setXrLineList(result.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
const handlePreview = (data) => {
|
||||
setPdfOpen(true)
|
||||
setFilesItem(data)
|
||||
|
|
@ -31,7 +72,11 @@ const EngineeringElements = ({ data }) => {
|
|||
case 'params':
|
||||
return <MainFeatureParams data={data} />;
|
||||
case 'buildings':
|
||||
return <MainBuildingInfo data={data} />;
|
||||
return <MainBuildingInfo data={info} />;
|
||||
case 'capacity-curve':
|
||||
return <CapacityCurve data={krLineList} />;
|
||||
case 'discharge-curve':
|
||||
return <XlCurve data={xrLineList} />;
|
||||
default:
|
||||
return (
|
||||
<div className="placeholder-content">
|
||||
|
|
@ -41,7 +86,11 @@ const EngineeringElements = ({ data }) => {
|
|||
);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getBuildInfo()
|
||||
getKrList()
|
||||
getXlList()
|
||||
}, [])
|
||||
return (
|
||||
<div className="engineering-elements">
|
||||
<div className="sidebar">
|
||||
|
|
|
|||
|
|
@ -49,14 +49,21 @@
|
|||
width: 6px;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
background: rgba(0, 160, 233, 0.5);
|
||||
border-radius: 3px;
|
||||
}
|
||||
&::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
&::-webkit-scrollbar-thumb:hover {
|
||||
background: rgba(0, 160, 233, 0.8);
|
||||
}
|
||||
|
||||
.engineering-descriptions {
|
||||
table {
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
|
||||
.ant-descriptions-view {
|
||||
border-color: rgba(59, 124, 255, 0.3);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import MonitoringElements from './components/MonitoringElements';
|
|||
import ReservoirAreaElements from './components/ModalComponents/ReservoirAreaElements';
|
||||
import EngineeringElements from './components/ModalComponents/EngineeringElements';
|
||||
import DownstreamElements from './components/ModalComponents/DownstreamElements';
|
||||
// import ManagementElements from './components/ModalComponents/ManagementElements';
|
||||
// import AllWeatherMastery from './components/AllWeatherMastery';
|
||||
import AllWeatherControl from './components/AllWeatherControl';
|
||||
import ManagementCycle from './components/ManagementCycle';
|
||||
import CommonModal from '../../UI/CommonModal';
|
||||
import { httppost } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
|
|
@ -23,7 +23,6 @@ const SiQuan = () => {
|
|||
{ label: '库区要素', value: 'kqys' },
|
||||
{ label: '工程要素', value: 'gcys' },
|
||||
{ label: '下游要素', value: 'xyys' },
|
||||
// { label: '管理要素', value: 'glys' },
|
||||
];
|
||||
|
||||
const getInfo = async () => {
|
||||
|
|
@ -64,7 +63,7 @@ const SiQuan = () => {
|
|||
<SupervisionCoverage data={infos} />
|
||||
</CommonCard>
|
||||
<CommonCard
|
||||
title="监测全要素"
|
||||
title="掌握全要素"
|
||||
className="panel-card card-2"
|
||||
headerExtra={<ThreeDots onClick={handleOpenModal} />}
|
||||
>
|
||||
|
|
@ -79,10 +78,10 @@ const SiQuan = () => {
|
|||
className="panel-card card-1"
|
||||
headerExtra={<ThreeDots onClick={() => console.log('管控全天候 clicked')} />}
|
||||
>
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
<AllWeatherControl />
|
||||
</CommonCard>
|
||||
<CommonCard title="管理全周期" className="panel-card card-3">
|
||||
<div className="placeholder-content">内容填充区域</div>
|
||||
<ManagementCycle />
|
||||
</CommonCard>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@
|
|||
}
|
||||
|
||||
.right-part {
|
||||
.card-1 { flex: 4; }
|
||||
.card-1 { flex: 5; }
|
||||
.card-2 { flex: 3; }
|
||||
.card-3 { flex: 1; }
|
||||
.card-3 { flex: 2; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue