forked from ddrilling/asb_cloud_front
Добавлен компонент для логгирования непрерывных значений LiveLog
This commit is contained in:
parent
923d469a86
commit
98f66dec1f
86
src/components/LiveLog.tsx
Normal file
86
src/components/LiveLog.tsx
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { createContext, ReactNode, useCallback, useContext, useMemo, useState } from 'react'
|
||||||
|
import { CloseOutlined } from '@ant-design/icons'
|
||||||
|
import { Button } from 'antd'
|
||||||
|
|
||||||
|
import { FunctionalValue, getFunctionalValue, isDev } from '@utils'
|
||||||
|
|
||||||
|
import '@styles/components/live_log.less'
|
||||||
|
|
||||||
|
export type LogType = 'info' | 'warn' | 'error' | 'critical'
|
||||||
|
export type VarType = { value: any, type: LogType }
|
||||||
|
|
||||||
|
export type LogContext = (varName: string, value: FunctionalValue<(prev?: any) => any>, type?: FunctionalValue<(prev: LogType) => LogType>) => void
|
||||||
|
|
||||||
|
export const LiveLogContext = createContext<LogContext>(() => {})
|
||||||
|
|
||||||
|
const renderVar = (name: string, value: any, type: LogType, remove: (name: string) => void) => {
|
||||||
|
if (typeof value === 'object')
|
||||||
|
value = JSON.stringify(value)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={`log-row log-${type}`}>
|
||||||
|
<span className={'log-close'} title={'Удалить значение'} onClick={() => remove(name)}><CloseOutlined /></span>
|
||||||
|
<span className={'log-name'}>{name}:</span>
|
||||||
|
<span className={'log-value'}>{String(value)}</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export type LiveLogProps = {
|
||||||
|
placement?: 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
||||||
|
children: JSX.Element
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LiveLog = ({ placement = 'top-left', children }: LiveLogProps) => {
|
||||||
|
if (!isDev()) return children
|
||||||
|
|
||||||
|
const [logMsgs, setLogMsgs] = useState<Record<string, VarType | undefined>>({})
|
||||||
|
|
||||||
|
const clear = useCallback(() => setLogMsgs({}), [])
|
||||||
|
|
||||||
|
const removeVar = useCallback((name: string) => {
|
||||||
|
setLogMsgs((prev) => {
|
||||||
|
if (!(name in prev)) return prev
|
||||||
|
const newMsgs = { ...prev }
|
||||||
|
delete newMsgs[name]
|
||||||
|
return newMsgs
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const log: LogContext = useCallback((varName, value, type) => {
|
||||||
|
setLogMsgs((prev) => {
|
||||||
|
const newValue = getFunctionalValue(value)(prev[varName]?.value)
|
||||||
|
const newType = getFunctionalValue(type)(prev[varName]?.type)
|
||||||
|
return {
|
||||||
|
...prev,
|
||||||
|
[varName]: {
|
||||||
|
type: newType || 'info',
|
||||||
|
value: newValue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const logInner = useMemo(() => Object.entries(logMsgs).map(([name, value]) => value && renderVar(name, value.value, value.type, removeVar)), [logMsgs, removeVar])
|
||||||
|
const isEmpty = useMemo(() => Object.keys(logMsgs).length <= 0, [logMsgs])
|
||||||
|
return (
|
||||||
|
<LiveLogContext.Provider value={log}>
|
||||||
|
{isEmpty || (
|
||||||
|
<div className={`log-box log-box-${placement}`}>
|
||||||
|
<div className={'log-box-label'}>
|
||||||
|
<span className={'log-box-label'}>Непрерывные значения</span>
|
||||||
|
<Button type={'link'} title={'Очистить'} onClick={clear}><CloseOutlined /></Button>
|
||||||
|
</div>
|
||||||
|
<div className={'log-box-content'}>
|
||||||
|
{logInner}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{children}
|
||||||
|
</LiveLogContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useLiveLog = () => useContext(LiveLogContext)
|
||||||
|
|
||||||
|
export default LiveLog
|
@ -3,6 +3,7 @@ import { ConfigProvider } from 'antd'
|
|||||||
import { createRoot } from 'react-dom/client'
|
import { createRoot } from 'react-dom/client'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
|
|
||||||
|
import LiveLog from '@components/LiveLog'
|
||||||
import { getUser } from '@utils'
|
import { getUser } from '@utils'
|
||||||
import { OpenAPI } from '@api'
|
import { OpenAPI } from '@api'
|
||||||
|
|
||||||
@ -22,7 +23,9 @@ const root = createRoot(container)
|
|||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<ConfigProvider locale={locale}>
|
<ConfigProvider locale={locale}>
|
||||||
|
<LiveLog>
|
||||||
<App />
|
<App />
|
||||||
|
</LiveLog>
|
||||||
</ConfigProvider>
|
</ConfigProvider>
|
||||||
</React.StrictMode>
|
</React.StrictMode>
|
||||||
)
|
)
|
||||||
|
@ -33,6 +33,7 @@ import SpinPicDisabled from '@images/SpinDisabled.png'
|
|||||||
|
|
||||||
import '@styles/pages/telemetry_view.less'
|
import '@styles/pages/telemetry_view.less'
|
||||||
import '@styles/pages/message.less'
|
import '@styles/pages/message.less'
|
||||||
|
import { useLiveLog } from '@asb/components/LiveLog'
|
||||||
|
|
||||||
const { Option } = Select
|
const { Option } = Select
|
||||||
|
|
||||||
@ -90,6 +91,8 @@ const TelemetryView = memo(() => {
|
|||||||
|
|
||||||
const [archiveMode, setArchiveMode] = useState(false)
|
const [archiveMode, setArchiveMode] = useState(false)
|
||||||
|
|
||||||
|
const log = useLiveLog()
|
||||||
|
|
||||||
const onStatusChanged = useCallback((value) => updateWell({ idState: value }), [well])
|
const onStatusChanged = useCallback((value) => updateWell({ idState: value }), [well])
|
||||||
|
|
||||||
const handleDataSaub = useCallback((data, replace = false) => {
|
const handleDataSaub = useCallback((data, replace = false) => {
|
||||||
@ -116,6 +119,7 @@ const TelemetryView = memo(() => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const onWheel = useCallback((e) => {
|
const onWheel = useCallback((e) => {
|
||||||
|
log('Wheel count', (prev) => prev ? prev + 1 : 1, 'warn')
|
||||||
if (!archiveMode && e.deltaY < 0) {
|
if (!archiveMode && e.deltaY < 0) {
|
||||||
setArchiveMode(true)
|
setArchiveMode(true)
|
||||||
} else if (archiveMode) {
|
} else if (archiveMode) {
|
||||||
|
53
src/styles/components/live_log.less
Normal file
53
src/styles/components/live_log.less
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
.log-box {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 1000;
|
||||||
|
background-color: rgba(0,0,0,.5);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
color: white;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
overflow-x: hidden;
|
||||||
|
width: 300px;
|
||||||
|
|
||||||
|
&.log-box-top-left { top: 10px; left: 10px; }
|
||||||
|
&.log-box-top-right { top: 10px; right: 10px; }
|
||||||
|
&.log-box-bottom-left { bottom: 10px; left: 10px; }
|
||||||
|
&.log-box-bottom-right { bottom: 10px; right: 10px; }
|
||||||
|
|
||||||
|
& .log-box-label {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
& span {
|
||||||
|
font-size: 1.25em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
& .log-box-content {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: stretch;
|
||||||
|
gap: 5px;
|
||||||
|
|
||||||
|
& .log-row {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
|
||||||
|
& .log-close {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .log-name {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.log-info { color: white }
|
||||||
|
&.log-warn { color: #faad14 }
|
||||||
|
&.log-error { color: #ff4d4f }
|
||||||
|
&.log-critical { color: #ff4d4f; font-weight: bolder; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user