diff --git a/src/service/apiurl.js b/src/service/apiurl.js index 92779f3..79606fb 100644 --- a/src/service/apiurl.js +++ b/src/service/apiurl.js @@ -3,7 +3,12 @@ const service_fxdd = '/gunshiApp/tsg' const service_xyt = '/gunshiApp/tsg'//登陆先用小玉潭 const service_ykz = '/gunshiApp/ykz' +const service_test = '/gunshiApp/dcpj' + const apiurl = { + test: { + find: service_test + '/stPRHisData/getHisData' + }, setMenu: service_fxdd + '/visitMenuLog/insert', setPassword: service_fxdd + '/user/updateSecretKey', login: { diff --git a/src/setupProxy.js b/src/setupProxy.js index 33a5f1d..c38ddf0 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -24,4 +24,13 @@ module.exports = function (app) { }, }) ); + + //卫星云图,雷达回波需要 + app.use( + '/gunshiApp/dcpj', + createProxyMiddleware({ + target: 'http://local.gunshiiot.com:18083', + changeOrigin: true, + }) + ); }; diff --git a/src/views/TestLine/drpOption.js b/src/views/TestLine/drpOption.js index 26fa204..558ea1e 100644 --- a/src/views/TestLine/drpOption.js +++ b/src/views/TestLine/drpOption.js @@ -1,15 +1,23 @@ import * as echarts from 'echarts'; import moment, { min } from 'moment'; -export default function drpOption(predict = [], history = []) { - console.log("predict", predict); - +export default function drpOption(predict=[],history=[],type) { + const LimitWater = type == 'cq' ? 112 : + type == 'sxs' ? 72.01 : + type == 'wpc' ? 112 : 0; // 水位 - const minRz = Math.floor(Math.min(...history.map(item => item.waters), ...predict.map(item => item.predict))) - const maxRz = Math.ceil(Math.max(...history.map(item => item.waters), ...predict.map(item => item.predict))) + const minRz = Math.floor(Math.min(...history.map(item => item.waters),LimitWater, ...predict.map(item => item.predict))) + const maxRz = Math.ceil(Math.max(...history.map(item => item.waters), LimitWater,...predict.map(item => item.predict))) // 雨量 const mindrp = Math.floor(Math.min(...history.map(item => item.rains))) const maxdrp = Math.ceil(Math.max(...history.map(item => item.rains))) + + // // 水位 + // const minRz = Math.floor(Math.min(...data.map(item => item.water),...data.map(item => item.predict))) + // const maxRz = Math.ceil(Math.max(...data.map(item => item.water),...data.map(item => item.predict))) + // // 雨量 + // const mindrp = Math.floor(Math.min(...data.map(item => item.rain))) + // const maxdrp = Math.ceil(Math.max(...data.map(item => item.rain))) console.log(minRz, maxRz); return { @@ -30,7 +38,7 @@ export default function drpOption(predict = [], history = []) { toolbox: { show: true, top: "15%", - right: "1%", + right: "0%", orient: 'vertical', feature: { dataZoom: { @@ -104,7 +112,7 @@ export default function drpOption(predict = [], history = []) { ], dataZoom: [{ type: 'inside', - start: 0, + start: (600 / history.length) * 100, end: 100 }, { start: 0, @@ -120,22 +128,23 @@ export default function drpOption(predict = [], history = []) { } }], series: [ - { - name: "实时水位", - type: "line", - showSymbol: false, - data: history.map(item => [item.tm, item.waters]), - smooth: true, - }, { name: "实时雨量", - type: "line", + type: "bar", color: '#F59A23', yAxisIndex: 1, showSymbol: false, data: history.map(item => [item.tm, item.rains]), smooth: true, }, + { + name: "实时水位", + type: "line", + showSymbol: false, + data: history.map(item => [item.tm, item.waters]), + smooth: true, + }, + { name: "预测水位", type: "line", @@ -145,53 +154,16 @@ export default function drpOption(predict = [], history = []) { data: predict.map(item => [item.tm, item.predict]), smooth: true, }, - // { - // name: "预测水量", - // yAxisIndex: 0, - // type: "line", - // showSymbol: true, - // data:[...data2], - // smooth: true, - // itemStyle: { normal: { label: { show: true } } } - // }, - // { - // name: "预测雨量", - // yAxisIndex: 1, - // type: "line", - // showSymbol: true, - // data: data4, - // smooth: true, - // itemStyle: { normal: { label: { show: true } } } - // }, - // { - // type: "line", - // data: [], - // markLine: { - // symbol: "none", - // lineStyle: { - // type: "solid", - // width: 2, - // }, - // data: [ - // // 下面绿色线 - // [ - // // 下面半截绿色的线 - // { - // xAxis: 599, - // yAxis: minRz, - // lineStyle: { - // color: "rgba(46, 224, 85, 1)", - // }, - // }, - // { - // xAxis: 599, - // yAxis: splitLineData[1], - // }, - // ], - // ], - // }, - - // }, + { + name: LimitWater != 0 ? "汛限水位" :'', + type: "line", + yAxisIndex: 0, + color:"#85ea2d", + showSymbol: false, + data:LimitWater != 0 ? history.map(item => [item.tm, LimitWater]) : [], + smooth: true, + }, + ], } } \ No newline at end of file diff --git a/src/views/TestLine/index.js b/src/views/TestLine/index.js index 7c80065..5a1f279 100644 --- a/src/views/TestLine/index.js +++ b/src/views/TestLine/index.js @@ -1,5 +1,5 @@ import React, { Fragment, useRef, useMemo, useEffect, useState } from 'react'; -import { Table, Card, Modal, Form, Input, Button, Row, Col, Typography, message, Tabs, Image, InputNumber } from 'antd'; +import { Table, Card, Modal, Form, Spin, Button, Row, Col, Typography, message, Tabs, Image, InputNumber, Descriptions } from 'antd'; import ToolBar from './toolbar' import ReactEcharts from 'echarts-for-react'; import './index.less' @@ -7,298 +7,104 @@ import drpOption from './drpOption.js' import { httppost2 } from '../../utils/request'; import TestApp from './createData.js' import { getAllHydroBatches, responseData } from './watersTools' -const TableE = ({ count, setEditData, tableData }) => { - const EditableCell = ({ - editing, - dataIndex, - title, - inputType, - record, - index, - children, - ...restProps - }) => { - const inputNode = ; - - return ( - - {editing ? ( - - {inputNode} - - ) : ( - children - )} - - ); - }; - const [editingKey, setEditingKey] = useState(''); - const [details, setDetails] = useState([]) - const isEditing = (record) => { - return editingKey.includes(record.key); +import apiurl from '../../service/apiurl'; +import moment from 'moment'; +export default function TestLine() { + const obj = { + 'hjw': '60906600', + 'sxs': '60917600', + 'szl': '60918000', + "wpc": 'ZH201606', + 'cq':'61013270' } + const [searchVal, setSearchVal] = useState(false) + const [historyData, setHistoryData] = useState([]) + const [predictData, setPredictData] = useState([]) + const [tableList, setTableList] = useState([]) + const [loading, setLoading] = useState(false) + const options = useMemo(() => { + if (searchVal.code) { + return drpOption(predictData, historyData,searchVal.code) + } + }, [predictData, historyData,searchVal]) + + // const options = useMemo(() => { + // return drpOption(tableList) + // }, [tableList]) + + + // 测试 const columns = [ { - title: '预见期', + title: '预测时间点', dataIndex: 'tm', - width: '30%', - + key: 'tm', + width: 175, + align: 'center', + fixed:'left' }, { - title: '雨量', - dataIndex: 'drp', - width: '30%', - editable: true, + title: '实际雨量(mm)', + dataIndex: 'rain', + key: 'rain', + width: 100, align: 'center' }, { - title: '水位', - dataIndex: 'rz', - width: '20%', + title: '实际水位(m)', + dataIndex: 'water', + key: 'water', + width: 100, + align: 'center' }, { - title: '操作', key: 'operation', width: "20%", fixed: 'right', align: 'center', - render: (_, record) => { - const editable = isEditing(record); - return editable ? ( - - save(record.key)} - style={{ - marginRight: 8, - }} - > - 完成 - - - - ) : ( -
- edit1(record)}> - 编辑 - -
- - ); - }, + title: '预测水位(m)', + dataIndex: 'predict', + key: 'predict', + width: 100, + align: 'center' + }, + { + title: '差值(m)', + dataIndex: 'cz', + key: 'cz', + width: 90, + align: 'center', + render: (v, r) => {(r.predict && r.water) ? Math.abs((r.predict - r.water)).toFixed(2) : ''} }, ] - const [form1] = Form.useForm() - const edit1 = (record) => { - form1.setFieldsValue({ - drp: '', - ...record, - }); - setEditingKey(record.key); - }; - const save = async (key) => { - try { - const row = await form1.validateFields(); - const newData = [...details]; - const index = newData.findIndex((item) => key === item.key); - if (index > -1) { - const item = newData[index]; - newData.splice(index, 1, { - ...item, - ...row, - }); - setDetails(newData); - setEditData(newData); - setEditingKey(''); - } else { - newData.push(row); - setDetails(newData); - setEditData(newData); - setEditingKey(''); - } - } catch (errInfo) { - console.log('Validate Failed:', errInfo); - } - }; - - useEffect(() => { - if (tableData.length > 0) { - setDetails(tableData) - } - }, [tableData]) - - - const mergedColumns = columns.map((col) => { - if (!col.editable) { - return col; - } - return { - ...col, - onCell: (record) => ({ - record, - dataIndex: col.dataIndex, - title: col.title, - editing: isEditing(record), - }), - }; - }); - - const handleAddRow = (count) => { - const newArr = Array(count).fill(0).map((item, i) => ({ - key: (i + 1).toString(), - tm: `${i + 1}小时`, - drp: '', - rz: '', - })) - form1.setFieldsValue(newArr[0]) - setDetails([...newArr]); - setEditData([...newArr]); - setEditingKey(newArr.map(item => item.key)); - }; - - useEffect(() => { - if (count) { - handleAddRow(count) - } - }, [count]) - - return ( - <> -
- - - - ) -} - - - -export default function TestLine() { - const [form] = Form.useForm() - const [searchVal, setSearchVal] = useState(false) - const [editData, setEditData] = useState([]) - const [type, setType] = useState({}) - const [tmCount, setTmCount] = useState('') - const [tableForm, setTableForm] = useState({}) - const [tableData, setTableData] = useState([]) - const [historyData, setHistoryData] = useState(responseData) - const [predictData, setPredictData] = useState([]) - // const options = useMemo(() => { - // return drpOption(tableForm.time || '1h', tableForm.tabArr || []) - // }, [tableForm]) - - const options = useMemo(() => { - return drpOption(predictData,historyData) - }, [predictData,historyData]) - - // useEffect(() => { - // if (searchVal) { - // getPrejectRain(searchVal.code) - // } - // }, [searchVal]) - - useEffect(() => { - let count; - if (type?.time) { - count = type.time == '1h' ? 1 : - type.time == '3h' ? 3 : - type.time == '6h' ? 6 : - type.time == '12h' ? 12 : - type.time == '24h' ? 24 : ''; - setTmCount(count) - } else { - count = 1 - setTmCount('') - } - }, [type]) - - - - const rowObj = { - "1小时": 420, - "2小时": 450, - "3小时": 480, - "4小时": 510, - "5小时": 540, - "6小时": 480, - "7小时": 420, - "8小时": 450, - "9小时": 480, - "10小时": 510, - "11小时": 540, - "12小时": 480, - "13小时": 420, - "14小时": 450, - "15小时": 480, - "16小时": 510, - "17小时": 540, - "18小时": 480, - "19小时": 420, - "20小时": 450, - "21小时": 480, - "22小时": 510, - "23小时": 540, - "24小时": 480, - - } - const save = async () => { - // const all = editData.some(item => !item.drp) - // if (all) { - // message.error("所有雨量不能为空") - // return - // } - try { - const newTabl = editData.map(item => ({ - ...item, - rz: rowObj[item.tm], - })) - setTableForm({ tabArr: newTabl, time: type.time }) - setTableData(newTabl) - - } catch (errInfo) { - console.log('Validate Failed:', errInfo); - } - }; - // 测试 - const getHistoryData = async (params) => { + setLoading(true) + params.stcd = obj[params.code]; try { - const allBatches = getAllHydroBatches(responseData); - const res =await processPredictions(allBatches, params.code) - if (res.length > 0) { - setPredictData(res) + const result = await httppost2(apiurl.test.find, params); + if (result.code == 200) { + const responseData = result.data.map(item => ({ ...item, tm: moment(item.tm).format('YYYY-MM-DD HH:00:00') })) + if (!responseData.length) { + setHistoryData(responseData) + return + } + setHistoryData(responseData) + const allBatches = getAllHydroBatches(responseData); + const res = await processPredictions(allBatches, params.code) + if (res.length > 0) { + setLoading(false) + setPredictData(res.map(item => ({...item,predict:item.predict.toFixed(2)}))) + const tableData = res.map(item => { + const obj = responseData.find(it => it.tm == item.tm) + return { + ...item, + predict: item.predict ? item.predict.toFixed(2) : '', + water: obj.waters, + rain:obj.rains + } + }) + setTableList(tableData) + } } - } catch (error) { - + console.log(error); } - - // try { - // const res = await httppost2('/api/hydrology/history'); - // if (res.code == 200) { - // const allBatches = getAllHydroBatches(res.data); - // if (allBatches.length) { - // processPredictions(allBatches,params.code) - // } - // } else { - // const allBatches = getAllHydroBatches(responseData); - // } - // } catch (error) { - // console.log(error); - // } } /** * 处理预测结果 @@ -323,6 +129,40 @@ export default function TestLine() { return results; }; + const findMinMaxRain = (arr) => { + + if (arr.length === 0) { + return { min: null, max: null }; // 如果数组为空,返回 null + } + + let min = arr[0]; // 初始化最小值为第一个元素 + let max = arr[0]; // 初始化最大值为第一个元素 + + for (let i = 1; i < arr.length; i++) { + if (arr[i].diff < min.diff) { + min = arr[i]; // 更新最小值 + } + if (arr[i].diff > max.diff) { + max = arr[i]; // 更新最大值 + } + } + + return { min, max }; + } + const summaryVal = useMemo(() => { + if (tableList.length > 0) { + const sum = tableList.reduce((total, cur) => total + Math.abs((cur.predict - cur.water)), 0); + const newArr = JSON.parse(JSON.stringify(tableList)); + const resultMaxOrMin = findMinMaxRain(newArr.map(item=> ({...item,diff:Math.abs((item.predict - item.water)).toFixed(2)}))) + return { + avergVal: (sum / tableList.length).toFixed(2), + maxVal: resultMaxOrMin?.max, + minVal: resultMaxOrMin?.min, + }; + } else { + return {} + } + },[tableList]) useEffect(() => { if (searchVal) { getHistoryData(searchVal) @@ -333,27 +173,100 @@ export default function TestLine() { return ( <>
-
+
-
+ { + historyData.length ? !loading ? +
-
-
- +
+
+ +
+
+
{ + return ( + <> + + 差值最大值时间点 + {summaryVal?.maxVal?.tm} + 差值最大值 + {summaryVal?.maxVal?.diff} + + {/* + 差值最小值时间点 + {summaryVal?.minVal?.tm} + 差值最小值 + {summaryVal?.minVal?.diff} + */} + + 差值平均值 + {summaryVal?.avergVal} + + + + ) + }} + /> + + + :
: +
} + + + {/* {!loading? +
+ +
+
+ +
+
+
{ + return ( + <> + + 差值最大值时间点 + {summaryVal?.maxVal?.tm} + 差值最大值 + {summaryVal?.maxVal?.diff} + + + 差值最小值时间点 + {summaryVal?.minVal?.tm} + 差值最小值 + {summaryVal?.minVal?.diff} + + + 差值平均值 + {summaryVal?.avergVal} + + + + ) + }} + /> + - {/*
- - -
*/} - - + :
+ } */} + diff --git a/src/views/TestLine/index.less b/src/views/TestLine/index.less index 843cec0..bc85522 100644 --- a/src/views/TestLine/index.less +++ b/src/views/TestLine/index.less @@ -1,3 +1,7 @@ .line-box{ background-color: #fff; -} \ No newline at end of file +} +.ant-table-summary { + background-color: #f2f9fd !important; + + } \ No newline at end of file diff --git a/src/views/TestLine/toolbar.js b/src/views/TestLine/toolbar.js index ef434a7..9d840df 100644 --- a/src/views/TestLine/toolbar.js +++ b/src/views/TestLine/toolbar.js @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import { Form, Input, Button, DatePicker, InputNumber } from 'antd'; +import { Form, Input, Button, DatePicker, InputNumber, message } from 'antd'; import NormalSelect from '../../components/Form/NormalSelect'; import moment from 'moment'; @@ -7,24 +7,24 @@ const { RangePicker } = DatePicker; const ToolBar = ({ setSearchVal, setType, save, form1 }) => { const types = [ + // { + // label: "黄家湾水库", + // value: "hjw" + // }, { - label: "hjw", - value: "hjw" - }, - { - label: "cq", + label: "车桥水库", value: "cq" }, { - label: "sxs", + label: "三星寺水库", value: "sxs" }, { - label: "szl", + label: "石子岭水库", value: "szl" }, { - label: "wpc", + label: "乌盆冲", value: "wpc" }, ] @@ -58,65 +58,139 @@ const ToolBar = ({ setSearchVal, setType, save, form1 }) => { let dateTimeRangeSo; if (values.tm) { dateTimeRangeSo = { - start: moment(values.tm[0]).format('YYYY-MM-DD HH:mm:ss'), - end: moment(values.tm[1]).format('YYYY-MM-DD HH:mm:ss') + start: moment(values.tm[0]).format('YYYY-MM-DD HH:00:00'), + end: moment(values.tm[1]).format('YYYY-MM-DD HH:00:00') } + } else { + message.error('请选择时间范围') } delete values.tm - setSearchVal({...values, start: dateTimeRangeSo.start,end: dateTimeRangeSo.end}); + setSearchVal({...values, stm: dateTimeRangeSo.start,etm: dateTimeRangeSo.end}); } + + const isLastDayOfFebruary = (date) => { + return date.month() === 1 && date.date() === moment(date).endOf('month').date(); + }; + + const disabledDate = (current) => { + if (!current) return false; + const start = moment('2024-01-01'); + const end = moment('2025-02-28'); + return current.isBefore(start, 'day') || current.isAfter(end, 'day'); + } + + // // 禁用不符合条件的日期 + // const disabledDate = (current) => { + // const dateRange = form.getFieldValue('tm'); // 获取当前日期范围 + // const startDate = dateRange?.[0]; // 获取开始日期 + + // // 限制年份为 2024 年 + // if (current.year() !== 2024) { + // return true; // 禁用非 2024 年的日期 + // } + + // // 如果没有选择开始日期,不禁用任何日期 + // if (!startDate) { + // return false; + // } + + // // 如果当前日期与开始日期的差值超过 30 天,则禁用 + // const diffInDays = Math.abs(current.diff(startDate, 'days')); + // return diffInDays > 30; + // }; + + // 当用户选择日期时触发 + const handleCalendarChange = (dates) => { + if(!dates) return; + const [start, end] = dates; + if (start && end) { + const diffInDays = Math.abs(end.diff(start, 'days')); + if (diffInDays > 30) { + // 如果选择的日期范围超过 30 天,重置结束日期 + form.setFieldsValue({ + tm: [start, null], // 保留开始日期,清空结束日期 + }); + } + } + }; const onValuesChange = (val, o) => { if ('time' in val) { setSearchVal({ time: val.time }) - setType({ time: val.time }) form1.resetFields() } if ('code' in val) { - setSearchVal(o) + let dateTimeRangeSo; + if (o.tm) { + dateTimeRangeSo = { + start: moment(o.tm[0]).format('YYYY-MM-DD HH:00:00'), + end: moment(o.tm[1]).format('YYYY-MM-DD HH:00:00') + } + } + delete o.tm + setSearchVal({...o, stm: dateTimeRangeSo.start,etm: dateTimeRangeSo.end}); + // setType({ time: "1h" }) // form.setFieldValue('time','1h') // form1.resetFields() } } useEffect(() => { - const start = moment().subtract(7, 'days').format('YYYY-MM-DD 00:00:00') - const end = moment().format('YYYY-MM-DD 23:59:59') + const stm = moment('2024-01-01').format('YYYY-MM-DD 00:00:00') + const etm = moment('2024-01-10').format('YYYY-MM-DD 00:00:00') const params = { - code: "hjw", + code: "cq", time: '1h', - start, - end + stm, + etm } - form.setFieldValue('name', params.code); - form.setFieldValue('tm', [moment(start), moment(end)]); + form.setFieldValue('code', params.code); + form.setFieldValue('tm', [moment('2024-01-01'), moment('2024-01-10')]); setSearchVal(params) - setType({ time: "1h" }) + }, []) return ( <>
-
+ {/* */} - + { + const [start, end] = value || []; + if (!start || !end) { + return Promise.reject(new Error('请选择完整的日期范围')); + } + const diffInDays = Math.abs(end.diff(start, 'days')); + if (diffInDays > 30) { + return Promise.reject(new Error('日期范围不能超过一个月')); + } + return Promise.resolve(); + }, + }, + ]} + > - {/* - - */} + + +
diff --git a/src/views/TestLine/watersTools.js b/src/views/TestLine/watersTools.js index ad87c41..f5f5290 100644 --- a/src/views/TestLine/watersTools.js +++ b/src/views/TestLine/watersTools.js @@ -24,7 +24,6 @@ export const getAllHydroBatches = (data) => { // 每次向后移动1个位置 startIndex += 1; } - return batches; };