feat(): 对全天候的雨情监测开发
parent
b57adda8e5
commit
84016faa09
|
|
@ -285,7 +285,19 @@ input:-webkit-autofill:active {
|
||||||
th { color: #fff; }
|
th { color: #fff; }
|
||||||
td { color: rgba(255, 255, 255, 0.8); }
|
td { color: rgba(255, 255, 255, 0.8); }
|
||||||
}
|
}
|
||||||
|
.ant-picker-time-panel-cell-inner{
|
||||||
|
color: #fff!important;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-time-panel-column > li.ant-picker-time-panel-cell-selected .ant-picker-time-panel-cell-inner{
|
||||||
|
background: #00a0e9;
|
||||||
|
}
|
||||||
|
.ant-picker-time-panel-column > li.ant-picker-time-panel-cell .ant-picker-time-panel-cell-inner:hover{
|
||||||
|
background: #013056 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
.ant-picker-cell {
|
.ant-picker-cell {
|
||||||
color: rgba(255, 255, 255, 0.5); // Default inactive color
|
color: rgba(255, 255, 255, 0.5); // Default inactive color
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,10 @@ const apiurl = {
|
||||||
router: service + '/getRouters',
|
router: service + '/getRouters',
|
||||||
role: service + '/system/menu/list'
|
role: service + '/system/menu/list'
|
||||||
},
|
},
|
||||||
|
station: {
|
||||||
|
rainlist: service + '/real/rain/list',//雨量站
|
||||||
|
reservoirlist: service + '/reservoir/water/listV2',//水库水位站
|
||||||
|
},
|
||||||
sq: {
|
sq: {
|
||||||
qfg: {
|
qfg: {
|
||||||
info:service + '/attResBase/list'
|
info:service + '/attResBase/list'
|
||||||
|
|
@ -23,12 +27,22 @@ const apiurl = {
|
||||||
},
|
},
|
||||||
qth: {
|
qth: {
|
||||||
rainList: {
|
rainList: {
|
||||||
list:service + '/attResBase/rainBasinDivision/queryStPptnDetails/list',
|
list: service + '/attResBase/rainBasinDivision/queryStPptnDetails/list',
|
||||||
|
queryStPptnDetails: service + '/attResBase/rainBasinDivision/queryStPptnDetails/stcd', //实时雨量近几小时数据
|
||||||
|
tableList: service + '/attResBase/rainBasinDivision/queryStStbprpPerHour/StcdAndStartTimeAndEndTime',//小时历史雨量表格数据
|
||||||
|
chartList: service + '/attResBase/rainBasinDivision/queryStStbprpPerHourChart/StcdAndStartTimeAndEndTime',//小时历史雨量图数据
|
||||||
|
dayTableList: service + '/attResBase/rainBasinDivision/queryStStbprpPerDay/StcdAndStartTimeAndEndTime',//日历史雨量表格数据
|
||||||
|
dayChartList: service + '/attResBase/rainBasinDivision/queryStStbprpPerDayChart/StcdAndStartTimeAndEndTime',//日小时历史雨量图数据
|
||||||
|
nearbyHistory:service + '/attResBase/maxRain' //获取历史近几小时数据
|
||||||
},
|
},
|
||||||
|
reservoir: {
|
||||||
|
list:service + '/screen/monitoring/rsvr'
|
||||||
|
}
|
||||||
},
|
},
|
||||||
qzq: {
|
qzq: {
|
||||||
list: service + '/projectEvents/doc/page',
|
list: service + '/projectEvents/doc/page',
|
||||||
export: service + '/projectEvents/export'
|
export: service + '/projectEvents/export',
|
||||||
|
info :service + '/wholeCycle/get'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
import apiurl from "./apiurl";
|
||||||
|
import { httpget, httppost } from "@/utils/request";
|
||||||
|
import {message} from 'antd';
|
||||||
|
|
||||||
|
//雨情列表
|
||||||
|
export async function rainlist(params) {
|
||||||
|
const {data, code, msg} = await httppost(apiurl.station.rainlist, params) || {};
|
||||||
|
if (code !== 200) {
|
||||||
|
message.error(msg || '请求失败');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const mapData = data.map(i=>({
|
||||||
|
...i,
|
||||||
|
lgtd : Number(i.lgtd)-1,
|
||||||
|
lttd : Number(i.lttd)-1.2,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return mapData||[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//水库列表
|
||||||
|
export async function reservoirlist(params) {
|
||||||
|
const {data, code, msg} = await httppost(apiurl.station.reservoirlist, params) || {};
|
||||||
|
if (code !== 200) {
|
||||||
|
message.error(msg || '请求失败');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapData = data.map(i=>({
|
||||||
|
...i,
|
||||||
|
lgtd : Number(i.lgtd)-1,
|
||||||
|
lttd : Number(i.lttd)-1.2,
|
||||||
|
}))
|
||||||
|
|
||||||
|
return mapData||[];
|
||||||
|
}
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
import React,{useState,useEffect} from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { Table } from 'antd';
|
import { Table } from 'antd';
|
||||||
|
import CommonModal from '@/views/Home/components/UI/CommonModal';
|
||||||
import arrowIcon from '@/assets/images/card/arrow.png';
|
import arrowIcon from '@/assets/images/card/arrow.png';
|
||||||
import smallCard from '@/assets/images/card/smallCard.png';
|
import smallCard from '@/assets/images/card/smallCard.png';
|
||||||
import wrj from '@/assets/images/card/wrj.png';
|
import wrj from '@/assets/images/card/wrj.png';
|
||||||
import apiurl from '@/service/apiurl';
|
import apiurl from '@/service/apiurl';
|
||||||
import { httpget,httppost } from '@/utils/request';
|
import { httpget, httppost } from '@/utils/request';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import RightPanel from '../ModalComponents/AllWeatherModal/RainMonitor/RightPanel';
|
||||||
|
|
||||||
const AllWeatherControl = () => {
|
const AllWeatherControl = () => {
|
||||||
|
const [reservoirItem, setReservoirItem] = useState({})
|
||||||
const [rainList, setRainList] = useState([])
|
const [rainList, setRainList] = useState([])
|
||||||
|
const [detailVisible, setDetailVisible] = useState(false)
|
||||||
|
const [selectedStcd, setSelectedStcd] = useState(null)
|
||||||
const rainColumns = [
|
const rainColumns = [
|
||||||
{
|
{
|
||||||
title: '站名',
|
title: '站名',
|
||||||
|
|
@ -16,7 +21,7 @@ const AllWeatherControl = () => {
|
||||||
key: 'stnm',
|
key: 'stnm',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
width: 140,
|
width: 140,
|
||||||
ellipsis:true
|
ellipsis: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '今日',
|
title: '今日',
|
||||||
|
|
@ -41,17 +46,28 @@ const AllWeatherControl = () => {
|
||||||
|
|
||||||
// Reservoir Data
|
// Reservoir Data
|
||||||
const reservoirData = [
|
const reservoirData = [
|
||||||
{ label: '主坝坝前', value: '103.17', unit: 'm', showArrow: true, underline: true },
|
{ label: '主坝坝前', value: reservoirItem?.rz, unit: 'm', upArrow: reservoirItem?.status > 0, underline: true,downArrow:reservoirItem?.status < 0 },
|
||||||
{ label: '汛限水位', value: '104.50', unit: 'm' },
|
{ label: '汛限水位', value: reservoirItem?.flLowLimLev, unit: 'm' },
|
||||||
{ label: '距汛限', value: '-1.67', unit: 'm', isNegative: true },
|
{ label: '距汛限', value: reservoirItem?.gapFlLowLimLev, unit: 'm', isNegative: reservoirItem?.gapFlLowLimLev < 0 },
|
||||||
{ label: '副坝坝前', value: '104.17', unit: 'm' },
|
{ label: '副坝坝前', value: reservoirItem?.rz, unit: 'm' },
|
||||||
{ label: '当前库容', value: '3867.0', unit: '万m³'},
|
{ label: '当前库容', value: reservoirItem?.nowCap, unit: '万m³' },
|
||||||
{ label: '有效库容', value: '2867.0', unit: '万m³'},
|
{ label: '有效库容', value: reservoirItem?.effectiveCap, unit: '万m³' },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
//指定水库获取
|
||||||
|
const getReservoir = async () => {
|
||||||
|
try {
|
||||||
|
const result = await httpget(apiurl.sq.qth.reservoir.list);
|
||||||
|
if (result.code == 200) {
|
||||||
|
setReservoirItem(result.data[0])
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
const getRainList = async () => {
|
const getRainList = async () => {
|
||||||
try {
|
try {
|
||||||
const result = await httpget(apiurl.sq.qth.rainList);
|
const result = await httpget(apiurl.sq.qth.rainList.list);
|
||||||
if (result.code == 200) {
|
if (result.code == 200) {
|
||||||
setRainList(result.data)
|
setRainList(result.data)
|
||||||
}
|
}
|
||||||
|
|
@ -61,8 +77,9 @@ const AllWeatherControl = () => {
|
||||||
}
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getRainList()
|
getRainList()
|
||||||
|
getReservoir()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="all-weather-control">
|
<div className="all-weather-control">
|
||||||
{/* 雨情 Section */}
|
{/* 雨情 Section */}
|
||||||
|
|
@ -81,31 +98,47 @@ const AllWeatherControl = () => {
|
||||||
rowKey={'stcd'}
|
rowKey={'stcd'}
|
||||||
rowClassName={(record) => record.isTotal ? 'total-row' : ''}
|
rowClassName={(record) => record.isTotal ? 'total-row' : ''}
|
||||||
bordered={false}
|
bordered={false}
|
||||||
scroll={{y:300}}
|
scroll={{ y: 300 }}
|
||||||
|
onRow={(record) => ({
|
||||||
|
onClick: () => {
|
||||||
|
setSelectedStcd(record);
|
||||||
|
setDetailVisible(true);
|
||||||
|
}
|
||||||
|
})}
|
||||||
/>
|
/>
|
||||||
|
<CommonModal
|
||||||
|
title={selectedStcd?.stnm}
|
||||||
|
visible={detailVisible}
|
||||||
|
onClose={() => setDetailVisible(false)}
|
||||||
|
width={'70%'}
|
||||||
|
bodyStyle={{ background: 'transparent', padding: 12 }}
|
||||||
|
>
|
||||||
|
<RightPanel stcd={selectedStcd?.stcd} cleanMode={true} />
|
||||||
|
</CommonModal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* 水库水情 Section */}
|
{/* 水库水情 Section */}
|
||||||
<div className="section reservoir-section">
|
<div className="section reservoir-section">
|
||||||
<div className="section-header">
|
<div className="section-header">
|
||||||
<div className="title-wrapper">
|
<div className="title-wrapper">
|
||||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||||
<span className="section-title">水库水情</span>
|
<span className="section-title">水库水情</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="reservoir-cards">
|
<div className="reservoir-cards">
|
||||||
{reservoirData.map((item, index) => (
|
{reservoirData.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="reservoir-card"
|
className="reservoir-card"
|
||||||
style={{ backgroundImage: `url(${smallCard})` }}
|
style={{ backgroundImage: `url(${smallCard})` }}
|
||||||
>
|
>
|
||||||
<div className={`value ${item.isPrimary ? 'primary' : ''} ${item.isNegative ? 'negative' : ''}`}>
|
<div className={`value ${item.isPrimary ? 'primary' : ''} ${item.isNegative ? 'negative' : 'positive'}`}>
|
||||||
<span className={`num ${item.underline ? 'underline' : ''}`}>{item.value}</span>
|
<span className={`num ${item.underline ? 'underline' : ''}`}>{item.value}</span>
|
||||||
<span className="unit">{item.unit}</span>
|
<span className="unit">{item.unit}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="label">{item.label}</div>
|
<div className="label">{item.label}</div>
|
||||||
{item.showArrow && <span className="arrow-up">↑</span>}
|
{item.upArrow && <span className="arrow-up">↑</span>}
|
||||||
|
{item.downArrow && <span className="arrow-down">↓</span>}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -114,15 +147,15 @@ const AllWeatherControl = () => {
|
||||||
{/* 无人机 Section */}
|
{/* 无人机 Section */}
|
||||||
<div className="section uav-section">
|
<div className="section uav-section">
|
||||||
<div className="section-header">
|
<div className="section-header">
|
||||||
<div className="title-wrapper">
|
<div className="title-wrapper">
|
||||||
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
<img src={arrowIcon} alt="arrow" className="arrow-icon" />
|
||||||
<span className="section-title">无人机</span>
|
<span className="section-title">无人机</span>
|
||||||
</div>
|
</div>
|
||||||
<span className="link">视频墙</span>
|
<span className="link">视频墙</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="uav-content">
|
<div className="uav-content">
|
||||||
<div
|
<div
|
||||||
className="uav-image"
|
className="uav-image"
|
||||||
style={{ backgroundImage: `url(${wrj})` }}
|
style={{ backgroundImage: `url(${wrj})` }}
|
||||||
/>
|
/>
|
||||||
<div className="uav-actions">
|
<div className="uav-actions">
|
||||||
|
|
|
||||||
|
|
@ -148,12 +148,15 @@
|
||||||
margin-top: 2px;
|
margin-top: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.arrow-up {
|
.arrow-up,.arrow-down {
|
||||||
color: #ff4d4f;
|
color: #ff4d4f;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 5px;
|
right: 5px;
|
||||||
top: 5px;
|
top: 5px;
|
||||||
}
|
}
|
||||||
|
.arrow-down{
|
||||||
|
color: #68c639;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,66 @@
|
||||||
import React from 'react';
|
import React,{useState,useEffect} from 'react';
|
||||||
import smallCard from '@/assets/images/card/smallCard.png';
|
import smallCard from '@/assets/images/card/smallCard.png';
|
||||||
|
import apiurl from '@/service/apiurl';
|
||||||
|
import { httpget } from '@/utils/request';
|
||||||
|
import PdfView from '@/views/Home/components/UI/PdfView';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
|
||||||
const ManagementCycle = () => {
|
const ManagementCycle = () => {
|
||||||
|
const [info, setInfo] = useState({})
|
||||||
|
const [pdfVisible, setPdfVisible] = useState(false);
|
||||||
|
const [pdfConfig, setPdfConfig] = useState({ title: '', url: '', fileId: '' });
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
{ label: '安全鉴定', value: '三类坝' },
|
{ label: '安全鉴定', value: info?.identifyType },
|
||||||
{ label: '病险水库', value: '是' },
|
{ label: '病险水库', value: info?.isDanger },
|
||||||
{ label: '除险加固', value: '2024年11月' },
|
{ label: '除险加固', value: info?.startDate },
|
||||||
{ label: '降等报废', value: '无' },
|
{ label: '降等报废', value: info?.implementationMeasure },
|
||||||
{ label: '调度规则', value: '2023年12月', underline: true },
|
{
|
||||||
{ label: '应急预案', value: '2023年12月', underline: true },
|
label: '调度规则',
|
||||||
|
value: info?.dispatchTime,
|
||||||
|
underline: true,
|
||||||
|
clickable: true,
|
||||||
|
fileId:info?.dispatchFileIds?.length? info?.dispatchFileIds[0] + '':undefined // Assuming this field exists
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: '应急预案',
|
||||||
|
value: info?.emergencyTime,
|
||||||
|
underline: true,
|
||||||
|
clickable: true,
|
||||||
|
fileId:info?.emergencyFileIds?.length? info?.emergencyFileIds[0] + '':undefined // Assuming this field exists
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const handleItemClick = (item) => {
|
||||||
|
const url = '/gunshiApp/ss/resPlanB/file/download/';
|
||||||
|
// if (!item?.dispatchFileIds || item?.dispatchFileIds.length) return;
|
||||||
|
// const field = item.label == '调度规程' ? item?.dispatchFileIds[0] + '' :
|
||||||
|
// item?.emergencyFileIds[0] + ''
|
||||||
|
if (item.clickable) {
|
||||||
|
setPdfConfig({
|
||||||
|
title: item.label,
|
||||||
|
url,
|
||||||
|
fileId:item.fileId
|
||||||
|
});
|
||||||
|
setPdfVisible(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInfo = async () => {
|
||||||
|
try {
|
||||||
|
const result = await httpget(apiurl.sq.qzq.info)
|
||||||
|
if (result.code == 200) {
|
||||||
|
setInfo(result.data)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getInfo()
|
||||||
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="management-cycle">
|
<div className="management-cycle">
|
||||||
<div className="card-grid">
|
<div className="card-grid">
|
||||||
|
|
@ -19,7 +68,11 @@ const ManagementCycle = () => {
|
||||||
<div
|
<div
|
||||||
key={index}
|
key={index}
|
||||||
className="cycle-card"
|
className="cycle-card"
|
||||||
style={{ backgroundImage: `url(${smallCard})` }}
|
style={{
|
||||||
|
backgroundImage: `url(${smallCard})`,
|
||||||
|
cursor: item.clickable ? 'pointer' : 'default'
|
||||||
|
}}
|
||||||
|
onClick={() => handleItemClick(item)}
|
||||||
>
|
>
|
||||||
<div className={`value-wrapper ${item.underline ? 'underlined' : ''}`}>
|
<div className={`value-wrapper ${item.underline ? 'underlined' : ''}`}>
|
||||||
<span className="value">{item.value}</span>
|
<span className="value">{item.value}</span>
|
||||||
|
|
@ -28,6 +81,14 @@ const ManagementCycle = () => {
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<PdfView
|
||||||
|
visible={pdfVisible}
|
||||||
|
title={pdfConfig.title}
|
||||||
|
url={'/gunshiApp/ss/resPlanB/file/download'}
|
||||||
|
fileId={pdfConfig.fileId}
|
||||||
|
onClose={() => setPdfVisible(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,235 @@
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { DatePicker, Button, Table } from 'antd';
|
||||||
|
import { SearchOutlined } from '@ant-design/icons';
|
||||||
|
import ReactEcharts from 'echarts-for-react';
|
||||||
|
import apiurl from '@/service/apiurl';
|
||||||
|
import { httpget, httppost } from '@/utils/request';
|
||||||
|
import moment from 'moment';
|
||||||
|
import drpOption from './drpOption';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
|
export default function RightPanel({ stcd, cleanMode = false }) {
|
||||||
|
const days = moment().diff(moment().startOf('year'), 'days') + 1;
|
||||||
|
const defaultRange = [
|
||||||
|
moment().subtract(7, 'days').add(1, 'hour').set({ minute: 0, second: 0 }),
|
||||||
|
moment().add(1, 'hour').set({ minute: 0, second: 0 }),
|
||||||
|
];
|
||||||
|
|
||||||
|
const [dates, setDates] = useState(defaultRange);
|
||||||
|
const [viewMode, setViewMode] = useState('hour');
|
||||||
|
const [historyTableList, setHistoryTableList] = useState([]);
|
||||||
|
const [historyChartList, setHistoryChartList] = useState({});
|
||||||
|
const [historyRainDetail, sethistoryRainDetail] = useState({});
|
||||||
|
const [rainDetail, setRainDetail] = useState({});
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{ title: '时间', dataIndex: 'time', key: 'time', align: 'center', width: 200 },
|
||||||
|
{
|
||||||
|
title: viewMode === 'hour' ? '小时雨量(mm)' : '日雨量(mm)',
|
||||||
|
dataIndex: 'sumDrp',
|
||||||
|
key: 'sumDrp',
|
||||||
|
align: 'center',
|
||||||
|
render: (rec) => <span>{rec ?? '-'}</span>,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const option = useMemo(() => {
|
||||||
|
return drpOption({ echartData: historyChartList });
|
||||||
|
}, [historyChartList]);
|
||||||
|
|
||||||
|
const bottomStats = [
|
||||||
|
{ label: '最大1h雨量(mm)', value: historyRainDetail?.h1 ?? '-' },
|
||||||
|
{ label: '最大3h雨量(mm)', value: historyRainDetail?.h3 ?? '-' },
|
||||||
|
{ label: '最大6h雨量(mm)', value: historyRainDetail?.h6 ?? '-' },
|
||||||
|
{ label: '最大12h雨量(mm)', value: historyRainDetail?.h12 ?? '-' },
|
||||||
|
{ label: '本年降雨天数', value: rainDetail?.yearDrpDay, suffix: true, total: days },
|
||||||
|
{ label: '今日雨量(mm)', value: rainDetail?.today ?? '-' },
|
||||||
|
{ label: '昨日雨量(mm)', value: rainDetail?.yesterdayDrp ?? '-' },
|
||||||
|
{ label: '本月雨量(mm)', value: rainDetail?.monthDrp ?? '-' },
|
||||||
|
{ label: '本年雨量(mm)', value: rainDetail?.yearDrp ?? '-' },
|
||||||
|
{ label: '本年最大日雨量(mm)', value: rainDetail?.maxDrp ?? '-', suffix: true, total: rainDetail?.maxDrpTime },
|
||||||
|
];
|
||||||
|
|
||||||
|
const getRainDetail = async (stcd) => {
|
||||||
|
const result = await httpget(apiurl.sq.qth.rainList.queryStPptnDetails, { stcd });
|
||||||
|
if (result.code === 200) {
|
||||||
|
setRainDetail(result.data);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRainHistoryData = async (params) => {
|
||||||
|
try {
|
||||||
|
const result = await httppost(apiurl.sq.qth.rainList.tableList, params);
|
||||||
|
if (result.code === 200) {
|
||||||
|
setHistoryTableList(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRainHistoryChartData = async (params) => {
|
||||||
|
try {
|
||||||
|
const result = await httppost(apiurl.sq.qth.rainList.chartList, params);
|
||||||
|
if (result.code === 200) {
|
||||||
|
setHistoryChartList(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDayRainHistoryData = async (params) => {
|
||||||
|
try {
|
||||||
|
const result = await httppost(apiurl.sq.qth.rainList.dayTableList, params);
|
||||||
|
if (result.code === 200) {
|
||||||
|
setHistoryTableList(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDayRainHistoryChartData = async (params) => {
|
||||||
|
try {
|
||||||
|
const result = await httppost(apiurl.sq.qth.rainList.dayChartList, params);
|
||||||
|
if (result.code === 200) {
|
||||||
|
setHistoryChartList(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getRainHistoryDetail = async (params) => {
|
||||||
|
try {
|
||||||
|
const result = await httppost(apiurl.sq.qth.rainList.nearbyHistory, params);
|
||||||
|
if (result.code === 200) {
|
||||||
|
sethistoryRainDetail(result.data);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSearch = () => {
|
||||||
|
if (!stcd) return;
|
||||||
|
const params = {
|
||||||
|
startTime: dates
|
||||||
|
? viewMode === 'hour'
|
||||||
|
? dates[0]?.format('YYYY-MM-DD HH:mm:00')
|
||||||
|
: dates[0]?.format('YYYY-MM-DD 00:00:00')
|
||||||
|
: undefined,
|
||||||
|
endTime: dates
|
||||||
|
? viewMode === 'hour'
|
||||||
|
? dates[1]?.format('YYYY-MM-DD HH:mm:59')
|
||||||
|
: dates[1]?.format('YYYY-MM-DD 59:59:59')
|
||||||
|
: undefined,
|
||||||
|
stcd,
|
||||||
|
};
|
||||||
|
if (viewMode === 'hour') {
|
||||||
|
getRainHistoryData(params);
|
||||||
|
getRainHistoryChartData(params);
|
||||||
|
} else {
|
||||||
|
getDayRainHistoryData(params);
|
||||||
|
getDayRainHistoryChartData(params);
|
||||||
|
}
|
||||||
|
getRainHistoryDetail(params);
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stcd) {
|
||||||
|
getRainDetail(stcd);
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [stcd]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (stcd) {
|
||||||
|
handleSearch();
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [viewMode]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rain-monitor-container">
|
||||||
|
<div className="main-content">
|
||||||
|
<div className="right-panel">
|
||||||
|
<div className="panel-header" style={cleanMode ? { justifyContent: 'flex-start' } : {}}>
|
||||||
|
{!cleanMode && <div className="query-label"><span className="dot"></span>数据查询</div>}
|
||||||
|
<div className="query-controls" style={cleanMode ? { marginLeft: 0 } : {}}>
|
||||||
|
<RangePicker
|
||||||
|
showTime={viewMode === 'hour'}
|
||||||
|
value={dates}
|
||||||
|
onChange={setDates}
|
||||||
|
style={{ width: 340 }}
|
||||||
|
format={viewMode === 'hour' ? 'YYYY-MM-DD HH:mm' : 'YYYY-MM-DD'}
|
||||||
|
allowClear={false}
|
||||||
|
dropdownClassName="rain-monitor-date-dropdown"
|
||||||
|
/>
|
||||||
|
<Button type="primary" className="ant-btn-ghost-blue" icon={<SearchOutlined />} onClick={handleSearch}>查询</Button>
|
||||||
|
<div className="time-toggle">
|
||||||
|
<Button
|
||||||
|
type={viewMode === 'hour' ? 'primary' : 'default'}
|
||||||
|
className={viewMode === 'hour' ? 'ant-btn-ghost-blue' : 'btn-transparent'}
|
||||||
|
onClick={() => setViewMode('hour')}
|
||||||
|
>
|
||||||
|
小时
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
type={viewMode === 'day' ? 'primary' : 'default'}
|
||||||
|
className={viewMode === 'day' ? 'ant-btn-ghost-blue' : 'btn-transparent'}
|
||||||
|
onClick={() => setViewMode('day')}
|
||||||
|
>
|
||||||
|
日
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="table-chart-layout">
|
||||||
|
<div className="data-table">
|
||||||
|
<Table
|
||||||
|
columns={columns}
|
||||||
|
dataSource={historyTableList}
|
||||||
|
size="small"
|
||||||
|
pagination={false}
|
||||||
|
scroll={{ y: 400 }}
|
||||||
|
rowKey="time"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="chart-view">
|
||||||
|
<div className="chart-container">
|
||||||
|
<ReactEcharts
|
||||||
|
option={option}
|
||||||
|
style={{ height: '100%', width: '100%' }}
|
||||||
|
notMerge={true}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="bottom-stats-grid">
|
||||||
|
{bottomStats.slice(0, 5).map((i, idx) => <div className="grid-header" key={`h1-${idx}`}>{i.label}</div>)}
|
||||||
|
{bottomStats.slice(0, 5).map((i, idx) => (
|
||||||
|
<div className="grid-value" key={`v1-${idx}`}>
|
||||||
|
<span className={i.suffix ? 'special-text' : ''}>{i.value}</span>
|
||||||
|
{i.total && <span>/{i.total}</span>}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{bottomStats.slice(5, 10).map((i, idx) => <div className="grid-header" key={`h2-${idx}`}>{i.label}</div>)}
|
||||||
|
{bottomStats.slice(5, 10).map((i, idx) => (
|
||||||
|
<div className="grid-value" key={`v2-${idx}`}>
|
||||||
|
{i.value}
|
||||||
|
{i.total && <span className="special-text">{i.total ? `(${moment(i.total).format('YYYY-MM-DD')})` : ''}</span>}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,179 @@
|
||||||
|
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import echarts from 'echarts/lib/echarts';
|
||||||
|
|
||||||
|
export default function DrpOption({ echartData, grid }) {
|
||||||
|
let totalDrp = 0;
|
||||||
|
const DRPLEVEL = [10, 20, 50, 100, 250];
|
||||||
|
const maxVal = DRPLEVEL.find(o => o > totalDrp);
|
||||||
|
const xMaxVal = echartData?.actual ? DRPLEVEL.find(o => {
|
||||||
|
let max = Math.max(...echartData?.actual || [])
|
||||||
|
return o > max
|
||||||
|
}):maxVal
|
||||||
|
const yMaxVal = echartData?.actual ? DRPLEVEL.find(o => {
|
||||||
|
let max = Math.max(...echartData?.total)
|
||||||
|
return o > max
|
||||||
|
}): maxVal
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
tooltip: {
|
||||||
|
trigger: 'axis',
|
||||||
|
},
|
||||||
|
grid: grid || {
|
||||||
|
x: 40,
|
||||||
|
y: 30,
|
||||||
|
x2: 30,
|
||||||
|
y2: 28,
|
||||||
|
borderWidth: 0
|
||||||
|
},
|
||||||
|
legend: {
|
||||||
|
// 显示图例
|
||||||
|
show: true,
|
||||||
|
// 图例的位置
|
||||||
|
data: ['实测', '累计'],
|
||||||
|
textStyle: { color: '#fff' },
|
||||||
|
},
|
||||||
|
calculable: true,
|
||||||
|
xAxis: [
|
||||||
|
{
|
||||||
|
type: 'category',
|
||||||
|
data: echartData?.time,
|
||||||
|
splitLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
formatter: val => val.substr('2020-'.length, 11)
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
lineStyle: {
|
||||||
|
color: '#07a6ff',
|
||||||
|
width: 0.5,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
],
|
||||||
|
yAxis: [
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
position: 'left',
|
||||||
|
name: "雨量mm",
|
||||||
|
nameTextStyle: { color: '#fff' },
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#07a6ff',
|
||||||
|
width: 0.25,
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: xMaxVal
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'value',
|
||||||
|
position: 'right',
|
||||||
|
nameTextStyle: { color: '#fff' },
|
||||||
|
name:"累计mm",
|
||||||
|
splitLine: {
|
||||||
|
show: true,
|
||||||
|
lineStyle: {
|
||||||
|
color: '#07a6ff',
|
||||||
|
width: 0.25,
|
||||||
|
type: 'dashed'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
axisLabel: {
|
||||||
|
color: '#fff',
|
||||||
|
fontSize: 12,
|
||||||
|
},
|
||||||
|
axisLine: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
axisTick: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
min: 0,
|
||||||
|
max: yMaxVal
|
||||||
|
}
|
||||||
|
],
|
||||||
|
series: [
|
||||||
|
{
|
||||||
|
name: '实测',
|
||||||
|
type: 'bar',
|
||||||
|
barWidth: '60%',
|
||||||
|
data: echartData?.actual,
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
barBorderRadius: [3, 3, 0, 0],
|
||||||
|
color: new echarts.graphic.LinearGradient(
|
||||||
|
0, 0, 0, 1,
|
||||||
|
[
|
||||||
|
{ offset: 0, color: '#3876cd' },
|
||||||
|
{ offset: 0.5, color: '#45b4e7' },
|
||||||
|
{ offset: 1, color: '#54ffff' }
|
||||||
|
]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
markPoint: {
|
||||||
|
data: [
|
||||||
|
{ type: 'max', name: '最大值', symbol: 'circle', symbolSize: 1, symbolOffset: [0, -12] },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
yAxisIndex: 1,
|
||||||
|
name: '累计',
|
||||||
|
type: 'line',
|
||||||
|
showSymbol: false,
|
||||||
|
label: {
|
||||||
|
show: false,
|
||||||
|
},
|
||||||
|
data: echartData?.total,
|
||||||
|
lineStyle: {
|
||||||
|
normal: {
|
||||||
|
width: 1,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
normal: {
|
||||||
|
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{
|
||||||
|
offset: 0,
|
||||||
|
color: 'rgba(3, 194, 236, 0.3)'
|
||||||
|
}, {
|
||||||
|
offset: 0.8,
|
||||||
|
color: 'rgba(3, 194, 236, 0)'
|
||||||
|
}
|
||||||
|
], false),
|
||||||
|
shadowColor: 'rgba(0, 0, 0, 0.1)',
|
||||||
|
shadowBlur: 10
|
||||||
|
}
|
||||||
|
},
|
||||||
|
itemStyle: {
|
||||||
|
normal: {
|
||||||
|
color: '#03C2EC'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,98 @@
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react';
|
||||||
|
import { Select } from 'antd';
|
||||||
|
import usePageTable from '@/components/crud/usePageTable';
|
||||||
|
import { createCrudService } from '@/components/crud/_';
|
||||||
|
import apiurl from '@/service/apiurl';
|
||||||
|
import { httpget,httppost } from '@/utils/request';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { rainlist } from '@/service/station';
|
||||||
|
import RightPanel from './RightPanel';
|
||||||
|
import './index.less';
|
||||||
|
|
||||||
|
const RainMonitor = () => {
|
||||||
|
//实时雨量
|
||||||
|
const [selectList, setSelectList] = useState([])
|
||||||
|
const [selected, setSelected] = useState('')
|
||||||
|
const [rainDetail, setRainDetail] = useState({})
|
||||||
|
|
||||||
|
const stats = [
|
||||||
|
{ label: '近1小时', value: rainDetail?.h1 ?? '-', unit: 'mm' },
|
||||||
|
{ label: '近3小时', value: rainDetail?.h3 ?? '-', unit: 'mm' },
|
||||||
|
{ label: '近6小时', value: rainDetail?.h6 ?? '-', unit: 'mm' },
|
||||||
|
{ label: '近12小时', value: rainDetail?.h12 ?? '-', unit: 'mm' },
|
||||||
|
{ label: '近24小时', value: rainDetail?.h24 ?? '-', unit: 'mm' },
|
||||||
|
{ label: '近48小时', value: rainDetail?.h48 ?? '-', unit: 'mm' },
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// 获取雨情站点
|
||||||
|
const getRainStationList = async() => {
|
||||||
|
try {
|
||||||
|
const data = await rainlist({})
|
||||||
|
setSelectList(data.map(item => ({ label: item.stnm, value: item.stcd,...item})))
|
||||||
|
setSelected(data[0].stcd)
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取实时详细雨量的 近几小时数据
|
||||||
|
const getRainDetail = async (stcd) => {
|
||||||
|
const result = await httpget(apiurl.sq.qth.rainList.queryStPptnDetails, { stcd });
|
||||||
|
if (result.code == 200) {
|
||||||
|
setRainDetail(result.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getRainStationList();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (selected) {
|
||||||
|
getRainDetail(selected);
|
||||||
|
}
|
||||||
|
}, [selected]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="rain-monitor-container">
|
||||||
|
<div className="main-content">
|
||||||
|
{/* Left Side: Stats Cards */}
|
||||||
|
<div className="left-panel">
|
||||||
|
<div className="panel-header">
|
||||||
|
<div className="query-label"><span className="dot"></span>实时雨情</div>
|
||||||
|
<div className="station-select">
|
||||||
|
<span>站点:</span>
|
||||||
|
<Select
|
||||||
|
value={selected}
|
||||||
|
onChange={setSelected}
|
||||||
|
style={{ width: 200 }}
|
||||||
|
options={selectList}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="update-time-banner">
|
||||||
|
雨情最新上报时间:{rainDetail.tm}
|
||||||
|
</div>
|
||||||
|
<div className="stats-grid">
|
||||||
|
{stats.map((item, idx) => (
|
||||||
|
<div key={idx} className="stat-card">
|
||||||
|
<div className="stat-value">
|
||||||
|
<span className="num">{item.value}</span>
|
||||||
|
<span className="unit"> {item.unit}</span>
|
||||||
|
</div>
|
||||||
|
<div className="stat-label">{item.label}</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<RightPanel stcd={selected} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default RainMonitor;
|
||||||
|
|
@ -0,0 +1,324 @@
|
||||||
|
.rain-monitor-container {
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
color: #fff;
|
||||||
|
|
||||||
|
.main-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.left-panel {
|
||||||
|
// flex: 1; /* 1:2 ratio */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 42px;
|
||||||
|
.query-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
.dot {
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background: #00a0e9;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.station-select {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
span { margin-right: 8px; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.update-time-banner {
|
||||||
|
background: rgba(0, 160, 233, 0.1);
|
||||||
|
border: 1px solid rgba(0, 160, 233, 0.3);
|
||||||
|
padding: 8px;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #fff;
|
||||||
|
width: 70%;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stats-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
gap: 42px 20px;
|
||||||
|
|
||||||
|
.stat-card {
|
||||||
|
width: calc(50% - 10px);
|
||||||
|
background: rgba(255, 255, 255, 0.05);
|
||||||
|
padding:25px 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
transition: all 0.3s;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba(0, 160, 233, 0.5);
|
||||||
|
background: rgba(0, 160, 233, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.stat-value {
|
||||||
|
margin-bottom: 24px;
|
||||||
|
.num {
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #00e5ff;
|
||||||
|
}
|
||||||
|
.unit {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.stat-label {
|
||||||
|
font-size: 16px;
|
||||||
|
color: rgba(255, 255, 255, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-panel {
|
||||||
|
flex: 2; /* 1:2 ratio */
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.panel-header {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
height: 42px;
|
||||||
|
.query-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
.dot {
|
||||||
|
width: 4px;
|
||||||
|
height: 16px;
|
||||||
|
background: #00a0e9;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.query-controls {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.time-toggle {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
margin-left: 16px;
|
||||||
|
|
||||||
|
.btn-transparent {
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid #00a0e9;
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: none;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
color: #00a0e9;
|
||||||
|
background: rgba(0, 160, 233, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-chart-layout {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
.data-table {
|
||||||
|
width: 330px;
|
||||||
|
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.chart-view {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-radius: 4px;
|
||||||
|
padding: 12px;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.chart-container {
|
||||||
|
flex: 1;
|
||||||
|
min-height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.bottom-stats-grid {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border-top: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
border-left: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
|
||||||
|
.grid-header {
|
||||||
|
width: 20%;
|
||||||
|
background: rgba(0, 160, 233, 0.1);
|
||||||
|
color: rgba(255, 255, 255);
|
||||||
|
padding: 8px 4px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
border-right: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
border-bottom: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-value {
|
||||||
|
width: 20%;
|
||||||
|
color: #fff;
|
||||||
|
padding: 8px 4px;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-right: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
border-bottom: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
|
||||||
|
.special-text {
|
||||||
|
color: #00e5ff;
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time Picker Panel Styles - REMOVED (moved to .rain-monitor-date-dropdown) */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dropdown Styles - Must be outside .rain-monitor-container because it renders in body */
|
||||||
|
.rain-monitor-date-dropdown {
|
||||||
|
background-color: #082f4d; // Ensure main background is dark
|
||||||
|
|
||||||
|
.ant-picker-panel-container {
|
||||||
|
background-color: #082f4d;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 160, 233, 0.3);
|
||||||
|
border: 1px solid rgba(0, 160, 233, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-header {
|
||||||
|
color: #fff;
|
||||||
|
border-bottom: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
|
||||||
|
button {
|
||||||
|
color: #fff;
|
||||||
|
&:hover {
|
||||||
|
color: #00a0e9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-content {
|
||||||
|
th {
|
||||||
|
color: #00a0e9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-cell {
|
||||||
|
color: rgba(255, 255, 255, 0.7);
|
||||||
|
|
||||||
|
&.ant-picker-cell-in-view {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .ant-picker-cell-inner {
|
||||||
|
background: rgba(0, 160, 233, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-picker-cell-selected .ant-picker-cell-inner {
|
||||||
|
background: #00a0e9;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range Selection Fix - Remove "Red Box" Color (Blue Background)
|
||||||
|
&-in-range::before {
|
||||||
|
background: transparent !important; // Remove the blue background
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure range start/end still have background
|
||||||
|
&-range-start .ant-picker-cell-inner,
|
||||||
|
&-range-end .ant-picker-cell-inner {
|
||||||
|
background: #00a0e9 !important;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Time Picker Styles */
|
||||||
|
.ant-picker-time-panel {
|
||||||
|
border-left: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-datetime-panel {
|
||||||
|
.ant-picker-time-panel {
|
||||||
|
border-left: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-time-panel-column {
|
||||||
|
border-left: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
> li.ant-picker-time-panel-cell {
|
||||||
|
.ant-picker-time-panel-cell-inner {
|
||||||
|
color: rgba(255, 255, 255, 0.8) !important; // Force white color
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba(0, 160, 233, 0.2);
|
||||||
|
color: #fff !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.ant-picker-time-panel-cell-selected {
|
||||||
|
.ant-picker-time-panel-cell-inner {
|
||||||
|
background: rgba(0, 160, 233, 0.4);
|
||||||
|
color: #00a0e9 !important;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-footer {
|
||||||
|
border-top: 1px solid rgba(0, 160, 233, 0.2);
|
||||||
|
|
||||||
|
.ant-picker-today-btn {
|
||||||
|
color: #00a0e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-picker-ok {
|
||||||
|
.ant-btn {
|
||||||
|
background-color: #00a0e9;
|
||||||
|
border-color: #00a0e9;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #008cc9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,42 +5,10 @@ import usePageTable from '@/components/crud/usePageTable';
|
||||||
import { createCrudService } from '@/components/crud/_';
|
import { createCrudService } from '@/components/crud/_';
|
||||||
import apiurl from '@/service/apiurl';
|
import apiurl from '@/service/apiurl';
|
||||||
import './index.less';
|
import './index.less';
|
||||||
|
import RainMonitor from './RainMonitor';
|
||||||
const { RangePicker } = DatePicker;
|
const { RangePicker } = DatePicker;
|
||||||
|
|
||||||
const RainPanel = () => {
|
|
||||||
const { tableProps, search } = usePageTable(createCrudService(apiurl.sq.qth.rainList).find);
|
|
||||||
const [range, setRange] = useState();
|
|
||||||
useEffect(() => {
|
|
||||||
search({ search: {} });
|
|
||||||
}, []);
|
|
||||||
const columns = [
|
|
||||||
{ title: '时间', dataIndex: 'tm', key: 'tm', width: 140, align: 'center' },
|
|
||||||
{ title: '小时雨量(mm)', dataIndex: 'drp', key: 'drp', align: 'center' },
|
|
||||||
];
|
|
||||||
const option = useMemo(() => ({
|
|
||||||
title: { text: '雨量趋势', left: 'center', textStyle: { color: '#fff' } },
|
|
||||||
tooltip: { trigger: 'axis' },
|
|
||||||
grid: { left: '8%', right: '4%', bottom: '10%', top: '15%' },
|
|
||||||
xAxis: { type: 'category', data: (tableProps.dataSource || []).map(i => i.tm), axisLabel: { color: '#fff' } },
|
|
||||||
yAxis: { type: 'value', axisLabel: { color: '#fff' }, splitLine: { show: true, lineStyle: { color: 'rgba(255,255,255,0.2)' } } },
|
|
||||||
series: [{ type: 'line', smooth: true, data: (tableProps.dataSource || []).map(i => i.drp), areaStyle: { color: 'rgba(0,160,233,0.25)' }, lineStyle: { color: '#00a0e9' } }],
|
|
||||||
}), [tableProps.dataSource]);
|
|
||||||
return (
|
|
||||||
<div className="awm-grid">
|
|
||||||
<div className="awm-left">
|
|
||||||
<div className="awm-toolbar">
|
|
||||||
<RangePicker value={range} onChange={setRange} />
|
|
||||||
<Button type="primary" className="ant-btn-ghost-blue" onClick={() => search({ search: { range } })}>查询</Button>
|
|
||||||
</div>
|
|
||||||
<Table columns={columns} {...tableProps} size="small" pagination={false} scroll={{ y: 360 }} />
|
|
||||||
</div>
|
|
||||||
<div className="awm-right">
|
|
||||||
<ReactEcharts option={option} style={{ height: '100%', width: '100%' }} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const ReservoirPanel = () => {
|
const ReservoirPanel = () => {
|
||||||
const columns = [
|
const columns = [
|
||||||
|
|
@ -107,7 +75,7 @@ const SafetyPanel = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const AllWeatherModal = ({ active }) => {
|
const AllWeatherModal = ({ active }) => {
|
||||||
if (active === 'rain') return <RainPanel />;
|
if (active === 'rain') return <RainMonitor />;
|
||||||
if (active === 'reservoir') return <ReservoirPanel />;
|
if (active === 'reservoir') return <ReservoirPanel />;
|
||||||
if (active === 'flow') return <FlowPanel />;
|
if (active === 'flow') return <FlowPanel />;
|
||||||
return <SafetyPanel />;
|
return <SafetyPanel />;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,9 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import CommonModal from '../CommonModal';
|
import CommonModal from '../CommonModal';
|
||||||
|
import { config } from "@/config";
|
||||||
const PdfView = ({ visible, title, onClose, url, fileId }) => {
|
const PdfView = ({ visible, title, onClose, url, fileId }) => {
|
||||||
|
console.log(url);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommonModal
|
<CommonModal
|
||||||
visible={visible}
|
visible={visible}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue