Compare commits
5 Commits
9f4fabde9d
...
6a1443e73a
| Author | SHA1 | Date |
|---|---|---|
|
|
6a1443e73a | |
|
|
07d05d20ed | |
|
|
0011c7218f | |
|
|
39c270984a | |
|
|
db011df5a6 |
|
|
@ -123,6 +123,13 @@
|
|||
}
|
||||
}
|
||||
|
||||
.ant-table-cell-fix-left, .ant-table-cell-fix-right{
|
||||
background: transparent !important;
|
||||
}
|
||||
.ant-table-thead > tr > th, .ant-table-tbody > tr > td, .ant-table tfoot > tr > th, .ant-table tfoot > tr > td{
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Table Scrollbar Fix (Remove white strip)
|
||||
.ant-table-body, .ant-table-content {
|
||||
&::-webkit-scrollbar {
|
||||
|
|
|
|||
|
|
@ -106,12 +106,17 @@ const apiurl = {
|
|||
shuikuBasicinfo: {
|
||||
detail: service + "/attResBase/list",
|
||||
update: service + "/attResBase/update",
|
||||
getFile: service + "/attResBase/file/get"
|
||||
getFile: service + "/attResBase/file/get",
|
||||
mangeFile: service + '/screen/manageHouseImg/get',
|
||||
},
|
||||
buildInfo: {
|
||||
detail: service + "/attResBuilding/info",
|
||||
update: service + "/attResBuilding/update",
|
||||
},
|
||||
skhj: {
|
||||
detail: service + '/reservoirDemarcationInfo/get',
|
||||
list: service + '/propertyCertificate/list',
|
||||
},
|
||||
kr: {
|
||||
list: service + "/stZvarlB/list",
|
||||
save: service + "/stZvarlB/insert",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import moment from "moment"
|
|||
|
||||
function QSYDW({ id, data, dispatch }) {
|
||||
console.log(data);
|
||||
const url = "http://223.75.53.141:9100/gs-hsz"
|
||||
const url = "http://223.75.53.141:9100/gs-ss"
|
||||
const width = 500;
|
||||
|
||||
const closePop = () => {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ import moment from "moment"
|
|||
|
||||
function YHJMH({ id, data, dispatch }) {
|
||||
console.log(data);
|
||||
const url = "http://223.75.53.141:9100/gs-hsz"
|
||||
const url = "http://223.75.53.141:9100/gs-ss"
|
||||
const width = 500;
|
||||
const closePop = () => {
|
||||
dispatch.runtime.closeFeaturePop(id);
|
||||
|
|
|
|||
|
|
@ -82,11 +82,14 @@
|
|||
.label {
|
||||
font-size: 14px;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.value {
|
||||
font-size: 14px;
|
||||
color: #00D8FF;
|
||||
white-space: nowrap;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,304 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Row, Col, Table, Radio } from 'antd';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import * as echarts from 'echarts';
|
||||
// import './ProcessLineChart.less'; // Reuse styles or create new ones
|
||||
|
||||
// Mock Data
|
||||
const mockData = {
|
||||
dates: ['2026-01-26', '2026-01-27', '2026-01-28', '2026-01-29', '2026-01-30', '2026-01-31', '2026-02-01', '2026-02-02', '2026-02-03', '2026-02-04', '2026-02-05', '2026-02-06', '2026-02-07'],
|
||||
reservoirLevel: [704.5, 704.4, 704.6, 704.5, 704.4, 704.5, 704.6, 704.5, 704.39, 704.4, 704.5, 704.6, 704.5],
|
||||
points: {
|
||||
'01': {
|
||||
x: [-89.88, -89.48, -88.77, -89.0, -88.19, -88.5, -88.44, -89.1, -88.75, -89.2, -88.9, -89.0, -88.8],
|
||||
y: [-26.96, -27.22, -28.33, -28.17, -28.48, -29.06, -28.73, -27.9, -28.5, -28.2, -28.1, -28.0, -28.4],
|
||||
z: [10.5, 10.6, 10.4, 10.5, 10.7, 10.6, 10.5, 10.6, 10.5, 10.4, 10.5, 10.6, 10.5]
|
||||
},
|
||||
'02': {
|
||||
x: [-114.67, -114.43, -113.94, -113.45, -113.72, -113.51, -113.9, -114.2, -114.29, -113.8, -114.0, -114.1, -114.3],
|
||||
y: [-24.63, -25.46, -24.91, -25.42, -24.57, -25.23, -25.19, -24.8, -25.0, -25.3, -25.1, -25.2, -25.4],
|
||||
z: [15.2, 15.3, 15.1, 15.2, 15.4, 15.3, 15.2, 15.3, 15.2, 15.1, 15.2, 15.3, 15.2]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const getChartOption = (data, mainType, subType) => {
|
||||
const pointNames = Object.keys(data.points);
|
||||
const colors = ['#5470C6', '#91CC75', '#EE6666'];
|
||||
|
||||
// Determine Y-axis name and data key based on types
|
||||
let yAxisName = '';
|
||||
let dataKey = '';
|
||||
|
||||
if (mainType === 'horizontal') {
|
||||
if (subType === 'upDown') {
|
||||
yAxisName = '上下游水平位移(mm)';
|
||||
dataKey = 'x';
|
||||
} else {
|
||||
yAxisName = '左右岸水平位移(mm)';
|
||||
dataKey = 'y';
|
||||
}
|
||||
} else {
|
||||
yAxisName = '垂直位移(mm)';
|
||||
dataKey = 'z';
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'cross', crossStyle: { color: '#999' } }
|
||||
},
|
||||
legend: {
|
||||
data: ['库水位(m)', ...pointNames],
|
||||
textStyle: { color: '#fff' }
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '10%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: data.dates,
|
||||
axisPointer: { type: 'shadow' },
|
||||
axisLine: { lineStyle: { color: '#86909C' } },
|
||||
axisLabel: { color: '#fff' }
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: yAxisName,
|
||||
axisLabel: { formatter: '{value}', color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' },
|
||||
splitLine: { lineStyle: { color: '#4E5969', type: 'dashed' } }
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '库水位(m)',
|
||||
min: 690,
|
||||
max: 715,
|
||||
interval: 5,
|
||||
axisLabel: { formatter: '{value}', color: '#fff' },
|
||||
nameTextStyle: { color: '#fff' },
|
||||
splitLine: { show: false }
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '库水位(m)',
|
||||
type: 'line',
|
||||
yAxisIndex: 1,
|
||||
data: data.reservoirLevel,
|
||||
lineStyle: { color: '#EE6666', width: 2 },
|
||||
itemStyle: { color: '#EE6666' },
|
||||
symbol: 'circle',
|
||||
symbolSize: 6
|
||||
},
|
||||
...pointNames.map((name, index) => ({
|
||||
name: name,
|
||||
type: 'line',
|
||||
yAxisIndex: 0,
|
||||
data: data.points[name][dataKey],
|
||||
lineStyle: { color: colors[index] },
|
||||
itemStyle: { color: colors[index] }
|
||||
}))
|
||||
],
|
||||
dataZoom: [
|
||||
{ type: 'inside', start: 0, end: 100 },
|
||||
{
|
||||
start: 0, end: 100,
|
||||
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
|
||||
handleSize: '80%',
|
||||
handleStyle: { color: '#fff', shadowBlur: 3, shadowColor: 'rgba(0, 0, 0, 0.6)', shadowOffsetX: 2, shadowOffsetY: 2 },
|
||||
textStyle: { color: '#fff' }
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
const DeformationPanel = () => {
|
||||
const [chartData] = useState(mockData);
|
||||
const [mainType, setMainType] = useState('horizontal'); // 'horizontal' | 'vertical'
|
||||
const [subType, setSubType] = useState('upDown'); // 'upDown' | 'leftRight'
|
||||
|
||||
// Generate Table Columns
|
||||
const getTableColumns = () => {
|
||||
const pointNames = Object.keys(chartData.points);
|
||||
|
||||
// Fixed columns
|
||||
const columns = [
|
||||
{
|
||||
title: '监测日期',
|
||||
dataIndex: 'date',
|
||||
key: 'date',
|
||||
width: 120,
|
||||
fixed: 'left',
|
||||
}
|
||||
];
|
||||
|
||||
// Dynamic columns for each point
|
||||
if (mainType === 'horizontal') {
|
||||
// For horizontal, show x and y
|
||||
columns.push({
|
||||
title: '水平位移(mm)',
|
||||
children: pointNames.map(name => ({
|
||||
title: name,
|
||||
children: [
|
||||
{ title: 'x', dataIndex: `${name}_x`, key: `${name}_x`, width: 80 },
|
||||
{ title: 'y', dataIndex: `${name}_y`, key: `${name}_y`, width: 80 }
|
||||
]
|
||||
}))
|
||||
});
|
||||
} else {
|
||||
// For vertical, show z
|
||||
columns.push({
|
||||
title: '垂直位移(mm)',
|
||||
children: pointNames.map(name => ({
|
||||
title: name,
|
||||
dataIndex: `${name}_z`,
|
||||
key: `${name}_z`,
|
||||
width: 100
|
||||
}))
|
||||
});
|
||||
}
|
||||
|
||||
return columns;
|
||||
};
|
||||
|
||||
// Generate Table Data
|
||||
const getTableData = () => {
|
||||
const dataSource = chartData.dates.map((date, index) => {
|
||||
const row = { key: index, date: date };
|
||||
|
||||
Object.keys(chartData.points).forEach(name => {
|
||||
if (mainType === 'horizontal') {
|
||||
row[`${name}_x`] = chartData.points[name].x[index];
|
||||
row[`${name}_y`] = chartData.points[name].y[index];
|
||||
} else {
|
||||
row[`${name}_z`] = chartData.points[name].z[index];
|
||||
}
|
||||
});
|
||||
|
||||
return row;
|
||||
});
|
||||
|
||||
// Summary (Max, Min, Range)
|
||||
const summary = {
|
||||
max: { date: '最大值', key: 'max' },
|
||||
min: { date: '最小值', key: 'min' },
|
||||
range: { date: '变幅', key: 'range' },
|
||||
};
|
||||
|
||||
const pointNames = Object.keys(chartData.points);
|
||||
const fields = [];
|
||||
pointNames.forEach(name => {
|
||||
if (mainType === 'horizontal') {
|
||||
fields.push(`${name}_x`, `${name}_y`);
|
||||
} else {
|
||||
fields.push(`${name}_z`);
|
||||
}
|
||||
});
|
||||
|
||||
fields.forEach(field => {
|
||||
const [name, key] = field.split('_');
|
||||
const values = chartData.points[name][key];
|
||||
const validValues = values.filter(v => v !== null && v !== undefined);
|
||||
|
||||
if (validValues.length > 0) {
|
||||
const max = Math.max(...validValues);
|
||||
const min = Math.min(...validValues);
|
||||
summary.max[field] = max.toFixed(2);
|
||||
summary.min[field] = min.toFixed(2);
|
||||
summary.range[field] = (max - min).toFixed(2);
|
||||
} else {
|
||||
summary.max[field] = '-';
|
||||
summary.min[field] = '-';
|
||||
summary.range[field] = '-';
|
||||
}
|
||||
});
|
||||
|
||||
return [...dataSource, summary.max, summary.min, summary.range];
|
||||
};
|
||||
|
||||
return (
|
||||
<Row gutter={16} style={{ height: '100%' }}>
|
||||
{/* Left Chart */}
|
||||
<Col span={14} style={{ height: '100%' }}>
|
||||
<ReactECharts
|
||||
option={getChartOption(chartData, mainType, subType)}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
|
||||
{/* Right Table */}
|
||||
<Col span={10} style={{ height: '100%', display: 'flex', flexDirection: 'column' }}>
|
||||
<div style={{ marginBottom: 10, display: 'flex', justifyContent: 'flex-end', gap: 10 }}>
|
||||
{mainType === 'horizontal' && (
|
||||
<Radio.Group
|
||||
value={subType}
|
||||
onChange={e => setSubType(e.target.value)}
|
||||
buttonStyle="solid"
|
||||
size="small"
|
||||
style={{ marginRight: 12 }}
|
||||
>
|
||||
<Radio.Button value="upDown" style={{
|
||||
borderRadius: '4px 0 0 4px',
|
||||
marginLeft: '-1px',
|
||||
background: subType === 'upDown' ? 'rgba(0, 160, 233, 0.8)' : 'rgba(18, 56, 102, 0.6)',
|
||||
borderColor: '#00a0e9',
|
||||
color: '#fff'
|
||||
}}>上下游</Radio.Button>
|
||||
<Radio.Button value="leftRight" style={{
|
||||
borderRadius: '0 4px 4px 0',
|
||||
marginLeft: '-1px',
|
||||
background: subType === 'leftRight' ? 'rgba(0, 160, 233, 0.8)' : 'rgba(18, 56, 102, 0.6)',
|
||||
borderColor: '#00a0e9',
|
||||
color: '#fff'
|
||||
}}>左右岸</Radio.Button>
|
||||
</Radio.Group>
|
||||
)}
|
||||
|
||||
<Radio.Group
|
||||
value={mainType}
|
||||
onChange={e => {
|
||||
setMainType(e.target.value);
|
||||
if (e.target.value === 'horizontal') {
|
||||
setSubType('upDown'); // Reset subType when switching back
|
||||
}
|
||||
}}
|
||||
buttonStyle="solid"
|
||||
size="small"
|
||||
>
|
||||
<Radio.Button value="horizontal" style={{
|
||||
borderRadius: '4px 0 0 4px',
|
||||
background: mainType === 'horizontal' ? 'rgba(0, 160, 233, 0.8)' : 'rgba(18, 56, 102, 0.6)',
|
||||
borderColor: '#00a0e9',
|
||||
color: '#fff'
|
||||
}}>水平位移</Radio.Button>
|
||||
<Radio.Button value="vertical" style={{
|
||||
borderRadius: '0 4px 4px 0',
|
||||
marginLeft: '-1px',
|
||||
background: mainType === 'vertical' ? 'rgba(0, 160, 233, 0.8)' : 'rgba(18, 56, 102, 0.6)',
|
||||
borderColor: '#00a0e9',
|
||||
color: '#fff'
|
||||
}}>垂直位移</Radio.Button>
|
||||
</Radio.Group>
|
||||
</div>
|
||||
|
||||
<Table
|
||||
columns={getTableColumns()}
|
||||
dataSource={getTableData()}
|
||||
pagination={false}
|
||||
scroll={{ y: 'calc(100vh - 350px)' }}
|
||||
size="small"
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeformationPanel;
|
||||
|
|
@ -0,0 +1,308 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Row, Col, Table } from 'antd';
|
||||
import ReactECharts from 'echarts-for-react';
|
||||
import * as echarts from 'echarts';
|
||||
// import './ProcessLineChart.less';
|
||||
|
||||
// Mock Data based on the screenshot
|
||||
const mockData = {
|
||||
dates: ['2026-01-26', '2026-01-27', '2026-01-28', '2026-01-29', '2026-01-30', '2026-01-31', '2026-02-01', '2026-02-02', '2026-02-03', '2026-02-04', '2026-02-05', '2026-02-06', '2026-02-07'],
|
||||
rainfall: [0, 0, 0.5, 0.5, 0, 0, 0, 0, 3, 0, 0, 0, 0],
|
||||
reservoirLevel: [null, null, null, null, 1141.7, 1141.69, 1141.65, 1141.52, 1144.41, 1144.34, 1144.34, 1144.33, 1144.3],
|
||||
pipes: {
|
||||
'UPD1': [1142, 1141.96, 1141.8, 1141.71, 1141.7, 1141.69, 1141.65, 1141.52, 1141.39, 1141.42, 1141.64, 1141.55, 1141.73],
|
||||
'UPD2': [1132.42, 1132.43, 1132.43, 1132.4, 1132.42, 1132.43, 1132.43, 1132.43, 1132.43, 1132.41, 1132.4, 1132.4, 1132.41],
|
||||
'UPD3': [1125.47, 1125.47, 1125.46, 1125.41, 1125.48, 1125.51, 1125.51, 1125.52, 1125.48, 1125.42, 1125.41, 1125.46, 1125.46],
|
||||
}
|
||||
};
|
||||
|
||||
const getChartOption = (data) => {
|
||||
const pipeNames = Object.keys(data.pipes);
|
||||
const colors = ['#5470C6', '#91CC75', '#EE6666', '#73C0DE', '#3BA272', '#FC8452', '#9A60B4', '#EA7CCC'];
|
||||
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: {
|
||||
type: 'cross',
|
||||
crossStyle: {
|
||||
color: '#999'
|
||||
}
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
data: ['雨量', '库水位', ...pipeNames],
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
left: '3%',
|
||||
right: '4%',
|
||||
bottom: '10%',
|
||||
containLabel: true
|
||||
},
|
||||
xAxis: [
|
||||
{
|
||||
type: 'category',
|
||||
data: data.dates,
|
||||
axisPointer: {
|
||||
type: 'shadow'
|
||||
},
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#86909C'
|
||||
}
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
],
|
||||
yAxis: [
|
||||
{
|
||||
type: 'value',
|
||||
name: '水位(m)',
|
||||
min: 1115,
|
||||
max: 1155,
|
||||
interval: 5,
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
color: '#fff'
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#fff'
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
color: '#4E5969'
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'value',
|
||||
name: '雨量(mm)',
|
||||
min: 0,
|
||||
max: 500,
|
||||
interval: 100,
|
||||
axisLabel: {
|
||||
formatter: '{value}',
|
||||
color: '#fff'
|
||||
},
|
||||
nameTextStyle: {
|
||||
color: '#fff'
|
||||
},
|
||||
splitLine: {
|
||||
show: false
|
||||
}
|
||||
}
|
||||
],
|
||||
series: [
|
||||
{
|
||||
name: '雨量',
|
||||
type: 'bar',
|
||||
yAxisIndex: 1,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' mm';
|
||||
}
|
||||
},
|
||||
data: data.rainfall,
|
||||
itemStyle: {
|
||||
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
|
||||
{ offset: 0, color: '#83bff6' },
|
||||
{ offset: 0.5, color: '#188df0' },
|
||||
{ offset: 1, color: '#188df0' }
|
||||
])
|
||||
}
|
||||
},
|
||||
{
|
||||
name: '库水位',
|
||||
type: 'line',
|
||||
yAxisIndex: 0,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' m';
|
||||
}
|
||||
},
|
||||
data: data.reservoirLevel,
|
||||
lineStyle: {
|
||||
color: colors[2]
|
||||
}
|
||||
},
|
||||
...pipeNames.map((name, index) => ({
|
||||
name: name,
|
||||
type: 'line',
|
||||
yAxisIndex: 0,
|
||||
tooltip: {
|
||||
valueFormatter: function (value) {
|
||||
return value + ' m';
|
||||
}
|
||||
},
|
||||
data: data.pipes[name],
|
||||
lineStyle: {
|
||||
color: colors[index + 3]
|
||||
}
|
||||
}))
|
||||
],
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100
|
||||
},
|
||||
{
|
||||
start: 0,
|
||||
end: 100,
|
||||
handleIcon: 'M10.7,11.9v-1.3H9.3v1.3c-4.9,0.3-8.8,4.4-8.8,9.4c0,5,3.9,9.1,8.8,9.4v1.3h1.3v-1.3c4.9-0.3,8.8-4.4,8.8-9.4C19.5,16.3,15.6,12.2,10.7,11.9z M13.3,24.4H6.7V23h6.6V24.4z M13.3,19.6H6.7v-1.4h6.6V19.6z',
|
||||
handleSize: '80%',
|
||||
handleStyle: {
|
||||
color: '#fff',
|
||||
shadowBlur: 3,
|
||||
shadowColor: 'rgba(0, 0, 0, 0.6)',
|
||||
shadowOffsetX: 2,
|
||||
shadowOffsetY: 2
|
||||
},
|
||||
textStyle: {
|
||||
color: '#fff'
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
const ProcessLineChart = () => {
|
||||
const [chartData] = useState(mockData);
|
||||
|
||||
const tableData = chartData.dates.map((date, index) => {
|
||||
const row = {
|
||||
key: index,
|
||||
date: date,
|
||||
reservoirLevel: chartData.reservoirLevel[index],
|
||||
rainfall: chartData.rainfall[index],
|
||||
};
|
||||
for (const pipeName in chartData.pipes) {
|
||||
row[pipeName] = chartData.pipes[pipeName][index];
|
||||
}
|
||||
return row;
|
||||
});
|
||||
|
||||
const pipeNames = Object.keys(chartData.pipes);
|
||||
const columns = [
|
||||
{ title: '监测日期', dataIndex: 'date', key: 'date', width: 120, fixed: 'left', align: 'center' },
|
||||
{ title: '库水位(m)', dataIndex: 'reservoirLevel', key: 'reservoirLevel', width: 100, align: 'center' },
|
||||
{ title: '雨量(mm)', dataIndex: 'rainfall', key: 'rainfall', width: 100, align: 'center' },
|
||||
{
|
||||
title: '渗压水位(m)',
|
||||
align: 'center',
|
||||
children: pipeNames.map(name => ({
|
||||
title: name,
|
||||
dataIndex: name,
|
||||
key: name,
|
||||
width: 100,
|
||||
align: 'center'
|
||||
})),
|
||||
},
|
||||
];
|
||||
const summaryNode = () => {
|
||||
const summary = {
|
||||
max: { date: '最大值' },
|
||||
min: { date: '最小值' },
|
||||
range: { date: '变幅' },
|
||||
};
|
||||
|
||||
const fields = ['reservoirLevel', 'rainfall', ...pipeNames];
|
||||
fields.forEach(field => {
|
||||
const values = chartData[field] || chartData.pipes[field];
|
||||
let max = -Infinity, min = Infinity, maxDate = '', minDate = '';
|
||||
values.forEach((v, i) => {
|
||||
if (v !== null && v !== undefined) {
|
||||
if (v > max) { max = v; maxDate = chartData.dates[i]; }
|
||||
if (v < min) { min = v; minDate = chartData.dates[i]; }
|
||||
}
|
||||
});
|
||||
|
||||
if (max === -Infinity) {
|
||||
summary.max[field] = 'N/A';
|
||||
summary.min[field] = 'N/A';
|
||||
summary.range[field] = 'N/A';
|
||||
summary.max[`${field}_date`] = '';
|
||||
summary.min[`${field}_date`] = '';
|
||||
} else {
|
||||
summary.max[field] = max.toFixed(2);
|
||||
summary.min[field] = min.toFixed(2);
|
||||
summary.range[field] = (max - min).toFixed(2);
|
||||
summary.max[`${field}_date`] = maxDate;
|
||||
summary.min[`${field}_date`] = minDate;
|
||||
}
|
||||
});
|
||||
|
||||
const cellContentStyle = { whiteSpace: 'pre-line', textAlign: 'center', verticalAlign: 'middle', borderBottom: '1px solid rgba(0, 160, 233, 0.3)' };
|
||||
const rowStyle = { background: 'rgba(0, 33, 64, 0.85)', color: '#fff' };
|
||||
const fixedCellStyle = {
|
||||
...cellContentStyle,
|
||||
background: 'rgba(0, 33, 64, 0.95)',
|
||||
color: '#fff',
|
||||
fontWeight: 'bold',
|
||||
boxShadow: '2px 0 5px rgba(0,0,0,0.3)'
|
||||
};
|
||||
|
||||
return (
|
||||
<Table.Summary fixed>
|
||||
<Table.Summary.Row style={rowStyle}>
|
||||
<Table.Summary.Cell index={0} fixed="left" style={fixedCellStyle}>{summary.max.date}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} style={cellContentStyle}>{summary.max.reservoirLevel}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} style={cellContentStyle}>{summary.max.rainfall}</Table.Summary.Cell>
|
||||
{pipeNames.map((name, i) => <Table.Summary.Cell key={`${name}-max`} index={i + 3} style={cellContentStyle}>{summary.max[name]}</Table.Summary.Cell>)}
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row style={rowStyle}>
|
||||
<Table.Summary.Cell index={0} fixed="left" style={fixedCellStyle}>日期</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} style={cellContentStyle}>{summary.max.reservoirLevel_date}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} style={cellContentStyle}>{summary.max.rainfall_date}</Table.Summary.Cell>
|
||||
{pipeNames.map((name, i) => <Table.Summary.Cell key={`${name}-max-date`} index={i + 3} style={cellContentStyle}>{summary.max[`${name}_date`]}</Table.Summary.Cell>)}
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row style={rowStyle}>
|
||||
<Table.Summary.Cell index={0} fixed="left" style={fixedCellStyle}>{summary.min.date}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} style={cellContentStyle}>{summary.min.reservoirLevel}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} style={cellContentStyle}>{summary.min.rainfall}</Table.Summary.Cell>
|
||||
{pipeNames.map((name, i) => <Table.Summary.Cell key={`${name}-min`} index={i + 3} style={cellContentStyle}>{summary.min[name]}</Table.Summary.Cell>)}
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row style={rowStyle}>
|
||||
<Table.Summary.Cell index={0} fixed="left" style={fixedCellStyle}>日期</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} style={cellContentStyle}>{summary.min.reservoirLevel_date}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} style={cellContentStyle}>{summary.min.rainfall_date}</Table.Summary.Cell>
|
||||
{pipeNames.map((name, i) => <Table.Summary.Cell key={`${name}-min-date`} index={i + 3} style={cellContentStyle}>{summary.min[`${name}_date`]}</Table.Summary.Cell>)}
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row style={rowStyle}>
|
||||
<Table.Summary.Cell index={0} fixed="left" style={fixedCellStyle}>{summary.range.date}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} style={cellContentStyle}>{summary.range.reservoirLevel}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} style={cellContentStyle}>{summary.range.rainfall}</Table.Summary.Cell>
|
||||
{pipeNames.map((name, i) => <Table.Summary.Cell key={`${name}-range`} index={i + 3} style={cellContentStyle}>{summary.range[name]}</Table.Summary.Cell>)}
|
||||
</Table.Summary.Row>
|
||||
</Table.Summary>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Row gutter={16} style={{ height: '100%' }}>
|
||||
<Col span={12} style={{ height: '98%' }}>
|
||||
<ReactECharts
|
||||
option={getChartOption(chartData)}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={12} style={{ height: '100%' }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableData}
|
||||
pagination={false}
|
||||
scroll={{ y: 'calc(100vh - 650px)' }}
|
||||
summary={summaryNode}// Adjust based on your layout
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
};
|
||||
|
||||
export default ProcessLineChart;
|
||||
|
|
@ -0,0 +1,401 @@
|
|||
import * as echarts from 'echarts';
|
||||
|
||||
export const getOption = (data = {}) => {
|
||||
const {
|
||||
waterLevel = 113.8,
|
||||
floodLevel = 128.42,
|
||||
pipes = [
|
||||
{ name: 'UPD4', x: 110, top: 175, bottom: 60, level: 103.67 },
|
||||
{ name: 'UPD1', x: 160, top: 175, bottom: 60, level: 103.67 },
|
||||
{ name: 'UPD2', x: 190, top: 150, bottom: 60, level: 102.89 },
|
||||
{ name: 'UPD3', x: 210, top: 130, bottom: 60, level: 101.12 },
|
||||
]
|
||||
} = data;
|
||||
|
||||
// Dam Geometry Configuration
|
||||
const foundationY = 40;
|
||||
const crestY = 180;
|
||||
|
||||
// Left Slope (Upstream)
|
||||
const leftToe = [20, foundationY];
|
||||
const leftCrest = [130, crestY];
|
||||
|
||||
// Right Slope (Downstream) with Berm
|
||||
const rightCrest = [150, crestY];
|
||||
const bermElevation = 120;
|
||||
const bermStart = [190, bermElevation];
|
||||
const bermEnd = [210, bermElevation];
|
||||
const rightToe = [250, foundationY];
|
||||
const distanceFromCrest = 20; // Distance from top of core to dam crest
|
||||
|
||||
const coreBaseLeft = 125;
|
||||
const coreBaseRight = 155;
|
||||
const coreTopLeft = 135;
|
||||
const coreTopRight = 145;
|
||||
const coreBottomY = foundationY;
|
||||
// const coreTopY = crestY - distanceFromCrest;
|
||||
const coreTopY = floodLevel;
|
||||
|
||||
// Dam Toe Weight (Gray Mound)
|
||||
// Shifted left to intersect with the main slope
|
||||
const toeWeightPoints = [
|
||||
[230, foundationY],
|
||||
[240, 55],
|
||||
[245, 55],
|
||||
[255, foundationY]
|
||||
];
|
||||
|
||||
// Colors
|
||||
const damColor = '#Decbb6'; // Light beige for shell
|
||||
const coreColor = '#D2a88d'; // Darker for core
|
||||
const foundationColor = '#8B4513'; // Dark brown
|
||||
const waterColor = 'rgba(0, 150, 136, 0.8)';
|
||||
const saturationLineColor = '#00a0e9'; // Bright blue
|
||||
const floodLineColor = 'red';
|
||||
const toeColor = '#808080'; // Gray for toe
|
||||
|
||||
// Calculations
|
||||
// Upstream Slope Line: y - y1 = m(x - x1)
|
||||
const mUp = (leftCrest[1] - leftToe[1]) / (leftCrest[0] - leftToe[0]);
|
||||
const cUp = leftToe[1] - mUp * leftToe[0];
|
||||
|
||||
// Intersection of Water Level with Upstream Slope
|
||||
// x = (y - c) / m
|
||||
const waterX = (waterLevel - cUp) / mUp;
|
||||
const floodX = (floodLevel - cUp) / mUp;
|
||||
|
||||
// Render Pipe Function
|
||||
const renderPipe = (params, api) => {
|
||||
const x = api.value(0);
|
||||
const top = api.value(1);
|
||||
const bottom = api.value(2);
|
||||
const level = api.value(3);
|
||||
const name = api.value(4);
|
||||
|
||||
const topPos = api.coord([x, top]);
|
||||
const bottomPos = api.coord([x, bottom]);
|
||||
const levelPos = api.coord([x, level]);
|
||||
|
||||
const width = 12;
|
||||
|
||||
return {
|
||||
type: 'group',
|
||||
children: [
|
||||
{
|
||||
type: 'rect',
|
||||
shape: {
|
||||
x: topPos[0] - width / 2,
|
||||
y: topPos[1],
|
||||
width: width,
|
||||
height: levelPos[1] - topPos[1]
|
||||
},
|
||||
style: {
|
||||
fill: 'rgba(200,200,200,0.2)',
|
||||
stroke: '#999',
|
||||
lineWidth: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'rect',
|
||||
shape: {
|
||||
x: levelPos[0] - width / 2,
|
||||
y: levelPos[1],
|
||||
width: width,
|
||||
height: bottomPos[1] - levelPos[1]
|
||||
},
|
||||
style: {
|
||||
fill: '#00a0e9',
|
||||
stroke: '#999',
|
||||
lineWidth: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: name,
|
||||
x: topPos[0],
|
||||
y: topPos[1] - 15,
|
||||
textAlign: 'center',
|
||||
fill: '#fff',
|
||||
fontSize: 12
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
style: {
|
||||
text: level.toFixed(2) + 'm',
|
||||
x: levelPos[0] + width / 2 + 5,
|
||||
y: levelPos[1],
|
||||
textAlign: 'left',
|
||||
textVerticalAlign: 'middle',
|
||||
fill: '#fff',
|
||||
fontSize: 11
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
};
|
||||
|
||||
// Saturation Line Logic
|
||||
const damCenterX = 140;
|
||||
const leftPipes = pipes.filter(p => p.x < damCenterX).sort((a, b) => a.x - b.x);
|
||||
const rightPipes = pipes.filter(p => p.x >= damCenterX).sort((a, b) => a.x - b.x);
|
||||
|
||||
const saturationPoints = [];
|
||||
|
||||
// 1. Start at water surface
|
||||
saturationPoints.push([waterX, waterLevel]);
|
||||
|
||||
// 2. Handle Left Side
|
||||
if (leftPipes.length > 0) {
|
||||
// Connect all left pipes
|
||||
leftPipes.forEach(p => saturationPoints.push([p.x, p.level]));
|
||||
// Extend to center from the last left pipe
|
||||
saturationPoints.push([damCenterX, leftPipes[leftPipes.length - 1].level]);
|
||||
} else {
|
||||
// No left pipes: Extend from water level to center
|
||||
saturationPoints.push([damCenterX, waterLevel]);
|
||||
}
|
||||
|
||||
// 3. Handle Right Side
|
||||
// Connect to the nearest pipe on the right (and subsequent ones)
|
||||
rightPipes.forEach(p => saturationPoints.push([p.x, p.level]));
|
||||
|
||||
// 4. End logic
|
||||
if (rightPipes.length > 0) {
|
||||
const lastPipe = rightPipes[rightPipes.length - 1];
|
||||
if (lastPipe.level < foundationY) {
|
||||
// If last pipe level is below foundation, extend horizontally to x=250
|
||||
saturationPoints.push([250, lastPipe.level]);
|
||||
} else {
|
||||
// Otherwise, connect to toe
|
||||
saturationPoints.push(rightToe);
|
||||
}
|
||||
} else {
|
||||
// No right pipes, connect to toe
|
||||
saturationPoints.push(rightToe);
|
||||
}
|
||||
|
||||
return {
|
||||
backgroundColor: 'transparent',
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
axisPointer: { type: 'cross' },
|
||||
formatter: () => ''
|
||||
},
|
||||
grid: {
|
||||
left: 60,
|
||||
right: 60,
|
||||
top: 60,
|
||||
bottom: 40
|
||||
},
|
||||
xAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 280,
|
||||
axisLabel: { color: '#fff' },
|
||||
splitLine: { show: false }
|
||||
},
|
||||
yAxis: {
|
||||
type: 'value',
|
||||
min: 0,
|
||||
max: 200,
|
||||
axisLabel: { color: '#fff', formatter: '{value}' },
|
||||
splitLine: {
|
||||
lineStyle: { type: 'dashed', color: 'rgba(255,255,255,0.1)' }
|
||||
},
|
||||
name: '断面高(m)',
|
||||
nameTextStyle: { color: '#fff', padding: [0, 0, 0, 20] }
|
||||
},
|
||||
series: [
|
||||
// 1. Foundation
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [[0, 0], [280, 0], [280, foundationY], [0, foundationY]].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: foundationColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 2. Dam Body Shell (Left)
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [leftToe, leftCrest, [coreTopLeft, coreTopY], [coreBaseLeft, foundationY]].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: damColor, stroke: damColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 3. Dam Body Shell (Right with Berm)
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [
|
||||
[coreBaseRight, foundationY],
|
||||
[coreTopRight, coreTopY],
|
||||
rightCrest,
|
||||
bermStart,
|
||||
bermEnd,
|
||||
rightToe
|
||||
].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: damColor, stroke: damColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 4. Core Wall
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [
|
||||
[coreBaseLeft, coreBottomY],
|
||||
[coreTopLeft, coreTopY],
|
||||
[coreTopRight, coreTopY],
|
||||
[coreBaseRight, coreBottomY]
|
||||
].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: coreColor, stroke: coreColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 5. Dam Crest Filler (Top Part)
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [
|
||||
[coreTopLeft, coreTopY],
|
||||
[coreTopRight, coreTopY],
|
||||
rightCrest,
|
||||
leftCrest
|
||||
].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: damColor, stroke: damColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 6. Dam Toe Weight
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = toeWeightPoints.map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: toeColor, stroke: toeColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 6. Upstream Water Level (Correctly Filled)
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: (params, api) => {
|
||||
const points = [
|
||||
[0, foundationY],
|
||||
leftToe, // Join the slope toe
|
||||
[waterX, waterLevel], // Join the slope at water level
|
||||
[0, waterLevel]
|
||||
].map(p => api.coord(p));
|
||||
return {
|
||||
type: 'polygon',
|
||||
shape: { points },
|
||||
style: { fill: waterColor },
|
||||
silent: true
|
||||
};
|
||||
},
|
||||
data: [[0, 0]]
|
||||
},
|
||||
// 7. Saturation Line
|
||||
{
|
||||
type: 'line',
|
||||
smooth: 0.4,
|
||||
symbol: 'none',
|
||||
lineStyle: { color: saturationLineColor, width: 3 },
|
||||
data: saturationPoints,
|
||||
z: 11
|
||||
},
|
||||
// 8. Flood Level (Dashed Horizontal)
|
||||
{
|
||||
type: 'line',
|
||||
markLine: {
|
||||
symbol: ['none', 'none'],
|
||||
label: {
|
||||
show: true,
|
||||
position: 'middle',
|
||||
formatter: `校核洪水位 ${floodLevel}m`,
|
||||
color: '#fff',
|
||||
padding: [0, 0, 10, 0]
|
||||
},
|
||||
lineStyle: { color: floodLineColor, type: 'dashed', width: 2 },
|
||||
data: [
|
||||
[
|
||||
{ x:70, yAxis: floodLevel },
|
||||
{ xAxis: floodX, yAxis: floodLevel } // To the dam body
|
||||
]
|
||||
]
|
||||
},
|
||||
data: []
|
||||
},
|
||||
// 9. Red Line from Flood Level to Dam Toe
|
||||
{
|
||||
type: 'line',
|
||||
symbol: 'none',
|
||||
lineStyle: { color: '#ff0000', width: 2, type: 'solid' }, // Red solid line
|
||||
data: [
|
||||
[floodX, floodLevel],
|
||||
[coreTopLeft, coreTopY],
|
||||
[coreTopRight, coreTopY],
|
||||
[237, 50] // To dam toe top
|
||||
],
|
||||
z: 10 // Ensure it's on top
|
||||
},
|
||||
// 10. Measured Water Level Label
|
||||
{
|
||||
type: 'scatter',
|
||||
symbol: 'triangle',
|
||||
symbolSize: 10,
|
||||
symbolRotate: 180,
|
||||
itemStyle: { color: saturationLineColor },
|
||||
label: {
|
||||
show: true,
|
||||
formatter: `实测水位 ${waterLevel}m`,
|
||||
position: 'top',
|
||||
color: '#fff',
|
||||
fontSize: 12,
|
||||
offset: [0, 0]
|
||||
},
|
||||
data: [[waterX / 2, waterLevel]]
|
||||
},
|
||||
// 10. Pipes
|
||||
{
|
||||
type: 'custom',
|
||||
renderItem: renderPipe,
|
||||
data: pipes.map(p => [p.x, p.top, p.bottom, p.level, p.name]),
|
||||
z: 12
|
||||
},
|
||||
]
|
||||
};
|
||||
};
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import ReactEcharts from 'echarts-for-react';
|
||||
import { DatePicker, Select, Button } from 'antd';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import moment from 'moment';
|
||||
import { getOption } from './chartOption';
|
||||
import ProcessLineChart from './ProcessLineChart';
|
||||
import DeformationPanel from './DeformationPanel';
|
||||
import './index.less';
|
||||
|
||||
const { RangePicker } = DatePicker;
|
||||
const { Option } = Select;
|
||||
|
||||
const SafetyPanel = () => {
|
||||
const [activeTab, setActiveTab] = useState('seepage');
|
||||
const [filter, setFilter] = useState({
|
||||
type: 'saturation', // saturation | process
|
||||
section: 'main_0_086',
|
||||
date: [moment().subtract(7, 'days'), moment()]
|
||||
});
|
||||
|
||||
const [chartData, setChartData] = useState({});
|
||||
const [quickDate, setQuickDate] = useState('1m'); // Default to 1 month
|
||||
|
||||
useEffect(() => {
|
||||
// Mock fetching data
|
||||
// In a real scenario, this would depend on the selected section
|
||||
setChartData({
|
||||
waterLevel: 113.8,
|
||||
floodLevel: 128.42,
|
||||
pipes: [
|
||||
{ name: 'UPD4', x: 110, top: 175, bottom: 60, level: 117.67 },
|
||||
{ name: 'UPD1', x: 160, top: 175, bottom: 60, level: 100.67 },
|
||||
{ name: 'UPD2', x: 190, top: 150, bottom: 30, level: 40 },
|
||||
{ name: 'UPD3', x: 210, top: 130, bottom: 20, level: 30 },
|
||||
]
|
||||
});
|
||||
}, [filter]);
|
||||
|
||||
const handleTabChange = (key) => {
|
||||
setActiveTab(key);
|
||||
};
|
||||
|
||||
const handleQuickDate = (type) => {
|
||||
setQuickDate(type);
|
||||
let start = moment();
|
||||
if (type === '1m') start = moment().subtract(1, 'months');
|
||||
if (type === '6m') start = moment().subtract(6, 'months');
|
||||
if (type === '1y') start = moment().subtract(1, 'years');
|
||||
setFilter({ ...filter, date: [start, moment()] });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="safety-panel-container">
|
||||
{/* Sidebar for navigation */}
|
||||
<div className="sidebar">
|
||||
<div
|
||||
className={`sidebar-btn ${activeTab === 'seepage' ? 'active' : ''}`}
|
||||
onClick={() => handleTabChange('seepage')}
|
||||
>
|
||||
渗压监测
|
||||
</div>
|
||||
<div
|
||||
className={`sidebar-btn ${activeTab === 'deformation' ? 'active' : ''}`}
|
||||
onClick={() => handleTabChange('deformation')}
|
||||
>
|
||||
变形监测
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Main content area */}
|
||||
<div className="main-content-area">
|
||||
{/* Filters bar */}
|
||||
<div className="filters-bar">
|
||||
{activeTab === 'seepage' ? (
|
||||
<>
|
||||
<Select
|
||||
value={filter.type}
|
||||
style={{ width: 120, marginRight: 12 }}
|
||||
onChange={v => setFilter({...filter, type: v})}
|
||||
dropdownStyle={{ background: '#0d2c4d', color: '#fff' }}
|
||||
>
|
||||
<Option value="saturation">浸润线图</Option>
|
||||
<Option value="process">过程线图</Option>
|
||||
</Select>
|
||||
|
||||
<span className="filter-label">断面:</span>
|
||||
<Select
|
||||
value={filter.section}
|
||||
style={{ width: 150, marginRight: 12 }}
|
||||
onChange={v => setFilter({...filter, section: v})}
|
||||
dropdownStyle={{ background: '#0d2c4d', color: '#fff' }}
|
||||
>
|
||||
<Option value="main_0_086">主坝0+086</Option>
|
||||
</Select>
|
||||
|
||||
<span className="filter-label">时间:</span>
|
||||
<RangePicker
|
||||
value={filter.date}
|
||||
onChange={v => setFilter({...filter, date: v})}
|
||||
style={{ width: 260, marginRight: 12 }}
|
||||
dropdownClassName="dark-picker-dropdown"
|
||||
/>
|
||||
|
||||
<Button className="ant-btn-ghost-blue" icon={<SearchOutlined />} onClick={() => {}}>查询</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Select value="过程线图" style={{ width: 120, marginRight: 12 }} disabled dropdownStyle={{ background: '#0d2c4d', color: '#fff' }}>
|
||||
<Option value="process">过程线图</Option>
|
||||
</Select>
|
||||
|
||||
<RangePicker
|
||||
value={filter.date}
|
||||
onChange={v => {
|
||||
setFilter({...filter, date: v});
|
||||
setQuickDate('');
|
||||
}}
|
||||
style={{ width: 260, marginRight: 12 }}
|
||||
dropdownClassName="dark-picker-dropdown"
|
||||
/>
|
||||
|
||||
<div className="quick-date-group" style={{ display: 'flex', marginRight: 12 }}>
|
||||
<Button type={quickDate === '1m' ? 'primary' : 'default'} onClick={() => handleQuickDate('1m')} style={{ borderRadius: '4px 0 0 4px' }}>近一月</Button>
|
||||
<Button type={quickDate === '6m' ? 'primary' : 'default'} onClick={() => handleQuickDate('6m')} style={{ borderRadius: '0', marginLeft: '-1px' }}>近半年</Button>
|
||||
<Button type={quickDate === '1y' ? 'primary' : 'default'} onClick={() => handleQuickDate('1y')} style={{ borderRadius: '0 4px 4px 0', marginLeft: '-1px' }}>近一年</Button>
|
||||
</div>
|
||||
|
||||
<Button className="ant-btn-ghost-blue" type="primary" onClick={() => {}}>查询</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Chart/Table content */}
|
||||
<div className="chart-content">
|
||||
{activeTab === 'seepage' ? (
|
||||
filter.type === 'saturation' ? (
|
||||
<ReactEcharts
|
||||
option={getOption(chartData)}
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
notMerge={true}
|
||||
lazyUpdate={true}
|
||||
/>
|
||||
) : (
|
||||
<ProcessLineChart />
|
||||
)
|
||||
) : (
|
||||
<DeformationPanel />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SafetyPanel;
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
.safety-panel-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
padding: 16px;
|
||||
color: #fff;
|
||||
|
||||
.sidebar {
|
||||
width: 140px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 15px;
|
||||
|
||||
.sidebar-btn {
|
||||
height: 36px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
color: #fff;
|
||||
font-size: 14px;
|
||||
border: 1px solid rgba(0, 160, 233, 0.6);
|
||||
background: rgba(0, 70, 120, 0.3);
|
||||
transition: all 0.3s;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 160, 233, 0.3);
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: rgba(0, 160, 233, 0.8);
|
||||
border-color: #00a0e9;
|
||||
box-shadow: 0 0 10px rgba(0, 160, 233, 0.4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.main-content-area {
|
||||
flex: 1;
|
||||
margin-left: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
.filters-bar {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-bottom: 16px;
|
||||
|
||||
.filter-label {
|
||||
margin-right: 8px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.chart-content {
|
||||
flex: 1;
|
||||
position: relative;
|
||||
overflow: hidden; // Prevent overflow
|
||||
|
||||
.echarts-for-react {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -8,14 +8,9 @@ import './index.less';
|
|||
import RainMonitor from './RainMonitor';
|
||||
import ReservoirPanel from './ReservoirPanel';
|
||||
import FlowPanel from './FlowPanel';
|
||||
import SafetyPanel from './SafetyPanel';
|
||||
const { RangePicker } = DatePicker;
|
||||
|
||||
const SafetyPanel = () => {
|
||||
return (
|
||||
<div className="awm-empty">内容待接入</div>
|
||||
);
|
||||
};
|
||||
|
||||
const AllWeatherModal = ({ active }) => {
|
||||
if (active === 'rain') return <RainMonitor />;
|
||||
if (active === 'reservoir') return <ReservoirPanel />;
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ const BasicInfo = ({ data, handlePreview }) => {
|
|||
>
|
||||
<Descriptions.Item label="水库名称" >{data?.resName}</Descriptions.Item>
|
||||
<Descriptions.Item label="水库代码" >{data?.resCode}</Descriptions.Item>
|
||||
<Descriptions.Item label="注册登记号" >{data?.regSn}</Descriptions.Item>
|
||||
<Descriptions.Item label="注册登记时间">{data?.regTime}</Descriptions.Item>
|
||||
{/* <Descriptions.Item label="注册登记号" >{data?.regSn}</Descriptions.Item>
|
||||
<Descriptions.Item label="注册登记时间">{data?.regTime}</Descriptions.Item> */}
|
||||
<Descriptions.Item label="工程位置">{data?.resLoc}</Descriptions.Item>
|
||||
<Descriptions.Item label="所在河流(水系)名称">{data?.basName}</Descriptions.Item>
|
||||
<Descriptions.Item label="水库规模">{skgmObj[data?.engScal]}</Descriptions.Item>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,218 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Descriptions,Image,Table,Button } from 'antd';
|
||||
import { PaperClipOutlined} from '@ant-design/icons';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import { httpget } from '@/utils/request';
|
||||
import { download } from '@/utils/tools';
|
||||
import PdfView from '@/views/Home/components/UI/PdfView';
|
||||
const MainBuildingInfo = () => {
|
||||
// 不动产
|
||||
const columns = [
|
||||
{ title: '序号', key: 'id', dataIndex: 'id', width: 60, align: "center", render: (v, r, i) => <span>{i+ 1}</span> },
|
||||
{ title: '名称', key: 'name', dataIndex: 'name' },
|
||||
{ title: '面积(万亩)', key: 'area', dataIndex: 'area' },
|
||||
{ title: '描述', key: 'area', dataIndex: 'area' },
|
||||
{
|
||||
title: '附件', key: 'files', dataIndex: 'files',
|
||||
render: (v, r) => <Button type='link' onClick={() => handlePreview(r)}>{(r.files && r.files.length > 0) ? r.files[0]?.fileName : ""}</Button>
|
||||
},
|
||||
]
|
||||
const [data, setData] = useState({})
|
||||
const [managementFiles, setManagementFiles] = useState([]);
|
||||
const [protectionFiles, setProtectionFiles] = useState([]);
|
||||
const [propertyFiles, setPropertyFiles] = useState([]);
|
||||
const [propertyData, setPropertyData] = useState([])
|
||||
const [pdfInfo, setPdfInfo] = useState({ visible: false, title: '', fileId: '' });
|
||||
const [imagePreview, setImagePreview] = useState({ visible: false, src: '' });
|
||||
const commonLabelStyle = {
|
||||
width: '200px',
|
||||
textAlign: 'right',
|
||||
};
|
||||
|
||||
const descriptionStyle = {
|
||||
marginBottom: '20px',
|
||||
};
|
||||
|
||||
const getDescriptionsProps = (title) => ({
|
||||
title: <span style={{ color: '#1890ff', fontSize: '16px', fontWeight: 'bold', borderLeft: '4px solid #1890ff', paddingLeft: '10px' }}>{title}</span>,
|
||||
column: 3,
|
||||
bordered: true,
|
||||
size: 'small',
|
||||
className: 'engineering-descriptions',
|
||||
labelStyle: commonLabelStyle,
|
||||
style: descriptionStyle,
|
||||
});
|
||||
|
||||
const getData = async () => {
|
||||
try {
|
||||
const res = await httpget(apiurl.sq.qys.projectAndWater.skhj.detail)
|
||||
if (res.code == 200) {
|
||||
// 处理三个附件字段
|
||||
const processFiles = (files) => {
|
||||
if (files && Array.isArray(files)) {
|
||||
return files.map(file => ({
|
||||
uid: file.fileId,
|
||||
name: file.fileName,
|
||||
status: 'done',
|
||||
url: `/gunshiApp/ss/reservoirDemarcationInfo/file/download/${file.fileId}`,
|
||||
response: { data: file }
|
||||
}));
|
||||
}
|
||||
return [];
|
||||
};
|
||||
setManagementFiles(processFiles(res.data.managementScopeAreaFiles));
|
||||
setProtectionFiles(processFiles(res.data.protectionScopeFiles));
|
||||
setPropertyFiles(processFiles(res.data.propertyCertificateAreaFiles));
|
||||
setData(res.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
const handlePreviewFile = (file) => {
|
||||
const fileData = file.response?.data || {
|
||||
fileName: file.name,
|
||||
fileId: file.uid
|
||||
};
|
||||
handlePreview({ files: [fileData] });
|
||||
}
|
||||
|
||||
const handlePreview = (item) => {
|
||||
const file = item?.files?.[0];
|
||||
if (!file || !file.fileName) return;
|
||||
const fileName = file.fileName;
|
||||
const fileId = file.fileId;
|
||||
const extension = fileName.split('.').pop().toLowerCase();
|
||||
const downloadUrl = `/gunshiApp/ss/propertyCertificate/file/download/${fileId}`;
|
||||
if (['jpg', 'jpeg', 'png', 'gif', 'bmp'].includes(extension)) {
|
||||
setImagePreview({
|
||||
visible: true,
|
||||
src: downloadUrl
|
||||
});
|
||||
} else if (extension === 'pdf') {
|
||||
setPdfInfo({
|
||||
visible: true,
|
||||
title: fileName,
|
||||
fileId: fileId
|
||||
});
|
||||
} else {
|
||||
download(downloadUrl)
|
||||
}
|
||||
};
|
||||
const getPropertyList = async () => {
|
||||
try {
|
||||
const res = await httpget(apiurl.sq.qys.projectAndWater.skhj.list)
|
||||
if (res.code == 200) {
|
||||
setPropertyData(res.data)
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getData()
|
||||
getPropertyList()
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<div className="form-container">
|
||||
<Descriptions {...getDescriptionsProps('管理和保护范围')}>
|
||||
<Descriptions.Item label="管理范围(km²)" >{data.managementScopeArea || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="管理范围划界说明" >{data.managementScopeAreaExplain || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="管理范围划界平面图" >
|
||||
{managementFiles.map(file => (
|
||||
<div key={file.uid} style={{ display: "flex", alignItems: "center", columnGap: 5, color: '#fff', marginLeft: 10 }}>
|
||||
<PaperClipOutlined />
|
||||
<span
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(e) => {
|
||||
handlePreviewFile(file)
|
||||
}}
|
||||
>
|
||||
{file.name}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="保护范围(km²)" >{data.protectionScopeArea || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="保护范围划界说明">{data.protectionScopeAreaExplain || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="保护范围平面图" >
|
||||
{protectionFiles.map(file => (
|
||||
<div key={file.uid} style={{ display: "flex", alignItems: "center", columnGap: 5, color: '#fff', marginLeft: 10 }}>
|
||||
<PaperClipOutlined />
|
||||
<span
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(e) => {
|
||||
handlePreviewFile(file)
|
||||
}}
|
||||
>
|
||||
{file.name}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</Descriptions.Item>
|
||||
<Descriptions.Item label="用地总面积(万亩)">{data.totalUseArea || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="用地划界说明">{data.totalUseAreaExplain || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="用地总面积平面图">
|
||||
{propertyFiles.map(file => (
|
||||
<div key={file.uid} style={{ display: "flex", alignItems: "center", columnGap: 5, color: '#fff', marginLeft: 10 }}>
|
||||
<PaperClipOutlined />
|
||||
<span
|
||||
style={{ cursor: "pointer" }}
|
||||
onClick={(e) => {
|
||||
handlePreviewFile(file)
|
||||
}}
|
||||
>
|
||||
{file.name}
|
||||
</span>
|
||||
|
||||
</div>
|
||||
))}
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<div className='bottomTable'>
|
||||
<div style={{ color: '#1890ff', fontSize: '16px', fontWeight: 'bold', borderLeft: '4px solid #1890ff', paddingLeft: '10px',marginBottom:20 }}>不动产权信息</div>
|
||||
<Table
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={propertyData}
|
||||
pagination={false}
|
||||
scroll={{ y: 500 }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* PDF Viewer */}
|
||||
{pdfInfo.visible && (
|
||||
<PdfView
|
||||
visible={pdfInfo.visible}
|
||||
onClose={() => setPdfInfo({ ...pdfInfo, visible: false })}
|
||||
title={pdfInfo.title}
|
||||
fileId={pdfInfo.fileId}
|
||||
url="/gunshiApp/ss/propertyCertificate/file/download/"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* Image Preview */}
|
||||
<div style={{ display: 'none' }}>
|
||||
<Image
|
||||
src={imagePreview.src}
|
||||
preview={{
|
||||
visible: imagePreview.visible,
|
||||
src: imagePreview.src,
|
||||
onVisibleChange: (value) => {
|
||||
setImagePreview({ ...imagePreview, visible: value });
|
||||
},
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MainBuildingInfo;
|
||||
|
|
@ -32,58 +32,70 @@ const MainBuildingInfo = ({data={}}) => {
|
|||
{/* 主坝 */}
|
||||
<Descriptions {...getDescriptionsProps('主坝')}>
|
||||
<Descriptions.Item label="坝型">{info.mainType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基岩性">{info.mainFoundation || '-'}</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.Item label="心墙顶高程(m)">{info.mainTopOfWaveBarrierElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝基防渗型式">{info.mainFoundControlType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 副坝 */}
|
||||
<Descriptions {...getDescriptionsProps('副坝')}>
|
||||
<Descriptions.Item label="坝型">{info.auxType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基岩性">{info.auxFoundation || '-'}</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.Item label="心墙顶高程(m)">{info.auxHeartWallCrestElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="坝基防渗型式">{info.auxFoundControlType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 溢洪道 */}
|
||||
<Descriptions {...getDescriptionsProps('溢洪道')}>
|
||||
<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.spillwayFoundation || '-'}</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.Item label="进口底高程(m)">{info.spillwayInBottomElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="底宽(m)">{info.spillwayBottomWidth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="渠深(m)">{info.spillwayCanalDepth || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大泄量(1%)(m³/s)">{info.spillwayMaxDischarge || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大泄量(0.1%)(m³/s)">{info.spillwayZeroMaxDischarge || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 灌溉发电洞 */}
|
||||
<Descriptions {...getDescriptionsProps('灌溉发电洞')}>
|
||||
<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 {...getDescriptionsProps('主坝输水管')}>
|
||||
<Descriptions.Item label="型式">{info.mwaterType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{info.mwaterCrossSection || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{info.mwaterInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="长度(m)">{info.mwaterLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="设计流量(m³/s)">{info.mwaterDesignFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进水口型式">{info.mwaterLiningType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
{/* 放空洞 */}
|
||||
<Descriptions {...getDescriptionsProps('放空洞')}>
|
||||
<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 {...getDescriptionsProps('副坝输水管')}>
|
||||
<Descriptions.Item label="型式">{info.awaterType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基岩性">{info.awaterFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{info.awaterCrossSection || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="壁厚(m)">{info.awaterThick || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{info.awaterInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="长度(m)">{info.awaterLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大流量(m³/s)">{info.awaterMaxFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进水口型式">{info.awaterLiningType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
|
||||
<Descriptions {...getDescriptionsProps('东输水隧洞')}>
|
||||
<Descriptions.Item label="型式">{info.waterConveyanceType || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="地基岩性">{info.waterConveyanceFoundation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="断面尺寸(m)">{info.waterConveyanceCrossSection || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="壁厚(m)">{info.waterConveyanceThick || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进口底板高程(m)">{info.waterConveyanceInletElevation || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="长度(m)">{info.waterConveyanceLength || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="最大流量(m³/s)">{info.waterConveyanceMaxFlow || '-'}</Descriptions.Item>
|
||||
<Descriptions.Item label="进水口型式">{info.waterConveyanceLiningType || '-'}</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,67 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { Descriptions, Image } from 'antd';
|
||||
import { httpget } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
import { config } from '@/config';
|
||||
const BasicInfo = ({ data }) => {
|
||||
const [fileList, setFileList] = useState([]) //上传文件列表
|
||||
// 获取管理用房图片
|
||||
const getManagePic = async () => {
|
||||
try {
|
||||
const result = await httpget(apiurl.sq.qys.projectAndWater.shuikuBasicinfo.mangeFile)
|
||||
if (result.code == 200) {
|
||||
const files = result.data?.files || [];
|
||||
if (files.length > 0) {
|
||||
const newFiles = files.map(item => ({
|
||||
filePath: item.filePath,
|
||||
fileId: item.fileId
|
||||
}))
|
||||
setFileList(newFiles)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
getManagePic()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="form-container">
|
||||
<Descriptions
|
||||
bordered
|
||||
column={2}
|
||||
size="small"
|
||||
className="engineering-descriptions"
|
||||
labelStyle={{ width: '160px', textAlign: 'right' }}
|
||||
>
|
||||
<Descriptions.Item label="主管部门" >{data?.competentDepartment}</Descriptions.Item>
|
||||
<Descriptions.Item label="管理单位" >{data?.managementUnit}</Descriptions.Item>
|
||||
<Descriptions.Item label="负责人">{data?.chargePerson}</Descriptions.Item>
|
||||
<Descriptions.Item label="注册登记号">{data?.regSn}</Descriptions.Item>
|
||||
<Descriptions.Item label="注册登记时间">{data?.regTime}</Descriptions.Item>
|
||||
<Descriptions.Item label="发证机关">{data?.issuingAuthority}</Descriptions.Item>
|
||||
<Descriptions.Item label="发证时间">{data?.issuingTime}</Descriptions.Item>
|
||||
<Descriptions.Item label="管理用房(m²)">{data?.managementHousing}</Descriptions.Item>
|
||||
<Descriptions.Item label="管理用房照片">
|
||||
<div className="file-link">
|
||||
{
|
||||
fileList.length > 0 ?
|
||||
fileList.map(item => <div key={item.uid} style={{ marginRight: 5 }} >
|
||||
<Image
|
||||
width={100}
|
||||
// height={50}
|
||||
src={config.minioIp + item.filePath}
|
||||
/>
|
||||
</div>) : null
|
||||
}
|
||||
</div>
|
||||
</Descriptions.Item>
|
||||
</Descriptions>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default BasicInfo;
|
||||
|
|
@ -5,6 +5,8 @@ import BasicInfo from './components/BasicInfo';
|
|||
import MainFeatureParams from './components/MainFeatureParams';
|
||||
import MainBuildingInfo from './components/MainBuildingInfo';
|
||||
import CapacityCurve from './components/CapacityCurve';
|
||||
import RunningInfo from './components/RunningInfo'
|
||||
import Demarcation from './components/Demarcation'
|
||||
import XlCurve from './components/XlCurve';
|
||||
import { httpget,httppost } from '@/utils/request';
|
||||
import apiurl from '@/service/apiurl';
|
||||
|
|
@ -21,6 +23,8 @@ const EngineeringElements = ({ data }) => {
|
|||
{ label: '工程基础信息', value: 'basic' },
|
||||
{ label: '主要特征参数', value: 'params' },
|
||||
{ label: '主要建筑物信息', value: 'buildings' },
|
||||
{ label: '运行管理信息', value: 'running' },
|
||||
{ label: '水库划界信息', value: 'demarcation' },
|
||||
{ label: '水库库容曲线', value: 'capacity-curve' },
|
||||
{ label: '水库泄流曲线', value: 'discharge-curve' },
|
||||
];
|
||||
|
|
@ -73,6 +77,10 @@ const EngineeringElements = ({ data }) => {
|
|||
return <MainFeatureParams data={data} />;
|
||||
case 'buildings':
|
||||
return <MainBuildingInfo data={info} />;
|
||||
case 'running':
|
||||
return <RunningInfo data={data} />;
|
||||
case 'demarcation':
|
||||
return <Demarcation />;
|
||||
case 'capacity-curve':
|
||||
return <CapacityCurve data={krLineList} />;
|
||||
case 'discharge-curve':
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const WaterRainSection = () => {
|
|||
const getRainList = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await httpget(apiurl.sy.sssyq.reservoir);
|
||||
const result = await httpget(apiurl.sy.sssyq.rain);
|
||||
if (result.code === 200) {
|
||||
setDataList(result.data);
|
||||
}
|
||||
|
|
@ -42,7 +42,7 @@ const WaterRainSection = () => {
|
|||
const getReservoirList = async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const result = await httpget(apiurl.sy.sssyq.rain);
|
||||
const result = await httpget(apiurl.sy.sssyq.reservoir);
|
||||
if (result.code === 200) {
|
||||
setDataList(result.data);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue