feat(): 首页大屏闸口开发

test
李神峰 2024-12-12 17:53:28 +08:00
parent 3c5bd3ac4e
commit 00e701be3b
32 changed files with 1511 additions and 24 deletions

View File

@ -1 +1 @@
PUBLIC_URL=/tsg PUBLIC_URL=/ykz

View File

@ -1,2 +1,2 @@
GENERATE_SOURCEMAP=false GENERATE_SOURCEMAP=false
PUBLIC_URL=/tsg PUBLIC_URL=/ykz

View File

@ -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",

BIN
src/assets/ykzImg/bp.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

BIN
src/assets/ykzImg/name.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
src/assets/ykzImg/text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
src/assets/ykzImg/title.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 KiB

View File

@ -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=""/>

View File

@ -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: [

View File

@ -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',

View File

@ -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;

View File

@ -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 /> },

View File

@ -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>
) )
} }

77
src/views/Home/index.less Normal file
View File

@ -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;
}
}

View File

@ -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

View File

@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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]} />
))
}
</>
)
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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,
}
}

View File

@ -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;

View File

@ -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;
}
}
}
}

View File

@ -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;
}

View File

@ -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('获取用户信息失败');
} }

View File

@ -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;

View File

@ -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;
}
}
}
}

View File

@ -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;