Merge branch 'hongbo/file-cabinet' into 'develop'

feat: 预警记录 图片od

See merge request web-project/zhst-lambo!19
This commit is contained in:
江志雄 2024-04-23 17:20:17 +08:00
commit 91315d4a9f
19 changed files with 182 additions and 82 deletions

View File

@ -1,8 +1,11 @@
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import { IRecord, VideoPlayerCardProps, ViewLargerImageModalRef } from '@zhst/biz';
import WindowToggle from './components/WindowToggle'; import WindowToggle from './components/WindowToggle';
import WarningRecordList from './components/WarningRecordList'; import WarningRecordList from './components/WarningRecordList';
import { ConfigProvider } from '@zhst/meta'; import { ConfigProvider } from '@zhst/meta';
import { IRecord } from '../WarningRecordCard';
import { VideoPlayerCardProps } from '../VideoPlayerCard';
import { ViewLargerImageModalRef } from '../ViewLargerImageModal';
interface RealTimeMonitorProps { interface RealTimeMonitorProps {
prefixCls?: string prefixCls?: string
videoDataSource?: VideoPlayerCardProps[]; videoDataSource?: VideoPlayerCardProps[];
@ -14,7 +17,7 @@ interface RealTimeMonitorProps {
/* /*
*/ */
handleDownloadImg?: (imgSrc?: string) => void; handleDownloadImg?: (imageKey?: string) => void;
/* /*
*/ */
@ -68,7 +71,6 @@ export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
recordListTitle="监控预警记录" recordListTitle="监控预警记录"
/> />
</div> </div>
); );
}; };

View File

@ -1,8 +1,11 @@
import React from 'react'; import React from 'react';
import { ViewLargerImageModal, WarningRecordCard, IRecord, ViewLargerImageModalRef } from '@zhst/biz'; import { IRecord } from '../../../WarningRecordCard';
import { ViewLargerImageModalRef } from '../../../ViewLargerImageModal';
import WarningRecordCard from '../../../WarningRecordCard';
import ViewLargerImageModal from '../../../ViewLargerImageModal';
import { Empty, Space, Spin } from 'antd'; import { Empty, Space, Spin } from 'antd';
import "./index.less"
import { LoadingOutlined } from '@ant-design/icons'; import { LoadingOutlined } from '@ant-design/icons';
import "./index.less"
interface WarningRecordListProps { interface WarningRecordListProps {
dataSource?: IRecord[]; dataSource?: IRecord[];
@ -10,7 +13,7 @@ interface WarningRecordListProps {
/* /*
*/ */
handleDownloadImg?: (imgSrc?: string) => void; handleDownloadImg?: (imageKey?: string) => void;
/* /*
*/ */

View File

@ -1,9 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import VideoPlayerCard from '../../../VideoPlayerCard';
import { VideoPlayerCardProps } from '../../../VideoPlayerCard';
import { Segmented } from 'antd'; import { Segmented } from 'antd';
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons'; import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
import { VideoPlayerCard, VideoPlayerCardProps } from '@zhst/biz';
import './index.less'
import { theme } from 'antd/lib'; import { theme } from 'antd/lib';
import './index.less'
type Size = 'large' | 'small' type Size = 'large' | 'small'

View File

@ -48,15 +48,15 @@ export default () => {
}) })
} }
const handleDownloadImg = (imgSrc?: string) => { const handleDownloadImg = (imageKey?: string) => {
console.log(imgSrc) console.log(imageKey)
// 可以调用 下面 方法关闭弹窗 // 可以调用 下面 方法关闭弹窗
// viewLargerImageModalRef.current?.handleCancel() // viewLargerImageModalRef.current?.handleCancel()
} }
const onRecordClick = (record?: IRecord) => { const onRecordClick = (record?: IRecord) => {
// 点击的时候把数据 拿过来处理一下传给大图弹框 // 点击的时候把数据 拿过来处理一下传给大图弹框
const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {} const { imageKey, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
const warningTimeShow = warningTime ? warningTime : formattedDate const warningTimeShow = warningTime ? warningTime : formattedDate
//用于渲染右侧的 信息 //用于渲染右侧的 信息
@ -68,7 +68,7 @@ export default () => {
{ label: '柜子ID', value: cabietId }, { label: '柜子ID', value: cabietId },
] ]
// 调用这个方法打开弹框 // 调用这个方法打开弹框
viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData }) viewLargerImageModalRef?.current?.show({ imageKey: imageKey, warningData: warningData })
setSelectedRecordId(record?.id) setSelectedRecordId(record?.id)
} }
@ -89,7 +89,7 @@ export default () => {
// 模拟 视频数据请求 // 模拟 视频数据请求
setTimeout(() => { setTimeout(() => {
// 对后端返回数据进行处理 组装一套符合属性的 数据 // 对后端返回数据进行处理 组装一套符合属性的 数据
const newVideoData: VideoPlayerCardProps = { imgSrc: videoData.imgSrc, title: videoData.title, } const newVideoData: VideoPlayerCardProps = { imageKey: videoData.imageKey, title: videoData.title, }
setVideoDataSource((pre) => { setVideoDataSource((pre) => {
const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => { const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => {
// 传给 选中的视频窗口 // 传给 选中的视频窗口
@ -121,7 +121,7 @@ export default () => {
setTimeout(() => { setTimeout(() => {
const newWarningDataSource: IRecord[] = warningData.map(o => { const newWarningDataSource: IRecord[] = warningData.map(o => {
return { return {
imgSrc: o.imgSrc, imageKey: o.imageKey,
id: o.id, id: o.id,
warningType: o.warningType, warningType: o.warningType,
boxId: o.boxId, boxId: o.boxId,
@ -136,12 +136,9 @@ export default () => {
setWarningDataSource(newWarningDataSource) setWarningDataSource(newWarningDataSource)
setIsRecordListLoading(false) setIsRecordListLoading(false)
}, 1000) }, 1000)
} }
return ( return (
<Space size={[8, 16]} direction="vertical"> <Space size={[8, 16]} direction="vertical">
<RealTimeMonitor <RealTimeMonitor
selectedWindowKey={selectedWindowKey} selectedWindowKey={selectedWindowKey}
@ -155,7 +152,7 @@ export default () => {
viewLargerImageModalRef={viewLargerImageModalRef} viewLargerImageModalRef={viewLargerImageModalRef}
isRecordListLoading={isRecordListLoading} isRecordListLoading={isRecordListLoading}
recordListTitle="监控预警记录" /> recordListTitle="监控预警记录" />
<button onClick={() => { mockData() }}></button> <button onClick={() => { mockData() }}></button>
</Space> </Space>
) )
} }

View File

@ -1,12 +1,12 @@
export const videoData = { export const videoData = {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
// videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1', // videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1',
title: `盒子1 点位1` title: `盒子1 点位1`
} }
export const warningData = [ export const warningData = [
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '156156ewr1', id: '156156ewr1',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '2', boxId: '2',
@ -17,7 +17,7 @@ export const warningData = [
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '156156ewr155', id: '156156ewr155',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '1', boxId: '1',
@ -28,7 +28,7 @@ export const warningData = [
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '156156rew155', id: '156156rew155',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '3', boxId: '3',
@ -39,7 +39,7 @@ export const warningData = [
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '15615615ew5', id: '15615615ew5',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '4', boxId: '4',
@ -50,7 +50,7 @@ export const warningData = [
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '15615615sdf5', id: '15615615sdf5',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '5', boxId: '5',

View File

@ -9,7 +9,7 @@ export interface VideoPlayerCardProps {
windowKey?: string; windowKey?: string;
selectedWindowKey?: string; selectedWindowKey?: string;
showType?: 'video' | "image"; showType?: 'video' | "image";
imgSrc?: string; imageKey?: string;
videoSrc?: string; videoSrc?: string;
cardProps?: CardProps; cardProps?: CardProps;
errorReasonText?: string; errorReasonText?: string;
@ -22,6 +22,7 @@ export interface VideoPlayerCardProps {
export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => { export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
const { ConfigContext } = ConfigProvider; const { ConfigContext } = ConfigProvider;
const { getPrefixCls } = useContext(ConfigContext); const { getPrefixCls } = useContext(ConfigContext);
const { prefixCls: customizePrefixCls, showType, imgSrc, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props; const { prefixCls: customizePrefixCls, showType, imgSrc, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props;
@ -40,7 +41,7 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
const videoPlayerCardStyle = size === 'small' ? { width: "calc(50% - 20px)" } : { flex: 1 } const videoPlayerCardStyle = size === 'small' ? { width: "calc(50% - 20px)" } : { flex: 1 }
useEffect(() => { useEffect(() => {
if (!isWindowLoading && (videoSrc || imgSrc)) { if (!isWindowLoading && (videoSrc || imageKey)) {
let contentElement: JSX.Element | null = null; let contentElement: JSX.Element | null = null;
if (videoSrc) { if (videoSrc) {
contentElement = ( contentElement = (
@ -48,11 +49,11 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
); );
videoRef.current?.setShowCrop(true) videoRef.current?.setShowCrop(true)
} else if (imgSrc) { } else if (imageKey) {
contentElement = ( contentElement = (
<img <img
alt="首帧图" alt="首帧图"
src={imgSrc} src={imageKey}
style={{ width: "100%", height: "100%", display: 'block' }} style={{ width: "100%", height: "100%", display: 'block' }}
/> />
); );
@ -61,7 +62,7 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
} else { } else {
setCardContent(null) setCardContent(null)
} }
}, [showType, imgSrc, videoSrc, isWindowLoading]); }, [showType, imageKey, videoSrc, isWindowLoading]);
return ( return (
<div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}> <div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}>

View File

@ -5,8 +5,9 @@ import { Space } from 'antd';
const mockVideoPlayerCardProps: VideoPlayerCardProps = { const mockVideoPlayerCardProps: VideoPlayerCardProps = {
showType: 'image', showType: 'image',
// videoSrc: 'https://example.com/video.mp4', videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1',
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', // 如果需要在没有视频时显示图片封面 // 如果需要在没有视频时显示图片封面
// imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
size: 'small', size: 'small',
}; };

View File

@ -3,6 +3,10 @@
padding: 0 20px; padding: 0 20px;
} }
.ant-card-bordered {
border: 2px solid #f0f0f0;
}
.ant-card-body { .ant-card-body {
padding: 0; padding: 0;
overflow: hidden; overflow: hidden;

View File

@ -19,7 +19,7 @@ title: VideoPlayerCard 视频播放卡片
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| windowKey | 每个卡片的唯一标识 | string | - | - | | windowKey | 每个卡片的唯一标识 | string | - | - |
| selectedWindowKey | 选中的窗口key | string | - | - | | selectedWindowKey | 选中的窗口key | string | - | - |
| imgSrc | 图片地址 | string | - | - | | imageKey | 图片地址 | string | - | - |
| videoSrc | 视频地址 | string | - | - | | videoSrc | 视频地址 | string | - | - |
| errorReasonText | 加载失败的错误提示 | string | - | - | | errorReasonText | 加载失败的错误提示 | string | - | - |
| isWindowLoading | 判断是否显示loading | boolean | - | - | | isWindowLoading | 判断是否显示loading | boolean | - | - |

View File

@ -2,15 +2,24 @@ import React, { useImperativeHandle, useRef, useState, forwardRef, useContext }
import { Modal, ModalProps, Space, SpaceProps } from 'antd'; import { Modal, ModalProps, Space, SpaceProps } from 'antd';
import theme from 'antd/lib/theme'; import theme from 'antd/lib/theme';
import { DownloadOutlined } from '@ant-design/icons'; import { DownloadOutlined } from '@ant-design/icons';
import { ConfigProvider } from '@zhst/meta'; import { ConfigProvider,CropperImage} from '@zhst/meta';
import './index.less' import './index.less'
type ViewLargerImageModalParams = { type ViewLargerImageModalParams = {
imgSrc?: string; imageKey?: string;
warningData?: { warningData?: {
label?: string; label?: string;
value?: string; value?: string;
}[]; }[];
odRect?: {
id?: string;
x: number;
y: number;
w: number;
h: number;
selectAble?: boolean;
}[]
}; };
export interface ViewLargerImageModalRef { export interface ViewLargerImageModalRef {
@ -21,7 +30,7 @@ export interface ViewLargerImageModalRef {
export interface ViewLargerImageModalProps { export interface ViewLargerImageModalProps {
prefixCls?: string prefixCls?: string
imgStyle?: React.CSSProperties; imgStyle?: React.CSSProperties;
downloadImg?: (imgSrc?: string) => void; downloadImg?: (imageKey?: string) => void;
title?: string; title?: string;
downloadText?: string; downloadText?: string;
modalProps?: ModalProps modalProps?: ModalProps
@ -35,11 +44,18 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
const { getPrefixCls } = useContext(ConfigContext); const { getPrefixCls } = useContext(ConfigContext);
const { prefixCls: customizePrefixCls, modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props const { prefixCls: customizePrefixCls, modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props
const componentName = getPrefixCls('biz-warning-larger-image', customizePrefixCls); const componentName = getPrefixCls('biz-warning-larger-image', customizePrefixCls);
const { useToken } = theme const { useToken } = theme
const { token } = useToken() const { token } = useToken()
const [open, setOpen] = useState<boolean>(false); const [open, setOpen] = useState<boolean>(false);
const [imgSrc, setImgSrc] = useState<string>(); const [imageKey, setimageKey] = useState<string>();
const [odRect, setOdRect] = useState<ViewLargerImageModalParams['odRect']>();
const [warningData, setWarningData] = useState<ViewLargerImageModalParams['warningData']>(); const [warningData, setWarningData] = useState<ViewLargerImageModalParams['warningData']>();
const odRectDefault = odRect?.map(rect => ({
...rect,
selectAble: rect.hasOwnProperty('selectAble') ? rect.selectAble : false
}));
const handleCancel = () => { const handleCancel = () => {
setOpen(false); setOpen(false);
@ -49,8 +65,9 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
return { return {
show: (_params) => { show: (_params) => {
setOpen(true); setOpen(true);
setImgSrc(_params?.imgSrc) setimageKey(_params?.imageKey)
setWarningData(_params?.warningData) setWarningData(_params?.warningData)
setOdRect(_params?.odRect)
}, },
handleCancel handleCancel
}; };
@ -67,8 +84,16 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
onCancel={handleCancel} onCancel={handleCancel}
{...modalProps} {...modalProps}
> >
<Space size={0} styles={{ item: { backgroundColor: '#F6F9FAFF' } }} {...spaceProps}> <Space size={0} {...spaceProps}>
<img alt={title} src={imgSrc} style={{ width: 789, height: 444, display: 'block', ...imgStyle }} /> <div className={`${componentName}-left-img`}>
<div style={{ width: 789, height: 444, ...imgStyle }}>
<CropperImage
// editAble={true}
odList={odRectDefault}
url={imageKey}
/>
</div>
</div>
<div className='right-context'> <div className='right-context'>
{warningData?.map(({ label, value }) => ( {warningData?.map(({ label, value }) => (
<div key={label} > <div key={label} >
@ -76,7 +101,7 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
{value} {value}
</div> </div>
))} ))}
{imgSrc && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imgSrc)} ><DownloadOutlined /><span style={{ paddingLeft: 3 }}>{downloadText}</span></div>} {imageKey && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imageKey)} ><DownloadOutlined /><span style={{ paddingLeft: 3 }}>{downloadText}</span></div>}
</div> </div>
</Space> </Space>
</Modal> </Modal>

View File

@ -7,7 +7,7 @@ import dayjs from 'dayjs';
// 结合预警图列表 演示查看预警大图的使用 例如 后端返回这样的数据结构 // 结合预警图列表 演示查看预警大图的使用 例如 后端返回这样的数据结构
const backEndData = [ const backEndData = [
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '1561561', id: '1561561',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '2', boxId: '2',
@ -16,9 +16,16 @@ const backEndData = [
// warningTime: "2023-03-01 ", // warningTime: "2023-03-01 ",
warningTimestamp: Date.now(), warningTimestamp: Date.now(),
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
odRect: [{
// "id": "456",
"x": 0.6519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898,
}]
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '156156155', id: '156156155',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '1', boxId: '1',
@ -27,13 +34,20 @@ const backEndData = [
// warningTime: "2023-03-01 ", // warningTime: "2023-03-01 ",
warningTimestamp: Date.now(), warningTimestamp: Date.now(),
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
odRect: [{
// "id": "456",
"x": 0.1519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898,
}]
} }
] ]
// 前端处理数据结构 // 前端处理数据结构
const dataSource = backEndData.map(o => { const dataSource = backEndData.map(o => {
return { return {
imgSrc: o.imgSrc, imageKey: o.imageKey,
id: o.id, id: o.id,
warningType: o.warningType, warningType: o.warningType,
boxId: o.boxId, boxId: o.boxId,
@ -43,6 +57,7 @@ const dataSource = backEndData.map(o => {
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`], warningInfo: [`盒子${o.boxId}`, `位置${o.position}`],
cabietText: `柜子ID: ${o.cabietId}`, cabietText: `柜子ID: ${o.cabietId}`,
warningTimestamp: o.warningTimestamp, warningTimestamp: o.warningTimestamp,
odRect: o.odRect
} }
}) })
@ -63,7 +78,7 @@ export default () => {
const handleClick = (record?: IRecord) => { const handleClick = (record?: IRecord) => {
// 点击的时候把数据 拿过来处理一下传给大图弹框 // 点击的时候把数据 拿过来处理一下传给大图弹框
const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {} const { imageKey, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss', odRect } = record || {}
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
const warningTimeShow = warningTime ? warningTime : formattedDate const warningTimeShow = warningTime ? warningTime : formattedDate
//用于渲染右侧的 信息 //用于渲染右侧的 信息
@ -75,8 +90,7 @@ export default () => {
{ label: '柜子ID', value: cabietId }, { label: '柜子ID', value: cabietId },
] ]
// 调用这个方法打开弹框 // 调用这个方法打开弹框
viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData }) viewLargerImageModalRef?.current?.show({ imageKey: imageKey, warningData: warningData, odRect: odRect })
setSelectedRecordId(record?.id) setSelectedRecordId(record?.id)
} }

View File

@ -19,7 +19,7 @@ title: ViewLargerImageModal 查看大图弹窗
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | | | show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | |
| handleCancel() | 通过 ref 用于关闭弹窗 | | | | | handleCancel() | 通过 ref 用于关闭弹窗 | | | |
| imgSrc | 图片地址 |string | | | | imageKey | 图片地址 |string | | |
| contextData | 大图显示的数据 | | | | | contextData | 大图显示的数据 | | | |
| imgStyle | 用于修改图片样式 | | | | | imgStyle | 用于修改图片样式 | | | |
| downloadImg | 传入下载图片的方法 | | | | | downloadImg | 传入下载图片的方法 | | | |

View File

@ -2,11 +2,12 @@ import { Card, Space, Divider, CardProps } from 'antd';
import { theme } from 'antd/lib'; import { theme } from 'antd/lib';
import React, { useContext } from 'react'; import React, { useContext } from 'react';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { ConfigProvider } from '@zhst/meta'; import { ConfigProvider,CropperImage} from '@zhst/meta';
import './index.less' import './index.less'
export interface IRecord { export interface IRecord {
imgSrc?: string; imageKey?: string;
id?: string; id?: string;
/** /**
@ -50,6 +51,17 @@ export interface IRecord {
@default YYYY-MM-DD HH:mm:ss @default YYYY-MM-DD HH:mm:ss
*/ */
warningTimeFormat?: string; warningTimeFormat?: string;
/*
od框
*/
odRect?: {
id?: string;
x: number;
y: number;
w: number;
h: number;
selectAble?: boolean;
}[]
}; };
@ -70,11 +82,17 @@ export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
const { getPrefixCls } = useContext(ConfigContext); const { getPrefixCls } = useContext(ConfigContext);
const { prefixCls: customizePrefixCls, record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props; const { prefixCls: customizePrefixCls, record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props;
const componentName = getPrefixCls('biz-warning-record-card', customizePrefixCls); const componentName = getPrefixCls('biz-warning-record-card', customizePrefixCls);
const { imgSrc, id, warningType, warningInfo = [], cabietText, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
;
const { imageKey, id, warningType, warningInfo = [], cabietText, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss', odRect = [] } = record || {}
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : ''; const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
const warningTimeShow = warningTime ? warningTime : formattedDate const warningTimeShow = warningTime ? warningTime : formattedDate
const { useToken } = theme const { useToken } = theme
const { token } = useToken() const { token } = useToken()
const odRectDefault = odRect?.map(rect => ({
...rect,
selectAble: rect.hasOwnProperty('selectAble') ? rect.selectAble : false
}));
const selectedBorderStyle = { const selectedBorderStyle = {
border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)" border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)"
} }
@ -86,15 +104,27 @@ export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
onRecordClick?.(record); onRecordClick?.(record);
}; };
return ( return (
<div className={componentName} key={id} onClick={handleClick} style={style}> <div className={componentName} key={id} onClick={handleClick} style={style}>
<Card <Card
cover={<img alt="预警图" src={imgSrc} style={{ width: 336, height: 203, borderRadius: 0, ...imgStyle }} />} cover={
<div style={{ width: 336, height: 203, ...imgStyle }}>
<CropperImage
// editAble={true}
odList={odRectDefault}
url={imageKey}
/>
</div>
}
style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }} style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }}
{...cardProps} {...cardProps}
> >
<div className='left-context'> <div className={`${componentName}-left-context`}>
<div className="warning-type">{warningType}</div> <div className={`${componentName}-left-context-warning-type`}>{warningType}</div>
<Space size={0} split={<Divider type="vertical" />}> <Space size={0} split={<Divider type="vertical" />}>
{warningInfo?.map((item, index) => ( {warningInfo?.map((item, index) => (
<div key={index} className="info-item"> <div key={index} className="info-item">
@ -102,9 +132,9 @@ export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
</div> </div>
))} ))}
</Space> </Space>
<div className='warning-time'>{warningTimeShow}</div> <div className={`${componentName}-left-context-warning-time`}>{warningTimeShow}</div>
</div> </div>
<div className='cabietInfo' >{cabietText}</div> <div className={`${componentName}-cabietInfo`} >{cabietText}</div>
</Card> </Card>
</div> </div>
); );

View File

@ -6,7 +6,7 @@ import { Space } from 'antd';
// 例如 后端返回这样的数据结构 // 例如 后端返回这样的数据结构
const backEndData = [ const backEndData = [
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '1561561', id: '1561561',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '2', boxId: '2',
@ -15,9 +15,16 @@ const backEndData = [
// warningTime: "2023-03-01 ", // warningTime: "2023-03-01 ",
warningTimestamp: Date.now(), warningTimestamp: Date.now(),
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
odRect: [{
// "id": "123",
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898,
}]
}, },
{ {
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
id: '156156155', id: '156156155',
warningType: '火焰识别', warningType: '火焰识别',
boxId: '1', boxId: '1',
@ -26,13 +33,20 @@ const backEndData = [
// warningTime: "2023-03-01 ", // warningTime: "2023-03-01 ",
warningTimestamp: Date.now(), warningTimestamp: Date.now(),
// warningTimeFormat:"YYYY-MM-DD" // warningTimeFormat:"YYYY-MM-DD"
odRect: [{
// "id": "456",
"x": 0.1519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898,
}]
} }
] ]
// 前端处理数据结构 // 前端处理数据结构
const dataSource = backEndData.map(o => { const dataSource = backEndData.map(o => {
return { return {
imgSrc: o.imgSrc, imageKey: o.imageKey,
id: o.id, id: o.id,
warningType: o.warningType, warningType: o.warningType,
boxId: o.boxId, boxId: o.boxId,
@ -41,16 +55,14 @@ const dataSource = backEndData.map(o => {
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`], warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`],
// cabietText: `柜子ID: ${o.cabietId}`, // cabietText: `柜子ID: ${o.cabietId}`,
warningTimestamp: o.warningTimestamp, warningTimestamp: o.warningTimestamp,
odRect: o.odRect
} }
}) })
export default () => { export default () => {
return ( return (
<Space size={[8, 16]} direction="vertical"> <Space size={[8, 16]} direction="vertical">
{ {dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} />)}
dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} />)
}
</Space> </Space>
) )
} }

View File

@ -7,8 +7,19 @@
line-height: 19px; line-height: 19px;
display: flex; display: flex;
margin-top: 10px; margin-top: 10px;
}
.left-context { .ant-card-bordered {
border: 2px solid #f0f0f0;
}
&-cover-img img {
width: 336px;
height: 203px;
border-radius: 0,
}
&-left-context {
flex: 1; flex: 1;
>div { >div {
@ -18,9 +29,8 @@
>div:nth-child(1) { >div:nth-child(1) {
margin-top: 0; margin-top: 0;
} }
}
.warning-type { &-warning-type {
font-weight: bold; font-weight: bold;
} }
} }

View File

@ -16,7 +16,7 @@ title: WarningRecordCard 预警记录卡片
| 参数 | 说明 | 类型 | 默认值 | 版本 | | 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- | | --- | --- | --- | --- | --- |
| imgSrc | 图片src | string | - | - | | imageKey | 图片src | string | - | - |
| id | 数据的唯一id 用于key 传值| string | - | - | | id | 数据的唯一id 用于key 传值| string | - | - |
| warningType | 预警类型 | string | - | - | | warningType | 预警类型 | string | - | - |
| warningInfo | 盒子 点位 柜子 等信息 | string[] | - | - | | warningInfo | 盒子 点位 柜子 等信息 | string[] | - | - |

View File

@ -1,4 +1,4 @@
.center-link{ .center-link {
width: 100%; width: 100%;
height: 100%; height: 100%;
padding: 30px; padding: 30px;
@ -7,7 +7,7 @@
overflow: hidden; overflow: hidden;
} }
.web-terminal{ .web-terminal {
width: 100%; width: 100%;
height: 100%; height: 100%;
// padding: 30px; // padding: 30px;
@ -16,17 +16,17 @@
// overflow: hidden; // overflow: hidden;
} }
.terminal-form{ .terminal-form {
width: 100%; width: 100%;
margin-bottom: 30px; margin-bottom: 30px;
h1{ h1 {
font-family: SourceHanSansCN, SourceHanSansCN; font-family: "SourceHanSansCN, SourceHanSansCN";
font-weight: bold; font-weight: bold;
font-size:16px; font-size: 16px;
text-align: left; text-align: left;
line-height: 24px; line-height: 24px;
margin-bottom: 20px; margin-bottom: 20px;
color: rgba(0,0,0,80%); color: rgba(0, 0, 0, 80%);
} }
} }

View File

@ -219,7 +219,7 @@ export interface ViewOption {
fitScaleAsMinScale?: boolean; fitScaleAsMinScale?: boolean;
} }
export type IOdRectOrigin { export type IOdRectOrigin = {
objectIndex: { objectIndex: {
objectId: string objectId: string
solutionId: string solutionId: string