Merge branch 'hb/big-image' into 'develop'
feat: 添加 按钮列表 ButtonList See merge request web-project/zhst-lambo!16
This commit is contained in:
commit
641ae6e7e1
@ -1,9 +1,10 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { IRecord, VideoPlayerCardProps, ViewLargerImageModalRef } from '@zhst/biz';
|
||||
import WindowToggle from './components/WindowToggle';
|
||||
import WarningRecordList from './components/WarningRecordList';
|
||||
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
interface RealTimeMonitorProps {
|
||||
prefixCls?: string
|
||||
videoDataSource?: VideoPlayerCardProps[];
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
@ -32,7 +33,11 @@ interface RealTimeMonitorProps {
|
||||
|
||||
export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
|
||||
const { videoDataSource,
|
||||
const { ConfigContext } = ConfigProvider;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
videoDataSource,
|
||||
handleWindowClick,
|
||||
handleCloseButtonClick,
|
||||
selectedWindowKey,
|
||||
@ -43,9 +48,10 @@ export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
selectedRecordId,
|
||||
isRecordListLoading,
|
||||
} = props
|
||||
const componentName = getPrefixCls('biz-real-time-monitor', customizePrefixCls);
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-real-time-monitor' style={{ display: 'flex' }} >
|
||||
<div className={componentName} style={{ display: 'flex' }} >
|
||||
<WindowToggle
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
dataSource={videoDataSource}
|
||||
|
@ -1,10 +1,11 @@
|
||||
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 { ConfigProvider, VideoPlayer, type VideoViewRef, } from '@zhst/meta';
|
||||
import React, { useState, useEffect, ReactNode, useRef, useContext } from 'react';
|
||||
import { CloseOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import './index.less'
|
||||
export interface VideoPlayerCardProps {
|
||||
prefixCls?: string;
|
||||
windowKey?: string;
|
||||
selectedWindowKey?: string;
|
||||
showType?: 'video' | "image";
|
||||
@ -21,8 +22,10 @@ export interface VideoPlayerCardProps {
|
||||
|
||||
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 { ConfigContext } = ConfigProvider;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, showType, imgSrc, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props;
|
||||
const componentName = getPrefixCls('biz-video-player-card', customizePrefixCls);
|
||||
const [cardContent, setCardContent] = useState<JSX.Element | null>(null);
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
|
@ -1,7 +1,8 @@
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef } from 'react';
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef, useContext } from 'react';
|
||||
import { Modal, ModalProps, Space, SpaceProps } from 'antd';
|
||||
import theme from 'antd/lib/theme';
|
||||
import { DownloadOutlined } from '@ant-design/icons';
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import './index.less'
|
||||
|
||||
type ViewLargerImageModalParams = {
|
||||
@ -18,6 +19,7 @@ export interface ViewLargerImageModalRef {
|
||||
}
|
||||
|
||||
export interface ViewLargerImageModalProps {
|
||||
prefixCls?: string
|
||||
imgStyle?: React.CSSProperties;
|
||||
downloadImg?: (imgSrc?: string) => void;
|
||||
title?: string;
|
||||
@ -29,7 +31,10 @@ export interface ViewLargerImageModalProps {
|
||||
export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLargerImageModalProps>(
|
||||
(props, ref) => {
|
||||
|
||||
const { modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props
|
||||
const { ConfigContext } = ConfigProvider;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, modalProps, downloadImg, imgStyle, title = '预警大图', downloadText = '下载大图', spaceProps } = props
|
||||
const componentName = getPrefixCls('biz-warning-larger-image', customizePrefixCls);
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
const [open, setOpen] = useState<boolean>(false);
|
||||
@ -53,7 +58,7 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className='zhst-biz-view-warning-larger-image-modal'
|
||||
className={componentName}
|
||||
open={open}
|
||||
destroyOnClose
|
||||
title={title}
|
||||
|
@ -1,4 +1,4 @@
|
||||
.zhst-biz-view-warning-larger-image-modal {
|
||||
.zhst-biz-warning-larger-image {
|
||||
font-family: MicrosoftYaHei;
|
||||
|
||||
.ant-modal-content {
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Card, Space, Divider, CardProps } from 'antd';
|
||||
import { theme } from 'antd/lib';
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import './index.less'
|
||||
export interface IRecord {
|
||||
|
||||
@ -53,6 +54,7 @@ export interface IRecord {
|
||||
};
|
||||
|
||||
export interface WarningRecordCardProps {
|
||||
prefixCls?: string;
|
||||
record?: IRecord;
|
||||
onRecordClick?: (record?: IRecord) => void;
|
||||
style?: React.CSSProperties;
|
||||
@ -63,9 +65,11 @@ export interface WarningRecordCardProps {
|
||||
};
|
||||
|
||||
export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
|
||||
|
||||
const componentName = `zhst-biz-warning-record-card`;
|
||||
const { record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props;
|
||||
|
||||
const { ConfigContext } = ConfigProvider;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, record, onRecordClick, style, cardProps, selectedRecordId, cardStyle, imgStyle } = props;
|
||||
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 formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
|
120
packages/meta/src/ButtonList/ButtonList.tsx
Normal file
120
packages/meta/src/ButtonList/ButtonList.tsx
Normal file
@ -0,0 +1,120 @@
|
||||
import React, { useState, useMemo, ReactNode, useRef, useEffect, useContext } from 'react';
|
||||
import { Button, Col, Dropdown, Row } from 'antd';
|
||||
import { Gutter } from 'antd/es/grid/row';
|
||||
import { ConfigContext } from '../config-provider';
|
||||
import './index.less';
|
||||
|
||||
|
||||
export interface IButtonItem {
|
||||
key: string;
|
||||
text: ReactNode;
|
||||
onClick: () => void;
|
||||
children?: Array<Omit<IButtonItem, 'weight'>>;
|
||||
// 用于排序
|
||||
weight?: number;
|
||||
icon?: ReactNode
|
||||
className?: string;
|
||||
isCenter?: boolean;
|
||||
};
|
||||
export interface IButtonItemWithoutWeight extends Omit<IButtonItem, 'weight'> { }
|
||||
export interface ButtonListProps {
|
||||
prefixCls?: string;
|
||||
buttons: Array<IButtonItem>
|
||||
gutter?: Gutter;
|
||||
};
|
||||
|
||||
const ButtonList: React.FC<ButtonListProps> = (props) => {
|
||||
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { buttons, gutter, prefixCls: customizePrefixCls } = props
|
||||
const componentName = getPrefixCls('button-list', customizePrefixCls);
|
||||
const buttonListRef = useRef<HTMLDivElement>(null);
|
||||
const centerButtonRef = useRef<HTMLDivElement>(null);
|
||||
const [activeKey, setActiveKey] = useState<string | null>(null);
|
||||
const [buttonListWrapMarginLeft, setButtonListWrapMarginLeft] = useState(0)
|
||||
|
||||
const sortedButtons = useMemo(() => {
|
||||
let buttonList = buttons.map((btn, index) => {
|
||||
if (btn.weight === undefined) {
|
||||
return { ...btn, weight: index }
|
||||
} else {
|
||||
return { ...btn, weight: btn.weight }
|
||||
}
|
||||
})
|
||||
const newButtonList = buttonList?.sort((a, b) => a.weight - b.weight)
|
||||
return newButtonList;
|
||||
}, [buttons]);
|
||||
|
||||
const handleButtonClick = (key: string, item: IButtonItem) => {
|
||||
setActiveKey(activeKey === key ? null : key);
|
||||
if (!item.children) {
|
||||
item.onClick();
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// 如果获取不到 需要居中的
|
||||
if (!centerButtonRef) return
|
||||
// 获取 buttonList 宽度
|
||||
const buttonListWidth: number = buttonListRef.current?.offsetWidth as number;
|
||||
// 获取 centerButton 宽度
|
||||
const centerButtonWidth: number = centerButtonRef.current?.offsetWidth as number
|
||||
// 获取 buttonList 相对视口左偏移量
|
||||
const buttonListOffset: number = buttonListRef.current?.offsetLeft as number
|
||||
// 获取 buttonList 中心点 距视口左边距离
|
||||
const buttonListCenterOffset = buttonListOffset + buttonListWidth / 2
|
||||
// 获取 centerButton 中心点 相对视口左偏移量
|
||||
const centerButtonOffset: number = centerButtonRef.current?.offsetLeft as number + centerButtonWidth / 2
|
||||
/*
|
||||
计算 centerButton 修正距离
|
||||
用 buttonList 中心点 距视口左边距离 - centerButton 中心点 相对视口左偏移量
|
||||
作为 buttonListWrap marginLeft 修正距离
|
||||
*/
|
||||
|
||||
// 这里为什么要 * 2 由于 justify-content: center; marginLeft 需要 * 2才是 正确的值 具体原因 还在研究
|
||||
const buttonListWrapMarginLeft = (buttonListCenterOffset - centerButtonOffset) * 2
|
||||
setButtonListWrapMarginLeft(buttonListWrapMarginLeft)
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className={componentName} ref={buttonListRef}>
|
||||
<Row gutter={gutter} className={`${componentName}-list-wrap`} style={{ marginLeft: buttonListWrapMarginLeft }} >
|
||||
{sortedButtons?.map((item) => (
|
||||
<Col key={item.key} ref={item?.isCenter ? centerButtonRef : undefined} >
|
||||
{item.children ? (
|
||||
<Dropdown
|
||||
menu={{
|
||||
items: item.children.map((child) => ({
|
||||
key: child.key,
|
||||
label: <span>{child.text}</span>,
|
||||
onClick: () => child.onClick(),
|
||||
})),
|
||||
}}
|
||||
open={activeKey === item.key}
|
||||
onOpenChange={(visible: boolean) => {
|
||||
if (!visible) setActiveKey(null);
|
||||
}}
|
||||
trigger={['click']}
|
||||
>
|
||||
<Button type="text" icon={item.icon} onClick={() => handleButtonClick(item.key, item)}>{item.text}</Button>
|
||||
</Dropdown>
|
||||
) : (
|
||||
<Button type="text"
|
||||
icon={item.icon}
|
||||
onClick={() => handleButtonClick(item.key, item)}
|
||||
>
|
||||
{item.text}
|
||||
</Button>
|
||||
)}
|
||||
</Col>
|
||||
))}
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ButtonList;
|
62
packages/meta/src/ButtonList/demo/base.tsx
Normal file
62
packages/meta/src/ButtonList/demo/base.tsx
Normal file
@ -0,0 +1,62 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import { Space } from 'antd'
|
||||
import { DownloadOutlined } from '@ant-design/icons';
|
||||
import { ButtonList } from '@zhst/meta'
|
||||
import { ButtonListProps } from '../ButtonList';
|
||||
import "./index.less"
|
||||
|
||||
export default () => {
|
||||
const [isPlay, setIsPlay] = useState(true);
|
||||
|
||||
const props: ButtonListProps = useMemo(() => {
|
||||
return {
|
||||
buttons: [
|
||||
{
|
||||
key: 'button1',
|
||||
text: '一级按钮1',
|
||||
onClick: () => console.log('一级按钮1被点击'),
|
||||
children: [
|
||||
{ key: 'subButton1-1', text: '二级按钮1-1', onClick: () => console.log('二级按钮1-1被点击'), icon: <DownloadOutlined /> },
|
||||
{ key: 'subButton1-2', text: '二级按钮1-2', onClick: () => console.log('二级按钮1-2被点击') },
|
||||
],
|
||||
// icon:<DownloadOutlined />,
|
||||
},
|
||||
{
|
||||
key: 'button2',
|
||||
text: '一级按钮2',
|
||||
onClick: () => console.log('一级按钮2被点击'),
|
||||
},
|
||||
{
|
||||
key: '播放',
|
||||
text: isPlay ? '播放按钮' : '图片按钮',
|
||||
onClick: () => { setIsPlay(!isPlay) },
|
||||
// isCenter: true
|
||||
},
|
||||
{
|
||||
key: 'button3',
|
||||
text: '一级按钮3',
|
||||
onClick: () => console.log('一级按钮3被点击'),
|
||||
},
|
||||
{
|
||||
key: 'button4',
|
||||
text: '一级按钮4',
|
||||
onClick: () => console.log('一级按钮4被点击'),
|
||||
|
||||
},
|
||||
{
|
||||
key: 'button5',
|
||||
text: '一级按钮5',
|
||||
onClick: () => console.log('一级按钮5被点击'),
|
||||
children: [
|
||||
{ key: 'subButton5-1', text: '二级按钮5-1', onClick: () => console.log('二级按钮5-1被点击') },
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
}, [isPlay])
|
||||
return (
|
||||
<Space size={[8, 16]} direction="vertical">
|
||||
<ButtonList {...props} />
|
||||
</Space>
|
||||
)
|
||||
}
|
5
packages/meta/src/ButtonList/demo/index.less
Normal file
5
packages/meta/src/ButtonList/demo/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
#buttonlist-demo-base {
|
||||
.dumi-default-previewer-demo>div {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
15
packages/meta/src/ButtonList/index.less
Normal file
15
packages/meta/src/ButtonList/index.less
Normal file
@ -0,0 +1,15 @@
|
||||
|
||||
.zhst-button-list {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.ant-btn-text:hover{
|
||||
background: none !important ;
|
||||
color: #247fdb !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
19
packages/meta/src/ButtonList/index.md
Normal file
19
packages/meta/src/ButtonList/index.md
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
group: 通用
|
||||
category: Components
|
||||
subtitle: 按钮列表
|
||||
title: ButtonList 按钮列表组件
|
||||
---
|
||||
|
||||
# ButtonList 按钮列表组件
|
||||
|
||||
<code src="./demo/base.tsx"></code>
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| ---- | ---- | ---- | ------ | ---- |
|
||||
| buttons | 传入按钮列表 |ButtonItem[]| - | - |
|
||||
| customButton | 传入自定义按钮 | ButtonItem | - | - |
|
||||
| gutter | 控制间隙 | Gutter | - | - |
|
||||
|
4
packages/meta/src/ButtonList/index.tsx
Normal file
4
packages/meta/src/ButtonList/index.tsx
Normal file
@ -0,0 +1,4 @@
|
||||
import ButtonList from './ButtonList'
|
||||
|
||||
|
||||
export default ButtonList
|
@ -93,3 +93,4 @@ export { default as App } from './app';
|
||||
export type { AppProps } from './app';
|
||||
export { default as notification } from './notification';
|
||||
export type { ArgsProps as NotificationArgsProps } from './notification';
|
||||
export { default as ButtonList } from './ButtonList'
|
||||
|
Loading…
Reference in New Issue
Block a user