feat(): 首页大屏闸口开发
parent
3c5bd3ac4e
commit
00e701be3b
|
|
@ -1 +1 @@
|
||||||
PUBLIC_URL=/tsg
|
PUBLIC_URL=/ykz
|
||||||
|
|
@ -1,2 +1,2 @@
|
||||||
GENERATE_SOURCEMAP=false
|
GENERATE_SOURCEMAP=false
|
||||||
PUBLIC_URL=/tsg
|
PUBLIC_URL=/ykz
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
"@wangeditor/editor": "^5.1.23",
|
"@wangeditor/editor": "^5.1.23",
|
||||||
"@wangeditor/editor-for-react": "^1.0.6",
|
"@wangeditor/editor-for-react": "^1.0.6",
|
||||||
"antd": "^4.21.7",
|
"antd": "^4.21.7",
|
||||||
|
"autofit.js": "^3.2.2",
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"clone": "^2.1.2",
|
"clone": "^2.1.2",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
|
|
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 865 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
|
|
@ -61,7 +61,8 @@ const TopMenu: React.FC<{
|
||||||
|
|
||||||
const menuClicked = (id: any) => {
|
const menuClicked = (id: any) => {
|
||||||
const menuItem:any = menu.find(m => m.id == id);
|
const menuItem:any = menu.find(m => m.id == id);
|
||||||
if (menuItem.title === "雨水工灾情") {
|
if (menuItem.title === "首页") {
|
||||||
|
navigate(menuItem.path)
|
||||||
}
|
}
|
||||||
const url = getMenuUrl(menuItem);
|
const url = getMenuUrl(menuItem);
|
||||||
|
|
||||||
|
|
@ -79,16 +80,7 @@ const TopMenu: React.FC<{
|
||||||
<div
|
<div
|
||||||
key={o.id}
|
key={o.id}
|
||||||
className={`app-top-menu-item${menuIndexes[0] == o.id ? ' active' : ''}`}
|
className={`app-top-menu-item${menuIndexes[0] == o.id ? ' active' : ''}`}
|
||||||
onClick={() => {
|
onClick={() => {menuClicked(o.id)}}
|
||||||
if(o.title==='防汛大屏'){
|
|
||||||
// window.open('http://local.gunshiiot.com:18083/xfdp/#/v/home?token='+localStorage.getItem('access_token'))
|
|
||||||
window.open('http://36.139.207.50:18083/xfdp/#/v/home?token='+localStorage.getItem('access_token'))
|
|
||||||
}else if(o.title==='数字孪生大屏'){
|
|
||||||
window.open('https://owrres.oss-cn-shenzhen.aliyuncs.com/zhtmp/index.html#/mgr/home')
|
|
||||||
}else{
|
|
||||||
menuClicked(o.id)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
style={{cursor:"pointer"}}
|
style={{cursor:"pointer"}}
|
||||||
>
|
>
|
||||||
<img src={`${process.env.PUBLIC_URL}/assets/${o.icon}.png`} alt=""/>
|
<img src={`${process.env.PUBLIC_URL}/assets/${o.icon}.png`} alt=""/>
|
||||||
|
|
|
||||||
|
|
@ -192,7 +192,7 @@ export async function loadMenu(): Promise<MenuItem[]> {
|
||||||
|
|
||||||
const id = idgen()
|
const id = idgen()
|
||||||
return [
|
return [
|
||||||
{ id: id(), title: '首页', path: '/mgr/home', icon: 'yzt' },
|
{ id: id(), title: '首页', path: '/home', icon: 'yzt' },
|
||||||
{
|
{
|
||||||
id: id(), title: '监测数据', redirect: '/mgr/jcsj/jcsj', icon: 'sz',
|
id: id(), title: '监测数据', redirect: '/mgr/jcsj/jcsj', icon: 'sz',
|
||||||
children: [
|
children: [
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,12 @@ const apiurl = {
|
||||||
router: service_xyt + '/getRouters',
|
router: service_xyt + '/getRouters',
|
||||||
role: service_xyt + '/system/menu/list'
|
role: service_xyt + '/system/menu/list'
|
||||||
},
|
},
|
||||||
|
zmjk: {
|
||||||
|
getList : service_xyt + '/attGateB/list',
|
||||||
|
getInformation: service_xyt + '/attGateB/data',
|
||||||
|
getDamData: service_xyt + '/gatePore/listByStcd',
|
||||||
|
getVideo: service_xyt + '/gateValveCctvRel/list'
|
||||||
|
},
|
||||||
sbwh: {
|
sbwh: {
|
||||||
whfabz: {
|
whfabz: {
|
||||||
page: service_fxdd + '/resPerson/page',
|
page: service_fxdd + '/resPerson/page',
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ async function send(url, options) {
|
||||||
if (code === 405) {
|
if (code === 405) {
|
||||||
// debugger;
|
// debugger;
|
||||||
//window.location.href = '/mgr/home';// /mgr/home /login
|
//window.location.href = '/mgr/home';// /mgr/home /login
|
||||||
window.location.href = '/tsg/#/login';
|
window.location.href = '/ykz/#/login';
|
||||||
// window.location.hash = '#/login';
|
// window.location.hash = '#/login';
|
||||||
}
|
}
|
||||||
return res.data;
|
return res.data;
|
||||||
|
|
|
||||||
|
|
@ -33,11 +33,12 @@ const AppRouters: React.FC = () => {
|
||||||
|
|
||||||
let element = useRoutes([
|
let element = useRoutes([
|
||||||
{ path: '/', element: <LoginPage /> },
|
{ path: '/', element: <LoginPage /> },
|
||||||
|
{ path: '/home', element: <HomePage /> },
|
||||||
{
|
{
|
||||||
path: '/mgr',
|
path: '/mgr',
|
||||||
element: <DashboardLayout />,
|
element: <DashboardLayout />,
|
||||||
children: [
|
children: [
|
||||||
{ path: 'home', element: <HomePage /> },
|
// { path: 'home', element: <HomePage /> },
|
||||||
// 监测数据
|
// 监测数据
|
||||||
{ path: 'jcsj/jcsj', element: <Jcsj /> },
|
{ path: 'jcsj/jcsj', element: <Jcsj /> },
|
||||||
{ path: 'jcsj/bjgl/bjjl', element: <PoliceRecord /> },
|
{ path: 'jcsj/bjgl/bjjl', element: <PoliceRecord /> },
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,71 @@
|
||||||
import React from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
|
import { useNavigate } from 'react-router';
|
||||||
|
import autofit from 'autofit.js'
|
||||||
|
import Zmjk from "./zmjk"
|
||||||
|
import './index.less'
|
||||||
|
|
||||||
export default function Home() {
|
const MenuTitleCard = ({key,title}) => {
|
||||||
return (
|
return (
|
||||||
<div>Home</div>
|
<div className='menuItem_style' key={key} title={title}>
|
||||||
|
{title}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default function Home() {
|
||||||
|
const title = [
|
||||||
|
{
|
||||||
|
title: '首页',
|
||||||
|
key: '/home',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '监测数据',
|
||||||
|
key: '/mgr/jcsj/jcsj',
|
||||||
|
}, {
|
||||||
|
title: '安全监测',
|
||||||
|
key: '/mgr/aqjc',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '系统管理',
|
||||||
|
key: '/mgr/xtgl/yhxx',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '工程运行',
|
||||||
|
key: '/mgr/gcyx/xxcx/jbqk',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: '设备维护',
|
||||||
|
key: '/mgr/sbwh/wxyhgl/wxfabz',
|
||||||
|
},
|
||||||
|
|
||||||
|
]
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const jumpMenu = (item) => {
|
||||||
|
navigate(item.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
autofit.init({
|
||||||
|
dh: 1080,
|
||||||
|
dw: 1920,
|
||||||
|
el:'#daping-body',
|
||||||
|
resize: true
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='daping-body' id='daping-body'>
|
||||||
|
<div className='topMenu'>
|
||||||
|
<div className='title'></div>
|
||||||
|
<div className='title_name'></div>
|
||||||
|
{title.map((item, i) => (
|
||||||
|
<div key={item.key} className={'styles'+i} onClick={()=>jumpMenu(item)} style={{cursor:'pointer'}}>
|
||||||
|
<MenuTitleCard title={item.title} />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<div className='content-box'>
|
||||||
|
<Zmjk />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,77 @@
|
||||||
|
.daping-body{
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 100vh;
|
||||||
|
background:url(../../assets/ykzImg/bp.png) no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
.topMenu{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
height: 160px;
|
||||||
|
background:url(../../assets/ykzImg/title.png) no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
.title{
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
// left: 41%;
|
||||||
|
width: 350px;
|
||||||
|
height: 70px;
|
||||||
|
background:url(../../assets/ykzImg/text.png) no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
.title_name{
|
||||||
|
position: absolute;
|
||||||
|
top: 130px;
|
||||||
|
// left: 41%;
|
||||||
|
width: 350px;
|
||||||
|
height: 70px;
|
||||||
|
background:url(../../assets/ykzImg/name.png) no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
.menuItem_style{
|
||||||
|
width: 170px;
|
||||||
|
height: 55px;
|
||||||
|
line-height: 55px;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: 5px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 700;
|
||||||
|
|
||||||
|
background:url(../../assets/ykzImg/menu_btn.png) no-repeat center;
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
.styles0{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
left:100px;
|
||||||
|
}
|
||||||
|
.styles1{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
left:300px;
|
||||||
|
}.styles2{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
left:500px;
|
||||||
|
}.styles3{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
right:100px;
|
||||||
|
}.styles4{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
right:300px;
|
||||||
|
}.styles5{
|
||||||
|
position: absolute;
|
||||||
|
top:30px;
|
||||||
|
right:500px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.content-box{
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { Shape } from 'react-konva';
|
||||||
|
|
||||||
|
const ColorPolygon: React.FC<{
|
||||||
|
pts: ({ x?: number, y?: number } | [number, number])[]
|
||||||
|
fill: string;
|
||||||
|
desc?: string;
|
||||||
|
opacity?: number;
|
||||||
|
}> = ({ pts, fill, opacity }) => {
|
||||||
|
return (
|
||||||
|
<Shape
|
||||||
|
fill={fill}
|
||||||
|
opacity={opacity}
|
||||||
|
sceneFunc={(context:any, shape:any) => {
|
||||||
|
context.beginPath();
|
||||||
|
pts.forEach((p, i) => {
|
||||||
|
let x:any, y:any;
|
||||||
|
if (Array.isArray(p)) {
|
||||||
|
x = p[0];
|
||||||
|
y = p[1];
|
||||||
|
} else {
|
||||||
|
x = p.x;
|
||||||
|
y = p.y;
|
||||||
|
}
|
||||||
|
if (i === 0) {
|
||||||
|
context.moveTo(x, y);
|
||||||
|
} else {
|
||||||
|
context.lineTo(x, y);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
context.closePath();
|
||||||
|
context.fillStrokeShape(shape)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ColorPolygon
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Layer, Rect } from 'react-konva';
|
||||||
|
import ColorPolygon from './ColorPolygon';
|
||||||
|
import { CanvasH, CanvasW, FarBuildingTop, Horizontal, RoofTop, SideRoomSize } from './consts';
|
||||||
|
import { ControlPts } from './coordinates';
|
||||||
|
import { RoomWindows } from './Window';
|
||||||
|
|
||||||
|
const Sider: React.FC<{
|
||||||
|
pts: ControlPts;
|
||||||
|
side: 'left' | 'right';
|
||||||
|
}> = ({ side, pts }) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layer
|
||||||
|
x={side === 'left' ? 0 : CanvasW}
|
||||||
|
scaleX={side === 'left' ? 1 : -1}
|
||||||
|
width={CanvasW * 0.5}
|
||||||
|
>
|
||||||
|
<ColorPolygon desc='水' fill="#458eab" pts={[[0, Horizontal], [0, CanvasH], [CanvasW * 0.5, CanvasH], [CanvasW * 0.5, Horizontal]]} />
|
||||||
|
|
||||||
|
<ColorPolygon desc='远处的墙' fill="#8fa7a7" pts={[[0, FarBuildingTop], pts.C2, pts.C1, [pts.C1.x, FarBuildingTop]]} />
|
||||||
|
|
||||||
|
<Rect x={pts.RoomLT.x} y={pts.RoomLT.y} width={SideRoomSize} height={SideRoomSize} fill="#738785" />
|
||||||
|
<RoomWindows rect={[pts.RoomLT.x, pts.RoomLT.y + 8, pts.RoomRB.x - 16, pts.RoomRB.y]} />
|
||||||
|
<ColorPolygon desc='房屋侧面' fill="#4a5c5e" pts={[pts.RoomRT, pts.RoomRB, pts.RoomRBFar, pts.RoomRTFar]} />
|
||||||
|
<Rect x={pts.RoomLT.x - 2} y={pts.RoomLT.y} width={SideRoomSize + 4} height={8} fill="#f2ebcd" />
|
||||||
|
<ColorPolygon desc='房屋侧面-白条' fill="#f2ebcd" pts={[
|
||||||
|
[pts.RoomRT.x + 2, pts.RoomRT.y],
|
||||||
|
[pts.RoomRB.x + 2, pts.RoomRT.y + 8],
|
||||||
|
[pts.RoomRTFar.x! + 2, pts.RoomRTFar.y! + 8],
|
||||||
|
[pts.RoomRTFar.x! + 2, pts.RoomRTFar.y!]
|
||||||
|
]} />
|
||||||
|
<ColorPolygon desc='房屋底面' fill="#4a5c5e" pts={[pts.RoomLB, pts.RoomLBFar, pts.RoomRBFar, pts.RoomRB]} />
|
||||||
|
<Rect x={pts.RoomRB.x - 16} y={pts.RoomRB.y - 8 - SideRoomSize} width={16} height={SideRoomSize} fill="#6e3a34" />
|
||||||
|
|
||||||
|
|
||||||
|
<ColorPolygon desc='侧面' fill="#4a5c5e" pts={[pts.L2, pts.B2, pts.B1, pts.L1]} />
|
||||||
|
<ColorPolygon desc='上盖' fill="#728381" pts={[pts.C2, pts.L2, pts.L1, pts.C1]} />
|
||||||
|
<ColorPolygon desc='墙' fill="#738b8b" pts={[[pts.C1.x, RoofTop], pts.C1, pts.L1, pts.A1]} />
|
||||||
|
|
||||||
|
<ColorPolygon desc='内壁' fill="#334648" pts={[pts.A1, pts.B1, pts.B3, pts.A2]} />
|
||||||
|
</Layer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Sider)
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
import React, { useMemo } from 'react';
|
||||||
|
import { Layer, Rect } from 'react-konva';
|
||||||
|
import ColorPolygon from './ColorPolygon';
|
||||||
|
import { Window1, WindowSep } from './Window';
|
||||||
|
import { TopRoomHeight } from './consts';
|
||||||
|
import { ControlPts, mirror } from './coordinates';
|
||||||
|
|
||||||
|
|
||||||
|
const Topper1: React.FC<{
|
||||||
|
pts: ControlPts;
|
||||||
|
type: number;
|
||||||
|
}> = ({ pts, type }) => {
|
||||||
|
|
||||||
|
const windows = useMemo<{
|
||||||
|
w: number[][];
|
||||||
|
h: number[][];
|
||||||
|
}>(() => {
|
||||||
|
const x1 = pts.TopRectLB.x;
|
||||||
|
const y0 = pts.TopRectLB.y - TopRoomHeight
|
||||||
|
const y1 = pts.TopRectLB.y - TopRoomHeight * 0.75;
|
||||||
|
const x2 = pts.TopRectRB.x;
|
||||||
|
const y2 = pts.TopRectLB.y - TopRoomHeight * 0.25;
|
||||||
|
if (type === 1) {
|
||||||
|
const u = (x2 - x1) / 10;
|
||||||
|
return {
|
||||||
|
w: [
|
||||||
|
[x1 + u, y1, x1 + 3 * u, y2],
|
||||||
|
[x1 + 4 * u, y1, x1 + 6 * u, y2],
|
||||||
|
[x1 + 7 * u, y1, x1 + 9 * u, y2],
|
||||||
|
],
|
||||||
|
h: []
|
||||||
|
}
|
||||||
|
} else if (type === 2) {
|
||||||
|
const u = (x2 - x1 - 8) / 14;
|
||||||
|
return {
|
||||||
|
w: [
|
||||||
|
[x1 + u, y1, x1 + 3 * u, y2],
|
||||||
|
[x1 + 4 * u, y1, x1 + 6 * u, y2],
|
||||||
|
[x1 + 8 * u + 8, y1, x1 + 10 * u + 8, y2],
|
||||||
|
[x1 + 11 * u + 8, y1, x1 + 13 * u + 8, y2],
|
||||||
|
],
|
||||||
|
h: [
|
||||||
|
[x1 + 7 * u, y0, x1 + 7 * u + 8, pts.TopRectLB.y],
|
||||||
|
],
|
||||||
|
}
|
||||||
|
} else if (type === 3) {
|
||||||
|
const xc = (x2 - x1) * 0.5;
|
||||||
|
const u = (xc - 8) / 8;
|
||||||
|
return {
|
||||||
|
w: [
|
||||||
|
[x1 + u, y1, x1 + 3 * u, y2],
|
||||||
|
[x1 + 5 * u + 8, y1, x1 + 7 * u + 8, y2],
|
||||||
|
[x1 + u + xc, y1, x1 + 3 * u + xc, y2],
|
||||||
|
[x1 + 5 * u + 8 + xc, y1, x1 + 7 * u + 8 + xc, y2],
|
||||||
|
],
|
||||||
|
h: [
|
||||||
|
[x1 + 4 * u, y0, x1 + 4 * u + 8, pts.TopRectLB.y],
|
||||||
|
[x1 + 4 * u + xc, y0, x1 + 4 * u + 8 + xc, pts.TopRectLB.y],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
} else if (type > 3) {
|
||||||
|
const xc1 = (x2 - x1) / 3;
|
||||||
|
const xc2 = xc1 * 2;
|
||||||
|
const u = (xc1 - 8) / 8;
|
||||||
|
return {
|
||||||
|
w: [
|
||||||
|
[x1 + u, y1, x1 + 3 * u, y2],
|
||||||
|
[x1 + 5 * u + 8, y1, x1 + 7 * u + 8, y2],
|
||||||
|
[x1 + u + xc1, y1, x1 + 3 * u + xc1, y2],
|
||||||
|
[x1 + 5 * u + 8 + xc1, y1, x1 + 7 * u + 8 + xc1, y2],
|
||||||
|
[x1 + u + xc2, y1, x1 + 3 * u + xc2, y2],
|
||||||
|
[x1 + 5 * u + 8 + xc2, y1, x1 + 7 * u + 8 + xc2, y2],
|
||||||
|
],
|
||||||
|
h: [
|
||||||
|
[x1 + 4 * u, y0, x1 + 4 * u + 8, pts.TopRectLB.y],
|
||||||
|
[x1 + 4 * u + xc1, y0, x1 + 4 * u + 8 + xc1, pts.TopRectLB.y],
|
||||||
|
[x1 + 4 * u + xc2, y0, x1 + 4 * u + 8 + xc2, pts.TopRectLB.y],
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
w: [], h: []
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layer>
|
||||||
|
<Rect fill='#738b8b' x={pts.TopRectLB.x} y={pts.TopRectLB.y - TopRoomHeight} width={pts.TopRectRB.x - pts.TopRectLB.x} height={TopRoomHeight} />
|
||||||
|
<ColorPolygon fill='#4a5c5e' pts={[pts.TopRectLB, pts.RoomRBFar, mirror(pts.RoomRBFar), pts.TopRectRB]} />
|
||||||
|
{
|
||||||
|
pts.SepsLTLBRBRT.map((s, index) => (
|
||||||
|
<ColorPolygon key={'a' + index} fill='#334648' pts={s} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
{
|
||||||
|
windows.w.map((o, index) => <Window1 rect={o} key={'w' + index} />)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
windows.h.map((o, index) => <WindowSep rect={o} key={'h' + index} />)
|
||||||
|
}
|
||||||
|
</Layer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Topper1);
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Layer, Rect } from 'react-konva';
|
||||||
|
import ColorPolygon from './ColorPolygon';
|
||||||
|
import { CanvasH, CanvasW, ViewCenter, WaterTop } from './consts';
|
||||||
|
import { ControlPts, interpolate, intersection, mirror } from './coordinates';
|
||||||
|
|
||||||
|
|
||||||
|
const Topper2: React.FC<{
|
||||||
|
pts: ControlPts;
|
||||||
|
waterRatio: number;
|
||||||
|
}> = ({ pts, waterRatio }) => {
|
||||||
|
|
||||||
|
const waterP1 = interpolate(pts.B1, { x: pts.L1.x, y: WaterTop }, waterRatio);
|
||||||
|
const waterP2 = intersection(waterP1, ViewCenter, { x: 0, y: undefined });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layer>
|
||||||
|
{
|
||||||
|
pts.SepsFront.map((s, index) => (
|
||||||
|
<Rect key={index} fill='#738b8b' x={s.x} y={s.y} width={s.w} height={s.h} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<ColorPolygon fill='#539cb9' pts={[waterP1, waterP2, mirror(waterP2), mirror(waterP1)]} opacity={0.8} />
|
||||||
|
<ColorPolygon fill='#2d99ba' pts={[waterP2, mirror(waterP2), [CanvasW, CanvasH], [0, CanvasH]]} opacity={0.8} />
|
||||||
|
</Layer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(Topper2);
|
||||||
|
|
@ -0,0 +1,104 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { Line, Rect } from 'react-konva';
|
||||||
|
import ColorPolygon from './ColorPolygon';
|
||||||
|
|
||||||
|
const S1 = 4;
|
||||||
|
|
||||||
|
export const Window1: React.FC<{
|
||||||
|
rect: number[];
|
||||||
|
}> = ({ rect }) => {
|
||||||
|
const [x1, y1, x2, y2] = rect;
|
||||||
|
|
||||||
|
const w1 = (x2 - x1 - S1) / 2;
|
||||||
|
const w2 = (x2 - x1 - S1 * 2) / 3;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Rect fill='#b1c3cf' x={x1} y={y1} width={w1} height={16} />
|
||||||
|
<Rect fill='#b1c3cf' x={x1 + w1 + S1} y={y1} width={w1} height={16} />
|
||||||
|
|
||||||
|
<Rect fill='#b1c3cf' x={x1} y={y1 + 16 + S1} width={w2} height={y2 - y1 - 16 - S1} />
|
||||||
|
<Rect fill='#b1c3cf' x={x1 + w2 + S1} y={y1 + 16 + S1} width={w2} height={y2 - y1 - 16 - S1} />
|
||||||
|
<Rect fill='#b1c3cf' x={x1 + (w2 + S1) * 2} y={y1 + 16 + S1} width={w2} height={y2 - y1 - 16 - S1} />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const WindowSep: React.FC<{
|
||||||
|
rect: number[];
|
||||||
|
}> = ({ rect }) => {
|
||||||
|
const [x1, y1, x2, y2] = rect;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Rect fill='#b1c3cf' x={x1} y={y1 - 8} width={x2 - x1} height={y2 - y1 + 8} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const RoomWindows: React.FC<{
|
||||||
|
rect: number[];
|
||||||
|
}> = ({ rect }) => {
|
||||||
|
const [x1, y1, x2, y2] = rect;
|
||||||
|
|
||||||
|
const u = (x2 - x1) / 10;
|
||||||
|
const v = (y2 - y1) / 6;
|
||||||
|
|
||||||
|
const c1 = x1 - 10 + 1;
|
||||||
|
const c2 = x1 - 10 + 7 * u;
|
||||||
|
const dc = (c2 - c1) / 10;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u} y={y1 + v} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u, y1 + v, x1 + 2 * u, y1 + v]} />
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 2 + 2} y={y1 + v} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 2 + 2, y1 + v, x1 + 3 * u + 2, y1 + v]} />
|
||||||
|
|
||||||
|
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 5} y={y1 + v} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 5, y1 + v, x1 + 6 * u, y1 + v]} />
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 6 + 2} y={y1 + v} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 6 + 2, y1 + v, x1 + 7 * u + 2, y1 + v]} />
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u} y={y1 + v * 4} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u, y1 + v * 4, x1 + 2 * u, y1 + v * 4]} />
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 2 + 2} y={y1 + v * 4} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 2 + 2, y1 + v * 4, x1 + 3 * u + 2, y1 + v * 4]} />
|
||||||
|
|
||||||
|
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 5} y={y1 + v * 4} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 5, y1 + v * 4, x1 + 6 * u, y1 + v * 4]} />
|
||||||
|
<Rect fill='#c1d3d5' x={x1 + u * 6 + 2} y={y1 + v * 4} width={u} height={v} />
|
||||||
|
<Line stroke='#fff' points={[x1 + u * 6 + 2, y1 + v * 4, x1 + 7 * u + 2, y1 + v * 4]} />
|
||||||
|
|
||||||
|
<Rect fill='#8fa7a7' x={x1 - 10} y={y1 + 3 * v} width={7 * u} height={v * 0.6} />
|
||||||
|
<ColorPolygon
|
||||||
|
fill='#4a5c5e'
|
||||||
|
pts={[
|
||||||
|
[x1 - 10, y1 + 3.6 * v],
|
||||||
|
[x1 - 10 + 4, y1 + 3.6 * v + 2],
|
||||||
|
[x1 - 10 + 7 * u + 3, y1 + 3.6 * v + 2],
|
||||||
|
[x1 - 10 + 7 * u + 3, y1 + 3 * v + 2],
|
||||||
|
[x1 - 10 + 7 * u, y1 + 3 * v],
|
||||||
|
[x1 - 10 + 7 * u, y1 + 3.6 * v + 2],
|
||||||
|
[x1 - 10 + 7 * u, y1 + 3.6 * v],
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
<Line stroke='#8fa7a7' lineJoin='round' points={[
|
||||||
|
x1, y1 + 2.5 * v + 2,
|
||||||
|
x1 - 10 + 4, y1 + 2.5 * v + 2,
|
||||||
|
x1 - 10, y1 + 2.5 * v, x1 - 10 + 7 * u, y1 + 2.5 * v,
|
||||||
|
x1 - 10 + 7 * u + 3, y1 + 2.5 * v + 2,
|
||||||
|
]} />
|
||||||
|
<Line stroke='#8fa7a7' points={[x1 - 10 + 4, y1 + 2.5 * v + 2, x1 - 10 + 4, y1 + 3 * v]} />
|
||||||
|
{
|
||||||
|
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => (
|
||||||
|
<Line key={i} stroke='#8fa7a7' points={[c1 + dc * i, y1 + 2.5 * v, c1 + dc * i, y1 + 3 * v]} />
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
</>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { Circle, Layer, Line, Rect } from 'react-konva';
|
||||||
|
import ColorPolygon from './ColorPolygon';
|
||||||
|
import { ViewCenter, WaterTop } from './consts';
|
||||||
|
import { ControlPts, interpolate, intersection } from './coordinates';
|
||||||
|
import ZmDec from './ZmDec';
|
||||||
|
import { useLinearAnim } from './useLinearAnim';
|
||||||
|
|
||||||
|
const ZmColumn: React.FC<{
|
||||||
|
kdMax: number;
|
||||||
|
gtophgt?: number;
|
||||||
|
idx: number;
|
||||||
|
pts: ControlPts;
|
||||||
|
waterRatio: number;
|
||||||
|
selected: boolean;
|
||||||
|
list:any;
|
||||||
|
}> = ({ kdMax, gtophgt, idx, pts, waterRatio, selected,list }) => {
|
||||||
|
const renKd = gtophgt; //useLinearAnim(gtophgt);
|
||||||
|
|
||||||
|
const a = pts.ZmArea[idx];
|
||||||
|
if (!a || typeof renKd !== 'number') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const hh1 = (a.lb1.y - a.lt1.y) * 0.5;
|
||||||
|
const hh2 = (a.lb2.y - a.lt2.y) * 0.5;
|
||||||
|
|
||||||
|
const ratio = renKd / kdMax;
|
||||||
|
const e1 = hh1 * ratio * 0.8;
|
||||||
|
const e2 = hh2 * ratio * 0.8;
|
||||||
|
|
||||||
|
const lineLineLeft = { x: (a.lt1.x + a.lt2.x) * 0.5, y: (a.lt1.y + a.lt2.y) * 0.5 };
|
||||||
|
const lineLineRight = { x: (a.rt1.x + a.rt2.x) * 0.5, y: (a.rt1.y + a.rt2.y) * 0.5 };
|
||||||
|
const line1 = interpolate(lineLineLeft, lineLineRight, 0.25);
|
||||||
|
const line2 = interpolate(lineLineLeft, lineLineRight, 0.75);
|
||||||
|
|
||||||
|
const ty1 = a.lt1.y + hh1 - e1;
|
||||||
|
const ty2 = a.lt2.y + hh2 - e2;
|
||||||
|
const joiny = (ty1 + ty2) * 0.5;
|
||||||
|
|
||||||
|
const waterP1 = interpolate(a.lb0, { x: a.lb0.x, y: WaterTop }, waterRatio);
|
||||||
|
const waterP1R = { x: a.rb0.x, y: waterP1.y };
|
||||||
|
const waterP2 = intersection(ViewCenter, waterP1, { x: a.lb1.x, y: undefined });
|
||||||
|
const waterP2R = { x: a.rb1.x, y: waterP2.y };
|
||||||
|
const waterP3 = intersection(ViewCenter, waterP1, { x: a.lb3.x, y: undefined });
|
||||||
|
waterP3.y -= 26;
|
||||||
|
const waterP3R = { x: a.rb3.x, y: waterP3.y };
|
||||||
|
if (waterP3.x < waterP2.x) {
|
||||||
|
waterP3.x = waterP2.x;
|
||||||
|
}
|
||||||
|
if (waterP3R.x > waterP2R.x) {
|
||||||
|
waterP3R.x = waterP2R.x
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
const b1 = { x: a.lb0.x, y: a.lb0.y - 32 };
|
||||||
|
const b6 = { x: a.rb0.x, y: a.rb0.y - 32 };
|
||||||
|
const b2 = interpolate(b1, b6, 0.4);
|
||||||
|
const b5 = interpolate(b1, b6, 0.6);
|
||||||
|
const b3 = { x: b2.x, y: b2.y + 12 };
|
||||||
|
const b4 = { x: b5.x, y: b5.y + 12 };
|
||||||
|
|
||||||
|
const b1_1 = intersection(b1, ViewCenter, { x: a.lb1.x, y: undefined });
|
||||||
|
const b1_6 = intersection(b6, ViewCenter, { x: a.rb1.x, y: undefined });
|
||||||
|
const b1_2 = intersection(b2, ViewCenter, { x: undefined, y: b1_1.y });
|
||||||
|
const b1_5 = intersection(b5, ViewCenter, { x: undefined, y: b1_6.y });
|
||||||
|
const b1_3 = intersection(b3, ViewCenter, { x: b1_2.x, y: undefined });
|
||||||
|
const b1_4 = intersection(b4, ViewCenter, { x: b1_5.x, y: undefined });
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
(idx != 0 && idx != list.length - 1) ?
|
||||||
|
waterP3 && waterP3R ? (
|
||||||
|
<ColorPolygon fill='#539cb9' pts={[waterP2, waterP2R, waterP3R, waterP3]} opacity={0.8} />
|
||||||
|
) : null : null
|
||||||
|
}
|
||||||
|
{/* <ColorPolygon
|
||||||
|
desc="闸门上测"
|
||||||
|
fill='#afb5b5'
|
||||||
|
pts={[
|
||||||
|
[a.lt1.x, ty1],
|
||||||
|
[a.rt1.x, ty1],
|
||||||
|
[a.rt2.x, ty2],
|
||||||
|
[a.lt2.x, ty2],
|
||||||
|
]}
|
||||||
|
/> */}
|
||||||
|
{idx != 0 ? <Line stroke='#222' strokeWidth={8} lineCap="round" points={[line2.x, line2.y, line2.x, joiny]} /> : null}
|
||||||
|
{idx!= list.length - 1 ? <Line stroke='#222' strokeWidth={8} lineCap="round" points={[line1.x, line1.y, line1.x, joiny]} /> : null}
|
||||||
|
{/* <Line stroke='#222' strokeWidth={8} lineCap="round" points={[line1.x, line1.y, line1.x, joiny]} />
|
||||||
|
<Line stroke='#222' strokeWidth={8} lineCap="round" points={[line2.x, line2.y, line2.x, joiny]} /> */}
|
||||||
|
|
||||||
|
{idx != list.length - 1 ? <Circle fill='#afb5b5' x={line1.x} y={joiny} radius={9} /> : ''}
|
||||||
|
{idx!= 0 ? <Circle fill='#afb5b5' x={line2.x} y={joiny} radius={9} /> :'' }
|
||||||
|
<Line stroke='#222' strokeWidth={12} points={[line1.x, joiny - 8, line1.x, joiny - 10]} />
|
||||||
|
<Line stroke='#222' strokeWidth={12} points={[line2.x, joiny - 8, line2.x, joiny - 10]} />
|
||||||
|
|
||||||
|
<Rect
|
||||||
|
desc='闸门正面'
|
||||||
|
fill={selected ? '#95927a' : '#5f6969'}
|
||||||
|
stroke={selected ? 'orange' : "#222"}
|
||||||
|
strokeWidth={1} x={a.lt1.x} y={ty1} width={a.rt1.x - a.lt1.x} height={hh1} />
|
||||||
|
|
||||||
|
<ZmDec tl={{ x: a.lt1.x, y: ty1 }} rb={{ x: a.rt1.x, y: ty1 + hh1 }} />
|
||||||
|
|
||||||
|
<ColorPolygon desc="出水口" fill='#8d9d9b' pts={[b1_1, b1_2, b2, b1]} />
|
||||||
|
<ColorPolygon desc="出水口" fill='#8d9d9b' pts={[b1_5, b1_6, b6, b5]} />
|
||||||
|
<ColorPolygon desc="出水口" fill='#8d9d9b' pts={[b1_2, b1_3, b3, b2]} />
|
||||||
|
<ColorPolygon desc="出水口" fill='#8d9d9b' pts={[b1_3, b1_4, b4, b3]} />
|
||||||
|
<ColorPolygon desc="出水口" fill='#8d9d9b' pts={[b1_4, b1_5, b5, b4]} />
|
||||||
|
<ColorPolygon desc="出水口" fill='#728381' pts={[b1, b2, b3, b4, b5, b6, a.rb0, a.lb0]} />
|
||||||
|
|
||||||
|
{
|
||||||
|
waterP1.y < b1.y ? (
|
||||||
|
<ColorPolygon fill='#539cb9' pts={[waterP1, waterP1R, waterP2R, waterP2]} opacity={0.8} />
|
||||||
|
) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default React.memo(ZmColumn)
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import { Layer } from 'react-konva';
|
||||||
|
import { ControlPts } from './coordinates';
|
||||||
|
import ZmColumn from './ZmColumn';
|
||||||
|
// import { StationItem, GateRuntime } from '../../../models/_/defs';
|
||||||
|
import { apertureMeter } from '../../../utils/utils';
|
||||||
|
|
||||||
|
const ZmColumns: React.FC<{
|
||||||
|
zmobj: any;
|
||||||
|
runtime: any;
|
||||||
|
pts: ControlPts;
|
||||||
|
selectedId?: string;
|
||||||
|
waterRatio: number;
|
||||||
|
}> = ({ zmobj, runtime, pts, waterRatio }) => {
|
||||||
|
const eqpnoList = useMemo(() => new Array(runtime.length).fill(0).map((o, index) => index), [runtime]);
|
||||||
|
return (
|
||||||
|
<Layer>
|
||||||
|
{
|
||||||
|
eqpnoList.map((o, index,arr) => (
|
||||||
|
<ZmColumn
|
||||||
|
key={o}
|
||||||
|
gtophgt={apertureMeter(runtime[o]?.realAperture)}
|
||||||
|
kdMax={2}
|
||||||
|
pts={pts}
|
||||||
|
idx={index}
|
||||||
|
list={arr}
|
||||||
|
waterRatio={waterRatio}
|
||||||
|
selected={false}
|
||||||
|
/>)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Layer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ZmColumns
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { Line, Rect } from 'react-konva';
|
||||||
|
import { Horizontal, ViewCenter } from './consts';
|
||||||
|
import { XY } from './coordinates'
|
||||||
|
|
||||||
|
const INTERVALS = [0, 1, 2];
|
||||||
|
|
||||||
|
const ZmDec: React.FC<{
|
||||||
|
tl: XY;
|
||||||
|
rb: XY;
|
||||||
|
}> = ({ tl, rb }) => {
|
||||||
|
|
||||||
|
const ux = (rb.x - tl.x) / 12;
|
||||||
|
const uy = (rb.y - tl.y) / 12;
|
||||||
|
|
||||||
|
const ox = tl.x + 3 * ux;
|
||||||
|
const oy = tl.y + 3 * uy;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{
|
||||||
|
INTERVALS.map(y => (
|
||||||
|
<React.Fragment key={y}>
|
||||||
|
{
|
||||||
|
INTERVALS.map(x => {
|
||||||
|
const cx = ox + x * 3 * ux;
|
||||||
|
const cy = oy + y * 3 * uy;
|
||||||
|
const l = cx - ux;
|
||||||
|
const r = cx + ux;
|
||||||
|
const t = cy - uy;
|
||||||
|
const b = cy + uy;
|
||||||
|
return (
|
||||||
|
<React.Fragment key={x}>
|
||||||
|
<Rect fill="323737" x={l} y={t} width={2 * ux} height={2 * uy} />
|
||||||
|
{
|
||||||
|
cx < ViewCenter.x ? (
|
||||||
|
<Line points={[l, t, l, b]} stroke="#afb5b5" strokeWidth={1} />
|
||||||
|
) : (
|
||||||
|
<Line points={[r, t, r, b]} stroke="#afb5b5" strokeWidth={1} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
cy < Horizontal ? (
|
||||||
|
<Line points={[l, t, r, t]} stroke="#afb5b5" strokeWidth={1} />
|
||||||
|
) : (
|
||||||
|
<Line points={[l, b, r, b]} stroke="#afb5b5" strokeWidth={1} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ZmDec
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
export const CanvasW = 1080;
|
||||||
|
export const CanvasH = 640;
|
||||||
|
|
||||||
|
export const Horizontal = CanvasH * 1.4 / 3;
|
||||||
|
export const ViewCenter = { x: CanvasW * 0.5, y: Horizontal };
|
||||||
|
|
||||||
|
export const GroundBase = CanvasH * 1.8 / 3;
|
||||||
|
export const BottomBase = CanvasH * 2.5 / 3;
|
||||||
|
export const RoofTop = CanvasH * 0.8 / 3;
|
||||||
|
export const RoofTopFar = RoofTop + 32;
|
||||||
|
export const FarBuildingTop = RoofTop - 16;
|
||||||
|
|
||||||
|
export const SideRoomSize = CanvasH * 0.7 / 3;
|
||||||
|
export const TopRoomHeight = SideRoomSize - 24;
|
||||||
|
export const PillarRatio = 0.2;
|
||||||
|
export const WaterTop = GroundBase;
|
||||||
|
|
@ -0,0 +1,180 @@
|
||||||
|
import { BottomBase, CanvasW, GroundBase, PillarRatio, RoofTop, RoofTopFar, SideRoomSize, ViewCenter } from "./consts";
|
||||||
|
|
||||||
|
export type XY = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type XYWH = {
|
||||||
|
x: number;
|
||||||
|
y: number;
|
||||||
|
w: number;
|
||||||
|
h: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function intersection(pt1: XY, pt2: XY, result: { x?: number, y?: number }): XY {
|
||||||
|
const invalid: XY = { x: result.x || 0, y: result.y || 0 };
|
||||||
|
if (typeof result.x === typeof result.y) {
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
const x1 = pt1.x, y1 = pt1.y, x2 = pt2.x, y2 = pt2.y;
|
||||||
|
|
||||||
|
if (typeof result.x === 'number') {
|
||||||
|
const x3 = result.x;
|
||||||
|
|
||||||
|
if (x2 === x1) {
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.y = (y2 - y1) * (x3 - x1) / (x2 - x1) + y1;
|
||||||
|
} else {
|
||||||
|
const y3 = result.y!;
|
||||||
|
|
||||||
|
if (y2 === y1) {
|
||||||
|
return invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
result.x = (x2 - x1) * (y3 - y1) / (y2 - y1) + x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function interpolate(pt1: XY, pt2: XY, ratio: number): XY {
|
||||||
|
return {
|
||||||
|
x: pt1.x + (pt2.x - pt1.x) * ratio,
|
||||||
|
y: pt1.y + (pt2.y - pt1.y) * ratio,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function mirror(pt: XY): XY {
|
||||||
|
return {
|
||||||
|
x: CanvasW - pt.x,
|
||||||
|
y: pt.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ControlPts = {
|
||||||
|
C1: XY;
|
||||||
|
L1: XY;
|
||||||
|
B1: XY;
|
||||||
|
C2: XY;
|
||||||
|
L2: XY;
|
||||||
|
B2: XY;
|
||||||
|
A1: XY;
|
||||||
|
A2: XY;
|
||||||
|
B3: XY;
|
||||||
|
RoomLT: XY;
|
||||||
|
RoomRT: XY;
|
||||||
|
RoomRB: XY;
|
||||||
|
RoomLB: XY;
|
||||||
|
RoomRTFar: XY;
|
||||||
|
RoomRBFar: XY;
|
||||||
|
RoomLBFar: XY;
|
||||||
|
TopRectLB: XY;
|
||||||
|
TopRectRB: XY;
|
||||||
|
SepsLTLBRBRT: XY[][];
|
||||||
|
SepsFront: XYWH[];
|
||||||
|
ZmArea: {
|
||||||
|
lt0: XY; lt1: XY; lt2: XY; lt3: XY;
|
||||||
|
lb0: XY; lb1: XY; lb2: XY; lb3: XY;
|
||||||
|
rt0: XY; rt1: XY; rt2: XY; rt3: XY;
|
||||||
|
rb0: XY; rb1: XY; rb2: XY; rb3: XY;
|
||||||
|
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function contextCoordinates(unitWidth: number, hole: number): ControlPts {
|
||||||
|
const C1 = { x: unitWidth * 0.6, y: GroundBase };
|
||||||
|
const L1 = { x: unitWidth, y: GroundBase };
|
||||||
|
const B1 = { x: unitWidth, y: BottomBase }
|
||||||
|
|
||||||
|
const C2 = intersection(ViewCenter, C1, { x: 0, y: undefined });
|
||||||
|
const L2 = intersection(ViewCenter, L1, { x: 0, y: undefined });
|
||||||
|
const B2 = intersection(ViewCenter, B1, { x: 0, y: undefined });
|
||||||
|
|
||||||
|
const A1 = { x: L1.x, y: RoofTop };
|
||||||
|
const A2 = intersection(ViewCenter, A1, { x: undefined, y: RoofTopFar });
|
||||||
|
|
||||||
|
const B3 = intersection(ViewCenter, B2, { x: A2.x, y: undefined })
|
||||||
|
|
||||||
|
const RoomLT = { x: (C1.x + L1.x) * 0.5 - SideRoomSize * 0.5, y: RoofTop - SideRoomSize }
|
||||||
|
const RoomRT = { x: (C1.x + L1.x) * 0.5 + SideRoomSize * 0.5, y: RoofTop - SideRoomSize }
|
||||||
|
const RoomRB = { x: (C1.x + L1.x) * 0.5 + SideRoomSize * 0.5, y: RoofTop }
|
||||||
|
const RoomLB = { x: (C1.x + L1.x) * 0.5 - SideRoomSize * 0.5, y: RoofTop }
|
||||||
|
const RoomRBFar = intersection(ViewCenter, RoomRB, { x: undefined, y: RoofTopFar });
|
||||||
|
const RoomRTFar = intersection(ViewCenter, RoomRT, { x: RoomRBFar.x, y: undefined });
|
||||||
|
const RoomLBFar = { x: RoomRBFar.x! - SideRoomSize, y: RoomRBFar.y };
|
||||||
|
|
||||||
|
|
||||||
|
const TopRectLB = interpolate(RoomRB, RoomRBFar, 0.05);
|
||||||
|
const TopRectRB = mirror(TopRectLB);
|
||||||
|
|
||||||
|
const TopHoleLT = intersection(A1, ViewCenter, { x: undefined, y: TopRectLB.y });
|
||||||
|
const TopHoleRT = mirror(TopHoleLT);
|
||||||
|
const HolesWidth = TopHoleRT.x - TopHoleLT.x;
|
||||||
|
const PillarWidth = (HolesWidth / hole) * PillarRatio;
|
||||||
|
const HoleWidth = (HolesWidth - PillarWidth * (hole - 1)) / hole;
|
||||||
|
|
||||||
|
const SepsLTLBRBRT: XY[][] = [];
|
||||||
|
const SepsFront: XYWH[] = [];
|
||||||
|
const ZmArea = [];
|
||||||
|
for (let i = 0; i < hole; i++) {
|
||||||
|
const TopBase = TopHoleLT.y;
|
||||||
|
// 隔断
|
||||||
|
if (i > 0) {
|
||||||
|
const frontRight = TopHoleLT.x + (PillarWidth + HoleWidth) * i;
|
||||||
|
const frontLeft = frontRight - PillarWidth;
|
||||||
|
SepsFront.push({ x: frontLeft, y: TopBase, w: PillarWidth, h: BottomBase - TopBase });
|
||||||
|
if (i < hole / 2) {
|
||||||
|
// 右侧面
|
||||||
|
const p1 = { x: frontRight, y: TopBase };
|
||||||
|
const p2 = { x: frontRight, y: BottomBase };
|
||||||
|
const p4 = intersection(p1, ViewCenter, { x: undefined, y: RoofTopFar });
|
||||||
|
const p3 = intersection(p2, ViewCenter, { x: p4.x, y: undefined });
|
||||||
|
SepsLTLBRBRT.push([p1, p2, p3, p4]);
|
||||||
|
} else if (i > hole / 2) {
|
||||||
|
// 左侧面
|
||||||
|
const p1 = { x: frontLeft, y: TopBase };
|
||||||
|
const p2 = { x: frontLeft, y: BottomBase };
|
||||||
|
const p4 = intersection(p1, ViewCenter, { x: undefined, y: RoofTopFar });
|
||||||
|
const p3 = intersection(p2, ViewCenter, { x: p4.x, y: undefined });
|
||||||
|
SepsLTLBRBRT.push([p1, p2, p3, p4]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 闸门面
|
||||||
|
{
|
||||||
|
const ZmTopBaseFront = TopBase + 6;
|
||||||
|
const ZmTopBaseBack = ZmTopBaseFront + 10;
|
||||||
|
const lt0 = { x: TopHoleLT.x + (PillarWidth + HoleWidth) * i, y: TopBase };
|
||||||
|
const lb0 = { x: lt0.x, y: BottomBase };
|
||||||
|
const rb0 = { x: lt0.x + HoleWidth, y: BottomBase };
|
||||||
|
const lt1 = intersection(ViewCenter, lt0, { x: undefined, y: ZmTopBaseFront });
|
||||||
|
const lt2 = intersection(ViewCenter, lt0, { x: undefined, y: ZmTopBaseBack });
|
||||||
|
const lt3 = intersection(ViewCenter, lt0, { x: undefined, y: RoofTopFar });
|
||||||
|
const lb1 = intersection(ViewCenter, lb0, { x: lt1.x, y: undefined });
|
||||||
|
const lb2 = intersection(ViewCenter, lb0, { x: lt2.x, y: undefined });
|
||||||
|
const lb3 = intersection(ViewCenter, lb0, { x: lt3.x, y: undefined });
|
||||||
|
const rb1 = intersection(ViewCenter, rb0, { x: undefined, y: lb1.y });
|
||||||
|
const rb2 = intersection(ViewCenter, rb0, { x: undefined, y: lb2.y });
|
||||||
|
const rb3 = intersection(ViewCenter, rb0, { x: undefined, y: lb3.y });
|
||||||
|
const rt0 = { x: rb0.x, y: lt0.y };
|
||||||
|
const rt1 = { x: rb1.x, y: lt1.y };
|
||||||
|
const rt2 = { x: rb2.x, y: lt2.y };
|
||||||
|
const rt3 = { x: rb3.x, y: lt3.y };
|
||||||
|
ZmArea.push({ lt0, lb0, rb0, rt0, lt1, rt1, lb1, rb1, lt2, lb2, rt2, rb2, lt3, lb3, rt3, rb3 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
C1, L1, B1, C2, L2, B2, A1, A2, B3,
|
||||||
|
RoomLT, RoomRT, RoomRB, RoomLB, RoomRTFar, RoomRBFar, RoomLBFar,
|
||||||
|
TopRectLB, TopRectRB,
|
||||||
|
SepsLTLBRBRT, SepsFront, ZmArea,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,225 @@
|
||||||
|
import React, { useEffect, useMemo, useState } from 'react'
|
||||||
|
import { Modal, Tabs, Descriptions, Image } from 'antd';
|
||||||
|
import { Stage } from 'react-konva';
|
||||||
|
import Sider from './Sider';
|
||||||
|
import Topper1 from './Topper1';
|
||||||
|
import Topper2 from './Topper2';
|
||||||
|
import ZmColumns from './ZmColumns';
|
||||||
|
import { contextCoordinates } from './coordinates';
|
||||||
|
import { renAperture } from '../../../utils/utils';
|
||||||
|
import HFivePlayer from '../../../components/video1Plary'
|
||||||
|
import './index.less';
|
||||||
|
import { httpget, httpget2, httppost2 } from '../../../utils/request';
|
||||||
|
import apiurl from '../../../service/apiurl';
|
||||||
|
const url = "http://223.75.53.141:9102/test.by-lyf.tmp"
|
||||||
|
const CanvasW = 1080
|
||||||
|
const CanvasH = 640
|
||||||
|
// const waterRatio = 0
|
||||||
|
const zmobj ={
|
||||||
|
"hpCode": "HP0074208040002120",
|
||||||
|
"stcd": "4265630075",
|
||||||
|
"ctrlType": "PLC",
|
||||||
|
"ctrlProtocol": "PLC",
|
||||||
|
"uprzStcd": null,
|
||||||
|
"dwrzStcd": null,
|
||||||
|
"flowStcd": null,
|
||||||
|
"gaType": "waga",
|
||||||
|
"ctrlPass": null,
|
||||||
|
"maxHgt": 1.9,
|
||||||
|
"minHgt": 0,
|
||||||
|
"name": "五岭包节制闸",
|
||||||
|
"ghtX": null,
|
||||||
|
"ghtY": null,
|
||||||
|
"irrCode": "D00000020",
|
||||||
|
"irrName": "三干渠",
|
||||||
|
"engCode": "ENG100076",
|
||||||
|
"engName": "三干渠管理处",
|
||||||
|
"orgCode": "A07",
|
||||||
|
"gaorNum": 3,
|
||||||
|
"wagaType": "节制闸",
|
||||||
|
"plcType": null,
|
||||||
|
"bim": 0,
|
||||||
|
"vip": 0,
|
||||||
|
"miu": null,
|
||||||
|
"lgtd": 112.242945,
|
||||||
|
"lttd": 30.848166,
|
||||||
|
"runtime": [
|
||||||
|
null,
|
||||||
|
{
|
||||||
|
"stcd": "4265630075",
|
||||||
|
"gateNumber": 1,
|
||||||
|
"realAperture": 376,
|
||||||
|
"setAperture": 0,
|
||||||
|
"sensorLever": null,
|
||||||
|
"altitudeLever": null,
|
||||||
|
"remoteSignal": 0,
|
||||||
|
"powerSignal": 0,
|
||||||
|
"openingSignal": 0,
|
||||||
|
"closeingSignal": 0,
|
||||||
|
"errorSignal": 0,
|
||||||
|
"openedSignal": 0,
|
||||||
|
"closedSignal": 0,
|
||||||
|
"tm": "2024-09-25 20:03:26",
|
||||||
|
"_online": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stcd": "4265630075",
|
||||||
|
"gateNumber": 2,
|
||||||
|
"realAperture": 388,
|
||||||
|
"setAperture": 0,
|
||||||
|
"sensorLever": null,
|
||||||
|
"altitudeLever": null,
|
||||||
|
"remoteSignal": 0,
|
||||||
|
"powerSignal": 0,
|
||||||
|
"openingSignal": 0,
|
||||||
|
"closeingSignal": 0,
|
||||||
|
"errorSignal": 0,
|
||||||
|
"openedSignal": 0,
|
||||||
|
"closedSignal": 0,
|
||||||
|
"tm": "2024-09-25 20:03:26",
|
||||||
|
"_online": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"stcd": "4265630075",
|
||||||
|
"gateNumber": 3,
|
||||||
|
"realAperture": 394,
|
||||||
|
"setAperture": 0,
|
||||||
|
"sensorLever": null,
|
||||||
|
"altitudeLever": null,
|
||||||
|
"remoteSignal": 0,
|
||||||
|
"powerSignal": null,
|
||||||
|
"openingSignal": 0,
|
||||||
|
"closeingSignal": 0,
|
||||||
|
"errorSignal": 0,
|
||||||
|
"openedSignal": 0,
|
||||||
|
"closedSignal": 0,
|
||||||
|
"tm": "2024-09-25 20:03:26",
|
||||||
|
"_online": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"real": {
|
||||||
|
"stcd": "4265630075",
|
||||||
|
"stationName": "五岭包节制闸",
|
||||||
|
"z1": null,
|
||||||
|
"zz1": null,
|
||||||
|
"z1tm": null,
|
||||||
|
"z2": null,
|
||||||
|
"zz2": null,
|
||||||
|
"z2tm": null,
|
||||||
|
"hq": null,
|
||||||
|
"hqtm": null,
|
||||||
|
"demtl": null
|
||||||
|
},
|
||||||
|
"cctvs": [],
|
||||||
|
"_idx": 88,
|
||||||
|
"_fav": false,
|
||||||
|
"_sort": 10086
|
||||||
|
}
|
||||||
|
|
||||||
|
const Page = () => {
|
||||||
|
const [waterRatio,setWaterRatio] = useState(0)
|
||||||
|
const [data,setData] = useState({})
|
||||||
|
const [damList, setDamList ] = useState([])
|
||||||
|
const [list, setList ] = useState([])
|
||||||
|
|
||||||
|
const hole = 10;//zmobj.gaorNum;
|
||||||
|
const xunit = CanvasW / (2 + hole);
|
||||||
|
const pts = contextCoordinates(xunit, hole);
|
||||||
|
const eqpnoList = useMemo(() => damList ? new Array(damList.length).fill(0).map((o, index) => index) : [], [damList]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
getList()
|
||||||
|
},[])
|
||||||
|
|
||||||
|
const getList = async()=>{
|
||||||
|
const {code, data} = await httppost2(apiurl.zmjk.getList)
|
||||||
|
if(code!==200){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const obj = data[0]||{}
|
||||||
|
getInformation(obj.gateCode)
|
||||||
|
getDamData(obj.stcd)
|
||||||
|
setData(obj)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const getDamData = async(stcd)=>{
|
||||||
|
const {code, data} = await httpget2(apiurl.zmjk.getDamData,{stcd})
|
||||||
|
if(code!==200){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const list = []
|
||||||
|
data.map((item)=>{
|
||||||
|
list.push({
|
||||||
|
...item,
|
||||||
|
realAperture:item.realAperture + 200
|
||||||
|
})
|
||||||
|
})
|
||||||
|
setDamList([...list,...list, ...list,list[0]])
|
||||||
|
}
|
||||||
|
|
||||||
|
const getInformation = async(gateCode)=>{
|
||||||
|
const {code, data} = await httpget2(apiurl.zmjk.getInformation,{gateCode})
|
||||||
|
if(code!==200){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.map((item)=>{
|
||||||
|
if(item.type===2){
|
||||||
|
setWaterRatio(item.value/5||0)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setList(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='sg_zmjk' style={{paddingRight:"0",paddingBottom:"0"}}>
|
||||||
|
<div style={{width:"100%"}}>
|
||||||
|
<div className="ant-card-body">
|
||||||
|
<dvi className="sg_zmjk_left" >
|
||||||
|
<Stage width={1080} height={640}>
|
||||||
|
<Sider pts={pts} side="left" />
|
||||||
|
<Sider pts={pts} side="right" />
|
||||||
|
<Topper1 pts={pts} type={hole} />
|
||||||
|
<ZmColumns runtime={damList} zmobj={zmobj} pts={pts} waterRatio={waterRatio} />
|
||||||
|
<Topper2 pts={pts} waterRatio={waterRatio} />
|
||||||
|
</Stage>
|
||||||
|
<div style={{ position: 'absolute', left: 0, top: 20, width: '100%', height: 100, display: 'flex', alignContent: 'center' }}>
|
||||||
|
<div key="sider1" style={{ flexGrow: 1, width: 100 }}></div>
|
||||||
|
{
|
||||||
|
eqpnoList.map(o => (
|
||||||
|
<div key={o}
|
||||||
|
onClick={() => {}}
|
||||||
|
className='o' style={{ flexGrow: 1, width: 100, display: 'flex', justifyContent: 'center', cursor: 'pointer' }}>
|
||||||
|
<div style={{ width: 80, height: 40, backgroundColor: '#43c4e7', borderRadius: 12, color: '#fff', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: 28 }}>#{o+1}</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<div key="sider2" style={{ flexGrow: 1, width: 100 }}></div>
|
||||||
|
</div>
|
||||||
|
<div style={{ position: 'absolute', left: 0, bottom: 20, width: '100%', height: 100, display: 'flex', alignContent: 'center' }}>
|
||||||
|
<div key="sider1" style={{ flexGrow: 1, width: 100 }}></div>
|
||||||
|
{
|
||||||
|
eqpnoList.map(o => (
|
||||||
|
<div key={o} className='o' style={{ flexGrow: 1, width: 100, display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<div
|
||||||
|
onClick={() => {}}
|
||||||
|
style={{ width: 80, height: 32, border: '1px solid #444', backgroundColor: '#fff', borderRadius: 4, color: '#888', display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: 18, cursor: 'pointer' }}
|
||||||
|
>
|
||||||
|
{renAperture(damList[o]?.realAperture)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
<div key="sider2" style={{ flexGrow: 1, width: 100 }}></div>
|
||||||
|
</div>
|
||||||
|
</dvi>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
.sg_zmjk{
|
||||||
|
.ant-card-body{
|
||||||
|
display: flex;
|
||||||
|
height: 100%;
|
||||||
|
.sg_zmjk_left{
|
||||||
|
top: 85px;
|
||||||
|
position: relative;
|
||||||
|
width: 1080px;
|
||||||
|
height: 640px;
|
||||||
|
transform: scale(1.3,1.2);
|
||||||
|
|
||||||
|
}
|
||||||
|
.sg_zmjk_right{
|
||||||
|
flex: 1;
|
||||||
|
// width: 40%;
|
||||||
|
height: 100%;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.sg_zmjk_right_video{
|
||||||
|
height: 400px;
|
||||||
|
margin: 30px 20px 30px -30px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
.sg_zmjk_right_video_title{
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
.sg_zmjk_right_video_content{
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
// height: 100%;
|
||||||
|
.sg_zmjk_right_video_content_left{
|
||||||
|
overflow-y: auto;
|
||||||
|
overflow-x: hidden;
|
||||||
|
padding: 10px;
|
||||||
|
width: 130px;
|
||||||
|
height: 363px;
|
||||||
|
border-right: 1px solid #bbb;
|
||||||
|
cursor: pointer;
|
||||||
|
.sg_zmjk_right_video_content_left_item{
|
||||||
|
width: 110px;
|
||||||
|
// height: 30px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
// line-height: 30px;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
.itemChecked{
|
||||||
|
background-color: #1890FF;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sg_zmjk_right_video_content_right{
|
||||||
|
flex: 1;
|
||||||
|
height: 100%;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sg_zmjk_right_information{
|
||||||
|
height: 180px;
|
||||||
|
margin: -10px 20px 30px -30px;
|
||||||
|
border-radius: 5px;
|
||||||
|
border: 1px solid #bbb;
|
||||||
|
.sg_zmjk_right_information_title{
|
||||||
|
height: 35px;
|
||||||
|
line-height: 35px;
|
||||||
|
padding-left: 10px;
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
.sg_zmjk_right_information_content{
|
||||||
|
display: flex;
|
||||||
|
padding: 2px 10px;
|
||||||
|
div{
|
||||||
|
width: 33%;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.sg_zmjk_right_more{
|
||||||
|
margin: -10px 20px 30px -30px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
import { useEffect, useReducer, useRef, useState } from "react";
|
||||||
|
|
||||||
|
|
||||||
|
const DURATION = 900;
|
||||||
|
const CNT = 5;
|
||||||
|
|
||||||
|
const INTERVAL = DURATION / CNT;
|
||||||
|
|
||||||
|
export function useLinearAnim(val: number | undefined) {
|
||||||
|
|
||||||
|
const ren = useRef(val);
|
||||||
|
|
||||||
|
const [_, refresh] = useReducer(s => s + 1, 0);
|
||||||
|
|
||||||
|
const alive = useRef<boolean>(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
return () => {
|
||||||
|
alive.current = false;
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (typeof val !== 'number') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ren.current == undefined) {
|
||||||
|
ren.current = val;
|
||||||
|
}
|
||||||
|
const len = val - ren.current;
|
||||||
|
|
||||||
|
let handle: any = null;
|
||||||
|
if (len) {
|
||||||
|
const dv = len / CNT;
|
||||||
|
let cnt = CNT;
|
||||||
|
handle = setInterval(() => {
|
||||||
|
if (cnt > 0 && alive.current) {
|
||||||
|
cnt--;
|
||||||
|
ren.current! -= dv;
|
||||||
|
refresh();
|
||||||
|
}
|
||||||
|
}, INTERVAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (handle) {
|
||||||
|
clearInterval(handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [val]);
|
||||||
|
|
||||||
|
return ren.current ?? val;
|
||||||
|
}
|
||||||
|
|
@ -71,7 +71,7 @@ const LoginPage = () => {
|
||||||
message.error((result.description).replace('参数错误',''));
|
message.error((result.description).replace('参数错误',''));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const getInfo=(result1:any,value:any)=>{
|
const getInfo = (result1: any, value: any) => {
|
||||||
if (result1.code === 200) {
|
if (result1.code === 200) {
|
||||||
if(checked){
|
if(checked){
|
||||||
localStorage.setItem('loginNamePwd',JSON.stringify(value))
|
localStorage.setItem('loginNamePwd',JSON.stringify(value))
|
||||||
|
|
@ -83,7 +83,7 @@ const LoginPage = () => {
|
||||||
localStorage.setItem('userName', result1.user.nickName);
|
localStorage.setItem('userName', result1.user.nickName);
|
||||||
localStorage.setItem('userId', result1.user.userId);
|
localStorage.setItem('userId', result1.user.userId);
|
||||||
|
|
||||||
navigate('/mgr/home');
|
navigate('/home');
|
||||||
}else{
|
}else{
|
||||||
message.error('获取用户信息失败');
|
message.error('获取用户信息失败');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,124 @@
|
||||||
import React from 'react'
|
import React, { Fragment, useRef, useMemo,useEffect,useState } from 'react';
|
||||||
|
import { Table, Card, Modal, Form, Input, Button, Row,Col, Timeline, message, Tabs,Image } from 'antd';
|
||||||
|
import ToolBar from './toolbar';
|
||||||
|
import apiurl from '../../../service/apiurl';
|
||||||
|
import usePageTable from '../../../components/crud/usePageTable2';
|
||||||
|
import { createCrudService } from '../../../components/crud/_';
|
||||||
|
import { httppost5 } from '../../../utils/request';
|
||||||
|
import { exportFile } from '../../../utils/tools.js';
|
||||||
|
import './index.less'
|
||||||
|
|
||||||
export default function Jcsj() {
|
const RealCard = ({item}) => {
|
||||||
return (
|
return (
|
||||||
<div>index</div>
|
<div className='card-container' key={item.label}>
|
||||||
|
<div className='item-one'>{item.label}</div>
|
||||||
|
<div className='item-two'><span style={{ fontSize: 20, fontWeight: 700 }}>{item.value}</span> (08-15 15:00:00)</div>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
const url = "http://223.75.53.141:9102/test.by-lyf.tmp"
|
||||||
|
const Page = () => {
|
||||||
|
const types = {
|
||||||
|
0: "闸后流量",
|
||||||
|
1: '闸前水位',
|
||||||
|
2:'闸后水位',
|
||||||
|
3:'雨量',
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const nameList = [
|
||||||
|
{
|
||||||
|
label: "闸后流量(m³/s)",
|
||||||
|
value:300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "闸前水位(m)",
|
||||||
|
value:300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "闸后水位(m)",
|
||||||
|
value:300
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "雨量(mm)",
|
||||||
|
value:300
|
||||||
|
}
|
||||||
|
]
|
||||||
|
const [searchVal, setSearchVal] = useState(false)
|
||||||
|
const columns = [
|
||||||
|
{ title: '序号', key: 'inx', dataIndex: 'inx', width: 60, align:"center" },
|
||||||
|
{
|
||||||
|
title: '监测项目', key: 'name', dataIndex: 'name', width: 150,
|
||||||
|
render: (v) => <span>{types[v]}</span>
|
||||||
|
},
|
||||||
|
{ title: '监测值', key: 'adress', dataIndex: 'adress', width: 150},
|
||||||
|
{
|
||||||
|
title: '监测时间', key: 'eventsDate', dataIndex: 'eventsDate', width: 140,
|
||||||
|
},
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
const width = useMemo(() => columns.reduce((total, cur) => total + (cur.width), 0), [columns]);
|
||||||
|
const { tableProps, search, refresh } = usePageTable(createCrudService(apiurl.sbwh.whfabz.page).find_noCode);
|
||||||
|
|
||||||
|
const exportExcel = () => {
|
||||||
|
let params = {
|
||||||
|
...searchVal,
|
||||||
|
}
|
||||||
|
httppost5(apiurl.pxjh.export, params).then(res => {
|
||||||
|
exportFile(`统计报表.xlsx`,res.data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
useEffect(() => {
|
||||||
|
const params = {
|
||||||
|
search: {
|
||||||
|
...searchVal,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
search(params)
|
||||||
|
}, [searchVal])
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='content-root clearFloat xybm' style={{paddingBottom:"0"}}>
|
||||||
|
<div className='lf CrudAdcdTreeTableBox' style={{ width: "100%", overflowY: "auto" }}>
|
||||||
|
<div className='real-data'>
|
||||||
|
<div className='real-title'>
|
||||||
|
<div className='icon_style'></div>
|
||||||
|
<div className='font_style'>实时数据</div>
|
||||||
|
</div>
|
||||||
|
<div className='real-item'>
|
||||||
|
{nameList.map(item => (
|
||||||
|
<RealCard item={item} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='real-data' style={{marginTop:20}}>
|
||||||
|
<div className='real-title'>
|
||||||
|
<div className='icon_style'></div>
|
||||||
|
<div className='font_style'>监测数据</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<Card className='nonebox'>
|
||||||
|
<ToolBar
|
||||||
|
setSearchVal={setSearchVal}
|
||||||
|
exportFile1={exportExcel}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
<div className="ant-card-body" style={{ padding: "20px 0 0 0",display:'flex',columnGap:10 }}>
|
||||||
|
<div style={{ width: 800 }}>
|
||||||
|
<Table columns={columns} rowKey="inx" {...tableProps} scroll={{ x: width , y: "calc( 100vh - 400px )"}}/>
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1 }}>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Page;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
.real-data{
|
||||||
|
.real-title{
|
||||||
|
display: flex;
|
||||||
|
column-gap: 10px;
|
||||||
|
align-items: center;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
padding-bottom: 5px;
|
||||||
|
.icon_style{
|
||||||
|
width: 6px;
|
||||||
|
height: 18px;
|
||||||
|
background-color: #259def;
|
||||||
|
}
|
||||||
|
.font_style{
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.real-item{
|
||||||
|
display: flex;
|
||||||
|
column-gap: 20px;
|
||||||
|
.card-container{
|
||||||
|
// width: 300px;
|
||||||
|
border: 1px solid #1d95ff;
|
||||||
|
border-radius: 6px;
|
||||||
|
color: #fff;
|
||||||
|
.item-one{
|
||||||
|
text-align: center;
|
||||||
|
background-color: #1d95ff;
|
||||||
|
}
|
||||||
|
.item-two{
|
||||||
|
text-align: center;
|
||||||
|
padding: 15px 40px;
|
||||||
|
color: #259dff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,84 @@
|
||||||
|
import React, { useEffect,useState } from 'react';
|
||||||
|
import { Form, Input, Button, DatePicker } from 'antd';
|
||||||
|
import NormalSelect from '../../../components/Form/NormalSelect';
|
||||||
|
|
||||||
|
import moment from 'moment';
|
||||||
|
const { RangePicker } = DatePicker;
|
||||||
|
const ToolBar = ({ setSearchVal, onSave, storeData, exportFile1 }) => {
|
||||||
|
|
||||||
|
const types = [
|
||||||
|
{
|
||||||
|
label: "闸后流量",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "闸前水位",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "闸后水位",
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "雨量",
|
||||||
|
value: 3,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
const types1 = [
|
||||||
|
{
|
||||||
|
label: "报警中",
|
||||||
|
value: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "已解除",
|
||||||
|
value: 1,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const [form] = Form.useForm();
|
||||||
|
|
||||||
|
const onFinish = (values) => {
|
||||||
|
let dateSo;
|
||||||
|
if (values.tm) {
|
||||||
|
dateSo = {
|
||||||
|
start: moment(values.tm[0]).format('YYYY-MM-DD HH:mm:ss'),
|
||||||
|
end: moment(values.tm[1]).format('YYYY-MM-DD HH:mm:ss')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete values.tm
|
||||||
|
setSearchVal({...values, dateSo});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div style={{display:'flex',justifyContent:'space-between'}}>
|
||||||
|
<Form form={form} className='toolbarBox' layout="inline" onFinish={onFinish}>
|
||||||
|
<Form.Item label="监测项目" name="type">
|
||||||
|
<NormalSelect allowClear style={{ width: '150px' }} options={types} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item label="监测时间" name="tm">
|
||||||
|
<RangePicker
|
||||||
|
allowClear
|
||||||
|
showTime
|
||||||
|
style={{ width: "300px" }}
|
||||||
|
format="YYYY-MM-DD HH:mm:ss"
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button type="primary" htmlType="submit">查询</Button>
|
||||||
|
</Form.Item>
|
||||||
|
|
||||||
|
<Form.Item>
|
||||||
|
<Button onClick={() => form.resetFields()}>重置</Button>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
<Button onClick={()=>exportFile1()}>导出</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToolBar;
|
||||||
Loading…
Reference in New Issue