feat: 视频分析模块开发

develop
JINGYJ 1 year ago
parent 43c86f77a0
commit f3357251d0

@ -369,4 +369,14 @@ export default [
path: '/involved-list',
component: 'Alarm/InvolvedList',
},
{
name: 'videoAnalysis',
path: '/videoAnalysis',
component: 'VideoAnalysis',
},
{
name: 'involved-list-upload',
path: '/involved-list-upload',
component: 'Alarm/InvolvedUploadList',
},
];

@ -68,6 +68,7 @@
"react-dev-inspector": "^1.8.4",
"react-dom": "^18.2.0",
"react-helmet-async": "^1.3.0",
"react-infinite-scroll-component": "^6.1.0",
"swiper": "^11.0.5",
"video.js": "^8.5.2",
"webrtc-streamer": "^0.8.3-4-g2d0afce"

@ -110,6 +110,26 @@ export async function getInitialState(): Promise<{
"component": "Hidden",
"title": "用户列表",
"routes": []
},
{
"path": "videoAnalysis",
"key": "",
"name": "videoAnalysis",
"icon": "VideoCameraOutlined",
"access": "",
"component": "Hidden",
"title": "视频分析",
"routes": []
},
{
"path": "involved-list-upload",
"key": "",
"name": "involved-list-upload",
"icon": "FileSearchOutlined",
"access": "",
"component": "Hidden",
"title": "重点关注(上传)",
"routes": []
}
]
},

@ -20,6 +20,18 @@ export const alarmRulesEnums: Record<string, any>[] = [
// },
];
// 视频分析
export const alarmVideoAnalysis: Record<string, any>[] = [
{
label: '单人徘徊告警',
key: '1',
},
{
label: '多人聚集告警',
key: '2',
}
];
// 分布式设备状态
export const deviceStatusEnums: Record<string, any> = {
allStatus: {

@ -76,10 +76,12 @@ export const interface_manage: { [key: string]: string } = {
'device.interface_manage.table.list.address': '接口地址',
'device.interface_manage.table.list.ip': 'IP地址',
'device.interface_manage.table.list.createTime': '创建时间',
'device.interface_manage.table.list.testTime': '状态查询时间',
'device.interface_manage.table.list.remark': '备注',
'device.interface_manage.table.list.add': '新建设备/输入源',
'device.interface_manage.table.list.addPic': '新建图像获取接口',
'device.interface_manage.table.list.updatePic': '编辑图像获取接口',
'device.interface_manage.table.list.capture': '最近拍摄',
'device.interface_manage.table.rule.required.name': '接口名称为必填项',
'device.interface_manage.table.rule.required.address': '接口地址为必填项',
'device.interface_manage.table.rule.required.ip': 'IP地址为必填项',

@ -50,7 +50,6 @@
font-weight: 400;
color: #FFFFFF;
background: rgba(0, 0, 0, 0.6);
.alarmSpan {
// color: #333;
margin-right: 24px;
@ -59,7 +58,7 @@
}
.alarmImgDescribe {
margin-bottom: 12px;
font-family: PingFang SC, PingFang SC;
font-family: PingFang SC;
font-weight: 500;
font-size: 16px;
color: #666;
@ -69,15 +68,15 @@
}
.alarmImgContent {
box-sizing: border-box;
margin-bottom: 24px;
padding: 16px;
width: 784px;
// height: 172px;
background: #F7F7F7;
border-radius: 4px;
border: 2px dashed #DCDCDC;
border: 1px dashed #DCDCDC;
display: flex;
justify-content: center;
}
}
.myButtonDisabled{

@ -77,28 +77,25 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
handlePostRecognition(updatedInvolvedInfo[index][0], value)
};
/** 单人告警组件 */
const handleSingleInvolved = () => {
if (involved === 1) {
setInvolved(0);
handlePostRecognition(props.values?.person_id, 0)
} else {
setInvolved(1);
handlePostRecognition(props.values?.person_id, 1)
}
}
// const handleSingleInvolved = () => {
// if (involved === 1) {
// setInvolved(0);
// handlePostRecognition(props.values?.person_id, 0)
// } else {
// setInvolved(1);
// handlePostRecognition(props.values?.person_id, 1)
// }
// }
// const [open, setOpen] = useState(false);
useEffect(() => {
console.log(Array.isArray(props.values?.person_id),'Array.isArray(props.values?.person_id)');
// console.log(Array.isArray(props.values?.person_id),'Array.isArray(props.values?.person_id)');
setImageSrc(props?.values?.picture_path?.[0])
}, [props.updateModalOpen])
return (
<ModalForm<any>
width={832}
title={intl.formatMessage({
id: 'alarm.list.table.form.title',
defaultMessage: `编辑${props.values.warning_name}`,
})}
title={`${props.values.warning_name}告警`}
open={props.updateModalOpen}
form={form}
autoFocusFirstInput
@ -121,17 +118,43 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
// searchConfig: {
// submitText: '忽略此事件',
// },
render: (props) => {
render: (prop) => {
return [
<Button
key="ok"
style={{ backgroundColor: '#E80D0D',color: '#FFF',borderBlockColor: '#E80D0D' }}
onClick={() => {
props.submit();
}}
>
</Button>
<Button
key="ok"
style={{ backgroundColor: '#E80D0D',color: '#FFF',borderBlockColor: '#E80D0D' }}
onClick={() => {
prop.submit();
}}
>
</Button>,
props.values?.person_list ? null : (
<Button
key="involved"
style={{ backgroundColor: '#FAAD14',color: '#FFF',borderBlockColor: '#FAAD14' }}
onClick={() => {
// console.log(props.updateModalOpen);
setInvolved(1);
handlePostRecognition(props.values?.person_id, 1)
}}
>
</Button>
),
props.values?.person_list ? null : (
<Button
key="noInvolved"
style={{ background: '#FFF',color: '#E80D0D',borderColor: '#E80D0D' }}
onClick={() => {
// console.log(props.updateModalOpen);
setInvolved(0);
handlePostRecognition(props.values?.person_id, 0)
}}
>
</Button>
)
];
},
}}
@ -168,6 +191,7 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
key={index}
indexId={index}
handleInvolved={handleInvolved}
time={props.values.trigger_time}
></ImageWithPopover>
);
})
@ -179,8 +203,9 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
src={item}
involved={involved}
key={index}
handleInvolved={handleSingleInvolved}
// handleInvolved={handleSingleInvolved}
reload={props.reload} // 将reload方法作为prop传递给ImageSinglePopover组件
time={props.values.trigger_time}
></ImageSinglePopover>
);
})
@ -194,8 +219,9 @@ const UpdateForm: React.FC<UpdateFormProps> = (props) => {
src={item}
involved={involved}
key={index}
handleInvolved={handleSingleInvolved}
// handleInvolved={handleSingleInvolved}
reload={props.reload} // 将reload方法作为prop传递给ImageSinglePopover组件
time={props.values.trigger_time}
></ImageSinglePopover>
);
})

@ -1,66 +1,68 @@
import React, { useState } from 'react';
import { Image, Popover, Button } from 'antd';
import { CloseCircleOutlined, EllipsisOutlined, EyeOutlined, InfoCircleOutlined } from '@ant-design/icons';
import { Image } from 'antd';
import { EyeOutlined } from '@ant-design/icons';
import moment from 'moment';
interface ImageSinglePopoverProps {
src: string;
involved: any;
handleInvolved: () => void;
// handleInvolved: () => void;
reload: any;
time: any;
}
const ImageSinglePopover: React.FC<ImageSinglePopoverProps> = ({ src, involved, handleInvolved, reload}) => {
const ImageSinglePopover: React.FC<ImageSinglePopoverProps> = ({ src, involved, reload, time}) => {
const [visible, setVisible] = useState(false);
const [open, setOpen] = useState(false);
// const [open, setOpen] = useState(false);
// 定义一个方法,用于生成自定义的遮罩层
const generateMask = (text:any) => (
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
<div style={{ display: 'flex', alignItems: 'center', fontSize: 12 }}>
<EyeOutlined style={{ marginRight: 8, fontSize: 12 }} />
<div>{text}</div>
</div>
</div>
);
const content = (
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center',alignItems: 'center', height: 56}}>
{/* <div>1</div>
<div>2</div> */}
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
icon={<InfoCircleOutlined style={{ color: '#FAAD14',fontSize: 12}} />}
onClick={()=>{
// setInvolved(true)
handleInvolved();
// reload()
setOpen(false)
}}
></Button>
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
onClick={()=>{
// setInvolved(false)
handleInvolved();
// reload()
setOpen(false)
}}
></Button>
<div style={{ display: 'flex', alignItems: 'center', fontSize: 12 }}>
<EyeOutlined style={{ marginRight: 8, fontSize: 12 }} />
<div>{text}</div>
</div>
</div>
);
// const content = (
// <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center',alignItems: 'center', height: 56}}>
// {/* <div>选项1</div>
// <div>选项2</div> */}
// <Button
// type="text"
// style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
// icon={<InfoCircleOutlined style={{ color: '#FAAD14',fontSize: 12}} />}
// onClick={()=>{
// // setInvolved(true)
// // handleInvolved();
// // reload()
// setOpen(false)
// }}
// >加入重点关注</Button>
// <Button
// type="text"
// style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
// icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
// onClick={()=>{
// // setInvolved(false)
// // handleInvolved();
// // reload()
// setOpen(false)
// }}
// >移除重点关注</Button>
// </div>
// );
const handleVisibleChange = (value: boolean) => {
setVisible(value);
};
const handleOpenChange = (value: boolean) => {
setOpen(value);
};
// const handleOpenChange = (value: boolean) => {
// setOpen(value);
// };
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 140, marginRight: 12 }}>
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 160, marginRight: 12 }}>
<Image
style={{ borderRadius: 4 }}
width={140}
@ -73,7 +75,8 @@ const ImageSinglePopover: React.FC<ImageSinglePopoverProps> = ({ src, involved,
}}
src={src}
/>
<Popover
<div style={{height: 30,textAlign: 'center',lineHeight: '30px',fontWeight: 500,color: '#333'}}>{moment(time).format('YYYY-MM-DD hh:mm:ss')}</div>
{/* <Popover
placement="right"
content={content}
trigger="click"
@ -88,7 +91,7 @@ const ImageSinglePopover: React.FC<ImageSinglePopoverProps> = ({ src, involved,
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
/>
</Popover>
</Popover> */}
{involved === 1 && (
<div
style={{

@ -1,15 +1,17 @@
import React, { useState } from 'react';
import { Image, Popover, Button } from 'antd';
import { CloseCircleOutlined, EllipsisOutlined, EyeOutlined, InfoCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
interface ImageWithPopoverProps {
src: string;
involved: any;
indexId: any;
handleInvolved: (value: any,index: any) => void;
time: any;
}
const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, indexId, handleInvolved }) => {
const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, indexId, handleInvolved,time }) => {
const [visible, setVisible] = useState(false);
const [open, setOpen] = useState(false);
@ -28,7 +30,7 @@ const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, inde
<div>2</div> */}
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF',marginBottom: 4 }}
icon={<InfoCircleOutlined style={{ color: '#FAAD14',fontSize: 12}} />}
onClick={()=>{
// setInvolved(true)
@ -57,7 +59,7 @@ const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, inde
};
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 140, marginRight: 12 }}>
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 160, marginRight: 12 }}>
<Image
style={{ borderRadius: 4 }}
width={140}
@ -76,16 +78,17 @@ const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, inde
trigger="click"
style={{ width: 104, height: 64 }}
color="rgba(0, 0, 0, 0.6)"
overlayInnerStyle={{ width: 104, height: 64, padding: 4, borderRadius: 2 }}
overlayInnerStyle={{ width: 104, height: 68, padding: 4, borderRadius: 2 }}
open={open}
onOpenChange={handleOpenChange}
>
<Button
style={{ position: 'absolute', bottom: 8, right: 0 }}
style={{ position: 'absolute', bottom: 20, right: 0 }}
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
/>
</Popover>
<div style={{height: 30,textAlign: 'center',lineHeight: '30px',fontWeight: 500,color: '#333'}}>{moment(time).format('YYYY-MM-DD hh:mm:ss')}</div>
{involved === 1 && (
<div
style={{

@ -160,6 +160,7 @@ const AlarmList: React.FC = () => {
>
<Image
width={96}
height={96}
preview={false}
src={record.picture_path[0]}
/>

@ -53,7 +53,7 @@ const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, person_id,relo
};
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 96, height: 96, marginRight: 12 }}>
<div style={{ position: 'relative', boxSizing: 'border-box', width: 96, height: 96 }}>
<Image
style={{ borderRadius: 4 }}
width={96}

@ -360,7 +360,7 @@ const InvolvedList: React.FC = () => {
}}
showActions="hover"
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 2, xl: 3, xxl: 3 }}
grid={{ gutter: 16, xs: 1, md: 2, lg: 2, xl: 3, xxl: 4 }}
metas={{
type: {
// 不展示在筛选项

@ -0,0 +1,104 @@
import React, { useState } from 'react';
import { Image, Popover, Button, message } from 'antd';
import { CloseCircleOutlined, EllipsisOutlined } from '@ant-design/icons';
import { useIntl } from '@umijs/max';
import { postRecognition } from '@/services/alarm/Involved';
interface ImageWithPopoverProps {
src: string;
reload: any;
person_id: any;
}
const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, person_id,reload }) => {
const intl = useIntl();
const [visible, setVisible] = useState(false);
const [open, setOpen] = useState(false);
const content = (
<div style={{ display: 'flex', justifyContent: 'center',alignItems: 'center', height: '100%'}}>
{/* <div>1</div>
<div>2</div> */}
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
onClick={(event)=>{
event.stopPropagation();
postRecognition({
person_id: person_id,
classify: '0'
})
.then(() => {
message.success('此人已被移除重点关注');
reload();
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
});
setOpen(false)
}}
></Button>
</div>
);
const handleVisibleChange = (value: boolean) => {
setVisible(value);
};
const handleOpenChange = (value: boolean) => {
setOpen(value);
};
const handleButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
event.stopPropagation(); // 阻止事件冒泡到父组件并阻止默认事件触发
};
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 96, height: 96 }}>
<Image
style={{ borderRadius: 4 }}
width={96}
height={96}
preview={false}
src={src}
/>
<Popover
placement="right"
content={content}
trigger="click"
style={{ width: 104, height: 32 }}
color="rgba(0, 0, 0, 0.6)"
overlayInnerStyle={{ width: 104, height: 32, padding: 4, borderRadius: 2 }}
open={open}
onOpenChange={handleOpenChange}
>
<Button
style={{ position: 'absolute', bottom: 0, right: -4 }}
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
onClick={handleButtonClick}
/>
</Popover>
{/* {involved.state && (
<div
style={{
position: 'absolute',
top: 0,
right: 0,
width: 64,
height: 24,
background: '#FAAD14',
borderRadius: '0px 4px 0px 4px',
color: '#FFF',
fontSize: 12,
textAlign: 'center',
lineHeight: '24px'
}}
>
</div>
)} */}
</div>
);
};
export default ImageWithPopover;

@ -0,0 +1,26 @@
.InvolvedImgBox {
box-sizing: border-box;
// display: flex;
// justify-content: flex-start;
padding: 16px 32px;
border-top: 1px solid #E0E0E0;
.involvedImgList {
position: relative;
span {
position: absolute;
width: 2px;
height: 30px;
bottom: -30px;
left: 15px;
border-left: 2px dashed #081FA8;
}
}
}
.myButtonDisabled{
visibility: hidden;
}
.involvedModalForm {
.ant-modal .ant-modal-content {
padding: 0 !important;
}
}

@ -0,0 +1,304 @@
import { putDeviceCategoryUpdateDeviceCategory } from '@/services/device/DeviceCategory';
import { postDeviceGroupGetDeviceGroupFkSelect } from '@/services/device/DeviceGroup';
import { ModalForm, ProForm, ProFormFieldSet, ProFormSelect, ProFormSwitch, ProFormText } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, message,Image, Button, Popover, List, Avatar } from 'antd';
import React, { useEffect, useState } from 'react';
import { getUploadInvolvedTravelList, postUploadRecognition } from '@/services/alarm/Involved';
import styles from './InvolvedDetails.less'
import './InvolvedDetails.less'
import moment from 'moment';
import { CloseCircleOutlined, EllipsisOutlined } from '@ant-design/icons';
import VirtualList from 'rc-virtual-list';
import trajectoryBottom from '../../../../../public/images/involved/trajectoryBottom.png'
export type FormValueType = {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
} & Partial<API.InvolvedDetailsParams>;
export type UpdateFormProps = {
updateModalOpen: boolean;
handleModal: () => void;
values: Partial<API.InvolvedDetailsParams>;
reload: any;
};
const InvolvedDetails: React.FC<UpdateFormProps> = (props) => {
const intl = useIntl();
const [form] = Form.useForm<API.InvolvedDetailsParams>();
const [dataFlag, setDataFlag] = useState(false);;
const [open, setOpen] = useState(false);
const [trajectoryData, setTrajectoryData] = useState([]);
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
const [currentPage, setCurrentPage] = useState<number>(1);
const [total, setTotal] = useState<number>(0);
const ContainerHeight = 630;
const content = (
<div style={{ display: 'flex', justifyContent: 'center',alignItems: 'center', height: '100%'}}>
{/* <div>1</div>
<div>2</div> */}
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
onClick={(event)=>{
event.stopPropagation();
postUploadRecognition({
person_id: props.values.person_id,
classify: '0'
})
.then(() => {
message.success('此人已被移除重点关注');
props.reload();
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
});
setOpen(false)
props.handleModal()
}}
></Button>
</div>
);
const handleOpenChange = (value: boolean) => {
setOpen(value);
};
const appendData = (page: any, pageSize: any) => {
const reqParams = {
page: page,
pageSize: pageSize,
// desc: false,
person_id: props.values.person_id,
// ...rest,
};
getUploadInvolvedTravelList(reqParams).then((res) => {
console.log(res);
if(res.data.results) {
setTrajectoryData(trajectoryData.concat(res.data.results));
setTotal(res.data.count)
if(res.data.next) {
setDataFlag(true)
}else {
setDataFlag(false)
// setTrajectoryData([]); // 重置trajectoryData数据为空数组
}
}
})
.catch(() => {
// setLoading(false);
setDataFlag(false)
// setTrajectoryData([]); // 重置trajectoryData数据为空数组
});
};
const onScroll = (e: React.UIEvent<HTMLElement, UIEvent>) => {
// Refer to: https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollHeight#problems_and_solutions
console.log(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - ContainerHeight);
if (Math.abs(e.currentTarget.scrollHeight - e.currentTarget.scrollTop - ContainerHeight) <= 1) {
if(dataFlag) {
const nextPage = currentPage + 1
setCurrentPage(nextPage);
appendData(nextPage, 10);
}
}
};
useEffect(() => {
if (props.updateModalOpen) {
// 调用接口获取数据
setTrajectoryData([]); // 重置trajectoryData数据为空数组
setCurrentPage(1);
setCurrentPageSize(10);
appendData(currentPage, currentPageSize);
}
}, [props.updateModalOpen]);
return (
<ModalForm<any>
width={615}
title={
<div
style={{
display: 'flex',
alignItems: 'center',
padding: '24px 32px 0px',
justifyContent: 'flex-start',
}}
>
<div style={{ position: 'relative', boxSizing: 'border-box', width: 120, height: 120 }}>
<Image
style={{ borderRadius: 4 }}
width={120}
height={120}
preview={false}
src={props?.values?.picture_path}
/>
<Popover
placement="right"
content={content}
trigger="click"
style={{ width: 104, height: 32 }}
color="rgba(0, 0, 0, 0.6)"
overlayInnerStyle={{ width: 104, height: 32, padding: 4, borderRadius: 2 }}
open={open}
onOpenChange={handleOpenChange}
>
<Button
style={{ position: 'absolute', bottom: 0, right: -4 }}
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
// onClick={handleButtonClick}
/>
</Popover>
<div
style={{
position: 'absolute',
top: 0,
right: 0,
width: 64,
height: 24,
background: '#FAAD14',
borderRadius: '0px 4px 0px 4px',
color: '#FFF',
fontSize: 12,
textAlign: 'center',
lineHeight: '24px',
fontWeight: 400
}}
>
</div>
</div>
<div
style={{
marginLeft: 12,
height: 98,
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
color: '#666',
fontSize: 14,
fontWeight: 400
}}
>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{moment(props?.values?.classify_time).format('YYYY-MM-DD hh:mm:ss')}
</span>
</div>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{moment(props?.values?.appear_time).format('YYYY-MM-DD hh:mm:ss')}
</span>
</div>
{/* <div>
:{' '}
<span
style={{
color: '#333',
}}
>
{props?.values?.device_name}
</span>
</div> */}
</div>
</div>
}
open={props.updateModalOpen}
form={form}
autoFocusFirstInput
modalProps={{
destroyOnClose: true,
onCancel: () => {
setTrajectoryData([]);
setCurrentPage(1);
setCurrentPageSize(10);
props.handleModal()
},
wrapClassName:"involvedModalForm"
}}
submitter={false}
submitTimeout={2000}
onFinish={async (values) => {
values.is_ignore = true
values.person_id = props.values.person_id
// console.log(values);
// postIgnoringvents(values)
// .then(() => {
// message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '成功' }));
// props.reload();
// })
// .catch(() => {
// message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
// });
setTrajectoryData([]);
setCurrentPage(1);
setCurrentPageSize(10);
props.handleModal();
return true;
}}
>
{/* <ProForm.Group> */}
{/* <div className={styles.alarmDetails}>
: <span className={styles.alarmSpan}></span>: <span className={styles.alarmSpan}>广1#</span>: <span className={styles.alarmSpan}>2023-01-15 22:00:03</span>
</div> */}
<div className={styles.InvolvedImgBox}>
<List>
<VirtualList
data={trajectoryData}
height={ContainerHeight}
itemHeight={64}
itemKey="id"
onScroll={onScroll}
>
{(item: any, index:any) => (
<div key={item.person_id + index}>
<List.Item style={{ borderBottom: 0, height: 64, padding: 0 }}>
<List.Item.Meta
avatar={
<div className={styles.involvedImgList}>
<img style={{ width: 32, height: 32 }} src={trajectoryBottom} />
{index + 1 !== total && <span />}
</div>
}
title={<div style={{ lineHeight: '30px', color: '#666' }}>: <span style={{ color: '#333', marginRight: 16}}>{moment(item.appear_time).format('YYYY-MM-DD hh:mm:ss')}</span> : <span style={{ color: '#333'}}>{item.video_name}</span></div>}
/>
<div>
<Image
style={{ borderRadius: 4 }}
width={48}
height={48}
preview={{
mask: '',
}}
src={item.picture_path}
/>
</div>
</List.Item>
{index === total - 1 && (
<div style={{ textAlign: 'center', color: '#999' }}>~</div>
)}
</div>
)}
</VirtualList>
</List>
</div>
{/* </ProForm.Group> */}
</ModalForm>
);
};
export default InvolvedDetails;

@ -0,0 +1,370 @@
import { alarmRulesEnums } from '@/enums/status';
import { ActionType, PageContainer, ProCard, ProList, useIntl } from '@ant-design/pro-components';
import { Image, Modal, Tabs } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import { proTablePaginationOptions } from '../../../../config/defaultTable';
// import DeviceStatusCard from './components/DeviceStatusCard';
// import CreateForm from './components/CreateForm';
import { getUploadInvolvedList } from '@/services/alarm/Involved';
import { QuestionCircleFilled } from '@ant-design/icons';
import InvolvedDetails from './components/InvolvedDetails';
import moment from 'moment';
import ImageWithPopover from './components/ImageWithPopover';
/**
* @
* 1
*/
const tabOptions: Record<string, any> = {
singlePersonHoveringAlarm: 90,
multiplePersonGatheringAlarm: 20,
sensitiveTimePeriodAlarm: 20,
ignored: 2,
// processingStatus: 10,
// errorStatus: 20,
};
export type DeleteBoxProps = {
modalOpen: boolean;
handleModal: () => void;
values: any;
reload: any;
};
const InvolvedUploadList: React.FC = () => {
const [cardActionProps, setCardActionProps] = useState<'actions' | 'extra'>('extra');
/**
* @en-US Pop-up window of new window
* @zh-CN
* */
const [createModalOpen, setCreateModalOpen] = useState<boolean>(false);
/**
* @en-US The pop-up window of the distribution update window
* @zh-CN
* */
const [updateModalOpen, setUpdateModalOpen] = useState<boolean>(false);
/**
* @en-US The pop-up window of the distribution update window
* @zh-CN
* */
const [modalOpen, setModalOpen] = useState(false);
const [currentRow, setCurrentRow] = useState<Record<string, any>>({});
/**
* @en-US International configuration
* @zh-CN
* */
// const access = useAccess();
// const intl = useIntl();
const actionRef = useRef<ActionType>();
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
const [currentPage, setCurrentPage] = useState<number>(1);
const [total, setTotal] = useState<number>(0);
const [activeTabIndex, setActiveTabIndex] = useState<number>(0);
const [dataTestList, setdataTestList] = useState<any>([]);
const [tab, setTab] = useState<string>(alarmRulesEnums[0].key);
const [tabs, setTabs] = useState<any>([]);
// const changeProjectTab = (key: string) => {
// setTab(key);
// console.log(key);
// // eslint-disable-next-line @typescript-eslint/no-use-before-define
// initList(key)
// };
const getTabs = () => {
// if (alarmRulesEnums.length) {
// setTab(alarmRulesEnums[0].key);
// }
setTabs(alarmRulesEnums);
};
// useEffect(() => {
// getTabs();
// }, []);
const handleCreateModal = () => {
if (createModalOpen) {
setCreateModalOpen(false);
setCurrentRow(undefined);
} else {
setCreateModalOpen(true);
}
};
const handleUpdateModal = () => {
if (updateModalOpen) {
setUpdateModalOpen(false);
setCurrentRow(undefined);
} else {
setUpdateModalOpen(true);
}
};
const handleDestroy = async () => {
if (modalOpen) {
setModalOpen(false);
setCurrentRow(undefined);
} else {
setModalOpen(true);
}
// deleteBusinessImageDeleteBusinessImage({ id: selectedRow.id })
// .then(() => {
// message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
// actionRef.current?.reload();
// })
// .catch(() => {
// message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
// });
};
const { confirm } = Modal;
const showConfirm = (record: any) => {
confirm({
title: `确定删除${record.name}`,
icon: <QuestionCircleFilled />,
content: '确定删除服务器1吗删除后将找不到此服务器请谨慎操作.',
okText: '确认',
cancelText: '取消',
width: 560,
onOk() {
console.log('OK');
},
onCancel() {
console.log('Cancel');
},
});
};
// 处理初始值
function initDataTestList(dataList: Record<string, any>[]) {
console.log(dataList, 'initDataTestList');
let finalList: { content: React.JSX.Element; }[] = []
if (Array.isArray(dataList) && dataList.length) {
finalList = dataList.map((record, index) => {
return {
content: (
<ProCard
className="gn"
style={{ backgroundColor: '#F5F6FF', margin: 0, padding: 0, borderRadius: 4 }}
bodyStyle={{ margin: 0, padding: 0 }}
>
<div
style={{
display: 'flex',
alignItems: 'center',
padding: 20,
justifyContent: 'flex-start',
}}
onClick={() => {
console.log(index, 'index');
setUpdateModalOpen(true);
setCurrentRow(record);
}}
>
{/* <Image
width={96}
preview={false}
src={record.picture_path[0]}
/> */}
<ImageWithPopover
src={record.picture_path}
// eslint-disable-next-line @typescript-eslint/no-use-before-define
reload={initList}
person_id={record.person_id}
// handleInvolved={handleInvolved}
></ImageWithPopover>
<div
style={{
marginLeft: 16,
height: 90,
display: 'flex',
flexDirection: 'column',
justifyContent: 'flex-start',
color: '#666',
}}
>
{/* <div>
:{' '}
<span
style={{
color: '#333',
}}
>
{moment(record.appear_time).format('YYYY-MM-DD hh:mm:ss')}
</span>
</div> */}
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{record.video_name}
</span>
</div>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{moment(record.classify_time).format('YYYY-MM-DD hh:mm:ss')}
</span>
</div>
</div>
</div>
</ProCard>
),
};
});
}
setdataTestList(() => [...finalList]);
}
// 初始化加载
async function initList(tabId:string = '1') {
const reqParams = {
page: currentPage,
pageSize: currentPageSize,
// desc: false,
classify: tabId,
// ...rest,
};
const resp = await getUploadInvolvedList({ ...reqParams });
// console.log(resp,'resp');
// setCurrentPageSize(resp?.data?.count)
setTotal(resp?.data?.count)
initDataTestList(resp?.data?.results);
// request={async (params = {}, sort) => {
// const { current, ...rest } = params;
// const reqParams = {
// page: current,
// desc: false,
// warning_type: tab,
// ...rest,
// };
// if (sort && Object.keys(sort).length) {
// reqParams.orderKey = Object.keys(sort)[0];
// let sort_select = sort[reqParams.orderKey];
// reqParams.desc = sort_select === 'descend';
// }
// // TODO 联调查询设备状态接口
// console.log(reqParams, 'reqParams');
// let resp = await postAlarmList({ ...reqParams });
// console.log(resp, 'postAlarmList_result');
// initDataTestList(resp.result);
// // return {
// // data: resp.result,
// // success: resp.success,
// // total: resp.count,
// // current: resp.count,
// // pageSize: resp.count,
// // };
// }}
}
useEffect(() => {
getTabs();
initList();
}, []);
useEffect(() => {
// 模拟异步请求数据
initList();
}, [currentPage, currentPageSize]);
return (
<PageContainer
// title={false}
// content={
// <div style={{
// display: 'flex',
// justifyContent: 'space-between'
// }}>
// <div style={{
// fontWeight: 600,
// fontSize: 20,
// color: '#333'
// }}></div>
// </div>
// }
>
<ProCard
className="gn"
bodyStyle={{ padding: 10, margin: 0 }}
style={{ padding: 0, margin: 0 }}
>
{/* <Tabs
activeKey={tab}
items={tabs}
onChange={(key) => {
changeProjectTab(key);
}}
></Tabs> */}
<ProList<any>
className="gn"
ghost={true}
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
style: {
width: '100%',
border: 0,
// minHeight: 700
// padding: 0, margin: 0
},
}}
cardProps={{
bodyStyle: {
padding: '8px 16px 16px',
borderRadius: 8,
},
}}
pagination={{
...proTablePaginationOptions,
total: total,
current: currentPage,
pageSize: currentPageSize,
showSizeChanger: true,
onChange: (page, pageSize) => {
console.log(page, pageSize);
setCurrentPage(page)
setCurrentPageSize(pageSize)
},
}}
showActions="hover"
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 2, xl: 3, xxl: 4 }}
metas={{
type: {
// 不展示在筛选项
hideInSearch: true,
},
content: {
hideInSearch: true,
},
actions: {
cardActionProps,
},
}}
dataSource={dataTestList}
/>
</ProCard>
{/* <CreateForm
createModalOpen={createModalOpen}
values={currentRow || {}}
handleModal={handleCreateModal}
reload={actionRef.current?.reload}
/> */}
<InvolvedDetails
updateModalOpen={updateModalOpen}
values={currentRow || {}}
handleModal={handleUpdateModal}
reload={initList}
/>
</PageContainer>
);
};
export default InvolvedUploadList;

@ -0,0 +1,58 @@
import React, { useState } from 'react';
import { Button, Tag, message } from 'antd';
import { RedoOutlined } from '@ant-design/icons';
import { postTestDevice } from '@/services/alarm/Interfaces'
import moment from 'moment';
import { useIntl } from '@umijs/max';
interface ImageSinglePopoverProps {
values: any;
reload: any;
}
const CaptureButton: React.FC<ImageSinglePopoverProps> = (props) => {
const intl = useIntl();
const [loading, setLoading] = useState<boolean>(false);
const connection = () => {
setLoading(true);
postTestDevice({
device_ip: props.values.device_ip,
id: props.values.id,
})
.then((res) => {
if(res.success) {
message.success(res.msg);
}
props.reload();
setLoading(false);
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
setLoading(false);
});
};
return (
<div>
<Tag bordered={false} color={props.values.test_result === 1? "success": ""} style={{
// fontSize:14,
color: props.values.test_result === 1? '#52C41A': "#999"
}}>
{props.values.test_result === 1 ? '在线' : '离线'}
</Tag>
<span>{moment(props.values.test_time).format('YYYY-MM-DD hh:mm:ss')}</span>
<Button
type="link"
icon={<RedoOutlined />}
loading={loading}
onClick={() => {
connection()
}}
/>
</div>
);
};
export default CaptureButton;

@ -0,0 +1,24 @@
.captureImgBox {
.captureImgDescribe {
margin-bottom: 12px;
font-family: PingFang SC;
font-weight: 500;
font-size: 16px;
color: #666;
span {
color: #333;
}
}
.captureImgContent {
box-sizing: border-box;
margin-bottom: 24px;
padding: 16px;
width: 100%;
// height: 172px;
background: #F7F7F7;
border-radius: 4px;
border: 1px dashed #DCDCDC;
display: flex;
justify-content: center;
}
}

@ -0,0 +1,80 @@
import { postInterfaces, postTestDevice } from '@/services/alarm/Interfaces';
import { ModalForm, ProForm, ProFormFieldSet, ProFormSelect, ProFormSwitch, ProFormText, ProFormTextArea } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Image, Form, message } from 'antd';
import React, { useState } from 'react';
import {
proFormSmallItemStyleProps,
proFormSmallModelWidth,
} from '../../../../../config/defaultForm';
import moment from 'moment';
import styles from './CaptureForm.less'
export type FormValueType = {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
} & Partial<API.UpdateInterfacesParams>;
export type UpdateFormProps = {
captureModalOpen: boolean;
handleModal: () => void;
values: Partial<API.UpdateInterfacesParams>;
reload: any;
};
const CaptureForm: React.FC<UpdateFormProps> = (props) => {
const intl = useIntl();
const [form] = Form.useForm<API.UpdateInterfacesParams>();
return (
<ModalForm<any>
width={proFormSmallModelWidth}
title={intl.formatMessage({
id: 'device.interface_manage.table.list.capture',
defaultMessage: `最近拍摄`,
})}
open={props.captureModalOpen}
form={form}
autoFocusFirstInput
modalProps={{
destroyOnClose: true,
onCancel: () => {
props.handleModal()
},
// okText: intl.formatMessage({ id: 'common.okText', defaultMessage: '确认' }),
// cancelText: intl.formatMessage({ id: 'common.cancelText', defaultMessage: '取消' }),
}}
submitTimeout={2000}
submitter={false}
onFinish={async (values) => {
console.log(values);
values.id = props.values.id
postInterfaces(values)
.then(() => {
message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '成功' }));
props.reload();
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
});
props.handleModal();
return true;
}}
>
<div className={styles.captureImgBox}>
<div className={styles.captureImgDescribe}>: <span>{props.values.device_name}</span></div>
<div className={styles.captureImgDescribe}>: <span>{moment(props.values.appear_time).format('YYYY-MM-DD hh:mm:ss')}</span></div>
<div className={styles.captureImgContent}>
<Image
width={100}
preview={false}
src={props.values.picture_path}
/>
</div>
</div>
</ModalForm>
);
};
export default CaptureForm;

@ -6,7 +6,7 @@ import {
deleteDeviceCategoryDeleteDeviceCategory,
postDeviceCategoryGetDeviceCategoryList,
} from '@/services/device/DeviceCategory';
import { getInterfaces, postInterfaces } from '@/services/alarm/Interfaces'
import { getInterfaces, postInterfaces, postTestDevice } from '@/services/alarm/Interfaces'
import type { ActionType, ProColumns } from '@ant-design/pro-components';
import { PageContainer, ProTable } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
@ -14,9 +14,12 @@ import { Button, Space, Tag, message } from 'antd';
import React, { useRef, useState } from 'react';
import { proTablePaginationOptions } from '../../../../config/defaultTable';
import { proIconForTableActionStyle } from '../../../../config/defaultIcon';
import { EditOutlined } from '@ant-design/icons';
import { EditOutlined, InstagramOutlined, RedoOutlined } from '@ant-design/icons';
import CreateForm from './components/CreateForm';
import UpdateForm from './components/UpdateForm';
import CaptureForm from './components/CaptureForm';
import CaptureButton from './components/CaptureButton';
import moment from 'moment';
const InterfaceManageList: React.FC = () => {
/**
* @en-US International configuration
@ -64,47 +67,38 @@ const InterfaceManageList: React.FC = () => {
}
};
const getAlarmRulesList = async () => {
return {
code: 0,
success: true,
data: {
"list": [
{
"id": 1,
"createTime": "2023-10-17T02:35:41.14308Z",
"updateTime": "2023-10-17T02:35:41.14308Z",
"name": "单人徘徊告警",
"address": "https://xxxx%E5%BC%80%E5%85%B3",
"isEnabled": true,
"remark": ""
},
{
"id": 2,
"createTime": "2023-10-17T02:40:28.292883Z",
"updateTime": "2023-10-26T03:02:51.356036Z",
"name": "多人聚集告警",
"address": "https://xxxx%E5%BC%80%E5%85%B3",
"isEnabled": false,
"remark": ""
},
{
"id": 4,
"createTime": "2023-12-12T02:54:52.204957Z",
"updateTime": "2023-12-12T02:54:52.204957Z",
"name": "敏感时间段告警",
"address": "https://xxxx%E5%BC%80%E5%85%B3",
"isEnabled": false,
"remark": ""
}
],
"total": 3,
"page": 1,
"pageSize": 10
},
msg: "获取成功"
// 最近拍摄
const [captureModalOpen, setCaptureModalOpen] = useState<boolean>(false);
const handleCaptureModal = () => {
console.log(captureModalOpen);
if (captureModalOpen) {
setCaptureModalOpen(false);
setCurrentRow(undefined);
} else {
setCaptureModalOpen(true);
}
}
};
// 测试连接
const [loading, setLoading] = useState<boolean>(false);
const connection = (value: any) => {
setLoading(true);
postTestDevice({
device_ip: value.device_ip,
id: value.id,
})
.then((res) => {
if(res.success) {
message.success(res.msg);
}
setLoading(false);
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
setLoading(false);
});
};
const columns: ProColumns<API.UpdateInterfacesParams>[] = [
{
@ -112,12 +106,48 @@ const InterfaceManageList: React.FC = () => {
dataIndex: 'device_name',
hideInSearch: true,
},
{
title: <FormattedMessage id="device.interface_manage.table.list.address" defaultMessage="接口地址" />,
dataIndex: 'device_api',
title: <FormattedMessage id="alarm_rules.page.status" defaultMessage="设备状态" />,
dataIndex: 'test_result',
hideInSearch: true,
render: (dom,entity) => {
return (
// <div>
// <Tag bordered={false} color={dom === 1? "success": ""} style={{
// // fontSize:14,
// color: dom === 1? '#52C41A': "#999"
// }}>
// {dom === 1 ? '在线' : '离线'}
// </Tag>
// <span>{moment(entity.appear_time).format('YYYY-MM-DD hh:mm:ss')}</span>
// <Button
// type="link"
// icon={<RedoOutlined />}
// loading={loading}
// onClick={() => {
// connection(entity)
// }}
// />
// </div>
<CaptureButton
values={entity || {}}
reload={actionRef.current?.reload}
/>
);
},
},
// {
// title: <FormattedMessage id="device.interface_manage.table.list.address" defaultMessage="接口地址" />,
// dataIndex: 'device_api',
// hideInSearch: true,
// },
// {
// title: <FormattedMessage id="device.interface_manage.table.list.testTime" defaultMessage="状态查询时间" />,
// dataIndex: 'test_time',
// sorter: true,
// hideInSearch: true,
// valueType: 'dateTime',
// },
{
title: <FormattedMessage id="device.interface_manage.table.list.createTime" defaultMessage="创建时间" />,
dataIndex: 'create_time',
@ -130,11 +160,36 @@ const InterfaceManageList: React.FC = () => {
title: <FormattedMessage id="pages.searchTable.titleOption" defaultMessage="操作" />,
dataIndex: 'option',
valueType: 'option',
width: '260px',
fixed: 'right',
render: (_, record) => [
<TableActionCard
key="TableActionCardRef"
renderActions={[
{
key: 'capture',
renderDom: (
<Button
key="capture"
type="link"
size="small"
style={{
color:"#081FA8",
}}
icon={<InstagramOutlined style={{
marginRight: 3
}} />}
onClick={() => {
console.log('11');
setCaptureModalOpen(true);
setCurrentRow(record);
}}
>
{/* 最近拍摄 */}
<FormattedMessage id="device.interface_manage.table.list.capture" defaultMessage="最近拍摄" />
</Button>
),
},
{
key: 'update',
renderDom: (
@ -144,7 +199,6 @@ const InterfaceManageList: React.FC = () => {
size="small"
style={{
color:"#081FA8",
}}
icon={<EditOutlined style={{
marginRight: 3
@ -157,7 +211,7 @@ const InterfaceManageList: React.FC = () => {
<FormattedMessage id="common.edit" defaultMessage="编辑" />
</Button>
),
},
},
{
key: 'destroy',
renderDom: (
@ -177,23 +231,23 @@ const InterfaceManageList: React.FC = () => {
<PageContainer
title={false}
content={
<div style={{
display: 'flex',
justifyContent: 'space-between'
}}>
<div style={{
fontWeight: 600,
fontSize: 20,
color: '#333'
}}></div>
<Button type="primary"
onClick={() => {
setCreateModalOpen(true);
}}
>
<FormattedMessage id="device.interface_manage.table.list.add" defaultMessage="新建设备/输入源" />
</Button>
</div>
<div style={{
display: 'flex',
justifyContent: 'space-between'
}}>
<div style={{
fontWeight: 600,
fontSize: 20,
color: '#333'
}}></div>
<Button type="primary"
onClick={() => {
setCreateModalOpen(true);
}}
>
<FormattedMessage id="device.interface_manage.table.list.add" defaultMessage="新建设备/输入源" />
</Button>
</div>
}
>
<ProTable<API.DeviceCategory>
@ -255,6 +309,12 @@ const InterfaceManageList: React.FC = () => {
handleModal={handleUpdateModal}
reload={actionRef.current?.reload}
/>
<CaptureForm
captureModalOpen={captureModalOpen}
values={currentRow || {}}
handleModal={handleCaptureModal}
reload={actionRef.current?.reload}
/>
</PageContainer>
);
};

@ -194,6 +194,26 @@ const Login: React.FC = () => {
"component": "Hidden",
"title": "用户列表",
"routes": []
},
{
"path": "videoAnalysis",
"key": "",
"name": "videoAnalysis",
"icon": "VideoCameraOutlined",
"access": "",
"component": "Hidden",
"title": "视频分析",
"routes": []
},
{
"path": "involved-list-upload",
"key": "",
"name": "involved-list-upload",
"icon": "FileSearchOutlined",
"access": "",
"component": "Hidden",
"title": "重点关注(上传)",
"routes": []
}
]
},

@ -0,0 +1,84 @@
.alarmImgBox {
// display: flex;
// justify-content: flex-start;
.alarmImgLeft {
position: relative;
margin-right: 32px;
width: 120px;
// height: 600px;
.alarmImgLeftBox{
width: 112px;
height: 112px;
border-radius: 4px;
// background: skyblue;
}
.alarmImgLeftBoxActive {
width: 112px;
height: 112px;
border-radius: 4px;
border: 1.5px solid #081FA8;
}
.shadowBox {
position: absolute;
left: 0;
bottom: 0px;
width: 112px;
height: 20px;
background: #FFF;
z-index: 999;
}
}
.alarmImgRight{
flex: 1;
position: relative;
.alarmImgRightTopBox {
width: 640px;
height: 640px;
background: skyblue;
}
.alarmDetails {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 38px;
padding-left: 24px;
line-height: 38px;
margin-bottom: 16px;
font-family: PingFang SC;
font-size: 16px;
font-weight: 400;
color: #FFFFFF;
background: rgba(0, 0, 0, 0.6);
.alarmSpan {
// color: #333;
margin-right: 24px;
}
}
}
.alarmImgDescribe {
margin-bottom: 12px;
font-family: PingFang SC;
font-weight: 500;
font-size: 16px;
color: #666;
span {
color: #333;
}
}
.alarmImgContent {
box-sizing: border-box;
margin-bottom: 24px;
padding: 16px;
width: 784px;
// height: 172px;
background: #F7F7F7;
border-radius: 4px;
border: 1px dashed #DCDCDC;
display: flex;
justify-content: center;
}
}
.myButtonDisabled{
visibility: hidden;
}

@ -0,0 +1,305 @@
import { ModalForm, ProForm, ProFormFieldSet, ProFormSelect, ProFormSwitch, ProFormText } from '@ant-design/pro-components';
import { FormattedMessage, useIntl } from '@umijs/max';
import { Form, message,Image, Button, Popover } from 'antd';
import React, { useEffect, useState } from 'react';
import { postIgnoringvents } from '@/services/alarm/Alarmlist';
import { postUploadRecognition } from '@/services/alarm/Involved';
// Import Swiper React components
// import { Swiper, SwiperSlide } from 'swiper/react';
// import { Navigation, Pagination, Mousewheel } from 'swiper/modules';
// Import Swiper styles
import 'swiper/css';
import 'swiper/css/navigation';
import 'swiper/css/pagination';
import styles from './AlarmDetails.less'
import moment from 'moment';
import ImageWithPopover from './ImageWithPopover';
import ImageSinglePopover from './ImageSinglePopover';
export type FormValueType = {
target?: string;
template?: string;
type?: string;
time?: string;
frequency?: string;
} & Partial<API.AlarmDetailsParams>;
export type UpdateFormProps = {
updateModalOpen: boolean;
handleModal: () => void;
values: Partial<API.AlarmDetailsParams>;
reload: any;
warning_type: any;
};
const UpdateForm: React.FC<UpdateFormProps> = (props) => {
const intl = useIntl();
const [form] = Form.useForm<API.AlarmDetailsParams>();
// const [isActive, setIsActive] = useState(0);
const [imageSrc, setImageSrc] = useState('');
// const [visible, setVisible] = useState(false);
const [involved, setInvolved] = useState(0);
// const [involvedInfo, setInvolvedInfo] = useState([...(props?.values?.person_list || [])]);
const [involvedInfo, setInvolvedInfo] = useState<any[]>([]);
// useEffect(() => {
// if (props.values?.person_list) {
// setInvolvedInfo([...props.values.person_list]);
// }
// }, [props.values?.person_list]);
// console.log(object);
// if(props.warning_type === '1') {
// console.log('props.values?.warning_type1');
// setInvolved(props.values.person_list[0][2]);
// }else {
// console.log('props.values?.warning_type2');
// // setInvolvedInfo([...props.values.person_list]);
// }
const handlePostRecognition = (person_id: any, classify: any) => {
postUploadRecognition({
person_id: person_id,
classify: classify
})
.then((res) => {
console.log(res.data.classify,'res.data.classify');
if(res.data.classify === 1) {
message.success('此人已被设为重点关注');
}else {
message.success('此人已被移除重点关注');
}
props.reload();
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
});
};
/** 多人告警组件 */
const handleInvolved = (value: any, index: any) => {
const updatedInvolvedInfo = [...involvedInfo];
console.log(updatedInvolvedInfo);
updatedInvolvedInfo[index][2] = value;
setInvolvedInfo(updatedInvolvedInfo);
handlePostRecognition(updatedInvolvedInfo[index][0], value)
};
/** 单人告警组件 */
// const handleSingleInvolved = () => {
// if (involved === 1) {
// setInvolved(0);
// handlePostRecognition(props.values?.person_id, 0)
// } else {
// setInvolved(1);
// handlePostRecognition(props.values?.person_id, 1)
// }
// }
// const [open, setOpen] = useState(false);
useEffect(() => {
// console.log(Array.isArray(props.values?.person_id),'Array.isArray(props.values?.person_id)');
// setImageSrc(props?.values?.picture_path?.[0])
if(props.updateModalOpen) {
if(props.warning_type === '1') {
console.log('props.values?.warning_type1');
setInvolved(props.values.person_list[0][2]);
}else {
console.log('props.values?.warning_type2');
setInvolvedInfo([...props.values.person_list]);
}
}
}, [props.updateModalOpen])
return (
<ModalForm<any>
width={832}
title={`${props.values.warning_name}告警`}
open={props.updateModalOpen}
form={form}
autoFocusFirstInput
modalProps={{
destroyOnClose: true,
onCancel: () => {
setInvolved(0);
props.handleModal()
},
okText: intl.formatMessage({ id: 'common.yes', defaultMessage: '确认' }),
cancelText: intl.formatMessage({ id: 'common.no', defaultMessage: '取消' }),
}}
submitter={{
// resetButtonProps: {
// style: {
// display: 'none',
// },
// },
// searchConfig: {
// submitText: '忽略此事件',
// },
render: (prop) => {
return [
<Button
key="ok"
style={{ backgroundColor: '#E80D0D',color: '#FFF',borderBlockColor: '#E80D0D' }}
onClick={() => {
prop.submit();
}}
>
</Button>,
props.warning_type === '2' ? null : (
<Button
key="involved"
style={{ backgroundColor: '#FAAD14',color: '#FFF',borderBlockColor: '#FAAD14' }}
onClick={() => {
// console.log(props.updateModalOpen);
setInvolved(1);
handlePostRecognition(props.values?.person_list[0][0], 1)
}}
>
</Button>
),
props.warning_type === '2' ? null : (
<Button
key="noInvolved"
style={{ background: '#FFF',color: '#E80D0D',borderColor: '#E80D0D' }}
onClick={() => {
// console.log(props.updateModalOpen);
setInvolved(0);
handlePostRecognition(props.values?.person_list[0][0], 0)
}}
>
</Button>
)
];
},
}}
submitTimeout={2000}
onFinish={async (values) => {
values.is_ignore = true
values.person_id = props.values.person_id
// console.log(values);
postIgnoringvents(values)
.then(() => {
message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '成功' }));
props.reload();
})
.catch(() => {
message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '失败' }));
});
props.handleModal();
return true;
}}
>
{/* <ProForm.Group> */}
<div className={styles.alarmImgBox}>
<div className={styles.alarmImgDescribe}>: <span>{props.values.origin}</span></div>
<div className={styles.alarmImgDescribe}>: <span className={styles.alarmSpan}>{moment(props.values.trigger_time).format('YYYY-MM-DD hh:mm:ss')}</span></div>
<div className={styles.alarmImgContent}>
{Array.isArray(props.values?.person_id_list)}
{props.warning_type === '2' ? (
Array.isArray(involvedInfo) && involvedInfo.length ? (
involvedInfo.map((item: any, index: any) => {
return (
<ImageWithPopover
src={item?.[1]}
involved={involvedInfo[index][2]}
key={index}
indexId={index}
handleInvolved={handleInvolved}
time={props.values.trigger_time}
></ImageWithPopover>
);
})
) : (
Array.isArray(props?.values?.picture_path) && props?.values?.picture_path.length ? (
props.values.picture_path.map((item: any, index: any) => {
return (
<ImageSinglePopover
src={item}
involved={involved}
key={index}
// handleInvolved={handleSingleInvolved}
reload={props.reload} // 将reload方法作为prop传递给ImageSinglePopover组件
time={props.values.trigger_time}
></ImageSinglePopover>
);
})
) : null
)
) : (
Array.isArray(props?.values?.picture_path) && props?.values?.picture_path.length ? (
props.values.picture_path.map((item: any, index: any) => {
return (
<ImageSinglePopover
src={item}
involved={involved}
key={index}
// handleInvolved={handleSingleInvolved}
reload={props.reload} // 将reload方法作为prop传递给ImageSinglePopover组件
time={props.values.trigger_time}
></ImageSinglePopover>
);
})
) : null
)}
{/* { Array.isArray(involvedInfo) && involvedInfo.length && involvedInfo.map((item: any, index: any) => {
console.log(involvedInfo,'item');
return(<ImageWithPopover src={item?.[1]} involved={involvedInfo[index][2]} key={index} indexId={index} handleInvolved={handleInvolved}></ImageWithPopover>)
})} */}
</div>
{/* <div className={styles.alarmImgLeft}>
<Swiper
style={{height:660}}
slidesPerView={5}
spaceBetween={20}
direction='vertical'
mousewheel={true}
modules={[Mousewheel]}
onSlideChange={() => {
console.log(111);
}}
// pagination={{
// clickable: true,
// }}
// modules={[Pagination]}
>
{ Array.isArray(props?.values?.picture_path) && props?.values?.picture_path.length && props?.values?.picture_path.map((item: any, index: any) => {
return (<SwiperSlide key={index} virtualIndex={index} onClick={() => {
console.log(index);
setIsActive(index)
setImageSrc(item)
}}>
<div className={ styles.alarmImgLeftBox }>
<Image
style={{
width: 112,
height: 112,
borderRadius: 4
}}
className={ index === isActive ? styles.alarmImgLeftBoxActive : '' }
preview={false}
src={item}
/>
</div>
</SwiperSlide>)
})}
</Swiper>
<div className={styles.shadowBox}></div>
</div>
<div className={styles.alarmImgRight}>
<div className={styles.alarmImgRightTopBox}>
<Image
width={640}
height={640}
preview={false}
src={imageSrc}
/>
</div>
<div className={styles.alarmDetails}>
: <span className={styles.alarmSpan}>{props.values.device_name}</span>: <span className={styles.alarmSpan}>{moment(props.values.trigger_time).format('YYYY-MM-DD hh:mm:ss')}</span>
</div>
</div> */}
</div>
{/* </ProForm.Group> */}
</ModalForm>
);
};
export default UpdateForm;

@ -0,0 +1,117 @@
import React, { useState } from 'react';
import { Image } from 'antd';
import { EyeOutlined } from '@ant-design/icons';
import moment from 'moment';
interface ImageSinglePopoverProps {
src: string;
involved: any;
// handleInvolved: () => void;
reload: any;
time: any;
}
const ImageSinglePopover: React.FC<ImageSinglePopoverProps> = ({ src, involved, reload, time}) => {
const [visible, setVisible] = useState(false);
// const [open, setOpen] = useState(false);
// 定义一个方法,用于生成自定义的遮罩层
const generateMask = (text:any) => (
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
<div style={{ display: 'flex', alignItems: 'center', fontSize: 12 }}>
<EyeOutlined style={{ marginRight: 8, fontSize: 12 }} />
<div>{text}</div>
</div>
</div>
);
// const content = (
// <div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center',alignItems: 'center', height: 56}}>
// {/* <div>选项1</div>
// <div>选项2</div> */}
// <Button
// type="text"
// style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
// icon={<InfoCircleOutlined style={{ color: '#FAAD14',fontSize: 12}} />}
// onClick={()=>{
// // setInvolved(true)
// // handleInvolved();
// // reload()
// setOpen(false)
// }}
// >加入重点关注</Button>
// <Button
// type="text"
// style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
// icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
// onClick={()=>{
// // setInvolved(false)
// // handleInvolved();
// // reload()
// setOpen(false)
// }}
// >移除重点关注</Button>
// </div>
// );
const handleVisibleChange = (value: boolean) => {
setVisible(value);
};
// const handleOpenChange = (value: boolean) => {
// setOpen(value);
// };
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 160, marginRight: 12 }}>
<Image
style={{ borderRadius: 4 }}
width={140}
height={140}
preview={{
visible,
src,
onVisibleChange: handleVisibleChange,
mask: generateMask("点击可预览大图"),
}}
src={src}
/>
<div style={{height: 30,textAlign: 'center',lineHeight: '30px',fontWeight: 500,color: '#333'}}>{moment(time).format('YYYY-MM-DD hh:mm:ss')}</div>
{/* <Popover
placement="right"
content={content}
trigger="click"
style={{ width: 104, height: 64 }}
color="rgba(0, 0, 0, 0.6)"
overlayInnerStyle={{ width: 104, height: 64, padding: 4, borderRadius: 2 }}
open={open}
onOpenChange={handleOpenChange}
>
<Button
style={{ position: 'absolute', bottom: 8, right: 0 }}
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
/>
</Popover> */}
{involved === 1 && (
<div
style={{
position: 'absolute',
top: 0,
right: 0,
width: 64,
height: 24,
background: '#FAAD14',
borderRadius: '0px 4px 0px 4px',
color: '#FFF',
fontSize: 12,
textAlign: 'center',
lineHeight: '24px'
}}
>
</div>
)}
</div>
);
};
export default ImageSinglePopover;

@ -0,0 +1,115 @@
import React, { useState } from 'react';
import { Image, Popover, Button } from 'antd';
import { CloseCircleOutlined, EllipsisOutlined, EyeOutlined, InfoCircleOutlined } from '@ant-design/icons';
import moment from 'moment';
interface ImageWithPopoverProps {
src: string;
involved: any;
indexId: any;
handleInvolved: (value: any,index: any) => void;
time: any;
}
const ImageWithPopover: React.FC<ImageWithPopoverProps> = ({ src, involved, indexId, handleInvolved,time }) => {
const [visible, setVisible] = useState(false);
const [open, setOpen] = useState(false);
// 定义一个方法,用于生成自定义的遮罩层
const generateMask = (text:any) => (
<div style={{ position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>
<div style={{ display: 'flex', alignItems: 'center', fontSize: 12 }}>
<EyeOutlined style={{ marginRight: 8, fontSize: 12 }} />
<div>{text}</div>
</div>
</div>
);
const content = (
<div style={{ display: 'flex', flexDirection: 'column', justifyContent: 'center',alignItems: 'center', height: 56}}>
{/* <div>1</div>
<div>2</div> */}
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF',marginBottom: 4 }}
icon={<InfoCircleOutlined style={{ color: '#FAAD14',fontSize: 12}} />}
onClick={()=>{
// setInvolved(true)
handleInvolved(1, indexId);
setOpen(false)
}}
></Button>
<Button
type="text"
style={{ height:22, padding: 0,fontSize: 12,color: '#FFF' }}
icon={<CloseCircleOutlined style={{ color: '#E80D0D',fontSize: 12}} />}
onClick={()=>{
// setInvolved(false)
handleInvolved(0, indexId);
setOpen(false)
}}
></Button>
</div>
);
const handleVisibleChange = (value: boolean) => {
setVisible(value);
};
const handleOpenChange = (value: boolean) => {
setOpen(value);
};
return (
<div style={{ position: 'relative', boxSizing: 'border-box', width: 140, height: 160, marginRight: 12 }}>
<Image
style={{ borderRadius: 4 }}
width={140}
height={140}
preview={{
visible,
src,
onVisibleChange: handleVisibleChange,
mask: generateMask("点击可预览大图"),
}}
src={src}
/>
<Popover
placement="right"
content={content}
trigger="click"
style={{ width: 104, height: 64 }}
color="rgba(0, 0, 0, 0.6)"
overlayInnerStyle={{ width: 104, height: 68, padding: 4, borderRadius: 2 }}
open={open}
onOpenChange={handleOpenChange}
>
<Button
style={{ position: 'absolute', bottom: 20, right: 0 }}
type="text"
icon={<EllipsisOutlined style={{ color: '#fff', fontSize: 24, transform: 'rotate(90deg)' }} />}
/>
</Popover>
<div style={{height: 30,textAlign: 'center',lineHeight: '30px',fontWeight: 500,color: '#333'}}>{moment(time).format('YYYY-MM-DD hh:mm:ss')}</div>
{involved === 1 && (
<div
style={{
position: 'absolute',
top: 0,
right: 0,
width: 64,
height: 24,
background: '#FAAD14',
borderRadius: '0px 4px 0px 4px',
color: '#FFF',
fontSize: 12,
textAlign: 'center',
lineHeight: '24px'
}}
>
</div>
)}
</div>
);
};
export default ImageWithPopover;

@ -0,0 +1,486 @@
import { alarmVideoAnalysis } from '@/enums/status';
import { ActionType, PageContainer, ProCard, ProList, useIntl } from '@ant-design/pro-components';
import { Button, DatePicker, Image, Modal, Tabs, Upload } from 'antd';
import React, { useEffect, useRef, useState } from 'react';
import { proTablePaginationOptions } from '../../../config/defaultTable';
// import DeviceStatusCard from './components/DeviceStatusCard';
// import CreateForm from './components/CreateForm';
import { postUploadAlarmList } from '@/services/alarm/Alarmlist';
import { LoadingOutlined, PlusOutlined, QuestionCircleFilled } from '@ant-design/icons';
import AlarmDetails from './components/AlarmDetails';
import moment from 'moment';
import { FormattedMessage } from '@umijs/max';
import type { DatePickerProps, UploadProps } from 'antd';
import locale from 'antd/es/date-picker/locale/zh_CN';
// import dayjs from 'dayjs';
// import 'dayjs/locale/zh-cn';
/**
* @
* 1
*/
const tabOptions: Record<string, any> = {
singlePersonHoveringAlarm: 90,
multiplePersonGatheringAlarm: 20,
sensitiveTimePeriodAlarm: 20,
ignored: 2,
// processingStatus: 10,
// errorStatus: 20,
};
export type DeleteBoxProps = {
modalOpen: boolean;
handleModal: () => void;
values: any;
reload: any;
};
const VideoAnalysis: React.FC = () => {
const [cardActionProps, setCardActionProps] = useState<'actions' | 'extra'>('extra');
/**
* @en-US Pop-up window of new window
* @zh-CN
* */
const [createModalOpen, setCreateModalOpen] = useState<boolean>(false);
/**
* @en-US The pop-up window of the distribution update window
* @zh-CN
* */
const [updateModalOpen, setUpdateModalOpen] = useState<boolean>(false);
/**
* @en-US The pop-up window of the distribution update window
* @zh-CN
* */
const [modalOpen, setModalOpen] = useState(false);
const [currentRow, setCurrentRow] = useState<Record<string, any>>({});
/**
* @en-US International configuration
* @zh-CN
* */
// const access = useAccess();
// const intl = useIntl();
const actionRef = useRef<ActionType>();
const [loading, setLoading] = useState(false);
// 动态设置每页数量
const [currentPageSize, setCurrentPageSize] = useState<number>(10);
const [currentPage, setCurrentPage] = useState<number>(1);
const [total, setTotal] = useState<number>(0);
const [activeTabIndex, setActiveTabIndex] = useState<number>(0);
const [dataTestList, setdataTestList] = useState<any>([]);
const [tab, setTab] = useState<string>(alarmVideoAnalysis[0].key);
const [tabs, setTabs] = useState<any>([]);
const changeProjectTab = (key: string) => {
setTab(key);
console.log(key);
// eslint-disable-next-line @typescript-eslint/no-use-before-define
initList(key)
};
const getTabs = () => {
// if (alarmVideoAnalysis.length) {
// setTab(alarmVideoAnalysis[0].key);
// }
setTabs(alarmVideoAnalysis);
};
// useEffect(() => {
// getTabs();
// }, []);
const handleCreateModal = () => {
if (createModalOpen) {
setCreateModalOpen(false);
setCurrentRow(undefined);
} else {
setCreateModalOpen(true);
}
};
const handleUpdateModal = () => {
if (updateModalOpen) {
setUpdateModalOpen(false);
setCurrentRow(undefined);
} else {
setUpdateModalOpen(true);
}
};
const handleDestroy = async () => {
if (modalOpen) {
setModalOpen(false);
setCurrentRow(undefined);
} else {
setModalOpen(true);
}
// deleteBusinessImageDeleteBusinessImage({ id: selectedRow.id })
// .then(() => {
// message.success(intl.formatMessage({ id: 'common.success', defaultMessage: '$$$' }));
// actionRef.current?.reload();
// })
// .catch(() => {
// message.error(intl.formatMessage({ id: 'common.failure', defaultMessage: '$$$' }));
// });
};
const { confirm } = Modal;
const showConfirm = (record: any) => {
confirm({
title: `确定删除${record.name}`,
icon: <QuestionCircleFilled />,
content: '确定删除服务器1吗删除后将找不到此服务器请谨慎操作.',
okText: '确认',
cancelText: '取消',
width: 560,
onOk() {
console.log('OK');
},
onCancel() {
console.log('Cancel');
},
});
};
// 处理初始值
function initDataTestList(dataList: Record<string, any>[]) {
console.log(dataList, 'initDataTestList');
let finalList: { content: React.JSX.Element; }[] = []
if (Array.isArray(dataList) && dataList.length) {
finalList = dataList.map((record, index) => {
return {
content: (
<ProCard
className="gn"
style={{ backgroundColor: '#F5F6FF', margin: 0, padding: 0, borderRadius: 4 }}
bodyStyle={{ margin: 0, padding: 0 }}
>
<div
style={{
display: 'flex',
alignItems: 'center',
padding: 20,
justifyContent: 'flex-start',
}}
onClick={() => {
console.log('11111111111111111');
setUpdateModalOpen(true);
setCurrentRow(record);
}}
>
<Image
width={96}
height={96}
preview={false}
src={record.picture_path[0]}
/>
<div
style={{
marginLeft: 16,
height: 90,
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
color: '#666',
}}
>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{record.warning_name}
</span>
</div>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{record.origin}
</span>
</div>
<div>
:{' '}
<span
style={{
color: '#333',
}}
>
{moment(record.trigger_time).format('YYYY-MM-DD hh:mm:ss')}
</span>
</div>
</div>
</div>
</ProCard>
),
};
});
}
setdataTestList(() => [...finalList]);
}
// 初始化加载
async function initList(tabId:string = tab) {
const reqParams = {
page: currentPage,
pageSize: currentPageSize,
// desc: false,
warning_type: tabId,
// ...rest,
};
const resp = await postUploadAlarmList({ ...reqParams });
// console.log(resp,'resp');
// setCurrentPageSize(resp?.data?.count)
setTotal(resp?.data?.count)
initDataTestList(resp?.data?.results);
// request={async (params = {}, sort) => {
// const { current, ...rest } = params;
// const reqParams = {
// page: current,
// desc: false,
// warning_type: tab,
// ...rest,
// };
// if (sort && Object.keys(sort).length) {
// reqParams.orderKey = Object.keys(sort)[0];
// let sort_select = sort[reqParams.orderKey];
// reqParams.desc = sort_select === 'descend';
// }
// // TODO 联调查询设备状态接口
// console.log(reqParams, 'reqParams');
// let resp = await postUploadAlarmList({ ...reqParams });
// console.log(resp, 'postAlarmList_result');
// initDataTestList(resp.result);
// // return {
// // data: resp.result,
// // success: resp.success,
// // total: resp.count,
// // current: resp.count,
// // pageSize: resp.count,
// // };
// }}
}
const handleChange: UploadProps['onChange'] = (info) => {
if (info.file.status === 'uploading') {
setLoading(true);
return;
}
if (info.file.status === 'done') {
// Get this url from response in real world.
setTimeout(()=> {
setLoading(false);
}, 1000)
// getBase64(info.file.originFileObj as FileType, (url) => {
// // setImageUrl(url);
// });
}
};
const onChange: DatePickerProps['onChange'] = (date, dateString) => {
console.log(date, dateString);
};
useEffect(() => {
getTabs();
initList();
}, []);
useEffect(() => {
// 模拟异步请求数据
initList();
}, [currentPage, currentPageSize]);
return (
<PageContainer
// title={false}
// content={
// <div style={{
// display: 'flex',
// justifyContent: 'space-between'
// }}>
// <div style={{
// fontWeight: 600,
// fontSize: 20,
// color: '#333'
// }}>视频分析</div>
// <Upload name="logo" action="/api/upload_warning_info/" showUploadList={false} onChange={handleChange}>
// <Button type="primary"
// onClick={() => {
// // setCreateModalOpen(true);
// }}
// >
// {loading ? <LoadingOutlined /> : null}
// 导入视频
// </Button>
// </Upload>
// </div>
// }
>
<ProCard
className="gn"
bodyStyle={{ padding: 10, margin: 0 }}
style={{ padding: 0, margin: 0 }}
>
<Tabs
activeKey={tab}
items={tabs}
onChange={(key) => {
changeProjectTab(key);
}}
></Tabs>
<div style={{ padding: '16px 16px 0'}}>
<DatePicker locale={locale} onChange={onChange} />
<Button type="primary"
style={{ margin: '0 16px' }}
onClick={() => {
// setCreateModalOpen(true);
}}
>
</Button>
<Button type="primary"
onClick={() => {
// setCreateModalOpen(true);
}}
>
</Button>
</div>
<ProList<any>
className="gn"
ghost={true}
itemCardProps={{
ghost: true,
bodyStyle: { padding: 0, margin: 0 },
style: {
width: '100%',
border: 0,
// minHeight: 700
// padding: 0, margin: 0
},
}}
// search={{
// labelWidth: proTableCommonOptions.searchLabelWidth,
// }}
// headerTitle={
// <>
// <div>
// {Object.keys(tabOptions).map((item, index) => {
// // eslint-disable-next-line react/jsx-key
// return (
// <Button
// style={{ marginRight: 12,border: 'none' }}
// // type={activeTabIndex === index ? 'primary' : 'default'}
// key={index}
// onClick={() => {
// setActiveTabIndex(index);
// }}
// >
// {Object.keys(alarmVideoAnalysis).includes(item)
// ? alarmVideoAnalysis[item].miniName
// : ''}
// {"("+tabOptions[item]+ ')'}
// </Button>
// );
// })}
// </div>
// </>
// }
cardProps={{
bodyStyle: {
padding: '8px 16px 16px',
borderRadius: 8,
},
}}
pagination={{
...proTablePaginationOptions,
total: total,
current: currentPage,
pageSize: currentPageSize,
showSizeChanger: true,
onChange: (page, pageSize) => {
console.log(page, pageSize);
setCurrentPage(page)
setCurrentPageSize(pageSize)
},
}}
showActions="hover"
rowSelection={false}
grid={{ gutter: 16, xs: 1, md: 2, lg: 2, xl: 3, xxl: 3 }}
metas={{
type: {
// 不展示在筛选项
hideInSearch: true,
},
content: {
hideInSearch: true,
},
actions: {
cardActionProps,
},
// status1: {
// // 自己扩展的字段,主要用于筛选,不在列表中显示
// title: '设备组',
// valueType: 'select',
// valueEnum: {
// '0': { text: '全部设备分组', status: '0' },
// '1': {
// text: '设备分组1',
// status: '1',
// },
// '2': {
// text: '设备分组2',
// status: '2',
// },
// '3': {
// text: '设备分组3',
// status: '3',
// },
// },
// },
// status2: {
// // 自己扩展的字段,主要用于筛选,不在列表中显示
// title: '分类',
// valueType: 'select',
// valueEnum: {
// '0': { text: '全部分类', status: '0' },
// '1': {
// text: '外围监控',
// status: '1',
// },
// '2': {
// text: '室内监控',
// status: '2',
// },
// '3': {
// text: '违规监控',
// status: '3',
// },
// },
// },
}}
dataSource={dataTestList}
/>
</ProCard>
{/* <CreateForm
createModalOpen={createModalOpen}
values={currentRow || {}}
handleModal={handleCreateModal}
reload={actionRef.current?.reload}
/> */}
<AlarmDetails
updateModalOpen={updateModalOpen}
values={currentRow || {}}
handleModal={handleUpdateModal}
reload={initList}
warning_type={tab}
/>
</PageContainer>
);
};
export default VideoAnalysis;

@ -37,4 +37,24 @@ export async function postIgnoringvents(
...(options || {}),
},
);
}
/** 上传告警列表 */
export async function postUploadAlarmList(
params: API.SearchAlarmListParams,
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/upload_warning_info/`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...params,
},
...(options || {}),
},
);
}

@ -58,4 +58,62 @@ export async function postRecognition(
...(options || {}),
},
);
}
/** 上传重点关注列表 */
export async function getUploadInvolvedList(
params: API.SearchInvolvedParams,
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/upload_recognition_people/`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...params,
},
...(options || {}),
},
);
}
/** 上传任务轨迹列表 */
export async function getUploadInvolvedTravelList(
params: API.SearchInvolvedTravelParams,
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/upload_travel_track/`,
{
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
params: {
...params,
},
...(options || {}),
},
);
}
/** 上传关注与取消关注 */
export async function postUploadRecognition(
body: API.RecognitionParams,
options?: { [key: string]: any },
) {
return request<API.Response & { data?: API.PageResult; msg?: string }>(
`/api/upload_recognition_people/`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
data: body,
...(options || {}),
},
);
}

@ -80,7 +80,9 @@ declare namespace API {
device_ip?: string; // IP地址
note?: string; // 备注
device_status?: string; // 设备状态
id?: string;
id?: string;
appear_time?: string; // 设备状态
picture_path?: string;
}
type AlarmDetailsParams = {
warning_name?: string; // 设备名称
@ -90,6 +92,9 @@ declare namespace API {
trigger_time?: string;
person_list?: any;
person_classify?: any;
warning_type?: any;
origin?: any;
person_id_list?: any;
}
type IgnoringventsParams = {
is_ignore?: any; // 设备代码 // 是否启用

@ -14,7 +14,8 @@ import {CarOutlined, UserOutlined, TableOutlined,
PictureOutlined,
OrderedListOutlined,
BranchesOutlined,
FileSearchOutlined
FileSearchOutlined,
VideoCameraOutlined
} from '@ant-design/icons';
const iconMap:any = {
@ -43,7 +44,8 @@ const iconMap:any = {
'PictureOutlined': <PictureOutlined/>,
'OrderedListOutlined':<OrderedListOutlined />,
'BranchesOutlined': <BranchesOutlined />,
'FileSearchOutlined': <FileSearchOutlined />
'FileSearchOutlined': <FileSearchOutlined />,
'VideoCameraOutlined': <VideoCameraOutlined />
}
// FIX从接口获取菜单时icon为string类型
const fixMenuItemIcon = (menus: MenuDataItem[], iconType = 'Outlined'): MenuDataItem[] => {

Loading…
Cancel
Save