forked from ddrilling/asb_cloud_front
102 lines
2.7 KiB
TypeScript
102 lines
2.7 KiB
TypeScript
import moment from 'moment'
|
|
import { useState, useEffect, memo, ReactNode } from 'react'
|
|
import {CaretUpOutlined, CaretDownOutlined, CaretRightOutlined} from '@ant-design/icons'
|
|
|
|
import '@styles/display.less'
|
|
|
|
export const formatNumber = (value?: unknown, format?: number) =>
|
|
Number.isInteger(format) && Number.isFinite(value)
|
|
? Number(value).toFixed(format)
|
|
: Number(value).toPrecision(4)
|
|
|
|
const iconStyle = { color:'#0008' }
|
|
const displayValueStyle = { display: 'flex', flexGrow: 1 }
|
|
|
|
export type ValueDisplayProps = {
|
|
prefix?: ReactNode
|
|
suffix?: ReactNode
|
|
format?: number | string | ((arg: string) => ReactNode)
|
|
isArrowVisible?: boolean
|
|
enumeration?: Record<string, string>
|
|
value: string
|
|
}
|
|
|
|
export type DisplayProps = ValueDisplayProps & {
|
|
className?: string
|
|
label?: ReactNode
|
|
}
|
|
|
|
export const ValueDisplay = memo<ValueDisplayProps>(({ prefix, value, suffix, isArrowVisible, format, enumeration }) => {
|
|
const [val, setVal] = useState<ReactNode>('---')
|
|
const [arrowState, setArrowState] = useState({
|
|
preVal: NaN,
|
|
preTimestamp: Date.now(),
|
|
direction: 0,
|
|
})
|
|
|
|
useEffect(() => {
|
|
setVal((preVal) => {
|
|
if ((value ?? '-') === '-' || value === '--') return '---'
|
|
if (typeof format === 'function') return format(enumeration?.[value] ?? value)
|
|
if (enumeration?.[value]) return enumeration[value]
|
|
|
|
if (Number.isFinite(+value)) {
|
|
if (isArrowVisible && (arrowState.preTimestamp + 1000 < Date.now())) {
|
|
let direction = 0
|
|
if (+value > arrowState.preVal)
|
|
direction = 1
|
|
if (+value < arrowState.preVal)
|
|
direction = -1
|
|
|
|
setArrowState({
|
|
preVal: +value,
|
|
preTimestamp: Date.now(),
|
|
direction: direction,
|
|
})
|
|
}
|
|
|
|
return formatNumber(value, Number(format))
|
|
}
|
|
|
|
if (value.length > 4) {
|
|
const valueDate = moment(value)
|
|
if (valueDate.isValid())
|
|
return valueDate.format(String(format))
|
|
}
|
|
|
|
return value
|
|
})
|
|
},[value, isArrowVisible, arrowState, format, enumeration])
|
|
|
|
let arrow = null
|
|
if(isArrowVisible)
|
|
switch (arrowState.direction){
|
|
case 0:
|
|
arrow = <CaretRightOutlined style={iconStyle}/>
|
|
break
|
|
case 1:
|
|
arrow = <CaretUpOutlined style={iconStyle}/>
|
|
break
|
|
case -1:
|
|
arrow = <CaretDownOutlined style={iconStyle}/>
|
|
break
|
|
default:
|
|
break
|
|
}
|
|
|
|
return(
|
|
<span className={'display_value'}>
|
|
{prefix} {val} {suffix}{arrow}
|
|
</span>
|
|
)
|
|
})
|
|
|
|
export const Display = memo<DisplayProps>(({ className, label, ...other })=> (
|
|
<div className={className}>
|
|
<div className={'display_label'}>{label}</div>
|
|
<div style={displayValueStyle}>
|
|
<ValueDisplay {...other}/>
|
|
</div>
|
|
</div>
|
|
))
|