From e767f8648accd343e0a383a53e51181dca54daef Mon Sep 17 00:00:00 2001 From: lishenfeng Date: Thu, 13 Nov 2025 16:58:52 +0800 Subject: [PATCH] =?UTF-8?q?feat():ai=E5=91=8A=E8=AD=A6=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E6=9B=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/video1Plary.js | 16 +- .../homePanelsLayoutPage/item_yujing/index.js | 2 +- .../item_yujing/table_AI.js | 4 +- src/views/spjk/aiWarn/index.js | 148 ++++++++++++------ src/views/spjk/aiWarn/toolbar.js | 60 +++---- 5 files changed, 137 insertions(+), 93 deletions(-) diff --git a/src/components/video1Plary.js b/src/components/video1Plary.js index 80f6de41a..de3a64222 100644 --- a/src/components/video1Plary.js +++ b/src/components/video1Plary.js @@ -2,6 +2,7 @@ import { FC, useEffect, useRef, useState } from 'react' // import styles from './index.module.less' import { message, Spin } from "antd"; import EZUIKit from 'ezuikit-js'; +import moment from 'moment'; /** * 海康视频H5插件视频播放 @@ -23,10 +24,16 @@ const HFivePlayer = ({ wsUrl, playerID, size }) => { const initVideo = () => { + const hasReplayRange = wsUrl?.beginTime && wsUrl?.endTime && wsUrl?.indexCode; + const beginStr = hasReplayRange ? moment(wsUrl.beginTime).format('YYYYMMDDHHmmss') : ''; + const endStr = hasReplayRange ? moment(wsUrl.endTime).format('YYYYMMDDHHmmss') : ''; + const ezUrl = hasReplayRange + ? `ezopen://open.ys7.com/${wsUrl.indexCode}/1.rec?begin=${beginStr}&end=${endStr}` + : `ezopen://open.ys7.com/${wsUrl.indexCode}/1.live`; playerYsy.current = new EZUIKit.EZUIKitPlayer({ id: 'player' + playerID, // 视频容器ID accessToken: wsUrl.src, - url: `ezopen://open.ys7.com/${wsUrl.indexCode}/1.live`, + url: ezUrl, // plugin: ["talk"], // 加载插件,talk-对讲 width: parentRef.current?.offsetWidth, height: parentRef.current?.offsetHeight, @@ -133,6 +140,13 @@ const HFivePlayer = ({ wsUrl, playerID, size }) => { if (wsUrl?.src) { setIsLoading(true) //开始加载 let preUrl = wsUrl?.src // 播放地址 + // 支持回放时间范围(海康取流地址若后端支持时间参数则追加) + if (wsUrl?.beginTime && wsUrl?.endTime) { + const begin = moment(wsUrl.beginTime).subtract(1,'hours').format('YYYY-MM-DD HH:mm:ss'); + const end = moment(wsUrl.endTime).format('YYYY-MM-DD HH:mm:ss'); + const sep = preUrl.includes('?') ? '&' : '?'; + preUrl = `${preUrl}${sep}beginTime=${begin}&endTime=${end}`; + } console.log(preUrl); const param = { playURL: preUrl, diff --git a/src/views/Home/homePanelsLayoutPage/item_yujing/index.js b/src/views/Home/homePanelsLayoutPage/item_yujing/index.js index 647f580cc..b11264ac8 100644 --- a/src/views/Home/homePanelsLayoutPage/item_yujing/index.js +++ b/src/views/Home/homePanelsLayoutPage/item_yujing/index.js @@ -121,7 +121,7 @@ const Page = ({ mySetTms }) => { { key==='位移告警'?setOpen(false)}/>:null } { key==='渗压告警'?setOpen(false)}/>:null } { key==='渗流告警'?setOpen(false)}/>:null } - {key === 'AI告警' ? : null} + {key === 'AI告警' ? : null} { key==='白蚁告警'?setOpen(false)}/>:null } diff --git a/src/views/Home/homePanelsLayoutPage/item_yujing/table_AI.js b/src/views/Home/homePanelsLayoutPage/item_yujing/table_AI.js index 4b3ee2346..d8f62b7f1 100644 --- a/src/views/Home/homePanelsLayoutPage/item_yujing/table_AI.js +++ b/src/views/Home/homePanelsLayoutPage/item_yujing/table_AI.js @@ -10,7 +10,7 @@ import apiurl from "../../../../service/apiurl"; import moment from 'moment'; -const Page = () => { +const Page = ({ tms }) => { // const { tableProps, search, refresh } = usePageTable(createCrudService('/gunshiApp/tsg/rescue/goods/page/query').find_noCode,{}); @@ -23,7 +23,7 @@ const Page = () => { return (
- + {/*
时间:{moment().format('YYYY-MM-DD HH:mm:ss')} 至 {moment().format('YYYY-MM-DD HH:mm:ss')}
*/}
) diff --git a/src/views/spjk/aiWarn/index.js b/src/views/spjk/aiWarn/index.js index d0ab5e38a..cd6e773d1 100644 --- a/src/views/spjk/aiWarn/index.js +++ b/src/views/spjk/aiWarn/index.js @@ -1,78 +1,128 @@ -import React, { Fragment, useRef, useMemo,useEffect,useState } from 'react'; -import { Table, Card,Modal,Form,Input,Button,Row,Pagination,message } from 'antd'; +import React, { Fragment, useRef, useMemo, useEffect, useState } from 'react'; +import { Table, Card, Modal, Form, Input, Button, Row, Pagination, message } from 'antd'; import { useSelector } from 'react-redux'; import ToolBar from './toolbar'; import apiurl from '../../../service/apiurl'; import usePageTable from '../../../components/crud/usePageTable3'; import { createCrudService } from '../../../components/crud/_'; +import { httpget2,httppost2 } from '../../../utils/request'; +import HFivePlayer from '../../../components/video1Plary'; import CardShow from "./Card" import "./index.less" -const Page = () => { - const role = useSelector(state => state.auth.role); - - const [searchVal, setSearchVal] = useState(false) - const { tableProps, search, refresh } = usePageTable(createCrudService(apiurl.spjk1.aiWarn.page1).find_noCode); - const onchange = (page, pageSize) => { - const obj = { - pageNumber: page, - pageSize: pageSize, - } - const searchParams = { - ...obj, - // search: { - // ...searchVal, - // } - } - search(searchParams) +import moment from 'moment'; +const Page = (props) => { + const tm = props?.tm; + const statusObj = { + 0: "未处理", + 1: '已处理' + }; + const levelStatus = { + 1: '低', + 2: '中', + 3: '高' } + const role = useSelector(state => state.auth.role); + const columns = [ + { title: '序号', key: 'inx', dataIndex: 'inx', width: 60, align: "center" }, + { title: '事件源名称', key: 'resName', dataIndex: 'resName', width: 150, ellipsis: true }, + { + title: '事件类型名称', key: 'eventTypeName', dataIndex: 'eventTypeName', width: 150, ellipsis: true + }, + { title: '事件处理状态', key: 'handleStatus', dataIndex: 'handleStatus', width: 120, render: (v) => {statusObj[v]} }, + { title: '事件等级', key: 'eventLevel', dataIndex: 'eventLevel', width: 100, render: (v) => {levelStatus[v]} }, + { title: '事件开始时间', key: 'startTime', dataIndex: 'startTime', width: 150, render: (v) => {v ? moment(v).format("YYYY-MM-DD HH:mm:ss") : ''} }, + { title: '事件结束时间', key: 'endTime', dataIndex: 'endTime', width: 150, render: (v) => {v ? moment(v).format("YYYY-MM-DD HH:mm:ss") : ''} }, + // { + // title: '操作', key: 'opr', dataIndex: 'opr', width: 100, align: "center", + // render:(v,r)=> + // }, + + ]; + const [searchVal, setSearchVal] = useState(false) + const [replayOpen, setReplayOpen] = useState(false) + const [replayItem, setReplayItem] = useState({}) + const [videoSrc, setVideoSrc] = useState('') + const { tableProps, search, refresh } = usePageTable(createCrudService(apiurl.spjk1.aiWarn.page1).find_noCode); + const width = useMemo(() => columns.reduce((total, cur) => total + (cur.width), 0), [columns]); + + const replay = (r) => { + setReplayOpen(true); + setReplayItem(r) + getVideoSrc(r) + } + + const getVideoSrc = async(data) => { + try { + // 仅获取播放地址,回放时间由播放器拼接 + const res = await httpget2(`${apiurl.gsxl.zfzl.videosrc}${data.resIndexCode}`) + setVideoSrc(res.data) + } catch (error) { + console.log(error); + } + } + // 当外部传入 tm([start,end])时,初始化查询条件 useEffect(() => { - if (searchVal) { - const params = { + if (tm && Array.isArray(tm) && tm[0]) { + setSearchVal({ + startTime: moment(tm[0]).format('YYYY-MM-DD HH:mm:ss'), + }) + } + }, [tm]) + + // 路由直接进入 AI 告警页(没有 tm)时,初始化一次默认查询 + useEffect(() => { + if (!tm) { + setSearchVal({}) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) + + useEffect(() => { + const params = { search: { ...searchVal, } }; - search(params) + // 避免初始化时触发空查询造成二次请求闪烁 + if (searchVal !== false) { + search(params) } - }, [searchVal]) return ( <> -
+
-
- { - tableProps.dataSource.length > 0 ? - tableProps.dataSource.map((item,i) => { - return ( -
- -
- ) - }) : null - } +
+ -
- -
+ setReplayOpen(false)} + footer={null} + destroyOnClose + > +
+ +
+
); diff --git a/src/views/spjk/aiWarn/toolbar.js b/src/views/spjk/aiWarn/toolbar.js index 0708ae2b4..0d5719266 100644 --- a/src/views/spjk/aiWarn/toolbar.js +++ b/src/views/spjk/aiWarn/toolbar.js @@ -5,26 +5,22 @@ import moment from 'moment'; import { httppost2 } from '../../../utils/request'; import apiurl from '../../../service/apiurl'; const { RangePicker } = DatePicker; -const ToolBar = ({ setSearchVal, onSave, storeData, role }) => { +const ToolBar = ({ setSearchVal, onSave, storeData, role, tm }) => { const searchBtn = role?.rule?.find(item => item.menuName == "查询")|| true; const warnTypes = [ { - label: "人员闯入", + label: "低", value:1 }, { - label: "工程车辆识别", + label: "中", value:2 }, { - label: "漂浮物识别", + label: "高", value:3 - }, - { - label: "游泳识别", - value:4 - }, + } ] const [form] = Form.useForm(); const [codeList, setCodeList] = useState([]) @@ -38,46 +34,30 @@ const ToolBar = ({ setSearchVal, onSave, storeData, role }) => { } } const onFinish = (values) => { - let dateSo; - if (values.tm) { - dateSo = { - start: moment(values.tm[0]).format('YYYY-MM-DD 00:00:00'), - end: moment(values.tm[1]).format('YYYY-MM-DD 23:59:59') - } + if (values.startTime) { + values.startTime = moment(values.startTime).format('YYYY-MM-DD HH:mm:ss'); } - delete values.tm - setSearchVal({...values, dateTimeRangeSo:dateSo}); + setSearchVal({...values}); } - - useEffect(() => { - getStationCode() - let time = [moment().subtract(1,"weeks"),moment()] - let dateSo = { - start:moment(time[0]).format('YYYY-MM-DD 00:00:00'), - end:moment(time[1]).format('YYYY-MM-DD 23:59:59'), - } - form.setFieldValue("tm",time) - setSearchVal({dateTimeRangeSo:dateSo}) - }, []) + // 预填开始时间(来自外部 tm) + useEffect(() => { + if (tm && Array.isArray(tm) && tm[0]) { + form.setFieldsValue({ startTime: moment(tm[0]) }) + } + }, [tm]) return ( <>
- - + - - - - +