闸门监控
parent
70b19cb2fc
commit
35f59e0f4b
|
|
@ -50,7 +50,10 @@
|
|||
"react-router-dom": "^6.3.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"redux": "^4.2.0",
|
||||
"typescript": "^4.7.4"
|
||||
"typescript": "^4.7.4",
|
||||
"konva": "^8.3.14",
|
||||
"react-konva": "^18.2.3"
|
||||
|
||||
},
|
||||
"scripts": {
|
||||
"start": "craco start",
|
||||
|
|
|
|||
|
|
@ -302,6 +302,9 @@ export async function loadMenu(): Promise<MenuItem[]> {
|
|||
{ id: id(), title: '防治宣传', path: '/mgr/sg/byfz/byxc' },
|
||||
]
|
||||
},
|
||||
{
|
||||
id: id(), title: '闸门监控', path: '/mgr/sg/zmjk',
|
||||
},
|
||||
{
|
||||
id: id(), title: '维修养护', path: '/mgr/sg/wxyh',
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,6 +24,14 @@ const apiurl = {
|
|||
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'
|
||||
},
|
||||
|
||||
// 基本情况
|
||||
home: {
|
||||
yq: service_fxdd + '/real/rain/list',//'/stStbprpB/rainfallStationDetails/rainfallList',//雨情
|
||||
|
|
|
|||
|
|
@ -10,6 +10,20 @@ export function changeObjectStringToMoment(obj: { [key: string]: any }, fields:
|
|||
return ret;
|
||||
}
|
||||
|
||||
export function apertureMeter(val?: any): number | undefined {
|
||||
if (typeof val !== 'number') {
|
||||
return undefined
|
||||
}
|
||||
return val / 1000;
|
||||
}
|
||||
|
||||
export function renAperture(val?: any) {
|
||||
if (typeof val !== 'number') {
|
||||
return '-'
|
||||
}
|
||||
|
||||
return (val / 1000).toFixed(3);
|
||||
}
|
||||
|
||||
export async function base64FromFile(file: File): Promise<string | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ import Xjxpz from "./rcgl/xcxj/xjxpz"
|
|||
import Fzxc from "./rcgl/byfz/fzxc"
|
||||
import Bypc from "./rcgl/byfz/bypc"
|
||||
|
||||
import Zmjk from "./rcgl/zmjk"
|
||||
import Wxyh from "./rcgl/wxyh"
|
||||
import Szzb from "./rcgl/szzb"
|
||||
import Stlljc from "./rcgl/stlljc"
|
||||
|
|
@ -191,6 +192,7 @@ const AppRouters: React.FC = () => {
|
|||
{ path: 'sg/xcxj/xjxpz', element: <Xjxpz/> },
|
||||
{ path: 'sg/byfz/byxc', element: <Fzxc /> },
|
||||
{ path: 'sg/byfz/bypc', element: <Bypc /> },
|
||||
{ path: 'sg/zmjk', element: <Zmjk /> },
|
||||
{ path: 'sg/wxyh', element: <Wxyh /> },
|
||||
{ path: 'sg/aqgl/aqjcgl', element: <Aqjcgl /> },
|
||||
{ path: 'sg/aqgl/fxgkqd', element: <Fxgkqd /> },
|
||||
|
|
|
|||
|
|
@ -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,119 @@
|
|||
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;
|
||||
}> = ({ kdMax, gtophgt, idx, pts, waterRatio, selected }) => {
|
||||
|
||||
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 (
|
||||
<>
|
||||
{
|
||||
waterP3 && waterP3R ? (
|
||||
<ColorPolygon fill='#539cb9' pts={[waterP2, waterP2R, waterP3R, waterP3]} opacity={0.8} />
|
||||
) : null
|
||||
}
|
||||
<ColorPolygon
|
||||
desc="闸门上测"
|
||||
fill='#afb5b5'
|
||||
pts={[
|
||||
[a.lt1.x, ty1],
|
||||
[a.rt1.x, ty1],
|
||||
[a.rt2.x, ty2],
|
||||
[a.lt2.x, ty2],
|
||||
]}
|
||||
/>
|
||||
<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]} />
|
||||
<Circle fill='#afb5b5' x={line1.x} y={joiny} radius={10} />
|
||||
<Circle fill='#afb5b5' x={line2.x} y={joiny} radius={10} />
|
||||
<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,35 @@
|
|||
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) => (
|
||||
<ZmColumn
|
||||
key={o}
|
||||
gtophgt={apertureMeter(runtime[o]?.realAperture)}
|
||||
kdMax={2}
|
||||
pts={pts}
|
||||
idx={index}
|
||||
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,350 @@
|
|||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
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 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 runtime = [
|
||||
null,
|
||||
{
|
||||
"stcd": "4265630075",
|
||||
"gateNumber": 1,
|
||||
"realAperture": 976,
|
||||
"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:31"
|
||||
},
|
||||
{
|
||||
"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:31"
|
||||
},
|
||||
{
|
||||
"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:31"
|
||||
}
|
||||
]
|
||||
|
||||
const myType = {
|
||||
// 闸前水位站 2闸后水位站 3流量站
|
||||
'1':'闸前水位/水深(m)',
|
||||
'2':'闸后水位/水深(m)',
|
||||
'3':'流量 (m³/s)',
|
||||
}
|
||||
|
||||
const Page = () => {
|
||||
const [itemIndex,setItemIndex] = useState(null)
|
||||
const [data,setData] = useState({})
|
||||
const [list, setList ] = useState([])
|
||||
const [damList, setDamList ] = useState([])
|
||||
const [videoList, setVideoList ] = useState([])
|
||||
const [videoArr, setvideoArr] = useState({})
|
||||
|
||||
|
||||
const hole = 3;//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)
|
||||
getVideo(obj.gateCode)
|
||||
setData(obj)
|
||||
}
|
||||
|
||||
const getInformation = async(gateCode)=>{
|
||||
const {code, data} = await httpget2(apiurl.zmjk.getInformation,{gateCode})
|
||||
if(code!==200){
|
||||
return
|
||||
}
|
||||
setList(data)
|
||||
}
|
||||
|
||||
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*1000
|
||||
})
|
||||
})
|
||||
setDamList(list)
|
||||
}
|
||||
|
||||
const getVideo = async(valveCode)=>{
|
||||
const {code, data} = await httppost2(apiurl.zmjk.getVideo,{valveCode})
|
||||
if(code!==200){
|
||||
return
|
||||
}
|
||||
setVideoList(data)
|
||||
}
|
||||
|
||||
const getVideoSrc = async (current) => {
|
||||
const res = await httpget2(`${apiurl.gsxl.zfzl.videosrc}${'32023a7f27d8448fa10511f24e96acff'}`)
|
||||
if (res.code == 200 && res.data?.length !== 0) {
|
||||
setvideoArr({src:res.data})
|
||||
}else{
|
||||
setvideoArr({})
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className='content-root clearFloat xybm sg_zmjk' style={{paddingRight:"0",paddingBottom:"0"}}>
|
||||
<div className='lf CrudAdcdTreeTableBox' style={{width:"100%",overflowY:"auto"}}>
|
||||
{/* <Card className='nonebox'>
|
||||
</Card> */}
|
||||
<div className="ant-card-body" style={{ padding: "20px 0 0 0" }}>
|
||||
<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>
|
||||
<dvi className="sg_zmjk_right">
|
||||
<div className='sg_zmjk_right_video'>
|
||||
<div className='sg_zmjk_right_video_title'>视频监控</div>
|
||||
<div className='sg_zmjk_right_video_content'>
|
||||
<div className='sg_zmjk_right_video_content_left'>
|
||||
{
|
||||
videoList.map((item,index)=>(
|
||||
<div className={index===itemIndex?'sg_zmjk_right_video_content_left_item itemChecked':'sg_zmjk_right_video_content_left_item'} onClick={()=>{setItemIndex(index);getVideoSrc(item.indexCode)}}>
|
||||
{item.name}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className='sg_zmjk_right_video_content_right'>
|
||||
{
|
||||
videoArr?.src &&
|
||||
<div
|
||||
className="content-video"
|
||||
style={{ width: '100%', height: '100%',cursor: "pointer" }}
|
||||
onClick={() => {
|
||||
// if (controlerParams.type == 1) {
|
||||
// setVideoOpen(true)
|
||||
// setIsShow(!isShow)
|
||||
// }
|
||||
}}
|
||||
>
|
||||
<HFivePlayer size={1} wsUrl={videoArr} playerID={'111'} />
|
||||
{/* <div style={{textAlign:"right"}}>注:单击视频显示/隐藏云台</div> */}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='sg_zmjk_right_information'>
|
||||
<div className='sg_zmjk_right_information_title'>监测数据</div>
|
||||
<div style={{height:'144px',overflowY:'auto',padding:'20px'}}>
|
||||
{
|
||||
list?.map((item)=>{
|
||||
return (
|
||||
<div className='sg_zmjk_right_information_content'>
|
||||
<div>{myType[item.type]}</div>
|
||||
<div>112.079 / 1.279</div>
|
||||
<div>07-10 12:09:00</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<div className='sg_zmjk_right_more'>》》查看更多信息</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: 30px;
|
||||
position: relative;
|
||||
width: 1080px;
|
||||
height: 640px;
|
||||
transform: scale(0.9,1);
|
||||
|
||||
}
|
||||
.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;
|
||||
}
|
||||
Loading…
Reference in New Issue