diff --git a/.env.development b/.env.development index 23a1bf7..16f3f9d 100644 --- a/.env.development +++ b/.env.development @@ -1 +1 @@ -PUBLIC_URL=/tsg \ No newline at end of file +PUBLIC_URL=/ykz \ No newline at end of file diff --git a/.env.production b/.env.production index 6dcc99b..c4afaa8 100644 --- a/.env.production +++ b/.env.production @@ -1,2 +1,2 @@ GENERATE_SOURCEMAP=false -PUBLIC_URL=/tsg \ No newline at end of file +PUBLIC_URL=/ykz \ No newline at end of file diff --git a/package.json b/package.json index 768273f..6473d6c 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@wangeditor/editor": "^5.1.23", "@wangeditor/editor-for-react": "^1.0.6", "antd": "^4.21.7", + "autofit.js": "^3.2.2", "axios": "^0.27.2", "clone": "^2.1.2", "clsx": "^1.2.1", diff --git a/src/assets/ykzImg/bp.png b/src/assets/ykzImg/bp.png new file mode 100644 index 0000000..5e6afb3 Binary files /dev/null and b/src/assets/ykzImg/bp.png differ diff --git a/src/assets/ykzImg/menu_btn.png b/src/assets/ykzImg/menu_btn.png new file mode 100644 index 0000000..b37bb96 Binary files /dev/null and b/src/assets/ykzImg/menu_btn.png differ diff --git a/src/assets/ykzImg/name.png b/src/assets/ykzImg/name.png new file mode 100644 index 0000000..0c48aac Binary files /dev/null and b/src/assets/ykzImg/name.png differ diff --git a/src/assets/ykzImg/text.png b/src/assets/ykzImg/text.png new file mode 100644 index 0000000..50aced3 Binary files /dev/null and b/src/assets/ykzImg/text.png differ diff --git a/src/assets/ykzImg/title.png b/src/assets/ykzImg/title.png new file mode 100644 index 0000000..b44b136 Binary files /dev/null and b/src/assets/ykzImg/title.png differ diff --git a/src/components/DashboardLayout/TopMenu.tsx b/src/components/DashboardLayout/TopMenu.tsx index b563aeb..723fec5 100644 --- a/src/components/DashboardLayout/TopMenu.tsx +++ b/src/components/DashboardLayout/TopMenu.tsx @@ -61,7 +61,8 @@ const TopMenu: React.FC<{ const menuClicked = (id: any) => { const menuItem:any = menu.find(m => m.id == id); - if (menuItem.title === "雨水工灾情") { + if (menuItem.title === "首页") { + navigate(menuItem.path) } const url = getMenuUrl(menuItem); @@ -79,16 +80,7 @@ const TopMenu: React.FC<{
{ - 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) - } - }} + onClick={() => {menuClicked(o.id)}} style={{cursor:"pointer"}} > diff --git a/src/models/auth/_.ts b/src/models/auth/_.ts index 09345ba..bf5892c 100644 --- a/src/models/auth/_.ts +++ b/src/models/auth/_.ts @@ -192,7 +192,7 @@ export async function loadMenu(): Promise { const id = idgen() 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', children: [ diff --git a/src/service/apiurl.js b/src/service/apiurl.js index 9a1e48c..49ddbd6 100644 --- a/src/service/apiurl.js +++ b/src/service/apiurl.js @@ -11,6 +11,12 @@ const apiurl = { router: service_xyt + '/getRouters', 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: { whfabz: { page: service_fxdd + '/resPerson/page', diff --git a/src/utils/request.js b/src/utils/request.js index 3c6ea73..4f5d83e 100644 --- a/src/utils/request.js +++ b/src/utils/request.js @@ -43,7 +43,7 @@ async function send(url, options) { if (code === 405) { // debugger; //window.location.href = '/mgr/home';// /mgr/home /login - window.location.href = '/tsg/#/login'; + window.location.href = '/ykz/#/login'; // window.location.hash = '#/login'; } return res.data; diff --git a/src/views/AppRouters.tsx b/src/views/AppRouters.tsx index 52f87c1..6974582 100644 --- a/src/views/AppRouters.tsx +++ b/src/views/AppRouters.tsx @@ -33,11 +33,12 @@ const AppRouters: React.FC = () => { let element = useRoutes([ { path: '/', element: }, + { path: '/home', element: }, { path: '/mgr', element: , children: [ - { path: 'home', element: }, + // { path: 'home', element: }, // 监测数据 { path: 'jcsj/jcsj', element: }, { path: 'jcsj/bjgl/bjjl', element: }, diff --git a/src/views/Home/index.js b/src/views/Home/index.js index 2ed541d..00844fe 100644 --- a/src/views/Home/index.js +++ b/src/views/Home/index.js @@ -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 ( -
Home
+
+ {title} +
+ ) +} +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 ( +
+
+
+
+ {title.map((item, i) => ( +
jumpMenu(item)} style={{cursor:'pointer'}}> + +
+ ))} +
+
+ +
+
) } diff --git a/src/views/Home/index.less b/src/views/Home/index.less new file mode 100644 index 0000000..afedfe4 --- /dev/null +++ b/src/views/Home/index.less @@ -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; + } +} \ No newline at end of file diff --git a/src/views/Home/zmjk/ColorPolygon.tsx b/src/views/Home/zmjk/ColorPolygon.tsx new file mode 100644 index 0000000..815144c --- /dev/null +++ b/src/views/Home/zmjk/ColorPolygon.tsx @@ -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 ( + { + 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 \ No newline at end of file diff --git a/src/views/Home/zmjk/Sider.tsx b/src/views/Home/zmjk/Sider.tsx new file mode 100644 index 0000000..c443cbd --- /dev/null +++ b/src/views/Home/zmjk/Sider.tsx @@ -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 ( + + + + + + + + + + + + + + + + + + + + + ) +} + +export default React.memo(Sider) \ No newline at end of file diff --git a/src/views/Home/zmjk/Topper1.tsx b/src/views/Home/zmjk/Topper1.tsx new file mode 100644 index 0000000..4a4f291 --- /dev/null +++ b/src/views/Home/zmjk/Topper1.tsx @@ -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 ( + + + + { + pts.SepsLTLBRBRT.map((s, index) => ( + + )) + } + { + windows.w.map((o, index) => ) + } + { + windows.h.map((o, index) => ) + } + + ) +} + +export default React.memo(Topper1); \ No newline at end of file diff --git a/src/views/Home/zmjk/Topper2.tsx b/src/views/Home/zmjk/Topper2.tsx new file mode 100644 index 0000000..cb393f1 --- /dev/null +++ b/src/views/Home/zmjk/Topper2.tsx @@ -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 ( + + { + pts.SepsFront.map((s, index) => ( + + )) + } + + + + ) +} + +export default React.memo(Topper2); \ No newline at end of file diff --git a/src/views/Home/zmjk/Window.tsx b/src/views/Home/zmjk/Window.tsx new file mode 100644 index 0000000..550ed8c --- /dev/null +++ b/src/views/Home/zmjk/Window.tsx @@ -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 ( + <> + + + + + + + + ) +} + +export const WindowSep: React.FC<{ + rect: number[]; +}> = ({ rect }) => { + const [x1, y1, x2, y2] = rect; + + return ( + + ) +} + +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 ( + <> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + { + [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(i => ( + + )) + } + + + + ) +} \ No newline at end of file diff --git a/src/views/Home/zmjk/ZmColumn.tsx b/src/views/Home/zmjk/ZmColumn.tsx new file mode 100644 index 0000000..6fe46fc --- /dev/null +++ b/src/views/Home/zmjk/ZmColumn.tsx @@ -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 ? ( + + ) : null : null + } + {/* */} + {idx != 0 ? : null} + {idx!= list.length - 1 ? : null} + {/* + */} + + {idx != list.length - 1 ? : ''} + {idx!= 0 ? :'' } + + + + + + + + + + + + + + + { + waterP1.y < b1.y ? ( + + ) : null + } + + + ) +} + +export default React.memo(ZmColumn) \ No newline at end of file diff --git a/src/views/Home/zmjk/ZmColumns.tsx b/src/views/Home/zmjk/ZmColumns.tsx new file mode 100644 index 0000000..2ab708c --- /dev/null +++ b/src/views/Home/zmjk/ZmColumns.tsx @@ -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 ( + + { + eqpnoList.map((o, index,arr) => ( + ) + ) + } + + ) +} + +export default ZmColumns \ No newline at end of file diff --git a/src/views/Home/zmjk/ZmDec.tsx b/src/views/Home/zmjk/ZmDec.tsx new file mode 100644 index 0000000..30f9f26 --- /dev/null +++ b/src/views/Home/zmjk/ZmDec.tsx @@ -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 => ( + + { + 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 ( + + + { + cx < ViewCenter.x ? ( + + ) : ( + + ) + } + { + cy < Horizontal ? ( + + ) : ( + + ) + } + + ) + }) + } + + )) + } + + ) +} + +export default ZmDec \ No newline at end of file diff --git a/src/views/Home/zmjk/consts.ts b/src/views/Home/zmjk/consts.ts new file mode 100644 index 0000000..1a9147e --- /dev/null +++ b/src/views/Home/zmjk/consts.ts @@ -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; diff --git a/src/views/Home/zmjk/coordinates.ts b/src/views/Home/zmjk/coordinates.ts new file mode 100644 index 0000000..93bff7e --- /dev/null +++ b/src/views/Home/zmjk/coordinates.ts @@ -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, + } +} \ No newline at end of file diff --git a/src/views/Home/zmjk/index.js b/src/views/Home/zmjk/index.js new file mode 100644 index 0000000..ddba721 --- /dev/null +++ b/src/views/Home/zmjk/index.js @@ -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 ( + <> +
+
+
+ + + + + + + + +
+
+ { + eqpnoList.map(o => ( +
{}} + className='o' style={{ flexGrow: 1, width: 100, display: 'flex', justifyContent: 'center', cursor: 'pointer' }}> +
#{o+1}
+
+ )) + } +
+
+
+
+ { + eqpnoList.map(o => ( +
+
{}} + 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)} +
+
+ )) + } +
+
+
+
+
+
+ + ); +} + +export default Page; diff --git a/src/views/Home/zmjk/index.less b/src/views/Home/zmjk/index.less new file mode 100644 index 0000000..d10d631 --- /dev/null +++ b/src/views/Home/zmjk/index.less @@ -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; + } + } + } +} \ No newline at end of file diff --git a/src/views/Home/zmjk/useLinearAnim.ts b/src/views/Home/zmjk/useLinearAnim.ts new file mode 100644 index 0000000..7fb7040 --- /dev/null +++ b/src/views/Home/zmjk/useLinearAnim.ts @@ -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(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; +} \ No newline at end of file diff --git a/src/views/Login/index1.tsx b/src/views/Login/index1.tsx index c0a90f3..c58a049 100644 --- a/src/views/Login/index1.tsx +++ b/src/views/Login/index1.tsx @@ -71,7 +71,7 @@ const LoginPage = () => { message.error((result.description).replace('参数错误','')); } } - const getInfo=(result1:any,value:any)=>{ + const getInfo = (result1: any, value: any) => { if (result1.code === 200) { if(checked){ localStorage.setItem('loginNamePwd',JSON.stringify(value)) @@ -83,7 +83,7 @@ const LoginPage = () => { localStorage.setItem('userName', result1.user.nickName); localStorage.setItem('userId', result1.user.userId); - navigate('/mgr/home'); + navigate('/home'); }else{ message.error('获取用户信息失败'); } diff --git a/src/views/WatchData/Jcsj/index.js b/src/views/WatchData/Jcsj/index.js index 2cbaa79..372570d 100644 --- a/src/views/WatchData/Jcsj/index.js +++ b/src/views/WatchData/Jcsj/index.js @@ -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 ( -
index
+
+
{item.label}
+
{item.value} (08-15 15:00:00)
+
) } +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) => {types[v]} + }, + { 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 ( + <> +
+
+
+
+
+
实时数据
+
+
+ {nameList.map(item => ( + + ))} +
+
+
+
+
+
监测数据
+
+
+ + + +
+
+ + +
+ +
+ + + + + ); +} + +export default Page; diff --git a/src/views/WatchData/Jcsj/index.less b/src/views/WatchData/Jcsj/index.less new file mode 100644 index 0000000..9a75c6a --- /dev/null +++ b/src/views/WatchData/Jcsj/index.less @@ -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; + } + } + } +} \ No newline at end of file diff --git a/src/views/WatchData/Jcsj/toolbar.js b/src/views/WatchData/Jcsj/toolbar.js new file mode 100644 index 0000000..3654d57 --- /dev/null +++ b/src/views/WatchData/Jcsj/toolbar.js @@ -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 ( + <> +
+
+ + + + + + + + + + + + + + + + + +
+ + ); +} + +export default ToolBar; \ No newline at end of file