Merge branch 'hongbo/file-cabinet' into 'develop'
YuanHongbo's avatar feat: 添加 预警大图组件 See merge request web-project/zhst-lambo!4
This commit is contained in:
commit
4436f47cd7
69
packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx
Normal file
69
packages/biz/src/RealTimeMonitor/RealTimeMonitor.tsx
Normal file
@ -0,0 +1,69 @@
|
||||
import React from 'react';
|
||||
import { IRecord, VideoPlayerCardProps, ViewLargerImageModalRef } from '@zhst/biz';
|
||||
import WindowToggle from './components/WindowToggle';
|
||||
import WarningRecordList from './components/WarningRecordList';
|
||||
|
||||
interface RealTimeMonitorProps {
|
||||
videoDataSource?: VideoPlayerCardProps[];
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
selectedWindowKey?: string;
|
||||
warningDataSource?: IRecord[];
|
||||
viewLargerImageModalRef?: React.RefObject<ViewLargerImageModalRef>;
|
||||
/*
|
||||
处理 图片下载按钮点击事件
|
||||
*/
|
||||
handleDownloadImg?: (imgSrc?: string) => void;
|
||||
/*
|
||||
处理 预警记录卡片点击事件
|
||||
*/
|
||||
onRecordClick?: (record?: IRecord) => void;
|
||||
/*
|
||||
获取选中的 记录 id 用于 判断是否显示 选中样式
|
||||
*/
|
||||
selectedRecordId?: string;
|
||||
isRecordListLoading?: boolean;
|
||||
recordListTitle?: string;
|
||||
style?: React.CSSProperties;
|
||||
cardStyle?: React.CSSProperties;
|
||||
imgStyle?: React.CSSProperties;
|
||||
largeImageTitle?: string;
|
||||
}
|
||||
|
||||
export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
|
||||
const { videoDataSource,
|
||||
handleWindowClick,
|
||||
handleCloseButtonClick,
|
||||
selectedWindowKey,
|
||||
warningDataSource,
|
||||
viewLargerImageModalRef,
|
||||
handleDownloadImg,
|
||||
onRecordClick,
|
||||
selectedRecordId,
|
||||
isRecordListLoading,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-real-time-monitor' style={{ display: 'flex' }} >
|
||||
<WindowToggle
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
dataSource={videoDataSource}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
/>
|
||||
<WarningRecordList
|
||||
dataSource={warningDataSource}
|
||||
handleDownloadImg={handleDownloadImg}
|
||||
onRecordClick={onRecordClick}
|
||||
selectedRecordId={selectedRecordId}
|
||||
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||
isRecordListLoading={isRecordListLoading}
|
||||
recordListTitle="监控预警记录"
|
||||
/>
|
||||
</div>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default RealTimeMonitor;
|
@ -0,0 +1,82 @@
|
||||
import React from 'react';
|
||||
import { ViewLargerImageModal, WarningRecordCard, IRecord, ViewLargerImageModalRef } from '@zhst/biz';
|
||||
import { Empty, Space, Spin } from 'antd';
|
||||
import "./index.less"
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
|
||||
interface WarningRecordListProps {
|
||||
dataSource?: IRecord[];
|
||||
viewLargerImageModalRef?: React.RefObject<ViewLargerImageModalRef>;
|
||||
/*
|
||||
处理 图片下载按钮点击事件
|
||||
*/
|
||||
handleDownloadImg?: (imgSrc?: string) => void;
|
||||
/*
|
||||
处理 预警记录卡片点击事件
|
||||
*/
|
||||
onRecordClick?: (record?: IRecord) => void;
|
||||
/*
|
||||
获取选中的 记录 id 用于 判断是否显示 选中样式
|
||||
*/
|
||||
selectedRecordId?: string;
|
||||
isRecordListLoading?: boolean;
|
||||
recordListTitle?: string;
|
||||
style?: React.CSSProperties;
|
||||
cardStyle?: React.CSSProperties;
|
||||
imgStyle?: React.CSSProperties;
|
||||
largeImageTitle?: string;
|
||||
}
|
||||
|
||||
const WarningRecordList: React.FC<WarningRecordListProps> = (props) => {
|
||||
|
||||
const {
|
||||
dataSource = [],
|
||||
viewLargerImageModalRef,
|
||||
selectedRecordId,
|
||||
handleDownloadImg,
|
||||
onRecordClick,
|
||||
isRecordListLoading,
|
||||
recordListTitle,
|
||||
style,
|
||||
cardStyle,
|
||||
imgStyle,
|
||||
largeImageTitle
|
||||
} = props
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-warning-record-list' style={style}>
|
||||
<div className='header'>{recordListTitle}</div>
|
||||
<div className='body'>
|
||||
{
|
||||
isRecordListLoading ?
|
||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} />} />
|
||||
</div>
|
||||
: (dataSource?.length) > 0 ?
|
||||
<Space direction='vertical' size={10} >
|
||||
{dataSource?.map((record, index) => {
|
||||
if (index > 2) return
|
||||
return (<WarningRecordCard
|
||||
key={record?.id}
|
||||
record={record}
|
||||
onRecordClick={(record) => { onRecordClick?.(record) }}
|
||||
selectedRecordId={selectedRecordId}
|
||||
cardStyle={{ width: 300, height: 264, ...cardStyle }}
|
||||
imgStyle={{ width: 280, height: 169, ...imgStyle }}
|
||||
/>)
|
||||
}
|
||||
)}
|
||||
</Space>
|
||||
:
|
||||
<div style={{ height: '100%', display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Empty description="暂无数据" />
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
{/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */}
|
||||
<ViewLargerImageModal ref={viewLargerImageModalRef} downloadImg={handleDownloadImg} title={largeImageTitle} />
|
||||
</div>
|
||||
)
|
||||
};
|
||||
|
||||
export default WarningRecordList;
|
@ -0,0 +1,20 @@
|
||||
.zhst-biz-warning-record-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-left: solid 1px #00000026;
|
||||
width: 320px;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
background-color: #EFF2F4;
|
||||
padding: 10px 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
import WarningRecordList from './WarningRecordList'
|
||||
export default WarningRecordList
|
@ -0,0 +1,71 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Segmented } from 'antd';
|
||||
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
|
||||
import { VideoPlayerCard, VideoPlayerCardProps } from '@zhst/biz';
|
||||
import './index.less'
|
||||
import { theme } from 'antd/lib';
|
||||
|
||||
type Size = 'large' | 'small'
|
||||
|
||||
interface WindowToggleProps {
|
||||
dataSource?: VideoPlayerCardProps[];
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
selectedWindowKey?: string;
|
||||
}
|
||||
|
||||
export const WindowToggle: React.FC<WindowToggleProps> = (props) => {
|
||||
|
||||
const { dataSource = [], handleWindowClick, handleCloseButtonClick, selectedWindowKey } = props
|
||||
const [size, setSize] = useState<Size>("large");
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
|
||||
const getLabelStyle = (isSelected: boolean) => ({
|
||||
padding: "0 11px", background: "#fff",
|
||||
...(isSelected ? { background: token.colorPrimary, color: '#fff' } : {}),
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-window-toggle'>
|
||||
{/* 切换按钮 */}
|
||||
<div className='header'>
|
||||
<Segmented
|
||||
defaultValue='large'
|
||||
options={[
|
||||
{ value: 'large', label: <div style={getLabelStyle(size === 'large')}><BarsOutlined /></div> },
|
||||
{ value: 'small', label: <div style={getLabelStyle(size === 'small')}><AppstoreOutlined /></div> },
|
||||
]}
|
||||
onChange={(value) => {
|
||||
// 当一个窗口时 默认 selectedkey 第一条数据的 windowkey
|
||||
if (value === 'large' && dataSource.length > 0) {
|
||||
const { windowKey } = dataSource[0]
|
||||
handleWindowClick?.(windowKey)
|
||||
}
|
||||
setSize(value as Size)
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className='body'>
|
||||
{
|
||||
dataSource?.map((item, index) => {
|
||||
if (size === "large" && index > 0) return
|
||||
return (
|
||||
<VideoPlayerCard
|
||||
key={item.windowKey}
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
size={size} {...item}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
/>)
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WindowToggle;
|
||||
|
@ -0,0 +1,45 @@
|
||||
.zhst-biz-window-toggle {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
background-color: #EFF2F4;
|
||||
padding: 10px 20px;
|
||||
box-sizing: border-box;
|
||||
|
||||
.ant-segmented {
|
||||
padding: 0;
|
||||
|
||||
.ant-segmented-group {
|
||||
border-radius: 4px;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-segmented-item {
|
||||
border-radius: 0;
|
||||
|
||||
.ant-segmented-item-label {
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background-color: #E5EAEC;
|
||||
padding: 10px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
>div {
|
||||
margin: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,2 @@
|
||||
import WindowToggle from './WindowToggle'
|
||||
export default WindowToggle
|
161
packages/biz/src/RealTimeMonitor/demo/base.tsx
Normal file
161
packages/biz/src/RealTimeMonitor/demo/base.tsx
Normal file
@ -0,0 +1,161 @@
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { IRecord, RealTimeMonitor, VideoPlayerCardProps, useViewLargerImageModal } from '@zhst/biz';
|
||||
import { videoData, warningData } from './mock';
|
||||
import { Space } from 'antd';
|
||||
import dayjs from 'dayjs'
|
||||
import './index.less'
|
||||
|
||||
export default () => {
|
||||
|
||||
// 必须设置初始数据 用于渲染 4个窗口
|
||||
const initialVideoDataSource: VideoPlayerCardProps[] = [
|
||||
{
|
||||
windowKey: 'first-window',
|
||||
},
|
||||
{
|
||||
windowKey: 'second-window',
|
||||
},
|
||||
{
|
||||
windowKey: 'third-window',
|
||||
},
|
||||
{
|
||||
windowKey: 'forth-window',
|
||||
}
|
||||
]
|
||||
const [videoDataSource, setVideoDataSource] = useState<VideoPlayerCardProps[]>(initialVideoDataSource);
|
||||
const [warningDataSource, setWarningDataSource] = useState<IRecord[]>();
|
||||
const [selectedWindowKey, setSelectedWindowKey] = useState<string | undefined>('first-window');
|
||||
const [selectedRecordId, setSelectedRecordId] = React.useState<string | undefined>()
|
||||
const [isRecordListLoading, setIsRecordListLoading] = React.useState<boolean>(false)
|
||||
// 把弹窗的ref 拿出来
|
||||
const viewLargerImageModalRef = useViewLargerImageModal()
|
||||
|
||||
const handleWindowClick = (key?: string) => {
|
||||
setSelectedWindowKey(key)
|
||||
}
|
||||
|
||||
const clearWindowData = (key?: string) => {
|
||||
// 当关闭窗口时 也要刷新 右侧 预警记录接口 不要忘记
|
||||
setVideoDataSource((pre) => {
|
||||
const newVideoDataSource = pre.map((item) => {
|
||||
if (item.windowKey === key) {
|
||||
return { windowKey: key };
|
||||
}
|
||||
return item; // 保持不变
|
||||
});
|
||||
return newVideoDataSource
|
||||
})
|
||||
}
|
||||
|
||||
const handleDownloadImg = (imgSrc?: string) => {
|
||||
console.log(imgSrc)
|
||||
// 可以调用 下面 方法关闭弹窗
|
||||
// viewLargerImageModalRef.current?.handleCancel()
|
||||
}
|
||||
|
||||
const onRecordClick = (record?: IRecord) => {
|
||||
// 点击的时候把数据 拿过来处理一下传给大图弹框
|
||||
const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
|
||||
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
//用于渲染右侧的 信息
|
||||
const warningData = [
|
||||
{ label: '预警类型', value: warningType },
|
||||
{ label: '预警时间', value: warningTimeShow },
|
||||
{ label: '盒子', value: boxId },
|
||||
{ label: '点位', value: position },
|
||||
{ label: '柜子ID', value: cabietId },
|
||||
]
|
||||
// 调用这个方法打开弹框
|
||||
viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData })
|
||||
|
||||
setSelectedRecordId(record?.id)
|
||||
}
|
||||
|
||||
const mockData = () => {
|
||||
// 请求时需要对应窗口为loading 状态
|
||||
setVideoDataSource((pre) => {
|
||||
const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => {
|
||||
// 开启loading
|
||||
if (item.windowKey === selectedWindowKey) {
|
||||
return { ...item, isWindowLoading: true, title: '' }
|
||||
}
|
||||
return item
|
||||
});
|
||||
return newVideoDataSource
|
||||
})
|
||||
|
||||
// 模拟 视频数据请求
|
||||
setTimeout(() => {
|
||||
// 对后端返回数据进行处理 组装一套符合属性的 数据
|
||||
const newVideoData: VideoPlayerCardProps = { imgSrc: videoData.imgSrc, title: videoData.title, }
|
||||
setVideoDataSource((pre) => {
|
||||
const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => {
|
||||
// 传给 选中的视频窗口
|
||||
if (item.windowKey === selectedWindowKey) {
|
||||
return { ...item, ...newVideoData }
|
||||
}
|
||||
return item
|
||||
});
|
||||
return newVideoDataSource
|
||||
})
|
||||
|
||||
setVideoDataSource((pre) => {
|
||||
const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => {
|
||||
// 关闭loading
|
||||
if (item.windowKey === selectedWindowKey) {
|
||||
return { ...item, isWindowLoading: false }
|
||||
}
|
||||
return item
|
||||
});
|
||||
return newVideoDataSource
|
||||
})
|
||||
|
||||
}, 3000);
|
||||
|
||||
// 模拟 预警记录数据请求
|
||||
|
||||
setIsRecordListLoading(true)
|
||||
|
||||
setTimeout(() => {
|
||||
const newWarningDataSource: IRecord[] = warningData.map(o => {
|
||||
return {
|
||||
imgSrc: o.imgSrc,
|
||||
id: o.id,
|
||||
warningType: o.warningType,
|
||||
boxId: o.boxId,
|
||||
position: o.position,
|
||||
cabietId: o.cabietId,
|
||||
//,`柜子ID: ${o.cabietId}`
|
||||
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`],
|
||||
// cabietText: `柜子ID: ${o.cabietId}`,
|
||||
warningTimestamp: o.warningTimestamp,
|
||||
}
|
||||
})
|
||||
setWarningDataSource(newWarningDataSource)
|
||||
setIsRecordListLoading(false)
|
||||
}, 1000)
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
|
||||
<Space size={[8, 16]} direction="vertical">
|
||||
<RealTimeMonitor
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
videoDataSource={videoDataSource}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={clearWindowData}
|
||||
warningDataSource={warningDataSource}
|
||||
handleDownloadImg={handleDownloadImg}
|
||||
onRecordClick={onRecordClick}
|
||||
selectedRecordId={selectedRecordId}
|
||||
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||
isRecordListLoading={isRecordListLoading}
|
||||
recordListTitle="监控预警记录" />
|
||||
<button onClick={() => { mockData() }}>模拟数据</button>
|
||||
</Space>
|
||||
)
|
||||
}
|
5
packages/biz/src/RealTimeMonitor/demo/index.less
Normal file
5
packages/biz/src/RealTimeMonitor/demo/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
#realtimemonitor-demo-base {
|
||||
.dumi-default-previewer-demo>div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
65
packages/biz/src/RealTimeMonitor/demo/mock.tsx
Normal file
65
packages/biz/src/RealTimeMonitor/demo/mock.tsx
Normal file
@ -0,0 +1,65 @@
|
||||
export const videoData = {
|
||||
imgSrc: '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',
|
||||
title: `盒子1 点位1`
|
||||
}
|
||||
|
||||
export const warningData = [
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '156156ewr1',
|
||||
warningType: '火焰识别',
|
||||
boxId: '2',
|
||||
position: '2',
|
||||
cabietId: '002',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '156156ewr155',
|
||||
warningType: '火焰识别',
|
||||
boxId: '1',
|
||||
position: '1',
|
||||
cabietId: '001',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '156156rew155',
|
||||
warningType: '火焰识别',
|
||||
boxId: '3',
|
||||
position: '3',
|
||||
cabietId: '004',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '15615615ew5',
|
||||
warningType: '火焰识别',
|
||||
boxId: '4',
|
||||
position: '4',
|
||||
cabietId: '004',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '15615615sdf5',
|
||||
warningType: '火焰识别',
|
||||
boxId: '5',
|
||||
position: '5',
|
||||
cabietId: '005',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
}
|
||||
]
|
||||
|
||||
|
36
packages/biz/src/RealTimeMonitor/index.md
Normal file
36
packages/biz/src/RealTimeMonitor/index.md
Normal file
@ -0,0 +1,36 @@
|
||||
---
|
||||
group: 数据展示
|
||||
category: Components
|
||||
subtitle: 实时监控页面
|
||||
title: RealTimeMonitor 实时监控页面
|
||||
---
|
||||
|
||||
# RealTimeMonitor 实时监控页面
|
||||
|
||||
|
||||
<code src="./demo/base.tsx"></code>
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| videoDataSource | 用于渲染 每个窗口的数据 | VideoPlayerCardProps[] | 需要传一组默认值用于窗口的渲染| - |
|
||||
| warningDataSource | 用于渲染 预警记录的数据 | WindowProps[] | 需要传一组默认值用于窗口的渲染| - |
|
||||
| handleWindowClick | 用于获取窗口的 windowKey 方便更新对应窗口数据 | (key?: string) => void; | - | - |
|
||||
| handleCloseButtonClick | 用于点击窗口关闭按钮的事件 | (key?: string) => void; | - | - |
|
||||
| selectedWindowKey | 选中的窗口的 key 用于控制 选中边框样式 |string| - | - |
|
||||
| handleDownloadImg | 用于处理查看大图下载图片的事件 | (key?: string) => void; | - | - |
|
||||
| onRecordClick | 用于处理预警记录卡片点击事件事件 | (key?: string) => void; | - | - |
|
||||
| selectedRecordId| 用于判断是否显示选中样式 |string| - | - |
|
||||
| isRecordListLoading | 判断预警记录列表loading状态 |boolean| - | - |
|
||||
| recordListTitle | 预警记录列表的标题 | string | - | - |
|
||||
| viewLargerImageModalRef | 查看大图弹窗的ref | viewLargerImageModalRef={viewLargerImageModalRef}| | - |
|
||||
| viewLargerImageModalRef | 查看大图弹窗的ref |React.RefObject\<ViewLargerImageModalRef\>| - | - |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
2
packages/biz/src/RealTimeMonitor/index.tsx
Normal file
2
packages/biz/src/RealTimeMonitor/index.tsx
Normal file
@ -0,0 +1,2 @@
|
||||
import RealTimeMonitor from './RealTimeMonitor'
|
||||
export default RealTimeMonitor
|
101
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
101
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
@ -0,0 +1,101 @@
|
||||
import { Card, Space, CardProps, Spin, Button } from 'antd';
|
||||
import { theme } from 'antd/lib';
|
||||
import { VideoPlayer, type VideoViewRef } from '@zhst/meta';
|
||||
import React, { useState, useEffect, ReactNode, useRef } from 'react';
|
||||
import { CloseOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import './index.less'
|
||||
export interface VideoPlayerCardProps {
|
||||
windowKey?: string;
|
||||
selectedWindowKey?: string;
|
||||
showType?: 'video' | "image";
|
||||
imgSrc?: string;
|
||||
videoSrc?: string;
|
||||
cardProps?: CardProps;
|
||||
errorReasonText?: string;
|
||||
isWindowLoading?: boolean;
|
||||
size?: 'large' | 'small';
|
||||
title?: string | ReactNode
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
}
|
||||
|
||||
export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
|
||||
|
||||
const componentName = `zhst-biz-video-player-card`;
|
||||
const { showType, imgSrc, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props;
|
||||
const [cardContent, setCardContent] = useState<JSX.Element | null>(null);
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
const videoRef = useRef<VideoViewRef>(null)
|
||||
const selectedBorderStyle = {
|
||||
border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)"
|
||||
}
|
||||
const cardStyle: React.CSSProperties = {
|
||||
...(size === 'large' ? { height: 931 } : { height: 456, cursor: 'pointer' }),
|
||||
...(size === 'small' && selectedWindowKey === windowKey ? selectedBorderStyle : {})
|
||||
};
|
||||
const videoPlayerCardStyle = size === 'small' ? { width: "calc(50% - 20px)" } : { flex: 1 }
|
||||
|
||||
useEffect(() => {
|
||||
if (!isWindowLoading && (videoSrc || imgSrc)) {
|
||||
let contentElement: JSX.Element | null = null;
|
||||
if (videoSrc) {
|
||||
contentElement = (
|
||||
<VideoPlayer ref={videoRef} url={videoSrc} />
|
||||
);
|
||||
videoRef.current?.setShowCrop(true)
|
||||
|
||||
} else if (imgSrc) {
|
||||
contentElement = (
|
||||
<img
|
||||
alt="首帧图"
|
||||
src={imgSrc}
|
||||
style={{ width: "100%", height: "100%", display: 'block' }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
setCardContent(contentElement);
|
||||
} else {
|
||||
setCardContent(null)
|
||||
}
|
||||
}, [showType, imgSrc, videoSrc, isWindowLoading]);
|
||||
|
||||
return (
|
||||
<div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}>
|
||||
<Card
|
||||
title={
|
||||
<Space style={{ width: "100%", justifyContent: "space-between" }}>
|
||||
<div>{title}</div>
|
||||
<div className="card-close-button">
|
||||
<Button type="text" onClick={() => { handleCloseButtonClick?.(windowKey) }} >
|
||||
<CloseOutlined />
|
||||
</Button>
|
||||
</div>
|
||||
</Space>}
|
||||
style={{ display: "flex", flexDirection: "column", borderRadius: 4, overflow: "hidden", ...cardStyle }}
|
||||
bodyStyle={{ flex: 1 }}
|
||||
{...cardProps}
|
||||
>
|
||||
{cardContent ? (
|
||||
<>
|
||||
{cardContent}
|
||||
</>
|
||||
) : (
|
||||
<div style={{ backgroundColor: '#000', height: '100%', display: 'flex', padding: '20px', boxSizing: 'border-box' }}>
|
||||
{
|
||||
isWindowLoading ?
|
||||
<div style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
<Spin indicator={<LoadingOutlined style={{ fontSize: 24 }} />} />
|
||||
</div>
|
||||
: !!errorReasonText && <span style={{ color: token.colorError }}>{errorReasonText}</span>
|
||||
}
|
||||
</div>
|
||||
)}
|
||||
{/* 其他内容 */}
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default VideoPlayerCard;
|
||||
|
19
packages/biz/src/VideoPlayerCard/demo/base.tsx
Normal file
19
packages/biz/src/VideoPlayerCard/demo/base.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
|
||||
import React from 'react';
|
||||
import { VideoPlayerCard, type VideoPlayerCardProps } from '@zhst/biz';
|
||||
import { Space } from 'antd';
|
||||
|
||||
const mockVideoPlayerCardProps: VideoPlayerCardProps = {
|
||||
showType: 'image',
|
||||
// videoSrc: 'https://example.com/video.mp4',
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png', // 如果需要在没有视频时显示图片封面
|
||||
size: 'small',
|
||||
};
|
||||
|
||||
export default () => {
|
||||
return (
|
||||
<Space size={[8, 16]} direction="vertical">
|
||||
<VideoPlayerCard {...mockVideoPlayerCardProps} />
|
||||
</Space>
|
||||
)
|
||||
}
|
30
packages/biz/src/VideoPlayerCard/index.less
Normal file
30
packages/biz/src/VideoPlayerCard/index.less
Normal file
@ -0,0 +1,30 @@
|
||||
.zhst-biz-video-player-card {
|
||||
.ant-card-head {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.ant-card-body {
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
border-radius: 0;
|
||||
|
||||
.zhst-image__video-view {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card-close-button {
|
||||
.ant-btn {
|
||||
padding: 0 3px;
|
||||
height: 22px;
|
||||
color: #00000073;
|
||||
}
|
||||
|
||||
.ant-btn:hover {
|
||||
padding: 0 3px;
|
||||
height: 22px;
|
||||
color: #000000e0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
34
packages/biz/src/VideoPlayerCard/index.md
Normal file
34
packages/biz/src/VideoPlayerCard/index.md
Normal file
@ -0,0 +1,34 @@
|
||||
---
|
||||
group: 数据展示
|
||||
category: Components
|
||||
subtitle: 视频播放卡片
|
||||
title: VideoPlayerCard 视频播放卡片
|
||||
---
|
||||
|
||||
# VideoPlayerCard 视频播放卡片
|
||||
|
||||
|
||||
<code src="./demo/base.tsx"></code>
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| windowKey | 每个卡片的唯一标识 | string | - | - |
|
||||
| selectedWindowKey | 选中的窗口key | string | - | - |
|
||||
| imgSrc | 图片地址 | string | - | - |
|
||||
| videoSrc | 视频地址 | string | - | - |
|
||||
| errorReasonText | 加载失败的错误提示 | string | - | - |
|
||||
| isWindowLoading | 判断是否显示loading | boolean | - | - |
|
||||
| size | 设置窗口大小 | 'large' \| 'small' | - | - |
|
||||
| title | 设置窗口标题 | string \| ReactNode | - | - |
|
||||
| handleCloseButtonClick | 处理关闭按钮事件 | (key?: string) => void| - | - |
|
||||
| handleWindowClick | 处理窗口点击事件 | (key?: string) => void| - | - |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
3
packages/biz/src/VideoPlayerCard/index.tsx
Normal file
3
packages/biz/src/VideoPlayerCard/index.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import VideoPlayerCard from './VideoPlayerCard'
|
||||
export type { VideoPlayerCardProps } from './VideoPlayerCard'
|
||||
export default VideoPlayerCard
|
@ -0,0 +1,86 @@
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef } from 'react';
|
||||
import { Modal, ModalProps, Space, SpaceProps } from 'antd';
|
||||
import theme from 'antd/lib/theme';
|
||||
import { DownloadOutlined } from '@ant-design/icons';
|
||||
import './index.less'
|
||||
|
||||
type ViewLargerImageModalParams = {
|
||||
imgSrc?: string;
|
||||
warningData?: {
|
||||
label?: string;
|
||||
value?: string;
|
||||
}[];
|
||||
};
|
||||
|
||||
export interface ViewLargerImageModalRef {
|
||||
show: (params?: ViewLargerImageModalParams) => void;
|
||||
handleCancel: () => void;
|
||||
}
|
||||
|
||||
export interface ViewLargerImageModalProps {
|
||||
imgStyle?: React.CSSProperties;
|
||||
downloadImg?: (imgSrc?: string) => void;
|
||||
title?: string;
|
||||
downloadText?: string;
|
||||
modalProps?: ModalProps
|
||||
spaceProps?: SpaceProps;
|
||||
}
|
||||
|
||||
export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLargerImageModalProps>(
|
||||
(props, ref) => {
|
||||
|
||||
const { modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
const [imgSrc, setImgSrc] = useState<string>();
|
||||
const [warningData, setWarningData] = useState<ViewLargerImageModalParams['warningData']>();
|
||||
|
||||
const handleCancel = () => {
|
||||
setOpen(false);
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => {
|
||||
return {
|
||||
show: (_params) => {
|
||||
setOpen(true);
|
||||
setImgSrc(_params?.imgSrc)
|
||||
setWarningData(_params?.warningData)
|
||||
},
|
||||
handleCancel
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='zhst-biz-view-warning-larger-image-modal'
|
||||
open={open}
|
||||
destroyOnClose
|
||||
title={title}
|
||||
width="1029px"
|
||||
footer={null}
|
||||
onCancel={handleCancel}
|
||||
{...modalProps}
|
||||
>
|
||||
<Space size={0} styles={{ item: { backgroundColor: '#F6F9FAFF' } }} {...spaceProps}>
|
||||
<img alt={title} src={imgSrc} style={{ width: 789, height: 444, display: 'block', ...imgStyle }} />
|
||||
<div className='right-context'>
|
||||
{warningData?.map(({ label, value }) => (
|
||||
<div key={label} >
|
||||
<span className='context-key'>{`${label}: `}</span>
|
||||
{value}
|
||||
</div>
|
||||
))}
|
||||
{imgSrc && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imgSrc)} ><DownloadOutlined /><span style={{ paddingLeft: 3 }}>{downloadText}</span></div>}
|
||||
</div>
|
||||
</Space>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
)
|
||||
|
||||
export default ViewLargerImageModal;
|
||||
|
||||
export const useViewLargerImageModal = () => {
|
||||
return useRef<ViewLargerImageModalRef>(null);
|
||||
};
|
94
packages/biz/src/ViewLargerImageModal/demo/base.tsx
Normal file
94
packages/biz/src/ViewLargerImageModal/demo/base.tsx
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
import React from 'react';
|
||||
import { ViewLargerImageModal, WarningRecordCard, IRecord, useViewLargerImageModal } from '@zhst/biz';
|
||||
import { Space } from 'antd';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
// 结合预警图列表 演示查看预警大图的使用 例如 后端返回这样的数据结构
|
||||
const backEndData = [
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '1561561',
|
||||
warningType: '火焰识别',
|
||||
boxId: '2',
|
||||
position: '2',
|
||||
cabietId: '002',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '156156155',
|
||||
warningType: '火焰识别',
|
||||
boxId: '1',
|
||||
position: '1',
|
||||
cabietId: '001',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
}
|
||||
]
|
||||
|
||||
// 前端处理数据结构
|
||||
const dataSource = backEndData.map(o => {
|
||||
return {
|
||||
imgSrc: o.imgSrc,
|
||||
id: o.id,
|
||||
warningType: o.warningType,
|
||||
boxId: o.boxId,
|
||||
position: o.position,
|
||||
cabietId: o.cabietId,
|
||||
//,`柜子ID ${o.cabietId}`
|
||||
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`],
|
||||
cabietText: `柜子ID: ${o.cabietId}`,
|
||||
warningTimestamp: o.warningTimestamp,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
export default () => {
|
||||
|
||||
const [selectedRecordId, setSelectedRecordId] = React.useState<string | undefined>()
|
||||
|
||||
// 把弹窗的ref 拿出来
|
||||
const viewLargerImageModalRef = useViewLargerImageModal()
|
||||
|
||||
const handleDownloadImg = () => {
|
||||
console.log('download')
|
||||
// 可以调用 下面 方法关闭弹窗
|
||||
// viewLargerImageModalRef.current?.handleCancel()
|
||||
}
|
||||
|
||||
const handleClick = (record?: IRecord) => {
|
||||
// 点击的时候把数据 拿过来处理一下传给大图弹框
|
||||
const { imgSrc, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
|
||||
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
//用于渲染右侧的 信息
|
||||
const warningData = [
|
||||
{ label: '预警类型', value: warningType },
|
||||
{ label: '预警时间', value: warningTimeShow },
|
||||
{ label: '盒子', value: boxId },
|
||||
{ label: '点位', value: position },
|
||||
{ label: '柜子ID', value: cabietId },
|
||||
]
|
||||
// 调用这个方法打开弹框
|
||||
viewLargerImageModalRef?.current?.show({ imgSrc: imgSrc, warningData: warningData })
|
||||
|
||||
setSelectedRecordId(record?.id)
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Space size={[8, 16]} >
|
||||
{
|
||||
dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} onRecordClick={(record) => { handleClick(record) }} selectedRecordId={selectedRecordId} />)
|
||||
}
|
||||
</Space>
|
||||
{/* 弹窗 绑定ref 后可以调用 handleCancel方法关闭弹窗 show方法打开弹窗 */}
|
||||
<ViewLargerImageModal ref={viewLargerImageModalRef} downloadImg={handleDownloadImg} title="预警大图" />
|
||||
</>
|
||||
)
|
||||
}
|
62
packages/biz/src/ViewLargerImageModal/index.less
Normal file
62
packages/biz/src/ViewLargerImageModal/index.less
Normal file
@ -0,0 +1,62 @@
|
||||
.zhst-biz-view-warning-larger-image-modal {
|
||||
font-family: MicrosoftYaHei;
|
||||
|
||||
.ant-modal-content {
|
||||
padding: 0;
|
||||
height: 492px;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
|
||||
.ant-modal-close {
|
||||
top: 14px;
|
||||
right: 16px;
|
||||
}
|
||||
|
||||
.ant-modal-header {
|
||||
height: 48px;
|
||||
line-height: 48px;
|
||||
margin-bottom: 0;
|
||||
|
||||
.ant-modal-title {
|
||||
height: 100%;
|
||||
line-height: 48px;
|
||||
font-weight: bold;
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.ant-modal-body {
|
||||
height: 444px;
|
||||
|
||||
>div {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: flex-start;
|
||||
|
||||
>div:nth-child(2) {
|
||||
position: relative;
|
||||
flex: 1;
|
||||
box-sizing: border-box;
|
||||
height: 100%;
|
||||
padding: 30px 16px;
|
||||
|
||||
.right-context>div {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.right-context .context-key {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.img-download {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
packages/biz/src/ViewLargerImageModal/index.md
Normal file
28
packages/biz/src/ViewLargerImageModal/index.md
Normal file
@ -0,0 +1,28 @@
|
||||
---
|
||||
group: 数据展示
|
||||
category: Components
|
||||
subtitle: 查看大图弹窗
|
||||
title: ViewLargerImageModal 查看大图弹窗
|
||||
---
|
||||
|
||||
# ViewLargerImageModal 查看大图弹窗
|
||||
|
||||
|
||||
<code src="./demo/base.tsx"></code>
|
||||
|
||||
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | |
|
||||
| handleCancel() | 通过 ref 用于关闭弹窗 | | | |
|
||||
| imgSrc | 图片地址 |string | | |
|
||||
| contextData | 大图显示的数据 | | | |
|
||||
| imgStyle | 用于修改图片样式 | | | |
|
||||
| downloadImg | 传入下载图片的方法 | | | |
|
||||
| title | 弹窗标题 | string | | |
|
||||
| downloadText | 下载按钮文本 | string | | |
|
||||
| modalProps | 弹窗属性 | | | |
|
||||
|
4
packages/biz/src/ViewLargerImageModal/index.tsx
Normal file
4
packages/biz/src/ViewLargerImageModal/index.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import ViewLargerImageModal, { useViewLargerImageModal } from './ViewLargerImageModal'
|
||||
export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal'
|
||||
export default ViewLargerImageModal;
|
||||
export { useViewLargerImageModal };
|
@ -1,16 +1,13 @@
|
||||
import { Card, Space, Divider } from 'antd';
|
||||
import { Card, Space, Divider, CardProps } from 'antd';
|
||||
import { theme } from 'antd/lib';
|
||||
import React from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import './index.less'
|
||||
|
||||
const componentName = `zhst-biz-warning-record-card`;
|
||||
|
||||
export interface IRecord {
|
||||
|
||||
imgSrc?: string;
|
||||
|
||||
id?: string;
|
||||
|
||||
/**
|
||||
* 预警类型
|
||||
*/
|
||||
@ -21,12 +18,28 @@ export interface IRecord {
|
||||
warningInfo?: string[]
|
||||
/*
|
||||
右侧 柜子id 显示
|
||||
/*
|
||||
盒子 ID
|
||||
*/
|
||||
cabietInfo?: string;
|
||||
boxId: string;
|
||||
/*
|
||||
位置信息
|
||||
*/
|
||||
position: string;
|
||||
/*
|
||||
柜子id
|
||||
*/
|
||||
cabietId?: string;
|
||||
/*
|
||||
直接传格式化好的时间
|
||||
/*
|
||||
右侧 柜子id 显示
|
||||
*/
|
||||
cabietText?: string;
|
||||
/*
|
||||
直接传格式化好的时间
|
||||
*/
|
||||
warningTime?: string ;
|
||||
warningTime?: string;
|
||||
/*
|
||||
传格时间戳
|
||||
*/
|
||||
@ -43,29 +56,41 @@ export interface WarningRecordCardProps {
|
||||
record?: IRecord;
|
||||
onRecordClick?: (record?: IRecord) => void;
|
||||
style?: React.CSSProperties;
|
||||
cardProps?: CardProps;
|
||||
selectedRecordId?: string;
|
||||
cardStyle?: React.CSSProperties;
|
||||
imgStyle?: React.CSSProperties;
|
||||
};
|
||||
|
||||
export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
|
||||
|
||||
const { record, onRecordClick, style } = props;
|
||||
const { imgSrc = '', id = '', warningType = '', warningInfo = [], cabietInfo = '', warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
|
||||
const componentName = `zhst-biz-warning-record-card`;
|
||||
const { record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props;
|
||||
const { imgSrc, id, warningType, warningInfo = [], cabietText, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
|
||||
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
const selectedBorderStyle = {
|
||||
border: `2px solid ${token.colorPrimary}`, boxShadow: " 0px 2px 9px 0px rgba(0,0,0,0.16)"
|
||||
}
|
||||
const selectedCardStyle: React.CSSProperties = {
|
||||
...(selectedRecordId === record?.id ? selectedBorderStyle : {})
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
onRecordClick?.(record);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={componentName} key={id} onClick={handleClick}>
|
||||
|
||||
<div className={componentName} key={id} onClick={handleClick} style={style}>
|
||||
<Card
|
||||
style={{ width: 356, height: 302 , padding: 10, borderRadius: 4 ,...style}}
|
||||
cover={<img alt="预警图" src={imgSrc} style={{ width: 336, height: 203, borderRadius: 0 }} />}
|
||||
cover={<img alt="预警图" src={imgSrc} style={{ width: 336, height: 203, borderRadius: 0, ...imgStyle }} />}
|
||||
style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }}
|
||||
{...cardProps}
|
||||
>
|
||||
|
||||
<div className='left-context'>
|
||||
<div className="description">{warningType}</div>
|
||||
<div className="warning-type">{warningType}</div>
|
||||
<Space size={0} split={<Divider type="vertical" />}>
|
||||
{warningInfo?.map((item, index) => (
|
||||
<div key={index} className="info-item">
|
||||
@ -75,9 +100,7 @@ export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
|
||||
</Space>
|
||||
<div className='warning-time'>{warningTimeShow}</div>
|
||||
</div>
|
||||
|
||||
<div className='cabietInfo' >{cabietInfo}</div>
|
||||
|
||||
<div className='cabietInfo' >{cabietText}</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
@ -1,29 +1,56 @@
|
||||
|
||||
import React from 'react';
|
||||
import {WarningRecordCard,type IRecord} from '@zhst/biz';
|
||||
import { WarningRecordCard } from '@zhst/biz';
|
||||
import { Space } from 'antd';
|
||||
|
||||
const props = {
|
||||
record :
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '1561561',
|
||||
warningType: '火焰识别',
|
||||
warningInfo:['盒子1','点位1'],
|
||||
cabietInfo: '柜子ID : C001',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp :Date.now() ,
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
onRecordClick:(record?:IRecord) =>{
|
||||
console.log(record)
|
||||
}
|
||||
}
|
||||
// 例如 后端返回这样的数据结构
|
||||
const backEndData = [
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '1561561',
|
||||
warningType: '火焰识别',
|
||||
boxId: '2',
|
||||
position: '2',
|
||||
cabietId: '002',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
},
|
||||
{
|
||||
imgSrc: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
id: '156156155',
|
||||
warningType: '火焰识别',
|
||||
boxId: '1',
|
||||
position: '1',
|
||||
cabietId: '001',
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
}
|
||||
]
|
||||
|
||||
// 前端处理数据结构
|
||||
const dataSource = backEndData.map(o => {
|
||||
return {
|
||||
imgSrc: o.imgSrc,
|
||||
id: o.id,
|
||||
warningType: o.warningType,
|
||||
boxId: o.boxId,
|
||||
position: o.position,
|
||||
cabietId: o.cabietId,
|
||||
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`],
|
||||
// cabietText: `柜子ID: ${o.cabietId}`,
|
||||
warningTimestamp: o.warningTimestamp,
|
||||
}
|
||||
})
|
||||
|
||||
export default () => {
|
||||
|
||||
return (
|
||||
<Space size={[8, 16]} direction="vertical">
|
||||
<WarningRecordCard {...props} />
|
||||
{
|
||||
dataSource?.map((record) => <WarningRecordCard key={record?.id} record={record} />)
|
||||
}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,8 @@
|
||||
.zhst-biz-warning-record-card {
|
||||
cursor: pointer;
|
||||
|
||||
.ant-card-body {
|
||||
padding: 0 !important;
|
||||
padding: 0;
|
||||
font-family: MicrosoftYaHei;
|
||||
line-height: 19px;
|
||||
display: flex;
|
||||
@ -9,17 +11,17 @@
|
||||
.left-context {
|
||||
flex: 1;
|
||||
|
||||
> div{
|
||||
>div {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
> div:nth-child(1) {
|
||||
margin-top: 0;
|
||||
>div:nth-child(1) {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.description{
|
||||
|
||||
.warning-type {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -20,12 +20,11 @@ title: WarningRecordCard 预警记录卡片
|
||||
| id | 数据的唯一id 用于key 传值| string | - | - |
|
||||
| warningType | 预警类型 | string | - | - |
|
||||
| warningInfo | 盒子 点位 柜子 等信息 | string[] | - | - |
|
||||
| cabietInfo | 右侧 柜子信息 | string | - | - |
|
||||
| cabietText | 右侧 柜子信息 | string | - | - |
|
||||
| warningTime | 预警时间 格式化后的时间字符串 | string | - | - |
|
||||
| warningTimestamp | 预警时间戳 | string \| nmbuer | - | - |
|
||||
| warningTimestamp | 预警时间戳 | string \| number | - | - |
|
||||
| warningTimeFormat | 预警时间格式 | string | YYYY-MM-DD HH:mm:ss | - |
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -6,6 +6,7 @@ import type { TreeProps, InputProps } from 'antd';
|
||||
import type { BoxTreeProps } from '../../../tree';
|
||||
import TreeTransferModal from '../../../treeTransferModal'
|
||||
import BoxTree from '../../../tree';
|
||||
// import './index.less'
|
||||
|
||||
export interface BoxPanelProps {
|
||||
searchInputProps?: InputProps
|
||||
|
@ -10,3 +10,10 @@ export { default as TreeTransferModal } from './treeTransferModal'
|
||||
export type { TreeTransferModalProps } from './treeTransferModal'
|
||||
export { default as WarningRecordCard } from './WarningRecordCard'
|
||||
export type { WarningRecordCardProps, IRecord } from './WarningRecordCard'
|
||||
export type { IRecord, WarningRecordCardProps } from './WarningRecordCard'
|
||||
export type { ViewLargerImageModalRef, ViewLargerImageModalProps } from './ViewLargerImageModal'
|
||||
export { default as ViewLargerImageModal, useViewLargerImageModal } from './ViewLargerImageModal'
|
||||
export type { VideoPlayerCardProps } from './VideoPlayerCard'
|
||||
export { default as VideoPlayerCard } from './VideoPlayerCard'
|
||||
export { default as RealTimeMonitor } from './RealTimeMonitor'
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user