Compare commits
9 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
d1c9bd32d5 | |
|
|
a6fd12bbf0 | |
|
|
0ac52e4e9e | |
|
|
9b5187625b | |
|
|
475e670b7c | |
|
|
2d60b17fbe | |
|
|
c6fd00bb26 | |
|
|
79d8a0d0a1 | |
|
|
01204ca96d |
|
|
@ -1 +1 @@
|
|||
PUBLIC_URL=/ykz
|
||||
PUBLIC_URL=/test
|
||||
|
|
@ -1,2 +1,2 @@
|
|||
GENERATE_SOURCEMAP=false
|
||||
PUBLIC_URL=/ykz
|
||||
PUBLIC_URL=/test
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
<script type="text/javascript" src="%PUBLIC_URL%/popmotion.xl.min.js"></script>
|
||||
<script type="text/javascript" src="%PUBLIC_URL%/imouplayer.js"></script>
|
||||
<script src="%PUBLIC_URL%/h5Player/h5player.min.js"></script>
|
||||
<title>盐卡引水闸信息化系统</title>
|
||||
<title>测试</title>
|
||||
|
||||
<style>
|
||||
.lf{
|
||||
|
|
|
|||
|
|
@ -187,8 +187,12 @@ export async function loadMenu(): Promise<MenuItem[]> {
|
|||
const tree = buildTree(data,0)
|
||||
const tree2 = tree?.filter((item:any) =>(item.menuId != "1" && item.menuId != "2" && item.menuId != "3"))
|
||||
handelTreeData(tree2,id)
|
||||
return tree2
|
||||
// return tree2
|
||||
|
||||
|
||||
return [
|
||||
{ id: id(), title: '测试', path: '/testLine', icon: 'yzt' },
|
||||
]
|
||||
|
||||
// const id = idgen()
|
||||
// return [
|
||||
|
|
|
|||
|
|
@ -3,7 +3,13 @@
|
|||
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',
|
||||
find1: service_test + '/stPRHisData/getHisDataV2'
|
||||
},
|
||||
setMenu: service_fxdd + '/visitMenuLog/insert',
|
||||
setPassword: service_fxdd + '/user/updateSecretKey',
|
||||
login: {
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@ const { createProxyMiddleware } = require('http-proxy-middleware');
|
|||
module.exports = function (app) {
|
||||
//咸丰调度系统
|
||||
app.use(
|
||||
'/gunshiApp',
|
||||
'/api',
|
||||
createProxyMiddleware({
|
||||
target: 'http://local.gunshiiot.com:18083/',//测试
|
||||
target: 'http://202.103.169.18:10100/',//测试
|
||||
// target: 'http://192.168.66.7:24106/',//正式
|
||||
// target: 'http://36.139.207.50:18083/',//移动云
|
||||
// target: 'http://192.168.66.49:24105/',//移动云
|
||||
|
|
@ -24,4 +24,14 @@ module.exports = function (app) {
|
|||
},
|
||||
})
|
||||
);
|
||||
|
||||
//卫星云图,雷达回波需要
|
||||
app.use(
|
||||
'/gunshiApp/dcpj',
|
||||
createProxyMiddleware({
|
||||
target: 'http://local.gunshiiot.com:18083',
|
||||
// target: 'http://192.168.66.30:24107',
|
||||
changeOrigin: true,
|
||||
})
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ import Dept from './SystemMangant/dept'
|
|||
import Role from './SystemMangant/role'
|
||||
import MenuM from './SystemMangant/menuM'
|
||||
import TestLine from './TestLine'
|
||||
import TestLine2 from './TestLine2'
|
||||
// const HomePage = lazy(() => import('./Home'))
|
||||
|
||||
|
||||
|
||||
const AppRouters: React.FC = () => {
|
||||
const dispatch = useDispatch<Dispatch>()
|
||||
|
||||
|
|
@ -37,7 +40,9 @@ const AppRouters: React.FC = () => {
|
|||
}, [dispatch])
|
||||
|
||||
let element = useRoutes([
|
||||
{ path: '/', element: <LoginPage /> },
|
||||
// { path: '/', element: <LoginPage /> },
|
||||
{ path: '/', element: <TestLine /> },
|
||||
{ path: '/test2', element: <TestLine2 /> },
|
||||
{ path: '/home', element: <HomePage /> },
|
||||
{
|
||||
path: '/mgr',
|
||||
|
|
@ -71,6 +76,7 @@ const AppRouters: React.FC = () => {
|
|||
|
||||
// 测试曲线
|
||||
{ path: 'testLine/testLine', element: <TestLine /> },
|
||||
{ path: 'testLine/testLine2', element: <TestLine2 /> },
|
||||
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,21 +1,176 @@
|
|||
import moment from "moment";
|
||||
export default function data(type) {
|
||||
const now = moment(); // 获取当前时间
|
||||
const startOfDay = now.clone().startOf('day'); // 获取今天的凌晨
|
||||
import { Button, Form, Input, InputNumber, Popconfirm, Table } from 'antd';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
const EditableContext = React.createContext(null);
|
||||
const EditableRow = ({ index, ...props }) => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<Form form={form} component={false}>
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
const EditableCell = ({
|
||||
title,
|
||||
editable,
|
||||
children,
|
||||
dataIndex,
|
||||
record,
|
||||
handleSave,
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(true);
|
||||
const inputRef = useRef(null);
|
||||
const form = useContext(EditableContext);
|
||||
// useEffect(() => {
|
||||
// if (editing) {
|
||||
// inputRef.current?.focus();
|
||||
// }
|
||||
// }, [editing]);
|
||||
const toggleEdit = (title) => {
|
||||
if (title == '雨量') {
|
||||
// setEditing(!editing);
|
||||
if (record[dataIndex]) {
|
||||
form.setFieldsValue({
|
||||
[dataIndex]: record[dataIndex],
|
||||
});
|
||||
|
||||
// 初始化数组,第一个元素是今天的凌晨
|
||||
let timeArray = [startOfDay];
|
||||
}
|
||||
};
|
||||
|
||||
// 生成接下来的时间点并添加到数组中,间隔为两个小时,且不超过当前时间
|
||||
let nextTime = startOfDay.clone().add(1, 'hours');
|
||||
while (nextTime <= now) {
|
||||
timeArray.push(nextTime.format('MM-DD HH:mm'));
|
||||
nextTime = nextTime.clone().add(1, 'hours');
|
||||
}
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
toggleEdit(title);
|
||||
handleSave({
|
||||
...record,
|
||||
...values,
|
||||
});
|
||||
} catch (errInfo) {
|
||||
console.log('Save failed:', errInfo);
|
||||
}
|
||||
};
|
||||
let childNode = children;
|
||||
if (editable) {
|
||||
childNode = editing ? (
|
||||
<Form.Item
|
||||
style={{
|
||||
margin: 0,
|
||||
}}
|
||||
name={dataIndex}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: `${title}必填`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber min={0} ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
className="editable-cell-value-wrap"
|
||||
style={{
|
||||
paddingRight: 24,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <td {...restProps} onClick={() => toggleEdit(title)}>{childNode}</td>;
|
||||
};
|
||||
const App = ({ count, tableData, setEditData }) => {
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
const defaultColumns = [
|
||||
{
|
||||
title: '预见期',
|
||||
dataIndex: 'tm',
|
||||
width: '30%',
|
||||
},
|
||||
{
|
||||
title: '雨量',
|
||||
dataIndex: 'drp',
|
||||
width: '30%',
|
||||
editable: true,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '水位',
|
||||
dataIndex: 'rz',
|
||||
width: '20%',
|
||||
},
|
||||
];
|
||||
const handleAdd = () => {
|
||||
const newArr = Array(count).fill(0).map((item, i) => ({
|
||||
key: (i + 1).toString(),
|
||||
tm: `${i + 1}小时`,
|
||||
drp: '',
|
||||
rz: '',
|
||||
}))
|
||||
|
||||
console.log(timeArray);
|
||||
let result;
|
||||
|
||||
setDataSource([...newArr]);
|
||||
setEditData([...newArr])
|
||||
};
|
||||
const handleSave = (row) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.key === item.key);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
...row,
|
||||
});
|
||||
console.log('newData', newData);
|
||||
setDataSource(newData);
|
||||
setEditData(newData)
|
||||
};
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
const columns = defaultColumns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
return result
|
||||
}
|
||||
useEffect(() => {
|
||||
if (count) {
|
||||
handleAdd(count)
|
||||
}
|
||||
}, [count])
|
||||
useEffect(() => {
|
||||
if (tableData.length > 0) {
|
||||
setDataSource(tableData)
|
||||
setEditData(tableData)
|
||||
}
|
||||
}, [tableData])
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
components={components}
|
||||
rowClassName={() => 'editable-row'}
|
||||
bordered
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
scroll={{ x: 200, y: 'calc( 100vh - 400px )' }}
|
||||
pagination={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default App;
|
||||
|
|
@ -1,226 +1,75 @@
|
|||
import * as echarts from 'echarts';
|
||||
import moment from 'moment';
|
||||
import moment, { min } from 'moment';
|
||||
|
||||
export default function drpOption(time = '',tabArr) {
|
||||
|
||||
const h1DrpData = tabArr.find(item => item.tm == '1小时');
|
||||
|
||||
// 水量
|
||||
let water = [
|
||||
{ time: "12-24 00:00", value: 480 },
|
||||
{ time: "12-24 01:00", value: 500 },
|
||||
{ time: "12-24 02:00", value: 450 },
|
||||
{ time: "12-24 03:00", value: 520 },
|
||||
{ time: "12-24 04:00", value: 490 },
|
||||
{ time: "12-24 05:00", value: 550 },
|
||||
{ time: "12-24 06:00", value: 580 },
|
||||
{ time: "12-24 07:00", value: 560 },
|
||||
{ time: "12-24 08:00", value: 530 },
|
||||
{ time: "12-24 09:00", value: 590 },
|
||||
{ time: "12-24 10:00", value: 540 },
|
||||
{ time: "12-24 11:00", value: 600 },
|
||||
{ time: "12-24 12:00", value: 620 },
|
||||
{ time: "12-24 13:00", value: 650 },
|
||||
{ time: "12-24 14:00", value: 680 },
|
||||
{ time: "12-24 15:00", value: 630 },
|
||||
];
|
||||
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),LimitWater, ...predict.map(item => item.predict)))
|
||||
const maxRz = Math.ceil(Math.max(...history.map(item => item.waters), LimitWater,...predict.map(item => item.predict)))
|
||||
// 雨量
|
||||
let rain = [
|
||||
{ time: "12-24 00:00", value: 3.8 },
|
||||
{ time: "12-24 01:00", value: 4 },
|
||||
{ time: "12-24 02:00", value: 3.5 },
|
||||
{ time: "12-24 03:00", value: 4.2 },
|
||||
{ time: "12-24 04:00", value: 3.9 },
|
||||
{ time: "12-24 05:00", value: 4.5 },
|
||||
{ time: "12-24 06:00", value: 4.8 },
|
||||
{ time: "12-24 07:00", value: 4.6 },
|
||||
{ time: "12-24 08:00", value: 4.3 },
|
||||
{ time: "12-24 09:00", value: 4.9 },
|
||||
{ time: "12-24 10:00", value: 4.4 },
|
||||
{ time: "12-24 11:00", value: 5.0 },
|
||||
{ time: "12-24 12:00", value: 5.2 },
|
||||
{ time: "12-24 13:00", value: 5.5 },
|
||||
{ time: "12-24 14:00", value: 5.8 },
|
||||
{ time: "12-24 15:00", value: 5.3 },
|
||||
];
|
||||
const mindrp = Math.floor(Math.min(...history.map(item => item.rains)))
|
||||
const maxdrp = Math.ceil(Math.max(...history.map(item => item.rains)))
|
||||
|
||||
const data = JSON.parse(JSON.stringify(water));
|
||||
const ydata = JSON.parse(JSON.stringify(rain));
|
||||
if (time == "1h") {
|
||||
data.push({ time: "12-24 16:00", value: 420, predict: true })
|
||||
ydata.push({ time: "12-24 16:00", value: h1DrpData?.drp, predict: true })
|
||||
} else if (time == "3h") {
|
||||
const wData = [
|
||||
{ time: "12-24 16:00", value: 420, predict: true },
|
||||
{ time: "12-24 17:00", value: 450, predict: true },
|
||||
{ time: "12-24 18:00", value: 480, predict: true },
|
||||
]
|
||||
const rData = [
|
||||
{ time: "12-24 16:00", value: tabArr.find( item =>item.tm == '1小时')?.drp, predict: true },
|
||||
{ time: "12-24 17:00", value: tabArr.find(item =>item.tm == '2小时')?.drp, predict: true },
|
||||
{ time: "12-24 18:00", value: tabArr.find(item =>item.tm == '3小时')?.drp, predict: true },
|
||||
]
|
||||
data.push(...wData)
|
||||
ydata.push(...rData)
|
||||
} else if (time == "6h") {
|
||||
const h6WData = [
|
||||
{ time: "12-24 16:00", value: 420, predict: true },
|
||||
{ time: "12-24 17:00", value: 450, predict: true },
|
||||
{ time: "12-24 18:00", value: 480, predict: true },
|
||||
{ time: "12-24 19:00", value: 510, predict: true },
|
||||
{ time: "12-24 20:00", value: 540, predict: true },
|
||||
{ time: "12-24 21:00", value: 480, predict: true },
|
||||
]
|
||||
const h6RData = [
|
||||
{ time: "12-24 16:00", value: tabArr.find( item =>item.tm == '1小时')?.drp, predict: true },
|
||||
{ time: "12-24 17:00", value: tabArr.find( item =>item.tm == '2小时')?.dr, predict: true },
|
||||
{ time: "12-24 18:00", value: tabArr.find( item =>item.tm == '3小时')?.dr, predict: true },
|
||||
{ time: "12-24 19:00", value: tabArr.find( item =>item.tm == '4小时')?.dr, predict: true },
|
||||
{ time: "12-24 20:00", value: tabArr.find( item =>item.tm == '5小时')?.dr, predict: true },
|
||||
{ time: "12-24 21:00", value: tabArr.find( item =>item.tm == '6小时')?.dr, predict: true },
|
||||
]
|
||||
|
||||
data.push(...h6WData)
|
||||
ydata.push(...h6RData)
|
||||
} else if(time == "12h") {
|
||||
const h12WData = [
|
||||
{ time: "12-24 16:00", value: 420, predict: true },
|
||||
{ time: "12-24 17:00", value: 450, predict: true },
|
||||
{ time: "12-24 18:00", value: 480, predict: true },
|
||||
{ time: "12-24 19:00", value: 510, predict: true },
|
||||
{ time: "12-24 20:00", value: 540, predict: true },
|
||||
{ time: "12-24 21:00", value: 480, predict: true },
|
||||
{ time: "12-24 22:00", value: 420, predict: true },
|
||||
{ time: "12-24 23:00", value: 450, predict: true },
|
||||
{ time: "12-24 24:00", value: 480, predict: true },
|
||||
{ time: "12-25 00:00", value: 510, predict: true },
|
||||
{ time: "12-25 01:00", value: 540, predict: true },
|
||||
{ time: "12-25 02:00", value: 480, predict: true },
|
||||
]
|
||||
const h12RData = [
|
||||
{ time: "12-24 16:00", value: tabArr.find( item =>item.tm == '1小时')?.drp, predict: true },
|
||||
{ time: "12-24 17:00", value: tabArr.find( item =>item.tm == '2小时')?.drp, predict: true },
|
||||
{ time: "12-24 18:00", value: tabArr.find( item =>item.tm == '3小时')?.drp, predict: true },
|
||||
{ time: "12-24 19:00", value: tabArr.find( item =>item.tm == '4小时')?.drp, predict: true },
|
||||
{ time: "12-24 20:00", value: tabArr.find( item =>item.tm == '5小时')?.drp, predict: true },
|
||||
{ time: "12-24 21:00", value: tabArr.find( item =>item.tm == '6小时')?.drp, predict: true },
|
||||
{ time: "12-24 22:00", value: tabArr.find( item =>item.tm == '7小时')?.drp, predict: true },
|
||||
{ time: "12-24 23:00", value: tabArr.find( item =>item.tm == '8小时')?.drp, predict: true },
|
||||
{ time: "12-24 24:00", value: tabArr.find( item =>item.tm == '9小时')?.drp, predict: true },
|
||||
{ time: "12-25 00:00", value: tabArr.find( item =>item.tm == '10小时')?.drp, predict: true },
|
||||
{ time: "12-25 01:00", value: tabArr.find( item =>item.tm == '11小时')?.drp, predict: true },
|
||||
{ time: "12-25 02:00", value: tabArr.find( item =>item.tm == '12小时')?.drp, predict: true },
|
||||
]
|
||||
|
||||
data.push(...h12WData)
|
||||
ydata.push(...h12RData)
|
||||
} else if (time == "24h") {
|
||||
const h24WData = [
|
||||
{ time: "12-24 16:00", value: 420, predict: true },
|
||||
{ time: "12-24 17:00", value: 450, predict: true },
|
||||
{ time: "12-24 18:00", value: 480, predict: true },
|
||||
{ time: "12-24 19:00", value: 510, predict: true },
|
||||
{ time: "12-24 20:00", value: 540, predict: true },
|
||||
{ time: "12-24 21:00", value: 480, predict: true },
|
||||
{ time: "12-24 22:00", value: 420, predict: true },
|
||||
{ time: "12-24 23:00", value: 450, predict: true },
|
||||
{ time: "12-24 24:00", value: 480, predict: true },
|
||||
{ time: "12-25 00:00", value: 510, predict: true },
|
||||
{ time: "12-25 01:00", value: 540, predict: true },
|
||||
{ time: "12-25 02:00", value: 480, predict: true },
|
||||
|
||||
{ time: "12-25 03:00", value: 420, predict: true },
|
||||
{ time: "12-25 04:00", value: 450, predict: true },
|
||||
{ time: "12-25 05:00", value: 480, predict: true },
|
||||
{ time: "12-25 06:00", value: 510, predict: true },
|
||||
{ time: "12-25 07:00", value: 540, predict: true },
|
||||
{ time: "12-25 08:00", value: 480, predict: true },
|
||||
{ time: "12-25 09:00", value: 420, predict: true },
|
||||
{ time: "12-25 10:00", value: 450, predict: true },
|
||||
{ time: "12-25 11:00", value: 480, predict: true },
|
||||
{ time: "12-25 12:00", value: 510, predict: true },
|
||||
{ time: "12-25 13:00", value: 540, predict: true },
|
||||
{ time: "12-25 14:00", value: 480, predict: true },
|
||||
]
|
||||
const h24RData = [
|
||||
{ time: "12-24 16:00", value: tabArr.find( item =>item.tm == '1小时')?.drp, predict: true },
|
||||
{ time: "12-24 17:00", value: tabArr.find( item =>item.tm == '2小时')?.drp, predict: true },
|
||||
{ time: "12-24 18:00", value: tabArr.find( item =>item.tm == '3小时')?.drp, predict: true },
|
||||
{ time: "12-24 19:00", value: tabArr.find( item =>item.tm == '4小时')?.drp, predict: true },
|
||||
{ time: "12-24 20:00", value: tabArr.find( item =>item.tm == '5小时')?.drp, predict: true },
|
||||
{ time: "12-24 21:00", value: tabArr.find( item =>item.tm == '6小时')?.drp, predict: true },
|
||||
{ time: "12-24 22:00", value: tabArr.find( item =>item.tm == '7小时')?.drp, predict: true },
|
||||
{ time: "12-24 23:00", value: tabArr.find( item =>item.tm == '8小时')?.drp, predict: true },
|
||||
{ time: "12-24 24:00", value: tabArr.find( item =>item.tm == '9小时')?.drp, predict: true },
|
||||
{ time: "12-25 00:00", value: tabArr.find( item =>item.tm == '10小时')?.drp, predict: true },
|
||||
{ time: "12-25 01:00", value: tabArr.find( item =>item.tm == '11小时')?.drp, predict: true },
|
||||
{ time: "12-25 02:00", value: tabArr.find( item =>item.tm == '12小时')?.drp, predict: true },
|
||||
|
||||
{ time: "12-25 03:00", value: tabArr.find( item =>item.tm == '13小时')?.drp, predict: true },
|
||||
{ time: "12-25 04:00", value: tabArr.find( item =>item.tm == '14小时')?.drp, predict: true },
|
||||
{ time: "12-25 05:00", value: tabArr.find( item =>item.tm == '15小时')?.drp, predict: true },
|
||||
{ time: "12-25 06:00", value: tabArr.find( item =>item.tm == '16小时')?.drp, predict: true },
|
||||
{ time: "12-25 07:00", value: tabArr.find( item =>item.tm == '17小时')?.drp, predict: true },
|
||||
{ time: "12-25 08:00", value: tabArr.find( item =>item.tm == '18小时')?.drp, predict: true },
|
||||
{ time: "12-25 09:00", value: tabArr.find( item =>item.tm == '19小时')?.drp, predict: true },
|
||||
{ time: "12-25 10:00", value: tabArr.find( item =>item.tm == '20小时')?.drp, predict: true },
|
||||
{ time: "12-25 11:00", value: tabArr.find( item =>item.tm == '21小时')?.drp, predict: true },
|
||||
{ time: "12-25 12:00", value: tabArr.find( item =>item.tm == '22小时')?.drp, predict: true },
|
||||
{ time: "12-25 13:00", value: tabArr.find( item =>item.tm == '23小时')?.drp, predict: true },
|
||||
{ time: "12-25 14:00", value: tabArr.find( item =>item.tm == '24小时')?.drp, predict: true },
|
||||
]
|
||||
data.push(...h24WData)
|
||||
ydata.push(...h24RData)
|
||||
}
|
||||
|
||||
|
||||
let data1 = []; //历史水量数据
|
||||
let data2 = []; //预测水量数据
|
||||
let data3 = []; //历史雨量数据
|
||||
let data4 = []; //预测雨量数据
|
||||
|
||||
|
||||
data.forEach((item) => {
|
||||
if (item.predict && time) {
|
||||
data2.push([item.time, item.value]);
|
||||
} else {
|
||||
data1.push([item.time, item.value]);
|
||||
}
|
||||
});
|
||||
|
||||
ydata.forEach((item) => {
|
||||
if (item.predict && time) {
|
||||
data4.push([item.time, item.value]);
|
||||
} else {
|
||||
data3.push([item.time, item.value]);
|
||||
}
|
||||
});
|
||||
const splitLineData1 = data1.at(-1);
|
||||
const splitLineData = data1.at(-1);
|
||||
const splitLineData2 = data3.at(-1);
|
||||
|
||||
// 如果是折线图,此处需要追加实际数据的最后一组数据,如果是柱状图,则不需要。
|
||||
data2.unshift(splitLineData1);
|
||||
data4.unshift(splitLineData2);
|
||||
// // 水位
|
||||
// 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 {
|
||||
grid: {
|
||||
left: 0,
|
||||
top: "22%",
|
||||
right: "0",
|
||||
bottom: 0,
|
||||
top: "20%",
|
||||
right: "3%",
|
||||
bottom: "10%",
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
legend: {
|
||||
right: "0",
|
||||
right: "center",
|
||||
top: "4%",
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
top: "15%",
|
||||
right: "0%",
|
||||
orient: 'vertical',
|
||||
feature: {
|
||||
dataZoom: {
|
||||
show: true,
|
||||
title: {
|
||||
zoom: '区域缩放',
|
||||
back: '区域缩放还原',
|
||||
}
|
||||
},
|
||||
magicType: {
|
||||
show: true,
|
||||
title: {
|
||||
line: '切换为折线图',
|
||||
bar: '切换为柱状图',
|
||||
},
|
||||
type: ['line', 'bar']
|
||||
},
|
||||
restore: {
|
||||
show: true,
|
||||
title: '还原'
|
||||
},
|
||||
saveAsImage: {
|
||||
show: true,
|
||||
name: '日到报率详情',
|
||||
title: '保存为图片'
|
||||
}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: data.map(item => item.time),
|
||||
// data: history.map(item => item.tm),
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
|
|
@ -229,6 +78,8 @@ export default function drpOption(time = '',tabArr) {
|
|||
{
|
||||
type: "value",
|
||||
name: '水位',
|
||||
min: minRz,
|
||||
max: maxRz,
|
||||
splitLine: {
|
||||
show: true,
|
||||
},
|
||||
|
|
@ -244,6 +95,8 @@ export default function drpOption(time = '',tabArr) {
|
|||
{
|
||||
type: "value",
|
||||
name: '雨量',
|
||||
min: mindrp,
|
||||
max: maxdrp,
|
||||
splitLine: {
|
||||
show: true,
|
||||
},
|
||||
|
|
@ -257,70 +110,60 @@ export default function drpOption(time = '',tabArr) {
|
|||
|
||||
},
|
||||
],
|
||||
dataZoom: [{
|
||||
type: 'inside',
|
||||
start: (600 / history.length) * 100,
|
||||
end: 100
|
||||
}, {
|
||||
start: 0,
|
||||
end: 10,
|
||||
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
|
||||
}
|
||||
}],
|
||||
series: [
|
||||
{
|
||||
name: "历史水量",
|
||||
type: "line",
|
||||
showSymbol: false,
|
||||
data: data1,
|
||||
smooth: true,
|
||||
},
|
||||
{
|
||||
name: "历史雨量",
|
||||
type: "line",
|
||||
name: "实测雨量",
|
||||
type: "bar",
|
||||
color: '#F59A23',
|
||||
yAxisIndex: 1,
|
||||
showSymbol: false,
|
||||
data: data3,
|
||||
data: history.map(item => [item.tm, item.rains]),
|
||||
smooth: true,
|
||||
},
|
||||
{
|
||||
name: "预测水量",
|
||||
name: "实测水位",
|
||||
type: "line",
|
||||
showSymbol: false,
|
||||
data: history.map(item => [item.tm, item.waters]),
|
||||
smooth: true,
|
||||
},
|
||||
|
||||
{
|
||||
name: "预测水位",
|
||||
type: "line",
|
||||
color: '#1fbcd2',
|
||||
yAxisIndex: 0,
|
||||
type: "line",
|
||||
showSymbol: true,
|
||||
data: data2,
|
||||
showSymbol: false,
|
||||
data: predict.map(item => [item.tm, item.predict]),
|
||||
smooth: true,
|
||||
itemStyle : { normal: {label : {show: true}}}
|
||||
},
|
||||
{
|
||||
name: "预测雨量",
|
||||
yAxisIndex: 1,
|
||||
name: LimitWater != 0 ? "汛限水位" :'',
|
||||
type: "line",
|
||||
showSymbol: true,
|
||||
data: data4,
|
||||
yAxisIndex: 0,
|
||||
color:"#85ea2d",
|
||||
showSymbol: false,
|
||||
data:LimitWater != 0 ? history.map(item => [item.tm, LimitWater]) : [],
|
||||
smooth: true,
|
||||
itemStyle : { normal: {label : {show: true}}}
|
||||
},
|
||||
{
|
||||
type: "line",
|
||||
data: [],
|
||||
markLine: {
|
||||
symbol: "none",
|
||||
lineStyle: {
|
||||
type: "solid",
|
||||
width: 2,
|
||||
},
|
||||
data: [
|
||||
// 下面绿色线
|
||||
[
|
||||
// 下面半截绿色的线
|
||||
{
|
||||
xAxis: splitLineData[0],
|
||||
yAxis: 0,
|
||||
lineStyle: {
|
||||
color: "rgba(46, 224, 85, 1)",
|
||||
},
|
||||
},
|
||||
{
|
||||
xAxis: splitLineData[0],
|
||||
yAxis: splitLineData[1],
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
|
||||
},
|
||||
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -1,281 +1,272 @@
|
|||
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'
|
||||
import drpOption from './drpOption.js'
|
||||
|
||||
|
||||
const TableE = ({count,setEditData,tableData}) => {
|
||||
const EditableCell = ({
|
||||
editing,
|
||||
dataIndex,
|
||||
title,
|
||||
inputType,
|
||||
record,
|
||||
index,
|
||||
children,
|
||||
...restProps
|
||||
}) => {
|
||||
const inputNode = <InputNumber min={0} style={{ textAlign: "center", flex: 1 }} />;
|
||||
return (
|
||||
<td {...restProps}>
|
||||
{editing ? (
|
||||
<Form.Item
|
||||
name={dataIndex}
|
||||
wrapperCol={[24]}
|
||||
style={{
|
||||
margin: 0,
|
||||
}}
|
||||
>
|
||||
{inputNode}
|
||||
</Form.Item>
|
||||
) : (
|
||||
children
|
||||
)}
|
||||
</td>
|
||||
);
|
||||
};
|
||||
const [editingKey, setEditingKey] = useState('');
|
||||
const [details, setDetails] = useState([])
|
||||
const isEditing = (record) => {
|
||||
return record.key === editingKey;
|
||||
import { httppost2 } from '../../utils/request';
|
||||
import TestApp from './createData.js'
|
||||
import { getAllHydroBatches, responseData } from './watersTools'
|
||||
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,
|
||||
align:'center'
|
||||
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 ? (
|
||||
<span>
|
||||
<Typography.Link
|
||||
onClick={() => save(record.key)}
|
||||
style={{
|
||||
marginRight: 8,
|
||||
}}
|
||||
>
|
||||
完成
|
||||
</Typography.Link>
|
||||
|
||||
</span>
|
||||
) : (
|
||||
<div style={{display:"flex",justifyContent:"center",columnGap:10}}>
|
||||
<Typography.Link disabled={editingKey !== ''} onClick={() => edit1(record)}>
|
||||
编辑
|
||||
</Typography.Link>
|
||||
</div>
|
||||
|
||||
);
|
||||
},
|
||||
title: '预测水位(m)',
|
||||
dataIndex: 'predict',
|
||||
key: 'predict',
|
||||
width: 100,
|
||||
align: 'center'
|
||||
},
|
||||
]
|
||||
const [form1] = Form.useForm()
|
||||
const edit1 = (record) => {
|
||||
form1.setFieldsValue({
|
||||
drp: '',
|
||||
...record,
|
||||
});
|
||||
setEditingKey(record.key);
|
||||
};
|
||||
const save = async (key) => {
|
||||
{
|
||||
title: '差值(m)',
|
||||
dataIndex: 'cz',
|
||||
key: 'cz',
|
||||
width: 90,
|
||||
align: 'center',
|
||||
render: (v, r) => <span>{(r.predict && r.water) ? Math.abs((r.predict - r.water)).toFixed(2) : ''}</span>
|
||||
},
|
||||
]
|
||||
const getHistoryData = async (params) => {
|
||||
setLoading(true)
|
||||
params.stcd = obj[params.code];
|
||||
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('');
|
||||
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 (errInfo) {
|
||||
console.log('Validate Failed:', errInfo);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (tableData.length > 0) {
|
||||
setDetails(tableData)
|
||||
}
|
||||
}, [tableData])
|
||||
|
||||
}
|
||||
/**
|
||||
* 处理预测结果
|
||||
* @param {Array} batches - 批次数据
|
||||
* @param {Array} predictions - 预测结果数组
|
||||
* @returns {Array} - 返回处理后的预测结果
|
||||
*/ const processPredictions = async (batches, name) => {
|
||||
const results = [];
|
||||
|
||||
const mergedColumns = columns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
for (const batch of batches) {
|
||||
const prediction = await httppost2('http://202.96.165.23:10100/api/v1/bot/water_infer', {
|
||||
rains: batch.rains,
|
||||
waters: batch.waters,
|
||||
name
|
||||
});
|
||||
results.push({
|
||||
predict: prediction?.data?.water_predicts[0], // 预测水位
|
||||
tm: batch.lastTm // 对应的时间点
|
||||
});
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
inputType: col.dataIndex === 'age' ? 'number' :
|
||||
col.dataIndex === 'sex' ? 'select' : "text",
|
||||
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[0].key);
|
||||
return results;
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (count) {
|
||||
handleAddRow(count)
|
||||
const findMinMaxRain = (arr) => {
|
||||
|
||||
if (arr.length === 0) {
|
||||
return { min: null, max: null }; // 如果数组为空,返回 null
|
||||
}
|
||||
}, [count])
|
||||
|
||||
return (
|
||||
<>
|
||||
<Form form={form1} component={false}>
|
||||
<Table
|
||||
rowKey="index"
|
||||
components={{
|
||||
body: {
|
||||
// row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
}}
|
||||
columns={mergedColumns}
|
||||
dataSource={details}
|
||||
scroll={{ x: 200,y: 'calc( 100vh - 400px )'}}
|
||||
pagination={false}
|
||||
/>
|
||||
</Form>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
export default function TestLine() {
|
||||
const [form] = Form.useForm()
|
||||
const [searchVal, setSearchVal] = useState({})
|
||||
const [editData, setEditData] = useState([])
|
||||
const [type, setType] = useState({})
|
||||
const [tmCount, setTmCount] = useState('')
|
||||
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)
|
||||
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 {
|
||||
count = 1
|
||||
setTmCount('')
|
||||
return {}
|
||||
}
|
||||
}, [type])
|
||||
const [tableForm, setTableForm] = useState({})
|
||||
const options = useMemo(() => {
|
||||
return drpOption(tableForm.time,tableForm.tabArr || [])
|
||||
}, [tableForm])
|
||||
},[tableList])
|
||||
useEffect(() => {
|
||||
if (searchVal) {
|
||||
getHistoryData(searchVal)
|
||||
}
|
||||
}, [searchVal])
|
||||
|
||||
const [tableData, setTableData] = useState([])
|
||||
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 () => {
|
||||
try {
|
||||
setTableForm({ tabArr: editData, time: type.time })
|
||||
const newTabl = editData.map(item => ({
|
||||
...item,
|
||||
rz: rowObj[item.tm],
|
||||
}))
|
||||
setTableData(newTabl)
|
||||
|
||||
} catch (errInfo) {
|
||||
console.log('Validate Failed:', errInfo);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='content-root clearFloat xybm' style={{ paddingBottom: "0" }}>
|
||||
<div className='lf CrudAdcdTreeTableBox' style={{ width: "100%", overflowY: "auto" }}>
|
||||
<div className='lf' style={{ width: "100%", overflowY: "auto" }}>
|
||||
<Card className='nonebox'>
|
||||
<ToolBar
|
||||
setSearchVal={setSearchVal}
|
||||
setType={setType}
|
||||
save={save}
|
||||
form1={form}
|
||||
/>
|
||||
</Card>
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0", height: 'calc( 100vh - 400px )' }}>
|
||||
|
||||
<div style={{ display: 'flex', columnGap: 20 }}>
|
||||
<div style={{ flex: 1,height: 'calc( 100vh - 400px )' }}>
|
||||
<ReactEcharts option={options} style={{ width: "100%", height: '100%' }} notMerge={true} />
|
||||
{
|
||||
historyData.length ? !loading ?
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0"}}>
|
||||
|
||||
<div style={{ display: 'flex', }}>
|
||||
<div style={{ flex: 1, height: 'calc( 100vh - 400px )', padding: 10 }}>
|
||||
<ReactEcharts option={options} style={{ width: "100%", height: '100%' }} notMerge={true} />
|
||||
</div>
|
||||
<div style={{ width: 600, marginRight: 30 }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableList}
|
||||
rowKey='tm'
|
||||
pagination={true}
|
||||
scroll={{ x: 600, y: 'calc(100vh - 300px)' }}
|
||||
summary={() => {
|
||||
return (
|
||||
<>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={12} align='center' colSpan={1} >差值最大值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} align='center' colSpan={2}>{summaryVal?.maxVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} align='center' colSpan={1}>差值最大值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={3} align='center' colSpan={1}>{summaryVal?.maxVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
{/* <Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center' colSpan={1} >差值最小值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={2}>{summaryVal?.minVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={6} align='center' colSpan={1}>差值最小值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={7} align='center' colSpan={1}>{summaryVal?.minVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row> */}
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center' colSpan={1} >差值平均值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={4}>{summaryVal?.avergVal}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</>
|
||||
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> : <div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}><Spin size="large" /></div> :
|
||||
<div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <img alt='' src={`${process.env.PUBLIC_URL}/assets/noData.png`} /></div>}
|
||||
|
||||
|
||||
{/* {!loading?
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0", height: 'calc( 100vh - 400px )' }}>
|
||||
|
||||
<div style={{ display: 'flex', }}>
|
||||
<div style={{ flex: 1, height: 'calc( 100vh - 400px )', padding: 10 }}>
|
||||
<ReactEcharts option={options} style={{ width: "100%", height: '100%' }} notMerge={true} />
|
||||
</div>
|
||||
<div style={{ width: 600, marginRight: 30 }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableList}
|
||||
rowKey='tm'
|
||||
pagination={true}
|
||||
scroll={{x:600,y:'calc(100vh - 300px)'}}
|
||||
summary={() => {
|
||||
return (
|
||||
<>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={12} align='center'colSpan={1} >差值最大值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} align='center' colSpan={2}>{summaryVal?.maxVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} align='center' colSpan={1}>差值最大值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={3} align='center' colSpan={1}>{summaryVal?.maxVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center'colSpan={1} >差值最小值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={2}>{summaryVal?.minVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={6} align='center' colSpan={1}>差值最小值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={7} align='center' colSpan={1}>{summaryVal?.minVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center'colSpan={1} >差值平均值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={4}>{summaryVal?.avergVal}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</>
|
||||
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ width: 380 }}>
|
||||
<TableE count={tmCount} setEditData={setEditData} tableData={tableData} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div> : <div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}><Spin size="large" /></div>
|
||||
} */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
.line-box{
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
.ant-table-summary {
|
||||
background-color: #f2f9fd !important;
|
||||
|
||||
}
|
||||
|
|
@ -1,15 +1,34 @@
|
|||
import React, { useEffect,useState } from 'react';
|
||||
import { Form, Input, Button, DatePicker, InputNumber } from 'antd';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Form, Input, Button, DatePicker, InputNumber, message } from 'antd';
|
||||
import NormalSelect from '../../components/Form/NormalSelect';
|
||||
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
const { RangePicker } = DatePicker;
|
||||
const ToolBar = ({ setSearchVal, setType, save, form1 }) => {
|
||||
|
||||
const types = Array(5).fill(0).map((item,i) => ({
|
||||
label: `${i + 1}#水库`,
|
||||
value: i + 1
|
||||
}))
|
||||
const navigate = useNavigate();
|
||||
|
||||
const types = [
|
||||
// {
|
||||
// label: "黄家湾水库",
|
||||
// value: "hjw"
|
||||
// },
|
||||
{
|
||||
label: "车桥水库",
|
||||
value: "cq"
|
||||
},
|
||||
{
|
||||
label: "三星寺水库",
|
||||
value: "sxs"
|
||||
},
|
||||
{
|
||||
label: "石子岭水库",
|
||||
value: "szl"
|
||||
},
|
||||
{
|
||||
label: "乌盆冲",
|
||||
value: "wpc"
|
||||
},
|
||||
]
|
||||
|
||||
const timeType = [
|
||||
{
|
||||
|
|
@ -33,53 +52,151 @@ const ToolBar = ({ setSearchVal, setType, save, form1 }) => {
|
|||
value: "24h"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const onFinish = (values) => {
|
||||
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, dateTimeRangeSo});
|
||||
save()
|
||||
setSearchVal({...values, stm: dateTimeRangeSo.start,etm: dateTimeRangeSo.end});
|
||||
}
|
||||
|
||||
const onValuesChange = (val) =>{
|
||||
|
||||
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})
|
||||
setSearchVal({ time: val.time })
|
||||
form1.resetFields()
|
||||
}
|
||||
if ('code' in val) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
const jump = () => {
|
||||
navigate('/test2');
|
||||
}
|
||||
useEffect(() => {
|
||||
const stm = moment('2024-07-10 00:00:00').format('YYYY-MM-DD 00:00:00')
|
||||
const etm = moment('2024-07-31 16:00:00').format('YYYY-MM-DD 00:00:00')
|
||||
const params = {
|
||||
code: 1,
|
||||
// time:'1h'
|
||||
code: "cq",
|
||||
stm,
|
||||
etm
|
||||
}
|
||||
form.setFieldsValue(params)
|
||||
form.setFieldValue('code', params.code);
|
||||
form.setFieldValue('tm', [moment('2024-07-10 00:00:00'), moment('2024-07-31 16:00:00')]);
|
||||
setSearchVal(params)
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{display:'flex',justifyContent:'space-between'}}>
|
||||
<Form form={form} className='toolbarBox' layout="inline" onFinish={onFinish} onValuesChange={onValuesChange}>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Form form={form} className='toolbarBox' layout="inline" onFinish={onFinish} >
|
||||
<Form.Item label="水库" name="code">
|
||||
<NormalSelect allowClear style={{ width: '150px' }} options={types} />
|
||||
<NormalSelect allowClear style={{ width: '150px' }} options={types} />
|
||||
</Form.Item>
|
||||
<Form.Item label="预见期" name="time">
|
||||
{/* <Form.Item label="预见期" name="time">
|
||||
<NormalSelect allowClear style={{ width: '150px' }} options={timeType} />
|
||||
</Form.Item> */}
|
||||
<Form.Item label="时间" name="tm"
|
||||
rules={[
|
||||
{
|
||||
validator: (_, value) => {
|
||||
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();
|
||||
},
|
||||
},
|
||||
]}
|
||||
>
|
||||
<RangePicker
|
||||
showTime
|
||||
disabledDate={disabledDate}
|
||||
onCalendarChange={handleCalendarChange}
|
||||
style={{ width: "330px" }}
|
||||
format="YYYY-MM-DD HH:00:00"
|
||||
// allowClear={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">生成</Button>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">查询</Button>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" onClick={jump}>时刻预测</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
import moment from "moment";
|
||||
/**
|
||||
* 使用滑动窗口获取水文数据批次
|
||||
* @param {Array} data - 后端返回的数据数组
|
||||
* @returns {Array} - 返回数组,每个元素包含600个点的数据
|
||||
*/
|
||||
export const getAllHydroBatches = (data) => {
|
||||
if (!Array.isArray(data) || data.length < 600) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const batches = [];
|
||||
let startIndex = 0;
|
||||
|
||||
// 当剩余数据量大于等于600时继续处理
|
||||
while (startIndex + 600 <= data.length) {
|
||||
const slicedData = data.slice(startIndex, startIndex + 600);
|
||||
batches.push({
|
||||
rains: slicedData.map(item => item.rains),
|
||||
waters: slicedData.map(item => item.waters),
|
||||
lastTm: slicedData[599].tm // 记录第600个点的时间
|
||||
});
|
||||
|
||||
// 每次向后移动1个位置
|
||||
startIndex += 1;
|
||||
}
|
||||
return batches;
|
||||
};
|
||||
|
||||
export const responseData = new Array(800).fill(0).map((item,index) => ({
|
||||
rains: (Math.random() * 1).toFixed(2),
|
||||
waters: (Math.random() * 100).toFixed(2),
|
||||
tm:moment().clone().add(index, 'hours').format("YYYY-MM-DD HH:00:00")
|
||||
}))
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
import React from 'react'
|
||||
|
||||
export default function RenderForm() {
|
||||
return (
|
||||
<div>RenderForm</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,176 @@
|
|||
import { Button, Form, Input, InputNumber, Popconfirm, Table } from 'antd';
|
||||
import React, { useContext, useEffect, useRef, useState } from 'react';
|
||||
const EditableContext = React.createContext(null);
|
||||
const EditableRow = ({ index, ...props }) => {
|
||||
const [form] = Form.useForm();
|
||||
return (
|
||||
<Form form={form} component={false}>
|
||||
<EditableContext.Provider value={form}>
|
||||
<tr {...props} />
|
||||
</EditableContext.Provider>
|
||||
</Form>
|
||||
);
|
||||
};
|
||||
const EditableCell = ({
|
||||
title,
|
||||
editable,
|
||||
children,
|
||||
dataIndex,
|
||||
record,
|
||||
handleSave,
|
||||
...restProps
|
||||
}) => {
|
||||
const [editing, setEditing] = useState(true);
|
||||
const inputRef = useRef(null);
|
||||
const form = useContext(EditableContext);
|
||||
// useEffect(() => {
|
||||
// if (editing) {
|
||||
// inputRef.current?.focus();
|
||||
// }
|
||||
// }, [editing]);
|
||||
const toggleEdit = (title) => {
|
||||
if (title == '雨量') {
|
||||
// setEditing(!editing);
|
||||
if (record[dataIndex]) {
|
||||
form.setFieldsValue({
|
||||
[dataIndex]: record[dataIndex],
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
const save = async () => {
|
||||
try {
|
||||
const values = await form.validateFields();
|
||||
toggleEdit(title);
|
||||
handleSave({
|
||||
...record,
|
||||
...values,
|
||||
});
|
||||
} catch (errInfo) {
|
||||
console.log('Save failed:', errInfo);
|
||||
}
|
||||
};
|
||||
let childNode = children;
|
||||
if (editable) {
|
||||
childNode = editing ? (
|
||||
<Form.Item
|
||||
style={{
|
||||
margin: 0,
|
||||
}}
|
||||
name={dataIndex}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
message: `${title}必填`,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber min={0} ref={inputRef} onPressEnter={save} onBlur={save} />
|
||||
</Form.Item>
|
||||
) : (
|
||||
<div
|
||||
className="editable-cell-value-wrap"
|
||||
style={{
|
||||
paddingRight: 24,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <td {...restProps} onClick={() => toggleEdit(title)}>{childNode}</td>;
|
||||
};
|
||||
const App = ({ count, tableData, setEditData }) => {
|
||||
const [dataSource, setDataSource] = useState([]);
|
||||
const defaultColumns = [
|
||||
{
|
||||
title: '预见期',
|
||||
dataIndex: 'tm',
|
||||
width: '30%',
|
||||
},
|
||||
{
|
||||
title: '雨量',
|
||||
dataIndex: 'drp',
|
||||
width: '30%',
|
||||
editable: true,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '水位',
|
||||
dataIndex: 'rz',
|
||||
width: '20%',
|
||||
},
|
||||
];
|
||||
const handleAdd = () => {
|
||||
const newArr = Array(count).fill(0).map((item, i) => ({
|
||||
key: (i + 1).toString(),
|
||||
tm: `${i + 1}小时`,
|
||||
drp: '',
|
||||
rz: '',
|
||||
}))
|
||||
|
||||
setDataSource([...newArr]);
|
||||
setEditData([...newArr])
|
||||
};
|
||||
const handleSave = (row) => {
|
||||
const newData = [...dataSource];
|
||||
const index = newData.findIndex((item) => row.key === item.key);
|
||||
const item = newData[index];
|
||||
newData.splice(index, 1, {
|
||||
...item,
|
||||
...row,
|
||||
});
|
||||
console.log('newData', newData);
|
||||
setDataSource(newData);
|
||||
setEditData(newData)
|
||||
};
|
||||
const components = {
|
||||
body: {
|
||||
row: EditableRow,
|
||||
cell: EditableCell,
|
||||
},
|
||||
};
|
||||
const columns = defaultColumns.map((col) => {
|
||||
if (!col.editable) {
|
||||
return col;
|
||||
}
|
||||
return {
|
||||
...col,
|
||||
onCell: (record) => ({
|
||||
record,
|
||||
editable: col.editable,
|
||||
dataIndex: col.dataIndex,
|
||||
title: col.title,
|
||||
handleSave,
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (count) {
|
||||
handleAdd(count)
|
||||
}
|
||||
}, [count])
|
||||
useEffect(() => {
|
||||
if (tableData.length > 0) {
|
||||
setDataSource(tableData)
|
||||
setEditData(tableData)
|
||||
}
|
||||
}, [tableData])
|
||||
return (
|
||||
<div>
|
||||
<Table
|
||||
components={components}
|
||||
rowClassName={() => 'editable-row'}
|
||||
bordered
|
||||
dataSource={dataSource}
|
||||
columns={columns}
|
||||
scroll={{ x: 200, y: 'calc( 100vh - 400px )' }}
|
||||
pagination={false}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export default App;
|
||||
|
|
@ -0,0 +1,205 @@
|
|||
import * as echarts from 'echarts';
|
||||
import moment, { min } from 'moment';
|
||||
|
||||
export default function drpOption(predict = [], history = [], type) {
|
||||
console.log("predict",predict[0]);
|
||||
|
||||
const LimitWater = type == 'cq' ? 112 :
|
||||
type == 'sxs' ? 72.01 :
|
||||
type == 'wpc' ? 112 : 0;
|
||||
// 水位
|
||||
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);
|
||||
const seen = new Map();
|
||||
const limitData = [...history, ...predict].filter(item => {
|
||||
const time = item.tm;
|
||||
if (!time) return true;
|
||||
const timeStr = moment(time).format('YYYY-MM-DD HH:mm:ss');
|
||||
|
||||
if (seen.has(timeStr)) {
|
||||
return false;
|
||||
}
|
||||
seen.set(timeStr, true);
|
||||
return true;
|
||||
});
|
||||
|
||||
const isShowSymbol = predict.length == 1 ? true : false;
|
||||
return {
|
||||
grid: {
|
||||
left: 0,
|
||||
top: "20%",
|
||||
right: "3%",
|
||||
bottom: "10%",
|
||||
containLabel: true,
|
||||
},
|
||||
tooltip: {
|
||||
trigger: 'axis',
|
||||
},
|
||||
legend: {
|
||||
right: "center",
|
||||
top: "4%",
|
||||
},
|
||||
toolbox: {
|
||||
show: true,
|
||||
top: "15%",
|
||||
right: "0%",
|
||||
orient: 'vertical',
|
||||
feature: {
|
||||
dataZoom: {
|
||||
show: true,
|
||||
title: {
|
||||
zoom: '区域缩放',
|
||||
back: '区域缩放还原',
|
||||
}
|
||||
},
|
||||
magicType: {
|
||||
show: true,
|
||||
title: {
|
||||
line: '切换为折线图',
|
||||
bar: '切换为柱状图',
|
||||
},
|
||||
type: ['line', 'bar']
|
||||
},
|
||||
restore: {
|
||||
show: true,
|
||||
title: '还原'
|
||||
},
|
||||
saveAsImage: {
|
||||
show: true,
|
||||
name: '日到报率详情',
|
||||
title: '保存为图片'
|
||||
}
|
||||
}
|
||||
},
|
||||
xAxis: {
|
||||
type: "category",
|
||||
// data: history.map(item => item.tm),
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
yAxis: [
|
||||
{
|
||||
type: "value",
|
||||
name: '水位',
|
||||
min: minRz,
|
||||
max: maxRz,
|
||||
splitLine: {
|
||||
show: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#7a869a",
|
||||
formatter: '{value} m'
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
type: "value",
|
||||
name: '雨量',
|
||||
min: mindrp,
|
||||
max: maxdrp,
|
||||
splitLine: {
|
||||
show: true,
|
||||
},
|
||||
axisLabel: {
|
||||
color: "#7a869a",
|
||||
formatter: '{value} mm'
|
||||
},
|
||||
axisTick: {
|
||||
show: false
|
||||
}
|
||||
|
||||
},
|
||||
],
|
||||
dataZoom: [{
|
||||
type: 'inside',
|
||||
start: (580 / history.length) * 100,
|
||||
// start:0,
|
||||
end: 100
|
||||
}, {
|
||||
start: 0,
|
||||
end: 10,
|
||||
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
|
||||
}
|
||||
}],
|
||||
series: [
|
||||
{
|
||||
name: "实测雨量",
|
||||
type: "bar",
|
||||
barWidth:3,
|
||||
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",
|
||||
color: '#1fbcd2',
|
||||
lineStyle: {
|
||||
width: 4 // 设置线的宽度为4px
|
||||
},
|
||||
yAxisIndex: 0,
|
||||
showSymbol: isShowSymbol,
|
||||
// symbolSize: 8,
|
||||
itemStyle: {
|
||||
borderWidth: 5
|
||||
},
|
||||
data: predict.map(item => [item.tm, item.predict]),
|
||||
smooth: true,
|
||||
},
|
||||
{
|
||||
name: LimitWater != 0 ? "汛限水位" :'',
|
||||
type: "line",
|
||||
yAxisIndex: 0,
|
||||
color:"#85ea2d",
|
||||
showSymbol: false,
|
||||
data:LimitWater != 0 ? limitData.map(item => [item.tm, LimitWater]) : [],
|
||||
smooth: true,
|
||||
},
|
||||
{
|
||||
// name:'截断',
|
||||
type: "bar",
|
||||
// color: '#F59A23',
|
||||
barWidth:3,
|
||||
yAxisIndex: 0,
|
||||
showSymbol: false,
|
||||
data: [[predict[0]?.tm, maxRz]],
|
||||
tooltip: {
|
||||
show:false
|
||||
},
|
||||
smooth: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,482 @@
|
|||
import React, { Fragment, useRef, useMemo, useEffect, useState } from 'react';
|
||||
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'
|
||||
import drpOption from './drpOption.js'
|
||||
import { httppost2 } from '../../utils/request';
|
||||
import TestApp from './createData.js'
|
||||
import { getAllHydroBatches, responseData } from './watersTools'
|
||||
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) {
|
||||
console.log(predictData,historyData);
|
||||
|
||||
return drpOption(predictData, historyData,searchVal.code)
|
||||
}
|
||||
}, [predictData, historyData,searchVal])
|
||||
|
||||
// const options = useMemo(() => {
|
||||
// return drpOption(tableList)
|
||||
// }, [tableList])
|
||||
const handleEmptyValue = (value) => {
|
||||
if (value === null || value === undefined || Number.isNaN(value)) {
|
||||
return '-';
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
// 测试
|
||||
const columns = [
|
||||
{
|
||||
title: '预测时间点',
|
||||
dataIndex: 'tm',
|
||||
key: 'tm',
|
||||
width: 175,
|
||||
align: 'center',
|
||||
fixed:'left'
|
||||
},
|
||||
{
|
||||
title: '预测降雨量(mm)',
|
||||
dataIndex: 'predictRainfall',
|
||||
key: 'predictRainfall',
|
||||
align: 'center',
|
||||
width: 120,
|
||||
// render: (text, record,index) => (
|
||||
// <InputNumber
|
||||
// defaultValue={text}
|
||||
// min={0}
|
||||
// precision={1}
|
||||
// onChange={(value) => handlePredictRainfallChange(value, index)}
|
||||
// style={{ width: '100%' }}
|
||||
// />
|
||||
// )
|
||||
},
|
||||
{
|
||||
title: '实测雨量(mm)',
|
||||
dataIndex: 'rains',
|
||||
key: 'rains',
|
||||
width: 120,
|
||||
align: 'center',
|
||||
render: (v) => <span>{ handleEmptyValue(v)}</span>
|
||||
},
|
||||
{
|
||||
title: '实测水位(m)',
|
||||
dataIndex: 'waters',
|
||||
key: 'waters',
|
||||
width: 100,
|
||||
align: 'center',
|
||||
render: (v) => <span>{ handleEmptyValue(v)}</span>
|
||||
|
||||
},
|
||||
{
|
||||
title: '预测水位(m)',
|
||||
dataIndex: 'predict',
|
||||
key: 'predict',
|
||||
width: 100,
|
||||
align: 'center'
|
||||
},
|
||||
{
|
||||
title: '差值(m)',
|
||||
dataIndex: 'cz',
|
||||
key: 'cz',
|
||||
width: 90,
|
||||
align: 'center',
|
||||
render: (v, r) => <span>{(r.predict && r.waters) ? Math.abs((r.predict - r.waters)).toFixed(2) : '-'}</span>
|
||||
},
|
||||
]
|
||||
|
||||
/**
|
||||
* 替换数组末尾指定数量的元素
|
||||
* @param {Array} arr - 原数组
|
||||
* @param {Array} newValues - 新值数组
|
||||
* @param {number} tn - 替换数量
|
||||
* @returns {Array} 新数组
|
||||
*/
|
||||
const replaceLastItems = (arr, newValues, tn = 1) => {
|
||||
if (!Array.isArray(arr)) {
|
||||
return newValues;
|
||||
}
|
||||
|
||||
const newArr = [...arr];
|
||||
const startIndex = Math.max(0, newArr.length - tn);
|
||||
|
||||
for (let i = 0; i < tn; i++) {
|
||||
if (startIndex + i < newArr.length) {
|
||||
newArr[startIndex + i] = newValues[i];
|
||||
}
|
||||
}
|
||||
|
||||
return newArr;
|
||||
};
|
||||
|
||||
/**
|
||||
* 收集预测雨量数据
|
||||
* @param {Array} data - 表格数据
|
||||
* @param {number} tn - 预测时段数
|
||||
* @returns {Array} 预测雨量数组
|
||||
*/
|
||||
const collectPredictRainfall = (data, tn = 1) => {
|
||||
if (!Array.isArray(data) || data.length === 0) return [];
|
||||
|
||||
const result = [];
|
||||
data.slice(-tn).forEach(item => {
|
||||
result.push((item.predictRainfall === '' || item.predictRainfall==null || item.predictRainfall == undefined) ? item.rains : item.predictRainfall);
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 处理预测雨量的变化
|
||||
* @param {Array} data - 原始数据
|
||||
* @param {Object} changes - 变化的数据 {index: value}
|
||||
* @returns {Array} 处理后的数据
|
||||
*/
|
||||
const handlePredictRainfallChanges =(data, value, index) => {
|
||||
if (!Array.isArray(data)) return [];
|
||||
const newData = [...data];
|
||||
if (newData[index]) {
|
||||
newData[index] = {
|
||||
...newData[index],
|
||||
predictRainfall: value,
|
||||
isModified: true // 标记该项已被修改
|
||||
};
|
||||
}
|
||||
return newData;
|
||||
};
|
||||
const [predictRainfalling, setPredictRainfalling] = useState({});
|
||||
const [tableUpdata, setTableUpdata] = useState([])
|
||||
const tableUpdataRef = useRef(null);
|
||||
// tableUpdataRef.current = tableUpdata;
|
||||
const handleRainfallChange = (value, index) => {
|
||||
setPredictRainfalling(prev => ({
|
||||
...prev,
|
||||
[index]: value
|
||||
}));
|
||||
const updatedData = handlePredictRainfallChanges(tableList, value, index);
|
||||
setTableList(updatedData)
|
||||
setTableUpdata(updatedData)
|
||||
tableUpdataRef.current = updatedData
|
||||
};
|
||||
const getHistoryData = async (params) => {
|
||||
params.stcd = obj[params.code];
|
||||
params.predictRainfallList = tableUpdataRef.current;
|
||||
if (tableUpdataRef.current.length && tableUpdataRef.current.some(item => item.predictRainfall === '' || item.predictRainfall == null || item.predictRainfall == undefined)) {
|
||||
message.warning(`请输入${searchVal.time}个预测雨量值`)
|
||||
return
|
||||
}
|
||||
setLoading(true)
|
||||
try {
|
||||
const result = await httppost2(apiurl.test.find1, 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)
|
||||
let subResponseData = JSON.parse(JSON.stringify(responseData)).slice(-searchVal.time)
|
||||
const allBatches = getAllHydroBatches(responseData);
|
||||
let needData = responseData;
|
||||
let type = tableUpdataRef.current.length > 0 ? 2 :1
|
||||
if (tableUpdataRef.current.length > 0) {
|
||||
needData = tableUpdataRef.current.map((item,i) => {
|
||||
return {
|
||||
...item,
|
||||
tm:subResponseData[i]?.tm
|
||||
}
|
||||
});
|
||||
}
|
||||
const res = await processPredictions(allBatches, params.code, needData, type)
|
||||
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) : '',
|
||||
waters: obj?.waters ,
|
||||
rains: obj?.rains,
|
||||
predictRainfall:type == 2 ? obj?.predictRainfall:''
|
||||
}
|
||||
})
|
||||
console.log("tableData",tableData);
|
||||
|
||||
setTableList(tableData)
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理预测结果
|
||||
* @param {Array} batches - 批次数据
|
||||
* @param {Array} predictions - 预测结果数组
|
||||
* @returns {Array} - 返回处理后的预测结果
|
||||
*/ const processPredictions = async (batches, name, responseArr, type) => {
|
||||
let arr = [];
|
||||
if (type == 1) {
|
||||
arr = JSON.parse(JSON.stringify(responseArr));
|
||||
arr.slice(-searchVal.time);
|
||||
} else {
|
||||
arr=responseArr
|
||||
}
|
||||
const predictRainArr = collectPredictRainfall(arr, searchVal.time) //收集的输入预测雨量数组
|
||||
const results = [];
|
||||
for (const batch of batches) {
|
||||
const prediction = await httppost2('http://202.96.165.23:10100/api/v1/bot/water_infer', {
|
||||
// rains: replaceLastItem(batch.rains,searchVal.predictRain),
|
||||
rains:replaceLastItems(batch.rains,predictRainArr,searchVal.time),
|
||||
waters: batch.waters,
|
||||
name,
|
||||
tn:searchVal.time
|
||||
});
|
||||
prediction?.data?.water_predicts.forEach((item,i) => {
|
||||
results.push({
|
||||
predict: item, // 预测水位
|
||||
tm: moment(batch.lastTm).clone().add(i, 'hours').format("YYYY-MM-DD HH:00:00") // 对应的时间点
|
||||
});
|
||||
})
|
||||
// results.push({
|
||||
// predict: prediction?.data?.water_predicts[0], // 预测水位
|
||||
// tm: batch.lastTm // 对应的时间点
|
||||
// });
|
||||
}
|
||||
|
||||
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.waters)), 0);
|
||||
const newArr = JSON.parse(JSON.stringify(tableList));
|
||||
const resultMaxOrMin = findMinMaxRain(newArr.map(item => ({ ...item, diff: Math.abs((item.predict - item.waters)).toFixed(2) })))
|
||||
return {
|
||||
avergVal: (sum / tableList.length).toFixed(2),
|
||||
maxVal: resultMaxOrMin?.max,
|
||||
minVal: resultMaxOrMin?.min,
|
||||
};
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}, [tableList])
|
||||
|
||||
useEffect(() => {
|
||||
if (searchVal.time) {
|
||||
setTableUpdata([])
|
||||
tableUpdataRef.current = []
|
||||
}
|
||||
}, [searchVal.time])
|
||||
|
||||
// useEffect(() => {
|
||||
// if (searchVal.code) {
|
||||
// setTableUpdata([])
|
||||
// tableUpdataRef.current = []
|
||||
// }
|
||||
// }, [searchVal.code])
|
||||
|
||||
// useEffect(() => {
|
||||
// if (searchVal.tm) {
|
||||
// setTableUpdata([])
|
||||
// tableUpdataRef.current = []
|
||||
// }
|
||||
// }, [searchVal.tm])
|
||||
|
||||
useEffect(() => {
|
||||
if (searchVal.etm && tableUpdataRef.current.length > 0) {
|
||||
tableUpdataRef.current = [...tableUpdataRef.current.map((item,index) => {
|
||||
return {
|
||||
...item,
|
||||
tm:moment(searchVal.etm).add(index + 1, 'hours').format('YYYY-MM-DD HH:00:00')
|
||||
}
|
||||
})]
|
||||
|
||||
}
|
||||
}, [searchVal.etm,searchVal.code])
|
||||
|
||||
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (searchVal) {
|
||||
getHistoryData(searchVal)
|
||||
}
|
||||
|
||||
}, [searchVal])
|
||||
|
||||
|
||||
|
||||
|
||||
// 渲染预测雨量输入表单
|
||||
const renderRainfallInputs = () => {
|
||||
const inputs = [];
|
||||
for (let i = 0; i < searchVal.time; i++) {
|
||||
inputs.push(
|
||||
<Form.Item
|
||||
key={i}
|
||||
label={`${i + 1}h`}
|
||||
style={{ marginBottom: 16 }}
|
||||
>
|
||||
<InputNumber
|
||||
value={predictRainfalling[i]}
|
||||
onChange={(value) => handleRainfallChange(value, i)}
|
||||
min={0}
|
||||
precision={1}
|
||||
placeholder={`请输入雨量`}
|
||||
style={{ width: 100 }}
|
||||
/>
|
||||
</Form.Item>
|
||||
);
|
||||
}
|
||||
return inputs;
|
||||
};
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='content-root clearFloat xybm' style={{ paddingBottom: "0" }}>
|
||||
<div className='lf' style={{ width: "100%", overflowY: "auto" }}>
|
||||
<Card className='nonebox'>
|
||||
<ToolBar
|
||||
setSearchVal={setSearchVal}
|
||||
setPredictRainfalling={setPredictRainfalling}
|
||||
/>
|
||||
</Card>
|
||||
{
|
||||
searchVal.time && <div style={{ marginTop: 16,marginLeft:10,marginRight:10 }}>
|
||||
<Form layout="inline">
|
||||
{renderRainfallInputs()}
|
||||
</Form>
|
||||
</div>
|
||||
}
|
||||
{
|
||||
historyData.length ? !loading ?
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0"}}>
|
||||
|
||||
<div style={{ display: 'flex', }}>
|
||||
<div style={{ flex: 1, height: 'calc( 100vh - 400px )', padding: 10 }}>
|
||||
<ReactEcharts option={options} style={{ width: "100%", height: '100%' }} notMerge={true} />
|
||||
</div>
|
||||
<div style={{ width: 700, marginRight: 30 }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableList}
|
||||
rowKey='tm'
|
||||
pagination={false}
|
||||
scroll={{ x: 600, y: 'calc(100vh - 300px)' }}
|
||||
summary={() => {
|
||||
return (
|
||||
<>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={12} align='center' colSpan={1} >差值最大值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} align='center' colSpan={2}>{summaryVal?.maxVal?.tm || '-'}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} align='center' colSpan={2}>差值最大值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={3} align='center' colSpan={1}>{summaryVal?.maxVal?.diff !='NaN'?summaryVal?.maxVal?.diff:"-"}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
{/* <Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center' colSpan={1} >差值最小值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={2}>{summaryVal?.minVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={6} align='center' colSpan={1}>差值最小值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={7} align='center' colSpan={1}>{summaryVal?.minVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row> */}
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center' colSpan={1} >差值平均值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={6}>{summaryVal?.avergVal!='NaN'?summaryVal?.avergVal: '-'}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</>
|
||||
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> : <div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}><Spin size="large" /></div> :
|
||||
<div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}> <img alt='' src={`${process.env.PUBLIC_URL}/assets/noData.png`} /></div>}
|
||||
|
||||
|
||||
{/* {!loading?
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0", height: 'calc( 100vh - 400px )' }}>
|
||||
|
||||
<div style={{ display: 'flex', }}>
|
||||
<div style={{ flex: 1, height: 'calc( 100vh - 400px )', padding: 10 }}>
|
||||
<ReactEcharts option={options} style={{ width: "100%", height: '100%' }} notMerge={true} />
|
||||
</div>
|
||||
<div style={{ width: 600, marginRight: 30 }}>
|
||||
<Table
|
||||
columns={columns}
|
||||
dataSource={tableList}
|
||||
rowKey='tm'
|
||||
pagination={true}
|
||||
scroll={{x:600,y:'calc(100vh - 300px)'}}
|
||||
summary={() => {
|
||||
return (
|
||||
<>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={12} align='center'colSpan={1} >差值最大值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={1} align='center' colSpan={2}>{summaryVal?.maxVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={2} align='center' colSpan={1}>差值最大值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={3} align='center' colSpan={1}>{summaryVal?.maxVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center'colSpan={1} >差值最小值时间点</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={2}>{summaryVal?.minVal?.tm}</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={6} align='center' colSpan={1}>差值最小值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={7} align='center' colSpan={1}>{summaryVal?.minVal?.diff}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
<Table.Summary.Row>
|
||||
<Table.Summary.Cell index={4} align='center'colSpan={1} >差值平均值</Table.Summary.Cell>
|
||||
<Table.Summary.Cell index={5} align='center' colSpan={4}>{summaryVal?.avergVal}</Table.Summary.Cell>
|
||||
</Table.Summary.Row>
|
||||
</>
|
||||
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div> : <div style={{ width: '100%', height: 'calc(100vh - 60px)', display: 'flex', justifyContent: 'center', alignItems: 'center' }}><Spin size="large" /></div>
|
||||
} */}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
.line-box{
|
||||
background-color: #fff;
|
||||
}
|
||||
.ant-table-summary {
|
||||
background-color: #f2f9fd !important;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,140 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Form, Input, Button, DatePicker, InputNumber, message } from 'antd';
|
||||
import NormalSelect from '../../components/Form/NormalSelect';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import moment from 'moment';
|
||||
const { RangePicker } = DatePicker;
|
||||
const ToolBar = ({ setSearchVal, setType, save, form1,setPredictRainfalling }) => {
|
||||
const navigate = useNavigate();
|
||||
const types = [
|
||||
// {
|
||||
// label: "黄家湾水库",
|
||||
// value: "hjw"
|
||||
// },
|
||||
{
|
||||
label: "车桥水库",
|
||||
value: "cq"
|
||||
},
|
||||
{
|
||||
label: "三星寺水库",
|
||||
value: "sxs"
|
||||
},
|
||||
{
|
||||
label: "石子岭水库",
|
||||
value: "szl"
|
||||
},
|
||||
{
|
||||
label: "乌盆冲",
|
||||
value: "wpc"
|
||||
},
|
||||
]
|
||||
|
||||
const timeType = [
|
||||
{
|
||||
label: "1h",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
label: "3h",
|
||||
value: 3
|
||||
},
|
||||
{
|
||||
label: "6h",
|
||||
value: 6
|
||||
},
|
||||
{
|
||||
label: "12h",
|
||||
value: 12
|
||||
},
|
||||
{
|
||||
label: "24h",
|
||||
value: 24
|
||||
}
|
||||
]
|
||||
|
||||
const [form] = Form.useForm();
|
||||
|
||||
const onFinish = (values) => {
|
||||
let dateTimeRangeSo;
|
||||
if (values.tm) {
|
||||
dateTimeRangeSo = {
|
||||
// start: moment(values.tm[0]).format('YYYY-MM-DD HH:00:00'),
|
||||
end: moment(values.tm).format('YYYY-MM-DD HH:00:00')
|
||||
}
|
||||
} else {
|
||||
message.error('请选择时间范围')
|
||||
}
|
||||
delete values.tm
|
||||
setSearchVal({...values,etm: dateTimeRangeSo.end});
|
||||
}
|
||||
const disabledFutureDate = (current) => {
|
||||
const maxDate = moment('2025-02-28');
|
||||
return current && (current > maxDate);
|
||||
};
|
||||
|
||||
const onValuesChange = (val, r) => {
|
||||
if ('time' in val) {
|
||||
setSearchVal({ ...r, time: val.time, etm: moment(r.tm).format("YYYY-MM-DD HH:mm:ss") })
|
||||
setPredictRainfalling({})
|
||||
}
|
||||
}
|
||||
|
||||
const jump = () => {
|
||||
navigate('/');
|
||||
}
|
||||
useEffect(() => {
|
||||
const stm = moment('2024-01-01').format('YYYY-MM-DD 00:00:00')
|
||||
const etm = moment('2024-07-28 11:00:00').format('YYYY-MM-DD HH:00:00')
|
||||
const params = {
|
||||
code: "cq",
|
||||
time: 6,
|
||||
predictRain:11,
|
||||
// stm,
|
||||
etm
|
||||
}
|
||||
form.setFieldValue('code', params.code);
|
||||
form.setFieldValue('tm',moment('2024-07-28 11:00:00'));
|
||||
form.setFieldValue('time', params.time);
|
||||
form.setFieldValue('predictRain', params.predictRain);
|
||||
setSearchVal(params)
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
|
||||
<Form form={form} className='toolbarBox' layout="inline" onFinish={onFinish} onValuesChange={onValuesChange}>
|
||||
<Form.Item label="水库" name="code">
|
||||
<NormalSelect allowClear={false} style={{ width: '150px' }} options={types} />
|
||||
</Form.Item>
|
||||
<Form.Item label="预测时段" name="time">
|
||||
<NormalSelect allowClear={false} style={{ width: '150px' }} options={timeType} />
|
||||
</Form.Item>
|
||||
{/* <Form.Item label="预测降雨量" name="predictRain">
|
||||
<InputNumber min={0} style={{ width: '150px' }}/>
|
||||
</Form.Item> */}
|
||||
<Form.Item label="时间" name="tm"
|
||||
>
|
||||
<DatePicker
|
||||
showTime
|
||||
disabledDate={disabledFutureDate}
|
||||
style={{ width: "250px" }}
|
||||
format="YYYY-MM-DD HH:00:00"
|
||||
allowClear={false}
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item>
|
||||
<Button type="primary" htmlType="submit">查询</Button>
|
||||
</Form.Item>
|
||||
<Form.Item>
|
||||
<Button type="primary" onClick={jump}>时段预测</Button>
|
||||
</Form.Item>
|
||||
</Form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default ToolBar;
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
import moment from "moment";
|
||||
/**
|
||||
* 使用滑动窗口获取水文数据批次
|
||||
* @param {Array} data - 后端返回的数据数组
|
||||
* @returns {Array} - 返回数组,每个元素包含600个点的数据
|
||||
*/
|
||||
export const getAllHydroBatches = (data) => {
|
||||
if (!Array.isArray(data) || data.length < 600) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const batches = [];
|
||||
let startIndex = 0;
|
||||
|
||||
// 当剩余数据量大于等于600时继续处理
|
||||
while (startIndex + 600 <= 600) {
|
||||
const slicedData = data.slice(startIndex, startIndex + 600);
|
||||
batches.push({
|
||||
rains: slicedData.map(item => item.rains),
|
||||
waters: slicedData.map(item => item.waters),
|
||||
// lastTm: slicedData[599].tm // 记录第600个点的时间
|
||||
lastTm:moment(slicedData[599].tm).clone().add(1, 'hours').format("YYYY-MM-DD HH:00:00")
|
||||
});
|
||||
|
||||
// 每次向后移动1个位置
|
||||
startIndex += 1;
|
||||
}
|
||||
return batches;
|
||||
};
|
||||
|
||||
export const responseData = new Array(800).fill(0).map((item,index) => ({
|
||||
rains: (Math.random() * 1).toFixed(2),
|
||||
waters: (Math.random() * 100).toFixed(2),
|
||||
tm:moment().clone().add(index, 'hours').format("YYYY-MM-DD HH:00:00")
|
||||
}))
|
||||
Loading…
Reference in New Issue