feat: 添加 视频窗口切换组件
This commit is contained in:
commit
d064da49a4
@ -1,5 +1,47 @@
|
|||||||
# @zhst/biz
|
# @zhst/biz
|
||||||
|
|
||||||
|
## 0.9.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.2
|
||||||
|
- @zhst/func@0.7.3
|
||||||
|
- @zhst/meta@0.8.3
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.1
|
||||||
|
- @zhst/func@0.7.2
|
||||||
|
- @zhst/meta@0.8.2
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- @zhst/biz 优化数组件
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.0
|
||||||
|
- @zhst/func@0.7.1
|
||||||
|
- @zhst/meta@0.8.1
|
||||||
|
|
||||||
|
## 0.7.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- 新增预警记录卡片组件
|
||||||
|
|
||||||
## 0.6.0
|
## 0.6.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
3
packages/biz/es/index.d.ts
vendored
3
packages/biz/es/index.d.ts
vendored
@ -1,5 +1,8 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal';
|
export { default as BigImageModal } from './BigImageModal';
|
||||||
export { default as BoxSelectTree } from './boxSelectTree';
|
export { default as BoxSelectTree } from './boxSelectTree';
|
||||||
export { default as Tree } from './tree';
|
export { default as Tree } from './tree';
|
||||||
|
export type { TreeData } from './tree';
|
||||||
export { default as TreeTransfer } from './treeTransfer';
|
export { default as TreeTransfer } from './treeTransfer';
|
||||||
export { default as TreeTransferModal } from './treeTransferModal';
|
export { default as TreeTransferModal } from './treeTransferModal';
|
||||||
|
export { default as WarningRecordCard } from './WarningRecordCard';
|
||||||
|
export type { IRecord, WarningRecordCardProps } from './WarningRecordCard';
|
||||||
|
@ -2,4 +2,5 @@ export { default as BigImageModal } from "./BigImageModal";
|
|||||||
export { default as BoxSelectTree } from "./boxSelectTree";
|
export { default as BoxSelectTree } from "./boxSelectTree";
|
||||||
export { default as Tree } from "./tree";
|
export { default as Tree } from "./tree";
|
||||||
export { default as TreeTransfer } from "./treeTransfer";
|
export { default as TreeTransfer } from "./treeTransfer";
|
||||||
export { default as TreeTransferModal } from "./treeTransferModal";
|
export { default as TreeTransferModal } from "./treeTransferModal";
|
||||||
|
export { default as WarningRecordCard } from "./WarningRecordCard";
|
26
packages/biz/es/useSocket/ws.d.ts
vendored
26
packages/biz/es/useSocket/ws.d.ts
vendored
@ -1,26 +0,0 @@
|
|||||||
declare class Channel {
|
|
||||||
/**
|
|
||||||
* io 实例化对象
|
|
||||||
*/
|
|
||||||
ioIns: any;
|
|
||||||
/**
|
|
||||||
* 已存在的订阅列表
|
|
||||||
*/
|
|
||||||
listeners: never[];
|
|
||||||
/**
|
|
||||||
* 调试信息 记录订阅/反订阅次数
|
|
||||||
*/
|
|
||||||
subscribeListenerId: never[];
|
|
||||||
unSubscribeListenerId: never[];
|
|
||||||
init: () => void;
|
|
||||||
retry: (listener: {
|
|
||||||
[x: string]: any;
|
|
||||||
lastRetryInterval: number | undefined;
|
|
||||||
intervalId: NodeJS.Timeout;
|
|
||||||
} | undefined) => void;
|
|
||||||
doEmit: (topic: any, req: any, listenerId: any) => void;
|
|
||||||
subscribe(topic: any, req: any, handle: any): () => void;
|
|
||||||
unSubscribe(topic: any, req: any, handleId: any, listenerId: any): void;
|
|
||||||
}
|
|
||||||
declare const channelIns: Channel;
|
|
||||||
export default channelIns;
|
|
8
packages/biz/es/utils/constants.d.ts
vendored
8
packages/biz/es/utils/constants.d.ts
vendored
@ -21,3 +21,11 @@ export declare const DeviceTab: {
|
|||||||
REAL_CAMERA_ONLYFACE: number;
|
REAL_CAMERA_ONLYFACE: number;
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number;
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number;
|
||||||
};
|
};
|
||||||
|
export declare const BOX_TYPE_LIST: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}[];
|
||||||
|
export declare const ALL_LIST: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}[];
|
||||||
|
@ -27,4 +27,17 @@ export var DeviceTab = {
|
|||||||
REAL_CAMERA_NOFACE: 6,
|
REAL_CAMERA_NOFACE: 6,
|
||||||
REAL_CAMERA_ONLYFACE: 7,
|
REAL_CAMERA_ONLYFACE: 7,
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8 // 只有普通摄像头,没有人脸、没有盒子、直连
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 盒子 Tab 切换
|
||||||
|
export var BOX_TYPE_LIST = [{
|
||||||
|
value: '1',
|
||||||
|
label: '盒子'
|
||||||
|
}, {
|
||||||
|
value: '2',
|
||||||
|
label: '盒子组'
|
||||||
|
}];
|
||||||
|
export var ALL_LIST = [{
|
||||||
|
value: '',
|
||||||
|
label: '全部'
|
||||||
|
}];
|
3
packages/biz/lib/index.d.ts
vendored
3
packages/biz/lib/index.d.ts
vendored
@ -1,5 +1,8 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal';
|
export { default as BigImageModal } from './BigImageModal';
|
||||||
export { default as BoxSelectTree } from './boxSelectTree';
|
export { default as BoxSelectTree } from './boxSelectTree';
|
||||||
export { default as Tree } from './tree';
|
export { default as Tree } from './tree';
|
||||||
|
export type { TreeData } from './tree';
|
||||||
export { default as TreeTransfer } from './treeTransfer';
|
export { default as TreeTransfer } from './treeTransfer';
|
||||||
export { default as TreeTransferModal } from './treeTransferModal';
|
export { default as TreeTransferModal } from './treeTransferModal';
|
||||||
|
export { default as WarningRecordCard } from './WarningRecordCard';
|
||||||
|
export type { IRecord, WarningRecordCardProps } from './WarningRecordCard';
|
||||||
|
@ -33,7 +33,8 @@ __export(src_exports, {
|
|||||||
BoxSelectTree: () => import_boxSelectTree.default,
|
BoxSelectTree: () => import_boxSelectTree.default,
|
||||||
Tree: () => import_tree.default,
|
Tree: () => import_tree.default,
|
||||||
TreeTransfer: () => import_treeTransfer.default,
|
TreeTransfer: () => import_treeTransfer.default,
|
||||||
TreeTransferModal: () => import_treeTransferModal.default
|
TreeTransferModal: () => import_treeTransferModal.default,
|
||||||
|
WarningRecordCard: () => import_WarningRecordCard.default
|
||||||
});
|
});
|
||||||
module.exports = __toCommonJS(src_exports);
|
module.exports = __toCommonJS(src_exports);
|
||||||
var import_BigImageModal = __toESM(require("./BigImageModal"));
|
var import_BigImageModal = __toESM(require("./BigImageModal"));
|
||||||
@ -41,11 +42,13 @@ var import_boxSelectTree = __toESM(require("./boxSelectTree"));
|
|||||||
var import_tree = __toESM(require("./tree"));
|
var import_tree = __toESM(require("./tree"));
|
||||||
var import_treeTransfer = __toESM(require("./treeTransfer"));
|
var import_treeTransfer = __toESM(require("./treeTransfer"));
|
||||||
var import_treeTransferModal = __toESM(require("./treeTransferModal"));
|
var import_treeTransferModal = __toESM(require("./treeTransferModal"));
|
||||||
|
var import_WarningRecordCard = __toESM(require("./WarningRecordCard"));
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
// Annotate the CommonJS export names for ESM import in node:
|
||||||
0 && (module.exports = {
|
0 && (module.exports = {
|
||||||
BigImageModal,
|
BigImageModal,
|
||||||
BoxSelectTree,
|
BoxSelectTree,
|
||||||
Tree,
|
Tree,
|
||||||
TreeTransfer,
|
TreeTransfer,
|
||||||
TreeTransferModal
|
TreeTransferModal,
|
||||||
|
WarningRecordCard
|
||||||
});
|
});
|
||||||
|
26
packages/biz/lib/useSocket/ws.d.ts
vendored
26
packages/biz/lib/useSocket/ws.d.ts
vendored
@ -1,26 +0,0 @@
|
|||||||
declare class Channel {
|
|
||||||
/**
|
|
||||||
* io 实例化对象
|
|
||||||
*/
|
|
||||||
ioIns: any;
|
|
||||||
/**
|
|
||||||
* 已存在的订阅列表
|
|
||||||
*/
|
|
||||||
listeners: never[];
|
|
||||||
/**
|
|
||||||
* 调试信息 记录订阅/反订阅次数
|
|
||||||
*/
|
|
||||||
subscribeListenerId: never[];
|
|
||||||
unSubscribeListenerId: never[];
|
|
||||||
init: () => void;
|
|
||||||
retry: (listener: {
|
|
||||||
[x: string]: any;
|
|
||||||
lastRetryInterval: number | undefined;
|
|
||||||
intervalId: NodeJS.Timeout;
|
|
||||||
} | undefined) => void;
|
|
||||||
doEmit: (topic: any, req: any, listenerId: any) => void;
|
|
||||||
subscribe(topic: any, req: any, handle: any): () => void;
|
|
||||||
unSubscribe(topic: any, req: any, handleId: any, listenerId: any): void;
|
|
||||||
}
|
|
||||||
declare const channelIns: Channel;
|
|
||||||
export default channelIns;
|
|
8
packages/biz/lib/utils/constants.d.ts
vendored
8
packages/biz/lib/utils/constants.d.ts
vendored
@ -21,3 +21,11 @@ export declare const DeviceTab: {
|
|||||||
REAL_CAMERA_ONLYFACE: number;
|
REAL_CAMERA_ONLYFACE: number;
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number;
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: number;
|
||||||
};
|
};
|
||||||
|
export declare const BOX_TYPE_LIST: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}[];
|
||||||
|
export declare const ALL_LIST: {
|
||||||
|
value: string;
|
||||||
|
label: string;
|
||||||
|
}[];
|
||||||
|
@ -19,7 +19,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|||||||
// src/utils/constants.ts
|
// src/utils/constants.ts
|
||||||
var constants_exports = {};
|
var constants_exports = {};
|
||||||
__export(constants_exports, {
|
__export(constants_exports, {
|
||||||
|
ALL_LIST: () => ALL_LIST,
|
||||||
BODY_SEARCH_THRESHOID: () => BODY_SEARCH_THRESHOID,
|
BODY_SEARCH_THRESHOID: () => BODY_SEARCH_THRESHOID,
|
||||||
|
BOX_TYPE_LIST: () => BOX_TYPE_LIST,
|
||||||
DeviceTab: () => DeviceTab,
|
DeviceTab: () => DeviceTab,
|
||||||
ENTER_CIRCLE: () => ENTER_CIRCLE,
|
ENTER_CIRCLE: () => ENTER_CIRCLE,
|
||||||
GLOBAL_IS_BOX_VMS_SHOW: () => GLOBAL_IS_BOX_VMS_SHOW,
|
GLOBAL_IS_BOX_VMS_SHOW: () => GLOBAL_IS_BOX_VMS_SHOW,
|
||||||
@ -62,9 +64,18 @@ var DeviceTab = {
|
|||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8
|
||||||
// 只有普通摄像头,没有人脸、没有盒子、直连
|
// 只有普通摄像头,没有人脸、没有盒子、直连
|
||||||
};
|
};
|
||||||
|
var BOX_TYPE_LIST = [
|
||||||
|
{ value: "1", label: "盒子" },
|
||||||
|
{ value: "2", label: "盒子组" }
|
||||||
|
];
|
||||||
|
var ALL_LIST = [
|
||||||
|
{ value: "", label: "全部" }
|
||||||
|
];
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
// Annotate the CommonJS export names for ESM import in node:
|
||||||
0 && (module.exports = {
|
0 && (module.exports = {
|
||||||
|
ALL_LIST,
|
||||||
BODY_SEARCH_THRESHOID,
|
BODY_SEARCH_THRESHOID,
|
||||||
|
BOX_TYPE_LIST,
|
||||||
DeviceTab,
|
DeviceTab,
|
||||||
ENTER_CIRCLE,
|
ENTER_CIRCLE,
|
||||||
GLOBAL_IS_BOX_VMS_SHOW,
|
GLOBAL_IS_BOX_VMS_SHOW,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/biz",
|
"name": "@zhst/biz",
|
||||||
"version": "0.6.0",
|
"version": "0.9.1",
|
||||||
"description": "业务库",
|
"description": "业务库",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"business",
|
"business",
|
||||||
@ -47,6 +47,5 @@
|
|||||||
"classnames": "^2.5.1",
|
"classnames": "^2.5.1",
|
||||||
"rc-util": "^5.38.1",
|
"rc-util": "^5.38.1",
|
||||||
"dayjs": "^1.11.10"
|
"dayjs": "^1.11.10"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
103
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
103
packages/biz/src/VideoPlayerCard/VideoPlayerCard.tsx
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
22
packages/biz/src/VideoPlayerCard/index.md
Normal file
22
packages/biz/src/VideoPlayerCard/index.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 视频播放卡片
|
||||||
|
title: VideoPlayerCard 视频播放卡片
|
||||||
|
---
|
||||||
|
|
||||||
|
# VideoPlayerCard 视频播放卡片
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
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
|
@ -18,6 +18,8 @@ export interface IRecord {
|
|||||||
用于显示 盒子 点位 柜子 等信息
|
用于显示 盒子 点位 柜子 等信息
|
||||||
*/
|
*/
|
||||||
warningInfo?: string[]
|
warningInfo?: string[]
|
||||||
|
/*
|
||||||
|
右侧 柜子id 显示
|
||||||
/*
|
/*
|
||||||
盒子 ID
|
盒子 ID
|
||||||
*/
|
*/
|
||||||
@ -30,6 +32,8 @@ export interface IRecord {
|
|||||||
柜子id
|
柜子id
|
||||||
*/
|
*/
|
||||||
cabietId?: string;
|
cabietId?: string;
|
||||||
|
/*
|
||||||
|
直接传格式化好的时间
|
||||||
/*
|
/*
|
||||||
右侧 柜子id 显示
|
右侧 柜子id 显示
|
||||||
*/
|
*/
|
||||||
@ -38,15 +42,16 @@ export interface IRecord {
|
|||||||
直接传格式化好的时间
|
直接传格式化好的时间
|
||||||
*/
|
*/
|
||||||
warningTime?: string;
|
warningTime?: string;
|
||||||
/*
|
/*
|
||||||
传格时间戳
|
传格时间戳
|
||||||
*/
|
*/
|
||||||
warningTimestamp?: string | number
|
warningTimestamp?: string | number
|
||||||
/*
|
/*
|
||||||
传格时间格式
|
传格时间格式
|
||||||
@default YYYY-MM-DD HH:mm:ss
|
@default YYYY-MM-DD HH:mm:ss
|
||||||
*/
|
*/
|
||||||
warningTimeFormat?: string;
|
warningTimeFormat?: string;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface WarningRecordCardProps {
|
export interface WarningRecordCardProps {
|
||||||
|
71
packages/biz/src/WindowToggle/WindowToggle.tsx
Normal file
71
packages/biz/src/WindowToggle/WindowToggle.tsx
Normal file
@ -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;
|
||||||
|
|
166
packages/biz/src/WindowToggle/demo/base.tsx
Normal file
166
packages/biz/src/WindowToggle/demo/base.tsx
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import { IRecord, VideoPlayerCardProps, WindowToggle, useViewLargerImageModal } from '@zhst/biz';
|
||||||
|
import { videoData, warningData } from './mock';
|
||||||
|
import { Space } from 'antd';
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import WarningRecordList from './components/WarningRecordList';
|
||||||
|
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">
|
||||||
|
<div className='zhst-biz-real-time-monitor' style={{ display: 'flex' }} >
|
||||||
|
<WindowToggle
|
||||||
|
selectedWindowKey={selectedWindowKey}
|
||||||
|
dataSource={videoDataSource}
|
||||||
|
handleWindowClick={handleWindowClick}
|
||||||
|
handleCloseButtonClick={clearWindowData}
|
||||||
|
/>
|
||||||
|
<WarningRecordList
|
||||||
|
dataSource={warningDataSource}
|
||||||
|
handleDownloadImg={handleDownloadImg}
|
||||||
|
onRecordClick={onRecordClick}
|
||||||
|
selectedRecordId={selectedRecordId}
|
||||||
|
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||||
|
isRecordListLoading={isRecordListLoading}
|
||||||
|
recordListTitle="监控预警记录"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button onClick={() => { mockData() }}>模拟数据</button>
|
||||||
|
</Space>
|
||||||
|
)
|
||||||
|
}
|
@ -0,0 +1,76 @@
|
|||||||
|
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;
|
||||||
|
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
|
5
packages/biz/src/WindowToggle/demo/index.less
Normal file
5
packages/biz/src/WindowToggle/demo/index.less
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#windowtoggle-demo-base {
|
||||||
|
.dumi-default-previewer-demo>div {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
65
packages/biz/src/WindowToggle/demo/mock.tsx
Normal file
65
packages/biz/src/WindowToggle/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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
45
packages/biz/src/WindowToggle/index.less
Normal file
45
packages/biz/src/WindowToggle/index.less
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
22
packages/biz/src/WindowToggle/index.md
Normal file
22
packages/biz/src/WindowToggle/index.md
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
---
|
||||||
|
group: 数据展示
|
||||||
|
category: Components
|
||||||
|
subtitle: 窗口切换组件
|
||||||
|
title: WindowToggle 窗口切换组件
|
||||||
|
---
|
||||||
|
|
||||||
|
# WindowToggle 窗口切换组件
|
||||||
|
|
||||||
|
|
||||||
|
<code src="./demo/base.tsx"></code>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
|
| --- | --- | --- | --- | --- |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
2
packages/biz/src/WindowToggle/index.tsx
Normal file
2
packages/biz/src/WindowToggle/index.tsx
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
import WindowToggle from './WindowToggle'
|
||||||
|
export default WindowToggle
|
@ -16,6 +16,9 @@ export interface BoxSelectTreeProps {
|
|||||||
tabsProps?: TabsProps
|
tabsProps?: TabsProps
|
||||||
searchInputProps?: InputProps
|
searchInputProps?: InputProps
|
||||||
treeProps?: TreeProps
|
treeProps?: TreeProps
|
||||||
|
showOptions?: boolean
|
||||||
|
customImport?: any
|
||||||
|
extraBtns?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
||||||
@ -31,7 +34,10 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
onCreateSubmit,
|
onCreateSubmit,
|
||||||
tabsProps,
|
tabsProps,
|
||||||
searchInputProps,
|
searchInputProps,
|
||||||
treeProps
|
treeProps,
|
||||||
|
customImport,
|
||||||
|
extraBtns,
|
||||||
|
showOptions = true
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const onChange = (key: string) => {
|
const onChange = (key: string) => {
|
||||||
@ -54,6 +60,9 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
onItemCheck={onItemCheck}
|
onItemCheck={onItemCheck}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
|
showOptions={showOptions}
|
||||||
|
customImport={customImport}
|
||||||
|
extraBtns={extraBtns}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
@ -72,6 +81,9 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
|||||||
onSearch={onSearch}
|
onSearch={onSearch}
|
||||||
onItemCheck={onItemCheck}
|
onItemCheck={onItemCheck}
|
||||||
onItemSelect={onItemSelect}
|
onItemSelect={onItemSelect}
|
||||||
|
showOptions={showOptions}
|
||||||
|
customImport={customImport}
|
||||||
|
extraBtns={extraBtns}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { FC, useState, useRef } from 'react';
|
import React, { FC, useState, useRef } from 'react';
|
||||||
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
|
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
|
||||||
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
|
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
|
||||||
import { DiffOutlined, SwitcherOutlined } from '@ant-design/icons'
|
import { ClockCircleOutlined, CloseCircleOutlined, DiffOutlined, FolderAddOutlined, ImportOutlined, SwitcherOutlined } from '@ant-design/icons'
|
||||||
import type { TreeProps, InputProps } from 'antd';
|
import type { TreeProps, InputProps } from 'antd';
|
||||||
import TreeTransferModal from '../../../treeTransferModal'
|
import TreeTransferModal from '../../../treeTransferModal'
|
||||||
import BoxTree from '../../../tree';
|
import BoxTree from '../../../tree';
|
||||||
@ -9,6 +9,7 @@ import BoxTree from '../../../tree';
|
|||||||
|
|
||||||
export interface BoxGroupPanelProps {
|
export interface BoxGroupPanelProps {
|
||||||
searchInputProps?: InputProps
|
searchInputProps?: InputProps
|
||||||
|
showOptions?: boolean
|
||||||
treeProps?: TreeProps
|
treeProps?: TreeProps
|
||||||
data: TreeDataNode[]
|
data: TreeDataNode[]
|
||||||
boxDataSource: TreeDataNode[]
|
boxDataSource: TreeDataNode[]
|
||||||
@ -19,11 +20,16 @@ export interface BoxGroupPanelProps {
|
|||||||
onBoxBatchDelete?: (data?: any) => void
|
onBoxBatchDelete?: (data?: any) => void
|
||||||
onBoxDelete?: (data?: any) => void
|
onBoxDelete?: (data?: any) => void
|
||||||
onCreateSubmit?: ModalFormProps['onFinish']
|
onCreateSubmit?: ModalFormProps['onFinish']
|
||||||
|
onClockClick?: () => void
|
||||||
|
customImport?: any
|
||||||
|
extraBtns?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
||||||
const {
|
const {
|
||||||
searchInputProps,
|
searchInputProps,
|
||||||
|
showOptions = true,
|
||||||
|
extraBtns,
|
||||||
data = [],
|
data = [],
|
||||||
onSearch,
|
onSearch,
|
||||||
treeProps,
|
treeProps,
|
||||||
@ -32,7 +38,9 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
onCreateSubmit,
|
onCreateSubmit,
|
||||||
onBoxBatchDelete,
|
onBoxBatchDelete,
|
||||||
onBoxDelete,
|
onBoxDelete,
|
||||||
boxDataSource
|
onClockClick,
|
||||||
|
boxDataSource,
|
||||||
|
customImport
|
||||||
} = props
|
} = props
|
||||||
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
|
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
|
||||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||||
@ -41,8 +49,7 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
const createFormRef = useRef<
|
const createFormRef = useRef<
|
||||||
ProFormInstance<{
|
ProFormInstance<{
|
||||||
name: string;
|
name: string;
|
||||||
company?: string;
|
boxList?: any[];
|
||||||
useMode?: string;
|
|
||||||
}>
|
}>
|
||||||
>()
|
>()
|
||||||
|
|
||||||
@ -76,89 +83,109 @@ const BoxGroupPanel: FC<BoxGroupPanelProps> = (props) => {
|
|||||||
setTargetItems(pre => pre.filter(o => o.key !== key))
|
setTargetItems(pre => pre.filter(o => o.key !== key))
|
||||||
}
|
}
|
||||||
|
|
||||||
const onOk = (data: any) => {
|
// 盒子点击确定
|
||||||
console.log('data', data)
|
const onBoxChoiceOk = async (data: any) => {
|
||||||
|
createFormRef.current?.setFieldValue('boxList', data)
|
||||||
|
createFormRef.current?.setFieldValue('boxName', 123)
|
||||||
|
console.log(createFormRef.current?.getFieldValue('boxList'))
|
||||||
|
setBoxChoiceOpen(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const onReset = () => {
|
// 盒子选择重置
|
||||||
|
const onBoxChoiceReset = () => {
|
||||||
setCheckedKeys([])
|
setCheckedKeys([])
|
||||||
setTargetItems([])
|
setTargetItems([])
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '0 16px' }}>
|
<div style={{ padding: '0 16px' }}>
|
||||||
|
{/* 盒子选择弹框 */}
|
||||||
<TreeTransferModal
|
<TreeTransferModal
|
||||||
open={boxChoiceOpen}
|
open={boxChoiceOpen}
|
||||||
onCancel={() => setBoxChoiceOpen(false)}
|
onCancel={() => setBoxChoiceOpen(false)}
|
||||||
onRadioChange={(val) => console.log('radio', val)} // 顶部 radio 事件
|
onRadioChange={(e) => console.log('radio', e.target.value)} // 顶部 radio 事件
|
||||||
dataSource={boxDataSource} // 数据源
|
dataSource={boxDataSource} // 数据源
|
||||||
targetItems={targetItems} // 右侧选中项
|
targetItems={targetItems} // 右侧选中项
|
||||||
checkedKeys={checkedKeys} // 左侧选中
|
checkedKeys={checkedKeys} // 左侧选中
|
||||||
onReset={onReset} // 重置按钮事件
|
onReset={onBoxChoiceReset} // 重置按钮事件
|
||||||
onOk={onOk} // 确定按钮事件
|
onOk={onBoxChoiceOk} // 确定按钮事件
|
||||||
onTreeCheck={onTreeCheck} // 树check选中事件
|
onTreeCheck={onTreeCheck} // 树check选中事件
|
||||||
onItemDelete={onItemDelete} // 右侧点击删除事件
|
onItemDelete={onItemDelete} // 右侧点击删除事件
|
||||||
/>
|
/>
|
||||||
<Space size={12} direction='vertical'>
|
<Space size={12} direction='vertical' style={{ width: '100%' }}>
|
||||||
<Space>
|
<Space size={4} style={{ width: '100%', justifyContent: 'space-between' }} >
|
||||||
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
|
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
|
||||||
<Button style={{ width: '80px' }} type='primary' >导入盒子</Button>
|
{customImport || (
|
||||||
|
<>
|
||||||
|
<Button type="text" onClick={() => handleCheckable()} icon={!isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
|
||||||
|
<Button type="text" onClick={() => onClockClick?.()} icon={<ClockCircleOutlined />} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Space>
|
</Space>
|
||||||
<Space align='center'>
|
{/* 是否显示操作按钮 */}
|
||||||
<ModalForm
|
{showOptions && (
|
||||||
width={'600px'}
|
<>
|
||||||
formRef={createFormRef}
|
<Space align='center'>
|
||||||
title="新建组"
|
<Button type='text' style={{ padding: '4px 8px' }} icon={<ImportOutlined />} >导入盒子</Button>
|
||||||
modalProps={{ destroyOnClose: true }}
|
<Divider type="vertical" style={{ margin: '8px 0' }} />
|
||||||
layout='horizontal'
|
<ModalForm<{
|
||||||
labelCol={{ span: 6 }}
|
name: string
|
||||||
wrapperCol={{ span: 18 }}
|
boxList?: any[]
|
||||||
trigger={<Button type='link' >新建组</Button>}
|
}>
|
||||||
submitter={{
|
width={'600px'}
|
||||||
searchConfig: {
|
formRef={createFormRef}
|
||||||
submitText: '确定',
|
title="新建组"
|
||||||
resetText: '取消',
|
modalProps={{ destroyOnClose: true }}
|
||||||
},
|
layout='horizontal'
|
||||||
}}
|
labelCol={{ span: 6 }}
|
||||||
onFinish={onCreateSubmit}
|
wrapperCol={{ span: 18 }}
|
||||||
>
|
trigger={<Button type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} >新建组</Button>}
|
||||||
<ProFormText
|
submitter={{
|
||||||
rules={[
|
searchConfig: {
|
||||||
{
|
submitText: '确定',
|
||||||
required: true,
|
resetText: '取消',
|
||||||
},
|
},
|
||||||
]}
|
}}
|
||||||
width="md"
|
onFinish={onCreateSubmit}
|
||||||
name="name"
|
>
|
||||||
label="盒子组名称"
|
<ProFormText
|
||||||
placeholder="请输入盒子名称"
|
rules={[
|
||||||
/>
|
{
|
||||||
<ProFormText
|
required: true,
|
||||||
width="md"
|
},
|
||||||
name="boxList"
|
]}
|
||||||
label="盒子选择"
|
width="md"
|
||||||
placeholder="已选择0个盒子"
|
name="name"
|
||||||
fieldProps={{
|
label="盒子组名称"
|
||||||
readOnly: true,
|
placeholder="请输入盒子名称"
|
||||||
suffix: (
|
/>
|
||||||
<Space>
|
<ProFormText
|
||||||
<a onClick={() => {
|
width="md"
|
||||||
createFormRef.current?.setFieldValue('boxList', null)
|
name="boxList"
|
||||||
}} >恢复默认</a>
|
label="盒子选择"
|
||||||
<a onClick={() => setBoxChoiceOpen(true)}>范围选择</a>
|
fieldProps={{
|
||||||
</Space>
|
readOnly: true,
|
||||||
)
|
value: `已选择${createFormRef.current?.getFieldValue('boxList')?.length || 0}个盒子`,
|
||||||
}}
|
suffix: (
|
||||||
/>
|
<Space>
|
||||||
</ModalForm>
|
<a onClick={() => {
|
||||||
<Divider type="vertical" />
|
createFormRef.current?.setFieldValue('boxList', null)
|
||||||
{/* @ts-ignore */}
|
onBoxChoiceReset()
|
||||||
<Button danger type='link' disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} >删除</Button>
|
}} >恢复默认</a>
|
||||||
<Divider type="vertical" />
|
<a onClick={() => setBoxChoiceOpen(true)}>范围选择</a>
|
||||||
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
|
</Space>
|
||||||
<Button type="link" onClick={() => handleCheckable()} icon={isTreeCheckable ? <DiffOutlined /> : <SwitcherOutlined />} />
|
)
|
||||||
</Space>
|
}}
|
||||||
<Divider style={{ margin: 0 }} />
|
/>
|
||||||
|
</ModalForm>
|
||||||
|
<Divider type="vertical" style={{ margin: '8px 0' }} />
|
||||||
|
{/* @ts-ignore */}
|
||||||
|
<Button danger type='text' style={{ padding: '4px 8px' }} icon={<CloseCircleOutlined />} disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} >删除</Button>
|
||||||
|
</Space>
|
||||||
|
<Divider style={{ margin: 0 }} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{extraBtns}
|
||||||
<BoxTree
|
<BoxTree
|
||||||
treeCheckable={isTreeCheckable}
|
treeCheckable={isTreeCheckable}
|
||||||
data={data}
|
data={data}
|
||||||
|
@ -2,10 +2,12 @@ import React, { useState } from 'react';
|
|||||||
import { BoxSelectTree } from '@zhst/biz';
|
import { BoxSelectTree } from '@zhst/biz';
|
||||||
import { treeData, boxDataSource } from './mock'
|
import { treeData, boxDataSource } from './mock'
|
||||||
import { Select, TreeProps, Modal, Checkbox } from 'antd';
|
import { Select, TreeProps, Modal, Checkbox } from 'antd';
|
||||||
|
import { BOX_TYPE_LIST } from '../../utils/constants';
|
||||||
|
|
||||||
const { Option } = Select
|
const { Option } = Select
|
||||||
|
|
||||||
const demo = () => {
|
const demo = () => {
|
||||||
|
const [activeKey, setActiveKey] = useState('1')
|
||||||
const [searchType, setSearchType] = useState('1')
|
const [searchType, setSearchType] = useState('1')
|
||||||
const [searchVal, setSearchVal] = useState('')
|
const [searchVal, setSearchVal] = useState('')
|
||||||
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
@ -32,18 +34,24 @@ const demo = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ border: '1px solid #ccc', width: '320px' }}>
|
<div style={{ border: '1px solid #ccc', width: '320px', minHeight: '900px' }}>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
<BoxSelectTree
|
<BoxSelectTree
|
||||||
data={treeData}
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
boxDataSource={boxDataSource}
|
boxDataSource={boxDataSource}
|
||||||
onSearch={e => console.log('搜索', e)}
|
onSearch={e => console.log('搜索', e)}
|
||||||
onCreateSubmit={async () => { return true }}
|
onCreateSubmit={async (_data) => {
|
||||||
|
console.log('新建盒子', _data)
|
||||||
|
return true
|
||||||
|
}}
|
||||||
onItemCheck={onTreeCheck}
|
onItemCheck={onTreeCheck}
|
||||||
onItemSelect={e => console.log('onItemSelect', e)}
|
onItemSelect={e => console.log('onItemSelect', e)}
|
||||||
onTabChange={e => console.log('tabChange', e)}
|
onTabChange={val => setActiveKey(val)}
|
||||||
onBoxDelete={data => console.log('盒子删除', data)}
|
onBoxDelete={data => console.log('盒子删除', data)}
|
||||||
onBoxBatchDelete={onBoxBatchDelete}
|
onBoxBatchDelete={onBoxBatchDelete}
|
||||||
|
tabsProps={{
|
||||||
|
activeKey,
|
||||||
|
}}
|
||||||
searchInputProps={{
|
searchInputProps={{
|
||||||
addonBefore: (
|
addonBefore: (
|
||||||
<Select
|
<Select
|
||||||
@ -54,8 +62,9 @@ const demo = () => {
|
|||||||
}}
|
}}
|
||||||
style={{ width: '72px' }}
|
style={{ width: '72px' }}
|
||||||
>
|
>
|
||||||
<Option value="1">盒子</Option>
|
{BOX_TYPE_LIST.map(item => (
|
||||||
<Option value="2">盒子组</Option>
|
<Option value={item.value}>{item.label}</Option>
|
||||||
|
))}
|
||||||
</Select>
|
</Select>
|
||||||
),
|
),
|
||||||
onChange: e => setSearchVal(e.target.value),
|
onChange: e => setSearchVal(e.target.value),
|
||||||
|
29
packages/biz/src/boxSelectTree/demo/extraBtns.tsx
Normal file
29
packages/biz/src/boxSelectTree/demo/extraBtns.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { BoxSelectTree } from '@zhst/biz';
|
||||||
|
import { treeData, boxDataSource } from './mock'
|
||||||
|
import { Button } from 'antd';
|
||||||
|
|
||||||
|
const demo = () => {
|
||||||
|
const [activeKey, setActiveKey] = useState('1')
|
||||||
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
|
||||||
|
<BoxSelectTree
|
||||||
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
|
boxDataSource={boxDataSource}
|
||||||
|
showOptions={false}
|
||||||
|
extraBtns={<Button type="dashed" style={{ color: 'green' }}>自定义按钮</Button>}
|
||||||
|
tabsProps={{
|
||||||
|
activeKey,
|
||||||
|
}}
|
||||||
|
treeProps={{
|
||||||
|
checkedKeys
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -1,6 +1,6 @@
|
|||||||
import { TreeDataNode } from "antd";
|
import { TreeData } from "@zhst/biz";
|
||||||
|
|
||||||
export const treeData: TreeDataNode[] = [
|
export const boxDataSource: TreeData[] = [
|
||||||
{
|
{
|
||||||
title: '全部盒子',
|
title: '全部盒子',
|
||||||
key: '0-0',
|
key: '0-0',
|
||||||
@ -12,10 +12,12 @@ export const treeData: TreeDataNode[] = [
|
|||||||
{
|
{
|
||||||
title: '摄像头1',
|
title: '摄像头1',
|
||||||
key: '0-0-0-0',
|
key: '0-0-0-0',
|
||||||
|
isCamera: true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: '摄像头2',
|
title: '摄像头2',
|
||||||
key: '0-0-0-1',
|
key: '0-0-0-1',
|
||||||
|
isCamera: true
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -25,7 +27,8 @@ export const treeData: TreeDataNode[] = [
|
|||||||
children: [
|
children: [
|
||||||
{
|
{
|
||||||
title: '摄像头4',
|
title: '摄像头4',
|
||||||
key: '0-0-1-0'
|
key: '0-0-1-0',
|
||||||
|
isCamera: true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@ -34,36 +37,18 @@ export const treeData: TreeDataNode[] = [
|
|||||||
];
|
];
|
||||||
|
|
||||||
|
|
||||||
export const boxDataSource: TreeDataNode[] = [
|
export const treeData: TreeData[] = [
|
||||||
|
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
|
||||||
|
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
|
||||||
|
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
|
||||||
{
|
{
|
||||||
key: '0-0',
|
key: '0-1-3',
|
||||||
title: '分组0-0',
|
title: '分组0-1-3',
|
||||||
isLeaf: false,
|
|
||||||
checkable: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: '0-1',
|
|
||||||
title: '分组0-1',
|
|
||||||
isLeaf: false,
|
isLeaf: false,
|
||||||
children: [
|
children: [
|
||||||
{ key: '0-1-0', title: '分组0-1-0', isLeaf: true, checkable: false },
|
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true, isCamera: true },
|
||||||
{ key: '0-1-1', title: '分组0-1-1', isLeaf: true, checkable: false },
|
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true, isCamera: true },
|
||||||
{ key: '0-1-2', title: '分组0-1-2', isLeaf: true, checkable: false },
|
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true, isCamera: true },
|
||||||
{
|
|
||||||
key: '0-1-3',
|
|
||||||
title: '分组0-1-3',
|
|
||||||
isLeaf: false,
|
|
||||||
children: [
|
|
||||||
{ key: '0-1-3-1', title: '分组0-1-3-1', isLeaf: true },
|
|
||||||
{ key: '0-1-3-2', title: '分组0-1-3-2', isLeaf: true },
|
|
||||||
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ key: '0-2', title: '分组0-2', isLeaf: false, checkable: false, },
|
|
||||||
{ key: '0-3', title: '分组0-3', isLeaf: false, checkable: false, },
|
|
||||||
{ key: '0-4', title: '分组0-4', isLeaf: false, checkable: false, },
|
|
||||||
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
|
|
||||||
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
|
|
||||||
];
|
];
|
||||||
|
61
packages/biz/src/boxSelectTree/demo/noOptions.tsx
Normal file
61
packages/biz/src/boxSelectTree/demo/noOptions.tsx
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { BoxSelectTree } from '@zhst/biz';
|
||||||
|
import { Button, Select, TreeProps } from 'antd';
|
||||||
|
import { FilterOutlined } from '@ant-design/icons';
|
||||||
|
import { BOX_TYPE_LIST } from '../../utils/constants';
|
||||||
|
import { treeData, boxDataSource } from './mock'
|
||||||
|
|
||||||
|
const { Option } = Select
|
||||||
|
|
||||||
|
const demo = () => {
|
||||||
|
const [activeKey, setActiveKey] = useState('1')
|
||||||
|
const [searchType, setSearchType] = useState('1')
|
||||||
|
const [searchVal, setSearchVal] = useState('')
|
||||||
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
|
|
||||||
|
const onTreeCheck: TreeProps['onCheck'] = (keys: any) => {
|
||||||
|
setCheckedKeys(keys)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
|
||||||
|
<BoxSelectTree
|
||||||
|
data={activeKey === '1' ? treeData : boxDataSource}
|
||||||
|
boxDataSource={boxDataSource}
|
||||||
|
onSearch={e => console.log('搜索', e)}
|
||||||
|
onItemCheck={onTreeCheck}
|
||||||
|
onItemSelect={e => console.log('onItemSelect', e)}
|
||||||
|
onTabChange={val => setActiveKey(val)}
|
||||||
|
onBoxDelete={data => console.log('盒子删除', data)}
|
||||||
|
showOptions={false}
|
||||||
|
tabsProps={{
|
||||||
|
activeKey,
|
||||||
|
}}
|
||||||
|
customImport={<Button type="text" icon={<FilterOutlined />} />}
|
||||||
|
searchInputProps={{
|
||||||
|
addonBefore: (
|
||||||
|
<Select
|
||||||
|
value={searchType}
|
||||||
|
onChange={_type => {
|
||||||
|
setSearchType(_type)
|
||||||
|
setSearchVal('')
|
||||||
|
}}
|
||||||
|
style={{ width: '72px' }}
|
||||||
|
>
|
||||||
|
{BOX_TYPE_LIST.map(item => (
|
||||||
|
<Option value={item.value}>{item.label}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
),
|
||||||
|
onChange: e => setSearchVal(e.target.value),
|
||||||
|
value: searchVal
|
||||||
|
}}
|
||||||
|
treeProps={{
|
||||||
|
checkedKeys
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -2,7 +2,7 @@
|
|||||||
category: Components
|
category: Components
|
||||||
title: BoxSelectTree 盒子树
|
title: BoxSelectTree 盒子树
|
||||||
demo:
|
demo:
|
||||||
cols: 2
|
cols: 4
|
||||||
group:
|
group:
|
||||||
title: 进阶组件
|
title: 进阶组件
|
||||||
order: 2
|
order: 2
|
||||||
@ -13,7 +13,10 @@ group:
|
|||||||
## 代码演示
|
## 代码演示
|
||||||
|
|
||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
|
<code src="./demo/extraBtns.tsx">自定义其它按钮</code>
|
||||||
|
<code src="./demo/noOptions.tsx">不显示其它按钮</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
@ -24,3 +27,8 @@ group:
|
|||||||
| tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - |
|
| tabsProps | Tabs组件的Props | antd的Tabs组件 | - | - |
|
||||||
| searchInputProps | 搜索框的Props | antd的Input组件 | - | - |
|
| searchInputProps | 搜索框的Props | antd的Input组件 | - | - |
|
||||||
| onTabChange | tab切换监听 | function: (e) => void | - | - |
|
| onTabChange | tab切换监听 | function: (e) => void | - | - |
|
||||||
|
| onBoxDelete | 盒子删除事件 | function: (e) => void | - | - |
|
||||||
|
| onBoxBatchDelete | 盒子批量删除事件 | function: (e) => void | - | - |
|
||||||
|
| onCreateSubmit | 新建提交事件 | function: (e) => void | - | - |
|
||||||
|
| showOptions | 展示其它功能按钮 | boolean | true | - |
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export { default as BigImageModal } from './BigImageModal'
|
export { default as BigImageModal } from './BigImageModal'
|
||||||
export { default as BoxSelectTree } from './boxSelectTree'
|
export { default as BoxSelectTree } from './boxSelectTree'
|
||||||
export { default as Tree } from './tree'
|
export { default as Tree } from './tree'
|
||||||
|
export type { TreeData } from './tree'
|
||||||
export { default as TreeTransfer } from './treeTransfer'
|
export { default as TreeTransfer } from './treeTransfer'
|
||||||
export { default as TreeTransferModal } from './treeTransferModal'
|
export { default as TreeTransferModal } from './treeTransferModal'
|
||||||
export { default as WarningRecordCard } from './WarningRecordCard'
|
export { default as WarningRecordCard } from './WarningRecordCard'
|
||||||
|
@ -1,16 +1,18 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
|
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
|
||||||
|
import theme from 'antd/es/theme'
|
||||||
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
|
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
|
||||||
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
|
||||||
const componentName = 'zhst-biz-tree'
|
const componentName = 'zhst-biz-tree'
|
||||||
|
const { useToken } = theme
|
||||||
|
|
||||||
export interface BoxTreeProps extends TreeProps {
|
export interface BoxTreeProps extends TreeProps {
|
||||||
data: TreeDataNode[]
|
data: TreeDataNode[]
|
||||||
treeCheckable?: boolean
|
treeCheckable?: boolean
|
||||||
showItemOption?: boolean
|
showItemOption?: boolean
|
||||||
treeProps?: TreeProps
|
customOptions?: any;
|
||||||
onItemCheck?: TreeProps['onCheck']
|
onItemCheck?: TreeProps['onCheck']
|
||||||
onItemSelect?: TreeProps['onSelect']
|
onItemSelect?: TreeProps['onSelect']
|
||||||
onItemSetting?: (_data: any) => void
|
onItemSetting?: (_data: any) => void
|
||||||
@ -19,52 +21,86 @@ export interface BoxTreeProps extends TreeProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const boxTree: FC<BoxTreeProps> = (props) => {
|
const boxTree: FC<BoxTreeProps> = (props) => {
|
||||||
const { onItemSelect, onItemCheck, onItemSetting, onItemDelete, data = [], showItemOption = true, treeCheckable = false, onRenameFinish } = props
|
const {
|
||||||
|
onItemSelect,
|
||||||
|
onItemCheck,
|
||||||
|
onItemSetting,
|
||||||
|
onItemDelete,
|
||||||
|
data = [],
|
||||||
|
showItemOption = true,
|
||||||
|
treeCheckable = false,
|
||||||
|
onRenameFinish,
|
||||||
|
customOptions
|
||||||
|
} = props
|
||||||
|
const { token } = useToken()
|
||||||
|
const [checkedItem, setCheckedItem] = useState<React.Key>('')
|
||||||
|
|
||||||
|
const cameraStatus = new Map([
|
||||||
|
['0', 'success'],
|
||||||
|
['1', 'error']
|
||||||
|
])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tree
|
<Tree
|
||||||
checkable={treeCheckable}
|
checkable={treeCheckable}
|
||||||
blockNode
|
blockNode
|
||||||
onSelect={onItemSelect}
|
onSelect={(selectedKeys, info) => {
|
||||||
|
setCheckedItem(selectedKeys[0])
|
||||||
|
onItemSelect?.(selectedKeys, info)
|
||||||
|
}}
|
||||||
onCheck={onItemCheck}
|
onCheck={onItemCheck}
|
||||||
treeData={data}
|
treeData={data}
|
||||||
titleRender={(_nodeData) => {
|
titleRender={(_nodeData) => {
|
||||||
return (
|
return (
|
||||||
<div className={`${componentName}-item-render`}>
|
<div className={`${componentName}-item-render`}>
|
||||||
{!_nodeData.children && <Badge style={{ marginRight: '6px' }} status="success" />}
|
{/* @ts-ignore */}
|
||||||
{_nodeData.title as any}
|
{!_nodeData.children && _nodeData.isCamera && <Badge style={{ marginRight: '6px' }} status={cameraStatus.get('0')} />}
|
||||||
{showItemOption && <Space className={`${componentName}-item-render_right`} style={{ float:'right' }} >
|
<span
|
||||||
<ModalForm
|
// @ts-ignore
|
||||||
title="重命名"
|
style={(checkedItem === _nodeData.key) && _nodeData.isCamera ? {
|
||||||
width={600}
|
color: token.colorPrimary
|
||||||
modalProps={{ destroyOnClose: true }}
|
} : {}}
|
||||||
layout='horizontal'
|
>
|
||||||
labelCol={{ span: 6 }}
|
{_nodeData.title as any}
|
||||||
wrapperCol={{ span: 18 }}
|
</span>
|
||||||
trigger={<EditOutlined />}
|
{showItemOption && (
|
||||||
submitter={{
|
<Space className={`${componentName}-item-render_right`} style={{ float:'right' }} >
|
||||||
searchConfig: {
|
{customOptions || (
|
||||||
submitText: '确定',
|
<>
|
||||||
resetText: '取消',
|
<ModalForm
|
||||||
},
|
title="重命名"
|
||||||
}}
|
width={600}
|
||||||
onFinish={async (value) => onRenameFinish?.(value, _nodeData)}
|
modalProps={{ destroyOnClose: true }}
|
||||||
>
|
layout='horizontal'
|
||||||
<ProFormText
|
labelCol={{ span: 6 }}
|
||||||
rules={[
|
wrapperCol={{ span: 18 }}
|
||||||
{
|
trigger={<EditOutlined />}
|
||||||
required: true,
|
submitter={{
|
||||||
},
|
searchConfig: {
|
||||||
]}
|
submitText: '确定',
|
||||||
width="md"
|
resetText: '取消',
|
||||||
name="name"
|
},
|
||||||
label="盒子名称"
|
}}
|
||||||
placeholder="请输入盒子名称"
|
onFinish={async (value) => onRenameFinish?.(value, _nodeData)}
|
||||||
/>
|
>
|
||||||
</ModalForm>
|
<ProFormText
|
||||||
<SettingOutlined onClick={() => onItemSetting?.(_nodeData)} />
|
rules={[
|
||||||
<CloseOutlined onClick={() => onItemDelete?.(_nodeData)} />
|
{
|
||||||
</Space>}
|
required: true,
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
width="md"
|
||||||
|
name="name"
|
||||||
|
label="盒子名称"
|
||||||
|
placeholder="请输入盒子名称"
|
||||||
|
/>
|
||||||
|
</ModalForm>
|
||||||
|
<SettingOutlined onClick={() => onItemSetting?.(_nodeData)} />
|
||||||
|
<CloseOutlined onClick={() => onItemDelete?.(_nodeData)} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</Space>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}}
|
}}
|
||||||
|
23
packages/biz/src/tree/demo/customOptions.tsx
Normal file
23
packages/biz/src/tree/demo/customOptions.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { Tree } from '@zhst/biz';
|
||||||
|
import { LoadingOutlined, PlayCircleOutlined, SettingOutlined } from '@ant-design/icons';
|
||||||
|
import { treeData } from './mock'
|
||||||
|
|
||||||
|
const demo = () => {
|
||||||
|
return (
|
||||||
|
<div style={{ width: '320px' }}>
|
||||||
|
<Tree
|
||||||
|
data={treeData}
|
||||||
|
customOptions={(
|
||||||
|
<>
|
||||||
|
<PlayCircleOutlined />
|
||||||
|
<SettingOutlined />
|
||||||
|
<LoadingOutlined />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default demo;
|
@ -14,8 +14,11 @@ const demo = () => {
|
|||||||
<div>
|
<div>
|
||||||
{title}
|
{title}
|
||||||
<div style={{ float: 'right' }} >
|
<div style={{ float: 'right' }} >
|
||||||
<Tooltip placement="right" title={'存在0个'}>
|
<Tooltip
|
||||||
<a >包含0个</a>
|
placement="right"
|
||||||
|
title={'存在0个'}
|
||||||
|
>
|
||||||
|
<a>在0个组中包含</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -14,8 +14,15 @@ group:
|
|||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
<code src="./demo/customTitleRender.tsx">自定义渲染界面</code>
|
<code src="./demo/customTitleRender.tsx">自定义渲染界面</code>
|
||||||
<code src="./demo/noOption.tsx">不展示配置项</code>
|
<code src="./demo/noOption.tsx">不展示配置项</code>
|
||||||
|
<code src="./demo/customOptions.tsx">自定义配置项</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
|
**额外参数可以参考 antd - Tree 组件**
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
| titleRender | 子项自定义 | ReactNode、 undefined | - | - |
|
||||||
|
| showItemOption | 是否显示额外配置功能 | boolean | true | - |
|
||||||
|
| customOptions | 自定义配置项 | any | - | - |
|
||||||
|
@ -1,3 +1,10 @@
|
|||||||
|
import { TreeDataNode } from 'antd';
|
||||||
import BoxTree from './boxTree';
|
import BoxTree from './boxTree';
|
||||||
|
|
||||||
|
export interface TreeData extends TreeDataNode {
|
||||||
|
children?: TreeDataNode['children'] & {
|
||||||
|
isCamera?: boolean
|
||||||
|
}[]
|
||||||
|
}
|
||||||
|
|
||||||
export default BoxTree;
|
export default BoxTree;
|
||||||
|
@ -13,6 +13,8 @@ group:
|
|||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
<code src="./demo/withModal.tsx">和Modal组合使用</code>
|
<code src="./demo/withModal.tsx">和Modal组合使用</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import React, { FC, useState } from 'react';
|
import React, { FC, useState } from 'react';
|
||||||
|
import { Modal, ModalProps, Radio, RadioGroupProps, Select, SelectProps, TransferProps, TreeDataNode, TreeProps } from 'antd';
|
||||||
import TreeTransfer from '../treeTransfer';
|
import TreeTransfer from '../treeTransfer';
|
||||||
import { Modal, ModalProps, Radio, RadioGroupProps, TransferProps, TreeDataNode } from 'antd';
|
import { ALL_LIST, BOX_TYPE_LIST } from '../utils/constants';
|
||||||
import { TreeProps } from 'antd/lib';
|
|
||||||
|
|
||||||
export interface TreeTransferModalProps {
|
export interface TreeTransferModalProps {
|
||||||
dataSource: TreeDataNode[]
|
dataSource: TreeDataNode[]
|
||||||
@ -17,7 +17,10 @@ export interface TreeTransferModalProps {
|
|||||||
open?: boolean
|
open?: boolean
|
||||||
onCancel?: ModalProps['onCancel']
|
onCancel?: ModalProps['onCancel']
|
||||||
onRadioChange?: RadioGroupProps['onChange']
|
onRadioChange?: RadioGroupProps['onChange']
|
||||||
|
onSelect?: SelectProps['onSelect']
|
||||||
modalProps?: ModalProps
|
modalProps?: ModalProps
|
||||||
|
radioProps?: RadioGroupProps
|
||||||
|
selectProps?: SelectProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
||||||
@ -31,11 +34,14 @@ const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
|||||||
onReset,
|
onReset,
|
||||||
onRadioChange,
|
onRadioChange,
|
||||||
onTreeCheck,
|
onTreeCheck,
|
||||||
|
onSelect,
|
||||||
targetItems,
|
targetItems,
|
||||||
modalProps,
|
modalProps,
|
||||||
|
radioProps,
|
||||||
|
selectProps,
|
||||||
} = props
|
} = props
|
||||||
|
|
||||||
const [type, setType] = useState('box')
|
const [type, setType] = useState('1')
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -48,17 +54,25 @@ const TreeTransferModal: FC<TreeTransferModalProps> = (props) => {
|
|||||||
{...modalProps}
|
{...modalProps}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<Radio.Group
|
<div>
|
||||||
onChange={e => {
|
<Radio.Group
|
||||||
setType(e.target.value)
|
onChange={e => {
|
||||||
onRadioChange?.(e)
|
setType(e.target.value)
|
||||||
}}
|
onRadioChange?.(e)
|
||||||
style={{ marginLeft: '24px', padding: '20px 0' }}
|
}}
|
||||||
value={type}
|
style={{ marginLeft: '24px', padding: '20px 0' }}
|
||||||
>
|
value={type}
|
||||||
<Radio value={'box'}>盒子</Radio>
|
options={BOX_TYPE_LIST}
|
||||||
<Radio value={'boxGroup'}>盒子组</Radio>
|
{...radioProps}
|
||||||
</Radio.Group>
|
/>
|
||||||
|
<Select
|
||||||
|
defaultValue={''}
|
||||||
|
style={{ marginLeft: 200, width: 150 }}
|
||||||
|
options={ALL_LIST}
|
||||||
|
onSelect={onSelect}
|
||||||
|
{...selectProps}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
{type === 'box' ?
|
{type === 'box' ?
|
||||||
(
|
(
|
||||||
<TreeTransfer
|
<TreeTransfer
|
||||||
|
@ -7,7 +7,7 @@ import { boxDataSource } from './mock'
|
|||||||
const App: React.FC = () => {
|
const App: React.FC = () => {
|
||||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||||
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||||
const [open, setOpen] = useState(false)
|
const [open, setOpen] = useState(true)
|
||||||
|
|
||||||
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
|
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
|
||||||
let _targetItems: TreeDataNode[] = []
|
let _targetItems: TreeDataNode[] = []
|
||||||
@ -47,7 +47,7 @@ const App: React.FC = () => {
|
|||||||
<TreeTransferModal
|
<TreeTransferModal
|
||||||
open={open}
|
open={open}
|
||||||
onCancel={() => setOpen(false)}
|
onCancel={() => setOpen(false)}
|
||||||
onRadioChange={() => setOpen(false)} // 顶部 radio 事件
|
onRadioChange={(e) => console.log('radioChange', e)} // 顶部 radio 事件
|
||||||
dataSource={boxDataSource} // 数据源
|
dataSource={boxDataSource} // 数据源
|
||||||
targetItems={targetItems} // 右侧选中项
|
targetItems={targetItems} // 右侧选中项
|
||||||
checkedKeys={checkedKeys} // 左侧选中
|
checkedKeys={checkedKeys} // 左侧选中
|
||||||
|
@ -12,6 +12,8 @@ group:
|
|||||||
|
|
||||||
<code src="./demo/basic.tsx">基本用法</code>
|
<code src="./demo/basic.tsx">基本用法</code>
|
||||||
|
|
||||||
|
## API
|
||||||
|
|
||||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||||
| --- | --- | --- | --- | --- |
|
| --- | --- | --- | --- | --- |
|
||||||
| data | 数据源 | Array[] | [] | - |
|
| data | 数据源 | Array[] | [] | - |
|
||||||
|
@ -25,3 +25,13 @@ export const DeviceTab = {
|
|||||||
REAL_CAMERA_ONLYFACE: 7,
|
REAL_CAMERA_ONLYFACE: 7,
|
||||||
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8, // 只有普通摄像头,没有人脸、没有盒子、直连
|
REAL_CAMERA_NOFACE_NOBOX_NODIRECONNECT: 8, // 只有普通摄像头,没有人脸、没有盒子、直连
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 盒子 Tab 切换
|
||||||
|
export const BOX_TYPE_LIST = [
|
||||||
|
{ value: '1', label: '盒子' },
|
||||||
|
{ value: '2', label: '盒子组' }
|
||||||
|
]
|
||||||
|
|
||||||
|
export const ALL_LIST = [
|
||||||
|
{ value: '', label: '全部' }
|
||||||
|
]
|
||||||
|
@ -1,5 +1,28 @@
|
|||||||
# @zhst/utils
|
# @zhst/utils
|
||||||
|
|
||||||
|
## 0.7.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.2
|
||||||
|
|
||||||
|
## 0.7.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.1
|
||||||
|
|
||||||
|
## 0.7.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/request@0.8.0
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/func",
|
"name": "@zhst/func",
|
||||||
"version": "0.7.0",
|
"version": "0.7.3",
|
||||||
"description": "函数合集",
|
"description": "函数合集",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"hooks"
|
"hooks"
|
||||||
|
@ -1,5 +1,31 @@
|
|||||||
# @zhst/hooks
|
# @zhst/hooks
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.7.3
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/func@0.7.2
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- @zhst/biz 优化数组件
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- @zhst/func@0.7.1
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -48,4 +48,4 @@ export var useActivateState = function useActivateState() {
|
|||||||
});
|
});
|
||||||
return isActive;
|
return isActive;
|
||||||
};
|
};
|
||||||
export default useActivateWrapper;
|
export default useActivateWrapper;
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/hooks",
|
"name": "@zhst/hooks",
|
||||||
"version": "0.7.0",
|
"version": "0.8.2",
|
||||||
"description": "hooks合集",
|
"description": "hooks合集",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"hooks"
|
"hooks"
|
||||||
|
@ -1,5 +1,34 @@
|
|||||||
# @zhst/utils
|
# @zhst/utils
|
||||||
|
|
||||||
|
## 0.8.3
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.2
|
||||||
|
- @zhst/func@0.7.3
|
||||||
|
- @zhst/meta@0.8.3
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.1
|
||||||
|
- @zhst/func@0.7.2
|
||||||
|
- @zhst/meta@0.8.2
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- Updated dependencies
|
||||||
|
- @zhst/hooks@0.8.0
|
||||||
|
- @zhst/func@0.7.1
|
||||||
|
- @zhst/meta@0.8.1
|
||||||
|
|
||||||
## 0.8.0
|
## 0.8.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/meta",
|
"name": "@zhst/meta",
|
||||||
"version": "0.8.0",
|
"version": "0.8.3",
|
||||||
"description": "原子组件",
|
"description": "原子组件",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"meta",
|
"meta",
|
||||||
|
@ -1,5 +1,23 @@
|
|||||||
# @zhst/request
|
# @zhst/request
|
||||||
|
|
||||||
|
## 0.8.2
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 修改 boxSelectTree 类型提示
|
||||||
|
|
||||||
|
## 0.8.1
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- 优化 boxSelectTree 组件,添加可以自定义配置按钮功能
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
|
||||||
|
### Minor Changes
|
||||||
|
|
||||||
|
- @zhst/biz 优化数组件
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
|
|
||||||
### Minor Changes
|
### Minor Changes
|
||||||
|
File diff suppressed because one or more lines are too long
@ -1,155 +0,0 @@
|
|||||||
var __create = Object.create;
|
|
||||||
var __defProp = Object.defineProperty;
|
|
||||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
||||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
||||||
var __getProtoOf = Object.getPrototypeOf;
|
|
||||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
||||||
var __export = (target, all) => {
|
|
||||||
for (var name in all)
|
|
||||||
__defProp(target, name, { get: all[name], enumerable: true });
|
|
||||||
};
|
|
||||||
var __copyProps = (to, from, except, desc) => {
|
|
||||||
if (from && typeof from === "object" || typeof from === "function") {
|
|
||||||
for (let key of __getOwnPropNames(from))
|
|
||||||
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
||||||
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
||||||
}
|
|
||||||
return to;
|
|
||||||
};
|
|
||||||
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
||||||
// If the importer is in node compatibility mode or this is not an ESM
|
|
||||||
// file that has been converted to a CommonJS file using a Babel-
|
|
||||||
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
||||||
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
||||||
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
||||||
mod
|
|
||||||
));
|
|
||||||
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
||||||
|
|
||||||
// src/index.ts
|
|
||||||
var src_exports = {};
|
|
||||||
__export(src_exports, {
|
|
||||||
ResponseError: () => ResponseError,
|
|
||||||
User: () => User,
|
|
||||||
default: () => src_default,
|
|
||||||
doRequest: () => doRequest,
|
|
||||||
req: () => req
|
|
||||||
});
|
|
||||||
module.exports = __toCommonJS(src_exports);
|
|
||||||
var import_umi_request = require("umi-request");
|
|
||||||
var import_lodash_es = require("lodash-es");
|
|
||||||
var import_antd = require("antd");
|
|
||||||
var import_base_64 = __toESM(require("base-64"));
|
|
||||||
var User = /* @__PURE__ */ ((User2) => {
|
|
||||||
User2["TOKEN_KEY"] = "USER-TOKEN";
|
|
||||||
User2["USER_KEY"] = "USER";
|
|
||||||
return User2;
|
|
||||||
})(User || {});
|
|
||||||
var ResponseError = class extends Error {
|
|
||||||
constructor(response, text, data, request, type = "ResponseError") {
|
|
||||||
super(text || response.statusText);
|
|
||||||
this.name = "ResponseError";
|
|
||||||
this.data = data;
|
|
||||||
this.response = response;
|
|
||||||
this.request = request;
|
|
||||||
this.type = type;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var req = (0, import_umi_request.extend)({
|
|
||||||
getResponse: true,
|
|
||||||
// timeout: 1000,
|
|
||||||
parseResponse: false
|
|
||||||
});
|
|
||||||
req.use(async (ctx, next) => {
|
|
||||||
const { req: req2 } = ctx;
|
|
||||||
const { toast = true } = (req2 == null ? void 0 : req2.options) || {};
|
|
||||||
try {
|
|
||||||
await next();
|
|
||||||
const { res } = ctx;
|
|
||||||
const d = await res.text();
|
|
||||||
if (res.status === 401) {
|
|
||||||
localStorage.removeItem("USER-TOKEN" /* TOKEN_KEY */);
|
|
||||||
localStorage.removeItem("USER" /* USER_KEY */);
|
|
||||||
import_antd.message.warning("登录过期,请重新登录!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const isEmptyRes = d === "";
|
|
||||||
if (!res)
|
|
||||||
return;
|
|
||||||
const body = !isEmptyRes ? JSON.parse(d) : d;
|
|
||||||
if (res.status >= 200 && res.status < 300) {
|
|
||||||
ctx.res = body;
|
|
||||||
} else {
|
|
||||||
let errMsg = res.headers.get("Grpc-Metadata-Errorx-Message");
|
|
||||||
if (errMsg) {
|
|
||||||
errMsg = import_base_64.default.decode(errMsg);
|
|
||||||
} else if (!errMsg && (0, import_lodash_es.get)(body, "message")) {
|
|
||||||
errMsg = `${(0, import_lodash_es.get)(body, "message")}`;
|
|
||||||
} else {
|
|
||||||
errMsg = "您的网络发生异常,无法连接服务器";
|
|
||||||
}
|
|
||||||
toast && import_antd.message.error(errMsg);
|
|
||||||
throw new ResponseError(res, errMsg, d, req2, "CustomError");
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
if ((0, import_lodash_es.get)(error, "type") !== "CustomError") {
|
|
||||||
toast && import_antd.message.error("您的网络发生异常,无法连接服务器");
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
var doRequest = (cgi, option) => {
|
|
||||||
const {
|
|
||||||
method,
|
|
||||||
url,
|
|
||||||
baseUrl,
|
|
||||||
data = {},
|
|
||||||
useBaseUrl = true,
|
|
||||||
originUrl = false,
|
|
||||||
refererSuffix = ""
|
|
||||||
} = cgi;
|
|
||||||
const token = localStorage.getItem("USER-TOKEN" /* TOKEN_KEY */);
|
|
||||||
let newUrl = "";
|
|
||||||
if (useBaseUrl) {
|
|
||||||
newUrl = `${baseUrl}${url}`;
|
|
||||||
} else {
|
|
||||||
newUrl = `http://10.0.0.7:32223${url}`;
|
|
||||||
}
|
|
||||||
if (originUrl) {
|
|
||||||
newUrl = url;
|
|
||||||
}
|
|
||||||
const regex = /\/:(\w+)/g;
|
|
||||||
const params = [];
|
|
||||||
let matches;
|
|
||||||
while ((matches = regex.exec(newUrl)) != null) {
|
|
||||||
if (matches[1]) {
|
|
||||||
params.push(matches[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
params.forEach(function(name) {
|
|
||||||
let d = data == null ? void 0 : data[name];
|
|
||||||
if (d == null) {
|
|
||||||
d = "";
|
|
||||||
}
|
|
||||||
newUrl = newUrl.replace(`:${name}`, d);
|
|
||||||
});
|
|
||||||
const newData = (0, import_lodash_es.omit)(data, params);
|
|
||||||
const paramObj = method.toLowerCase() === "get" ? { params: newData } : { data: newData };
|
|
||||||
return req(newUrl, {
|
|
||||||
method,
|
|
||||||
...paramObj,
|
|
||||||
...option,
|
|
||||||
headers: {
|
|
||||||
authorization: token,
|
|
||||||
...refererSuffix ? { zhst_referer: `${baseUrl}${refererSuffix}` } : {}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
var src_default = doRequest;
|
|
||||||
// Annotate the CommonJS export names for ESM import in node:
|
|
||||||
0 && (module.exports = {
|
|
||||||
ResponseError,
|
|
||||||
User,
|
|
||||||
doRequest,
|
|
||||||
req
|
|
||||||
});
|
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zhst/request",
|
"name": "@zhst/request",
|
||||||
"version": "0.7.0",
|
"version": "0.8.2",
|
||||||
"description": "请求库",
|
"description": "请求库",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"request",
|
"request",
|
||||||
|
Loading…
Reference in New Issue
Block a user