feat(zhst/material): 升级智能柜的算法配置面板
This commit is contained in:
parent
7f64ffe221
commit
b5a74de4d9
@ -1,8 +1,9 @@
|
|||||||
import React, { forwardRef, ReactNode, useContext, useImperativeHandle } from 'react';
|
import React, { forwardRef, memo, ReactNode, useContext, useImperativeHandle } from 'react';
|
||||||
import { Button, Flex, Image } from "antd";
|
|
||||||
import theme from 'antd/es/theme'
|
import theme from 'antd/es/theme'
|
||||||
import { CropperImage, ConfigProvider } from '@zhst/meta'
|
import { CameraOutlined } from '@ant-design/icons'
|
||||||
import type { CropperImageProps } from '@zhst/meta'
|
import { Flex, Button, Image } from 'antd'
|
||||||
|
import { VideoPlayer, ConfigProvider } from '@zhst/meta'
|
||||||
|
import type { VideoViewProps } from '@zhst/meta'
|
||||||
import { AlgorithmConfigImg, ErrorImage } from '../utils/base64Images'
|
import { AlgorithmConfigImg, ErrorImage } from '../utils/base64Images'
|
||||||
import AlgorithmTable from './components/algorithmTable'
|
import AlgorithmTable from './components/algorithmTable'
|
||||||
import TimeTemplateTable from './components/timeTemplateTable';
|
import TimeTemplateTable from './components/timeTemplateTable';
|
||||||
@ -10,10 +11,11 @@ import { AlgorithmTableProps } from './components/algorithmTable/AlgorithmTable'
|
|||||||
import { TimeTemplateTableProps } from './components/timeTemplateTable/TimeTemplateTable';
|
import { TimeTemplateTableProps } from './components/timeTemplateTable/TimeTemplateTable';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
import { Alert } from 'antd';
|
||||||
|
|
||||||
const { useToken } = theme
|
const { useToken } = theme
|
||||||
|
|
||||||
const Title = (props: any) => <h2 style={{ color: 'rgba(0, 0, 0, 0.88)' }} {...props}>{props.children}</h2>
|
const Title = memo((props: any) => (<h2 style={{ color: 'rgba(0, 0, 0, 0.88)' }} {...props}>{props.children}</h2>))
|
||||||
|
|
||||||
export interface AlgorithmConfigProps {
|
export interface AlgorithmConfigProps {
|
||||||
onAddAlgorithm?: () => void
|
onAddAlgorithm?: () => void
|
||||||
@ -43,13 +45,18 @@ export interface AlgorithmConfigProps {
|
|||||||
id: string;
|
id: string;
|
||||||
name: string;
|
name: string;
|
||||||
}[]
|
}[]
|
||||||
algorithmTableProps?: AlgorithmTableProps<any>
|
algorithmTableProps?: Partial<AlgorithmTableProps<any>>
|
||||||
timeTemplateTableProps?: TimeTemplateTableProps<any>
|
timeTemplateTableProps?: Partial<TimeTemplateTableProps<any>>
|
||||||
cropperImageProps?: CropperImageProps
|
|
||||||
selectedKey?: string
|
selectedKey?: string
|
||||||
rowKey?: string
|
rowKey?: string
|
||||||
type: AlgorithmTableProps<any>['tableType']
|
type: AlgorithmTableProps<any>['tableType']
|
||||||
title?:string; // boxList列表的属性名称【点位列表、盒子列表】
|
title?:string; // boxList列表的属性名称【点位列表、盒子列表】
|
||||||
|
/**
|
||||||
|
* @description 当前选中的视频链接
|
||||||
|
*/
|
||||||
|
videoUrl?: string
|
||||||
|
videoProps?: Partial<VideoViewProps>
|
||||||
|
errorMessage?: string;
|
||||||
onSelect?: (key: string, info?: any) => void
|
onSelect?: (key: string, info?: any) => void
|
||||||
/**
|
/**
|
||||||
* 是否显示/隐藏加载更多按钮
|
* 是否显示/隐藏加载更多按钮
|
||||||
@ -59,6 +66,12 @@ export interface AlgorithmConfigProps {
|
|||||||
* 点击加载更多事件
|
* 点击加载更多事件
|
||||||
*/
|
*/
|
||||||
onLoadMoreButtonClick?: () => void;
|
onLoadMoreButtonClick?: () => void;
|
||||||
|
/**
|
||||||
|
* 自定义左侧box
|
||||||
|
* @param data 当前box详情
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
customBoxItemRender?: (data?: any) => void
|
||||||
/**
|
/**
|
||||||
* 自定义加载更多按钮
|
* 自定义加载更多按钮
|
||||||
*/
|
*/
|
||||||
@ -79,15 +92,18 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
|||||||
const {
|
const {
|
||||||
algorithmTableDataSource = [],
|
algorithmTableDataSource = [],
|
||||||
timeTemplateDataSource = [],
|
timeTemplateDataSource = [],
|
||||||
drawListener,
|
|
||||||
cropperImageProps = {},
|
|
||||||
algorithmTableProps,
|
algorithmTableProps,
|
||||||
timeTemplateTableProps,
|
timeTemplateTableProps,
|
||||||
|
videoProps,
|
||||||
selectedKey,
|
selectedKey,
|
||||||
|
customBoxItemRender,
|
||||||
|
errorMessage,
|
||||||
boxList = [],
|
boxList = [],
|
||||||
type = 'multiple',
|
type = 'single',
|
||||||
rowKey = 'id',
|
rowKey = 'id',
|
||||||
onSelect, title='盒子名称',
|
onSelect,
|
||||||
|
title='盒子名称',
|
||||||
|
videoUrl,
|
||||||
showLoadMoreButton,
|
showLoadMoreButton,
|
||||||
onLoadMoreButtonClick,
|
onLoadMoreButtonClick,
|
||||||
customBatchCenterContent,
|
customBatchCenterContent,
|
||||||
@ -96,47 +112,46 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
|||||||
} = props
|
} = props
|
||||||
const { getPrefixCls } = useContext(ConfigContext);
|
const { getPrefixCls } = useContext(ConfigContext);
|
||||||
const componentName = getPrefixCls('material-algo', customizePrefixCls);
|
const componentName = getPrefixCls('material-algo', customizePrefixCls);
|
||||||
|
|
||||||
const { token } = useToken()
|
const { token } = useToken()
|
||||||
// @ts-ignore
|
|
||||||
const { type: cropType } = cropperImageProps
|
|
||||||
|
|
||||||
useImperativeHandle(ref, () => ({
|
useImperativeHandle(ref, () => ({
|
||||||
}))
|
}))
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Flex className={componentName} style={{ border: `1px solid ${token.colorBorder}`, backgroundColor: token.colorBgBase }}>
|
<Flex className={componentName} style={{ backgroundColor: token.colorBgBase }}>
|
||||||
<div className={classNames(`${componentName}-left`)} title={title} style={{ position: 'relative', width: '13.9%' }}>
|
<div className={classNames(`${componentName}-left`)} title={title} style={{ position: 'relative' }}>
|
||||||
<Title className={classNames(`${componentName}-title`)}>{title}</Title>
|
<Title className={classNames(`${componentName}-title`)}>{title}</Title>
|
||||||
<div className={classNames(`${componentName}-left-list`)} style={{ borderTop: `1px solid ${token.colorBorder}` }}>
|
<div className={classNames(`${componentName}-left-list`)}>
|
||||||
{boxList.map(item => {
|
{boxList.map(item => {
|
||||||
return (
|
return (
|
||||||
<p
|
customBoxItemRender?.(item) || (
|
||||||
// @ts-ignore
|
<p
|
||||||
key={item[rowKey]}
|
|
||||||
// @ts-ignore
|
|
||||||
onClick={() => onSelect?.(item[rowKey], item)}
|
|
||||||
style={{
|
|
||||||
margin: 0,
|
|
||||||
padding: `${token.paddingXXS}px ${token.paddingLG}px`,
|
|
||||||
cursor: 'pointer',
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
color: selectedKey === item[rowKey] ? token.colorPrimary : token.colorText,
|
key={item[rowKey]}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
backgroundColor: selectedKey === item[rowKey] ? token.blue1 : token.colorBgBase,
|
onClick={() => onSelect?.(item[rowKey], item)}
|
||||||
transition: '.2s ease all',
|
style={{
|
||||||
}}
|
margin: 0,
|
||||||
onMouseEnter={(e: any) => {
|
padding: `${token.paddingXXS}px`,
|
||||||
e.target.style.backgroundColor = token.colorPrimaryBg
|
cursor: 'pointer',
|
||||||
e.target.style.color = token.colorPrimary
|
// @ts-ignore
|
||||||
}}
|
color: selectedKey === item[rowKey] ? token.colorPrimary : token.colorText,
|
||||||
onMouseLeave={(e: any) => {
|
// @ts-ignore
|
||||||
// @ts-ignore
|
backgroundColor: selectedKey === item[rowKey] ? token.blue1 : token.colorBgBase,
|
||||||
if (selectedKey === item[rowKey]) return
|
transition: '.2s ease all',
|
||||||
e.target.style.color = token.colorText
|
}}
|
||||||
e.target.style.backgroundColor = null
|
onMouseEnter={(e: any) => {
|
||||||
}}
|
e.target.style.backgroundColor = token.colorPrimaryBg
|
||||||
>{item.name}</p>
|
e.target.style.color = token.colorPrimary
|
||||||
|
}}
|
||||||
|
onMouseLeave={(e: any) => {
|
||||||
|
// @ts-ignore
|
||||||
|
if (selectedKey === item[rowKey]) return
|
||||||
|
e.target.style.color = token.colorText
|
||||||
|
e.target.style.backgroundColor = null
|
||||||
|
}}
|
||||||
|
><CameraOutlined style={{ marginRight: 8 }} />{item.name}</p>
|
||||||
|
)
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
@ -146,13 +161,13 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ boxSizing: 'border-box', width: '46.3%', textAlign: 'center', borderLeft: `1px solid ${token.colorBorder}`, borderRight: `1px solid ${token.colorBorder}` }}>
|
<div className={classNames(`${componentName}-middle`)} style={{ boxSizing: 'border-box', width: '46.3%', textAlign: 'center', }}>
|
||||||
|
{errorMessage && <Alert style={{ marginBottom: 16 }} message={`错误代码:${errorMessage || '-'}`} type="error" showIcon />}
|
||||||
{/* 单个配置 */}
|
{/* 单个配置 */}
|
||||||
{type === 'single' ? (
|
{type === 'single' ? (
|
||||||
<CropperImage
|
<VideoPlayer
|
||||||
type="line"
|
url={videoUrl!}
|
||||||
onCropEnd={drawListener}
|
{...videoProps}
|
||||||
{...cropperImageProps}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className={classNames(`${componentName}-middle-cont`)}>
|
<div className={classNames(`${componentName}-middle-cont`)}>
|
||||||
@ -175,10 +190,10 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ width: '39.8%' }} >
|
<div className={classNames(`${componentName}-right`)} >
|
||||||
<div>
|
<div>
|
||||||
<Title className={classNames(`${componentName}-title`)}>时间模板</Title>
|
<Title className={classNames(`${componentName}-title`)}>时间模板</Title>
|
||||||
<div style={{ padding: `${token.paddingMD}px ${token.paddingSM}px`, borderTop: `1px solid ${token.colorBorder}`, borderBottom: `1px solid ${token.colorBorder}` }}>
|
<div >
|
||||||
<TimeTemplateTable
|
<TimeTemplateTable
|
||||||
dataSource={timeTemplateDataSource}
|
dataSource={timeTemplateDataSource}
|
||||||
{...timeTemplateTableProps}
|
{...timeTemplateTableProps}
|
||||||
@ -187,9 +202,10 @@ const AlgorithmConfig = forwardRef<AlgorithmConfigRef, AlgorithmConfigProps>((pr
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Title className={classNames(`${componentName}-title`)}>算法应用</Title>
|
<Title className={classNames(`${componentName}-title`)}>算法应用</Title>
|
||||||
<div style={{ padding: `${token.paddingMD}px ${token.paddingSM}px`, borderTop: `1px solid ${token.colorBorder}` }}>
|
<div >
|
||||||
<AlgorithmTable
|
<AlgorithmTable
|
||||||
dataSource={algorithmTableDataSource}
|
dataSource={algorithmTableDataSource}
|
||||||
|
timeTemplateData={timeTemplateDataSource}
|
||||||
tableType={type}
|
tableType={type}
|
||||||
{...algorithmTableProps}
|
{...algorithmTableProps}
|
||||||
/>
|
/>
|
||||||
|
@ -1,27 +1,24 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
import { DeleteFilled, EditFilled, ImportOutlined, PlusCircleFilled } from '@ant-design/icons';
|
|
||||||
import type { ParamsType, ProColumns, ProTableProps } from '@ant-design/pro-components';
|
import type { ParamsType, ProColumns, ProTableProps } from '@ant-design/pro-components';
|
||||||
import {
|
import {
|
||||||
ProTable,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { Popconfirm, Select, Space, Switch } from 'antd';
|
import { Button, ButtonProps, Popconfirm, Select, Space, Switch } from 'antd';
|
||||||
import { ConfigProvider } from '@zhst/meta'
|
import { ConfigProvider } from '@zhst/meta'
|
||||||
import theme from 'antd/es/theme'
|
|
||||||
import { AnyObject } from 'antd/es/_util/type';
|
import { AnyObject } from 'antd/es/_util/type';
|
||||||
import { SelectProps } from 'antd/lib';
|
import { SelectProps } from 'antd/lib';
|
||||||
import SchemaFormModal from '../schemaFormModal';
|
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import './index.less'
|
import './index.less'
|
||||||
|
|
||||||
const { useToken } = theme
|
|
||||||
const { ConfigContext } = ConfigProvider
|
const { ConfigContext } = ConfigProvider
|
||||||
|
|
||||||
export interface AlgorithmTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
export interface AlgorithmTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
||||||
onAddAlgorithm?: (id?: string, record?: any) => void
|
onAddAlgorithm?: (id?: string, record?: any) => void
|
||||||
onItemSwitch?: (status?: boolean, id?: string, info?: any) => void
|
onItemSwitch?: (status?: boolean, id?: string, info?: any) => void
|
||||||
onItemEdit?: (values?: any, info?: any) => void
|
onItemEdit?: (values?: any, type?: 'edit' | 'delete' | 'draw' | 'switch' | 'runCycle', info?: any ) => void
|
||||||
onItemDelete?: (id?: string, info?: any) => void
|
onItemDelete?: (id?: string, info?: any) => void
|
||||||
onSortSelect?: SelectProps['onChange']
|
onSortSelect?: SelectProps['onChange']
|
||||||
|
onReuse?: ButtonProps['onClick']
|
||||||
onDraw?: (id: any, info?: any) => void
|
onDraw?: (id: any, info?: any) => void
|
||||||
selectedKey?: string
|
selectedKey?: string
|
||||||
sortList?: {
|
sortList?: {
|
||||||
@ -29,87 +26,90 @@ export interface AlgorithmTableProps<DataSource, Params extends ParamsType = Par
|
|||||||
value: string;
|
value: string;
|
||||||
}[]
|
}[]
|
||||||
tableType?: 'multiple' | 'single' // 多选/单选
|
tableType?: 'multiple' | 'single' // 多选/单选
|
||||||
|
timeTemplateData?: any[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const AlgorithmTable= <DataSource extends AnyObject = AnyObject>(
|
const AlgorithmTable= <DataSource extends AnyObject = AnyObject>(
|
||||||
props: AlgorithmTableProps<DataSource, ParamsType, 'text'>
|
props: AlgorithmTableProps<DataSource, ParamsType, 'text'>
|
||||||
) => {
|
) => {
|
||||||
const {
|
const {
|
||||||
onAddAlgorithm,
|
|
||||||
onItemSwitch,
|
|
||||||
onItemEdit,
|
onItemEdit,
|
||||||
onItemDelete,
|
|
||||||
onSortSelect,
|
onSortSelect,
|
||||||
selectedKey,
|
onReuse,
|
||||||
onDraw,
|
timeTemplateData = [],
|
||||||
tableType = 'multiple',
|
|
||||||
sortList = [],
|
sortList = [],
|
||||||
prefixCls: customizePrefixCls
|
prefixCls: customizePrefixCls
|
||||||
} = props
|
} = props
|
||||||
const { getPrefixCls } = useContext(ConfigContext);
|
const { getPrefixCls } = useContext(ConfigContext);
|
||||||
const componentName = getPrefixCls('material-algo-algoTable', customizePrefixCls);
|
const componentName = getPrefixCls('material-algo-algoTable', customizePrefixCls);
|
||||||
|
|
||||||
|
|
||||||
const { token } = useToken()
|
|
||||||
|
|
||||||
const columns: ProColumns<DataSource>[] = [
|
const columns: ProColumns<DataSource>[] = [
|
||||||
{
|
{
|
||||||
|
editable: false,
|
||||||
title: '算法名称',
|
title: '算法名称',
|
||||||
dataIndex: 'templateName',
|
dataIndex: 'templateName',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
disable: true,
|
||||||
title: '运行周期',
|
title: '运行周期',
|
||||||
|
key: 'runCycle',
|
||||||
dataIndex: 'runCycle',
|
dataIndex: 'runCycle',
|
||||||
valueType: 'select',
|
render: (_, record) => {
|
||||||
valueEnum: {
|
return (
|
||||||
1: { text: '黑夜' },
|
<Select
|
||||||
0: { text: '白天' },
|
style={{ width: 120 }}
|
||||||
|
placeholder="运行周期"
|
||||||
|
defaultValue={record.runCycle}
|
||||||
|
onChange={value => onItemEdit?.(value, 'runCycle', record)}
|
||||||
|
>
|
||||||
|
{timeTemplateData.map(o => (
|
||||||
|
<Select.Option key={o.id} >{o.templateName}</Select.Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// title: '算力占用',
|
editable: false,
|
||||||
// dataIndex: 'powerOccupy',
|
title: '启动状态',
|
||||||
// },
|
dataIndex: 'status',
|
||||||
|
render: (_, record) => <Switch defaultChecked={record.status} onChange={_status => onItemEdit?.(_status, 'switch', record)} />
|
||||||
|
},
|
||||||
{
|
{
|
||||||
title: '操作',
|
title: '操作',
|
||||||
key: 'option',
|
key: 'option',
|
||||||
valueType: 'option',
|
valueType: 'option',
|
||||||
fixed: 'right',
|
fixed: 'right',
|
||||||
width: '120px',
|
width: 140,
|
||||||
render: (_DOM, record) => [
|
render: (_DOM, record) => [
|
||||||
<Switch value={record.status} onChange={_status => onItemSwitch?.(_status, record.id, record)} />,
|
<a onClick={() => onItemEdit?.(record.id, 'draw', record)}>框选</a>,
|
||||||
<a onClick={() => onDraw?.(record.id, record)} style={{ display: tableType === 'single' ? 'block' : 'none' }} href="#"><ImportOutlined /></a>,
|
<a onClick={() => onItemEdit?.(record.id, 'edit', record)}>编辑</a>,
|
||||||
<SchemaFormModal
|
|
||||||
type={record.templateType}
|
|
||||||
onFinish={async (values) => onItemEdit?.(values, record)}
|
|
||||||
trigger={<a href="#"><EditFilled /></a>}
|
|
||||||
/>
|
|
||||||
,
|
|
||||||
<Popconfirm
|
<Popconfirm
|
||||||
title="确定删除吗?"
|
title="确定删除吗?"
|
||||||
onConfirm={() => onItemDelete?.(record.id, record)}
|
onConfirm={() => onItemEdit?.(record.id, 'delete', record)}
|
||||||
>
|
>
|
||||||
<a href="#"><DeleteFilled /></a>
|
<a style={{ color: 'red' }}>删除</a>
|
||||||
</Popconfirm>,
|
</Popconfirm>,
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
console.log('123', 123)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={componentName}>
|
<div className={componentName}>
|
||||||
<Space className={classNames(`${componentName}-top`)} size={16}>
|
<Space className={classNames(`${componentName}-top`)} size={16}>
|
||||||
<Select
|
<Select
|
||||||
className={classNames(`${componentName}-top-select`)}
|
className={classNames(`${componentName}-top-select`)}
|
||||||
value={selectedKey}
|
placeholder="新增算法"
|
||||||
onChange={onSortSelect}
|
onChange={onSortSelect}
|
||||||
options={sortList}
|
options={sortList}
|
||||||
/>
|
/>
|
||||||
<PlusCircleFilled className={classNames(`${componentName}-top-plus`)} onClick={() => onAddAlgorithm?.(selectedKey)} style={{ color: token.colorPrimary, cursor: 'pointer' }} />
|
<Button onClick={onReuse}>配置复用</Button>
|
||||||
</Space>
|
</Space>
|
||||||
<ProTable<DataSource>
|
<ProTable<DataSource>
|
||||||
columns={columns}
|
columns={columns}
|
||||||
bordered
|
scroll={{ y: 400, x: 600 }}
|
||||||
scroll={{ y: 240, x: 600 }}
|
|
||||||
dataSource={[]}
|
dataSource={[]}
|
||||||
cardProps={{
|
cardProps={{
|
||||||
bodyStyle: {
|
bodyStyle: {
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
|
||||||
&-select {
|
&-select {
|
||||||
width: 320px;
|
width: 160px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-plus {
|
&-plus {
|
||||||
|
@ -5,8 +5,7 @@ import {
|
|||||||
ProTable,
|
ProTable,
|
||||||
} from '@ant-design/pro-components';
|
} from '@ant-design/pro-components';
|
||||||
import { AnyObject } from 'antd/es/_util/type';
|
import { AnyObject } from 'antd/es/_util/type';
|
||||||
import { InputNumber } from 'antd';
|
import './index.less'
|
||||||
|
|
||||||
export interface TimeTemplateTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
export interface TimeTemplateTableProps<DataSource, Params extends ParamsType = ParamsType, ValueType = "text"> extends ProTableProps<DataSource, Params, ValueType> {
|
||||||
onItemBlur?: (value?: number | string, id?: any, record?: any) => void,
|
onItemBlur?: (value?: number | string, id?: any, record?: any) => void,
|
||||||
}
|
}
|
||||||
@ -14,10 +13,6 @@ export interface TimeTemplateTableProps<DataSource, Params extends ParamsType =
|
|||||||
const TimeTemplateTable = <DataSource extends AnyObject = AnyObject>(
|
const TimeTemplateTable = <DataSource extends AnyObject = AnyObject>(
|
||||||
props: TimeTemplateTableProps<DataSource, ParamsType, 'text'>
|
props: TimeTemplateTableProps<DataSource, ParamsType, 'text'>
|
||||||
) => {
|
) => {
|
||||||
const {
|
|
||||||
onItemBlur,
|
|
||||||
} = props
|
|
||||||
|
|
||||||
|
|
||||||
const columns: ProColumns<DataSource>[] = [
|
const columns: ProColumns<DataSource>[] = [
|
||||||
{
|
{
|
||||||
@ -32,28 +27,17 @@ const TimeTemplateTable = <DataSource extends AnyObject = AnyObject>(
|
|||||||
title: '布控星期',
|
title: '布控星期',
|
||||||
dataIndex: 'arrangeDay',
|
dataIndex: 'arrangeDay',
|
||||||
},
|
},
|
||||||
// TODO: 暂时先注释后续在做这个功能
|
|
||||||
// {
|
|
||||||
// title: '算力占用',
|
|
||||||
// dataIndex: 'powerOccupy',
|
|
||||||
// },
|
|
||||||
{
|
|
||||||
title: '配置路数',
|
|
||||||
key: 'option',
|
|
||||||
valueType: 'option',
|
|
||||||
render: (_, record) => <InputNumber value={record.lineNum} onBlur={e => onItemBlur?.(e.target.value, record.id, record)} min={0} />,
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ProTable<DataSource>
|
<ProTable<DataSource>
|
||||||
|
className='time-template-table'
|
||||||
columns={columns}
|
columns={columns}
|
||||||
cardProps={{
|
cardProps={{
|
||||||
bodyStyle: {
|
bodyStyle: {
|
||||||
padding: 0
|
padding: 0
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
bordered
|
|
||||||
scroll={{ y: 95 }}
|
scroll={{ y: 95 }}
|
||||||
toolbar={undefined}
|
toolbar={undefined}
|
||||||
rowKey="id"
|
rowKey="id"
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
.time-template-table {
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
@ -2,7 +2,7 @@ import React, { useRef, useState } from 'react';
|
|||||||
import { AlgorithmConfig, AlgorithmConfigRef } from '@zhst/material';
|
import { AlgorithmConfig, AlgorithmConfigRef } from '@zhst/material';
|
||||||
import type { AlgorithmConfigProps } from '@zhst/material';
|
import type { AlgorithmConfigProps } from '@zhst/material';
|
||||||
import { Button, Space, Switch } from 'antd';
|
import { Button, Space, Switch } from 'antd';
|
||||||
import { CropperImageRefProps } from '@zhst/meta';
|
import { CropperImageRefProps, VideoViewRef } from '@zhst/meta';
|
||||||
|
|
||||||
|
|
||||||
const algorithmTableDataSource: any = []
|
const algorithmTableDataSource: any = []
|
||||||
@ -20,7 +20,7 @@ for (let i = 0; i < 100; i += 1) {
|
|||||||
odRect:{
|
odRect:{
|
||||||
"x":0.553125,"y":0.29722223,"w":0.048958335,"h":0.2462963
|
"x":0.553125,"y":0.29722223,"w":0.048958335,"h":0.2462963
|
||||||
},
|
},
|
||||||
runCycle: i % 2 !== 0 ? '白天' : '黑夜',
|
runCycle: String(i),
|
||||||
creator: Math.floor(Math.random() * 20),
|
creator: Math.floor(Math.random() * 20),
|
||||||
});
|
});
|
||||||
timeTemplateDataSource.push({
|
timeTemplateDataSource.push({
|
||||||
@ -38,6 +38,8 @@ for (let i = 0; i < 100; i += 1) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const VIDEO_URL = `ws://10.0.0.7:9033/flv/File/test/test_h264_${Math.floor(Math.random() * 6) + 1}.mp4.flv?ip=127.0.0.1`
|
||||||
|
|
||||||
const demo = () => {
|
const demo = () => {
|
||||||
const [algorithmTableList, setAlgorithmTableList] = useState(algorithmTableDataSource)
|
const [algorithmTableList, setAlgorithmTableList] = useState(algorithmTableDataSource)
|
||||||
const [timeTemplateData, setTimeTemplateData] = useState(timeTemplateDataSource)
|
const [timeTemplateData, setTimeTemplateData] = useState(timeTemplateDataSource)
|
||||||
@ -45,14 +47,15 @@ const demo = () => {
|
|||||||
const [selectedKey, setSelectedKey] = useState('1')
|
const [selectedKey, setSelectedKey] = useState('1')
|
||||||
const [cropType, setCropType] = useState<'line' | 'rect'>('line')
|
const [cropType, setCropType] = useState<'line' | 'rect'>('line')
|
||||||
const [algorithmSelectedKey, setAlgorithmSelectedKey] = useState('1')
|
const [algorithmSelectedKey, setAlgorithmSelectedKey] = useState('1')
|
||||||
const [tableType, setTableType] = useState<AlgorithmConfigProps['type']>('multiple')
|
const [tableType, setTableType] = useState<AlgorithmConfigProps['type']>('single')
|
||||||
const [editAble, setEditAble] = useState(false)
|
const [editAble, setEditAble] = useState(false)
|
||||||
const algorithmConfigRef = useRef<AlgorithmConfigRef>(null)
|
const algorithmConfigRef = useRef<AlgorithmConfigRef>(null)
|
||||||
const cropperImageRef = useRef<CropperImageRefProps>(null)
|
const videoRef = useRef<VideoViewRef>(null)
|
||||||
|
const [videoUrl, setVideoUrl] = useState('')
|
||||||
|
const [odList, setOdList] = useState([])
|
||||||
|
|
||||||
// 绘画事件
|
// 绘画事件
|
||||||
const handleDraw = (id: any, info: any) => {
|
const handleDraw = (id: any, info: any) => {
|
||||||
console.log('cropperImageRef', cropperImageRef)
|
|
||||||
setEditAble(true)
|
setEditAble(true)
|
||||||
setCropType('line')
|
setCropType('line')
|
||||||
}
|
}
|
||||||
@ -75,15 +78,41 @@ const demo = () => {
|
|||||||
selectedKey={selectedKey}
|
selectedKey={selectedKey}
|
||||||
onSelect={key => {
|
onSelect={key => {
|
||||||
setSelectedKey(key)
|
setSelectedKey(key)
|
||||||
|
setVideoUrl(VIDEO_URL)
|
||||||
|
setOdList([
|
||||||
|
{
|
||||||
|
"id": "123",
|
||||||
|
"x": 0.5519352,
|
||||||
|
"y": 0.2965385,
|
||||||
|
"w": 0.05185461,
|
||||||
|
"h": 0.24698898,
|
||||||
|
selectAble: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "456",
|
||||||
|
"x": 0.58543766,
|
||||||
|
"y": Math.random(),
|
||||||
|
"w": 0.052037954,
|
||||||
|
"h": 0.2664015
|
||||||
|
}
|
||||||
|
])
|
||||||
// setTimeTemplateData([])
|
// setTimeTemplateData([])
|
||||||
// setTableList([])
|
// setTableList([])
|
||||||
// setBoxList([])
|
// setBoxList([])
|
||||||
}}
|
}}
|
||||||
|
videoUrl={videoUrl}
|
||||||
|
videoProps={{
|
||||||
|
ref: videoRef,
|
||||||
|
onCropChange: (showCrop, normalizationRect) => {
|
||||||
|
console.log('showCrop', showCrop, normalizationRect)
|
||||||
|
},
|
||||||
|
showOD: true,
|
||||||
|
odList
|
||||||
|
}}
|
||||||
type={tableType}
|
type={tableType}
|
||||||
// 算法模块
|
// 算法模块
|
||||||
algorithmTableProps={{
|
algorithmTableProps={{
|
||||||
onItemSwitch: (status, id) => {
|
onItemSwitch: (status, id) => {
|
||||||
console.log('算法状态 switch 变更')
|
|
||||||
setAlgorithmTableList((pre: any[]) => {
|
setAlgorithmTableList((pre: any[]) => {
|
||||||
let arr = pre.map(o => {
|
let arr = pre.map(o => {
|
||||||
if (o.id === id) {
|
if (o.id === id) {
|
||||||
@ -94,30 +123,25 @@ const demo = () => {
|
|||||||
return arr
|
return arr
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
onItemEdit: async (values, itemInfo) => {
|
onItemEdit: async (values, type, info) => {
|
||||||
console.log('算法单项编辑表单提交', values, itemInfo)
|
videoRef.current?.setShowCrop(true)
|
||||||
|
console.log('算法单项编辑表单提交', videoRef, info)
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
onDraw: (id, info) => handleDraw(id, info),
|
onDraw: (id, info) => handleDraw(id, info),
|
||||||
onItemDelete: (id, itemInfo) => console.log('删除', id, itemInfo),
|
onItemDelete: (id, itemInfo) => console.log('删除', id, itemInfo),
|
||||||
onAddAlgorithm: (id) => console.log('添加模板', id),
|
onAddAlgorithm: (id) => console.log('添加模板', id),
|
||||||
selectedKey: algorithmSelectedKey,
|
selectedKey: algorithmSelectedKey,
|
||||||
onSortSelect: (value) => setAlgorithmSelectedKey(value),
|
// onSortSelect: (value) => setAlgorithmSelectedKey(value),
|
||||||
sortList: [
|
sortList: [
|
||||||
{ label: '白天', value: '1' },
|
{ label: '火焰识别', value: '1' },
|
||||||
{ label: '黑夜', value: '2' },
|
{ label: '人脸识别', value: '2' },
|
||||||
]
|
]
|
||||||
}}
|
}}
|
||||||
// 时间模板模块
|
// 时间模板模块
|
||||||
timeTemplateTableProps={{
|
timeTemplateTableProps={{
|
||||||
onItemBlur: (val, id, itemInfo) => console.log('失焦事件', val, id, itemInfo),
|
onItemBlur: (val, id, itemInfo) => console.log('失焦事件', val, id, itemInfo),
|
||||||
}}
|
}}
|
||||||
cropperImageProps={{
|
|
||||||
type: cropType,
|
|
||||||
editAble,
|
|
||||||
ref: cropperImageRef,
|
|
||||||
url: 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</Space>
|
</Space>
|
||||||
);
|
);
|
||||||
|
@ -1,21 +1,38 @@
|
|||||||
.zhst-material-algo {
|
.zhst-material-algo {
|
||||||
|
display: flex;
|
||||||
&-title {
|
&-title {
|
||||||
margin: 18px 16px;
|
margin: 16px 0;
|
||||||
|
margin-top: 0;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-left {
|
&-left {
|
||||||
|
flex: 0 0 240px;
|
||||||
|
border-right: 1px solid #e5e5e5;
|
||||||
&-list {
|
&-list {
|
||||||
padding-bottom: 36px;
|
padding-bottom: 36px;
|
||||||
max-height: 612px;
|
max-height: 892px;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
box-sizing: 'border-box';
|
box-sizing: 'border-box';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-middle {
|
&-middle {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 0 0 1040px;
|
||||||
|
margin: 0 24px;
|
||||||
|
height: auto;
|
||||||
|
|
||||||
&-cont {
|
&-cont {
|
||||||
|
align-items: center;
|
||||||
padding: 84px;
|
padding: 84px;
|
||||||
|
border: 1px solid #e5e5e5;
|
||||||
|
border-radius: 8px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&-right {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -358,6 +358,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
|||||||
if (!isReady) return;
|
if (!isReady) return;
|
||||||
|
|
||||||
if (showCrop) {
|
if (showCrop) {
|
||||||
|
// 编辑状态
|
||||||
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, () => {
|
handlerCropStart = addEventListenerWrapper(corpContainerRef.current, EVENT_CROP_START, () => {
|
||||||
setCropRect(null);
|
setCropRect(null);
|
||||||
});
|
});
|
||||||
@ -372,7 +373,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
|||||||
alignRef?.current?.forceAlign?.();
|
alignRef?.current?.forceAlign?.();
|
||||||
});
|
});
|
||||||
let video: any = videoRef.current;
|
let video: any = videoRef.current;
|
||||||
//计算 limitcroppbox
|
//计算 limit crop box
|
||||||
let scale = Math.min(
|
let scale = Math.min(
|
||||||
video.offsetWidth / video.videoWidth,
|
video.offsetWidth / video.videoWidth,
|
||||||
video.offsetHeight / video.videoHeight
|
video.offsetHeight / video.videoHeight
|
||||||
@ -435,8 +436,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
|||||||
height: _element.clientHeight,
|
height: _element.clientHeight,
|
||||||
backgroundColor: 'transparent'
|
backgroundColor: 'transparent'
|
||||||
});
|
});
|
||||||
|
// 预览状态
|
||||||
// 判定是否存在od框
|
|
||||||
showOD && odList?.forEach(_od => {
|
showOD && odList?.forEach(_od => {
|
||||||
cropInsRef?.current?.addShape(_od);
|
cropInsRef?.current?.addShape(_od);
|
||||||
})
|
})
|
||||||
@ -447,7 +447,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
|||||||
cropInsRef?.current?.destroy?.();
|
cropInsRef?.current?.destroy?.();
|
||||||
cropInsRef.current = null;
|
cropInsRef.current = null;
|
||||||
};
|
};
|
||||||
}, [showCrop, isReady]);
|
}, [showCrop, isReady, odList]);
|
||||||
|
|
||||||
const latestCropRect = useLatest(cropRect);
|
const latestCropRect = useLatest(cropRect);
|
||||||
|
|
||||||
@ -507,6 +507,7 @@ const VideoPlayer = forwardRef<VideoViewRef, VideoViewProps>((props, ref) => {
|
|||||||
// 监听showCrop、cropRect - 监听是否可编辑、绘制的矩形
|
// 监听showCrop、cropRect - 监听是否可编辑、绘制的矩形
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
//计算归一化crop rect
|
//计算归一化crop rect
|
||||||
|
// ! 待优化
|
||||||
let normalizationRect = null;
|
let normalizationRect = null;
|
||||||
if (showCrop && cropRect) {
|
if (showCrop && cropRect) {
|
||||||
let video: any = videoRef.current;
|
let video: any = videoRef.current;
|
||||||
|
Loading…
Reference in New Issue
Block a user