feat():全周期开发

qzc-dev
李神峰 2026-01-27 17:59:11 +08:00
parent 6fd8692b8d
commit 34546864f4
16 changed files with 907 additions and 120 deletions

View File

@ -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

View File

@ -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{

View File

@ -14,7 +14,17 @@ const apiurl = {
qys: {
yhjmhPage:service + '/iaCFlrvvlg/page',
qsydwPage:service + '/iaCBsnssinfo/page',
wxqPage:service + '/iaCDanad/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',
}
}
}
}

View File

@ -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;

View File

@ -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 {
// ...
}
}
}
}

View File

@ -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;

View File

@ -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;
}
}
}
}

View File

@ -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;

View File

@ -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 MainBuildingInfo = ({ data = {} }) => {
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>
);

View File

@ -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;

View File

@ -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">

View File

@ -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);
}

View File

@ -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>

View File

@ -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; }
}
}