feat: 大图初稿

This commit is contained in:
NICE CODE BY DEV 2024-01-17 19:25:13 +08:00
parent b42ae38eb2
commit 1fdceb89b1
23 changed files with 546 additions and 466 deletions

View File

@ -1,11 +1,14 @@
// @ts-nocheck // @ts-nocheck
import React, { useRef, useState } from 'react' import React, { useRef, useState } from 'react'
import { Descriptions, Modal, Tabs } from 'antd'; import { ConfigProvider, Descriptions, Modal, Tabs, Button, BigImagePreview } from '@zhst/meta';
import classNames from 'classnames' import classNames from 'classnames'
import type { ModalProps, DescriptionsProps, TabsProps } from 'antd' import type { ModalProps, DescriptionsProps, TabsProps } from '@zhst/meta'
import { get } from '@zhst/func'; import { get } from '@zhst/func';
import { MODEL_TYPE, TAB_TYPE } from '@zhst/types';
import './index.less' import './index.less'
import Navigation from './components/navigation'; import Navigation from './components/navigation';
import CombineImage from './components/CombineImage'
import { BIG_IMAGE_DATA } from './mock'
const DescriptionsItem = Descriptions.Item const DescriptionsItem = Descriptions.Item
@ -21,12 +24,14 @@ export interface BigImageModalProps extends ModalProps {
} }
tabsConfig: { // 导航栏配置 tabsConfig: { // 导航栏配置
data: Pick<TabsProps, 'items'> & { data: Pick<TabsProps, 'items'> & {
key: 'NORMAL' | 'COMPATER' | 'TRACK' key: TAB_TYPE
} // 导航栏列表 } // 导航栏列表
} }
dataSource: any dataSource: any
imageData: any imageData: any
relatedData: any relatedData: any
mode?: MODEL_TYPE
changeMode?: (mode: MODEL_TYPE) => void
} }
const initialStyle ={ const initialStyle ={
@ -42,35 +47,52 @@ const BigImageModal: React.FC<BigImageModalProps> = (props) => {
descriptionConfig = { descriptionConfig = {
data: [] data: []
}, },
tabsConfig = { dataSource = [],
data: [ imageData = [],
relatedData = [],
mode = 'IMAGE',
changeMode
} = props
const tabsConfig = {
data: [
{ {
label: '对比图模式', label: '对比图模式',
key: '1', key: '1',
children: '对比图组件', children: (
<CombineImage
targetData={dataSource}
compareData={dataSource}
/>
)
}, },
{ {
label: '场景图模式', label: '场景图模式',
key: '2', key: '2',
children: '场景图组件', children: (
<BigImagePreview
height={'500px'}
dataSource={BIG_IMAGE_DATA}
/>
)
} }
], ]
}, }
dataSource = [],
imageData = [],
relatedData = [],
} = props
const showCropRef = useRef(false); const showCropRef = useRef(false);
const scaleRef = useRef(0); const scaleRef = useRef(0);
// ========================== 头切换 ========================= // ========================== 头切换 =========================
const [activeKey, setActiveKey] = useState<string>(get(tabsConfig, 'data[0].key')); const [tab, setTab] = useState<TAB_TYPE>(get(tabsConfig, 'data[0].key'));
const [activeKey, setActiveKey] = useState<string>('related');
// ========================= 预览切换下标 ========================= // ========================= 预览切换下标 =========================
const [previewIndex, setPreviewIndex] = useState<number>(0) const [previewIndex, setPreviewIndex] = useState<number>(0)
const [isRelated, setIsRelated] = useState<number>(false) const [isRelated, setIsRelated] = useState<number>(false)
// ========================= 模式切换 ============================
const [currentMode, setCurrentMode] = useState(mode)
return ( return (
<Modal <Modal
destroyOnClose destroyOnClose
@ -80,39 +102,49 @@ const BigImageModal: React.FC<BigImageModalProps> = (props) => {
title={title} title={title}
{...props} {...props}
> >
{descriptionConfig.data.map(descriptions => ( <ConfigProvider
<Descriptions theme={{
key={descriptions.title} token: {
title={ colorTextSecondary: 'rgba(0,0,0,0.45)'
<p style={{ margin: '12px 0 0', fontSize: initialStyle.fontSize }}> },
{descriptions.title} components: {
</p> Descriptions: {
} titleMarginBottom: '20px',
column={8} viewBg: '#f6f6f6',
style={{ padding: '0 64px' }} titleColor: 'rgba(0,0,0,0.45)',
> colorTextLabel: 'rgba(0,0,0,0.45)',
{descriptions?.children?.map(item => ( contentColor: 'rgba(0,0,0,0.88)',
<DescriptionsItem },
key={item.key} },
label={item.label} }}
span={1} >
contentStyle={{ fontSize: initialStyle.fontSize }} {descriptionConfig.data.map(descriptions => (
labelStyle={{ fontSize: initialStyle.fontSize }} <Descriptions
>{item.children}</DescriptionsItem> key={descriptions.title}
))} title={
</Descriptions> <p style={{ margin: '12px 0 0', fontSize: initialStyle.fontSize }}>
))} {descriptions.title}
<Tabs </p>
defaultActiveKey={activeKey} }
centered column={8}
tabBarStyle={{ fontSize: '18px' }} style={{ padding: '0 64px' }}
items={tabsConfig.data} >
{...tabsConfig} {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 <div
className={classNames(`${componentPrefix}-view-container`)} className={classNames(`${componentPrefix}-view-container`)}
style={ style={
activeKey === 'TRACK' tab === 'TRACK'
? { ? {
height: '718px', height: '718px',
marginBottom: '0px', marginBottom: '0px',
@ -120,8 +152,17 @@ const BigImageModal: React.FC<BigImageModalProps> = (props) => {
: {} : {}
} }
> >
<Tabs
activeKey={tab}
centered
onChange={v => setTab(v)}
tabBarStyle={{ fontSize: '18px', fontWeight:'bold' }}
items={tabsConfig.data}
{...tabsConfig}
/>
{/* 切换按钮组件 */}
{ {
activeKey !== 'TRACK' && ( tab !== 'TRACK' && (
<> <>
{/* ----------------------------------- 上一张按钮 ---------------------------------- */} {/* ----------------------------------- 上一张按钮 ---------------------------------- */}
<Navigation <Navigation
@ -154,6 +195,26 @@ const BigImageModal: React.FC<BigImageModalProps> = (props) => {
</> </>
) )
} }
{/* --------------------------------- 模型碰撞组件 --------------------------------- */}
{isRelated && tab !== 'TRACK' && (
<div className="relatedWrapper">
<Tabs
className="relatedTabs"
tabPosition={'left'}
activeKey={activeKey}
onChange={(key: string) => {
setActiveKey(key);
}}
items={tabList.map((item) => {
return {
label: item.label,
key: item.key,
children: item.children,
};
})}
/>
</div>
)}
</div> </div>
</Modal> </Modal>
) )

View File

@ -0,0 +1,28 @@
import React, { FC } from 'react';
import { CompareImage, Flex, Score } from '@zhst/meta'
interface ComBineImageProps {
targetData: {
url: string;
score: number;
}[]
compareData: {
url: string;
score: number
}[]
}
const ComBineImage: FC<ComBineImageProps> = (props) => {
const { targetData = [], compareData = [] } = props
return (
<Flex justify='space-evenly' align='center' style={{ padding:'0 32px' }}>
<CompareImage dataSource={targetData} label="目标图" />
<Score score={0.2} />
<CompareImage dataSource={compareData} openRoll={false} label="对比图" />
</Flex>
)
}
export default ComBineImage

View File

@ -0,0 +1,66 @@
import React from 'react';
import { BigImageModal } from '@zhst/biz'
import { DescriptionsProps } from '@zhst/meta'
import { IMAGE_DATA, BIG_IMAGE_DATA } from '../mock'
import { bigImageModalAdapter } from '@zhst/biz'
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: '否',
},
]
}
];
export default () => {
const imageDataAdapter = bigImageModalAdapter(IMAGE_DATA)
console.log(imageDataAdapter)
return (
<BigImageModal
title="查看大图"
open
dataSource={IMAGE_DATA.dataSource}
imageData={IMAGE_DATA.dataSource}
width={1098}
descriptionConfig={{ data: descriptionList }}
/>
)
}

View File

@ -1,5 +1,4 @@
.zhst-image { .zhst-image {
.zhst-dialog-content { .zhst-dialog-content {
box-shadow: 0 4px 12px rgb(0 0 0 / 20%); box-shadow: 0 4px 12px rgb(0 0 0 / 20%);
} }
@ -8,7 +7,6 @@
&-view-container { &-view-container {
position: relative; position: relative;
width: 100%; width: 100%;
height: 532px;
margin-bottom: 16px; margin-bottom: 16px;
&__nav { &__nav {
@ -227,232 +225,6 @@
} }
} }
.zhst-image__header {
width: 100%;
// margin-top: 3px;
margin-bottom: 10px;
&__pad0 {
padding: 0;
}
&__pad66 {
padding: 0 66px;
}
&__bar {
display: flex;
width: 100%;
background: #f6f6f6;
// box-shadow: 0px 0px 8px 0px rgba(172, 172, 172, 0.5);
justify-content: center;
// border-color: #f0f0f0;
// border-bottom-width: 1px;
// border-bottom-style: solid;
}
&__barNoColor {
display: flex;
width: 100%;
justify-content: center;
border-color: #f0f0f0;
border-bottom-width: 1px;
border-bottom-style: solid;
}
&__item {
position: relative;
display: flex;
height: 40px;
align-items: center;
justify-content: center;
margin: 0 15px;
color: #999;
cursor: pointer;
font-size: 14px;
font-weight: bold;
line-height: 19px;
transition: font-size 0.3s ease;
&:hover {
// font-size: 18px;
color: #333;
}
&::before {
position: absolute;
bottom: 0;
left: 50%;
width: 0;
border-bottom: 2px solid #09f;
content: '';
transition: all 0.3s ease;
}
&--active {
background-color: transparent;
color: #333;
font-size: 18px;
// color: #0099ff;
&::before {
left: 0;
width: 100%;
}
}
}
}
.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 {
position: relative;
width: 345px;
height: 460px;
box-sizing: content-box;
border: 1px solid #f0f0f0;
}
&__view {
width: 345px;
height: 460px;
}
&__label {
position: absolute;
z-index: 99;
top: 0;
left: 0;
display: flex;
height: 34px;
align-items: center;
justify-content: center;
// width: 48px;
padding: 0 6px;
background: #09f;
color: #fff;
}
&__tool {
display: flex;
width: 345px;
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 {
width: 140px;
height: 80px;
}
&--text {
color: #999;
font-size: 14px;
line-height: 22px;
}
}
&__scoll-module {
position: absolute;
top: 0%;
left: 0%;
display: flex;
width: 100%;
height: 100%;
align-items: flex-end;
justify-content: space-between;
pointer-events: none;
&__btn {
display: flex;
width: 50px;
height: 50px;
align-items: center;
justify-content: center;
margin: 6px;
border-radius: 50%;
opacity: 0.5;
pointer-events: all;
&>span {
display: flex;
align-items: center;
justify-content: center;
}
}
&__btn:hover {
background-color: #09f !important;
color: #fff !important;
}
}
}
.zhst-image__trackmodel { .zhst-image__trackmodel {
&__panel { &__panel {
position: relative; position: relative;
@ -645,23 +417,6 @@
} }
} }
.zhst-image__null {
display: flex;
height: 100%;
flex-direction: column;
align-items: center;
justify-content: center;
&__text {
// margin-left: 105px;
margin-top: 8px;
color: #999;
font-size: 14px;
width: 100%;
text-align: center;
}
}
.zhst-image__attributePanel { .zhst-image__attributePanel {
margin: 0 66px; margin: 0 66px;
background: #f6f6f6; background: #f6f6f6;
@ -710,45 +465,27 @@
.relatedContent { .relatedContent {
width: 100%; width: 100%;
height: 100px; height: 100px;
display: flex; display: flex;
.relatedPics { .relatedPics {
width: 742px; width: 742px;
height: 100px; height: 100px;
// display: flex;
// box-sizing: border-box;
// background: #fafafa;
// border-radius: 2px;
// border: 1px solid #f0f0f0;
// .LeftBtn,
// .RighttBtn {
// width: 34px;
// height: 100%;
// display: flex;
// justify-content: center;
// align-items: center;
// }
// .ListContent {
// flex: 1;
// height: 100%;
// }
} }
.disabled { .disabled {
color: rgba(0, 0, 0, 0.25); color: rgba(0, 0, 0, 25%);
} }
.relatedBtn { .relatedBtn {
flex: 1; flex: 1;
font-size: 14px; font-size: 14px;
color: #333333; color: #333;
display: flex; display: flex;
align-items: flex-end; align-items: flex-end;
cursor: pointer; cursor: pointer;
&:hover { &:hover {
color: #0099ff; color: #09f;
} }
} }
} }

View File

@ -9,68 +9,5 @@ group:
# 大图弹框 # 大图弹框
```jsx <code src="./demo/index.tsx">基本</code>
import React from 'react';
import { Button } from 'antd'
import { BigImageModal } from '@zhst/biz'
import { DescriptionsProps } from '@zhst/biz'
import { IMAGE_DATA } from './mock.ts'
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: '否',
},
]
}
];
export default () => {
console.log(IMAGE_DATA)
return (
<BigImageModal
title="查看大图"
open
dataSource={IMAGE_DATA.dataSource}
imageData={IMAGE_DATA.dataSource}
width={1098}
descriptionConfig={{ data: descriptionList }}
/>
)
}
```

View File

@ -900,3 +900,152 @@ export const IMAGE_DATA = {
}, },
"specialTitle": "" "specialTitle": ""
} }
export const BIG_IMAGE_DATA = [
{
imageKey: 'http://10.0.0.120:30003/file/singer-20240110/1/5/1744894622934503424.jpg',
odRect:{
"x":0.5445312,
"y":0.19166666,
"w":0.08671875,
"h":0.40138888
},
attachImg: [
{
"url": "http://10.0.0.120:30003/file/singer-20240110/1/5/1744894622695428096.jpg","label": "形体"
},{
"url": "http://10.0.0.120:30003/file/singer-20240110/1/5/1744894588427964418.jpg",
"label": "人脸"
}
],
score: '0.6', // 人脸质量分
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,
}
]
},
{
imageKey: 'http://10.0.0.120:30003/file/singer-20240115/1/9/1746795581994436608.jpg',
odRect:{
"x":0.553125,"y":0.29722223,"w":0.048958335,"h":0.2462963
},
attachImg: [
{
"url": "http://10.0.0.120:30003/file/singer-20240115/1/9/1746795581163964416.jpg","label": "形体"
},{
"url": "http://10.0.0.120:30003/file/singer-20240115/1/9/1746795546867140608.jpg",
"label": "人脸"
}
],
score: 0.815207, // 人脸质量分
showScore: true, // 人脸质量分
cameraPosition: 'string', // 摄像头位置
time: '2022-01-01', // 摄像头拍摄时间
objects: [
{
"objectIndex": {
"objectId": "1746816737430472704",
"solutionId": "0",
"deviceId": "0",
"fragmentId": "0"
},
"objectType": "OBJECT_TYPE_PEDESTRAIN",
"sourceObjectId": "0",
"frameInfo": {
"frameId": "0",
"frameTimestamp": "1705308539109",
"width": 0,
"height": 0,
"originWidth": 0,
"originHeight": 0,
"offsetTime": "0",
"skipNumber": "0"
},
"infoOnSource": {
"bboxInFrame": {
"bboxRatio": {
"x": 0.5519352,
"y": 0.2965385,
"w": 0.05185461,
"h": 0.24698898
},
},
"countInSource": 0,
"indexInSource": 0
},
"qualityScore": 0,
},
{
"objectIndex": {
"objectId": "1746816737430472705",
"solutionId": "0",
"deviceId": "0",
"fragmentId": "0"
},
"objectType": "OBJECT_TYPE_PEDESTRAIN",
"sourceObjectId": "0",
"level": 0,
"confidence": 0.9310699,
"frameInfo": {
"frameId": "0",
"frameTimestamp": "1705308539109",
"width": 0,
"height": 0,
"originWidth": 0,
"originHeight": 0,
"offsetTime": "0",
"skipNumber": "0"
},
"infoOnSource": {
"bboxInFrame": {
"bboxRatio": {
"x": 0.58543766,
"y": 0.3203356,
"w": 0.052037954,
"h": 0.2664015
},
},
"countInSource": 0,
"indexInSource": 0
},
"qualityScore": 0,
}
]
}
]

View File

@ -2,44 +2,12 @@
* *
*/ */
import React from 'react'; import React from 'react';
import { AlgorithmVersionStr, HumanProperty, ObjectType, Rect, ViewOption, AlignType, IScreenshotButtonProp, ODRECT } from '@zhst/types' 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 TAB_TYPE = 'COMPATER' | 'NORMAL' | 'TRACK';
export type MODEL_TYPE = 'VIDEO' | 'IMAGE'; export type MODEL_TYPE = 'VIDEO' | 'IMAGE';
export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
imageKey: string; //不在监听url变化 更新走销毁
odRect: ODRECT;
attachImg?: Array<{ label: string; url: string }>;
showAttachImgLabel: boolean;
/* 截图渲染 */
screenshotButtonAlign: AlignType;
screenshotButtonRender: (screenshotButtonProp: IScreenshotButtonProp) => React.ReactElement;
/* 可观测值 */
scale$?: number;
showCrop$?: boolean;
hideLeftTopBtn?: boolean;
score?: number;
viewOption?: ViewOption;
}
export interface VideoViewProps {
/* 播放地址 */
flvUrl: string;
/* 播放总时间 */
maxDuration?: number;
/* 截图渲染 */
screenshotButtonAlign?: AlignType;
screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => React.ReactElement;
/* 默认截图框 */
defautlNormalizationRect?: Rect;
/* 截图回调 */
onCropChange?: (showCrop: boolean, normalizationRect: null | Rect) => void;
/* 可观测值 */
showCrop$?: boolean;
}
export interface CarouselProps { export interface CarouselProps {
hasPre?: boolean; hasPre?: boolean;
hasNext?: boolean; hasNext?: boolean;
@ -60,21 +28,6 @@ export interface HeaderProps {
tabsFilter: TAB_TYPE[]; tabsFilter: TAB_TYPE[];
} }
export interface ImgViewRef {
/* 图片实例 */
imgInsRef: React.MutableRefObject<any>;
/* 切换图片模式 */
setShowCrop: React.Dispatch<React.SetStateAction<boolean>>;
}
export interface VideoViewRef {
/* 当前图片模式 */
cropAble: boolean;
setShowCrop: React.Dispatch<React.SetStateAction<boolean>>;
downloadVideoframe: () => void;
}
export interface ParamProps { export interface ParamProps {
tab: string; tab: string;
selectItem: ISelectItem; selectItem: ISelectItem;
@ -134,9 +87,9 @@ interface IOldImageData {
hasNext?: boolean; hasNext?: boolean;
selectIndex?: number; selectIndex?: number;
onSelectIndexChange?: (i: number) => void; onSelectIndexChange?: (i: number) => void;
dataSource: any[]; dataSource: BigImageData[];
dataSources: any[]; dataSources: BigImageData[];
relatedData?: any[]; relatedData?: BigImageData[];
transformPropFunc: (item: any) => ISelectItem; transformPropFunc: (item: any) => ISelectItem;
transformVideoPropFunc: ( transformVideoPropFunc: (
item: ISelectItem item: ISelectItem
@ -170,8 +123,18 @@ export interface ToolProps {
disableVideo: boolean; disableVideo: boolean;
} }
export default (data: IOldImageData) => { export interface ImageModalDataProps {
const newData = data targetData: []
compactData: []
return newData
} }
const adapter = (data: IOldImageData): ImageModalDataProps => {
return {
targetData: [],
compactData: [],
}
}
export default adapter

View File

@ -1 +1 @@
export { default as BigImageModalAdapter } from './BigImageModalAdapter' export { default as bigImageModalAdapter } from './bigImageModalAdapter'

View File

@ -47,17 +47,17 @@ export interface ImgViewProps extends React.HTMLAttributes<HTMLElement> {
time?: string | number time?: string | number
objects: any[] objects: any[]
}> }>
showAttachImgLabel: boolean; // 是否显示缩略图 showAttachImgLabel?: boolean; // 是否显示缩略图
showOpt: boolean; // 是否显示操作面板 showOpt?: boolean; // 是否显示操作面板
width?: string | number; // 画布宽度 width?: string | number; // 画布宽度
height?: string | number; // 画布高度 height?: string | number; // 画布高度
/* 截图渲染 */ /* 截图渲染 */
screenshotButtonAlign: AlignType; screenshotButtonAlign?: AlignType;
screenshotButtonRender: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement; screenshotButtonRender?: (screenshotButtonProp: IScreenshotButtonProp) => ReactElement;
hideLeftTopBtn?: boolean; hideLeftTopBtn?: boolean;
showScore?: boolean // 是否显示相似度 showScore?: boolean // 是否显示相似度
viewOption?: ViewOption; viewOption?: ViewOption;
objects: IOdRectOrigin[] // 图片人物框选 objects?: IOdRectOrigin[] // 图片人物框选
} }
export interface ImgViewRef { export interface ImgViewRef {
/* 图片实例 */ /* 图片实例 */

View File

@ -1,5 +1,5 @@
import BigImagePreview from './BigImagePreview' import BigImagePreview from './BigImagePreview'
export type { ImgViewProps } from './BigImagePreview' export type { ImgViewProps, ImgViewRef } from './BigImagePreview'
export default BigImagePreview export default BigImagePreview

View File

@ -15,14 +15,14 @@ export interface CompareImageProps {
* @description * @description
* @default "默认值" * @default "默认值"
*/ */
label: string; label?: string;
openRoll?: boolean; //开启滚动模式 openRoll?: boolean; //开启翻页
dataSource?: Array<{ dataSource?: Array<{
url: string; url: string;
score: number; score: number | string;
}>; }>;
showScore?: boolean; // 是否展示相似度 showScore?: boolean; // 是否展示相似度
current: number; // 当前图片下标 current?: number; // 当前图片下标
} }
export interface CompareImageRefProps { export interface CompareImageRefProps {
@ -31,7 +31,7 @@ export interface CompareImageRefProps {
// 对比图组件 // 对比图组件
const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props, ref) => { const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props, ref) => {
const { label, openRoll = false, dataSource = [], showScore = true, current = 0 } = props; const { label = '标题', openRoll = true, dataSource = [], showScore = true, current = 0 } = props;
const imgContainerRef = useRef(null); const imgContainerRef = useRef(null);
const imgInsRef = useRef<any>(null); const imgInsRef = useRef<any>(null);
const [scale, setScale] = useState(0); const [scale, setScale] = useState(0);
@ -40,6 +40,8 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
// 初始化页面 // 初始化页面
useEffect(() => { useEffect(() => {
if (!dataSource?.length) return
const handleTransformChange = addEventListenerWrapper( const handleTransformChange = addEventListenerWrapper(
imgContainerRef.current, imgContainerRef.current,
'viewer-transform-change', 'viewer-transform-change',
@ -87,6 +89,8 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
handleIndexChange handleIndexChange
})); }));
if (!dataSource) return null
return ( return (
<div className={classNames(`${componentName}__container`)}> <div className={classNames(`${componentName}__container`)}>
<div className={classNames(`${componentName}__label`)}>{label}</div> <div className={classNames(`${componentName}__label`)}>{label}</div>
@ -125,7 +129,7 @@ const CompareImage = forwardRef<CompareImageRefProps, CompareImageProps>((props,
</Button> </Button>
</div> </div>
)} )}
{showScore && <CornerScore scoreTxt={dataSource[currentIndex].score} />} {showScore && <CornerScore scoreTxt={dataSource[currentIndex]?.score || 0} />}
<div className={classNames(`${componentName}__tool`)}> <div className={classNames(`${componentName}__tool`)}>
<Button <Button
type="text" type="text"

View File

@ -14,8 +14,6 @@
&__container { &__container {
position: relative; position: relative;
width: 345px;
height: 460px;
box-sizing: content-box; box-sizing: content-box;
border: 1px solid #f0f0f0; border: 1px solid #f0f0f0;
} }
@ -99,6 +97,7 @@
transform: translateY(-100%); transform: translateY(-100%);
&>img { &>img {
margin-bottom: 12px;
width: 140px; width: 140px;
height: 80px; height: 80px;
} }

View File

@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import type { DescriptionsProps, RadioChangeEvent } from 'antd'; import type { DescriptionsProps, RadioChangeEvent } from '@zhst/meta';
import { Button, ConfigProvider, Descriptions, Radio } from 'antd'; import { Button, ConfigProvider, Descriptions, Radio } from '@zhst/meta';
const borderedItems: DescriptionsProps['items'] = [ const borderedItems: DescriptionsProps['items'] = [
{ {
@ -98,11 +98,14 @@ const App: React.FC = () => {
return ( return (
<ConfigProvider <ConfigProvider
theme={{ theme={{
token: {
colorTextSecondary: 'rgba(0,0,0,0.45)'
},
components: { components: {
Descriptions: { Descriptions: {
labelBg: '#f6f6f6', viewBg: '#f6f6f6',
titleColor: 'rgba(0,0,0,0.88)', titleColor: 'rgba(0,0,0,0.45)',
colorTextLabel: 'rgba(0,0,0,0.88)', colorTextLabel: 'rgba(0,0,0,0.45)',
titleMarginBottom: 2, titleMarginBottom: 2,
itemPaddingBottom: 8, itemPaddingBottom: 8,
colonMarginRight: 10, colonMarginRight: 10,

View File

@ -7,6 +7,10 @@ import { genStyleHooks, mergeToken } from '../../theme/internal';
/** Component only token. Which will handle additional calculation of alias token */ /** Component only token. Which will handle additional calculation of alias token */
export interface ComponentToken { export interface ComponentToken {
// Component token here // Component token here
/**
*
*/
viewBg: string;
/** /**
* @desc * @desc
* @descEN Background color of label * @descEN Background color of label
@ -49,7 +53,8 @@ export interface ComponentToken {
extraColor: string; extraColor: string;
} }
interface DescriptionsToken extends FullToken<'Descriptions'> {} interface DescriptionsToken extends FullToken<'Descriptions'> {
}
const genBorderedStyle = (token: DescriptionsToken): CSSObject => { const genBorderedStyle = (token: DescriptionsToken): CSSObject => {
const { componentCls, labelBg } = token; const { componentCls, labelBg } = token;
@ -57,6 +62,7 @@ const genBorderedStyle = (token: DescriptionsToken): CSSObject => {
[`&${componentCls}-bordered`]: { [`&${componentCls}-bordered`]: {
[`> ${componentCls}-view`]: { [`> ${componentCls}-view`]: {
border: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`, border: `${unit(token.lineWidth)} ${token.lineType} ${token.colorSplit}`,
backgroundColor: `${token.viewBg}`,
'> table': { '> table': {
tableLayout: 'auto', tableLayout: 'auto',
borderCollapse: 'collapse', borderCollapse: 'collapse',
@ -113,6 +119,7 @@ const genDescriptionStyles: GenerateStyle<DescriptionsToken> = (token) => {
[componentCls]: { [componentCls]: {
...resetComponent(token), ...resetComponent(token),
...genBorderedStyle(token), ...genBorderedStyle(token),
backgroundColor: token.viewBg,
[`&-rtl`]: { [`&-rtl`]: {
direction: 'rtl', direction: 'rtl',
}, },
@ -137,6 +144,7 @@ const genDescriptionStyles: GenerateStyle<DescriptionsToken> = (token) => {
[`${componentCls}-view`]: { [`${componentCls}-view`]: {
width: '100%', width: '100%',
borderRadius: token.borderRadiusLG, borderRadius: token.borderRadiusLG,
backgroundColor: token.viewBg,
table: { table: {
width: '100%', width: '100%',
tableLayout: 'fixed', tableLayout: 'fixed',

View File

@ -1,9 +1,7 @@
--- ---
category: Components category: Components
title: Divider title: Divider 分割线
subtitle: 分割线 subtitle: 分割线
cover: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*7sMiTbzvaDoAAAAAAAAAAAAADrJ8AQ/original
coverDark: https://mdn.alipayobjects.com/huamei_7uahnr/afts/img/A*KPSEQ74PLg4AAAAAAAAAAAAADrJ8AQ/original
demo: demo:
cols: 2 cols: 2
group: group:
@ -42,7 +40,3 @@ group:
| plain | 文字是否显示为普通正文样式 | boolean | false | 4.2.0 | | plain | 文字是否显示为普通正文样式 | boolean | false | 4.2.0 |
| style | 分割线样式对象 | CSSProperties | - | | | style | 分割线样式对象 | CSSProperties | - | |
| type | 水平还是垂直类型 | `horizontal` \| `vertical` | `horizontal` | | | type | 水平还是垂直类型 | `horizontal` \| `vertical` | `horizontal` | |
## 主题变量Design Token
<ComponentTokenTable component="Divider"></ComponentTokenTable>

View File

@ -1,8 +1,11 @@
export { default as doubleClick } from './doubleClick'; export { default as doubleClick } from './doubleClick';
export { default as Icon } from './iconfont'; export { default as Icon } from './iconfont';
export { default as CompareImage } from './CompareImage' export { default as CompareImage } from './CompareImage'
export type { CompareImageProps } from './CompareImage'
export { default as BigImagePreview } from './BigImagePreview' export { default as BigImagePreview } from './BigImagePreview'
export type { ImgViewProps, ImgViewRef } from './BigImagePreview'
export { default as VideoPlayer } from './VideoPlayer' export { default as VideoPlayer } from './VideoPlayer'
export type { VideoViewProps, VideoViewRef } from './VideoPlayer'
export { default as Tabs } from './tabs' export { default as Tabs } from './tabs'
export type { TabPaneProps, TabsProps } from './tabs'; export type { TabPaneProps, TabsProps } from './tabs';
export { default as Button } from './button' export { default as Button } from './button'
@ -25,7 +28,7 @@ export type { FormProps, FormItemProps } from './form';
export { default as Select } from './select' export { default as Select } from './select'
export type { SelectProps } from './select'; export type { SelectProps } from './select';
export { default as Radio } from './radio' export { default as Radio } from './radio'
export type { RadioProps } from './radio'; export type { RadioProps, RadioChangeEvent, RadioGroupButtonStyle, RadioChangeEventTarget, RadioGroupContextProps, RadioGroupProps, RadioGroupOptionType } from './radio';
export { default as Checkbox } from './checkbox' export { default as Checkbox } from './checkbox'
export type { CheckboxProps, CheckboxGroupProps } from './checkbox'; export type { CheckboxProps, CheckboxGroupProps } from './checkbox';
export { default as Input } from './input' export { default as Input } from './input'
@ -45,3 +48,7 @@ export { default as Modal } from './modal'
export type { ModalFuncProps, ModalProps } from './modal'; export type { ModalFuncProps, ModalProps } from './modal';
export { default as Divider } from './divider' export { default as Divider } from './divider'
export type { DividerProps } from './divider'; export type { DividerProps } from './divider';
export { default as Descriptions } from './descriptions'
export type { DescriptionsContextProps, DescriptionsItemType, DescriptionsProps } from './descriptions'
export { default as Flex } from './flex'
export { default as Score } from './score'

View File

@ -4,7 +4,7 @@ import type { RadioProps, RadioRef } from './interface';
import InternalRadio from './radio'; import InternalRadio from './radio';
import Button from './radioButton'; import Button from './radioButton';
export { export type {
RadioChangeEvent, RadioChangeEvent,
RadioChangeEventTarget, RadioChangeEventTarget,
RadioGroupButtonStyle, RadioGroupButtonStyle,

View File

@ -0,0 +1,57 @@
//@ts-nocheck
import React, { useMemo } from 'react';
import classNames from 'classnames';
import './index.less';
const componentName = `zhst-image__score`;
export interface ScoreProps {
score: number;
showTitle?: boolean;
r?: number;
fontSize?: number;
borderColor?: string;
borderSize?: number;
waveColor?: string;
}
export const Score: React.FC<ScoreProps> = (props) => {
const {
score,
r = 44,
showTitle = true,
fontSize = 28,
borderSize = 8,
borderColor = 'rgb(0 153 255 / 10%)',
waveColor = 'linear-gradient(180deg, #a0efff 0%, #09f 100%)',
} = props;
const waveHeight = `${score * r * 2}px`;
return useMemo(
() => (
<div className={classNames(`${componentName}`)}>
<div
className={classNames(`${componentName}-box`)}
style={{ border: `${borderSize}px solid ${borderColor}` }}
>
<div
style={{ width: r * 2, height: r * 2 }}
className={classNames(`${componentName}-box-bg`)}
>
<div
className={classNames(`${componentName}-box-bg-inner`)}
style={{ height: waveHeight, background: waveColor }}
/>
</div>
<div
style={{ fontSize }}
className={classNames(`${componentName}-score`)}
>{`${Math.floor(score * 100)}%`}</div>
</div>
{showTitle && <div className={classNames(`${componentName}-text`)}></div>}
</div>
),
[score]
);
};
Score.displayName = componentName;
export default Score;

View File

@ -0,0 +1,48 @@
.zhst-image__score {
display: flex;
flex-direction: column;
align-items: center;
&-box {
position: relative;
display: flex;
box-sizing: border-box;
align-items: center;
justify-content: center;
margin-bottom: 12px;
border-radius: 50%;
&-bg {
display: flex;
overflow: hidden;
box-sizing: border-box;
align-items: flex-end;
justify-content: center;
border: 2px solid #fff;
background-color: #fff;
border-radius: 50%;
&-inner {
width: 100% !important;
height: 0;
}
}
}
&-score {
position: absolute;
top: 50%;
left: 50%;
color: rgb(0 0 0 / 88%);
font-size: 28px;
transform: translate(-50%, -50%);
}
&-text {
width: 54px;
height: 24px;
color: rgb(0 0 0 / 88%);
font-size: 18px;
line-height: 24px;
}
}

View File

@ -0,0 +1,17 @@
---
group: 数据录入
category: Components
subtitle: 分数
title: Score 分数
---
```jsx
import React from 'react'
import { Score } from '@zhst/meta'
export default () => {
return (
<Score score={0.3} />
)
}
```

View File

@ -0,0 +1,3 @@
import Score from './Score'
export default Score

View File

@ -1,9 +1,5 @@
{ {
"references": [{ "path": "../../tsconfig.json" }], "references": [{ "path": "../../tsconfig.json" }],
"compilerOptions": { "compilerOptions": {
"paths": { }
"@zhst/meta": ["./src"]
}
},
"exclude": ["src/**/demo"]
} }

View File

@ -26,3 +26,6 @@ export enum IBigImageOpt {
ADD_ARCHIVE_WITH_HK, //添加到档案库 ADD_ARCHIVE_WITH_HK, //添加到档案库
ADD_CURRENT_SRARCH, //添加到当前检索(目标检索) ADD_CURRENT_SRARCH, //添加到当前检索(目标检索)
} }
export type TAB_TYPE = 'COMPATER' | 'NORMAL' | 'TRACK';
export type MODEL_TYPE = 'VIDEO' | 'IMAGE';