Merge branch 'develop'
# Conflicts: # deploy/build.sh
This commit is contained in:
commit
2310cac125
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -2,9 +2,9 @@
|
||||
"configurations": [
|
||||
{
|
||||
"type": "chrome",
|
||||
"name": "http://localhost:8000/metas/big-image-preview",
|
||||
"name": "lambo",
|
||||
"request": "launch",
|
||||
"url": "http://localhost:8000/metas/big-image-preview"
|
||||
"url": "http://localhost:8000/metas"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
159
docs/index.md
159
docs/index.md
@ -1,159 +0,0 @@
|
||||
---
|
||||
hero:
|
||||
title: lambo
|
||||
description: 致力于提升前端开发效率与规范
|
||||
actions:
|
||||
- text: 快速上手
|
||||
link: /bizs
|
||||
features:
|
||||
- title: biz
|
||||
emoji: 🍑
|
||||
description: 业务库
|
||||
- title: hooks
|
||||
emoji: 💎
|
||||
description: hooks
|
||||
- title: func
|
||||
emoji: 🌈
|
||||
description: 常用函数库
|
||||
- title: meta
|
||||
emoji: ☀️
|
||||
description: 原子组件库
|
||||
- title: constants
|
||||
emoji: 🈶️
|
||||
description: 静态定义库
|
||||
- title: request
|
||||
emoji: 🥣
|
||||
description: 网络请求库
|
||||
- title: types
|
||||
emoji: 🈸
|
||||
description: typescript 声明库
|
||||
- title: material
|
||||
emoji: 🥱
|
||||
description: 物料库
|
||||
- title: cli
|
||||
emoji: 🐔
|
||||
description: 脚手架
|
||||
---
|
||||
|
||||
## 目录结构
|
||||
|
||||
<Tree>
|
||||
<ul>
|
||||
<li>
|
||||
docs
|
||||
<small>全局文档</small>
|
||||
<ul>
|
||||
<li>
|
||||
index.md
|
||||
<small>这是首页文档</small>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
packages
|
||||
<small>组件包目录</small>
|
||||
<ul>
|
||||
<li>
|
||||
biz
|
||||
<small>业务组件</small>
|
||||
</li>
|
||||
<li>
|
||||
func
|
||||
<small>函数库</small>
|
||||
</li>
|
||||
<li>
|
||||
hooks
|
||||
<small>hooks</small>
|
||||
</li>
|
||||
<li>
|
||||
constants
|
||||
<small>静态枚举值定义</small>
|
||||
</li>
|
||||
<li>
|
||||
meta
|
||||
<small>元组件</small>
|
||||
</li>
|
||||
<li>
|
||||
request
|
||||
<small>请求库</small>
|
||||
</li>
|
||||
<li>
|
||||
types
|
||||
<small>类型定义库</small>
|
||||
</li>
|
||||
<li>
|
||||
material
|
||||
<small>物料库</small>
|
||||
</li>
|
||||
<li>
|
||||
cli
|
||||
<small>脚手架</small>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
src
|
||||
<small>这是 src 文件夹</small>
|
||||
<ul>
|
||||
<li>
|
||||
index.md
|
||||
<small>这是 index.md</small>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
.dumirc.ts
|
||||
<small>文档配置</small>
|
||||
</li>
|
||||
<li>
|
||||
package.json
|
||||
<small>这是 package.json</small>
|
||||
</li>
|
||||
</ul>
|
||||
</Tree>
|
||||
|
||||
## 本文档食用说明
|
||||
|
||||
目前在进行中的项目为:@zhst/bizs、@zhst/hooks、@zhst/meta、@zhst/func..
|
||||
|
||||
bizs: 基于@zhst/hooks、@zhst/meta、@zhst/func 开发,基本贴近于业务。<Badge>doing</Badge>
|
||||
|
||||
meta:基于 antd 开发,作为公司的定制化原子组件。<Badge>doing</Badge>
|
||||
|
||||
hooks:基于 ahooks、@zhst/func 定制化二次开发。<Badge>doing</Badge>
|
||||
|
||||
func:基于 lodash-es 定制化二次开发 (由于 utils 包名被使用了)<Badge>doing</Badge>
|
||||
|
||||
## 后续构思
|
||||
|
||||
想做一个,基于智慧视通开发场景和业务场景的前端技术流程化方案,希望它能渗透到整个研发的所有流程中。
|
||||
|
||||
比如:代码规范、git 提交规范、物料库、基于 electron 的前端工具客户端(可集成物料库、图片上传小工具)、api 自动生成...
|
||||
|
||||
:::info{title=@zhst/lint}
|
||||
lint 工具库,包含:eslint-config、eslint-plugin、commit-lint
|
||||
:::
|
||||
|
||||
:::info{title=@zhst/metarial}
|
||||
物料库,可以直接通过 clone npm 仓库的形式生成模板页面,页面没有任何依赖,一个页面就是一个项目。
|
||||
:::
|
||||
|
||||
:::info{title=@zhst/app}
|
||||
基于 electron 的前端客户端工具,初期功能构思方案有:文件上传、git 仓库管理、物料库可视化页面一键生成
|
||||
:::
|
||||
|
||||
:::info{title=@zhst/autoapi}
|
||||
接口一键生成工具
|
||||
:::
|
||||
|
||||
:::info{title=@types/zhst}
|
||||
类型定义库
|
||||
:::
|
||||
|
||||
:::info{title=@zhst/constants}
|
||||
静态变量枚举库
|
||||
:::
|
||||
|
||||
:::info{title=@zhst/cli}
|
||||
基于物料库的脚手架,可以直接通过可视化界面搭建项目,偏向于 lowcode+ 思维
|
||||
:::
|
@ -51,7 +51,6 @@
|
||||
"prettier --parser=typescript --write"
|
||||
]
|
||||
},
|
||||
"dependencies": {},
|
||||
"devDependencies": {
|
||||
"@changesets/cli": "^2.27.1",
|
||||
"@commitlint/cli": "^17.1.2",
|
||||
|
@ -1,5 +1,200 @@
|
||||
# @zhst/biz
|
||||
|
||||
## 0.21.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: 修改 zhst/meta
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.3
|
||||
|
||||
## 0.21.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz、zhst/meta、zhst/material: 修改 od、修改 boxSelectTree
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.2
|
||||
|
||||
## 0.21.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz: fix: 边框颜色主题色,实时监控窗口有图片和选中,预警记录文字溢出
|
||||
|
||||
## 0.21.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.1
|
||||
|
||||
## 0.21.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.0
|
||||
|
||||
## 0.21.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.13.0
|
||||
- @zhst/func@0.15.0
|
||||
- @zhst/icon@0.5.0
|
||||
- @zhst/meta@0.19.0
|
||||
|
||||
## 0.20.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.14.1
|
||||
- @zhst/hooks@0.12.1
|
||||
- @zhst/meta@0.18.1
|
||||
|
||||
## 0.20.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 重新发版
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: zhst/biz 优化实时监控布局
|
||||
|
||||
## 0.19.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz: 实时监控预警记录添加滚动条
|
||||
|
||||
## 0.19.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.11.0
|
||||
- @zhst/func@0.13.0
|
||||
- @zhst/icon@0.3.0
|
||||
- @zhst/meta@0.17.0
|
||||
|
||||
## 0.18.8
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.12.0
|
||||
- @zhst/hooks@0.10.4
|
||||
- @zhst/meta@0.16.4
|
||||
|
||||
## 0.18.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.3
|
||||
- @zhst/hooks@0.10.3
|
||||
- @zhst/meta@0.16.3
|
||||
|
||||
## 0.18.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- biz 优化无限滚动组件、boxselectTree 组件;material 修改算法编辑模块
|
||||
|
||||
## 0.18.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz 优化 boxselecttree
|
||||
|
||||
## 0.18.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- biz-transfer: 修改删除时透出
|
||||
|
||||
## 0.18.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz - 修改穿梭框事件透出
|
||||
|
||||
## 0.18.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.2
|
||||
- @zhst/hooks@0.10.2
|
||||
- @zhst/meta@0.16.2
|
||||
|
||||
## 0.18.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.1
|
||||
- @zhst/hooks@0.10.1
|
||||
- @zhst/meta@0.16.1
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/biz:新增摘要列表-无限滚动组件
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.10.0
|
||||
- @zhst/func@0.11.0
|
||||
- @zhst/meta@0.16.0
|
||||
|
||||
## 0.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 视频添加 OD 框,查看大图首次点击修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.15.0
|
||||
- @zhst/func@0.10.2
|
||||
- @zhst/hooks@0.9.2
|
||||
|
||||
## 0.16.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz: fix: 在业务层控制窗口切换状态
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/meta 大图圈选组件点击选不上 bug 修复,attach 遮挡底部框事件阻止修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.14.0
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- biz: 视频播放首图添加 od 框
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/biz",
|
||||
"version": "0.14.0",
|
||||
"version": "0.21.5",
|
||||
"description": "业务库",
|
||||
"keywords": [
|
||||
"business",
|
||||
@ -47,6 +47,7 @@
|
||||
"antd": "^5.12.5",
|
||||
"classnames": "^2.5.1",
|
||||
"dayjs": "^1.11.10",
|
||||
"rc-util": "^5.38.1"
|
||||
"rc-util": "^5.38.1",
|
||||
"react-infinite-scroll-component": "^6.1.0"
|
||||
}
|
||||
}
|
||||
|
@ -223,11 +223,6 @@ const BigImageModal: React.FC<BigImageModalProps, BigModalRef> = forwardRef((pro
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
// TODO: 页面初始化
|
||||
useEffect(() => {
|
||||
}, [dataSource]);
|
||||
|
||||
// 暴露 ref 实例
|
||||
useImperativeHandle(ref, () => ({
|
||||
ref,
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
:global {
|
||||
i:hover {
|
||||
color: #f0f0f0 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ const Navigation: React.FC<{
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Button type="text" disabled={disabled} onClick={onClick}>
|
||||
<Button type="text" disabled={disabled} shape='circle' onClick={onClick}>
|
||||
<IconFont size={28} color={color} icon={prev ? 'icon-qiehuanzuo' : 'icon-qiehuanyou'} />
|
||||
</Button>
|
||||
</div>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useContext } from 'react';
|
||||
import WindowToggle from './components/WindowToggle';
|
||||
import React, { useContext, useRef } from 'react';
|
||||
import WindowToggle, { ISize } from './components/WindowToggle';
|
||||
import WarningRecordList from './components/WarningRecordList';
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import { IRecord } from '../WarningRecordCard';
|
||||
@ -32,6 +32,10 @@ interface RealTimeMonitorProps {
|
||||
cardStyle?: React.CSSProperties;
|
||||
imgStyle?: React.CSSProperties;
|
||||
largeImageTitle?: string;
|
||||
size: ISize;
|
||||
setSize: React.Dispatch<React.SetStateAction<ISize>>
|
||||
maxRecordCount?: number;
|
||||
warningImgStyle?: React.CSSProperties;
|
||||
}
|
||||
|
||||
export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
@ -50,16 +54,24 @@ export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
onRecordClick,
|
||||
selectedRecordId,
|
||||
isRecordListLoading,
|
||||
size,
|
||||
setSize,
|
||||
maxRecordCount,
|
||||
warningImgStyle,
|
||||
} = props
|
||||
const toggleRef = useRef<HTMLDivElement>()
|
||||
const componentName = getPrefixCls('biz-real-time-monitor', customizePrefixCls);
|
||||
|
||||
return (
|
||||
<div className={componentName} style={{ display: 'flex' }} >
|
||||
<WindowToggle
|
||||
toggleRef={toggleRef}
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
dataSource={videoDataSource}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
size={size}
|
||||
setSize={setSize}
|
||||
/>
|
||||
<WarningRecordList
|
||||
dataSource={warningDataSource}
|
||||
@ -69,6 +81,9 @@ export const RealTimeMonitor: React.FC<RealTimeMonitorProps> = (props) => {
|
||||
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||
isRecordListLoading={isRecordListLoading}
|
||||
recordListTitle="监控预警记录"
|
||||
maxHeight={toggleRef.current?.offsetHeight}
|
||||
maxRecordCount={maxRecordCount}
|
||||
imgStyle={warningImgStyle}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
@ -4,6 +4,7 @@ import { ViewLargerImageModalRef } from '../../../ViewLargerImageModal';
|
||||
import WarningRecordCard from '../../../WarningRecordCard';
|
||||
import ViewLargerImageModal from '../../../ViewLargerImageModal';
|
||||
import { Empty, Space, Spin } from 'antd';
|
||||
import { pxToRem } from '@zhst/func'
|
||||
import { LoadingOutlined } from '@ant-design/icons';
|
||||
import "./index.less"
|
||||
|
||||
@ -28,6 +29,8 @@ interface WarningRecordListProps {
|
||||
cardStyle?: React.CSSProperties;
|
||||
imgStyle?: React.CSSProperties;
|
||||
largeImageTitle?: string;
|
||||
maxHeight?: number;
|
||||
maxRecordCount?: number;
|
||||
}
|
||||
|
||||
const WarningRecordList: React.FC<WarningRecordListProps> = (props) => {
|
||||
@ -43,11 +46,12 @@ const WarningRecordList: React.FC<WarningRecordListProps> = (props) => {
|
||||
style,
|
||||
cardStyle,
|
||||
imgStyle,
|
||||
largeImageTitle
|
||||
largeImageTitle,
|
||||
maxHeight,
|
||||
maxRecordCount = 10
|
||||
} = props
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-warning-record-list' style={style}>
|
||||
<div className='zhst-biz-warning-record-list' style={{ maxHeight: `${pxToRem(`${maxHeight}`)}`, ...style }} >
|
||||
<div className='header'>{recordListTitle}</div>
|
||||
<div className='body'>
|
||||
{
|
||||
@ -58,14 +62,14 @@ const WarningRecordList: React.FC<WarningRecordListProps> = (props) => {
|
||||
: (dataSource?.length) > 0 ?
|
||||
<Space direction='vertical' size={10} >
|
||||
{dataSource?.map((record, index) => {
|
||||
if (index > 2) return
|
||||
if (index > maxRecordCount - 1) 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 }}
|
||||
cardStyle={{ ...cardStyle }}
|
||||
imgStyle={{ ...imgStyle }}
|
||||
/>)
|
||||
}
|
||||
)}
|
||||
|
@ -2,19 +2,21 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border-left: solid 1px #00000026;
|
||||
width: 320px;
|
||||
min-width: 320px;
|
||||
|
||||
.header {
|
||||
width: 100%;
|
||||
height: 48px;
|
||||
background-color: #EFF2F4;
|
||||
padding: 10px 20px;
|
||||
padding: 0 20px;
|
||||
box-sizing: border-box;
|
||||
line-height: 48px;
|
||||
}
|
||||
|
||||
.body {
|
||||
padding: 10px;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
flex: 1;
|
||||
}
|
||||
}
|
@ -1,35 +1,35 @@
|
||||
import React, { useState } from 'react';
|
||||
import React from 'react';
|
||||
import VideoPlayerCard from '../../../VideoPlayerCard';
|
||||
import { VideoPlayerCardProps } from '../../../VideoPlayerCard';
|
||||
import { Segmented } from 'antd';
|
||||
import { Row, Col, Segmented, theme } from 'antd';
|
||||
import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons';
|
||||
import { theme } from 'antd/lib';
|
||||
import { pxToRem } from '@zhst/func'
|
||||
import './index.less'
|
||||
|
||||
type Size = 'large' | 'small'
|
||||
export type ISize = 'large' | 'small'
|
||||
|
||||
interface WindowToggleProps {
|
||||
dataSource?: VideoPlayerCardProps[];
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
selectedWindowKey?: string;
|
||||
size: ISize;
|
||||
setSize: React.Dispatch<React.SetStateAction<ISize>>
|
||||
toggleRef: React.MutableRefObject<any>
|
||||
}
|
||||
|
||||
export const WindowToggle: React.FC<WindowToggleProps> = (props) => {
|
||||
|
||||
const { dataSource = [], handleWindowClick, handleCloseButtonClick, selectedWindowKey } = props
|
||||
const [size, setSize] = useState<Size>("large");
|
||||
const { dataSource = [], handleWindowClick, handleCloseButtonClick, selectedWindowKey, size = "large", setSize, toggleRef } = props
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
|
||||
const getLabelStyle = (isSelected: boolean) => ({
|
||||
padding: "0 11px", background: "#fff",
|
||||
padding: `0 ${pxToRem("11px")}`, background: "#fff",
|
||||
...(isSelected ? { background: token.colorPrimary, color: '#fff' } : {}),
|
||||
});
|
||||
|
||||
|
||||
return (
|
||||
<div className='zhst-biz-window-toggle'>
|
||||
<div className='zhst-biz-window-toggle' ref={toggleRef}>
|
||||
{/* 切换按钮 */}
|
||||
<div className='header'>
|
||||
<Segmented
|
||||
@ -44,25 +44,52 @@ export const WindowToggle: React.FC<WindowToggleProps> = (props) => {
|
||||
const { windowKey } = dataSource[0]
|
||||
handleWindowClick?.(windowKey)
|
||||
}
|
||||
setSize(value as Size)
|
||||
setSize(value as ISize)
|
||||
}}
|
||||
/>
|
||||
</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}
|
||||
/>)
|
||||
})
|
||||
}
|
||||
|
||||
<Row gutter={[0, 20]} style={{ width: "100%" }} > {/* 设置栅格间距 */}
|
||||
{
|
||||
size === "large" ?
|
||||
<>
|
||||
{
|
||||
dataSource?.map((item, index) => { // 仅显示前四个元素,即两行两列
|
||||
if (index > 0) return null
|
||||
return (
|
||||
<Col xs={24} sm={24} md={24} lg={24} xl={24} key={item.windowKey}>
|
||||
<VideoPlayerCard
|
||||
key={""}
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
size={size}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
{...item}
|
||||
/>
|
||||
</Col>)
|
||||
})
|
||||
|
||||
}
|
||||
</>
|
||||
: <>
|
||||
{dataSource?.map((item) => {
|
||||
return (
|
||||
<Col xs={24} sm={12} md={12} lg={12} xl={12} className='sm-card' key={item.windowKey}>
|
||||
<VideoPlayerCard
|
||||
key={item.windowKey}
|
||||
selectedWindowKey={selectedWindowKey}
|
||||
size={size}
|
||||
handleWindowClick={handleWindowClick}
|
||||
handleCloseButtonClick={handleCloseButtonClick}
|
||||
{...item}
|
||||
/>
|
||||
</Col>
|
||||
);
|
||||
})}</>
|
||||
}
|
||||
</Row>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -29,17 +29,16 @@
|
||||
}
|
||||
|
||||
.body {
|
||||
flex: 1;
|
||||
width: 100%;
|
||||
background-color: #E5EAEC;
|
||||
padding: 10px;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
>div {
|
||||
margin: 10px;
|
||||
.sm-card:nth-child(odd) {
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
.sm-card:nth-child(even) {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,2 +1,4 @@
|
||||
import WindowToggle from './WindowToggle'
|
||||
export default WindowToggle
|
||||
export default WindowToggle
|
||||
import type { ISize } from './WindowToggle';
|
||||
export type { ISize };
|
@ -3,6 +3,7 @@ import React, { useState } from 'react';
|
||||
import { IRecord, RealTimeMonitor, VideoPlayerCardProps, useViewLargerImageModal } from '@zhst/biz';
|
||||
import { videoData, warningData } from './mock';
|
||||
import { Space } from 'antd';
|
||||
import { pxToRem } from '@zhst/func';
|
||||
import dayjs from 'dayjs'
|
||||
import './index.less'
|
||||
|
||||
@ -23,6 +24,8 @@ export default () => {
|
||||
windowKey: 'forth-window',
|
||||
}
|
||||
]
|
||||
// 控制窗口切换
|
||||
const [size, setSize] = useState<"large" | "small">('large')
|
||||
const [videoDataSource, setVideoDataSource] = useState<VideoPlayerCardProps[]>(initialVideoDataSource);
|
||||
const [warningDataSource, setWarningDataSource] = useState<IRecord[]>();
|
||||
const [selectedWindowKey, setSelectedWindowKey] = useState<string | undefined>('first-window');
|
||||
@ -34,7 +37,6 @@ export default () => {
|
||||
const handleWindowClick = (key?: string) => {
|
||||
setSelectedWindowKey(key)
|
||||
}
|
||||
|
||||
const clearWindowData = (key?: string) => {
|
||||
// 当关闭窗口时 也要刷新 右侧 预警记录接口 不要忘记
|
||||
setVideoDataSource((pre) => {
|
||||
@ -47,16 +49,13 @@ export default () => {
|
||||
return newVideoDataSource
|
||||
})
|
||||
}
|
||||
|
||||
const handleDownloadImg = (imageKey?: string) => {
|
||||
console.log(imageKey)
|
||||
// 可以调用 下面 方法关闭弹窗
|
||||
// viewLargerImageModalRef.current?.handleCancel()
|
||||
}
|
||||
|
||||
const onRecordClick = (record?: IRecord) => {
|
||||
// 点击的时候把数据 拿过来处理一下传给大图弹框
|
||||
const { imageKey, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss' } = record || {}
|
||||
const { imageKey, warningType, boxId, position, cabietId, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss', odRect = [] } = record || {}
|
||||
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
//用于渲染右侧的 信息
|
||||
@ -68,8 +67,7 @@ export default () => {
|
||||
{ label: '柜子ID', value: cabietId },
|
||||
]
|
||||
// 调用这个方法打开弹框
|
||||
viewLargerImageModalRef?.current?.show({ imageKey: imageKey, warningData: warningData })
|
||||
|
||||
viewLargerImageModalRef?.current?.show({ imageKey: imageKey, warningData: warningData, odRect: odRect })
|
||||
setSelectedRecordId(record?.id)
|
||||
}
|
||||
|
||||
@ -89,7 +87,8 @@ export default () => {
|
||||
// 模拟 视频数据请求
|
||||
setTimeout(() => {
|
||||
// 对后端返回数据进行处理 组装一套符合属性的 数据
|
||||
const newVideoData: VideoPlayerCardProps = { imageKey: videoData.imageKey, title: videoData.title, }
|
||||
// videoSrc : videoData.videoSrc
|
||||
const newVideoData: VideoPlayerCardProps = { imageKey: videoData.imageKey, title: videoData.title, odRect: videoData.odRect }
|
||||
setVideoDataSource((pre) => {
|
||||
const newVideoDataSource: VideoPlayerCardProps[] = pre.map((item) => {
|
||||
// 传给 选中的视频窗口
|
||||
@ -131,6 +130,7 @@ export default () => {
|
||||
warningInfo: [`盒子${o.boxId}`, `位置${o.position}`, `柜子ID${o.cabietId}`],
|
||||
// cabietText: `柜子ID: ${o.cabietId}`,
|
||||
warningTimestamp: o.warningTimestamp,
|
||||
odRect: o.odRect
|
||||
}
|
||||
})
|
||||
setWarningDataSource(newWarningDataSource)
|
||||
@ -151,7 +151,12 @@ export default () => {
|
||||
selectedRecordId={selectedRecordId}
|
||||
viewLargerImageModalRef={viewLargerImageModalRef}
|
||||
isRecordListLoading={isRecordListLoading}
|
||||
recordListTitle="监控预警记录" />
|
||||
recordListTitle="监控预警记录"
|
||||
size={size}
|
||||
setSize={setSize}
|
||||
warningImgStyle={{ width: `${pxToRem("280px")}`, height: `${pxToRem("169px")}` }}
|
||||
/>
|
||||
|
||||
<button onClick={() => { mockData() }}>模拟请求</button>
|
||||
</Space>
|
||||
)
|
||||
|
@ -1,7 +1,14 @@
|
||||
export const videoData = {
|
||||
imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
// videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1',
|
||||
title: `盒子1 点位1`
|
||||
videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1',
|
||||
title: `盒子1 点位1`,
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
}
|
||||
|
||||
export const warningData = [
|
||||
@ -15,6 +22,13 @@ export const warningData = [
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
},
|
||||
{
|
||||
imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
@ -26,6 +40,13 @@ export const warningData = [
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
},
|
||||
{
|
||||
imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
@ -37,6 +58,13 @@ export const warningData = [
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
},
|
||||
{
|
||||
imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
@ -48,6 +76,13 @@ export const warningData = [
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
},
|
||||
{
|
||||
imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
@ -59,6 +94,13 @@ export const warningData = [
|
||||
// warningTime: "2023-03-01 ",
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
}]
|
||||
}
|
||||
]
|
||||
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Card, Space, CardProps, Spin, Button } from 'antd';
|
||||
import { theme } from 'antd/lib';
|
||||
import { ConfigProvider, VideoPlayer, type VideoViewRef, } from '@zhst/meta';
|
||||
import { Card, Space, CardProps, Spin, Button, theme } from 'antd';
|
||||
import { ConfigProvider, VideoPlayer, CropperImage, type VideoViewRef, } from '@zhst/meta';
|
||||
import React, { useState, useEffect, ReactNode, useRef, useContext } from 'react';
|
||||
import { CloseOutlined, LoadingOutlined } from '@ant-design/icons';
|
||||
import './index.less'
|
||||
@ -18,44 +17,56 @@ export interface VideoPlayerCardProps {
|
||||
title?: string | ReactNode
|
||||
handleCloseButtonClick?: (key?: string) => void;
|
||||
handleWindowClick?: (key?: string) => void;
|
||||
odRect?: {
|
||||
id: string;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
h: number;
|
||||
selectAble?: boolean;
|
||||
}[]
|
||||
[key: string]: any
|
||||
}
|
||||
|
||||
export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
|
||||
|
||||
|
||||
const { ConfigContext } = ConfigProvider;
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const { prefixCls: customizePrefixCls, showType, imageKey, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '' } = props;
|
||||
const { prefixCls: customizePrefixCls, showType, imageKey, videoSrc, cardProps, isWindowLoading, errorReasonText, size, title, handleCloseButtonClick, handleWindowClick, windowKey, selectedWindowKey = '', odRect = [] } = props;
|
||||
const componentName = getPrefixCls('biz-video-player-card', customizePrefixCls);
|
||||
const [cardContent, setCardContent] = useState<JSX.Element | null>(null);
|
||||
const { useToken } = theme
|
||||
const { token } = useToken()
|
||||
const videoRef = useRef<VideoViewRef>(null)
|
||||
const odRectDefault = odRect?.map(rect => ({
|
||||
...rect,
|
||||
selectAble: rect.hasOwnProperty('selectAble') ? rect.selectAble : false
|
||||
}));
|
||||
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 || imageKey)) {
|
||||
let contentElement: JSX.Element | null = null;
|
||||
if (videoSrc) {
|
||||
contentElement = (
|
||||
<VideoPlayer ref={videoRef} url={videoSrc} />
|
||||
<VideoPlayer ref={videoRef} url={videoSrc} showOD odList={odRectDefault} />
|
||||
);
|
||||
videoRef.current?.setShowCrop(true)
|
||||
|
||||
} else if (imageKey) {
|
||||
contentElement = (
|
||||
<img
|
||||
alt="首帧图"
|
||||
src={imageKey}
|
||||
style={{ width: "100%", height: "100%", display: 'block' }}
|
||||
/>
|
||||
<div style={{ width: "100%", height: "100%" }}>
|
||||
<CropperImage
|
||||
// editAble={true}
|
||||
selectAble={false}
|
||||
odList={odRectDefault}
|
||||
url={imageKey}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
setCardContent(contentElement);
|
||||
@ -63,10 +74,10 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
|
||||
setCardContent(null)
|
||||
}
|
||||
}, [showType, imageKey, videoSrc, isWindowLoading]);
|
||||
|
||||
return (
|
||||
<div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} style={videoPlayerCardStyle}>
|
||||
<div className={componentName} onClick={() => { handleWindowClick?.(windowKey) }} >
|
||||
<Card
|
||||
className={`${size === 'large' ? `${componentName}-large` : `${componentName}-small`}`}
|
||||
title={
|
||||
<Space style={{ width: "100%", justifyContent: "space-between" }}>
|
||||
<div>{title}</div>
|
||||
@ -77,7 +88,7 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
|
||||
</div>
|
||||
</Space>}
|
||||
style={{ display: "flex", flexDirection: "column", borderRadius: 4, overflow: "hidden", ...cardStyle }}
|
||||
bodyStyle={{ flex: 1 }}
|
||||
styles={{ body: { flex: 1 } }}
|
||||
{...cardProps}
|
||||
>
|
||||
{cardContent ? (
|
||||
@ -85,7 +96,7 @@ export const VideoPlayerCard: React.FC<VideoPlayerCardProps> = (props) => {
|
||||
{cardContent}
|
||||
</>
|
||||
) : (
|
||||
<div style={{ backgroundColor: '#000', height: '100%', display: 'flex', padding: '20px', boxSizing: 'border-box' }}>
|
||||
<div className={`${componentName}-error`} >
|
||||
{
|
||||
isWindowLoading ?
|
||||
<div style={{ flex: 1, display: 'flex', justifyContent: 'center', alignItems: 'center' }}>
|
||||
|
@ -7,7 +7,7 @@ const mockVideoPlayerCardProps: VideoPlayerCardProps = {
|
||||
showType: 'image',
|
||||
videoSrc: 'ws://10.0.0.7:9033/flv/File/test/test_h264_1.mp4.flv?ip=127.0.0.1',
|
||||
// 如果需要在没有视频时显示图片封面
|
||||
// imageKey: 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
// imageKey : 'https://i.yourimageshare.com/lRHiD2UnAT.png',
|
||||
size: 'small',
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,21 @@
|
||||
.zhst-biz-video-player-card {
|
||||
&-large {
|
||||
height: 931px;
|
||||
}
|
||||
|
||||
&-small {
|
||||
height: 456px;
|
||||
cursor: pointer
|
||||
}
|
||||
|
||||
&-error {
|
||||
background-color: #000;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
padding: 20px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.ant-card-head {
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { useImperativeHandle, useRef, useState, forwardRef, useContext } from 'react';
|
||||
import { Modal, ModalProps, Space, SpaceProps } from 'antd';
|
||||
import theme from 'antd/lib/theme';
|
||||
import { Modal, ModalProps, Space, SpaceProps, theme } from 'antd';
|
||||
import { DownloadOutlined } from '@ant-design/icons';
|
||||
import { ConfigProvider,CropperImage} from '@zhst/meta';
|
||||
import { ConfigProvider, CropperImage } from '@zhst/meta';
|
||||
|
||||
import './index.less'
|
||||
|
||||
@ -44,8 +43,6 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
|
||||
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);
|
||||
@ -85,14 +82,13 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
|
||||
{...modalProps}
|
||||
>
|
||||
<Space size={0} {...spaceProps}>
|
||||
<div className={`${componentName}-left-img`}>
|
||||
<div style={{ width: 789, height: 444, ...imgStyle }}>
|
||||
<CropperImage
|
||||
// editAble={true}
|
||||
odList={odRectDefault}
|
||||
url={imageKey}
|
||||
/>
|
||||
</div>
|
||||
<div className={`${componentName}-left-img`} style={{ ...imgStyle }}>
|
||||
<CropperImage
|
||||
// editAble={false}
|
||||
// selectAble={false}
|
||||
odList={odRectDefault}
|
||||
url={imageKey}
|
||||
/>
|
||||
</div>
|
||||
<div className='right-context'>
|
||||
{warningData?.map(({ label, value }) => (
|
||||
@ -101,7 +97,7 @@ export const ViewLargerImageModal = forwardRef<ViewLargerImageModalRef, ViewLarg
|
||||
{value}
|
||||
</div>
|
||||
))}
|
||||
{imageKey && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imageKey)} ><DownloadOutlined /><span style={{ paddingLeft: 3 }}>{downloadText}</span></div>}
|
||||
{imageKey && downloadImg && <div className='img-download' style={{ color: token.colorPrimary }} onClick={() => downloadImg?.(imageKey)} ><DownloadOutlined /><span className='img-download-text'>{downloadText}</span></div>}
|
||||
</div>
|
||||
</Space>
|
||||
</Modal>
|
||||
|
@ -17,7 +17,7 @@ const backEndData = [
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
// "id": "456",
|
||||
"id": "456",
|
||||
"x": 0.6519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
@ -35,7 +35,7 @@ const backEndData = [
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
// "id": "456",
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
@ -71,7 +71,6 @@ export default () => {
|
||||
const viewLargerImageModalRef = useViewLargerImageModal()
|
||||
|
||||
const handleDownloadImg = () => {
|
||||
console.log('download')
|
||||
// 可以调用 下面 方法关闭弹窗
|
||||
// viewLargerImageModalRef.current?.handleCancel()
|
||||
}
|
||||
|
@ -1,6 +1,11 @@
|
||||
.zhst-biz-warning-larger-image {
|
||||
font-family: MicrosoftYaHei;
|
||||
|
||||
&-left-img {
|
||||
width: 789px;
|
||||
height: 444px;
|
||||
}
|
||||
|
||||
.ant-modal-content {
|
||||
padding: 0;
|
||||
height: 492px;
|
||||
@ -52,6 +57,10 @@
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
cursor: pointer;
|
||||
|
||||
.img-download-text {
|
||||
padding-left: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ title: ViewLargerImageModal 查看大图弹窗
|
||||
| --- | --- | --- | --- | --- |
|
||||
| show() |通过 ref 用于开启弹窗 可以将点击的 记录传给弹窗| | | |
|
||||
| handleCancel() | 通过 ref 用于关闭弹窗 | | | |
|
||||
| imageKey | 图片地址 |string | | |
|
||||
| imageKey | 图片地址 |string | | |
|
||||
| contextData | 大图显示的数据 | | | |
|
||||
| imgStyle | 用于修改图片样式 | | | |
|
||||
| downloadImg | 传入下载图片的方法 | | | |
|
||||
|
@ -1,9 +1,7 @@
|
||||
import { Card, Space, Divider, CardProps } from 'antd';
|
||||
import { theme } from 'antd/lib';
|
||||
import { Card, Space, Divider, CardProps, theme } from 'antd';
|
||||
import React, { useContext } from 'react';
|
||||
import dayjs from 'dayjs';
|
||||
import { ConfigProvider,CropperImage} from '@zhst/meta';
|
||||
|
||||
import { ConfigProvider, CropperImage } from '@zhst/meta';
|
||||
import './index.less'
|
||||
export interface IRecord {
|
||||
|
||||
@ -55,7 +53,7 @@ export interface IRecord {
|
||||
接收 od框 坐标
|
||||
*/
|
||||
odRect?: {
|
||||
id?: string;
|
||||
id: string;
|
||||
x: number;
|
||||
y: number;
|
||||
w: number;
|
||||
@ -77,13 +75,11 @@ export interface WarningRecordCardProps {
|
||||
};
|
||||
|
||||
export const WarningRecordCard: React.FC<WarningRecordCardProps> = (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 { imageKey, id, warningType, warningInfo = [], cabietText, warningTime, warningTimestamp, warningTimeFormat = 'YYYY-MM-DD HH:mm:ss', odRect = [] } = record || {}
|
||||
const formattedDate = warningTimestamp ? dayjs(warningTimestamp).format(warningTimeFormat) : '';
|
||||
const warningTimeShow = warningTime ? warningTime : formattedDate
|
||||
@ -99,42 +95,40 @@ export const WarningRecordCard: React.FC<WarningRecordCardProps> = (props) => {
|
||||
const selectedCardStyle: React.CSSProperties = {
|
||||
...(selectedRecordId === record?.id ? selectedBorderStyle : {})
|
||||
};
|
||||
|
||||
const handleClick = () => {
|
||||
onRecordClick?.(record);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className={componentName} key={id} onClick={handleClick} style={style}>
|
||||
<Card
|
||||
cover={
|
||||
<div style={{ width: 336, height: 203, ...imgStyle }}>
|
||||
<CropperImage
|
||||
// editAble={true}
|
||||
odList={odRectDefault}
|
||||
url={imageKey}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
style={{ width: 356, height: 302, padding: 10, borderRadius: 4, ...selectedCardStyle, ...cardStyle }}
|
||||
className={`${componentName}-card`}
|
||||
style={{ ...selectedCardStyle, ...cardStyle }}
|
||||
{...cardProps}
|
||||
>
|
||||
<div className={`${componentName}-left-context`}>
|
||||
<div className={`${componentName}-left-context-warning-type`}>{warningType}</div>
|
||||
<Space size={0} split={<Divider type="vertical" />}>
|
||||
{warningInfo?.map((item, index) => (
|
||||
<div key={index} className="info-item">
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
<div className={`${componentName}-left-context-warning-time`}>{warningTimeShow}</div>
|
||||
<div className={`${componentName}-card-img`} style={{ ...imgStyle }}>
|
||||
<CropperImage
|
||||
// 无法触发 图片点击时间需要 加 selectAble
|
||||
selectAble={false}
|
||||
odList={odRectDefault}
|
||||
url={imageKey}
|
||||
/>
|
||||
</div>
|
||||
<div className={`${componentName}-cabietInfo`} >{cabietText}</div>
|
||||
<div style={{ display: 'flex' }}>
|
||||
<div className={`${componentName}-left-context`}>
|
||||
<div className={`${componentName}-left-context-warning-type`}>{warningType}</div>
|
||||
<Space size={0} split={<Divider type="vertical" />}>
|
||||
{warningInfo?.map((item, index) => (
|
||||
<div key={index} className="info-item">
|
||||
{item}
|
||||
</div>
|
||||
))}
|
||||
</Space>
|
||||
<div className={`${componentName}-left-context-warning-time`}>{warningTimeShow}</div>
|
||||
</div>
|
||||
<div className={`${componentName}-cabietInfo`} >{cabietText}</div>
|
||||
|
||||
</div>
|
||||
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
|
@ -16,7 +16,7 @@ const backEndData = [
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
// "id": "123",
|
||||
"id": "123",
|
||||
"x": 0.5519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
@ -34,7 +34,7 @@ const backEndData = [
|
||||
warningTimestamp: Date.now(),
|
||||
// warningTimeFormat:"YYYY-MM-DD"
|
||||
odRect: [{
|
||||
// "id": "456",
|
||||
"id": "456",
|
||||
"x": 0.1519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
|
@ -1,24 +1,32 @@
|
||||
.zhst-biz-warning-record-card {
|
||||
cursor: pointer;
|
||||
|
||||
.ant-card-body {
|
||||
padding: 0;
|
||||
font-family: MicrosoftYaHei;
|
||||
line-height: 19px;
|
||||
display: flex;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
|
||||
.ant-card-bordered {
|
||||
border: 2px solid #f0f0f0;
|
||||
}
|
||||
|
||||
&-cover-img img {
|
||||
width: 336px;
|
||||
height: 203px;
|
||||
border-radius: 0,
|
||||
&-card {
|
||||
border-radius: 4px;
|
||||
max-width: 380px;
|
||||
|
||||
&-img {
|
||||
width: 356px ;
|
||||
height: 203px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.ant-card-body {
|
||||
padding: 10px;
|
||||
font-family: MicrosoftYaHei;
|
||||
line-height: 19px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&-left-context {
|
||||
flex: 1;
|
||||
|
||||
|
@ -16,7 +16,7 @@ title: WarningRecordCard 预警记录卡片
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| imageKey | 图片src | string | - | - |
|
||||
| imageKey | 图片src | string | - | - |
|
||||
| id | 数据的唯一id 用于key 传值| string | - | - |
|
||||
| warningType | 预警类型 | string | - | - |
|
||||
| warningInfo | 盒子 点位 柜子 等信息 | string[] | - | - |
|
||||
|
@ -1,13 +1,18 @@
|
||||
import React, { FC } from 'react';
|
||||
import React, { FC, useContext } from 'react';
|
||||
import { Tabs, TabsProps } from 'antd'
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import BoxPanel from './components/boxPanel';
|
||||
import type { BoxPanelProps } from './components/boxPanel';
|
||||
|
||||
import './index.less'
|
||||
import classNames from 'classnames';
|
||||
export interface BoxSelectTreeProps extends BoxPanelProps {
|
||||
onTabChange?: (e: any) => void
|
||||
tabsProps?: TabsProps
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
||||
const {
|
||||
data,
|
||||
@ -28,69 +33,52 @@ const BoxSelectTree: FC<BoxSelectTreeProps> = (props) => {
|
||||
customImport,
|
||||
showOptions,
|
||||
extraBtns,
|
||||
prefixCls: customizePrefixCls
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('biz-box-select-tree', customizePrefixCls);
|
||||
|
||||
const items: TabsProps['items'] = [
|
||||
{
|
||||
key: '1',
|
||||
label: <div style={{ textAlign:'center', width: '160px' }} >盒子</div>,
|
||||
children: (
|
||||
<BoxPanel
|
||||
searchInputProps={searchInputProps}
|
||||
boxDataSource={boxDataSource}
|
||||
treeProps={treeProps}
|
||||
data={data}
|
||||
onCreate={onCreate}
|
||||
onCreateSubmit={onCreateSubmit}
|
||||
onBoxBatchDelete={onBoxBatchDelete}
|
||||
onBoxDelete={onBoxDelete}
|
||||
onSearch={onSearch}
|
||||
onItemCheck={onItemCheck}
|
||||
onItemSelect={onItemSelect}
|
||||
showOptions={showOptions}
|
||||
customImport={customImport}
|
||||
extraBtns={extraBtns}
|
||||
onClockClick={onClockClick}
|
||||
onImport={onImport}
|
||||
/>
|
||||
)
|
||||
label: <div className={classNames(componentName + '-tab')} style={{ textAlign:'center' }} >盒子</div>,
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: <div style={{ textAlign:'center', width: '160px' }} >盒子组</div>,
|
||||
children: (
|
||||
<BoxPanel
|
||||
searchInputProps={searchInputProps}
|
||||
boxDataSource={boxDataSource}
|
||||
treeProps={treeProps}
|
||||
data={data}
|
||||
onCreate={onCreate}
|
||||
onCreateSubmit={onCreateSubmit}
|
||||
onBoxBatchDelete={onBoxBatchDelete}
|
||||
onBoxDelete={onBoxDelete}
|
||||
onSearch={onSearch}
|
||||
onItemCheck={onItemCheck}
|
||||
onItemSelect={onItemSelect}
|
||||
showOptions={showOptions}
|
||||
customImport={customImport}
|
||||
extraBtns={extraBtns}
|
||||
onClockClick={onClockClick}
|
||||
onImport={onImport}
|
||||
/>
|
||||
)
|
||||
label: <div className={classNames(componentName + '-tab')} style={{ textAlign:'center' }} >盒子组</div>,
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
centered
|
||||
items={items}
|
||||
onChange={onTabChange}
|
||||
tabBarGutter={0}
|
||||
indicator={{ size: (origin) => origin, align: 'center' }}
|
||||
{...tabsProps}
|
||||
/>
|
||||
<div className={componentName}>
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
centered
|
||||
items={items}
|
||||
onChange={onTabChange}
|
||||
tabBarGutter={0}
|
||||
indicator={{ size: (origin) => origin, align: 'center' }}
|
||||
{...tabsProps}
|
||||
/>
|
||||
<BoxPanel
|
||||
searchInputProps={searchInputProps}
|
||||
boxDataSource={boxDataSource}
|
||||
treeProps={treeProps}
|
||||
data={data}
|
||||
onCreate={onCreate}
|
||||
onCreateSubmit={onCreateSubmit}
|
||||
onBoxBatchDelete={onBoxBatchDelete}
|
||||
onBoxDelete={onBoxDelete}
|
||||
onSearch={onSearch}
|
||||
onItemCheck={onItemCheck}
|
||||
onItemSelect={onItemSelect}
|
||||
showOptions={showOptions}
|
||||
customImport={customImport}
|
||||
extraBtns={extraBtns}
|
||||
onClockClick={onClockClick}
|
||||
onImport={onImport}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -0,0 +1,36 @@
|
||||
.zhst-biz-box-select-tree-panel {
|
||||
&-search {
|
||||
display: flex;
|
||||
padding: 0 12px;
|
||||
|
||||
&-input {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&-btns {
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
&-btns {
|
||||
padding: 6px 12px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
&-common {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
&-import {
|
||||
padding: 4px 8px;
|
||||
}
|
||||
|
||||
&-divider {
|
||||
margin: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
&-tree {
|
||||
padding: 6px 0;
|
||||
}
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
import React, { FC, useState, useRef } from 'react';
|
||||
import React, { FC, useState, useRef, useContext } from 'react';
|
||||
import{ Button, Divider, Input, Space, TreeDataNode } from 'antd'
|
||||
import { ModalForm, ModalFormProps, ProFormInstance, ProFormText } from '@ant-design/pro-components'
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import { ClockCircleOutlined, CloseCircleOutlined, DiffOutlined, FolderAddOutlined, ImportOutlined, SwitcherOutlined } from '@ant-design/icons'
|
||||
import type { TreeProps, InputProps } from 'antd';
|
||||
import type { BoxTreeProps } from '../../../tree';
|
||||
import TreeTransferModal from '../../../treeTransferModal'
|
||||
import BoxTree from '../../../tree';
|
||||
import './index.less'
|
||||
import classNames from 'classnames';
|
||||
|
||||
export interface BoxPanelProps {
|
||||
searchInputProps?: InputProps
|
||||
@ -26,8 +29,11 @@ export interface BoxPanelProps {
|
||||
onCreate?: () => void
|
||||
customImport?: any
|
||||
extraBtns?: any
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
const BoxPanel: FC<BoxPanelProps> = (props) => {
|
||||
const {
|
||||
searchInputProps,
|
||||
@ -46,8 +52,12 @@ const BoxPanel: FC<BoxPanelProps> = (props) => {
|
||||
onBatch,
|
||||
onCreate,
|
||||
boxDataSource,
|
||||
prefixCls: customizePrefixCls,
|
||||
customImport
|
||||
} = props
|
||||
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('biz-box-select-tree-panel', customizePrefixCls);
|
||||
const [isTreeCheckable, setIsTreeCheckable] = useState(false)
|
||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||
const [boxChoiceOpen, setBoxChoiceOpen] = useState(false)
|
||||
@ -104,7 +114,7 @@ const BoxPanel: FC<BoxPanelProps> = (props) => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '0 16px' }}>
|
||||
<div className={componentName}>
|
||||
{/* 盒子选择弹框 */}
|
||||
<TreeTransferModal
|
||||
open={boxChoiceOpen}
|
||||
@ -118,102 +128,109 @@ const BoxPanel: FC<BoxPanelProps> = (props) => {
|
||||
onTreeCheck={onTreeCheck} // 树check选中事件
|
||||
onItemDelete={onItemDelete} // 右侧点击删除事件
|
||||
/>
|
||||
<Space size={12} direction='vertical' style={{ width: '100%' }}>
|
||||
<Space size={4} style={{ width: '100%', justifyContent: 'space-between' }} >
|
||||
<Input size='middle' onChange={(e) => onSearch?.(e)} placeholder='请输入盒子名称' {...searchInputProps} />
|
||||
{customImport || (
|
||||
<>
|
||||
<Button type="text" onClick={() => onBatch?.() || handleCheckable()} icon={isTreeCheckable ? <SwitcherOutlined /> : <DiffOutlined />} />
|
||||
<Button type="text" onClick={() => onClockClick?.()} icon={<ClockCircleOutlined />} />
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
{/* 是否显示操作按钮 */}
|
||||
{showOptions && (
|
||||
<>
|
||||
<Space align='center'>
|
||||
<Button type='text' style={{ padding: '4px 8px' }} onClick={() => onImport?.()} icon={<ImportOutlined />} >导入盒子</Button>
|
||||
<Divider type="vertical" style={{ margin: '8px 0' }} />
|
||||
{onCreate ?
|
||||
(
|
||||
<Button onClick={onCreate} type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} >新建组</Button>
|
||||
) : (
|
||||
<ModalForm<{
|
||||
name: string
|
||||
boxList?: any[]
|
||||
}>
|
||||
width={'600px'}
|
||||
open={onCreate ? false : undefined}
|
||||
formRef={createFormRef}
|
||||
title="新建组"
|
||||
modalProps={{ destroyOnClose: true }}
|
||||
layout='horizontal'
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
trigger={<Button type='text' style={{ padding: '4px 8px' }} icon={<FolderAddOutlined />} >新建组</Button>}
|
||||
submitter={{
|
||||
searchConfig: {
|
||||
submitText: '确定',
|
||||
resetText: '取消',
|
||||
},
|
||||
}}
|
||||
onFinish={onCreateSubmit}
|
||||
>
|
||||
<ProFormText
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
max: 20,
|
||||
},
|
||||
{
|
||||
pattern: /^[^\s]*$/g,
|
||||
message: '禁止输入空格'
|
||||
}
|
||||
]}
|
||||
fieldProps={{ showCount: true }}
|
||||
width="md"
|
||||
name="name"
|
||||
label="盒子组名称"
|
||||
placeholder="请输入盒子名称"
|
||||
/>
|
||||
<ProFormText
|
||||
width="md"
|
||||
name="boxList"
|
||||
label="盒子选择"
|
||||
fieldProps={{
|
||||
readOnly: true,
|
||||
value: `已选择${createFormRef.current?.getFieldValue('boxList')?.length || 0}个盒子`,
|
||||
suffix: (
|
||||
<Space>
|
||||
<a onClick={() => {
|
||||
createFormRef.current?.setFieldValue('boxList', null)
|
||||
onBoxChoiceReset()
|
||||
}} >恢复默认</a>
|
||||
<a onClick={() => setBoxChoiceOpen(true)}>范围选择</a>
|
||||
</Space>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</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
|
||||
treeCheckable={isTreeCheckable}
|
||||
data={data}
|
||||
onItemSelect={onItemSelect}
|
||||
onItemCheck={onItemCheck}
|
||||
onItemDelete={onBoxDelete}
|
||||
{...treeProps}
|
||||
<div className={classNames(componentName + '-search')}>
|
||||
<Input
|
||||
className={classNames(componentName + '-search-input')}
|
||||
size='middle'
|
||||
onChange={(e) => onSearch?.(e)}
|
||||
placeholder='请输入盒子名称'
|
||||
{...searchInputProps}
|
||||
/>
|
||||
</Space>
|
||||
{customImport || (
|
||||
<div
|
||||
className={classNames(componentName + '-search-btns')}
|
||||
>
|
||||
<Button type="text" onClick={() => onBatch?.() || handleCheckable()} icon={isTreeCheckable ? <SwitcherOutlined /> : <DiffOutlined />} />
|
||||
<Button type="text" onClick={() => onClockClick?.()} icon={<ClockCircleOutlined />} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{/* 是否显示操作按钮 */}
|
||||
{showOptions && (
|
||||
<>
|
||||
<div className={classNames(componentName + '-btns')}>
|
||||
<Button className={classNames(componentName + '-btns-common')} type='text' onClick={() => onImport?.()} icon={<ImportOutlined />} >导入盒子</Button>
|
||||
<Divider className={classNames(componentName + '-btns-divider')} type="vertical" />
|
||||
{onCreate ?
|
||||
(
|
||||
<Button className={classNames(componentName + '-btns-common')} onClick={onCreate} type='text' icon={<FolderAddOutlined />} >新建组</Button>
|
||||
) : (
|
||||
<ModalForm<{
|
||||
name: string
|
||||
boxList?: any[]
|
||||
}>
|
||||
className={classNames(componentName + '-create-modal')}
|
||||
open={onCreate ? false : undefined}
|
||||
formRef={createFormRef}
|
||||
title="新建组"
|
||||
modalProps={{ destroyOnClose: true }}
|
||||
layout='horizontal'
|
||||
labelCol={{ span: 6 }}
|
||||
wrapperCol={{ span: 18 }}
|
||||
trigger={<Button type='text' className={classNames(componentName + '-btns-common')} icon={<FolderAddOutlined />} >新建组</Button>}
|
||||
submitter={{
|
||||
searchConfig: {
|
||||
submitText: '确定',
|
||||
resetText: '取消',
|
||||
},
|
||||
}}
|
||||
onFinish={onCreateSubmit}
|
||||
>
|
||||
<ProFormText
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
max: 20,
|
||||
},
|
||||
{
|
||||
pattern: /^[^\s]*$/g,
|
||||
message: '禁止输入空格'
|
||||
}
|
||||
]}
|
||||
fieldProps={{ showCount: true }}
|
||||
width="md"
|
||||
name="name"
|
||||
label="盒子组名称"
|
||||
placeholder="请输入盒子名称"
|
||||
/>
|
||||
<ProFormText
|
||||
width="md"
|
||||
name="boxList"
|
||||
label="盒子选择"
|
||||
fieldProps={{
|
||||
readOnly: true,
|
||||
value: `已选择${createFormRef.current?.getFieldValue('boxList')?.length || 0}个盒子`,
|
||||
suffix: (
|
||||
<Space>
|
||||
<a onClick={() => {
|
||||
createFormRef.current?.setFieldValue('boxList', null)
|
||||
onBoxChoiceReset()
|
||||
}} >恢复默认</a>
|
||||
<a onClick={() => setBoxChoiceOpen(true)}>范围选择</a>
|
||||
</Space>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</ModalForm>
|
||||
)
|
||||
}
|
||||
<Divider className={classNames(componentName + '-btns-divider')} type="vertical" />
|
||||
{/* @ts-ignore */}
|
||||
<Button className={classNames(componentName + '-btns-common')} danger type='text' icon={<CloseCircleOutlined />} disabled={treeProps?.checkedKeys?.length <= 0} onClick={onBoxBatchDelete} >删除</Button>
|
||||
</div>
|
||||
<Divider style={{ margin: 0 }} />
|
||||
</>
|
||||
)}
|
||||
{extraBtns}
|
||||
<BoxTree
|
||||
className={classNames(componentName + '-tree')}
|
||||
treeCheckable={isTreeCheckable}
|
||||
data={data}
|
||||
onItemSelect={onItemSelect}
|
||||
onItemCheck={onItemCheck}
|
||||
onItemDelete={onBoxDelete}
|
||||
{...treeProps}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ const demo = () => {
|
||||
addonBefore: (
|
||||
<Select
|
||||
value={searchType}
|
||||
dropdownMatchSelectWidth={false}
|
||||
onChange={_type => {
|
||||
setSearchType(_type)
|
||||
setSearchVal('')
|
||||
|
5
packages/biz/src/boxSelectTree/index.less
Normal file
5
packages/biz/src/boxSelectTree/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
.zhst-biz-box-select-tree {
|
||||
&-tab {
|
||||
width: 160px;
|
||||
}
|
||||
}
|
@ -17,4 +17,5 @@ export { default as ViewLargerImageModal, useViewLargerImageModal } from './View
|
||||
export type { VideoPlayerCardProps } from './VideoPlayerCard'
|
||||
export { default as VideoPlayerCard } from './VideoPlayerCard'
|
||||
export { default as RealTimeMonitor } from './RealTimeMonitor'
|
||||
|
||||
export { default as InfiniteList } from './infiniteList'
|
||||
export type { InfiniteListProps, InfiniteListRefProps } from './infiniteList'
|
||||
|
129
packages/biz/src/infiniteList/InfiniteList.tsx
Normal file
129
packages/biz/src/infiniteList/InfiniteList.tsx
Normal file
@ -0,0 +1,129 @@
|
||||
/**
|
||||
* Created by jiangzhixiong
|
||||
*/
|
||||
|
||||
import React, { forwardRef, ReactNode, useContext, useImperativeHandle, useRef } from 'react'
|
||||
import { ConfigProvider } from '@zhst/meta';
|
||||
import { Divider, Flex } from 'antd';
|
||||
import classNames from 'classnames';
|
||||
import InfiniteScroll from 'react-infinite-scroll-component';
|
||||
import { SearchCard, SearchCardProps } from './components';
|
||||
import './index.less'
|
||||
import { Idata } from './components/SearchCard';
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
export interface InfiniteListProps {
|
||||
type?: 'custom' | 'auto'
|
||||
prefixCls?: string;
|
||||
height?: number;
|
||||
itemRender?: (data?: any) => React.ReactNode
|
||||
loading?: boolean; //
|
||||
data: Idata[];
|
||||
targetId?: string; // 滚动列表 ID
|
||||
loadMore?: (data?: any) => any;
|
||||
params?: {
|
||||
[key: string]: any;
|
||||
}
|
||||
hasMore: boolean;
|
||||
endMessage?: ReactNode
|
||||
loadingMessage?: ReactNode
|
||||
onItemClick?: (data: any) => void;
|
||||
searchCardProps?: SearchCardProps
|
||||
}
|
||||
|
||||
export interface InfiniteListRefProps {
|
||||
|
||||
}
|
||||
|
||||
const InfiniteList = forwardRef<InfiniteListRefProps, InfiniteListProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
height,
|
||||
type = 'auto',
|
||||
loadingMessage = <p style={{ textAlign: 'center' }}>加载中...</p>,
|
||||
targetId = 'scrollableDiv',
|
||||
itemRender,
|
||||
hasMore,
|
||||
onItemClick,
|
||||
loadMore,
|
||||
data = [],
|
||||
endMessage = <Divider plain>没有更多数据了...🤐</Divider>,
|
||||
searchCardProps
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('biz-infinite-list', customizePrefixCls);
|
||||
const listRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
||||
}))
|
||||
|
||||
return (
|
||||
<div
|
||||
id={targetId}
|
||||
className={classNames(componentName)}
|
||||
ref={listRef}
|
||||
style={{
|
||||
height,
|
||||
overflow: 'auto',
|
||||
padding: 12
|
||||
}}
|
||||
>
|
||||
{/* {loading ? (
|
||||
<p>加载中...</p>
|
||||
) : (
|
||||
<Flex wrap='wrap' gap="small" className={classNames(componentName + 'items')}>
|
||||
{data?.list?.map((item) => (
|
||||
itemRender?.(item) || (
|
||||
<div className={classNames(componentName + 'items-item')}>
|
||||
<SearchCard data={item} />
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</Flex>
|
||||
)} */}
|
||||
<InfiniteScroll
|
||||
dataLength={data.length}
|
||||
next={type === 'auto' ? loadMore! : () => {}}
|
||||
hasMore={hasMore}
|
||||
loader={loadingMessage}
|
||||
endMessage={endMessage}
|
||||
scrollableTarget={targetId}
|
||||
>
|
||||
<Flex wrap='wrap' gap="small" className={classNames(componentName + 'items')}>
|
||||
{data?.map((item, idx) => (
|
||||
itemRender?.(item) || (
|
||||
<div
|
||||
key={idx}
|
||||
className={classNames(componentName + 'items-item')}
|
||||
onClick={() => {
|
||||
onItemClick?.(item)
|
||||
}}
|
||||
>
|
||||
<SearchCard
|
||||
id={idx + 1}
|
||||
data={item}
|
||||
width="184px"
|
||||
{...searchCardProps}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
))}
|
||||
</Flex>
|
||||
</InfiniteScroll>
|
||||
{/* <div style={{ marginTop: 8 }}>
|
||||
{!noMore && (
|
||||
<Button onClick={loadMore} disabled={loadingMore}>
|
||||
{loadingMore ? '加载中...' : '点击加载更多'}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
{noMore && <span>没有更多数据了</span>}
|
||||
</div> */}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default InfiniteList
|
105
packages/biz/src/infiniteList/components/SearchCard.tsx
Normal file
105
packages/biz/src/infiniteList/components/SearchCard.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/04/28
|
||||
*/
|
||||
|
||||
import React, { forwardRef, useContext, useImperativeHandle } from 'react'
|
||||
import { ConfigProvider, EMPTY_BASE64 } from '@zhst/meta'
|
||||
import { Flex, Image } from 'antd';
|
||||
import './index.less'
|
||||
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
export interface Idata {
|
||||
id?: string | number;
|
||||
url?: string;
|
||||
sort?: number;
|
||||
title?: string;
|
||||
subtitle?: string;
|
||||
}
|
||||
|
||||
export interface SearchCardProps extends Idata {
|
||||
prefixCls?: string;
|
||||
data?: Idata
|
||||
width?: string;
|
||||
height?: string;
|
||||
onCreateTxt?: string;
|
||||
onCreate?: (data: any) => void;
|
||||
onAddTxt?: string;
|
||||
onAdd?: (data: any) => void;
|
||||
onRemoveTxt?: string;
|
||||
onRemove?: (data: any) => void;
|
||||
customOptionRender?: React.ReactNode
|
||||
}
|
||||
|
||||
export interface SearchCardRefProps {
|
||||
}
|
||||
|
||||
const SearchCard = forwardRef<SearchCardRefProps, SearchCardProps>((props, ref) => {
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
url,
|
||||
id,
|
||||
title,
|
||||
subtitle,
|
||||
sort,
|
||||
data,
|
||||
onCreate,
|
||||
onCreateTxt = '创建检索',
|
||||
onAddTxt = '添加目标',
|
||||
onRemoveTxt = '移除轨迹',
|
||||
onAdd,
|
||||
onRemove,
|
||||
customOptionRender,
|
||||
width = '184px',
|
||||
height = '100%'
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext)
|
||||
const componentName = getPrefixCls('biz-search-card', customizePrefixCls);
|
||||
|
||||
const stopBumble = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>, fn?: ((data: Idata) => void), data?: Idata) => {
|
||||
e.stopPropagation()
|
||||
fn?.(data!)
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
|
||||
}))
|
||||
|
||||
return (
|
||||
<div
|
||||
className={componentName}
|
||||
style={{
|
||||
width,
|
||||
height
|
||||
}}
|
||||
>
|
||||
<div className={`${componentName}-main`}>
|
||||
<i className={`${componentName}-main-num`}>{id || sort}</i>
|
||||
<Image
|
||||
className={`${componentName}-main-img`}
|
||||
src={url || data?.url}
|
||||
height={'240px'}
|
||||
preview={false}
|
||||
fallback={EMPTY_BASE64}
|
||||
/>
|
||||
<Flex align='center' justify='space-between' className={`${componentName}-main-opt`}>
|
||||
{customOptionRender || (
|
||||
<>
|
||||
<a onClick={(e) => stopBumble(e, onCreate, data)}>{onCreateTxt}</a>
|
||||
|
|
||||
<a onClick={(e) => stopBumble(e, onAdd, data)}>{onAddTxt}</a>
|
||||
|
|
||||
<a onClick={(e) => stopBumble(e, onRemove, data)}>{onRemoveTxt}</a>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</div>
|
||||
<div className={`${componentName}-footer`}>
|
||||
<p className={`${componentName}-footer-tit`}>{title || data?.title}</p>
|
||||
<p className={`${componentName}-footer-subtitle`}>{subtitle || data?.subtitle}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default SearchCard
|
81
packages/biz/src/infiniteList/components/index.less
Normal file
81
packages/biz/src/infiniteList/components/index.less
Normal file
@ -0,0 +1,81 @@
|
||||
.zhst-biz-search-card {
|
||||
border: 2px solid transparent;
|
||||
transition: .1s ease-in all;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
border: 2px solid #09f;
|
||||
|
||||
.zhst-biz-search-card-main-opt {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&-main {
|
||||
position: relative;
|
||||
|
||||
&-num {
|
||||
position: absolute;
|
||||
right: 2px;
|
||||
top: 2px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
line-height: 20px;
|
||||
font-style: normal;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
color: rgb(153, 153, 153);
|
||||
background-color: rgba(255, 255, 255, 75%);
|
||||
z-index: 1;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
&-img {
|
||||
width: 100%;
|
||||
height: 240px;
|
||||
}
|
||||
|
||||
&-opt {
|
||||
display: none;
|
||||
position: absolute;
|
||||
padding: 6px 3px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
bottom: 0;
|
||||
font-size: 12px;
|
||||
background-color: #09f;
|
||||
color: #fff;
|
||||
box-sizing: border-box;
|
||||
transition: .2s ease-in all;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-footer {
|
||||
padding: 6px;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
|
||||
&-tit {
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
&-subtitle {
|
||||
margin: 0;
|
||||
line-height: 20px;
|
||||
transition: .1s ease-in all;
|
||||
|
||||
&:hover {
|
||||
color: #09f;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
6
packages/biz/src/infiniteList/components/index.tsx
Normal file
6
packages/biz/src/infiniteList/components/index.tsx
Normal file
@ -0,0 +1,6 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/04/28
|
||||
*/
|
||||
|
||||
export { default as SearchCard } from './SearchCard'
|
||||
export type { SearchCardProps, SearchCardRefProps } from './SearchCard'
|
50
packages/biz/src/infiniteList/demo/basic.tsx
Normal file
50
packages/biz/src/infiniteList/demo/basic.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { InfiniteList } from '@zhst/biz'
|
||||
|
||||
export default () => {
|
||||
const [data, setData] = useState([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const loadMoreData = () => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo')
|
||||
.then((res) => res.json())
|
||||
.then((body) => {
|
||||
let res = body.results.map(o => {
|
||||
return {
|
||||
title: o.name.first,
|
||||
subtitle: o.name.last,
|
||||
url: o.picture.large
|
||||
}
|
||||
})
|
||||
setData([...data, ...res]);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadMoreData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<InfiniteList
|
||||
loading={loading}
|
||||
loadMore={loadMoreData}
|
||||
height={300}
|
||||
hasMore={data.length < 100}
|
||||
data={data}
|
||||
onItemClick={_data => console.log('item点击:', _data)}
|
||||
searchCardProps={{
|
||||
onAdd: (_data) => console.log('新增', _data),
|
||||
onCreate: (_data) => console.log('创建', _data),
|
||||
onRemove: (_data) => console.log('删除', _data),
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
58
packages/biz/src/infiniteList/demo/custom.tsx
Normal file
58
packages/biz/src/infiniteList/demo/custom.tsx
Normal file
@ -0,0 +1,58 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { InfiniteList } from '@zhst/biz'
|
||||
import { Button, Input, Space } from 'antd'
|
||||
|
||||
export default () => {
|
||||
const [data, setData] = useState([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [params, setParams] = useState({})
|
||||
|
||||
const loadMoreData = (params?: { name: string; age?: number; sex: string; tel: number }) => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo')
|
||||
.then((res) => res.json())
|
||||
.then((body) => {
|
||||
let res = body.results.map(o => {
|
||||
return {
|
||||
title: o.name.first,
|
||||
subtitle: o.name.last,
|
||||
url: o.picture.large
|
||||
}
|
||||
})
|
||||
setData([...data, ...res]);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadMoreData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Space direction='vertical'>
|
||||
<Space>
|
||||
<Input placeholder='名称' onChange={(e) => setParams(pre => ({ ...pre, name: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='年龄' onChange={(e) => setParams(pre => ({ ...pre, age: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='性别' onChange={(e) => setParams(pre => ({ ...pre, sex: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='手机号' onChange={(e) => setParams(pre => ({ ...pre, tel: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Button onClick={() => loadMoreData(params)}>加载更多</Button>
|
||||
</Space>
|
||||
<InfiniteList
|
||||
loading={loading}
|
||||
loadMore={() => loadMoreData(params)}
|
||||
height={300}
|
||||
hasMore={data.length < 100}
|
||||
data={data}
|
||||
type="custom"
|
||||
loadingMessage={<Button onClick={() => loadMoreData(params)}>加载更多</Button>}
|
||||
onItemClick={data => console.log('item点击:', data)}
|
||||
/>
|
||||
</Space>
|
||||
)
|
||||
}
|
72
packages/biz/src/infiniteList/demo/customItem.tsx
Normal file
72
packages/biz/src/infiniteList/demo/customItem.tsx
Normal file
@ -0,0 +1,72 @@
|
||||
import React, { useEffect, useState } from 'react'
|
||||
import { InfiniteList } from '@zhst/biz'
|
||||
import { Button, Input, Space } from 'antd'
|
||||
|
||||
interface IData { name: string; age?: number; sex: string; tel: number }
|
||||
|
||||
export default () => {
|
||||
const [data, setData] = useState<any>([])
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [params, setParams] = useState<IData>({
|
||||
name: '',
|
||||
tel: 123,
|
||||
age: 12,
|
||||
sex: '男'
|
||||
})
|
||||
|
||||
const loadMoreData = (params?: IData) => {
|
||||
if (loading) {
|
||||
return;
|
||||
}
|
||||
setLoading(true);
|
||||
fetch('https://randomuser.me/api/?results=10&inc=id,key,name,gender,email,nat,picture&noinfo', {
|
||||
})
|
||||
.then((res) => res.json())
|
||||
.then((body) => {
|
||||
setData([...data, ...body.results]);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => {
|
||||
setLoading(false);
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadMoreData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<Space direction='vertical'>
|
||||
<Space>
|
||||
<Input placeholder='名称' onChange={(e) => setParams(pre => ({ ...pre, name: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='年龄' onChange={(e) => setParams(pre => ({ ...pre, age: Number(e.target.value) }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='性别' onChange={(e) => setParams(pre => ({ ...pre, sex: e.target.value }))} style={{ width: '120px' }} />
|
||||
<Input placeholder='手机号' onChange={(e) => setParams(pre => ({ ...pre, tel: Number(e.target.value) }))} style={{ width: '120px' }} />
|
||||
<Button onClick={() => loadMoreData(params)}>加载更多</Button>
|
||||
</Space>
|
||||
<InfiniteList
|
||||
loading={loading}
|
||||
loadMore={() => loadMoreData(params)}
|
||||
height={300}
|
||||
hasMore={data.length < 100}
|
||||
data={data}
|
||||
type="custom"
|
||||
loadingMessage={<Button onClick={() => loadMoreData(params)}>加载更多</Button>}
|
||||
itemRender={() => {
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: '200px',
|
||||
height: '100px',
|
||||
border: '1px solid #000',
|
||||
boxSizing: 'border-box'
|
||||
}}>
|
||||
自定义的子元素
|
||||
</div>
|
||||
)
|
||||
}}
|
||||
onItemClick={data => console.log('item点击:', data)}
|
||||
/>
|
||||
</Space>
|
||||
)
|
||||
}
|
17
packages/biz/src/infiniteList/demo/mock.ts
Normal file
17
packages/biz/src/infiniteList/demo/mock.ts
Normal file
@ -0,0 +1,17 @@
|
||||
const resultData = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13'];
|
||||
|
||||
export function getLoadMoreList(nextId: string | undefined, limit: number): Promise<any> {
|
||||
let start = 0;
|
||||
const end = start + limit;
|
||||
const list = resultData.slice(start, end);
|
||||
const nId = resultData.length >= end ? resultData[end] : undefined;
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve({
|
||||
list,
|
||||
nextId: nId,
|
||||
isNoMore: list.length > 20
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
}
|
5
packages/biz/src/infiniteList/index.less
Normal file
5
packages/biz/src/infiniteList/index.less
Normal file
@ -0,0 +1,5 @@
|
||||
.zhst-biz-infinite-list {
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
38
packages/biz/src/infiniteList/index.md
Normal file
38
packages/biz/src/infiniteList/index.md
Normal file
@ -0,0 +1,38 @@
|
||||
---
|
||||
category: Components
|
||||
title: infiniteList 无限滚动列表
|
||||
toc: content
|
||||
group:
|
||||
title: 数据展示
|
||||
---
|
||||
|
||||
无限滚动列表
|
||||
|
||||
## 代码演示
|
||||
|
||||
<code src="./demo/basic.tsx">基本用法</code>
|
||||
<code src="./demo/custom.tsx">手动触发</code>
|
||||
<code src="./demo/customItem.tsx">自定义子元素</code>
|
||||
|
||||
## API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| data | 数据源 | Idata[] | [] | - |
|
||||
| loading | 数据源 | Array[] | [] | - |
|
||||
| data | 数据源 | Array[] | [] | - |
|
||||
| data | 数据源 | Array[] | [] | - |
|
||||
| data | 数据源 | Array[] | [] | - |
|
||||
| data | 数据源 | Array[] | [] | - |
|
||||
| data | 数据源 | Array[] | [] | - |
|
||||
|
||||
## Idata
|
||||
|
||||
```js
|
||||
interface Idata {
|
||||
id?: string | number;
|
||||
url?: string; // 链接
|
||||
title?: string; // 标题
|
||||
subtitle?: string; // 副标题
|
||||
}
|
||||
```
|
5
packages/biz/src/infiniteList/index.tsx
Normal file
5
packages/biz/src/infiniteList/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import InfinityList from './InfiniteList'
|
||||
|
||||
export type { InfiniteListProps, InfiniteListRefProps } from './InfiniteList'
|
||||
|
||||
export default InfinityList
|
@ -2,6 +2,8 @@ import React, { forwardRef, useContext, useImperativeHandle, useRef } from 'reac
|
||||
import { Button, Modal, ModalProps, Select, SelectProps, Space, theme } from 'antd';
|
||||
import { ConfigProvider, CropperImage, Scanner, CropperImageProps, CropperImageRefProps } from '@zhst/meta'
|
||||
import { IconFont } from '@zhst/icon'
|
||||
import classNames from 'classnames';
|
||||
import './index.less'
|
||||
|
||||
export interface ODModalProps extends ModalProps {
|
||||
prefixCls?: string;
|
||||
@ -95,7 +97,7 @@ const ODModal = forwardRef<ODModalRefProps, ODModalProps>((props, ref) => {
|
||||
onCancel={onCancel}
|
||||
onOk={onOk}
|
||||
{...modalProps}
|
||||
className={componentName}
|
||||
rootClassName={componentName}
|
||||
>
|
||||
<Space size={12} direction='vertical' align='center' style={{ textAlign: 'center' }}>
|
||||
<Scanner style={{ width: odWidth, height: odHeight }} visible={scanning}>
|
||||
@ -118,7 +120,7 @@ const ODModal = forwardRef<ODModalRefProps, ODModalProps>((props, ref) => {
|
||||
<div>
|
||||
选中类型:
|
||||
<Select
|
||||
style={{ width: '90px' }}
|
||||
className={classNames(componentName + '-type')}
|
||||
defaultValue={selectDefaultValue}
|
||||
value={selectedType}
|
||||
options={selectOptions}
|
||||
@ -129,7 +131,7 @@ const ODModal = forwardRef<ODModalRefProps, ODModalProps>((props, ref) => {
|
||||
<Button disabled={handSelectDisable} size='small' type="link" onClick={onHandSelect}><IconFont icon="icon-shoudongkuangxuan" /> 手动框选</Button>
|
||||
<Button disabled={autoSelectDisable} size='small' type="link" onClick={onAutoSelect}><IconFont icon="icon-zidong" /> 自动框选</Button>
|
||||
<Button disabled={resetDisable} size='small' type="link" onClick={onReset}><IconFont icon="icon-zhongzhi3" /> 重置</Button>
|
||||
{showRotateButton && <IconFont onIconClick={onRotate} styles={{ marginLeft: '6px' }} color={token.colorPrimary} icon="icon-xuanzhuan1" />}
|
||||
{showRotateButton && <IconFont className={classNames(componentName + '-rotate')} onIconClick={onRotate} color={token.colorPrimary} icon="icon-xuanzhuan1" />}
|
||||
</Space>
|
||||
)}
|
||||
</Space>
|
||||
|
@ -69,11 +69,8 @@ const demo = () => {
|
||||
autoSelectDisable={paintType === 'auto'}
|
||||
onCropEnd={_cropData => console.log('结束绘制:', _cropData)}
|
||||
onReset={() => console.log('重置')}
|
||||
onRotate={() => console.log('旋转', odModalRef.current.rotateTo(90))}
|
||||
onRotate={() => console.log('旋转', odModalRef.current?.rotateTo?.(90))}
|
||||
onTypeSelect={(val) => {
|
||||
if (val === 1) {
|
||||
|
||||
}
|
||||
setSelectedType(val)
|
||||
}}
|
||||
/>
|
||||
|
9
packages/biz/src/odModal/index.less
Normal file
9
packages/biz/src/odModal/index.less
Normal file
@ -0,0 +1,9 @@
|
||||
.zhst-od-modal {
|
||||
&-type {
|
||||
width: 90px;
|
||||
}
|
||||
|
||||
&-rotate {
|
||||
margin-left: 6px;
|
||||
}
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
import React, { FC, useState } from 'react';
|
||||
import { Tree, Badge, TreeDataNode, Space, TreeProps } from 'antd';
|
||||
import theme from 'antd/es/theme'
|
||||
import { Tree, Badge, TreeDataNode, Space, TreeProps, theme } from 'antd';
|
||||
import { CloseOutlined, EditOutlined, SettingOutlined } from '@ant-design/icons'
|
||||
import { ModalForm, ProFormText } from '@ant-design/pro-components';
|
||||
import './index.less'
|
||||
|
@ -1,10 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { Button, Card, Flex, Input, InputProps, Tree } from 'antd';
|
||||
import theme from 'antd/es/theme'
|
||||
import { TransferProps, TreeDataNode, TreeProps } from 'antd';
|
||||
import { Button, Card, ConfigProvider, theme, Flex, Input, InputProps, TransferProps, TreeDataNode, TreeProps, Tree } from 'antd';
|
||||
import './index.less'
|
||||
import { DeleteOutlined, DoubleRightOutlined, SearchOutlined } from '@ant-design/icons';
|
||||
import { getAllRootKeyById } from './treeTransferHelper';
|
||||
|
||||
const componentName = 'zhst-biz-treeTransfer'
|
||||
|
||||
@ -16,7 +13,7 @@ export interface TreeTransferProps {
|
||||
checkedKeys: string[];
|
||||
onTreeSelect?: TreeProps['onSelect']
|
||||
onTreeCheck?: TreeProps['onCheck']
|
||||
onItemDelete?: (key: string, info?: { root: TreeDataNode[], keys: string[] }) => void
|
||||
onItemDelete?: (key: string, info?: TreeDataNode) => void
|
||||
onChange?: TransferProps['onChange'];
|
||||
onOk?: (data: any) => void;
|
||||
onReset?: () => void;
|
||||
@ -56,20 +53,29 @@ const TreeTransfer: React.FC<TreeTransferProps> = ({
|
||||
<Card
|
||||
className={`${componentName}-left_card`}
|
||||
title={<div style={{ textAlign: 'center' }} >可选择的范围</div>}
|
||||
bodyStyle={{ padding: 12 }}
|
||||
>
|
||||
<Input prefix={<SearchOutlined />} onChange={e => setKeyWords(e.target.value)} placeholder='请输入设备名称' {...searchInputProps} />
|
||||
<Tree
|
||||
style={{ marginTop: '6px' }}
|
||||
height={420}
|
||||
blockNode
|
||||
checkable
|
||||
checkedKeys={checkedKeys}
|
||||
treeData={findNodesWithKeyword(keyWords, dataSource)}
|
||||
onCheck={(keys, info) => onTreeCheck?.(keys, info)}
|
||||
onSelect={(keys, info) => onTreeSelect?.(keys, info)}
|
||||
{...treeProps}
|
||||
/>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Tree: {
|
||||
colorBgContainer: '#FCFCFC'
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Tree
|
||||
className={`${componentName}-left_card-tree`}
|
||||
height={420}
|
||||
blockNode
|
||||
checkable
|
||||
checkedKeys={checkedKeys}
|
||||
treeData={findNodesWithKeyword(keyWords, dataSource)}
|
||||
onCheck={(keys, info) => onTreeCheck?.(keys, info)}
|
||||
onSelect={(keys, info) => onTreeSelect?.(keys, info)}
|
||||
{...treeProps}
|
||||
/>
|
||||
</ConfigProvider>
|
||||
</Card>
|
||||
</div>
|
||||
<DoubleRightOutlined/>
|
||||
@ -77,8 +83,6 @@ const TreeTransfer: React.FC<TreeTransferProps> = ({
|
||||
<Card
|
||||
className={`${componentName}-right_card`}
|
||||
title={<div style={{ textAlign: 'center' }}>已选择的范围</div>}
|
||||
bodyStyle={{ padding: 0 }}
|
||||
|
||||
>
|
||||
<div
|
||||
className={`${componentName}-right_card__items`}
|
||||
@ -99,8 +103,8 @@ const TreeTransfer: React.FC<TreeTransferProps> = ({
|
||||
{item.title as any}
|
||||
<div style={{ float: 'right' }}>
|
||||
<DeleteOutlined onClick={() => {
|
||||
const { root, keys } = getAllRootKeyById(item.key as string, dataSource)
|
||||
onItemDelete?.(item.key as string, { root, keys })
|
||||
// const { root, keys } = getAllRootKeyById(item.key as string, dataSource)
|
||||
onItemDelete?.(item.key as string, item)
|
||||
}} />
|
||||
</div>
|
||||
</div>
|
||||
|
@ -22,9 +22,9 @@ const App: React.FC = () => {
|
||||
* @param key
|
||||
* @param param1
|
||||
*/
|
||||
const onItemDelete = (key: any, { keys }: any) => {
|
||||
const onItemDelete = (key: any, { keys = [] }: any) => {
|
||||
setCheckedKeys(pre => {
|
||||
const newKeys = pre.filter(_key => !keys.includes(_key))
|
||||
const newKeys = pre.filter(_key => _key !== key)
|
||||
console.log('newKeys', newKeys, keys)
|
||||
return newKeys
|
||||
})
|
||||
|
@ -25,11 +25,48 @@ export const boxDataSource: TreeDataNode[] = [
|
||||
{ key: '0-1-3-3', title: '分组0-1-3-3', isLeaf: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: '0-1-4',
|
||||
title: '分组0-1-4',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '0-1-4-1', title: '分组0-1-3-1', isLeaf: true },
|
||||
{ key: '0-1-4-2', title: '分组0-1-3-2', isLeaf: true },
|
||||
{ key: '0-1-4-3', title: '分组0-1-3-3', isLeaf: true },
|
||||
],
|
||||
},
|
||||
{
|
||||
key: '0-1-5',
|
||||
title: '分组0-1-5',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '0-1-5-1', title: '分组0-1-3-1', isLeaf: true },
|
||||
{ key: '0-1-5-2', title: '分组0-1-3-2', isLeaf: true },
|
||||
{ key: '0-1-5-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-4',
|
||||
title: '分组0-4',
|
||||
isLeaf: false,
|
||||
checkable: false,
|
||||
children: [
|
||||
{
|
||||
key: '0-4-5',
|
||||
title: '分组0-4-5',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '0-4-5-1', title: '分组0-1-3-1', isLeaf: true },
|
||||
{ key: '0-4-5-2', title: '分组0-1-3-2', isLeaf: true },
|
||||
{ key: '0-4-5-3', title: '分组0-1-3-3', isLeaf: true },
|
||||
],
|
||||
},
|
||||
]
|
||||
},
|
||||
{ key: '0-5', title: '分组0-4', isLeaf: false, checkable: false, },
|
||||
{ key: '0-6', title: '分组0-4', isLeaf: false, checkable: false, },
|
||||
];
|
||||
|
@ -2,15 +2,19 @@
|
||||
&-left {
|
||||
&_card {
|
||||
width: 500px;
|
||||
height: 522px;
|
||||
min-height: 544px;
|
||||
background-color: #FCFCFC;
|
||||
|
||||
&-tree {
|
||||
margin-top: 6px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-right {
|
||||
&_card {
|
||||
width: 300px;
|
||||
height: 522px;
|
||||
min-height: 544px;
|
||||
background-color: #FCFCFC;
|
||||
|
||||
&__items {
|
||||
@ -18,6 +22,7 @@
|
||||
width: 100%;
|
||||
height: calc(100% - 105px);
|
||||
overflow-y: scroll;
|
||||
max-height: 422px;
|
||||
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
@ -27,6 +32,7 @@
|
||||
margin: 0;
|
||||
padding: 4px 12px;
|
||||
cursor: pointer;
|
||||
transition: 0.3s ease-out all;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { FC, useState } from 'react';
|
||||
import { Modal, ModalProps, Radio, RadioGroupProps, Select, SelectProps, TransferProps, TreeDataNode, TreeProps } from 'antd';
|
||||
import TreeTransfer from '../treeTransfer';
|
||||
import { TreeTransferProps } from '../treeTransfer'
|
||||
|
||||
export interface TreeTransferModalProps {
|
||||
dataSource: TreeDataNode[]
|
||||
@ -9,7 +10,7 @@ export interface TreeTransferModalProps {
|
||||
checkedKeys: string[];
|
||||
onTreeSelect?: TreeProps['onSelect']
|
||||
onTreeCheck?: TreeProps['onCheck']
|
||||
onItemDelete?: (key: string, info?: { root: TreeDataNode[], keys: string[] }) => void
|
||||
onItemDelete?: TreeTransferProps['onItemDelete']
|
||||
onChange?: TransferProps['onChange'];
|
||||
onOk?: (data: any) => void;
|
||||
onReset?: () => void;
|
||||
|
@ -2,11 +2,12 @@ import React, { useState } from 'react';
|
||||
import { TreeTransferModal } from '@zhst/biz';
|
||||
import { Button, TreeDataNode } from 'antd';
|
||||
import { TreeProps } from 'antd/lib';
|
||||
import { boxDataSource } from './mock'
|
||||
import { boxDataSource, boxGroupDataSource } from './mock'
|
||||
|
||||
const App: React.FC = () => {
|
||||
const [targetItems, setTargetItems] = useState<TreeDataNode[]>([]);
|
||||
const [checkedKeys, setCheckedKeys] = useState<string[]>([]);
|
||||
const [type, setType] = useState<string>('1');
|
||||
const [open, setOpen] = useState(true)
|
||||
|
||||
const onTreeCheck: TreeProps['onCheck'] = (keys: any, info) => {
|
||||
@ -47,14 +48,17 @@ const App: React.FC = () => {
|
||||
<TreeTransferModal
|
||||
open={open}
|
||||
onCancel={() => setOpen(false)}
|
||||
onRadioChange={(e) => console.log('radioChange', e)} // 顶部 radio 事件
|
||||
dataSource={boxDataSource} // 数据源
|
||||
onRadioChange={(e) => setType(e.target.value)} // 顶部 radio 事件
|
||||
dataSource={type === '1' ? boxDataSource : boxGroupDataSource} // 数据源
|
||||
targetItems={targetItems} // 右侧选中项
|
||||
checkedKeys={checkedKeys} // 左侧选中
|
||||
onReset={onReset} // 重置按钮事件
|
||||
onOk={onOk} // 确定按钮事件
|
||||
onTreeCheck={onTreeCheck} // 树check选中事件
|
||||
onItemDelete={onItemDelete} // 右侧点击删除事件
|
||||
radioProps={{
|
||||
value: type
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
@ -3,33 +3,74 @@ import { TreeDataNode } from "antd";
|
||||
export const boxDataSource: TreeDataNode[] = [
|
||||
{
|
||||
key: '0-0',
|
||||
title: '分组0-0',
|
||||
title: '全部盒子',
|
||||
value: 0,
|
||||
isLeaf: false,
|
||||
checkable: false,
|
||||
children: [
|
||||
{
|
||||
key: '0-1',
|
||||
title: '盒子组-1',
|
||||
value: 1,
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '0-1-0', value: '10', title: '盒子1-0', isLeaf: true, },
|
||||
{ key: '0-1-1', value: '11', title: '盒子1-1', isLeaf: true, },
|
||||
{ key: '0-1-2', value: '12', title: '盒子1-2', isLeaf: true, },
|
||||
],
|
||||
},
|
||||
{ key: '0-2', value: '2', title: '盒子组-2', isLeaf: false, checkable: false, },
|
||||
{ key: '0-3', value: '3', title: '盒子组-3', isLeaf: false, checkable: false, },
|
||||
{
|
||||
key: '0-4',
|
||||
title: '盒子组-4',
|
||||
value: '4',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '0-4-10', value: '10', title: '盒子1-0', isLeaf: true, },
|
||||
{ key: '0-4-11', value: '11', title: '盒子1-1', isLeaf: true, },
|
||||
{ key: '0-4-12', value: '12', title: '盒子1-2', isLeaf: true, },
|
||||
],
|
||||
},
|
||||
{ key: '0-5', value: '5', title: '盒子组-4', isLeaf: false, checkable: false, },
|
||||
{ key: '0-6', value: '6', title: '盒子组-4', isLeaf: false, checkable: false, },
|
||||
]
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
|
||||
export const boxGroupDataSource: TreeDataNode[] = [
|
||||
{
|
||||
key: '0',
|
||||
title: '盒子组-0',
|
||||
value: '0',
|
||||
isLeaf: false,
|
||||
checkable: false,
|
||||
},
|
||||
{
|
||||
key: '0-1',
|
||||
title: '分组0-1',
|
||||
key: '1',
|
||||
value: '1',
|
||||
title: '盒子组-1',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ 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-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-1-10', value: '10', title: '盒子1-0', isLeaf: true, },
|
||||
{ key: '0-1-11', value: '11', title: '盒子1-1', isLeaf: true, },
|
||||
{ key: '0-1-12', value: '12', title: '盒子1-2', 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, },
|
||||
{ key: '2', value: '2', title: '盒子组-2', isLeaf: false, checkable: false, },
|
||||
{
|
||||
key: '3',
|
||||
title: '盒子组-3',
|
||||
value: '3',
|
||||
isLeaf: false,
|
||||
children: [
|
||||
{ key: '3-10', value: '10', title: '盒子1-0', isLeaf: true, },
|
||||
{ key: '3-11', value: '11', title: '盒子1-1', isLeaf: true, },
|
||||
{ key: '3-12', value: '12', title: '盒子1-2', isLeaf: true, },
|
||||
],
|
||||
},
|
||||
{ key: '4', value: '4', title: '盒子组-4', isLeaf: false, checkable: false, },
|
||||
{ key: '5', value: '4', title: '盒子组-5', isLeaf: false, checkable: false, },
|
||||
];
|
||||
|
@ -2,7 +2,12 @@ import { defineConfig } from 'father';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: { output: 'es' },
|
||||
cjs: { output: 'lib' },
|
||||
// umd: { output: 'dist' }
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
});
|
||||
|
@ -1,5 +1,94 @@
|
||||
# @zhst/utils
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.15.0
|
||||
|
||||
## 0.14.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/func: 修改 pxToRem 算法
|
||||
- @zhst/request@0.14.1
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 重新发版
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.14.0
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.13.0
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: zhst/func 添加 pxToRem 方法
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/request@0.12.4
|
||||
|
||||
## 0.11.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.12.3
|
||||
|
||||
## 0.11.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.12.2
|
||||
|
||||
## 0.11.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.12.1
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/biz:新增摘要列表-无限滚动组件
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.12.0
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/request@0.11.0
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,43 +0,0 @@
|
||||
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
|
||||
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
||||
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
||||
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
|
||||
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
||||
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/03/20
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import { getValueByUrl } from '@zhst/func';
|
||||
import { Input, Button, Space } from 'antd';
|
||||
var demo = function demo() {
|
||||
var _useState = useState(null),
|
||||
_useState2 = _slicedToArray(_useState, 2),
|
||||
url = _useState2[0],
|
||||
setUrl = _useState2[1];
|
||||
var _useState3 = useState(null),
|
||||
_useState4 = _slicedToArray(_useState3, 2),
|
||||
keyword = _useState4[0],
|
||||
setKeyword = _useState4[1];
|
||||
var _useState5 = useState(null),
|
||||
_useState6 = _slicedToArray(_useState5, 2),
|
||||
outputVal = _useState6[0],
|
||||
setOutPutVal = _useState6[1];
|
||||
var handleClick = function handleClick() {
|
||||
var val = getValueByUrl(keyword, url);
|
||||
setOutPutVal(val);
|
||||
};
|
||||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Space, null, "\u94FE\u63A5\uFF1A", /*#__PURE__*/React.createElement(Input, {
|
||||
onChange: function onChange(e) {
|
||||
return setUrl(e.target.value);
|
||||
}
|
||||
}), "\u83B7\u53D6\u5B57\u6BB5\uFF1A", /*#__PURE__*/React.createElement(Input, {
|
||||
onChange: function onChange(e) {
|
||||
return setKeyword(e.target.value);
|
||||
}
|
||||
}), /*#__PURE__*/React.createElement(Button, {
|
||||
onClick: handleClick
|
||||
}, "\u63D0\u4EA4")), /*#__PURE__*/React.createElement("p", null, "\u8F93\u51FA\uFF1A", outputVal));
|
||||
};
|
||||
export default demo;
|
@ -71,4 +71,19 @@ export var getValueByUrl = function getValueByUrl(key, str) {
|
||||
result = new URLSearchParams(str.indexOf('?') > -1 ? str : "?".concat(str)).get(key);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* 行内px 转 rem
|
||||
* @param value px像素
|
||||
* @param rootFontSize 根元素大小: 默认16px
|
||||
*/
|
||||
export var pxToRem = function pxToRem(value, rootFontSize) {
|
||||
var fontSize = rootFontSize || 80 || parseFloat(document.documentElement.style.fontSize);
|
||||
var valueArr = value.split(' ');
|
||||
return valueArr.filter(function (o) {
|
||||
return o;
|
||||
}).map(function (val) {
|
||||
return parseFloat(val) / fontSize + 'rem';
|
||||
}).join(' ');
|
||||
};
|
@ -1,48 +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/string/demo/getValueByUrl.tsx
|
||||
var getValueByUrl_exports = {};
|
||||
__export(getValueByUrl_exports, {
|
||||
default: () => getValueByUrl_default
|
||||
});
|
||||
module.exports = __toCommonJS(getValueByUrl_exports);
|
||||
var import_react = __toESM(require("react"));
|
||||
var import_func = require("@zhst/func");
|
||||
var import_antd = require("antd");
|
||||
var demo = () => {
|
||||
const [url, setUrl] = (0, import_react.useState)(null);
|
||||
const [keyword, setKeyword] = (0, import_react.useState)(null);
|
||||
const [outputVal, setOutPutVal] = (0, import_react.useState)(null);
|
||||
const handleClick = () => {
|
||||
let val = (0, import_func.getValueByUrl)(keyword, url);
|
||||
setOutPutVal(val);
|
||||
};
|
||||
return /* @__PURE__ */ import_react.default.createElement("div", null, /* @__PURE__ */ import_react.default.createElement(import_antd.Space, null, "链接:", /* @__PURE__ */ import_react.default.createElement(import_antd.Input, { onChange: (e) => setUrl(e.target.value) }), "获取字段:", /* @__PURE__ */ import_react.default.createElement(import_antd.Input, { onChange: (e) => setKeyword(e.target.value) }), /* @__PURE__ */ import_react.default.createElement(import_antd.Button, { onClick: handleClick }, "提交")), /* @__PURE__ */ import_react.default.createElement("p", null, "输出:", outputVal));
|
||||
};
|
||||
var getValueByUrl_default = demo;
|
@ -22,7 +22,8 @@ __export(string_exports, {
|
||||
cutStr: () => cutStr,
|
||||
getStrLength: () => getStrLength,
|
||||
getValueByUrl: () => getValueByUrl,
|
||||
isUrl: () => isUrl
|
||||
isUrl: () => isUrl,
|
||||
pxToRem: () => pxToRem
|
||||
});
|
||||
module.exports = __toCommonJS(string_exports);
|
||||
var getStrLength = function(str) {
|
||||
@ -74,10 +75,16 @@ var getValueByUrl = (key, str) => {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
var pxToRem = (value, rootFontSize) => {
|
||||
const fontSize = rootFontSize || 80;
|
||||
const valueArr = value.split(" ");
|
||||
return valueArr.filter((o) => o).map((val) => parseFloat(val) / fontSize + "rem").join(" ");
|
||||
};
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
cutStr,
|
||||
getStrLength,
|
||||
getValueByUrl,
|
||||
isUrl
|
||||
isUrl,
|
||||
pxToRem
|
||||
});
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/func",
|
||||
"version": "0.10.1",
|
||||
"version": "0.15.0",
|
||||
"description": "函数合集",
|
||||
"keywords": [
|
||||
"hooks"
|
||||
|
25
packages/func/src/string/demo/pxTorem.tsx
Normal file
25
packages/func/src/string/demo/pxTorem.tsx
Normal file
@ -0,0 +1,25 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/03/20
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react'
|
||||
import { pxToRem } from '@zhst/func'
|
||||
import { Input } from 'antd'
|
||||
|
||||
const demo = () => {
|
||||
const [outputVal, setOutPutVal ] = useState<any>(null)
|
||||
|
||||
const handleChange = (e: { target: { value: string } }) => {
|
||||
const value = pxToRem(e.target.value)
|
||||
setOutPutVal(value)
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Input onChange={handleChange} />
|
||||
<p>输出:{outputVal}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default demo
|
131
packages/func/src/string/demo/scale.temp.ts
Normal file
131
packages/func/src/string/demo/scale.temp.ts
Normal file
@ -0,0 +1,131 @@
|
||||
// @ts-nocheck
|
||||
// !! 参考代码,不投入使用
|
||||
/**
|
||||
* 适应屏幕
|
||||
*/
|
||||
const screenAdapt = () => {
|
||||
window.global = window;
|
||||
(function () {
|
||||
if ($(window).width() >= 1920) {
|
||||
$(window).width() && $('body').css('width', $(window).width());
|
||||
$(window).height() && $('body').css('height', $(window).height());
|
||||
} else {
|
||||
$(window).width() && $('body').css('width', "1920px");
|
||||
|
||||
var ratio = $(window).width() / (1920 || $('body').width());
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100%",
|
||||
height: "1080px"
|
||||
});
|
||||
}
|
||||
$('head').append('<meta name="viewport" content=""/>');
|
||||
|
||||
|
||||
//监听页面是否发生改变
|
||||
$(window, document).resize(function () {
|
||||
resize();
|
||||
})
|
||||
|
||||
|
||||
function resize () {
|
||||
if (window.screen.display == 2) { // 等比缩放高度铺满
|
||||
resizeCenter();
|
||||
} else if (window.screen.display == 3) { //全屏铺满
|
||||
resizeFull();
|
||||
} else if (window.screen.display == 4) { //等比缩放高度铺满并且可以左右移动
|
||||
resizeHeight();
|
||||
} else { // 等比缩放宽度铺满
|
||||
resizeWidth();
|
||||
}
|
||||
|
||||
}
|
||||
function resizeWidth () {
|
||||
window.location.reload()
|
||||
if ($(window).width() >= 1920) {
|
||||
var ratio = $(window).width() / ($(window).width() || $('body').width());
|
||||
$(window).height() && $('body').css('height', $(window).height());
|
||||
} else {
|
||||
$('body').css('height', "1080px");
|
||||
}
|
||||
var ratio = $(window).width() / (1920 || $('body').width());
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100%"
|
||||
});
|
||||
}
|
||||
function resizeCenter () {
|
||||
if (!window.screen.height || !window.screen.width) return resizeCenterBak();
|
||||
var ratio = $(window).height() / window.screen.height;
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: 100 * (window.screen.width / $(window).width() * ratio) + "%" + ' 100%',
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
marginLeft: ($(window).width() - $('body').width() * ratio) / 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resizeHeight () { //
|
||||
if (!window.screen.height || !window.screen.width) return resizeCenterBak();
|
||||
var ratio = $(window).height() / window.screen.height;
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: 100 * (window.screen.width / $(window).width() * ratio) + "%" + ' 100%',
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
// marginLeft: ($(window).width() - $('body').width() * ratio) / 2
|
||||
});
|
||||
$('html').css({
|
||||
overflowX: 'scroll',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function resizeFull () {
|
||||
if (!window.screen.height || !window.screen.width) return resizeFullBak();
|
||||
var ratioX = $(window).width() / window.screen.width;
|
||||
var ratioY = $(window).height() / window.screen.height;
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratioX + ", " + ratioY + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100% 100%",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resizeCenterBak () {
|
||||
var ratioX = $(window).width() / $('body').width();
|
||||
var ratioY = $(window).height() / $('body').height();
|
||||
var ratio = Math.min(ratioX, ratioY);
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: (1 / ratioX) * 100 * ratio + "%",
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
marginLeft: ($(window).width() - $('body').width() * ratio) / 2
|
||||
});
|
||||
}
|
||||
function resizeFullBak () {
|
||||
var ratioX = $(window).width() / $('body').width();
|
||||
var ratioY = $(window).height() / $('body').height();
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratioX + ", " + ratioY + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100% " + ratioY * 100 + "%",
|
||||
});
|
||||
}
|
||||
})();
|
||||
}
|
@ -21,3 +21,4 @@ const value3 = getValueByUrl('a', 'a=123&token=asdfasdfsdf')
|
||||
```
|
||||
|
||||
<code src="./demo/getValueByUrl.tsx">调试台</code>
|
||||
<code src="./demo/pxTorem.tsx">px 转 rem</code>
|
||||
|
@ -78,3 +78,15 @@ export const getValueByUrl = (key: string, str: string) => {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* 行内px 转 rem
|
||||
* @param value px像素
|
||||
* @param rootFontSize 根元素大小: 默认16px
|
||||
*/
|
||||
export const pxToRem = (value: string, rootFontSize?: number) => {
|
||||
const fontSize = rootFontSize || 80 || parseFloat(document.documentElement.style.fontSize)
|
||||
const valueArr = value.split(' ')
|
||||
|
||||
return valueArr.filter(o => o).map(val => ((parseFloat(val) / fontSize) + 'rem')).join(' ')
|
||||
}
|
||||
|
151
packages/func/src/utils/autoSize.ts
Normal file
151
packages/func/src/utils/autoSize.ts
Normal file
@ -0,0 +1,151 @@
|
||||
// @ts-nocheck
|
||||
// !! 开发中
|
||||
// 手动添加mate标签
|
||||
const addMeta = (name: string, content: string) => {
|
||||
const meta = document.createElement('meta');
|
||||
meta.content = content;
|
||||
meta.name = name;
|
||||
document.getElementsByTagName('head')[0].appendChild(meta);
|
||||
};
|
||||
|
||||
|
||||
const autoResize = (opt: {
|
||||
el: HTMLDivElement
|
||||
targetWidth?: number
|
||||
targetHeight?: number
|
||||
}) => {
|
||||
const { targetHeight = 1080, targetWidth = 1920, el } = opt
|
||||
let targetRatio = targetWidth / targetHeight; // 宽高比率 (宽 / 高) - 默认:16 /9
|
||||
|
||||
// 当前设备(浏览器)的宽度
|
||||
let clientWidth =
|
||||
document.documentElement.clientWidth || document.body.clientWidth;
|
||||
let clientHeight =
|
||||
document.documentElement.clientHeight || document.body.clientHeight;
|
||||
// 当前宽高比例
|
||||
// let currentRatio = clientWidth / clientHeight;
|
||||
|
||||
if (clientWidth >= 1920) {
|
||||
el.style.width = `${clientWidth}px`
|
||||
el.style.height = `${clientHeight}px`
|
||||
} else {
|
||||
el.style.width = '1920px'
|
||||
|
||||
// let currentRatio =
|
||||
}
|
||||
|
||||
addMeta(
|
||||
'viewport',
|
||||
'width=' + clientWidth + ',initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no,viewport-fit=cover',
|
||||
);
|
||||
|
||||
|
||||
const resizeWidth = () => {
|
||||
if ($(window).width() >= 1920) {
|
||||
var ratio = $(window).width() / ($(window).width() || $('body').width());
|
||||
$(window).height() && $('body').css('height', $(window).height());
|
||||
} else {
|
||||
$('body').css('height', "1080px");
|
||||
}
|
||||
var ratio = $(window).width() / (1920 || $('body').width());
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100%"
|
||||
});
|
||||
}
|
||||
function resizeCenter () {
|
||||
if (!window.screen.height || !window.screen.width) return resizeCenterBak();
|
||||
var ratio = $(window).height() / window.screen.height;
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: 100 * (window.screen.width / $(window).width() * ratio) + "%" + ' 100%',
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
marginLeft: ($(window).width() - $('body').width() * ratio) / 2
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resizeHeight () { //
|
||||
if (!window.screen.height || !window.screen.width) return resizeCenterBak();
|
||||
var ratio = $(window).height() / window.screen.height;
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: 100 * (window.screen.width / $(window).width() * ratio) + "%" + ' 100%',
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
});
|
||||
$('html').css({
|
||||
overflowX: 'scroll',
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
function resizeFull () {
|
||||
if (!window.screen.height || !window.screen.width) return resizeFullBak();
|
||||
var ratioX = $(window).width() / window.screen.width;
|
||||
var ratioY = $(window).height() / window.screen.height;
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratioX + ", " + ratioY + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100% 100%",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function resizeCenterBak () {
|
||||
var ratioX = $(window).width() / $('body').width();
|
||||
var ratioY = $(window).height() / $('body').height();
|
||||
var ratio = Math.min(ratioX, ratioY);
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratio + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: (1 / ratioX) * 100 * ratio + "%",
|
||||
backgroundPosition: ($(window).width() - $('body').width() * ratio) / 2 + "px top",
|
||||
marginLeft: ($(window).width() - $('body').width() * ratio) / 2
|
||||
});
|
||||
}
|
||||
function resizeFullBak () {
|
||||
var ratioX = $(window).width() / $('body').width();
|
||||
var ratioY = $(window).height() / $('body').height();
|
||||
|
||||
|
||||
$('body').css({
|
||||
transform: "scale(" + ratioX + ", " + ratioY + ")",
|
||||
transformOrigin: "left top",
|
||||
backgroundSize: "100% " + ratioY * 100 + "%",
|
||||
});
|
||||
}
|
||||
|
||||
if (window.screen.display === 2) { // 等比缩放高度铺满
|
||||
resizeCenter();
|
||||
} else if (window.screen.display === 3) { //全屏铺满
|
||||
resizeFull();
|
||||
} else if (window.screen.display === 4) { //等比缩放高度铺满并且可以左右移动
|
||||
resizeHeight();
|
||||
} else { // 等比缩放宽度铺满
|
||||
resizeWidth();
|
||||
}
|
||||
|
||||
|
||||
// if (currentRatio > targetRatio) {
|
||||
// let scaleRatio = clientHeight / targetHeight; // 参照高度进行缩放(屏幕很宽的情况下)
|
||||
// const transform = `scale(${scaleRatio}) translateX(-50%) left: 50%`;
|
||||
// console.log('transform', transform)
|
||||
// // el.style.transform =
|
||||
// } else {
|
||||
// // 4.开始缩放网页
|
||||
// let scaleRatio = clientWidth / targetWidth; // 参照宽度进行缩放(默认情况下)
|
||||
// console.log('scaleRatio', scaleRatio)
|
||||
// el.style.transform = `scale(${scaleRatio})`;
|
||||
// }
|
||||
}
|
||||
|
||||
export default autoResize
|
@ -2,7 +2,12 @@ import { defineConfig } from 'father';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: { output: 'es' },
|
||||
cjs: { output: 'lib' },
|
||||
// umd: { output: 'dist' }
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
});
|
||||
|
@ -1,5 +1,87 @@
|
||||
# @zhst/hooks
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.15.0
|
||||
|
||||
## 0.12.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.14.1
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 重新发版
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.14.0
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.13.0
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.12.0
|
||||
|
||||
## 0.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.3
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.2
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.1
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/biz:新增摘要列表-无限滚动组件
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.11.0
|
||||
|
||||
## 0.9.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.10.2
|
||||
|
||||
## 0.9.1
|
||||
|
||||
### Patch Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/hooks",
|
||||
"version": "0.9.1",
|
||||
"version": "0.13.0",
|
||||
"description": "hooks合集",
|
||||
"keywords": [
|
||||
"hooks"
|
||||
|
@ -2,6 +2,12 @@ import { defineConfig } from 'father';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: { output: 'es' },
|
||||
cjs: { output: 'lib' },
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
},
|
||||
});
|
||||
|
@ -1,5 +1,23 @@
|
||||
# @zhst/icon
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 重新发版
|
||||
|
||||
## 0.3.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
## 0.2.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -1,8 +0,0 @@
|
||||
import React from 'react';
|
||||
import { IconFont } from '@zhst/icon';
|
||||
var demo = function demo() {
|
||||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(IconFont, {
|
||||
icon: "icon-daoru1"
|
||||
}));
|
||||
};
|
||||
export default demo;
|
@ -1,33 +0,0 @@
|
||||
import React from 'react';
|
||||
var iconJson = require("../font/iconfont.json");
|
||||
import { IconFont } from '@zhst/icon';
|
||||
import "./index.less";
|
||||
import { message } from '@zhst/meta';
|
||||
var demo = function demo() {
|
||||
var iconArr = iconJson['glyphs'];
|
||||
return /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement("ul", {
|
||||
className: 'demo-ul'
|
||||
}, iconArr.map(function (item) {
|
||||
var font_class = item.font_class,
|
||||
name = item.name;
|
||||
var fontName = "icon-".concat(font_class);
|
||||
return /*#__PURE__*/React.createElement("li", {
|
||||
className: 'demo-li'
|
||||
}, /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
marginBottom: 20
|
||||
},
|
||||
icon: fontName,
|
||||
size: 32,
|
||||
onIconClick: function onIconClick() {
|
||||
navigator.clipboard.writeText(fontName);
|
||||
message.success("\u590D\u5236".concat(fontName, "\u6210\u529F"));
|
||||
}
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
className: "demo-li-name"
|
||||
}, name), /*#__PURE__*/React.createElement("div", {
|
||||
className: "demo-li-name"
|
||||
}, fontName));
|
||||
})));
|
||||
};
|
||||
export default demo;
|
@ -1,20 +0,0 @@
|
||||
.demo {
|
||||
&-ul {
|
||||
list-style-type: none;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
&-li {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
height: 150px;
|
||||
width: 150px;
|
||||
|
||||
&-name {
|
||||
color: #666;
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/icon",
|
||||
"version": "0.2.0",
|
||||
"version": "0.5.0",
|
||||
"description": "图标库",
|
||||
"keywords": [
|
||||
"icon",
|
||||
|
@ -1,5 +1,253 @@
|
||||
# @zhst/material
|
||||
|
||||
## 0.17.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: 修改 zhst/meta
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.3
|
||||
- @zhst/biz@0.21.5
|
||||
|
||||
## 0.17.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz、zhst/meta、zhst/material: 修改 od、修改 boxSelectTree
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.2
|
||||
- @zhst/biz@0.21.4
|
||||
|
||||
## 0.17.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.21.3
|
||||
|
||||
## 0.17.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: 修改 cropperImage 渲染问题
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.1
|
||||
- @zhst/biz@0.21.2
|
||||
|
||||
## 0.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: cropperImage 透出矩形坐标
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.0
|
||||
- @zhst/biz@0.21.1
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.13.0
|
||||
- @zhst/func@0.15.0
|
||||
- @zhst/meta@0.19.0
|
||||
- @zhst/biz@0.21.0
|
||||
|
||||
## 0.15.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.14.1
|
||||
- @zhst/biz@0.20.1
|
||||
- @zhst/hooks@0.12.1
|
||||
- @zhst/meta@0.18.1
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.19.2
|
||||
|
||||
## 0.14.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.12.0
|
||||
- @zhst/func@0.14.0
|
||||
- @zhst/meta@0.18.0
|
||||
- @zhst/biz@0.20.0
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.11.0
|
||||
- @zhst/func@0.13.0
|
||||
- @zhst/meta@0.17.0
|
||||
- @zhst/biz@0.19.0
|
||||
|
||||
## 0.13.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.12.0
|
||||
- @zhst/biz@0.18.8
|
||||
- @zhst/hooks@0.10.4
|
||||
- @zhst/meta@0.16.4
|
||||
|
||||
## 0.13.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/material: 修改 theme 组件引用方式
|
||||
|
||||
## 0.13.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/material: 修改 antd 依赖版本
|
||||
|
||||
## 0.13.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/material: 修复引用 antd/theme 失败
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/material: 添加盒子列表加载更多
|
||||
|
||||
## 0.12.7
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.3
|
||||
- @zhst/biz@0.18.7
|
||||
- @zhst/hooks@0.10.3
|
||||
- @zhst/meta@0.16.3
|
||||
|
||||
## 0.12.6
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- biz 优化无限滚动组件、boxselectTree 组件;material 修改算法编辑模块
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.18.6
|
||||
|
||||
## 0.12.5
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.18.5
|
||||
|
||||
## 0.12.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.18.4
|
||||
|
||||
## 0.12.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.18.3
|
||||
|
||||
## 0.12.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/request 修改报错提示逻辑、zhst/material - 删除算法配置路数
|
||||
- @zhst/func@0.11.2
|
||||
- @zhst/biz@0.18.2
|
||||
- @zhst/hooks@0.10.2
|
||||
- @zhst/meta@0.16.2
|
||||
|
||||
## 0.12.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.1
|
||||
- @zhst/biz@0.18.1
|
||||
- @zhst/hooks@0.10.1
|
||||
- @zhst/meta@0.16.1
|
||||
|
||||
## 0.12.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/biz:新增摘要列表-无限滚动组件
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.10.0
|
||||
- @zhst/func@0.11.0
|
||||
- @zhst/meta@0.16.0
|
||||
- @zhst/biz@0.18.0
|
||||
|
||||
## 0.11.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 视频添加 OD 框,查看大图首次点击修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.15.0
|
||||
- @zhst/biz@0.17.0
|
||||
- @zhst/func@0.10.2
|
||||
- @zhst/hooks@0.9.2
|
||||
|
||||
## 0.10.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.16.1
|
||||
|
||||
## 0.10.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.14.0
|
||||
- @zhst/biz@0.16.0
|
||||
|
||||
## 0.10.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- material 修改找不到包的问题
|
||||
|
||||
## 0.10.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/biz@0.15.0
|
||||
|
||||
## 0.10.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@zhst/material",
|
||||
"version": "0.10.0",
|
||||
"version": "0.17.4",
|
||||
"description": "物料库",
|
||||
"keywords": [
|
||||
"business",
|
||||
@ -43,7 +43,7 @@
|
||||
"@zhst/meta": "workspace:^",
|
||||
"xterm": "^5.3.0",
|
||||
"xterm-addon-fit": "^0.8.0",
|
||||
"antd": "^5.14.2",
|
||||
"antd": "^5.12.5",
|
||||
"classnames": "^2.5.1",
|
||||
"rc-util": "^5.38.1"
|
||||
}
|
||||
|
@ -1,17 +1,19 @@
|
||||
import React, { forwardRef } from 'react';
|
||||
import { Flex, Image } from "antd";
|
||||
import React, { forwardRef, ReactNode, useContext, useImperativeHandle } from 'react';
|
||||
import { Button, Flex, Image } from "antd";
|
||||
import theme from 'antd/es/theme'
|
||||
import { CropperImage } from '@zhst/meta'
|
||||
import { CropperImage, ConfigProvider } from '@zhst/meta'
|
||||
import type { CropperImageProps } from '@zhst/meta'
|
||||
import { AlgorithmConfigImg, ErrorImage } from '../utils/base64Images'
|
||||
import AlgorithmTable from './components/algorithmTable'
|
||||
import TimeTemplateTable from './components/timeTemplateTable';
|
||||
import { AlgorithmTableProps } from './components/algorithmTable/AlgorithmTable';
|
||||
import { TimeTemplateTableProps } from './components/timeTemplateTable/TimeTemplateTable';
|
||||
import classNames from 'classnames';
|
||||
import './index.less'
|
||||
|
||||
const { useToken } = theme
|
||||
|
||||
const Title = (props: any) => <h2 style={{ margin: '18px 16px', fontSize: '14px', color: 'rgba(0, 0, 0, 0.88)' }} >{props.children}</h2>
|
||||
const Title = (props: any) => <h2 style={{ color: 'rgba(0, 0, 0, 0.88)' }} {...props}>{props.children}</h2>
|
||||
|
||||
export interface AlgorithmConfigProps {
|
||||
onAddAlgorithm?: () => void
|
||||
@ -49,42 +51,71 @@ export interface AlgorithmConfigProps {
|
||||
type: AlgorithmTableProps<any>['tableType']
|
||||
title?:string; // boxList列表的属性名称【点位列表、盒子列表】
|
||||
onSelect?: (key: string, info?: any) => void
|
||||
/**
|
||||
* 是否显示/隐藏加载更多按钮
|
||||
*/
|
||||
showLoadMoreButton?: boolean
|
||||
/**
|
||||
* 点击加载更多事件
|
||||
*/
|
||||
onLoadMoreButtonClick?: () => void;
|
||||
/**
|
||||
* 自定义加载更多按钮
|
||||
*/
|
||||
customLoadMoreButton: ReactNode
|
||||
/**
|
||||
* 自定义批量中间文案
|
||||
*/
|
||||
customBatchCenterContent: ReactNode
|
||||
prefixCls?: string;
|
||||
}
|
||||
|
||||
export interface AlgorithmConfigRef {
|
||||
}
|
||||
|
||||
const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((props) => {
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((props, ref) => {
|
||||
const {
|
||||
algorithmTableDataSource = [],
|
||||
timeTemplateDataSource = [],
|
||||
boxList = [],
|
||||
drawListener,
|
||||
cropperImageProps = {},
|
||||
algorithmTableProps,
|
||||
timeTemplateTableProps,
|
||||
selectedKey,
|
||||
boxList = [],
|
||||
type = 'multiple',
|
||||
rowKey = 'id',
|
||||
onSelect, title='盒子名称',
|
||||
showLoadMoreButton,
|
||||
onLoadMoreButtonClick,
|
||||
customBatchCenterContent,
|
||||
customLoadMoreButton,
|
||||
prefixCls: customizePrefixCls
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('material-algo', customizePrefixCls);
|
||||
|
||||
const { token } = useToken()
|
||||
// @ts-ignore
|
||||
const { type: cropType } = cropperImageProps
|
||||
|
||||
// useImperativeHandle(ref, () => ({
|
||||
// }))
|
||||
useImperativeHandle(ref, () => ({
|
||||
}))
|
||||
|
||||
return (
|
||||
<Flex style={{ border: `1px solid ${token.colorBorder}`, backgroundColor: token.colorBgBase }}>
|
||||
<div title={title} style={{ width: '13.9%' }}>
|
||||
<Title>{title}</Title>
|
||||
<div style={{ borderTop: `1px solid ${token.colorBorder}` }}>
|
||||
<Flex className={componentName} style={{ border: `1px solid ${token.colorBorder}`, backgroundColor: token.colorBgBase }}>
|
||||
<div className={classNames(`${componentName}-left`)} title={title} style={{ position: 'relative', width: '13.9%' }}>
|
||||
<Title className={classNames(`${componentName}-title`)}>{title}</Title>
|
||||
<div className={classNames(`${componentName}-left-list`)} style={{ borderTop: `1px solid ${token.colorBorder}` }}>
|
||||
{boxList.map(item => {
|
||||
return (
|
||||
<p
|
||||
key={item.id}
|
||||
onClick={() => onSelect?.(item.id, item)}
|
||||
// @ts-ignore
|
||||
key={item[rowKey]}
|
||||
// @ts-ignore
|
||||
onClick={() => onSelect?.(item[rowKey], item)}
|
||||
style={{
|
||||
margin: 0,
|
||||
padding: `${token.paddingXXS}px ${token.paddingLG}px`,
|
||||
@ -93,12 +124,27 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
||||
color: selectedKey === item[rowKey] ? token.colorPrimary : token.colorText,
|
||||
// @ts-ignore
|
||||
backgroundColor: selectedKey === item[rowKey] ? token.blue1 : token.colorBgBase,
|
||||
transition: '0cancelDraw.2s ease'
|
||||
transition: '.2s ease all',
|
||||
}}
|
||||
onMouseEnter={(e: any) => {
|
||||
e.target.style.backgroundColor = token.colorPrimaryBg
|
||||
e.target.style.color = token.colorPrimary
|
||||
}}
|
||||
onMouseLeave={(e: any) => {
|
||||
// @ts-ignore
|
||||
if (selectedKey === item[rowKey]) return
|
||||
e.target.style.color = token.colorText
|
||||
e.target.style.backgroundColor = null
|
||||
}}
|
||||
>{item.name}</p>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{showLoadMoreButton && (
|
||||
<div style={{ width: '100%', padding: '6px', position: 'absolute', left: '0', bottom: '0', boxSizing: 'border-box' }}>
|
||||
{customLoadMoreButton || <Button onClick={onLoadMoreButtonClick} block>加载更多</Button>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ boxSizing: 'border-box', width: '46.3%', textAlign: 'center', borderLeft: `1px solid ${token.colorBorder}`, borderRight: `1px solid ${token.colorBorder}` }}>
|
||||
{/* 单个配置 */}
|
||||
@ -109,7 +155,7 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
||||
{...cropperImageProps}
|
||||
/>
|
||||
) : (
|
||||
<div style={{ padding: '84px' }}>
|
||||
<div className={classNames(`${componentName}-middle-cont`)}>
|
||||
<Image
|
||||
width={'62.5%'}
|
||||
src={AlgorithmConfigImg}
|
||||
@ -117,19 +163,21 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
||||
fallback={ErrorImage}
|
||||
/>
|
||||
<h2>请进行批量配置</h2>
|
||||
<ul style={{ display: 'inline-block', paddingLeft: 0, width: '51.8%', listStyle: 'none', textAlign: 'left', color: token.colorTextLabel }}>
|
||||
<li>· 盒子批量配置仅支持同型号盒子;</li>
|
||||
<li>· 采取覆盖式更新,不保留原有配置,且预警检测框默认全屏范围;</li>
|
||||
<li>· 人流量统计默认检测线为屏幕中央横向线条,且箭头指向下方;</li>
|
||||
<li>· 优先选择拉流正常的摄像头。</li>
|
||||
</ul>
|
||||
{customBatchCenterContent || (
|
||||
<ul style={{ display: 'inline-block', paddingLeft: 0, width: '51.8%', listStyle: 'none', textAlign: 'left', color: token.colorTextLabel }}>
|
||||
<li>· 盒子批量配置仅支持同型号盒子;</li>
|
||||
<li>· 采取覆盖式更新,不保留原有配置,且预警检测框默认全屏范围;</li>
|
||||
<li>· 人流量统计默认检测线为屏幕中央横向线条,且箭头指向下方;</li>
|
||||
<li>· 优先选择拉流正常的摄像头。</li>
|
||||
</ul>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
<div style={{ width: '39.8%' }} >
|
||||
<div>
|
||||
<Title>时间模板</Title>
|
||||
<Title className={classNames(`${componentName}-title`)}>时间模板</Title>
|
||||
<div style={{ padding: `${token.paddingMD}px ${token.paddingSM}px`, borderTop: `1px solid ${token.colorBorder}`, borderBottom: `1px solid ${token.colorBorder}` }}>
|
||||
<TimeTemplateTable
|
||||
dataSource={timeTemplateDataSource}
|
||||
@ -138,7 +186,7 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Title>算法应用</Title>
|
||||
<Title className={classNames(`${componentName}-title`)}>算法应用</Title>
|
||||
<div style={{ padding: `${token.paddingMD}px ${token.paddingSM}px`, borderTop: `1px solid ${token.colorBorder}` }}>
|
||||
<AlgorithmTable
|
||||
dataSource={algorithmTableDataSource}
|
||||
|
@ -1,16 +1,20 @@
|
||||
import React from 'react';
|
||||
import React, { useContext } from 'react';
|
||||
import { DeleteFilled, EditFilled, ImportOutlined, PlusCircleFilled } from '@ant-design/icons';
|
||||
import type { ParamsType, ProColumns, ProTableProps } from '@ant-design/pro-components';
|
||||
import {
|
||||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { Popconfirm, Select, Space, Switch } from 'antd';
|
||||
import theme from 'antd/es/theme';
|
||||
import { ConfigProvider } from '@zhst/meta'
|
||||
import theme from 'antd/es/theme'
|
||||
import { AnyObject } from 'antd/es/_util/type';
|
||||
import { SelectProps } from 'antd/lib';
|
||||
import SchemaFormModal from '../schemaFormModal';
|
||||
import classNames from 'classnames';
|
||||
import './index.less'
|
||||
|
||||
const { useToken } = theme
|
||||
const { ConfigContext } = ConfigProvider
|
||||
|
||||
export interface AlgorithmTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
||||
onAddAlgorithm?: (id?: string, record?: any) => void
|
||||
@ -40,7 +44,11 @@ const AlgorithmTable= <DataSource extends AnyObject = AnyObject>(
|
||||
onDraw,
|
||||
tableType = 'multiple',
|
||||
sortList = [],
|
||||
prefixCls: customizePrefixCls
|
||||
} = props
|
||||
const { getPrefixCls } = useContext(ConfigContext);
|
||||
const componentName = getPrefixCls('material-algo-algoTable', customizePrefixCls);
|
||||
|
||||
|
||||
const { token } = useToken()
|
||||
|
||||
@ -53,21 +61,21 @@ const AlgorithmTable= <DataSource extends AnyObject = AnyObject>(
|
||||
title: '运行周期',
|
||||
dataIndex: 'runCycle',
|
||||
valueType: 'select',
|
||||
width: 80,
|
||||
valueEnum: {
|
||||
1: { text: '黑夜' },
|
||||
0: { text: '白天' },
|
||||
},
|
||||
},
|
||||
{
|
||||
title: '算力占用',
|
||||
dataIndex: 'powerOccupy',
|
||||
},
|
||||
// {
|
||||
// title: '算力占用',
|
||||
// dataIndex: 'powerOccupy',
|
||||
// },
|
||||
{
|
||||
title: '操作',
|
||||
key: 'option',
|
||||
valueType: 'option',
|
||||
fixed: true,
|
||||
fixed: 'right',
|
||||
width: '120px',
|
||||
render: (_DOM, record) => [
|
||||
<Switch value={record.status} onChange={_status => onItemSwitch?.(_status, record.id, record)} />,
|
||||
<a onClick={() => onDraw?.(record.id, record)} style={{ display: tableType === 'single' ? 'block' : 'none' }} href="#"><ImportOutlined /></a>,
|
||||
@ -88,29 +96,34 @@ const AlgorithmTable= <DataSource extends AnyObject = AnyObject>(
|
||||
];
|
||||
|
||||
return (
|
||||
<ProTable<DataSource>
|
||||
columns={columns}
|
||||
bordered
|
||||
scroll={{ y: 240 }}
|
||||
dataSource={[]}
|
||||
headerTitle={(
|
||||
<Space size={16}>
|
||||
<Select
|
||||
value={selectedKey}
|
||||
style={{ width: 320 }}
|
||||
onChange={onSortSelect}
|
||||
options={sortList}
|
||||
/>
|
||||
<PlusCircleFilled onClick={() => onAddAlgorithm?.()} style={{ fontSize: '24px', color: token.colorPrimary, cursor: 'pointer' }} />
|
||||
</Space>
|
||||
)}
|
||||
toolbar={undefined}
|
||||
rowKey="id"
|
||||
search={false}
|
||||
options={false}
|
||||
pagination={false}
|
||||
{...props}
|
||||
/>
|
||||
<div className={componentName}>
|
||||
<Space className={classNames(`${componentName}-top`)} size={16}>
|
||||
<Select
|
||||
className={classNames(`${componentName}-top-select`)}
|
||||
value={selectedKey}
|
||||
onChange={onSortSelect}
|
||||
options={sortList}
|
||||
/>
|
||||
<PlusCircleFilled className={classNames(`${componentName}-top-plus`)} onClick={() => onAddAlgorithm?.(selectedKey)} style={{ color: token.colorPrimary, cursor: 'pointer' }} />
|
||||
</Space>
|
||||
<ProTable<DataSource>
|
||||
columns={columns}
|
||||
bordered
|
||||
scroll={{ y: 240, x: 600 }}
|
||||
dataSource={[]}
|
||||
cardProps={{
|
||||
bodyStyle: {
|
||||
padding: 0
|
||||
}
|
||||
}}
|
||||
toolbar={undefined}
|
||||
rowKey="id"
|
||||
search={false}
|
||||
options={false}
|
||||
pagination={false}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,13 @@
|
||||
.zhst-material-algo-algoTable {
|
||||
&-top {
|
||||
margin-bottom: 12px;
|
||||
|
||||
&-select {
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
&-plus {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,10 +1,11 @@
|
||||
|
||||
import React from 'react';
|
||||
import type { ParamsType, ProColumns, ProTableProps } from '@ant-design/pro-components';
|
||||
import {
|
||||
ProTable,
|
||||
} from '@ant-design/pro-components';
|
||||
import { InputNumber } from 'antd';
|
||||
import { AnyObject } from 'antd/es/_util/type';
|
||||
import { InputNumber } from 'antd';
|
||||
|
||||
export interface TimeTemplateTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
||||
onItemBlur?: (value?: number | string, id?: any, record?: any) => void,
|
||||
@ -31,10 +32,11 @@ const TimeTemplateTable = <DataSource extends AnyObject = AnyObject>(
|
||||
title: '布控星期',
|
||||
dataIndex: 'arrangeDay',
|
||||
},
|
||||
{
|
||||
title: '算力占用',
|
||||
dataIndex: 'powerOccupy',
|
||||
},
|
||||
// TODO: 暂时先注释后续在做这个功能
|
||||
// {
|
||||
// title: '算力占用',
|
||||
// dataIndex: 'powerOccupy',
|
||||
// },
|
||||
{
|
||||
title: '配置路数',
|
||||
key: 'option',
|
||||
@ -46,6 +48,11 @@ const TimeTemplateTable = <DataSource extends AnyObject = AnyObject>(
|
||||
return (
|
||||
<ProTable<DataSource>
|
||||
columns={columns}
|
||||
cardProps={{
|
||||
bodyStyle: {
|
||||
padding: 0
|
||||
}
|
||||
}}
|
||||
bordered
|
||||
scroll={{ y: 95 }}
|
||||
toolbar={undefined}
|
||||
|
@ -8,7 +8,7 @@ const algorithmTableDataSource: any = []
|
||||
const timeTemplateDataSource: any = []
|
||||
const boxListData: any[] | (() => any[]) = []
|
||||
|
||||
for (let i = 0; i < 5; i += 1) {
|
||||
for (let i = 0; i < 100; i += 1) {
|
||||
algorithmTableDataSource.push({
|
||||
id: String(i),
|
||||
templateName: '算法模板' + (i + 1),
|
||||
|
21
packages/material/src/algorithmConfig/index.less
Normal file
21
packages/material/src/algorithmConfig/index.less
Normal file
@ -0,0 +1,21 @@
|
||||
.zhst-material-algo {
|
||||
&-title {
|
||||
margin: 18px 16px;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
&-left {
|
||||
&-list {
|
||||
padding-bottom: 36px;
|
||||
max-height: 612px;
|
||||
overflow-y: scroll;
|
||||
box-sizing: 'border-box';
|
||||
}
|
||||
}
|
||||
|
||||
&-middle {
|
||||
&-cont {
|
||||
padding: 84px;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import React, { useState } from 'react';
|
||||
import { AlgorithmConfigModal } from '@zhst/material';
|
||||
import { Button } from 'antd';
|
||||
|
||||
const algorithmTableDataSource: any = []
|
||||
const timeTemplateDataSource: any = []
|
||||
@ -26,7 +27,7 @@ for (let i = 0; i < 5; i += 1) {
|
||||
}
|
||||
|
||||
const demo = () => {
|
||||
const [open, setOpen] = useState(true)
|
||||
const [open, setOpen] = useState(false)
|
||||
const [algorithmTableList, setAlgorithmTableList] = useState(algorithmTableDataSource)
|
||||
const [timeTemplateData, setTimeTemplateData] = useState(timeTemplateDataSource)
|
||||
const [boxList, setBoxList] = useState(boxListData)
|
||||
@ -34,7 +35,8 @@ const demo = () => {
|
||||
const [algorithmSelectedKey, setAlgorithmSelectedKey] = useState('1')
|
||||
|
||||
return (
|
||||
<div style={{ border: '1px solid #ccc', width: '340px', minHeight: '900px' }}>
|
||||
<div>
|
||||
<Button onClick={() => setOpen(true)}>打开</Button>
|
||||
<AlgorithmConfigModal
|
||||
title="批量算法设置"
|
||||
width={1500}
|
||||
|
@ -47,12 +47,12 @@ const Password: FC<PasswordProps> = (props) => {
|
||||
<Form.Item
|
||||
name="rePassword"
|
||||
label="确认密码"
|
||||
dependencies={['password']}
|
||||
dependencies={['newPassword']}
|
||||
rules={[
|
||||
{ required: true, message: '请再次输入密码!' },
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue('password') === value) {
|
||||
if (!value || getFieldValue('newPassword') === value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error('两次输入的密码不一致!'));
|
||||
|
@ -1,5 +1,161 @@
|
||||
# @zhst/utils
|
||||
|
||||
## 0.20.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: 修改 zhst/meta
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.3
|
||||
|
||||
## 0.20.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- zhst/biz、zhst/meta、zhst/material: 修改 od、修改 boxSelectTree
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.2
|
||||
|
||||
## 0.20.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- fix: 修改 cropperImage 渲染问题
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.1
|
||||
|
||||
## 0.20.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: cropperImage 透出矩形坐标
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.20.0
|
||||
|
||||
## 0.19.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 修复之前发版错乱问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.13.0
|
||||
- @zhst/func@0.15.0
|
||||
- @zhst/icon@0.5.0
|
||||
- @zhst/meta@0.19.0
|
||||
|
||||
## 0.18.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.14.1
|
||||
- @zhst/hooks@0.12.1
|
||||
- @zhst/meta@0.18.1
|
||||
|
||||
## 0.18.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- feat: 重新发版
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.12.0
|
||||
- @zhst/func@0.14.0
|
||||
- @zhst/icon@0.4.0
|
||||
- @zhst/meta@0.18.0
|
||||
|
||||
## 0.17.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- fix: 修复适配问题
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.11.0
|
||||
- @zhst/func@0.13.0
|
||||
- @zhst/icon@0.3.0
|
||||
- @zhst/meta@0.17.0
|
||||
|
||||
## 0.16.4
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/func@0.12.0
|
||||
- @zhst/hooks@0.10.4
|
||||
- @zhst/meta@0.16.4
|
||||
|
||||
## 0.16.3
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.3
|
||||
- @zhst/hooks@0.10.3
|
||||
- @zhst/meta@0.16.3
|
||||
|
||||
## 0.16.2
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.2
|
||||
- @zhst/hooks@0.10.2
|
||||
- @zhst/meta@0.16.2
|
||||
|
||||
## 0.16.1
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- @zhst/func@0.11.1
|
||||
- @zhst/hooks@0.10.1
|
||||
- @zhst/meta@0.16.1
|
||||
|
||||
## 0.16.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/biz:新增摘要列表-无限滚动组件
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/hooks@0.10.0
|
||||
- @zhst/func@0.11.0
|
||||
- @zhst/meta@0.16.0
|
||||
|
||||
## 0.15.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- 视频添加 OD 框,查看大图首次点击修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.15.0
|
||||
- @zhst/func@0.10.2
|
||||
- @zhst/hooks@0.9.2
|
||||
|
||||
## 0.14.0
|
||||
|
||||
### Minor Changes
|
||||
|
||||
- zhst/meta 大图圈选组件点击选不上 bug 修复,attach 遮挡底部框事件阻止修复
|
||||
|
||||
### Patch Changes
|
||||
|
||||
- Updated dependencies
|
||||
- @zhst/meta@0.14.0
|
||||
|
||||
## 0.13.0
|
||||
|
||||
### Minor Changes
|
||||
|
@ -17,8 +17,7 @@ import React, { useEffect, useState, useRef, useImperativeHandle } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { get, pick, isNull, generateImg, dataURLToBlob, getTransforms, addEventListenerWrapper, getFileByRect } from '@zhst/func';
|
||||
import Align from 'rc-align';
|
||||
import { Button, Empty } from '..';
|
||||
import { IconFont as Icon } from '@zhst/icon';
|
||||
import { Empty, AttachImage } from '..';
|
||||
import { Cropper, Viewer, EVENT_VIEWER_TRANSFORM_CHANGE, EVENT_VIEWER_READY, EVENT_CROP_START, EVENT_CROP_END } from "../ImageEditor";
|
||||
import BtnGroup from "./components/BtnGroup";
|
||||
import "./index.less";
|
||||
@ -480,16 +479,6 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
||||
}
|
||||
};
|
||||
|
||||
// ============================= attact img =========================
|
||||
var _useState17 = useState(0),
|
||||
_useState18 = _slicedToArray(_useState17, 2),
|
||||
selectAttachImgIndex = _useState18[0],
|
||||
setSelectAttachImgIndex = _useState18[1];
|
||||
var _useState19 = useState(false),
|
||||
_useState20 = _slicedToArray(_useState19, 2),
|
||||
isZoomin = _useState20[0],
|
||||
setIsZoomin = _useState20[1];
|
||||
|
||||
// ============================== Ref ===============================
|
||||
useImperativeHandle(ref, function () {
|
||||
return {
|
||||
@ -544,46 +533,10 @@ export var BigImagePreview = /*#__PURE__*/React.forwardRef(function (props, ref)
|
||||
setShowCrop: setShowCrop,
|
||||
cropType: cropType,
|
||||
selectAlgorithmVersion: selectAlgorithmVersion
|
||||
}))), (attachImg === null || attachImg === void 0 ? void 0 : attachImg.length) && !showCrop && /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "-attach"), isZoomin && "".concat(componentName, "-attach--zoomin"), "".concat(componentName, "-attach--fixed"), isZoomin && "".concat(componentName, "-attach--zoomin--fixed"))
|
||||
}, /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "-attach__tab"))
|
||||
}, showAttachImgLabel ? attachImg === null || attachImg === void 0 ? void 0 : attachImg.map(function (_ref6, index) {
|
||||
var label = _ref6.label;
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
key: index,
|
||||
className: classNames("".concat(componentName, "-attach__tab-item"), selectAttachImgIndex === index && "".concat(componentName, "-attach__tab-item--select")),
|
||||
onMouseEnter: function onMouseEnter() {
|
||||
setSelectAttachImgIndex(index);
|
||||
}
|
||||
}, label);
|
||||
}) : null), /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "-attach__scale"))
|
||||
}, /*#__PURE__*/React.createElement(Button, {
|
||||
type: "text"
|
||||
//绝对定位下onClick事件失效采用onMouseDown
|
||||
,
|
||||
onMouseDown: function onMouseDown(e) {
|
||||
//如果是左键执行
|
||||
if (e.button == 0) {
|
||||
setIsZoomin(function (pre) {
|
||||
return !pre;
|
||||
});
|
||||
}
|
||||
},
|
||||
style: {
|
||||
color: '#fff'
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(Icon, {
|
||||
styles: {
|
||||
display: 'flex'
|
||||
},
|
||||
icon: isZoomin ? 'icon-cancle_fullscreen' : 'icon-fullscreen'
|
||||
}))), /*#__PURE__*/React.createElement("img", {
|
||||
draggable: "false",
|
||||
className: classNames("".concat(componentName, "-attach__img"), "".concat(componentName, "-attach__img--fixed")),
|
||||
src: get(attachImg, "".concat(selectAttachImgIndex, ".url"), '')
|
||||
})), (showScore || score) && /*#__PURE__*/React.createElement("div", {
|
||||
}))), (attachImg === null || attachImg === void 0 ? void 0 : attachImg.length) && !showCrop && /*#__PURE__*/React.createElement(AttachImage, {
|
||||
showAttachImgLabel: showAttachImgLabel,
|
||||
data: attachImg
|
||||
}), (showScore || score) && /*#__PURE__*/React.createElement("div", {
|
||||
style: {
|
||||
bottom: 20
|
||||
},
|
||||
|
@ -101,8 +101,7 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
type: "primary",
|
||||
shape: "circle",
|
||||
style: {
|
||||
width: '56px',
|
||||
height: '56px'
|
||||
width: '56px'
|
||||
},
|
||||
icon: /*#__PURE__*/React.createElement(IconFont, {
|
||||
icon: "icon-qiehuanzuo",
|
||||
@ -116,8 +115,7 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
type: "primary",
|
||||
shape: "circle",
|
||||
style: {
|
||||
width: '56px',
|
||||
height: '56px'
|
||||
width: '56px'
|
||||
},
|
||||
icon: /*#__PURE__*/React.createElement(IconFont, {
|
||||
icon: "icon-qiehuanyou",
|
||||
|
@ -123,6 +123,8 @@
|
||||
box-sizing: border-box;
|
||||
|
||||
&__btn {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
opacity: 0.4;
|
||||
pointer-events: all;
|
||||
|
||||
|
@ -30,31 +30,32 @@ export default {
|
||||
_this$eventHandleList = this.eventHandleList,
|
||||
eventHandleList = _this$eventHandleList === void 0 ? [] : _this$eventHandleList,
|
||||
options = this.options;
|
||||
//图片事件
|
||||
// 鼠标滚轮事件
|
||||
var scaleAble = get(options, 'scaleAble', true);
|
||||
if (scaleAble) {
|
||||
var handleWhele = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWhele);
|
||||
var handleWheel = addEventListenerWrapper(canvas, EVENT_WHEEL, this.onWheel.bind(this));
|
||||
eventHandleList.push(handleWheel);
|
||||
}
|
||||
|
||||
// 鼠标 - 拖拽事件
|
||||
var dragAble = get(options, 'dragAble', true);
|
||||
if (dragAble) {
|
||||
var handleDragStart = addEventListenerWrapper(canvas, EVENT_POINTER_DOWN, this.onDragStart.bind(this));
|
||||
eventHandleList.push(addEventListenerWrapper);
|
||||
eventHandleList.push(handleDragStart);
|
||||
var handleDragMove = addEventListenerWrapper(element.ownerDocument, EVENT_POINTER_MOVE, this.onDragMove.bind(this));
|
||||
eventHandleList.push(handleDragMove);
|
||||
EVENT_POINTER_UP.trim().split(REGEXP_SPACES).forEach(function (eventName) {
|
||||
var handleDragEnd = addEventListenerWrapper(element.ownerDocument, eventName, _this.onDragEnd.bind(_this));
|
||||
EVENT_POINTER_UP.trim().split(REGEXP_SPACES).forEach(function (_eventName) {
|
||||
var handleDragEnd = addEventListenerWrapper(element.ownerDocument, _eventName, _this.onDragEnd.bind(_this));
|
||||
eventHandleList.push(handleDragEnd);
|
||||
});
|
||||
}
|
||||
|
||||
//rect事件
|
||||
var handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
// const handleLeveal = addEventListenerWrapper(canvas, EVENT_LEAVEL, this.onLeavel.bind(this));
|
||||
// eventHandleList.push(handleLeveal);
|
||||
// const handleEnter = addEventListenerWrapper(canvas, EVENT_ENTER, this.onEnter.bind(this));
|
||||
// eventHandleList.push(handleEnter);
|
||||
// 鼠标 - 点击事件
|
||||
var selectAble = get(options, 'selectAble', true);
|
||||
if (selectAble) {
|
||||
var handleClick = addEventListenerWrapper(canvas, EVENT_CLICK, this.onClick.bind(this));
|
||||
eventHandleList.push(handleClick);
|
||||
}
|
||||
},
|
||||
unbind: function unbind() {
|
||||
var eventHandleList = this.eventHandleList;
|
||||
@ -67,7 +68,7 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
/* 图片事件 */onWheel: function onWheel(event, cropBox) {
|
||||
/* 鼠标滚轮事件 */onWheel: function onWheel(event, cropBox) {
|
||||
var _this2 = this;
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
@ -97,6 +98,7 @@ export default {
|
||||
})
|
||||
}, cropBox);
|
||||
},
|
||||
// 鼠标拖拽 - 开始拖拽
|
||||
onDragStart: function onDragStart(event) {
|
||||
event.stopPropagation();
|
||||
// This line is required for preventing page zooming in iOS browsers
|
||||
@ -119,6 +121,7 @@ export default {
|
||||
this.action = ACTION_DRAG;
|
||||
addClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
// 鼠标拖拽 - 拖拽中
|
||||
onDragMove: function onDragMove(event) {
|
||||
event.stopPropagation();
|
||||
|
||||
@ -147,6 +150,7 @@ export default {
|
||||
this.pointer.startX = this.pointer.endX;
|
||||
this.pointer.startY = this.pointer.endY;
|
||||
},
|
||||
// 鼠标拖拽 - 停止拖拽
|
||||
onDragEnd: function onDragEnd(event) {
|
||||
event.stopPropagation();
|
||||
var action = this.action;
|
||||
@ -158,14 +162,7 @@ export default {
|
||||
this.point = null;
|
||||
removeClass(this.canvas, CLASS_MOVE);
|
||||
},
|
||||
/* rect事件 */
|
||||
// onLeavel(event) {
|
||||
// const pointerCenter = this.windowToCanvasAxis(event);
|
||||
// this.highlightShape(pointerCenter);
|
||||
// },
|
||||
// onEnter(event) {
|
||||
// this.highlightShape(null);
|
||||
// },
|
||||
// 鼠标点击
|
||||
onClick: function onClick(event) {
|
||||
event.stopPropagation();
|
||||
var pointerCenter = this.windowToCanvasAxis(event);
|
||||
|
@ -13,7 +13,12 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
||||
function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
|
||||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||
//@ts-nocheck
|
||||
import * as turf from '@turf/turf';
|
||||
import { AXIS_TYPE_ORIGIN, AXIS_TYPE_CANVAS, AXIS_TYPE_IMAGE } from "./constants";
|
||||
export function rectToPolygon(axisRect) {
|
||||
var polygon = turf.polygon([[[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)]]]);
|
||||
return polygon;
|
||||
}
|
||||
|
||||
//设置数据的精度
|
||||
//accuracy 表示精度 以原点为中心向左为正,向右为负,
|
||||
@ -42,17 +47,14 @@ export default {
|
||||
targetTransform: {
|
||||
translateX: 0,
|
||||
translateY: 0,
|
||||
scale: 0,
|
||||
scale: 1,
|
||||
rotate: 0
|
||||
// rotate: 90,
|
||||
},
|
||||
windowToCanvasAxis: function windowToCanvasAxis(event) {
|
||||
var _this$canvas$getBound = this.canvas.getBoundingClientRect(),
|
||||
x = _this$canvas$getBound.x,
|
||||
y = _this$canvas$getBound.y;
|
||||
return {
|
||||
x: event.pageX - x,
|
||||
y: event.pageY - y,
|
||||
x: event.offsetX,
|
||||
y: event.offsetY,
|
||||
__AXIS_TYPE__: AXIS_TYPE_CANVAS
|
||||
};
|
||||
},
|
||||
@ -76,7 +78,8 @@ export default {
|
||||
var targetTransform = this.targetTransform;
|
||||
var translateX = targetTransform.translateX,
|
||||
translateY = targetTransform.translateY,
|
||||
scale = targetTransform.scale;
|
||||
_targetTransform$scal = targetTransform.scale,
|
||||
scale = _targetTransform$scal === void 0 ? 1 : _targetTransform$scal;
|
||||
var axis = _objectSpread(_objectSpread({
|
||||
x: translateX + x * scale,
|
||||
y: translateY + y * scale
|
||||
|
@ -75,7 +75,14 @@ var Viewer = (_dec = Mixin(Render, Event, Shape, Helper), _dec(_class = /*#__PUR
|
||||
}, {
|
||||
key: "build",
|
||||
value: function build() {
|
||||
var _this$options = this.options,
|
||||
_this$options$width = _this$options.width,
|
||||
width = _this$options$width === void 0 ? 300 : _this$options$width,
|
||||
_this$options$height = _this$options.height,
|
||||
height = _this$options$height === void 0 ? 150 : _this$options$height;
|
||||
var canvas = document.createElement('canvas');
|
||||
canvas.width = width || canvas.width;
|
||||
canvas.height = height || canvas.height;
|
||||
addClass(canvas, CLASS_CANVAS);
|
||||
this.element.appendChild(canvas);
|
||||
this.canvas = canvas;
|
||||
|
@ -65,7 +65,6 @@ export default {
|
||||
});
|
||||
},
|
||||
initCanvas: function initCanvas() {
|
||||
if (!this.image) return;
|
||||
//通过样式设置 不依赖父元素的prosition
|
||||
var element = this.element,
|
||||
canvas = this.canvas,
|
||||
@ -83,7 +82,7 @@ export default {
|
||||
var fitTransform = this.calcFitScreen();
|
||||
this.targetTransform = Object.assign({}, this.targetTransform, fitTransform);
|
||||
dispatchEvent(this.element, EVENT_VIEWER_TRANSFORM_CHANGE, cloneDeep(this.targetTransform));
|
||||
//产品需求:fitscale 是minscale
|
||||
//产品需求:fitscale 是 minscale
|
||||
var _options$fitScaleAsMi = options.fitScaleAsMinScale,
|
||||
fitScaleAsMinScale = _options$fitScaleAsMi === void 0 ? false : _options$fitScaleAsMi;
|
||||
if (fitScaleAsMinScale) {
|
||||
@ -106,8 +105,9 @@ export default {
|
||||
};
|
||||
loop();
|
||||
},
|
||||
// 绘制画布
|
||||
renderCanvas: function renderCanvas(_ctx) {
|
||||
if (!this.image || !this.canvas) return;
|
||||
if (!this.canvas) return;
|
||||
var containerData = this.containerData,
|
||||
canvas = this.canvas,
|
||||
targetTransform = this.targetTransform,
|
||||
@ -128,14 +128,14 @@ export default {
|
||||
ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
// ctx.setTransform(scale, 0, 0, scale, translateX, translateY);
|
||||
//旋转
|
||||
var centerX = this.image.width / 2;
|
||||
var centerY = this.image.height / 2;
|
||||
var centerX = this.image ? this.image.width / 2 : canvas.width;
|
||||
var centerY = this.image ? this.image.height / 2 : canvas.height;
|
||||
ctx.translate(centerX, centerY);
|
||||
ctx.rotate(rotate / 180 * Math.PI);
|
||||
ctx.translate(-centerX, -centerY);
|
||||
|
||||
//图片
|
||||
ctx.drawImage(this.image, 0, 0);
|
||||
this.image && ctx.drawImage(this.image, 0, 0);
|
||||
ctx.restore();
|
||||
//画图形
|
||||
ctx.save();
|
||||
|
@ -14,13 +14,9 @@ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e
|
||||
import { isNil, isArray, isFunction } from '@zhst/func';
|
||||
import * as turf from '@turf/turf';
|
||||
import booleanPointInPolygon from '@turf/boolean-point-in-polygon';
|
||||
import { setNumberAccuracy } from "./helper";
|
||||
import { rectToPolygon } from "./helper";
|
||||
import { SHAPE_TYPE_RECT, SHAPE_TYPE_CIRCLE, EVENT_SHAPE_SELECT } from "./constants";
|
||||
import { dispatchEvent } from "../utils";
|
||||
function rectToPolygon(axisRect) {
|
||||
var polygon = turf.polygon([[[setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y, -2)], [setNumberAccuracy(axisRect.x2, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y2, -2)], [setNumberAccuracy(axisRect.x, -2), setNumberAccuracy(axisRect.y, -2)]]]);
|
||||
return polygon;
|
||||
}
|
||||
export default {
|
||||
//store
|
||||
shapeList: [],
|
||||
@ -47,20 +43,20 @@ export default {
|
||||
this.changeZoonAble(true);
|
||||
}
|
||||
},
|
||||
//method
|
||||
addShape: function addShape(shap) {
|
||||
//method:添加矩形
|
||||
addShape: function addShape(shape) {
|
||||
var type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : SHAPE_TYPE_RECT;
|
||||
this.color = shap.color ? shap.color : '';
|
||||
if (isNil(shap) || this.disableAdd) return;
|
||||
this.color = shape.color ? shape.color : '';
|
||||
if (isNil(shape) || this.disableAdd) return;
|
||||
var _this$shapeList = this.shapeList,
|
||||
preShapeList = _this$shapeList === void 0 ? [] : _this$shapeList;
|
||||
var shapList = isArray(shap) ? shap : [shap];
|
||||
shapList = shapList.map(function (v) {
|
||||
var _shapeList = isArray(shape) ? shape : [shape];
|
||||
_shapeList = _shapeList.map(function (v) {
|
||||
return _objectSpread(_objectSpread({}, v), {}, {
|
||||
__SHAPE_TYPE__: type
|
||||
});
|
||||
});
|
||||
this.shapeList = [].concat(_toConsumableArray(preShapeList), _toConsumableArray(shapList));
|
||||
this.shapeList = [].concat(_toConsumableArray(preShapeList), _toConsumableArray(_shapeList));
|
||||
},
|
||||
//
|
||||
setSelectShapId: function setSelectShapId(id) {
|
||||
@ -214,9 +210,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
// 绘制矩形
|
||||
renderRect: function renderRect(ctx, shape, type) {
|
||||
//算rect
|
||||
var axisRect = this.imgRectAxisToCanvasAxisRect(shape);
|
||||
var axisRect = this.imgRectAxisToCanvasAxisRect(_objectSpread(_objectSpread({}, shape), {}, {
|
||||
image: ctx.canvas
|
||||
}));
|
||||
var rect = {
|
||||
x: axisRect.x2 > axisRect.x ? axisRect.x : axisRect.x2,
|
||||
y: axisRect.y2 > axisRect.y ? axisRect.y : axisRect.y2,
|
||||
|
@ -1,4 +1,5 @@
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||||
@ -18,15 +19,14 @@ import { noop, get, addEventListenerWrapper, dataURLToBlob, nextTick, toRealNumb
|
||||
import Align from 'rc-align';
|
||||
import { useLatest, useUpdateEffect, useFullscreen, useUnmount } from '@zhst/hooks';
|
||||
import classNames from 'classnames';
|
||||
import download from 'downloadjs';
|
||||
import { Button, message } from '..';
|
||||
import { message } from '..';
|
||||
import { IconFont } from '@zhst/icon';
|
||||
import { Cropper, EVENT_CROP_START, EVENT_CROP_END } from "../ImageEditor";
|
||||
import { Cropper, EVENT_CROP_START, EVENT_CROP_END, Viewer } from "../ImageEditor";
|
||||
import FlvPlayer, { FLV_EVENT } from "./components/FlvPlayer";
|
||||
import Range from "./components/Progress";
|
||||
import Loading from "./components/Loading";
|
||||
import { CROP_TYPE } from "../utils/constants";
|
||||
import { getShowStatus } from "./videoPlayerHelper";
|
||||
import { downloadFrame, getShowStatus } from "./videoPlayerHelper";
|
||||
import "./index.less";
|
||||
var componentName = "zhst-image__video-view";
|
||||
var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
@ -42,6 +42,16 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
adjustY: true
|
||||
}
|
||||
} : _props$screenshotButt,
|
||||
_props$autoPlay = props.autoPlay,
|
||||
autoPlay = _props$autoPlay === void 0 ? false : _props$autoPlay,
|
||||
odList = props.odList,
|
||||
showOD = props.showOD,
|
||||
_props$width = props.width,
|
||||
width = _props$width === void 0 ? '100%' : _props$width,
|
||||
_props$height = props.height,
|
||||
height = _props$height === void 0 ? '532px' : _props$height,
|
||||
_props$backgroundColo = props.backgroundColor,
|
||||
backgroundColor = _props$backgroundColo === void 0 ? '#333' : _props$backgroundColo,
|
||||
_props$screenshotButt2 = props.screenshotButtonRender,
|
||||
screenshotButtonRender = _props$screenshotButt2 === void 0 ? function () {
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
@ -53,7 +63,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
}, "\u56DE\u8C03DOM");
|
||||
} : _props$screenshotButt2,
|
||||
onCropChange = props.onCropChange,
|
||||
defaultNormalizationRect = props.defautlNormalizationRect;
|
||||
defaultNormalizationRect = props.defautlNormalizationRect,
|
||||
playerProps = props.playerProps;
|
||||
// ========================== 播放 =========================
|
||||
//实例参数
|
||||
var containerRef = useRef(null); //容器ref
|
||||
@ -257,6 +268,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
// 重新加载
|
||||
var _reload = /*#__PURE__*/function () {
|
||||
var _ref = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
|
||||
var oldTime;
|
||||
@ -309,6 +322,8 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
return _ref.apply(this, arguments);
|
||||
};
|
||||
}();
|
||||
|
||||
// 进度条操作
|
||||
var seek = function seek(v) {
|
||||
if (videoInsRef.current && isVideoLoadFinished) {
|
||||
setPlayTime(parseFloat(v));
|
||||
@ -317,6 +332,7 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
message.warning('待视频加载完,才可操作进度条');
|
||||
}
|
||||
};
|
||||
|
||||
// ========================== 视频opt bar =========================
|
||||
var _useFullscreen = useFullscreen(containerRef, {
|
||||
pageFullscreen: true
|
||||
@ -354,17 +370,15 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
_useState22 = _slicedToArray(_useState21, 2),
|
||||
cropRect = _useState22[0],
|
||||
setCropRect = _useState22[1];
|
||||
useEffect(function () {
|
||||
var _videoInsRef$current4, _videoInsRef$current5;
|
||||
showCrop ? videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current4 = videoInsRef.current) === null || _videoInsRef$current4 === void 0 ? void 0 : _videoInsRef$current4.pause() : videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current5 = videoInsRef.current) === null || _videoInsRef$current5 === void 0 ? void 0 : _videoInsRef$current5.play();
|
||||
}, [showCrop]);
|
||||
|
||||
// 监听showCrop, isReady - 是否可编辑、视频播放组件是否挂载
|
||||
useEffect(function () {
|
||||
var handlerCropStart;
|
||||
var handlerCropEnd;
|
||||
setCropRect(null);
|
||||
if (!isReady) return;
|
||||
if (showCrop) {
|
||||
var _canvas$parentNode;
|
||||
var _canvas$parentNode, _videoInsRef$current4;
|
||||
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, function () {
|
||||
setCropRect(null);
|
||||
});
|
||||
@ -412,18 +426,41 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
};
|
||||
}
|
||||
isFirstFlagRef.current = false;
|
||||
|
||||
// 初始化圈选工具
|
||||
cropInsRef.current = new Cropper(corpContainerRef.current, {
|
||||
showMask: true,
|
||||
cropBoxLimited: cropBoxLimited,
|
||||
editAble: false,
|
||||
img: imageData,
|
||||
initialCropBoxData: initialCropBoxData
|
||||
});
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current4 = videoInsRef.current) === null || _videoInsRef$current4 === void 0 || _videoInsRef$current4.pause();
|
||||
} else {
|
||||
var _videoInsRef$current5;
|
||||
var _element = videoInsRef.current._mediaElement || {};
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current5 = videoInsRef.current) === null || _videoInsRef$current5 === void 0 || _videoInsRef$current5.play();
|
||||
// 挂载图片选择
|
||||
cropInsRef.current = new Viewer(corpContainerRef.current, {
|
||||
scaleAble: false,
|
||||
selectAble: false,
|
||||
dragAble: false,
|
||||
width: _element.clientWidth,
|
||||
height: _element.clientHeight,
|
||||
backgroundColor: 'transparent'
|
||||
});
|
||||
|
||||
// 判定是否存在od框
|
||||
showOD && (odList === null || odList === void 0 ? void 0 : odList.forEach(function (_od) {
|
||||
var _cropInsRef$current;
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current = cropInsRef.current) === null || _cropInsRef$current === void 0 || _cropInsRef$current.addShape(_od);
|
||||
}));
|
||||
}
|
||||
return function () {
|
||||
var _handlerCropStart, _handlerCropEnd, _cropInsRef$current, _cropInsRef$current$d;
|
||||
var _handlerCropStart, _handlerCropEnd, _cropInsRef$current2, _cropInsRef$current2$;
|
||||
(_handlerCropStart = handlerCropStart) === null || _handlerCropStart === void 0 || _handlerCropStart.remove();
|
||||
(_handlerCropEnd = handlerCropEnd) === null || _handlerCropEnd === void 0 || _handlerCropEnd.remove();
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current = cropInsRef.current) === null || _cropInsRef$current === void 0 || (_cropInsRef$current$d = _cropInsRef$current.destroy) === null || _cropInsRef$current$d === void 0 || _cropInsRef$current$d.call(_cropInsRef$current);
|
||||
cropInsRef === null || cropInsRef === void 0 || (_cropInsRef$current2 = cropInsRef.current) === null || _cropInsRef$current2 === void 0 || (_cropInsRef$current2$ = _cropInsRef$current2.destroy) === null || _cropInsRef$current2$ === void 0 || _cropInsRef$current2$.call(_cropInsRef$current2);
|
||||
cropInsRef.current = null;
|
||||
};
|
||||
}, [showCrop, isReady]);
|
||||
@ -502,7 +539,7 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
};
|
||||
}();
|
||||
|
||||
//回调
|
||||
// 监听showCrop、cropRect - 监听是否可编辑、绘制的矩形
|
||||
useEffect(function () {
|
||||
//计算归一化crop rect
|
||||
var normalizationRect = null;
|
||||
@ -528,41 +565,11 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
}, [showCrop, cropRect]);
|
||||
|
||||
// ========================== 截帧 =========================
|
||||
var downloadVideoframe = useCallback( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee4() {
|
||||
var _videoInsRef$current6, _videoInsRef$current7, video, canvas, ctx, base64;
|
||||
return _regeneratorRuntime().wrap(function _callee4$(_context4) {
|
||||
while (1) switch (_context4.prev = _context4.next) {
|
||||
case 0:
|
||||
try {
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current6 = videoInsRef.current) === null || _videoInsRef$current6 === void 0 || (_videoInsRef$current7 = _videoInsRef$current6.pause) === null || _videoInsRef$current7 === void 0 || _videoInsRef$current7.call(_videoInsRef$current6);
|
||||
video = videoRef.current;
|
||||
canvas = document.createElement('canvas');
|
||||
ctx = canvas.getContext('2d');
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx === null || ctx === void 0 || ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx === null || ctx === void 0 || ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL();
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx === null || ctx === void 0 || ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
base64 = canvas.toDataURL('image/png');
|
||||
}
|
||||
download(base64);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
case 1:
|
||||
case "end":
|
||||
return _context4.stop();
|
||||
}
|
||||
}, _callee4);
|
||||
})), []);
|
||||
var downloadVideoFrame = useCallback(function (opt) {
|
||||
var _videoInsRef$current6, _videoInsRef$current7;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current6 = videoInsRef.current) === null || _videoInsRef$current6 === void 0 || (_videoInsRef$current7 = _videoInsRef$current6.pause) === null || _videoInsRef$current7 === void 0 || _videoInsRef$current7.call(_videoInsRef$current6);
|
||||
downloadFrame(videoRef.current, opt);
|
||||
}, []);
|
||||
|
||||
// ============================== 暴露出去的方法 ===============================
|
||||
var latestIsReady = useLatest(isReady);
|
||||
@ -573,17 +580,31 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
setShowCrop: function setShowCrop(dispatch) {
|
||||
var isReady = latestIsReady.current;
|
||||
if (!isReady) return;
|
||||
_setShowCrop(dispatch);
|
||||
_setShowCrop === null || _setShowCrop === void 0 || _setShowCrop(dispatch);
|
||||
},
|
||||
downloadVideoframe: downloadVideoframe
|
||||
downloadVideoFrame: downloadVideoFrame,
|
||||
pause: function pause() {
|
||||
var _videoInsRef$current8, _videoInsRef$current9;
|
||||
(_videoInsRef$current8 = videoInsRef.current) === null || _videoInsRef$current8 === void 0 || (_videoInsRef$current9 = _videoInsRef$current8.pause) === null || _videoInsRef$current9 === void 0 || _videoInsRef$current9.call(_videoInsRef$current8);
|
||||
},
|
||||
play: function play() {
|
||||
var _videoInsRef$current10, _videoInsRef$current11;
|
||||
(_videoInsRef$current10 = videoInsRef.current) === null || _videoInsRef$current10 === void 0 || (_videoInsRef$current11 = _videoInsRef$current10.play) === null || _videoInsRef$current11 === void 0 || _videoInsRef$current11.call(_videoInsRef$current10);
|
||||
},
|
||||
reload: _reload
|
||||
};
|
||||
});
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName)),
|
||||
ref: containerRef
|
||||
}, url && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FlvPlayer, {
|
||||
ref: containerRef,
|
||||
style: {
|
||||
width: width,
|
||||
height: height,
|
||||
backgroundColor: backgroundColor
|
||||
}
|
||||
}, url && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement(FlvPlayer, _extends({
|
||||
playId: playSeq,
|
||||
autoPlay: true,
|
||||
autoPlay: autoPlay,
|
||||
className: classNames("".concat(componentName, "-flv")),
|
||||
type: url.startsWith('http') ? 'mp4' : 'flv',
|
||||
url: url,
|
||||
@ -594,12 +615,14 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
hasAudio: false,
|
||||
hasVideo: true
|
||||
},
|
||||
onCreat: initPlayer
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
onCreate: initPlayer
|
||||
}, playerProps)), /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "-crop-container")),
|
||||
ref: corpContainerRef,
|
||||
style: {
|
||||
display: isFullscreen ? 'none' : 'block'
|
||||
display: isFullscreen ? 'none' : 'block',
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}
|
||||
}), showCrop && cropRect && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
|
||||
ref: alginContainerRef,
|
||||
@ -625,27 +648,26 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
cropType: CROP_TYPE['CUSTOM']
|
||||
}))), !showCrop && /*#__PURE__*/React.createElement("div", {
|
||||
className: "".concat(componentName, "-opt")
|
||||
}, /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Button, {
|
||||
type: "text",
|
||||
onClick: function onClick() {
|
||||
if (!isPlay) {
|
||||
var _videoInsRef$current8;
|
||||
//播放中暂停
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current8 = videoInsRef.current) === null || _videoInsRef$current8 === void 0 || _videoInsRef$current8.play();
|
||||
_setShowCrop(false);
|
||||
} else {
|
||||
var _videoInsRef$current9;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current9 = videoInsRef.current) === null || _videoInsRef$current9 === void 0 || _videoInsRef$current9.pause();
|
||||
}
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
marginRight: '12px',
|
||||
color: '#fff',
|
||||
display: 'flex'
|
||||
},
|
||||
onIconClick: function onIconClick() {
|
||||
if (!isPlay) {
|
||||
var _videoInsRef$current12;
|
||||
//播放中暂停
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current12 = videoInsRef.current) === null || _videoInsRef$current12 === void 0 || _videoInsRef$current12.play();
|
||||
_setShowCrop(false);
|
||||
} else {
|
||||
var _videoInsRef$current13;
|
||||
videoInsRef === null || videoInsRef === void 0 || (_videoInsRef$current13 = videoInsRef.current) === null || _videoInsRef$current13 === void 0 || _videoInsRef$current13.pause();
|
||||
}
|
||||
},
|
||||
color: "#1890ff",
|
||||
icon: !isPlay ? 'icon-shipinbofang' : 'icon-shipinzanting'
|
||||
}))), /*#__PURE__*/React.createElement("div", {
|
||||
icon: !isPlay ? 'icon-bofang3' : 'icon-zanting1'
|
||||
}), /*#__PURE__*/React.createElement("div", {
|
||||
className: "".concat(componentName, "-opt-range"),
|
||||
onClick: function onClick(e) {
|
||||
e.stopPropagation();
|
||||
@ -656,20 +678,19 @@ var VideoPlayer = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
max: showMaxDuration,
|
||||
showSlider: showSlider,
|
||||
onChange: seek
|
||||
}), /*#__PURE__*/React.createElement("div", null, formatDurationTime(playTime), "/", formatDurationTime(showMaxDuration))), /*#__PURE__*/React.createElement("div", null, /*#__PURE__*/React.createElement(Button, {
|
||||
type: "text",
|
||||
onClick: function onClick(e) {
|
||||
}), /*#__PURE__*/React.createElement("div", null, formatDurationTime(playTime), "/", formatDurationTime(showMaxDuration))), /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
display: 'flex',
|
||||
marginLeft: '12px'
|
||||
},
|
||||
color: "#fff",
|
||||
size: 18,
|
||||
onIconClick: function onIconClick(e) {
|
||||
e.stopPropagation();
|
||||
toggleFullscreen();
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(IconFont, {
|
||||
styles: {
|
||||
color: '#fff',
|
||||
display: 'flex'
|
||||
},
|
||||
size: 18,
|
||||
icon: isFullscreen ? 'icon-cancle_fullscreen' : 'icon-fullscreen'
|
||||
})))), !!showStatus && /*#__PURE__*/React.createElement(Loading, {
|
||||
icon: isFullscreen ? 'icon-suoxiao1' : 'icon-quanping1'
|
||||
})), !!showStatus && /*#__PURE__*/React.createElement(Loading, {
|
||||
status: showStatus,
|
||||
reload: function reload() {
|
||||
return _reload();
|
||||
|
@ -1,4 +1,4 @@
|
||||
var _excluded = ["className", "autoPlay", "config", "onCreat", "playId"];
|
||||
var _excluded = ["className", "autoPlay", "config", "onCreate", "playId"];
|
||||
function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
|
||||
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
||||
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
||||
@ -45,12 +45,13 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
autoPlay = _this$props$autoPlay === void 0 ? true : _this$props$autoPlay,
|
||||
_this$props$config = _this$props.config,
|
||||
config = _this$props$config === void 0 ? {} : _this$props$config,
|
||||
onCreat = _this$props.onCreat,
|
||||
onCreate = _this$props.onCreate,
|
||||
playId = _this$props.playId,
|
||||
others = _objectWithoutProperties(_this$props, _excluded);
|
||||
if ($video) {
|
||||
if (flvjs.isSupported() && _this.props.url && _this.props.url) {
|
||||
var reload = function reload() {
|
||||
var _this$flvPlayer;
|
||||
if (_this.flvPlayer && _this.flvPlayer.destroy) {
|
||||
try {
|
||||
_this.flvPlayer.destroy();
|
||||
@ -65,7 +66,7 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
flvPlayer.load();
|
||||
_this.flvPlayer = flvPlayer;
|
||||
// @ts-ignore
|
||||
var controller = _this.flvPlayer._transmuxer._controller;
|
||||
var controller = (_this$flvPlayer = _this.flvPlayer) === null || _this$flvPlayer === void 0 || (_this$flvPlayer = _this$flvPlayer._transmuxer) === null || _this$flvPlayer === void 0 ? void 0 : _this$flvPlayer._controller;
|
||||
var wsLoader = controller._ioctl._loader;
|
||||
var oldWsOnCompleteFunc = wsLoader._onComplete;
|
||||
wsLoader._onComplete = function () {
|
||||
@ -82,10 +83,9 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
oldWsOnCompleteFunc();
|
||||
};
|
||||
_this.flvPlayer.reload = reload;
|
||||
onCreat && onCreat(_this.flvPlayer, $video);
|
||||
onCreate === null || onCreate === void 0 || onCreate(_this.flvPlayer, $video);
|
||||
};
|
||||
reload();
|
||||
onCreat && onCreat(_this.flvPlayer, $video);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -95,9 +95,9 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
key: "componentWillUnmount",
|
||||
value: function componentWillUnmount() {
|
||||
if (this.flvPlayer) {
|
||||
var _this$flvPlayer, _this$flvPlayer2;
|
||||
(_this$flvPlayer = this.flvPlayer) === null || _this$flvPlayer === void 0 || _this$flvPlayer.unload();
|
||||
(_this$flvPlayer2 = this.flvPlayer) === null || _this$flvPlayer2 === void 0 || _this$flvPlayer2.detachMediaElement();
|
||||
var _this$flvPlayer2, _this$flvPlayer3;
|
||||
(_this$flvPlayer2 = this.flvPlayer) === null || _this$flvPlayer2 === void 0 || _this$flvPlayer2.unload();
|
||||
(_this$flvPlayer3 = this.flvPlayer) === null || _this$flvPlayer3 === void 0 || _this$flvPlayer3.detachMediaElement();
|
||||
}
|
||||
}
|
||||
}, {
|
||||
@ -119,13 +119,11 @@ var VideoPlayer = /*#__PURE__*/function (_Component) {
|
||||
return /*#__PURE__*/React.createElement("video", {
|
||||
muted: true,
|
||||
preload: "metadata",
|
||||
className: className
|
||||
// controls={true}
|
||||
,
|
||||
style: Object.assign({
|
||||
className: className,
|
||||
style: _objectSpread({
|
||||
width: '100%',
|
||||
height: '100%'
|
||||
}, style ? style : {}),
|
||||
}, style),
|
||||
ref: this.initFlv
|
||||
});
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ function _objectWithoutProperties(source, excluded) { if (source == null) return
|
||||
function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { Slider } from 'antd';
|
||||
import { Slider, ConfigProvider } from 'antd';
|
||||
import "./index.less";
|
||||
var componentName = "zhst-image__range";
|
||||
export var Range = function Range(props) {
|
||||
@ -15,6 +15,15 @@ export var Range = function Range(props) {
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
style: style,
|
||||
className: classNames("".concat(componentName), !showSlider && "".concat(componentName, "--no-slider"), className)
|
||||
}, /*#__PURE__*/React.createElement(Slider, others));
|
||||
}, /*#__PURE__*/React.createElement(ConfigProvider, {
|
||||
theme: {
|
||||
components: {
|
||||
Slider: {
|
||||
railBg: 'rgba(255, 255, 255, 0.6)',
|
||||
railHoverBg: 'rgba(255, 255, 255, 0.6)'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, /*#__PURE__*/React.createElement(Slider, others)));
|
||||
};
|
||||
export default Range;
|
@ -1,8 +1,6 @@
|
||||
.zhst-image__video-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
height: 532px;
|
||||
background-color: #333;
|
||||
|
||||
// &-flv {
|
||||
@ -37,7 +35,7 @@
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
padding: 0 12px;
|
||||
padding: 0 12px 0 24px;
|
||||
background-color: rgb(0 0 0 / 80%);
|
||||
line-height: 32px;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import download from "downloadjs";
|
||||
export function getShowStatus(isLoadingVideo, isEnd, isError) {
|
||||
var status = null;
|
||||
if (isLoadingVideo) {
|
||||
@ -10,4 +11,41 @@ export function getShowStatus(isLoadingVideo, isEnd, isError) {
|
||||
status = 'END';
|
||||
}
|
||||
return status;
|
||||
}
|
||||
}
|
||||
|
||||
// 下载功能的可配置属性
|
||||
|
||||
// 视屏截帧、下载
|
||||
export var downloadFrame = function downloadFrame(_videoDom, opt) {
|
||||
var _ref = opt || {},
|
||||
_ref$downloadAble = _ref.downloadAble,
|
||||
downloadAble = _ref$downloadAble === void 0 ? true : _ref$downloadAble,
|
||||
_ref$fileName = _ref.fileName,
|
||||
fileName = _ref$fileName === void 0 ? 'image' : _ref$fileName,
|
||||
_ref$fileType = _ref.fileType,
|
||||
fileType = _ref$fileType === void 0 ? 'image/png' : _ref$fileType;
|
||||
try {
|
||||
var video = _videoDom;
|
||||
var canvas = document.createElement('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
var base64;
|
||||
|
||||
//当视频处于还未加载出来时,截屏为黑色图片
|
||||
if (video.readyState === 0) {
|
||||
ctx === null || ctx === void 0 || ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
canvas.width = video.offsetWidth;
|
||||
canvas.height = video.offsetHeight;
|
||||
// @ts-ignore
|
||||
ctx.fillStyle = 'black';
|
||||
ctx === null || ctx === void 0 || ctx.fillRect(0, 0, canvas.width, canvas.height);
|
||||
} else {
|
||||
canvas.width = video.videoWidth;
|
||||
canvas.height = video.videoHeight;
|
||||
ctx === null || ctx === void 0 || ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
||||
}
|
||||
base64 = canvas.toDataURL(fileType);
|
||||
downloadAble && download(base64, fileName);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
};
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user