feat(zhst/biz): 添加大图组件v2
This commit is contained in:
parent
a501656907
commit
ce6a719bc2
12
.fatherrc.ts
12
.fatherrc.ts
@ -1,5 +1,15 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
});
|
||||
|
@ -61,6 +61,7 @@
|
||||
"dumi": "^2.2.13",
|
||||
"eslint": "^8.23.0",
|
||||
"father": "^4.1.0",
|
||||
"father-plugin-less": "^0.0.2",
|
||||
"husky": "^8.0.1",
|
||||
"lerna": "^8.0.0",
|
||||
"lint-staged": "^13.0.3",
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
plugins: ['father-plugin-less'],
|
||||
});
|
||||
|
@ -35,6 +35,7 @@
|
||||
"registry": "http://10.0.0.77:4874"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/core": "^1.3.9",
|
||||
"@zhst/types": "workspace:^"
|
||||
},
|
||||
"dependencies": {
|
||||
|
304
packages/biz/src/BigImage/BigImage.tsx
Normal file
304
packages/biz/src/BigImage/BigImage.tsx
Normal file
@ -0,0 +1,304 @@
|
||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react'
|
||||
import {
|
||||
ConfigProvider,
|
||||
Descriptions,
|
||||
CropperImage,
|
||||
AttachImage,
|
||||
VideoPlayer,
|
||||
RelatedImage,
|
||||
Radio,
|
||||
Tooltip,
|
||||
Button,
|
||||
Tabs
|
||||
} from '@zhst/meta';
|
||||
import classNames from 'classnames'
|
||||
import { IconFont } from '@zhst/icon'
|
||||
import { BigImageProps, BigImageRef } from './interface'
|
||||
import CombineImage from './components/CombineImage'
|
||||
import './index.less'
|
||||
|
||||
const DescriptionsItem = Descriptions.Item
|
||||
|
||||
export const componentPrefix = 'zhst-big-image'
|
||||
|
||||
const initialStyle ={
|
||||
fontSize: '12px'
|
||||
}
|
||||
|
||||
const BigImage = forwardRef<BigImageRef, BigImageProps>((props, ref) => {
|
||||
const {
|
||||
// ------------ 通用配置 -------------------
|
||||
type,
|
||||
viewHeight,
|
||||
width = '100%',
|
||||
children,
|
||||
// ------------ 顶部按钮 -----------------
|
||||
topButtonRender,
|
||||
// ------------ 描述 -----------------
|
||||
descriptionList = [],
|
||||
showDescription,
|
||||
// ------------- tab 导航 ----------------
|
||||
customTabBarExtraContent,
|
||||
tabProps,
|
||||
onTabChange,
|
||||
// ------------- 场景图 -------------
|
||||
cropperImageProps = {
|
||||
cropButtonList: []
|
||||
},
|
||||
// ----------------- 对比图 ---------------------
|
||||
combineImageProps,
|
||||
// ------------ 视频模式 -----------------
|
||||
videoProps,
|
||||
// ------------ view 操作按钮 -----------------
|
||||
showModeChange,
|
||||
modeButtonGroupProps,
|
||||
viewTopModeButtonList = [
|
||||
{
|
||||
key: 'image',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
key: 'video',
|
||||
label: '视频'
|
||||
}
|
||||
],
|
||||
// ------------------ 翻页 ----------------------
|
||||
showNavigation,
|
||||
prevButtonProps,
|
||||
onPrevButtonClick,
|
||||
onNextButtonClick,
|
||||
nextButtonProps,
|
||||
// ------------------ 人脸碰撞模型 -----------------
|
||||
relatedImageProps,
|
||||
isRelated = false,
|
||||
theme,
|
||||
} = props
|
||||
const combineImageRef = useRef<any>(null)
|
||||
const videoPlayerRef = useRef<any>(null)
|
||||
const cropperImageRef = useRef<any>(null)
|
||||
|
||||
cropperImageProps.cropButtonList = cropperImageProps?.cropButtonList || [
|
||||
{
|
||||
key: 'auto',
|
||||
icon: <IconFont icon='icon-zidong' />,
|
||||
label: '智能框选',
|
||||
},
|
||||
{
|
||||
key: 'custom',
|
||||
icon: <IconFont icon='icon-shoudong' />,
|
||||
label: '手动框选',
|
||||
}
|
||||
];
|
||||
|
||||
// ------------------- 初始化模式 ----------------------
|
||||
const initMode = (type: BigImageProps['type'] = 'normal') => {
|
||||
switch (type) {
|
||||
case 'compater':
|
||||
return (
|
||||
<CombineImage
|
||||
// @ts-ignore
|
||||
ref={combineImageRef}
|
||||
height={viewHeight}
|
||||
{...combineImageProps}
|
||||
/>
|
||||
)
|
||||
case 'normal':
|
||||
return (
|
||||
<div style={{ height: viewHeight, width: '100%' }}>
|
||||
<CropperImage
|
||||
ref={cropperImageRef}
|
||||
type='rect'
|
||||
// @ts-ignore
|
||||
height={viewHeight}
|
||||
{...cropperImageProps}
|
||||
>
|
||||
{/* // ------------ 显示条件:当不为编辑状态,并且有图片值 ----------------- */}
|
||||
{!cropperImageProps?.editAble && cropperImageProps?.attachImageData && (
|
||||
<>
|
||||
<AttachImage
|
||||
data={cropperImageProps?.attachImageData}
|
||||
{...cropperImageProps?.attachImageProps}
|
||||
/>
|
||||
<div
|
||||
style={{
|
||||
position: 'absolute',
|
||||
right: '4px',
|
||||
bottom: '4px',
|
||||
fontSize: '18px',
|
||||
color: 'red',
|
||||
cursor: 'default'
|
||||
}}
|
||||
>{`人脸质量分:${(Number(cropperImageProps?.score) as number).toFixed(2)}`}</div>
|
||||
</>
|
||||
)}
|
||||
{/* // ------------ 场景图绘制工具栏 ----------------- */}
|
||||
{cropperImageProps?.showEditTools && (
|
||||
<div className={`${componentPrefix}-view-cropper-btn`}>
|
||||
<Radio.Group
|
||||
className={`${componentPrefix}-view-cropper-btn-group`}
|
||||
size="small"
|
||||
buttonStyle='solid'
|
||||
// @ts-ignore
|
||||
onChange={cropperImageProps?.onCropperTypeChange}
|
||||
{...cropperImageProps.btnGroupProps}
|
||||
>
|
||||
{cropperImageProps?.cropButtonList?.map(btn => (
|
||||
<Tooltip key={btn.key} title={btn.label}>
|
||||
{/* @ts-ignore */}
|
||||
<Radio.Button value={btn.key}{...btn.props}><div className={`${componentPrefix}-view-cropper-btn-group-radio`}>{btn.icon} {btn.label}</div></Radio.Button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Radio.Group>
|
||||
<Button onClick={cropperImageProps?.onExitEdit} className={`${componentPrefix}-view-cropper-btn_close`} type="primary" size="small" icon={<IconFont icon="icon-danchuangguanbi" />} />
|
||||
</div>
|
||||
)}
|
||||
</CropperImage>
|
||||
</div>
|
||||
)
|
||||
case 'video':
|
||||
return (
|
||||
// @ts-ignore
|
||||
<VideoPlayer ref={videoPlayerRef} height={viewHeight} {...videoProps} />
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露 ref 实例
|
||||
useImperativeHandle(ref, () => ({
|
||||
// @ts-ignore
|
||||
cropperImageRef: cropperImageRef?.current,
|
||||
videoPlayerRef: videoPlayerRef?.current,
|
||||
combineImageRef: combineImageRef?.current,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames(`${componentPrefix}-view`)}
|
||||
style={{ width: `${parseInt(width as string)}px` }}
|
||||
>
|
||||
<div className={classNames(`${componentPrefix}-view-btns`)}>
|
||||
{topButtonRender}
|
||||
</div>
|
||||
{showDescription && (
|
||||
<div
|
||||
className={classNames(`${componentPrefix}-view-desc`)}
|
||||
>
|
||||
<ConfigProvider
|
||||
theme={{
|
||||
components: {
|
||||
Descriptions: {
|
||||
viewBg: '#f6f6f6',
|
||||
colorBgLayout:'#ccc',
|
||||
titleColor: 'rgba(0,0,0,0.45)',
|
||||
colorTextLabel: 'rgba(0,0,0,0.45)',
|
||||
contentColor: 'rgba(0,0,0,0.88)',
|
||||
},
|
||||
},
|
||||
...theme
|
||||
}}
|
||||
>
|
||||
{descriptionList.map(descriptions => (
|
||||
<Descriptions
|
||||
key={descriptions.title}
|
||||
title={descriptions.showTitle && descriptions.title}
|
||||
column={8}
|
||||
{...descriptions.props}
|
||||
>
|
||||
{descriptions?.children?.map(item => (
|
||||
<DescriptionsItem
|
||||
key={item.key}
|
||||
label={item.label}
|
||||
span={1}
|
||||
contentStyle={{ fontSize: initialStyle.fontSize }}
|
||||
labelStyle={{ fontSize: initialStyle.fontSize }}
|
||||
>{item.children}</DescriptionsItem>
|
||||
))}
|
||||
</Descriptions>
|
||||
))}
|
||||
</ConfigProvider>
|
||||
</div>
|
||||
)}
|
||||
<Tabs
|
||||
tabBarExtraContent={customTabBarExtraContent}
|
||||
onChange={onTabChange}
|
||||
items={[
|
||||
{
|
||||
label: `场景图`,
|
||||
key: '1',
|
||||
},
|
||||
{
|
||||
label: `对比图`,
|
||||
key: '2',
|
||||
}
|
||||
]}
|
||||
{...tabProps}
|
||||
/>
|
||||
<div
|
||||
className={classNames(`${componentPrefix}-view-container`)}
|
||||
>
|
||||
{/* ---------------- view 视图左上角导航按钮 ------------------ */}
|
||||
{showModeChange && (
|
||||
<div
|
||||
className={classNames(`${componentPrefix}-view-container-modeNav`)}
|
||||
>
|
||||
<Radio.Group
|
||||
buttonStyle='solid'
|
||||
size='small'
|
||||
{...modeButtonGroupProps}
|
||||
>
|
||||
{viewTopModeButtonList?.map(btn => (
|
||||
<Tooltip key={btn.key} title={btn.tooltipTxt}>
|
||||
{/* @ts-ignore */}
|
||||
<Radio.Button value={btn.key} {...btn.props}>{btn.icon} {btn.label}</Radio.Button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</Radio.Group>
|
||||
</div>
|
||||
)}
|
||||
{/* --------------------------------- 视频播放模式 --------------------------------- */}
|
||||
{initMode(type)}
|
||||
{/* 切换按钮组件 */}
|
||||
{/* ----------------------------------- 上一张按钮 ---------------------------------- */}
|
||||
{showNavigation && (
|
||||
<Button
|
||||
className={classNames(
|
||||
`${componentPrefix}-view-container-nav`,
|
||||
`${componentPrefix}-view-container-nav_left`
|
||||
)}
|
||||
icon={<IconFont icon="icon-qiehuanzuo" />}
|
||||
type="primary"
|
||||
// style={{ backgroundColor: 'rgba(255,255,255,0.8)' }}
|
||||
shape='circle'
|
||||
onClick={onPrevButtonClick}
|
||||
{...prevButtonProps}
|
||||
/>
|
||||
)}
|
||||
{/* ----------------------------------- 下一张按钮 ---------------------------------- */}
|
||||
{showNavigation && (
|
||||
<Button
|
||||
className={classNames(
|
||||
`${componentPrefix}-view-container-nav`,
|
||||
`${componentPrefix}-view-container-nav_right`
|
||||
)}
|
||||
icon={<IconFont icon="icon-qiehuanyou" />}
|
||||
type="primary"
|
||||
// style={{ backgroundColor: 'rgba(255,255,255,0.8)' }}
|
||||
shape='circle'
|
||||
onClick={onNextButtonClick}
|
||||
{...nextButtonProps}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
{/* ----------------------------------- 人脸碰撞组件 ---------------------------------- */}
|
||||
{isRelated && (
|
||||
// @ts-ignore
|
||||
<RelatedImage
|
||||
{...relatedImageProps}
|
||||
/>
|
||||
)}
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export default BigImage
|
@ -0,0 +1,3 @@
|
||||
.zhst-big-image-combime-image {
|
||||
background-color: #f7f7f7;
|
||||
}
|
82
packages/biz/src/BigImage/components/CombineImage/index.tsx
Normal file
82
packages/biz/src/BigImage/components/CombineImage/index.tsx
Normal file
@ -0,0 +1,82 @@
|
||||
|
||||
import React, { FC, useRef, forwardRef, useImperativeHandle } from 'react';
|
||||
import { CompareImage, Flex, Progress, ProgressProps, CompareImageProps } from '@zhst/meta'
|
||||
import './index.less'
|
||||
|
||||
export interface ComBineImageProps {
|
||||
height?: string | number
|
||||
data: {
|
||||
imgSummary: string;
|
||||
compaterImage: string;
|
||||
imageKey: string;
|
||||
score: number;
|
||||
}
|
||||
prevDisable?: boolean;
|
||||
nextDisable?: boolean;
|
||||
onPre?: () => void;
|
||||
onNext?: () => void;
|
||||
openRoll?: boolean
|
||||
targetImageProps?: CompareImageProps
|
||||
sourceImageProps?: CompareImageProps
|
||||
}
|
||||
|
||||
const conicColors: ProgressProps['strokeColor'] = {
|
||||
'0%': '#42E2AC',
|
||||
'50%': '#DFAF2E',
|
||||
'100%': '#F95C55',
|
||||
};
|
||||
|
||||
const componentName = 'zhst-big-image-combime-image'
|
||||
|
||||
const ComBineImage: FC<ComBineImageProps> = forwardRef((props, ref) => {
|
||||
const {
|
||||
height,
|
||||
data,
|
||||
prevDisable,
|
||||
nextDisable,
|
||||
onNext,
|
||||
onPre,
|
||||
openRoll
|
||||
} = props
|
||||
const { imgSummary, compaterImage, score } = data
|
||||
const targetImageRef = useRef(null)
|
||||
const compareImageRef = useRef(null)
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
compareImageRef,
|
||||
targetImageRef
|
||||
}));
|
||||
|
||||
return (
|
||||
<Flex className={componentName} justify='space-between' align='center' >
|
||||
<CompareImage
|
||||
ref={targetImageRef}
|
||||
height={height}
|
||||
width="400px"
|
||||
preDisable={prevDisable}
|
||||
nextDisable={nextDisable}
|
||||
onNext={onNext}
|
||||
onPre={onPre}
|
||||
showScore={false}
|
||||
openRoll={openRoll}
|
||||
url={imgSummary}
|
||||
label="目标图"
|
||||
{...props.targetImageProps}
|
||||
/>
|
||||
<Progress type="circle" size={72} strokeWidth={6} percent={Number(score || 0)} strokeColor={conicColors} />
|
||||
<CompareImage
|
||||
ref={compareImageRef}
|
||||
width="400px"
|
||||
height={height}
|
||||
url={compaterImage}
|
||||
openRoll={false}
|
||||
score={score}
|
||||
label="预警图"
|
||||
labelColor='#FA5852'
|
||||
{...props.sourceImageProps}
|
||||
/>
|
||||
</Flex>
|
||||
)
|
||||
})
|
||||
|
||||
export default ComBineImage
|
44
packages/biz/src/BigImage/components/navigation/index.less
Normal file
44
packages/biz/src/BigImage/components/navigation/index.less
Normal file
@ -0,0 +1,44 @@
|
||||
.zhst-image__nav {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
width: 48px;
|
||||
height: 100%;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
cursor: pointer;
|
||||
font-size: 0;
|
||||
|
||||
&>button {
|
||||
& span {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
i:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
|
||||
&--disable {
|
||||
:global {
|
||||
i {
|
||||
color: #f0f0f0;
|
||||
cursor: not-allowed !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-prev {
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
&-next {
|
||||
right: 12px;
|
||||
}
|
||||
}
|
40
packages/biz/src/BigImage/components/navigation/index.tsx
Normal file
40
packages/biz/src/BigImage/components/navigation/index.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
// !! 已废弃
|
||||
import * as React from 'react';
|
||||
import classnames from 'classnames';
|
||||
import { Button } from '@zhst/meta';
|
||||
import { IconFont } from '@zhst/icon'
|
||||
import './index.less';
|
||||
|
||||
const componentName = `zhst-image__nav`;
|
||||
|
||||
const Navigation: React.FC<{
|
||||
show?: boolean;
|
||||
onClick?: React.MouseEventHandler<HTMLElement>;
|
||||
prev?: boolean;
|
||||
next?: boolean;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
color?: string;
|
||||
hoverColor?: string;
|
||||
}> = (props) => {
|
||||
const { show, prev, next, disabled, onClick, className, color } = props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
`${componentName}`,
|
||||
prev && `${componentName}-prev`,
|
||||
next && `${componentName}-next`,
|
||||
disabled && `${componentName}--disable`,
|
||||
!show && `${componentName}--hide`,
|
||||
className
|
||||
)}
|
||||
>
|
||||
<Button type="text" disabled={disabled} shape='circle' onClick={onClick}>
|
||||
<IconFont size={28} color={color} icon={prev ? 'icon-qiehuanzuo' : 'icon-qiehuanyou'} />
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Navigation;
|
Binary file not shown.
After Width: | Height: | Size: 143 KiB |
71
packages/biz/src/BigImage/demo/index.tsx
Normal file
71
packages/biz/src/BigImage/demo/index.tsx
Normal file
@ -0,0 +1,71 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { BigImage } from '@zhst/biz'
|
||||
import { Space, Switch } from '@zhst/meta'
|
||||
import { pick, get } from '@zhst/func'
|
||||
import { BIG_IMAGE_DATA, attributeList } from '../mock'
|
||||
import Img from './imgs/photo-1503185912284-5271ff81b9a8.webp'
|
||||
|
||||
const BigModal = (props: any) => {
|
||||
const {
|
||||
} = props
|
||||
const [dataSource, setDataSource] = useState(BIG_IMAGE_DATA)
|
||||
const [showDesc, setShowDesc] = useState(true)
|
||||
const [type, setType] = useState('normal')
|
||||
const modalRef = useRef(null)
|
||||
|
||||
return (
|
||||
<div style={{ padding: '32px', border: '1px solid #09f' }}>
|
||||
<Space>
|
||||
<span>显示属性:<Switch value={showDesc} onChange={e => setShowDesc(pre => !pre)} /></span>
|
||||
</Space>
|
||||
<BigImage
|
||||
type={type}
|
||||
ref={modalRef}
|
||||
width={896}
|
||||
viewHeight={'440px'}
|
||||
showModeChange
|
||||
onTabChange={(newVal) => setType(newVal === '1'? 'normal': 'compater')}
|
||||
// ------------ 属性列表 -----------------
|
||||
showDescription={showDesc}
|
||||
descriptionList={attributeList}
|
||||
// ------------ 图片/视频切换 -----------------
|
||||
viewTopModeButtonList={[
|
||||
{
|
||||
key: 'image',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
key: 'video',
|
||||
label: '视频'
|
||||
}
|
||||
]}
|
||||
modeButtonGroupProps={{
|
||||
defaultValue: 'image',
|
||||
onChange: e => console.log('模式切换', e)
|
||||
}}
|
||||
// ------------ 导航功能 -----------------
|
||||
showNavigation
|
||||
onPrevButtonClick={val => console.log('pre', val)}
|
||||
onNextButtonClick={val => console.log('next', val)}
|
||||
// ------------ 场景图功能 -----------------
|
||||
cropperImageProps={{
|
||||
url: Img,
|
||||
score: 50,
|
||||
odList: get(dataSource, 'odRect', []),
|
||||
attachImageData: get(dataSource, 'attachImg', []),
|
||||
}}
|
||||
// ------------ 对比图模式 -----------------
|
||||
combineImageProps={{
|
||||
data: pick(dataSource, 'compaterImage', 'imgSummary', 'imageKey', 'score'),
|
||||
}}
|
||||
// ------------ 视频模块 -----------------
|
||||
videoProps={{
|
||||
url: get(dataSource, 'flvUrl', '')
|
||||
}}
|
||||
>
|
||||
</BigImage>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BigModal
|
128
packages/biz/src/BigImage/demo/oldData.tsx
Normal file
128
packages/biz/src/BigImage/demo/oldData.tsx
Normal file
@ -0,0 +1,128 @@
|
||||
// @ts-nocheck
|
||||
import React, { useState } from 'react';
|
||||
import { BigImageModal } from '@zhst/biz'
|
||||
import { Button, DescriptionsProps } from '@zhst/meta'
|
||||
import { IMAGE_DATA, BIG_IMAGE_DATA } from '../mock'
|
||||
import bigImageModalAdapter from '../util/bigImageModalAdapter'
|
||||
import { get } from '@zhst/func';
|
||||
|
||||
const descriptionList: DescriptionsProps['items'] = [
|
||||
{
|
||||
title: '人员属性',
|
||||
children: [
|
||||
{
|
||||
key: '1',
|
||||
label: '性别',
|
||||
children: '男',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: '年龄',
|
||||
children: '成年',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: '帽子',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: '上身颜色',
|
||||
children: '灰',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: '下身颜色',
|
||||
children: '蓝色',
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: '附着物',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: '骑行',
|
||||
children: '否',
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
// 适配器,适配老接口
|
||||
const NewImageModal = bigImageModalAdapter(BigImageModal, {
|
||||
oldMode: true
|
||||
})
|
||||
|
||||
const BigModal = (props) => {
|
||||
const {
|
||||
onClose,
|
||||
isArchiveDetail = false,
|
||||
specialTitle = '对比图2',
|
||||
transformPropFunc,
|
||||
screenshotButtonRender,
|
||||
showLowFaceTip = false
|
||||
} = props
|
||||
const [visible, setVisible] = useState(false)
|
||||
const [selectIndex, setSelectIndex] = useState(0)
|
||||
const [dataSource, setDataSource] = useState(IMAGE_DATA.dataSource)
|
||||
const [dataSources, setDataSources] = useState(IMAGE_DATA.dataSource)
|
||||
const [selectItem, setSelectItem] = useState({})
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Button onClick={() => setVisible(true)} >查看大图</Button>
|
||||
<NewImageModal
|
||||
title="查看大图"
|
||||
dataSource={dataSource}
|
||||
imageData={dataSource}
|
||||
width={1098}
|
||||
onClose={() => onClose}
|
||||
descriptionConfig={{ data: descriptionList }}
|
||||
visible={visible}
|
||||
isArchiveDetail={isArchiveDetail}
|
||||
ToolProps={{
|
||||
// renderLeft: leftOperateBar({ disableBtn, onActionClick: onBigImageActionClick }),
|
||||
// renderRight: rightOperateBar({
|
||||
// disableBtn,
|
||||
// onActionClick: onBigImageActionClick,
|
||||
// isArchiveDetail,
|
||||
// }),
|
||||
// renderVideoBtn: !disableBtn.includes(OPT['PLAY_VIDEO']),
|
||||
// disableVideo: disableVideo,
|
||||
}}
|
||||
selectIndex={selectIndex}
|
||||
onSelectIndexChange={(index: number) => {
|
||||
index > 0 && index < dataSources.length && setSelectIndex(index);
|
||||
}}
|
||||
// tabsFilter={tabsFilter}
|
||||
specialTitle={specialTitle}
|
||||
transformPropFunc={async (item: any) => {
|
||||
let bigImageInfo = !!transformPropFunc && (await transformPropFunc(item));
|
||||
setSelectItem({ ...bigImageInfo });
|
||||
return { ...bigImageInfo };
|
||||
}}
|
||||
screenshotButtonRender={screenshotButtonRender}
|
||||
//@ts-ignore
|
||||
transformVideoPropFunc={async (item) => {
|
||||
const { maxDuration: duration = 20 } = item || {};
|
||||
const time = get(item, 'timestamp');
|
||||
const cameraId = get(item, 'cameraId');
|
||||
const { url: flvUrl } = {
|
||||
url: 'url',
|
||||
downloadUrl: 'url',
|
||||
};
|
||||
return {
|
||||
flvUrl,
|
||||
maxDuration: duration,
|
||||
};
|
||||
}}
|
||||
nullDialogProp={{
|
||||
emptyText: showLowFaceTip ? '目标图人脸质量较低,暂无聚类数据' : '暂无数据',
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BigModal
|
89
packages/biz/src/BigImage/demo/withEdit.tsx
Normal file
89
packages/biz/src/BigImage/demo/withEdit.tsx
Normal file
@ -0,0 +1,89 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { BigImage } from '@zhst/biz'
|
||||
import { Space, Switch, Button } from '@zhst/meta'
|
||||
import { pick, get } from '@zhst/func'
|
||||
import { BIG_IMAGE_DATA, attributeList } from '../mock'
|
||||
import Img from './imgs/photo-1503185912284-5271ff81b9a8.webp'
|
||||
|
||||
const testOd = [
|
||||
{
|
||||
"id": "456",
|
||||
"x": 0.58543766,
|
||||
"y": 0.3203356,
|
||||
"w": 0.052037954,
|
||||
"h": 0.2664015
|
||||
}
|
||||
]
|
||||
|
||||
const BigModal = (props: any) => {
|
||||
const {
|
||||
} = props
|
||||
const [dataSource, setDataSource] = useState(BIG_IMAGE_DATA)
|
||||
const [showDesc, setShowDesc] = useState(true)
|
||||
const [editAble, setEditAble] = useState(false)
|
||||
const [odList, setOdList] = useState(get(dataSource, 'odRect', []))
|
||||
const [type, setType] = useState('normal')
|
||||
const bigImageRef = useRef(null)
|
||||
|
||||
return (
|
||||
<div style={{ padding: '32px', border: '1px solid #09f' }}>
|
||||
<Space>
|
||||
<span>显示属性:<Switch value={showDesc} onChange={e => setShowDesc(pre => !pre)} /></span>
|
||||
<span>打开编辑模式:<Switch value={editAble} onChange={e => setEditAble(pre => !pre)} /></span>
|
||||
<Button onClick={() => setOdList(testOd)}>修改Od</Button>
|
||||
</Space>
|
||||
<BigImage
|
||||
type={type}
|
||||
ref={bigImageRef}
|
||||
width={896}
|
||||
viewHeight={'440px'}
|
||||
showModeChange
|
||||
onTabChange={(newVal) => setType(newVal === '1'? 'normal': 'compater')}
|
||||
// ------------ 属性列表 -----------------
|
||||
showDescription={showDesc}
|
||||
descriptionList={attributeList}
|
||||
// ------------ 图片/视频切换 -----------------
|
||||
viewTopModeButtonList={[
|
||||
{
|
||||
key: 'image',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
key: 'video',
|
||||
label: '视频'
|
||||
}
|
||||
]}
|
||||
modeButtonGroupProps={{
|
||||
defaultValue: 'image',
|
||||
onChange: e => console.log('模式切换', e)
|
||||
}}
|
||||
// ------------ 导航功能 -----------------
|
||||
showNavigation
|
||||
onPrevButtonClick={val => console.log('pre', val)}
|
||||
onNextButtonClick={val => console.log('next', val)}
|
||||
// ------------ 场景图功能 -----------------
|
||||
cropperImageProps={{
|
||||
editAble,
|
||||
url: Img,
|
||||
score: 50,
|
||||
odList: odList,
|
||||
showEditTools: editAble,
|
||||
attachImageData: get(dataSource, 'attachImg', []),
|
||||
onCropperTypeChange: v => console.log('框选模式', v),
|
||||
onExitEdit: () => setEditAble(pre => !pre)
|
||||
}}
|
||||
// ------------ 对比图模式 -----------------
|
||||
combineImageProps={{
|
||||
data: pick(dataSource, 'compaterImage', 'imgSummary', 'imageKey', 'score'),
|
||||
}}
|
||||
// ------------ 视频模块 -----------------
|
||||
videoProps={{
|
||||
url: get(dataSource, 'flvUrl', '')
|
||||
}}
|
||||
>
|
||||
</BigImage>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BigModal
|
78
packages/biz/src/BigImage/demo/withRelatedImage.tsx
Normal file
78
packages/biz/src/BigImage/demo/withRelatedImage.tsx
Normal file
@ -0,0 +1,78 @@
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { BigImage } from '@zhst/biz'
|
||||
import { Button, Space, Switch } from '@zhst/meta'
|
||||
import { pick, get } from '@zhst/func'
|
||||
import { BIG_IMAGE_DATA, attributeList, RELATED_IMAGES } from '../mock'
|
||||
|
||||
const BigModal = (props: any) => {
|
||||
const {
|
||||
} = props
|
||||
const [visible, setVisible] = useState(true)
|
||||
const [dataSource, setDataSource] = useState(BIG_IMAGE_DATA)
|
||||
const [selectedItemKey, setSelectedItemKey] = useState()
|
||||
const [showFaceModel, setShowFaceModel] = useState(true)
|
||||
const [type, setType] = useState('normal')
|
||||
const modalRef = useRef(null)
|
||||
|
||||
return (
|
||||
<div style={{ padding: '32px', border: '1px solid #09f' }}>
|
||||
<Space>
|
||||
<span>显示人脸碰撞模型:<Switch value={showFaceModel} onChange={e => setShowFaceModel(pre => !pre)} /></span>
|
||||
</Space>
|
||||
<BigImage
|
||||
type={type}
|
||||
open={visible}
|
||||
ref={modalRef}
|
||||
viewHeight={'440px'}
|
||||
width={896}
|
||||
onCancel={() => setVisible(false)}
|
||||
showModeChange
|
||||
onTabChange={(newVal, oldVal) => setType(newVal === '1'? 'normal': 'compater')}
|
||||
// ------------ 图片/视频切换 -----------------
|
||||
viewTopModeButtonList={[
|
||||
{
|
||||
key: 'image',
|
||||
label: '图片'
|
||||
},
|
||||
{
|
||||
key: 'video',
|
||||
label: '视频'
|
||||
}
|
||||
]}
|
||||
modeButtonGroupProps={{
|
||||
defaultValue: 'image',
|
||||
onChange: e => console.log('模式切换', e)
|
||||
}}
|
||||
// ------------ 场景图功能 -----------------
|
||||
cropperImageProps={{
|
||||
url: "https://gw.alipayobjects.com/zos/antfincdn/LlvErxo8H9/photo-1503185912284-5271ff81b9a8.webp",
|
||||
score: 50,
|
||||
odList: get(dataSource, 'odRect', []),
|
||||
attachImageData: get(dataSource, 'attachImg', []),
|
||||
}}
|
||||
// ------------ 对比图模式 -----------------
|
||||
combineImageProps={{
|
||||
data: pick(dataSource, 'compaterImage', 'imgSummary', 'imageKey', 'score'),
|
||||
}}
|
||||
// ------------ 视频模块 -----------------
|
||||
videoProps={{
|
||||
url: get(dataSource, 'flvUrl', '')
|
||||
}}
|
||||
// ------------ 人脸碰撞模型 -----------------
|
||||
isRelated={showFaceModel}
|
||||
relatedImageProps={{
|
||||
activeTab: 'related',
|
||||
selectedItemKey,
|
||||
data: RELATED_IMAGES,
|
||||
onCancel: () => console.log('取消关联'),
|
||||
onConnect: () => console.log('关联'),
|
||||
onTabChange: (newVal, oldVal) => console.log('tab切换', newVal, oldVal),
|
||||
onItemSelected: (item) => setSelectedItemKey(item.key)
|
||||
}}
|
||||
>
|
||||
</BigImage>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BigModal
|
BIN
packages/biz/src/BigImage/images/emptyImage.png
Normal file
BIN
packages/biz/src/BigImage/images/emptyImage.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
packages/biz/src/BigImage/images/percent_background.png
Normal file
BIN
packages/biz/src/BigImage/images/percent_background.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 514 B |
132
packages/biz/src/BigImage/index.less
Normal file
132
packages/biz/src/BigImage/index.less
Normal file
@ -0,0 +1,132 @@
|
||||
.zhst-big-image {
|
||||
.zhst-dialog-content {
|
||||
box-shadow: 0 4px 12px rgb(0 0 0 / 20%);
|
||||
}
|
||||
|
||||
.zhst-tabs .zhst-tabs-nav-wrap {
|
||||
background-color: #f6f6f6;
|
||||
}
|
||||
|
||||
&-view {
|
||||
&-btns {
|
||||
margin-bottom: 16px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
}
|
||||
&-desc {
|
||||
margin-bottom: 16px;
|
||||
padding: 16px 16px 0 16px;
|
||||
background-color: #f7f7f7;
|
||||
.zhst-descriptions-header {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
.zhst-descriptions-title {
|
||||
font-size: 14px;
|
||||
}
|
||||
}
|
||||
// ------------ tab -----------------
|
||||
.zhst-tabs-nav {
|
||||
margin-bottom: 8px;
|
||||
.zhst-tabs-tab {
|
||||
&:not(:first-child) {
|
||||
margin-left: 24px;
|
||||
}
|
||||
padding: 0;
|
||||
padding-bottom: 4px;
|
||||
}
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&-container {
|
||||
position: relative;
|
||||
min-height: 440px;
|
||||
width: 100%;
|
||||
margin-bottom: 16px;
|
||||
font-size: 0;
|
||||
&-modeNav {
|
||||
padding: 2px;
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
left: 4px;
|
||||
z-index: 10;
|
||||
border-radius: 4px;
|
||||
}
|
||||
&__nav {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 50%;
|
||||
width: 40px !important;
|
||||
height: 40px !important;
|
||||
background: #d9d9d9;
|
||||
border-radius: 100%;
|
||||
cursor: pointer;
|
||||
transform: translateY(-50%);
|
||||
|
||||
&>button {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
&--disabled {
|
||||
opacity: 0.3;
|
||||
|
||||
&>button {
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__nav:hover {
|
||||
background: #09f;
|
||||
color: #fff !important;
|
||||
}
|
||||
// ------------ 导航 -----------------
|
||||
&-nav {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background-color: rgba(255, 255, 255, 0.8);
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
background-color: rgba(255, 255, 255, 0.8)!important;
|
||||
}
|
||||
&_left {
|
||||
left: 8px;
|
||||
}
|
||||
&_right {
|
||||
right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ------------ 场景图 -----------------
|
||||
&-cropper-btn {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
&_close {
|
||||
margin-left: 4px;
|
||||
vertical-align: top;
|
||||
}
|
||||
&-group {
|
||||
.zhst-radio-button-wrapper {
|
||||
display: inline-flex;
|
||||
font-size: 12px;
|
||||
color: #191919;
|
||||
background-color: rgba(255, 255, 255, 0.8)
|
||||
}
|
||||
&-radio {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
.anticon {
|
||||
margin-right: 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
96
packages/biz/src/BigImage/index.md
Normal file
96
packages/biz/src/BigImage/index.md
Normal file
@ -0,0 +1,96 @@
|
||||
---
|
||||
group: 进阶组件
|
||||
category: Components
|
||||
subtitle: 大图组件
|
||||
toc: content
|
||||
title: BigImage 大图组件
|
||||
---
|
||||
|
||||
## 大图弹框
|
||||
|
||||
<code src="./demo/index.tsx">基本</code>
|
||||
<code src="./demo/withRelatedImage.tsx">人脸碰撞模型</code>
|
||||
<code src="./demo/withEdit.tsx">编辑模式</code>
|
||||
|
||||
### API
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 | 版本 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| type | 当前模式 | 'compater'、'normal'、'video' | - | |
|
||||
| viewHeight | 视图高度 | string、number | - | |
|
||||
| width | 宽度 | string、number | - | |
|
||||
| showDescription | 描述列表显示\隐藏 | boolean | false | |
|
||||
| descriptionsProps | 描述列表透传 | | antd - DescriptionsProps | |
|
||||
| descriptionList | 描述列表数据(见下文) | | IDescriptionList | |
|
||||
| topButtonRender | 顶部按钮 | | ReactNode、string | |
|
||||
| customTabBarExtraContent | 自定义tab尾部导航插槽 | | ReactNode、 string | |
|
||||
| onTabChange | tab事件监听 | | antd - TabsProps['onChange'] | |
|
||||
| tabProps | tab透传 | | antd - TabsProps | |
|
||||
| showModeChange | 是否显示模式切换按钮 | | boolean | |
|
||||
| viewTopModeButtonList | 模式切换按钮列表 | | TypeRadio[] | |
|
||||
| modeButtonGroupProps | 模式切换按钮组透传 | RadioGroupProps | - | |
|
||||
| isRelated | 人脸碰撞模型显示\隐藏 | boolean | | |
|
||||
| relatedImageProps | 人脸碰撞模型透传 | zhst/meta - RelatedImageProps | | |
|
||||
| cropperImageProps | 场景图模式透传 | ICropperImageProps | | |
|
||||
| combineImageProps | 对比图模式透传 | ComBineImageProps | | |
|
||||
| videoProps | 视频模式透传 | videoProps | | |
|
||||
| showNavigation | 是否展示导航 | boolean | | |
|
||||
| prevButtonProps | 前翻箭头透传 | prevButtonProps | | |
|
||||
| onPrevButtonClick | 前翻箭头点击事件 | () => void; | | |
|
||||
| nextButtonProps | 下翻箭头透传 | () => void; | | |
|
||||
| onNextButtonClick | 下翻箭头点击事件 | () => void; | | |
|
||||
| children | | ReactNode | | |
|
||||
|
||||
### IDescriptionList
|
||||
|
||||
```ts
|
||||
interface IDescriptionList {
|
||||
title: string;
|
||||
showTitle?: boolean;
|
||||
props?: DescriptionsProps
|
||||
children: DescriptionsProps['items']
|
||||
}[]
|
||||
```
|
||||
|
||||
###
|
||||
|
||||
```ts
|
||||
interface ICropperImageProps extends CropperImageProps {
|
||||
showEditTools?: boolean // 是否展示编辑按钮
|
||||
editAble?: boolean // 是否开启编辑模式
|
||||
score?: string | number // 分数
|
||||
btnGroupProps?: BtnGroupProps; // crop 场景图模式下的按钮拓展
|
||||
cropButtonList?: TypeRadio[] // 编辑按钮列表
|
||||
onCropperTypeChange?: (type: RadioProps['onChange']) => void
|
||||
onExitEdit?: ButtonProps['onClick'] // 退出编辑模式
|
||||
attachImageData?: AttachImageProps['data'] // 左下角预览图
|
||||
attachImageProps?: AttachImageProps // 左下角预览图透传
|
||||
}
|
||||
```
|
||||
|
||||
## 设计方案
|
||||
|
||||
结合当下的业务场景,目前大图组件有三种模式
|
||||
|
||||
1. 场景图模式
|
||||
-
|
||||
2. 对比图模式
|
||||
3. 视频模式
|
||||
|
||||
场景图和视频模式,支持用户编辑圈选
|
||||
|
||||
三种模式状态下,都会有外层模块的嵌套,目前有以下几种:
|
||||
|
||||
1. 描述模块
|
||||
2. 顶部拓展
|
||||
- 目前仅支持自定义
|
||||
- 默认下边间距 16px
|
||||
3. tabs 切换
|
||||
- 默认下间距:16px
|
||||
- 支持自定义文案
|
||||
- 支持自定义数量
|
||||
- 支持后方插槽
|
||||
4. 人脸碰撞模型
|
||||
- 支持用户自定义传入数据
|
||||
|
||||
本来想通过插件的形式按需加载
|
5
packages/biz/src/BigImage/index.tsx
Normal file
5
packages/biz/src/BigImage/index.tsx
Normal file
@ -0,0 +1,5 @@
|
||||
import BigImage from "./BigImage";
|
||||
|
||||
export type { BigImageProps, BigImageRef } from './BigImage'
|
||||
|
||||
export default BigImage
|
84
packages/biz/src/BigImage/interface.ts
Normal file
84
packages/biz/src/BigImage/interface.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { ReactNode } from 'react'
|
||||
import {
|
||||
ButtonProps,
|
||||
RadioProps,
|
||||
RadioGroupProps,
|
||||
VideoViewProps,
|
||||
DescriptionsProps,
|
||||
TabsProps,
|
||||
RelatedImageProps,
|
||||
BtnGroupProps,
|
||||
CropperImageProps,
|
||||
VideoViewRef,
|
||||
AttachImageProps
|
||||
} from '@zhst/meta'
|
||||
import { ComBineImageProps } from './components/CombineImage'
|
||||
|
||||
export type TypeRadio = {
|
||||
label?: string;
|
||||
key: string;
|
||||
tooltipTxt?: string;
|
||||
onClick?: ButtonProps['onClick']
|
||||
icon?: ReactNode | string;
|
||||
props?: ButtonProps
|
||||
}
|
||||
|
||||
type TypePlugin = 'compater' | 'normal' | 'video' | 'faceMode'
|
||||
|
||||
export interface BigImageProps {
|
||||
type?: TypePlugin // 当前 tab
|
||||
viewHeight?: string | number;
|
||||
width?: string | number
|
||||
typePlugins?: TypePlugin[] // TODO: 开启插件类型
|
||||
// ------------ 描述列表 -----------------
|
||||
showDescription?: boolean;
|
||||
descriptionsProps?: DescriptionsProps
|
||||
descriptionList?: {
|
||||
title: string;
|
||||
showTitle?: boolean;
|
||||
props?: DescriptionsProps
|
||||
children: DescriptionsProps['items']
|
||||
}[]
|
||||
// ------------------ 顶部按钮列表
|
||||
topButtonRender?: ReactNode | string
|
||||
// ---------------- Tabs 导航 ------------------
|
||||
customTabBarExtraContent?: string | ReactNode
|
||||
onTabChange?: TabsProps['onChange']
|
||||
tabProps?: TabsProps
|
||||
// ------------ 图片 | 视频切换导航 -----------------
|
||||
showModeChange?: boolean
|
||||
viewTopModeButtonList?: TypeRadio[]
|
||||
modeButtonGroupProps?: RadioGroupProps
|
||||
// ----------------- 人脸碰转 -----------------
|
||||
isRelated?: boolean // 人脸碰撞功能打开
|
||||
relatedImageProps?: RelatedImageProps
|
||||
// -------------------------- crop 场景图模式 -----------------------
|
||||
cropperImageProps?: CropperImageProps & {
|
||||
showEditTools?: boolean
|
||||
editAble?: boolean
|
||||
score?: string | number
|
||||
btnGroupProps?: BtnGroupProps; // crop 场景图模式下的按钮拓展
|
||||
cropButtonList?: TypeRadio[]
|
||||
onCropperTypeChange?: (type: RadioProps['onChange']) => void
|
||||
onExitEdit?: ButtonProps['onClick']
|
||||
attachImageData?: AttachImageProps['data']
|
||||
attachImageProps?: AttachImageProps
|
||||
}
|
||||
// -------------------- 对比图模式 -------------------------
|
||||
combineImageProps?: ComBineImageProps
|
||||
// ------------ 导航 -----------------
|
||||
showNavigation?: boolean // 是否展示导航箭头
|
||||
prevButtonProps?: any;
|
||||
onPrevButtonClick?: () => void;
|
||||
nextButtonProps?: any
|
||||
onNextButtonClick?: () => void;
|
||||
theme?: any
|
||||
children?: React.ReactNode
|
||||
// ------------ 视频模式 -----------------
|
||||
videoProps?: VideoViewProps
|
||||
}
|
||||
|
||||
export interface BigImageRef {
|
||||
videoPlayerRef: VideoViewRef
|
||||
combineImageRef: any
|
||||
}
|
292
packages/biz/src/BigImage/mock.ts
Normal file
292
packages/biz/src/BigImage/mock.ts
Normal file
@ -0,0 +1,292 @@
|
||||
import imageUrl from './demo/imgs/photo-1503185912284-5271ff81b9a8.webp'
|
||||
|
||||
export const IMAGE_DATA = {
|
||||
"enAbleDeleteFeature": true,
|
||||
"tabsFilter": [
|
||||
"COMPATER",
|
||||
"NORMAL"
|
||||
],
|
||||
"selectIndex": 4,
|
||||
"disableBtn": [
|
||||
0,
|
||||
1,
|
||||
4,
|
||||
20
|
||||
],
|
||||
"dataSource": {
|
||||
"objectId": "1742110565582518272",
|
||||
"condition": {
|
||||
"featureInfo": null,
|
||||
"featureData": "AAAAAAAAAAAAAAAAAAAAAAA==",
|
||||
"imageData": "",
|
||||
"alg": "VERSION_REID_HEAD_ATTR",
|
||||
"rect": {
|
||||
"x": 0.271875,
|
||||
"y": 0.32222223,
|
||||
"w": 0.2859375,
|
||||
"h": 0.67777777
|
||||
},
|
||||
"objectImageUrl": "singer-20240102/1/129529/1742047651878156288.jpg",
|
||||
"srcImageUrl": "singer-20240102/1/129529/1742047652511496192.jpg"
|
||||
},
|
||||
"score": 0.7163062,
|
||||
"timestamp": 1704186491979,
|
||||
"deviceId": "129533",
|
||||
"id": "129533",
|
||||
"name": "4楼门口过道人脸",
|
||||
"dirid": "0",
|
||||
"status": "1",
|
||||
"longitude": 120.125,
|
||||
"latitude": 30.280500411987305,
|
||||
"caseId": "0",
|
||||
"caseGroup": "",
|
||||
"isDeleted": "DEVICEMANAGER_BOOL_DEFAULT",
|
||||
"objectIndex": {
|
||||
"objectId": "1742110565582518272",
|
||||
"solutionId": "1",
|
||||
"deviceId": "129533",
|
||||
"fragmentId": "0"
|
||||
},
|
||||
"objectType": "OBJECT_TYPE_PEDESTRAIN",
|
||||
"isObjectTrack": true,
|
||||
"pathId": "1742110532019697664",
|
||||
"frameInfo": {
|
||||
"frameId": "0",
|
||||
"frameTimestamp": "1704186491979",
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"originWidth": 1920,
|
||||
"originHeight": 1080,
|
||||
"offsetTime": "24714687",
|
||||
"skipNumber": "0"
|
||||
},
|
||||
"level": 1,
|
||||
"bboxInFrame": {
|
||||
"x": 0.603125,
|
||||
"y": 0.3314815,
|
||||
"w": 0.0578125,
|
||||
"h": 0.2712963
|
||||
},
|
||||
"bboxExtInFrame": {
|
||||
"x": 0.546875,
|
||||
"y": 0.2638889,
|
||||
"w": 0.17135416,
|
||||
"h": 0.40648147
|
||||
},
|
||||
"objectImageKey": "",
|
||||
"objectExtImageKey": "http://10.0.0.7:30003/file/singer-20240102/1/129533/1742110565582518272.jpg",
|
||||
"frameImageKey": "http://10.0.0.7:30003/file/singer-20240102/1/129533/1742110565603489792.jpg",
|
||||
"confidence": 0.817271,
|
||||
"sourceObjectId": "1742110565603489792",
|
||||
"storeTimestamp": "0",
|
||||
"gbNumber": "",
|
||||
"qualityScore": 0,
|
||||
"subObjectCount": 1,
|
||||
"subObjectType": [
|
||||
"OBJECT_TYPE_FACE"
|
||||
],
|
||||
"subObjectIds": [
|
||||
"1742110532015503360"
|
||||
],
|
||||
"solutionId": "1",
|
||||
"fragmentId": "0",
|
||||
"contrastKey": "singer-20240102/1/129533/1742110565582518272.jpg",
|
||||
"compaterImages": [
|
||||
"http://10.0.0.7:30003/file/singer-20240102/1/129529/1742047651878156288.jpg"
|
||||
],
|
||||
"imgSummary": "singer-20240102/1/129533/1742110565582518272.jpg",
|
||||
"imageKey": "http://10.0.0.7:30003/file/singer-20240102/1/129533/1742110565582518272.jpg",
|
||||
"srcImageUrl": "http://10.0.0.7:30003/file/singer-20240102/1/129533/1742110565603489792.jpg",
|
||||
"algorithmVersion": "VERSION_REID_HEAD_ATTR",
|
||||
"cameraId": "129533",
|
||||
"cameraName": "4楼门口过道人脸"
|
||||
},
|
||||
"isArchiveDetail": false,
|
||||
"ToolProps": {
|
||||
"renderVideoBtn": true,
|
||||
"disableVideo": false
|
||||
},
|
||||
"specialTitle": ""
|
||||
}
|
||||
|
||||
export const RELATED_IMAGES = [
|
||||
{ key: '123', url: imageUrl },
|
||||
{ key: '22', url: imageUrl },
|
||||
{ key: '22122333', url: imageUrl },
|
||||
{ key: '2212243', url: imageUrl },
|
||||
{ key: '224523433', url: imageUrl },
|
||||
{ key: '224235453', url: imageUrl },
|
||||
{ key: '245423', url: imageUrl },
|
||||
{ key: '224233543', url: imageUrl },
|
||||
{ key: '22452343', url: imageUrl },
|
||||
{ key: '22323243', url: imageUrl },
|
||||
{ key: '2236456', url: imageUrl },
|
||||
{ key: '224563', url: imageUrl },
|
||||
{ key: '24565423', url: imageUrl },
|
||||
{ key: '245645623', url: imageUrl },
|
||||
{ key: '2456435623', url: imageUrl },
|
||||
{ key: '2323', url: imageUrl }
|
||||
]
|
||||
|
||||
export const BIG_IMAGE_DATA = {
|
||||
imageKey: imageUrl,
|
||||
imgSummary: imageUrl,
|
||||
flvUrl: 'ws://10.0.0.120:9033/flv/HaikangNvr/45.flv?ip=10.0.2.103&stime=1712539148&etime=1712539168',
|
||||
compaterImage: imageUrl,
|
||||
odRect: [
|
||||
{
|
||||
id: '123',
|
||||
"x":0.5445312,
|
||||
"y":0.19166666,
|
||||
"w":0.08671875,
|
||||
"h":0.40138888
|
||||
},
|
||||
{
|
||||
"id": "123",
|
||||
"x": 0.5519352,
|
||||
"y": 0.2965385,
|
||||
"w": 0.05185461,
|
||||
"h": 0.24698898,
|
||||
},
|
||||
{
|
||||
"id": "456",
|
||||
"x": 0.58543766,
|
||||
"y": 0.3203356,
|
||||
"w": 0.052037954,
|
||||
"h": 0.2664015
|
||||
}
|
||||
],
|
||||
attachImg: [
|
||||
{
|
||||
"url": imageUrl,
|
||||
"label": "形体"
|
||||
},{
|
||||
"url": imageUrl,
|
||||
"label": "人脸"
|
||||
}
|
||||
],
|
||||
score: 60, // 人脸质量分
|
||||
showScore: true, // 人脸质量分
|
||||
cameraPosition: 'string', // 摄像头位置
|
||||
time: '2022-01-01', // 摄像头拍摄时间
|
||||
objects: [
|
||||
{
|
||||
"objectIndex": {
|
||||
"objectId": "1746832189053474816",
|
||||
"solutionId": "0",
|
||||
"deviceId": "0",
|
||||
"fragmentId": "0"
|
||||
},
|
||||
"objectType": "OBJECT_TYPE_PEDESTRAIN",
|
||||
"sourceObjectId": "0",
|
||||
"level": 0,
|
||||
"confidence": 0.881164,
|
||||
"frameInfo": {
|
||||
"frameId": "0",
|
||||
"frameTimestamp": "1705312223057",
|
||||
"width": 0,
|
||||
"height": 0,
|
||||
"originWidth": 0,
|
||||
"originHeight": 0,
|
||||
"offsetTime": "0",
|
||||
"skipNumber": "0"
|
||||
},
|
||||
"infoOnSource": {
|
||||
"bboxInFrame": {
|
||||
"bboxRatio": {
|
||||
"x": 0.61418945,
|
||||
"y": 0.34309354,
|
||||
"w": 0.067661405,
|
||||
"h": 0.34659258
|
||||
},
|
||||
},
|
||||
"countInSource": 0,
|
||||
"indexInSource": 0
|
||||
},
|
||||
"qualityScore": 0,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
export const attributeList = [
|
||||
{
|
||||
title: '人员属性',
|
||||
children: [
|
||||
{
|
||||
key: '1',
|
||||
label: '性别',
|
||||
children: '男',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: '年龄',
|
||||
children: '成年',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: '帽子',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: '上身颜色',
|
||||
children: '灰',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: '下身颜色',
|
||||
children: '蓝色',
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: '附着物',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: '骑行',
|
||||
children: '否',
|
||||
},
|
||||
]
|
||||
},
|
||||
{
|
||||
title: '社区规范',
|
||||
children: [
|
||||
{
|
||||
key: '1',
|
||||
label: '性别',
|
||||
children: '男',
|
||||
},
|
||||
{
|
||||
key: '2',
|
||||
label: '年龄',
|
||||
children: '成年',
|
||||
},
|
||||
{
|
||||
key: '3',
|
||||
label: '帽子',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '4',
|
||||
label: '上身颜色',
|
||||
children: '灰',
|
||||
},
|
||||
{
|
||||
key: '5',
|
||||
label: '下身颜色',
|
||||
children: '蓝色',
|
||||
},
|
||||
{
|
||||
key: '6',
|
||||
label: '附着物',
|
||||
children: '无',
|
||||
},
|
||||
{
|
||||
key: '7',
|
||||
label: '骑行',
|
||||
children: '否',
|
||||
},
|
||||
]
|
||||
}
|
||||
];
|
195
packages/biz/src/BigImage/util/bigImageModalAdapter.tsx
Normal file
195
packages/biz/src/BigImage/util/bigImageModalAdapter.tsx
Normal file
@ -0,0 +1,195 @@
|
||||
/**
|
||||
* 适配老的大屏组件数据格式传入
|
||||
*/
|
||||
import React, { } from 'react';
|
||||
import { AlgorithmVersionStr, HumanProperty, ObjectType, Rect, IScreenshotButtonProp } from '@zhst/types'
|
||||
import { VideoViewProps, ImgViewProps, VideoViewRef, ImgViewRef } from '@zhst/meta'
|
||||
|
||||
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'TRACK';
|
||||
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
|
||||
|
||||
export interface CarouselProps {
|
||||
hasPre?: boolean;
|
||||
hasNext?: boolean;
|
||||
selectIndex: number;
|
||||
setSelectIndex: React.Dispatch<React.SetStateAction<number>>;
|
||||
dataSource: Array<{
|
||||
key: string;
|
||||
url: string;
|
||||
}>;
|
||||
}
|
||||
|
||||
export type ISelectItem = Partial<Omit<ImgViewProps, 'screenshotButtonRender'>> &
|
||||
Partial<Omit<VideoViewProps, 'screenshotButtonRender'>>;
|
||||
|
||||
/**
|
||||
* 描述列表 description
|
||||
*/
|
||||
export interface HeaderProps {
|
||||
value: TAB_TYPE;
|
||||
onChange: (type: TAB_TYPE) => void;
|
||||
tabsFilter: TAB_TYPE[];
|
||||
}
|
||||
|
||||
export interface ParamProps {
|
||||
tab: string;
|
||||
selectItem: ISelectItem;
|
||||
imgViewRef: React.MutableRefObject<ImgViewRef>;
|
||||
VideoViewRef: React.MutableRefObject<VideoViewRef>;
|
||||
model: MODEL_TYPE;
|
||||
setModel: React.Dispatch<React.SetStateAction<MODEL_TYPE>>;
|
||||
/* 可观测值 */
|
||||
scale$: number;
|
||||
showCrop$: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 工具栏
|
||||
*/
|
||||
export interface ToolProps {
|
||||
renderRight?: (props: ParamProps) => React.ReactNode;
|
||||
renderLeft?: (props: ParamProps) => React.ReactNode;
|
||||
renderVideoBtn?: boolean;
|
||||
param: ParamProps;
|
||||
disableVideo: boolean;
|
||||
}
|
||||
|
||||
|
||||
export interface BigImageData {
|
||||
//imageKey 小图
|
||||
extendRectList: (Rect & { algorithmVersion: AlgorithmVersionStr; imageKey: string })[];
|
||||
rectList: (Rect & { algorithmVersion: AlgorithmVersionStr; imageKey: string })[];
|
||||
attachImg: { url: string; label: '形体' | '人脸' }[];
|
||||
odRect: Rect;
|
||||
compaterImages: string[] // 目标图列表
|
||||
constractKey: string; // 当前比较中的目标图
|
||||
frameImageKey: string; // 场景图
|
||||
imageKey?: string; // 大图
|
||||
imgSummary: string; // 摘要图
|
||||
objectExtImageKey: string; //比对到的目标图扩展图 === imgSummary
|
||||
|
||||
attributeList: { label: string; list: any[] }[];
|
||||
archiveImages?: any;
|
||||
spaceName: string;
|
||||
|
||||
objectIndex?: {
|
||||
deviceId: string;
|
||||
fragmentId: string;
|
||||
objectId: string;
|
||||
solutionId: string;
|
||||
}
|
||||
|
||||
objectType: ObjectType;
|
||||
objectId: string; //这张摘要本身的Id
|
||||
bodyObjectId?: string;
|
||||
faceObjectId?: string; //这张摘要下的人脸Id(如果有)
|
||||
sourceObjectId?: string; //这张摘要上游的形体Id(如果有)
|
||||
cameraId: string;
|
||||
cameraName: string;
|
||||
selectIndex: number;
|
||||
humanProperty: HumanProperty;
|
||||
qualityScore?: number; //人脸质量分
|
||||
score: number; // 相似度
|
||||
timestamp: string;
|
||||
bodyImageUrl: string;
|
||||
faceImageUrl: string;
|
||||
algorithmVersion: AlgorithmVersionStr;
|
||||
|
||||
bodySpaceName: string;
|
||||
faceSpaceName: string;
|
||||
position: {
|
||||
lat: number
|
||||
lng: number
|
||||
}
|
||||
|
||||
solutionId?: string;
|
||||
[index: string]: any;
|
||||
}
|
||||
|
||||
|
||||
interface IOldImageData {
|
||||
visible?: boolean; // 显示隐藏弹框
|
||||
defaultModel?: MODEL_TYPE; // 视频模式 | 图片模式
|
||||
onClose?: () => void; // 关闭弹框
|
||||
isLoading?: boolean; // 是否加载中
|
||||
hasPre?: boolean; // 向前翻页
|
||||
hasNext?: boolean; // 向后翻页
|
||||
selectIndex?: number; // 选中的数据(dataSource为数组情况下)
|
||||
onSelectIndexChange?: (i: number) => void; // 修改当前下标
|
||||
dataSource: BigImageData[]; // 数据1
|
||||
dataSources: BigImageData[]; // 数据2
|
||||
relatedData?: BigImageData[]; // 数据3
|
||||
transformPropFunc: (item: any) => ISelectItem; // 格式化数据方法
|
||||
transformVideoPropFunc: (
|
||||
item: ISelectItem
|
||||
) => Promise<Omit<VideoViewProps, 'screenshotButtonRender'>>; // 视频模式格式化数据方法
|
||||
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => React.ReactElement;
|
||||
showTool?: boolean; // 是否显示底部菜单
|
||||
showCarousel?: boolean; //
|
||||
imgViewProp?: Partial<ImgViewProps>; // 图片模式的配置
|
||||
videoViewProp?: Partial<VideoViewProps>; // 视频模式的配置
|
||||
ToolProps?: Partial<ToolProps>; // 底部菜单的配置
|
||||
nullDialogProp?: {
|
||||
emptyText?: string;
|
||||
}; // 暂无数据的配置
|
||||
showHeader?: boolean; // 是否显示 description
|
||||
tabsFilter?: TAB_TYPE[]; // tabs 过滤
|
||||
useVirtual?: boolean; // 是否显示虚拟
|
||||
loadNext?: (i: number) => Promise<void>; // 下一个
|
||||
loadPre?: (i: number) => Promise<void>; // 前一个
|
||||
children: React.ReactNode; // 子元素
|
||||
title?: string; // 标题
|
||||
specialTitle?: string; // 对比图模式下标题
|
||||
isRelated?: boolean;
|
||||
carouselProp?: Partial<CarouselProps>;
|
||||
}
|
||||
|
||||
|
||||
export interface ImageModalDataProps {
|
||||
targetData: BigImageData[]
|
||||
compactData: BigImageData[]
|
||||
}
|
||||
|
||||
export interface ModalAdapterConfigProps {
|
||||
oldMode?: boolean; // 是否是老模式
|
||||
}
|
||||
|
||||
/**
|
||||
* 兼容老数据格式
|
||||
* @param _data 老数据格式
|
||||
* @returns newData
|
||||
*/
|
||||
const translateOldImageData = (_data: IOldImageData) => {
|
||||
return {
|
||||
..._data,
|
||||
open: _data.visible,
|
||||
onCancel: _data.onClose
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 大图组件适配器,兼容老接口
|
||||
* @param Cmp 大图组件
|
||||
* @param config 额外配置
|
||||
* @returns 大图组件
|
||||
*/
|
||||
const adapter = (Cmp: any, config: ModalAdapterConfigProps): any => {
|
||||
const { oldMode = false } = config
|
||||
|
||||
return (props: IOldImageData) => {
|
||||
const newProps = oldMode ? translateOldImageData(props) : props
|
||||
console.log('adapter----适配数据', props, newProps)
|
||||
|
||||
// 该属性已经废弃
|
||||
delete newProps.visible
|
||||
|
||||
return (
|
||||
<Cmp
|
||||
{...newProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default adapter
|
36
packages/biz/src/BigImage/util/interface.ts
Normal file
36
packages/biz/src/BigImage/util/interface.ts
Normal file
@ -0,0 +1,36 @@
|
||||
export interface IBigImageModalData {
|
||||
imageKey?: string // 目标图
|
||||
imgSummary?: string // 大图
|
||||
flvUrl?: string // 视频链接
|
||||
compaterImages?: string[] // 对比图
|
||||
odRect?: { // od 框数据
|
||||
"x": number
|
||||
"y": number
|
||||
"w": number
|
||||
"h": number
|
||||
[key: string]: string | number; // 拓展参数
|
||||
}[],
|
||||
attachImg?: { // 小图,只有在场景图模式生效(人脸、形体)
|
||||
"url": string
|
||||
"label": string
|
||||
[key: string]: string
|
||||
}[],
|
||||
score?: number | string // 人脸质量分
|
||||
showScore?: boolean // 人脸质量分
|
||||
cameraPosition?: string // 摄像头位置
|
||||
time?: string // 摄像头拍摄时间
|
||||
objects: { // 拓展参数、可以自由支配
|
||||
objectIndex: {
|
||||
[key: string]: any
|
||||
},
|
||||
objectType: string
|
||||
sourceObjectId: string
|
||||
level: number
|
||||
confidence: number
|
||||
infoOnSource: {
|
||||
[key: string]: any
|
||||
},
|
||||
qualityScore: number
|
||||
[key: string]: any
|
||||
}[]
|
||||
}
|
@ -1,5 +1,7 @@
|
||||
export { default as BigImageModal } from './BigImageModal'
|
||||
export type { BigImageModalProps } from './BigImageModal'
|
||||
export { default as BigImage } from './BigImage'
|
||||
export type { BigImageProps, BigImageRef } from './BigImage'
|
||||
export { default as BoxSelectTree } from './boxSelectTree'
|
||||
export type { BoxSelectTreeProps } from './boxSelectTree'
|
||||
export { default as Tree } from './tree'
|
||||
|
1
packages/hooks/es/useSocket/index.d.ts
vendored
1
packages/hooks/es/useSocket/index.d.ts
vendored
@ -1 +0,0 @@
|
||||
export {};
|
1
packages/hooks/lib/useSocket/index.d.ts
vendored
1
packages/hooks/lib/useSocket/index.d.ts
vendored
@ -1 +0,0 @@
|
||||
export {};
|
@ -1,13 +1,16 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
plugins: ['father-plugin-less'],
|
||||
});
|
||||
|
@ -1,3 +0,0 @@
|
||||
.icon:hover {
|
||||
color: #6accca !important;
|
||||
}
|
@ -1,13 +1,16 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
plugins: ['father-plugin-less'],
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* Created by jiangzhixiong on 2024/05/21
|
||||
*/
|
||||
import { forwardRef, useImperativeHandle, useRef, } from 'react'
|
||||
import { forwardRef, useImperativeHandle, useRef, } from 'react'
|
||||
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||
import {
|
||||
DragCircleMode,
|
||||
@ -14,12 +14,11 @@ import drawRectMode from 'mapbox-gl-draw-rectangle-mode'
|
||||
// @ts-ignore
|
||||
import drawStaticMode from '@mapbox/mapbox-gl-draw-static-mode'
|
||||
// @ts-ignore
|
||||
import drawCircleMode from './Draw/drawCircleMode.draw.js'
|
||||
import drawCircleMode from './mode/drawCircleMode.draw.js'
|
||||
import { useControl } from 'react-map-gl';
|
||||
import type { ControlPosition } from 'react-map-gl';
|
||||
import { MapContextValue } from 'react-map-gl/dist/esm/components/map';
|
||||
|
||||
export type DrawControlProps = ConstructorParameters<typeof MapboxDraw>[0] & {
|
||||
export interface DrawControlProps extends MapboxDraw {
|
||||
position?: ControlPosition;
|
||||
onCreate?: (evt: {features: object[]}) => void;
|
||||
onUpdate?: (evt: {features: object[]; action: string}) => void;
|
||||
@ -38,6 +37,7 @@ export interface DrawControlRefProps {
|
||||
}
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, ref) => {
|
||||
const drawRef = useRef<DrawControlRefProps['drawer']>(null)
|
||||
|
||||
@ -45,12 +45,13 @@ const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, re
|
||||
() => {
|
||||
let draw = new MapboxDraw(
|
||||
{
|
||||
// @ts-ignore
|
||||
modes: {
|
||||
...MapboxDraw.modes,
|
||||
// draw_line_select: drawLineSelectMode,
|
||||
draw_rect: drawRectMode,
|
||||
drag_circle: DragCircleMode,
|
||||
draw_circle : drawCircleMode,
|
||||
draw_circle: drawCircleMode,
|
||||
direct_select: DirectMode,
|
||||
simple_select: SimpleSelectMode,
|
||||
static: drawStaticMode,
|
||||
@ -62,7 +63,7 @@ const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, re
|
||||
drawRef.current = draw
|
||||
return draw
|
||||
},
|
||||
(context: MapContextValue) => {
|
||||
(context: any) => {
|
||||
const { map } = context
|
||||
map.on('draw.create', e => props.onCreate?.(e));
|
||||
map.on('draw.update', e => props.onUpdate?.(e));
|
||||
@ -98,11 +99,4 @@ const DrawControl = forwardRef<DrawControlRefProps, DrawControlProps>((props, re
|
||||
return null;
|
||||
})
|
||||
|
||||
DrawControl.defaultProps = {
|
||||
onCreate: () => {},
|
||||
onUpdate: () => {},
|
||||
onDelete: () => {},
|
||||
|
||||
};
|
||||
|
||||
export default DrawControl
|
||||
|
24
packages/map/src/drawControl/mode/doubleClickZoom.js
Normal file
24
packages/map/src/drawControl/mode/doubleClickZoom.js
Normal file
@ -0,0 +1,24 @@
|
||||
const doubleClickZoom = {
|
||||
enable(ctx) {
|
||||
setTimeout(() => {
|
||||
if (
|
||||
!ctx.map ||
|
||||
!ctx.map.doubleClickZoom ||
|
||||
!ctx._ctx ||
|
||||
!ctx._ctx.store ||
|
||||
!ctx._ctx.store.getInitialConfigValue
|
||||
)
|
||||
return;
|
||||
if (!ctx._ctx.store.getInitialConfigValue('doubleClickZoom')) return;
|
||||
ctx.map.doubleClickZoom.enable();
|
||||
}, 0);
|
||||
},
|
||||
disable(ctx) {
|
||||
setTimeout(() => {
|
||||
if (!ctx.map || !ctx.map.doubleClickZoom) return;
|
||||
ctx.map.doubleClickZoom.disable();
|
||||
}, 0);
|
||||
},
|
||||
};
|
||||
|
||||
export default doubleClickZoom;
|
69
packages/map/src/drawControl/mode/drawCircleMode.draw.js
Normal file
69
packages/map/src/drawControl/mode/drawCircleMode.draw.js
Normal file
@ -0,0 +1,69 @@
|
||||
import MapboxDraw from '@mapbox/mapbox-gl-draw';
|
||||
import doubleClickZoom from './doubleClickZoom';
|
||||
import * as turf from '@turf/turf';
|
||||
const { circle, distance, helpers: turfHelpers } = turf;
|
||||
const drawCircleMode = { ...MapboxDraw.modes.draw_polygon };
|
||||
drawCircleMode.onSetup = function () {
|
||||
const polygon = this.newFeature({
|
||||
type: 'Feature',
|
||||
properties: {
|
||||
isCircle: true,
|
||||
center: [],
|
||||
},
|
||||
geometry: {
|
||||
type: 'Polygon',
|
||||
coordinates: [],
|
||||
},
|
||||
});
|
||||
|
||||
this.addFeature(polygon);
|
||||
|
||||
this.clearSelectedFeatures();
|
||||
doubleClickZoom.disable(this);
|
||||
// dragPan.disable(this);
|
||||
this.updateUIClasses({ mouse: 'add' });
|
||||
this.activateUIButton('Polygon');
|
||||
this.setActionableState({
|
||||
trash: true,
|
||||
});
|
||||
|
||||
return {
|
||||
polygon,
|
||||
currentVertexPosition: 0,
|
||||
};
|
||||
};
|
||||
drawCircleMode.onClick = drawCircleMode.onTap = function (state, e) {
|
||||
const currentCenter = state.polygon.properties.center;
|
||||
if (currentCenter.length === 0) {
|
||||
// dragPan.disable(this)
|
||||
state.polygon.properties.center = [e.lngLat.lng, e.lngLat.lat];
|
||||
} else {
|
||||
// dragPan.enable(this);
|
||||
return this.changeMode('simple_select', { featureIds: [state.polygon.id] });
|
||||
}
|
||||
};
|
||||
drawCircleMode.onDrag = drawCircleMode.onMouseMove = function (state, e) {
|
||||
const center = state.polygon.properties.center;
|
||||
if (center.length > 0) {
|
||||
const distanceInKm = distance(
|
||||
turfHelpers.point(center),
|
||||
turfHelpers.point([e.lngLat.lng, e.lngLat.lat]),
|
||||
{
|
||||
units: 'kilometers',
|
||||
}
|
||||
);
|
||||
const circleFeature = circle(center, distanceInKm);
|
||||
state.polygon.incomingCoords(circleFeature.geometry.coordinates);
|
||||
state.polygon.properties.radiusInKm = distanceInKm;
|
||||
state.polygon.properties.lastClickCoord = [e.lngLat.lng, e.lngLat.lat];
|
||||
}
|
||||
};
|
||||
//它决定当前 Drew 数据存储中的哪些特性将在地图上呈现。
|
||||
//所有传递给“显示”的特性都将被渲染,因此可以为每个内部特性传递多个显示特性。
|
||||
//有关如何制作显示特性的建议,请参阅‘ styling-pull’in‘ API.md’
|
||||
drawCircleMode.toDisplayFeatures = function (state, geojson, display) {
|
||||
const isActivePolygon = geojson.properties.id === state.polygon.id;
|
||||
geojson.properties.active = isActivePolygon ? 'true' : 'false';
|
||||
display(geojson);
|
||||
};
|
||||
export default drawCircleMode;
|
@ -1,13 +1,16 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
plugins: ['father-plugin-less'],
|
||||
});
|
||||
|
@ -1,13 +1,16 @@
|
||||
import { defineConfig } from 'father';
|
||||
import { defineConfig } from 'father-plugin-less';
|
||||
|
||||
export default defineConfig({
|
||||
// more father config: https://github.com/umijs/father/blob/master/docs/config.md
|
||||
esm: {
|
||||
output: 'es',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
cjs: {
|
||||
output: 'lib',
|
||||
ignores: ['**/demo/*', 'src/**/demo/*']
|
||||
ignores: ['**/demo/*', 'src/**/demo/*'],
|
||||
transformer: 'babel',
|
||||
},
|
||||
plugins: ['father-plugin-less'],
|
||||
});
|
||||
|
@ -1,51 +0,0 @@
|
||||
.zhst-image__btn-group {
|
||||
// display: flex;
|
||||
width: 30px;
|
||||
box-shadow: 0 2px 6px 0 rgb(0 0 0 / 40%);
|
||||
|
||||
&__item {
|
||||
display: flex;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #000;
|
||||
|
||||
&>button {
|
||||
padding: 0;
|
||||
color: #fff;
|
||||
|
||||
&:hover {
|
||||
color: #09f;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: #09f;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&>span {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&--active {
|
||||
&>button {
|
||||
color: #09f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&--circle {
|
||||
background-color: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
&--circle &__item {
|
||||
margin-bottom: 4px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
}
|
@ -1,54 +0,0 @@
|
||||
.zhst-image__img-view {
|
||||
position: relative;
|
||||
width: calc(100%);
|
||||
height: 100%;
|
||||
font-size: 0;
|
||||
|
||||
&__face-score {
|
||||
position: absolute;
|
||||
right: 20px;
|
||||
bottom: 80px;
|
||||
color: red;
|
||||
font-family: 'Microsoft YaHei';
|
||||
font-size: 19px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-opt {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&-crop-opt {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
&-align {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-main {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-size: 0;
|
||||
|
||||
&--cursor {
|
||||
& canvas {
|
||||
min-height: 320px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&-screenshot {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
}
|
@ -16,8 +16,12 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
var customizePrefixCls = props.prefixCls,
|
||||
_props$label = props.label,
|
||||
label = _props$label === void 0 ? '标题' : _props$label,
|
||||
_props$width = props.width,
|
||||
width = _props$width === void 0 ? '400' : _props$width,
|
||||
height = props.height,
|
||||
_props$openRoll = props.openRoll,
|
||||
openRoll = _props$openRoll === void 0 ? true : _props$openRoll,
|
||||
labelColor = props.labelColor,
|
||||
_props$url = props.url,
|
||||
url = _props$url === void 0 ? '' : _props$url,
|
||||
_props$score = props.score,
|
||||
@ -33,6 +37,7 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
getPrefixCls = _useContext.getPrefixCls;
|
||||
var componentName = getPrefixCls('image__compater-view', customizePrefixCls);
|
||||
var imgContainerRef = useRef(null);
|
||||
var containerRef = useRef(null);
|
||||
var imgInsRef = useRef(null);
|
||||
var _useState = useState(0),
|
||||
_useState2 = _slicedToArray(_useState, 2),
|
||||
@ -47,8 +52,10 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
setScale(get(data, 'scale', 0));
|
||||
});
|
||||
if (generateImg(url)) {
|
||||
console.log('containerRef', containerRef);
|
||||
imgInsRef.current = new Viewer(imgContainerRef.current, {
|
||||
image: generateImg(url)
|
||||
image: generateImg(url),
|
||||
height: parseInt(height)
|
||||
});
|
||||
}
|
||||
return function () {
|
||||
@ -74,9 +81,15 @@ var CompareImage = /*#__PURE__*/forwardRef(function (props, ref) {
|
||||
};
|
||||
});
|
||||
return /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "__container"))
|
||||
className: classNames("".concat(componentName, "__container")),
|
||||
style: {
|
||||
width: "".concat(parseInt(width), "px")
|
||||
}
|
||||
}, label && /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "__label"))
|
||||
className: classNames("".concat(componentName, "__label")),
|
||||
style: {
|
||||
backgroundColor: labelColor
|
||||
}
|
||||
}, label), !url ? /*#__PURE__*/React.createElement("div", {
|
||||
className: classNames("".concat(componentName, "__empty"))
|
||||
}, /*#__PURE__*/React.createElement("img", {
|
||||
|
@ -1,21 +0,0 @@
|
||||
.zhst-image__CornerScore {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
width: 56px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
text-align: right;
|
||||
padding-right: 1px;
|
||||
background-size: 100%;
|
||||
background-image: url('data: image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHAAAAAsCAYAAAC9rDzHAAAByUlEQVR4Xu2cO08DMRCEJy0tlNBCSwmU0EIJLbS0UEILLTX/Fo3kk1AUHrrsjB3dWIoUnZTdvfnOZ6+1mxXGGHsADgEcA9hvnyMAvJ7xiwKrjuoQ0HmDxu8ZMxToAZDQrgAE2gxg6z9xAjwFcAvgoCDumGgKuADeA7iI6vUKqAFyE/KU12U9uMmiGuBr4Ong0bIS4A2Aa234sa4CyFzuPfLqFVABfGg5nv4OFu5BAZAbl4+F62q7fQVAJul3tjtYuCMFwEcATNozDAooAL7ltMVATngS8+kLP54UMzAAjc9VABrFVrgKQIWqRpsBaBRb4SoAFaoabQagUWyFqwBUqGq0GYBGsRWuAlChqtFmABrFVrgKQIWqRpsBaBRb4SoAFaoabVYDZLU1K9EyTApUA2RzyrMp9rgRlBWylIIlFRkmBapnIIuZ0hJmgkc3lQBTzGQEN7mqApjNSwd4VTOQr8yXFDL1IbjtDOTMY/dR1r0+/LZaA1n7yb6/wOsEb+4rlMDYdZR0oSO4uZuYtEkPAO17CP9dA3nCwll3Mlj8iw/nL4ABN/gj8hPAgBsc3KY1kJuTs7Y5yV+B7BBA5nKXrSUsKcGOgJvC/ALSJBp5mBHCFAAAAABJRU5ErkJggg==');
|
||||
z-index: 99;
|
||||
|
||||
&>span {
|
||||
padding-right: 6px;
|
||||
line-height: 22px;
|
||||
font-size: 12px;
|
||||
vertical-align: middle;
|
||||
color: rgba(255, 255, 255, 100%);
|
||||
}
|
||||
}
|
@ -1,144 +0,0 @@
|
||||
.zhst-image__compater-view {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
&>div:first-child {
|
||||
margin-right: 25px;
|
||||
}
|
||||
|
||||
&>div:last-child {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
&__container {
|
||||
font-size: 0;
|
||||
position: relative;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
&__view {
|
||||
min-width: 345px;
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 34px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
// width: 48px;
|
||||
padding: 0 6px;
|
||||
background: #09f;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
&__tool {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f9f9f9;
|
||||
|
||||
i,
|
||||
span {
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
i {
|
||||
margin-right: 4px;
|
||||
}
|
||||
|
||||
&>*:not(:last-child) {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
&__scale {
|
||||
display: inline-block;
|
||||
width: 38px;
|
||||
height: 16px;
|
||||
|
||||
// margin-left: 15px;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid rgb(77 77 77 / 100%);
|
||||
background: rgb(255 255 255 / 100%);
|
||||
border-radius: 2px;
|
||||
color: #4d4d4d;
|
||||
cursor: default;
|
||||
font-size: 12px;
|
||||
line-height: 16px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&__line {
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background: #e6e6e6;
|
||||
}
|
||||
}
|
||||
|
||||
&__empty {
|
||||
position: absolute;
|
||||
z-index: 9;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: #f9f9f9;
|
||||
transform: translateY(-100%);
|
||||
|
||||
&>img {
|
||||
margin-bottom: 12px;
|
||||
width: 140px;
|
||||
height: 80px;
|
||||
}
|
||||
|
||||
&--text {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
}
|
||||
}
|
||||
|
||||
&__scoll-module {
|
||||
position: absolute;
|
||||
padding: 12px;
|
||||
bottom: 48px;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: flex-end;
|
||||
justify-content: space-between;
|
||||
pointer-events: none;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__btn {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
opacity: 0.4;
|
||||
pointer-events: all;
|
||||
|
||||
&>span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
}
|
||||
|
||||
&__btn:hover {
|
||||
opacity: 0.6;
|
||||
background-color: #09f !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
.zhst-image__video-view__player-mask {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgb(4 4 4 / 70%);
|
||||
|
||||
&--bg {
|
||||
z-index: 999;
|
||||
background-color: rgb(4 4 4 / 100%);
|
||||
}
|
||||
|
||||
i {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&-title {
|
||||
margin-top: 12px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
|
||||
& a {
|
||||
color: #09f;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.zhst-image__video-view__icon-wraper {
|
||||
display: flex;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: rgb(255 255 255 / 10%);
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
line-height: 80px;
|
||||
text-align: center;
|
||||
|
||||
// &:hover {
|
||||
// background: #0099ff;
|
||||
// }
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
.zhst-image__range {
|
||||
position: relative;
|
||||
|
||||
&--no-slider {
|
||||
.next-range-slider {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
& .next-range .next-range-track {
|
||||
height: 8px;
|
||||
margin-top: -4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
& .next-range .next-range-selected {
|
||||
height: 8px;
|
||||
margin-top: -4px;
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
& .next-range .next-range-slider-inner {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
border-color: #fff;
|
||||
margin-top: -7px;
|
||||
margin-left: -7px;
|
||||
background-color: #0098ff;
|
||||
}
|
||||
|
||||
& .next-range .next-range-slider {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
margin-top: -7px;
|
||||
margin-left: -7px;
|
||||
}
|
||||
|
||||
& .next-range.simulation-click>.next-range-slider-inner {
|
||||
border: 2px solid #fff !important;
|
||||
}
|
||||
|
||||
& .next-range .next-range-frag.next-range-active .next-range-slider .next-range-slider-inner {
|
||||
border: 2px solid #fff !important;
|
||||
}
|
||||
|
||||
& .next-range .next-range-slider.next-range-slider-moving .next-range-slider-inner {
|
||||
border: 2px solid #fff !important;
|
||||
}
|
||||
}
|
@ -1,73 +0,0 @@
|
||||
.zhst-image__video-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
background-color: #333;
|
||||
|
||||
// &-flv {
|
||||
// width: 85%;
|
||||
// }
|
||||
&-screenshot {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
&-crop-container {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&-align {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
&-opt {
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 32px;
|
||||
box-sizing: border-box;
|
||||
align-items: center;
|
||||
padding: 0 12px 0 24px;
|
||||
background-color: rgb(0 0 0 / 80%);
|
||||
line-height: 32px;
|
||||
|
||||
&>div:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-right: 12px;
|
||||
}
|
||||
|
||||
&>div:last-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin-left: 12px;
|
||||
}
|
||||
|
||||
&-range {
|
||||
display: flex;
|
||||
height: 32px;
|
||||
flex: 1;
|
||||
align-items: center;
|
||||
line-height: 32px;
|
||||
text-align: center;
|
||||
|
||||
&>div:first-child {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
&>div:last-child {
|
||||
width: 100px;
|
||||
margin-left: 8px;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -9,6 +9,7 @@ export { default as VideoPlayer } from "./VideoPlayer";
|
||||
// antd
|
||||
export { default as Tabs } from "./tabs";
|
||||
export { default as Tree } from "./tree";
|
||||
export { default as Spin } from "./spin";
|
||||
export { default as message } from "./message";
|
||||
export { default as Button } from "./button";
|
||||
export { default as Image } from "./image";
|
||||
|
@ -17,6 +17,9 @@ export interface CompareImageProps {
|
||||
* @default "默认值"
|
||||
*/
|
||||
label?: string;
|
||||
labelColor?: string;
|
||||
width?: string;
|
||||
height?: string
|
||||
showTools?: boolean;
|
||||
prefixCls?: string;
|
||||
openRoll?: boolean; //开启翻页
|
||||
@ -39,7 +42,10 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
label = '标题',
|
||||
width = '400',
|
||||
height,
|
||||
openRoll = true,
|
||||
labelColor,
|
||||
url = '',
|
||||
score = 0,
|
||||
preDisable,
|
||||
@ -69,11 +75,10 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
|
||||
}
|
||||
);
|
||||
|
||||
if (generateImg(url)) {
|
||||
imgInsRef.current = new Viewer(imgContainerRef.current, {
|
||||
image: generateImg(url),
|
||||
});
|
||||
}
|
||||
imgInsRef.current = new Viewer(imgContainerRef.current, {
|
||||
image: url,
|
||||
height: parseInt(height!),
|
||||
});
|
||||
|
||||
return () => {
|
||||
handleTransformChange?.remove();
|
||||
@ -96,8 +101,8 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className={classNames(`${componentName}__container`)}>
|
||||
{label && <div className={classNames(`${componentName}__label`)}>{label}</div>}
|
||||
<div className={classNames(`${componentName}__container`)} style={{ width: `${parseInt(width)}px` }}>
|
||||
{label && <div className={classNames(`${componentName}__label`)} style={{ backgroundColor: labelColor }}>{label}</div>}
|
||||
{!url ? (
|
||||
<div className={classNames(`${componentName}__empty`)}>
|
||||
<img
|
||||
@ -121,7 +126,6 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
|
||||
style={{ width: '56px' }}
|
||||
icon={<IconFont icon="icon-qiehuanzuo" size={32} color='#fff' />}
|
||||
>
|
||||
|
||||
</Button>
|
||||
<Button
|
||||
className={classNames(`${componentName}__scoll-module__btn`)}
|
||||
@ -159,7 +163,6 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
|
||||
<span className={classNames(`${componentName}__tool__scale`)}>
|
||||
{Math.round(scale * 100) + '%'}
|
||||
</span>
|
||||
<div className={classNames(`${componentName}__tool__line`)}></div>
|
||||
{/* </Button> */}
|
||||
<Button
|
||||
type="text"
|
||||
|
@ -1,7 +1,7 @@
|
||||
.zhst-image__CornerScore {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
bottom: 36px;
|
||||
width: 56px;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
|
@ -13,7 +13,7 @@ export const CornerScore: React.FC<ScoreProps> = (props) => {
|
||||
return useMemo(
|
||||
() => (
|
||||
<div className={classNames(`${componentName}`)}>
|
||||
<span>{~~(scoreTxt * 100)}%</span>
|
||||
<span>{~~(scoreTxt)}%</span>
|
||||
</div>
|
||||
),
|
||||
[scoreTxt]
|
||||
|
@ -19,39 +19,36 @@
|
||||
border: 1px solid #f0f0f0;
|
||||
}
|
||||
|
||||
&__view {
|
||||
min-width: 345px;
|
||||
min-height: 450px;
|
||||
}
|
||||
|
||||
&__label {
|
||||
padding: 4px 8px;
|
||||
position: absolute;
|
||||
z-index: 99;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
display: flex;
|
||||
font-size: 16px;
|
||||
height: 34px;
|
||||
font-size: 14px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
// width: 48px;
|
||||
padding: 0 6px;
|
||||
background: #09f;
|
||||
background: #52ACFA;
|
||||
color: #fff;
|
||||
border-bottom-left-radius: 8px;
|
||||
}
|
||||
|
||||
&__tool {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
justify-content: center;
|
||||
background: #f9f9f9;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
|
||||
i,
|
||||
span {
|
||||
color: #333 !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
i {
|
||||
@ -63,14 +60,12 @@
|
||||
}
|
||||
|
||||
&__scale {
|
||||
padding: 2px 14px;
|
||||
display: inline-block;
|
||||
width: 38px;
|
||||
height: 16px;
|
||||
|
||||
// margin-left: 15px;
|
||||
box-sizing: content-box;
|
||||
border: 1px solid rgb(77 77 77 / 100%);
|
||||
background: rgb(255 255 255 / 100%);
|
||||
border: 1px solid #fff;
|
||||
border-radius: 2px;
|
||||
color: #4d4d4d;
|
||||
cursor: default;
|
||||
|
@ -72,6 +72,7 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
|
||||
const {
|
||||
prefixCls: customizePrefixCls,
|
||||
url,
|
||||
height = 0,
|
||||
odList,
|
||||
selectedItem,
|
||||
onMouseDown,
|
||||
@ -115,7 +116,8 @@ const CropperImage = forwardRef<CropperImageRefProps, CropperImageProps>((props,
|
||||
image: url,
|
||||
scaleAble,
|
||||
selectAble,
|
||||
height: 600,
|
||||
// @ts-ignore
|
||||
height: parseInt(height),
|
||||
fitScaleAsMinScale: true,
|
||||
dragAble: false,
|
||||
});
|
||||
|
@ -80,5 +80,3 @@ demo:
|
||||
| strokeWidth | 仪表盘进度条线的宽度,单位是进度条画布宽度的百分比 | number | 6 | - |
|
||||
|
||||
## 主题变量(Design Token)
|
||||
|
||||
<ComponentTokenTable component="Progress"></ComponentTokenTable>
|
||||
|
@ -27,7 +27,7 @@ const RelatedCarousel: FC<RelatedCarouselProps> = (_props: any) => {
|
||||
onItemSelected,
|
||||
label,
|
||||
onClick,
|
||||
width = '742px',
|
||||
width = '100%',
|
||||
height = '100px',
|
||||
selectedKey: defaultSelectedKey
|
||||
} = _props
|
||||
|
@ -25,6 +25,8 @@ module.exports = __toCommonJS(src_exports);
|
||||
var import_antd = require("antd");
|
||||
var import_func = require("@zhst/func");
|
||||
var Slave = class {
|
||||
config;
|
||||
authTokenDefine;
|
||||
// 设置参数
|
||||
constructor() {
|
||||
this.authTokenDefine = "ZHST_AUTH_TOKEN";
|
||||
|
@ -4,6 +4,7 @@
|
||||
"declaration": true,
|
||||
"skipLibCheck": true,
|
||||
"esModuleInterop": true,
|
||||
"declarationMap": true,
|
||||
"composite": true,
|
||||
"jsx": "react",
|
||||
"baseUrl": "./",
|
||||
@ -12,9 +13,9 @@
|
||||
"@zhst/*": ["packages/*/src/"]
|
||||
},
|
||||
"importHelpers": false,
|
||||
"sourceMap": true,
|
||||
"strictNullChecks": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowJs": true,
|
||||
"jsxFactory": "React.createElement",
|
||||
"jsxFragmentFactory": "React.Fragment",
|
||||
"noUnusedParameters": true,
|
||||
|
Loading…
Reference in New Issue
Block a user