From 371d754dbc275f3720b6dc7628399d51cbd7b276 Mon Sep 17 00:00:00 2001 From: zhaowei Date: Thu, 8 May 2025 15:16:15 +0800 Subject: [PATCH 1/4] =?UTF-8?q?feat:=20=E5=AE=9A=E6=97=B6=E5=88=B7?= =?UTF-8?q?=E6=96=B0=E6=89=A7=E8=A1=8C=E6=97=B6=E9=97=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ActiveLearn/Instance/index.tsx | 17 +++++++++++++++++ .../components/ActiveLearnBasic/index.tsx | 7 ++++--- react-ui/src/pages/AutoML/Instance/index.tsx | 17 +++++++++++++++++ .../AutoML/components/AutoMLBasic/index.tsx | 13 ++++++++++--- react-ui/src/pages/Experiment/Info/index.jsx | 15 ++++++++------- .../components/ExperimentDrawer/index.tsx | 10 ++++++---- .../src/pages/HyperParameter/Instance/index.tsx | 17 +++++++++++++++++ .../components/HyperParameterBasic/index.tsx | 6 ++++-- react-ui/src/utils/index.ts | 11 +++++++++++ 9 files changed, 94 insertions(+), 19 deletions(-) diff --git a/react-ui/src/pages/ActiveLearn/Instance/index.tsx b/react-ui/src/pages/ActiveLearn/Instance/index.tsx index 680f935c..756acfd4 100644 --- a/react-ui/src/pages/ActiveLearn/Instance/index.tsx +++ b/react-ui/src/pages/ActiveLearn/Instance/index.tsx @@ -35,6 +35,8 @@ function ActiveLearnInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); + const [currentTime, setCurrentTime] = useState(); + const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -46,6 +48,20 @@ function ActiveLearnInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); + // 定时刷新耗时 + useEffect(() => { + if (finish_time) { + setCurrentTime(new Date(finish_time)); + } else { + const timer = setInterval(() => { + setCurrentTime(new Date()); + }, 1000); + return () => { + clearInterval(timer); + }; + } + }, [finish_time]); + // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getActiveLearnInsReq(instanceId)); @@ -153,6 +169,7 @@ function ActiveLearnInstance() { className={styles['active-learn-instance__basic']} info={experimentInfo} runStatus={workflowStatus} + finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx index 892e6725..e76fe67b 100644 --- a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx +++ b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx @@ -31,9 +31,10 @@ type BasicInfoProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + finishTime?: Date; }; -function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfoProps) { +function BasicInfo({ info, className, runStatus, finishTime, isInstance = false }: BasicInfoProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -218,7 +219,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo }, { label: '执行时长', - value: elapsedTime(info.create_time, runStatus.finishedAt), + value: elapsedTime(info.create_time, finishTime), ellipsis: true, }, { @@ -245,7 +246,7 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo ellipsis: true, }, ]; - }, [runStatus, info]); + }, [runStatus, info, finishTime]); return (
diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 44489ea7..4ffb085a 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -35,6 +35,8 @@ function AutoMLInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); + const [currentTime, setCurrentTime] = useState(); + const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -46,6 +48,20 @@ function AutoMLInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); + // 定时刷新耗时 + useEffect(() => { + if (finish_time) { + setCurrentTime(new Date(finish_time)); + } else { + const timer = setInterval(() => { + setCurrentTime(new Date()); + }, 1000); + return () => { + clearInterval(timer); + }; + } + }, [finish_time]); + // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getExperimentInsReq(instanceId)); @@ -156,6 +172,7 @@ function AutoMLInstance() { className={styles['auto-ml-instance__basic']} info={autoMLInfo} runStatus={workflowStatus} + finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx index 98a1f4ba..e31c7ecb 100644 --- a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx +++ b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx @@ -40,9 +40,16 @@ type AutoMLBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + finishTime?: Date; }; -function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) { +function AutoMLBasic({ + info, + className, + runStatus, + finishTime, + isInstance = false, +}: AutoMLBasicProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -296,7 +303,7 @@ function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLB }, { label: '执行时长', - value: elapsedTime(info.create_time, runStatus.finishedAt), + value: elapsedTime(info.create_time, finishTime), }, { label: '状态', @@ -321,7 +328,7 @@ function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLB ), }, ]; - }, [runStatus, info]); + }, [runStatus, info, finishTime]); return (
diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index 7ecaf4ee..d7d7b16b 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -27,11 +27,12 @@ function ExperimentText() { const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); const [propsDrawerOpen, openPropsDrawer, closePropsDrawer, propsDrawerOpenRef] = useVisible(false); - const [currentDate, setCurrentDate] = useState(); + const [currentTime, setCurrentTime] = useState(); const navigate = useNavigate(); const evtSourceRef = useRef(); const width = 110; const height = 36; + const finish_time = experimentIns?.finish_time useEffect(() => { initGraph(); @@ -62,16 +63,17 @@ function ExperimentText() { // 定时刷新耗时 useEffect(() => { - if (experimentIns && !experimentIns.finish_time) { + if (finish_time) { + setCurrentTime(new Date(finish_time)); + } else { const timer = setInterval(() => { - setCurrentDate(new Date()); - console.log('定时刷新'); + setCurrentTime(new Date()); }, 1000); return () => { clearInterval(timer); }; } - }, [experimentIns]); + }, [finish_time]); // 获取流水线模版 const getWorkflow = async () => { @@ -100,7 +102,6 @@ function ExperimentText() { if (res && res.data && workflowRef.current) { setExperimentIns(res.data); const { status, nodes_status, argo_ins_ns, argo_ins_name, finish_time } = res.data; - setCurrentDate(new Date(finish_time)); const workflowData = workflowRef.current; const experimentStatusObjs = parseJsonText(nodes_status); workflowData.nodes.forEach((item) => { @@ -489,7 +490,7 @@ function ExperimentText() {
执行时长: - {elapsedTime(experimentIns?.create_time, experimentIns?.finish_time)} + {elapsedTime(experimentIns?.create_time, currentTime)}
状态: diff --git a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx index bcb3af1e..a74690ac 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx @@ -41,15 +41,17 @@ const ExperimentDrawer = ({ instanceNodeStartTime, instanceNodeEndTime, }: ExperimentDrawerProps) => { - const [currentDate, setCurrentDate] = useState( + const [currentTime, setCurrentTime] = useState( instanceNodeEndTime ? new Date(instanceNodeEndTime) : new Date(), ); // 定时刷新耗时 useEffect(() => { - if (!instanceNodeEndTime) { + if (instanceNodeEndTime) { + setCurrentTime(new Date(instanceNodeEndTime)); + } else { const timer = setInterval(() => { - setCurrentDate(new Date()); + setCurrentTime(new Date()); }, 1000); return () => { clearInterval(timer); @@ -158,7 +160,7 @@ const ExperimentDrawer = ({
耗时: - {elapsedTime(instanceNodeStartTime, currentDate)} + {elapsedTime(instanceNodeStartTime, currentTime)}
(null); + const [currentTime, setCurrentTime] = useState(); + const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -46,6 +48,20 @@ function HyperParameterInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); + // 定时刷新耗时 + useEffect(() => { + if (finish_time) { + setCurrentTime(new Date(finish_time)); + } else { + const timer = setInterval(() => { + setCurrentTime(new Date()); + }, 1000); + return () => { + clearInterval(timer); + }; + } + }, [finish_time]); + // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getRayInsReq(instanceId)); @@ -168,6 +184,7 @@ function HyperParameterInstance() { className={styles['hyper-parameter-instance__basic']} info={experimentInfo} runStatus={workflowStatus} + finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx index 89487cb6..e62bc6ff 100644 --- a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx @@ -33,12 +33,14 @@ type HyperParameterBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + finishTime?: Date; }; function HyperParameterBasic({ info, className, runStatus, + finishTime, isInstance = false, }: HyperParameterBasicProps) { const getResourceDescription = useComputingResource()[1]; @@ -155,7 +157,7 @@ function HyperParameterBasic({ }, { label: '执行时长', - value: elapsedTime(info.create_time, runStatus.finishedAt), + value: elapsedTime(info.create_time, finishTime), ellipsis: true, }, { @@ -182,7 +184,7 @@ function HyperParameterBasic({ ellipsis: true, }, ]; - }, [runStatus, info]); + }, [runStatus, info, finishTime]); return (
diff --git a/react-ui/src/utils/index.ts b/react-ui/src/utils/index.ts index 3113c8ea..995f3501 100644 --- a/react-ui/src/utils/index.ts +++ b/react-ui/src/utils/index.ts @@ -6,6 +6,7 @@ import { PageEnum } from '@/enums/pagesEnums'; import G6 from '@antv/g6'; +import { number } from 'echarts'; /** * 生成 8 位随机数 @@ -346,3 +347,13 @@ export const trimCharacter = (str: string, ch: string): string => { export const convertEmptyStringToUndefined = (value?: string): string | undefined => { return value === '' ? undefined : value; }; + + +export const formatNumber = (value?: number | null, toFixed?: number) : number | string => { + if (typeof value !== "number") { + return '--' + } + + return toFixed ? Number(value).toFixed(toFixed) : value +} + From bef5bf649ef7e61cb460145bdc870d545fbb4a52 Mon Sep 17 00:00:00 2001 From: zhaowei Date: Fri, 9 May 2025 11:43:25 +0800 Subject: [PATCH 2/4] =?UTF-8?q?fix:=20=E5=AE=9E=E9=AA=8C=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E6=97=B6=E9=95=BF=E5=AE=9A=E6=97=B6=E5=88=B7=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/app.tsx | 2 + react-ui/src/hooks/useSSE.ts | 39 +++--- react-ui/src/hooks/useServerTime.ts | 54 ++++++++ .../src/pages/ActiveLearn/Instance/index.tsx | 14 +- react-ui/src/pages/AutoML/Instance/index.tsx | 14 +- .../index.less | 0 .../index.tsx | 43 ++----- .../ExperimentInstanceList/instance.tsx | 83 ++++++++++++ .../components/ExperimentList/index.tsx | 121 ++++++++++++------ react-ui/src/pages/Experiment/Info/index.jsx | 8 +- .../components/ExperimentDrawer/index.tsx | 10 +- .../index.less | 0 .../index.tsx | 45 +++---- .../ExperimentInstanceList/instance.tsx | 85 ++++++++++++ react-ui/src/pages/Experiment/index.jsx | 117 +++++++++++------ .../pages/HyperParameter/Instance/index.tsx | 14 +- .../Points/components/Statistics/index.less | 1 + .../Points/components/Statistics/index.tsx | 13 +- .../Workspace/components/UserPoints/index.tsx | 7 +- react-ui/src/services/experiment/index.js | 8 ++ react-ui/src/utils/constant.ts | 3 + react-ui/src/utils/format.ts | 16 +++ react-ui/src/utils/index.ts | 9 -- 23 files changed, 503 insertions(+), 203 deletions(-) create mode 100644 react-ui/src/hooks/useServerTime.ts rename react-ui/src/pages/AutoML/components/{ExperimentInstance => ExperimentInstanceList}/index.less (100%) rename react-ui/src/pages/AutoML/components/{ExperimentInstance => ExperimentInstanceList}/index.tsx (83%) create mode 100644 react-ui/src/pages/AutoML/components/ExperimentInstanceList/instance.tsx rename react-ui/src/pages/Experiment/components/{ExperimentInstance => ExperimentInstanceList}/index.less (100%) rename react-ui/src/pages/Experiment/components/{ExperimentInstance => ExperimentInstanceList}/index.tsx (84%) create mode 100644 react-ui/src/pages/Experiment/components/ExperimentInstanceList/instance.tsx diff --git a/react-ui/src/app.tsx b/react-ui/src/app.tsx index ac8b8652..686c495d 100644 --- a/react-ui/src/app.tsx +++ b/react-ui/src/app.tsx @@ -11,6 +11,7 @@ import { getAccessToken } from './access'; import ErrorBoundary from './components/ErrorBoundary'; import './dayjsConfig'; import { removeAllPageCacheState } from './hooks/useCacheState'; +import { globalGetSeverTime } from './hooks/useServerTime'; import { getRemoteMenu, getRoutersInfo, @@ -29,6 +30,7 @@ export { requestConfig as request } from './requestConfig'; export async function getInitialState(): Promise { const fetchUserInfo = async () => { try { + globalGetSeverTime(); const response = await getUserInfo(); return { ...response.user, diff --git a/react-ui/src/hooks/useSSE.ts b/react-ui/src/hooks/useSSE.ts index 5e278675..9f364f68 100644 --- a/react-ui/src/hooks/useSSE.ts +++ b/react-ui/src/hooks/useSSE.ts @@ -1,11 +1,12 @@ import { parseJsonText } from '@/utils'; -import { useCallback, useRef } from 'react'; +import { useEffect } from 'react'; +import { ExperimentStatus } from '@/enums'; +import { NodeStatus } from '@/types'; -export const useSSE = (onMessage: (data: any) => void) => { - const evtSourceRef = useRef(null); - - const setupSSE = useCallback( - (name: string, namespace: string) => { +export type MessageHandler = (experimentInsId: number, status: string, finishedAt: string, nodes: Record) => void +export const useSSE = (experimentInsId: number, status: ExperimentStatus, name: string, namespace: string, onMessage: MessageHandler) => { + useEffect(() => { + if (status === ExperimentStatus.Pending || status === ExperimentStatus.Running) { const { origin } = location; const params = encodeURIComponent(`metadata.namespace=${namespace},metadata.name=${name}`); const evtSource = new EventSource( @@ -18,11 +19,10 @@ export const useSSE = (onMessage: (data: any) => void) => { return; } const dataJson = parseJsonText(data); - if (dataJson) { - const nodes = dataJson?.result?.object?.status?.nodes; - if (nodes) { - onMessage(nodes); - } + const statusData = dataJson?.result?.object?.status; + if (statusData) { + const { finishedAt, phase, nodes } = statusData; + onMessage(experimentInsId, phase, finishedAt, nodes); } }; @@ -30,17 +30,10 @@ export const useSSE = (onMessage: (data: any) => void) => { console.error('SSE error: ', error); }; - evtSourceRef.current = evtSource; - }, - [onMessage], - ); - - const closeSSE = useCallback(() => { - if (evtSourceRef.current) { - evtSourceRef.current.close(); - evtSourceRef.current = null; + return () => { + evtSource.close(); + } } - }, []); - - return [setupSSE, closeSSE]; + + }, [experimentInsId, status, name, namespace, onMessage]); }; diff --git a/react-ui/src/hooks/useServerTime.ts b/react-ui/src/hooks/useServerTime.ts new file mode 100644 index 00000000..89b39775 --- /dev/null +++ b/react-ui/src/hooks/useServerTime.ts @@ -0,0 +1,54 @@ +/* + * @Author: 赵伟 + * @Date: 2024-10-10 08:51:41 + * @Description: 服务器时间 hook + */ + +import { getSeverTimeReq } from '@/services/experiment'; +import { to } from '@/utils/promise'; +import { useCallback, useEffect, useState } from 'react'; + +let globalTimeOffset: number | undefined = undefined; + +export const globalGetSeverTime = async () => { + const requestStartTime = Date.now() + const [res] = await to(getSeverTimeReq()); + const requestEndTime = Date.now() + const requestDuration = (requestEndTime - requestStartTime) / 2; + if (res && res.data) { + const serverDate = new Date(res.data); + const timeOffset = serverDate.getTime() + requestDuration - requestEndTime ; + globalTimeOffset = timeOffset; + return timeOffset + } +}; + +export const now = () => { + return new Date(Date.now() + (globalTimeOffset ?? 0)) +} + +/** 获取服务器时间 */ +export function useServerTime() { + const [timeOffset, setTimeOffset] = useState(globalTimeOffset ?? 0); + + useEffect(() => { + // 获取服务器时间 + const getSeverTime = async () => { + const [res] = await to(globalGetSeverTime()); + if (res) { + setTimeOffset(res) + } + }; + + if (!globalTimeOffset) { + getSeverTime(); + } + }, []); + + const now = useCallback(() => { + return new Date(Date.now() + timeOffset) + }, [timeOffset]) + + + return [now, timeOffset] as const; +} diff --git a/react-ui/src/pages/ActiveLearn/Instance/index.tsx b/react-ui/src/pages/ActiveLearn/Instance/index.tsx index 756acfd4..ba62fae7 100644 --- a/react-ui/src/pages/ActiveLearn/Instance/index.tsx +++ b/react-ui/src/pages/ActiveLearn/Instance/index.tsx @@ -1,5 +1,6 @@ import KFIcon from '@/components/KFIcon'; import { AutoMLTaskType, ExperimentStatus } from '@/enums'; +import { useServerTime } from '@/hooks/useServerTime'; import { getActiveLearnInsReq } from '@/services/activeLearn'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; @@ -35,7 +36,8 @@ function ActiveLearnInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); - const [currentTime, setCurrentTime] = useState(); + const [now] = useServerTime(); + const [currentTime, setCurrentTime] = useState(now()); const finish_time = workflowStatus?.finishedAt; useEffect(() => { @@ -54,13 +56,13 @@ function ActiveLearnInstance() { setCurrentTime(new Date(finish_time)); } else { const timer = setInterval(() => { - setCurrentTime(new Date()); + setCurrentTime(now()); }, 1000); return () => { clearInterval(timer); }; } - }, [finish_time]); + }, [finish_time, now]); // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { @@ -122,13 +124,13 @@ function ActiveLearnInstance() { if (dataJson) { const nodes = dataJson?.result?.object?.status?.nodes; if (nodes) { + // 节点 + setNodes(nodes); + const workflowStatus = Object.values(nodes).find((node: any) => node.displayName.startsWith(NodePrefix), ) as NodeStatus; - // 节点 - setNodes(nodes); - // 设置工作流状态 if (workflowStatus) { setWorkflowStatus(workflowStatus); diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 4ffb085a..675b02d4 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -1,5 +1,6 @@ import KFIcon from '@/components/KFIcon'; import { AutoMLTaskType, AutoMLType, ExperimentStatus } from '@/enums'; +import { useServerTime } from '@/hooks/useServerTime'; import { getExperimentInsReq } from '@/services/autoML'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; @@ -35,7 +36,8 @@ function AutoMLInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); - const [currentTime, setCurrentTime] = useState(); + const [now] = useServerTime(); + const [currentTime, setCurrentTime] = useState(now()); const finish_time = workflowStatus?.finishedAt; useEffect(() => { @@ -54,13 +56,13 @@ function AutoMLInstance() { setCurrentTime(new Date(finish_time)); } else { const timer = setInterval(() => { - setCurrentTime(new Date()); + setCurrentTime(now()); }, 1000); return () => { clearInterval(timer); }; } - }, [finish_time]); + }, [finish_time, now]); // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { @@ -126,13 +128,13 @@ function AutoMLInstance() { if (dataJson) { const nodes = dataJson?.result?.object?.status?.nodes; if (nodes) { + // 节点 + setNodes(nodes); + const workflowStatus = Object.values(nodes).find((node: any) => node.displayName.startsWith(NodePrefix), ) as NodeStatus; - // 节点 - setNodes(nodes); - if (workflowStatus) { setWorkflowStatus(workflowStatus); diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.less b/react-ui/src/pages/AutoML/components/ExperimentInstanceList/index.less similarity index 100% rename from react-ui/src/pages/AutoML/components/ExperimentInstance/index.less rename to react-ui/src/pages/AutoML/components/ExperimentInstanceList/index.less diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentInstanceList/index.tsx similarity index 83% rename from react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx rename to react-ui/src/pages/AutoML/components/ExperimentInstanceList/index.tsx index 74cf1115..05d6d786 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstance/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentInstanceList/index.tsx @@ -1,20 +1,19 @@ import KFIcon from '@/components/KFIcon'; import { ExperimentStatus } from '@/enums'; import { useCheck } from '@/hooks/useCheck'; -import { experimentStatusInfo } from '@/pages/Experiment/status'; import themes from '@/styles/theme.less'; import { type ExperimentInstance } from '@/types'; -import { elapsedTime, formatDate } from '@/utils/date'; import { to } from '@/utils/promise'; import { modalConfirm } from '@/utils/ui'; import { DoubleRightOutlined } from '@ant-design/icons'; -import { App, Button, Checkbox, ConfigProvider, Typography } from 'antd'; +import { App, Button, Checkbox, ConfigProvider } from 'antd'; import classNames from 'classnames'; import { useEffect, useMemo } from 'react'; import { ExperimentListType, experimentListConfig } from '../ExperimentList/config'; import styles from './index.less'; +import ExperimentInstanceComponent from './instance'; -type ExperimentInstanceProps = { +type ExperimentInstanceListProps = { type: ExperimentListType; experimentInsList?: ExperimentInstance[]; experimentInsTotal: number; @@ -24,7 +23,7 @@ type ExperimentInstanceProps = { onLoadMore?: () => void; }; -function ExperimentInstanceComponent({ +function ExperimentInstanceList({ type, experimentInsList, experimentInsTotal, @@ -32,7 +31,7 @@ function ExperimentInstanceComponent({ onRemove, onTerminate, onLoadMore, -}: ExperimentInstanceProps) { +}: ExperimentInstanceListProps) { const { message } = App.useApp(); const allIntanceIds = useMemo(() => { return experimentInsList?.map((item) => item.id) || []; @@ -171,28 +170,14 @@ function ExperimentInstanceComponent({ > {index + 1} -
- {elapsedTime(item.create_time, item.finish_time)} -
-
- - {formatDate(item.create_time)} - -
-
- - - {experimentStatusInfo[item.status as ExperimentStatus]?.label} - -
+
-
-
{elapsedTime(item.create_time, item.finish_time)}
-
- - {formatDate(item.create_time)} - -
-
-
- - - {experimentStatusInfo[item.status as ExperimentStatus]?.label} - -
+ + +
))} diff --git a/react-ui/src/pages/Workspace/components/UserPoints/index.tsx b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx index 98e63cbf..a6eb3ece 100644 --- a/react-ui/src/pages/Workspace/components/UserPoints/index.tsx +++ b/react-ui/src/pages/Workspace/components/UserPoints/index.tsx @@ -1,5 +1,6 @@ import { PointsStatistics } from '@/pages/Points/index'; import { getPointsStatisticsReq } from '@/services/points'; +import { formatNumber } from '@/utils/format'; import { to } from '@/utils/promise'; import { useNavigate } from '@umijs/max'; import { Typography } from 'antd'; @@ -22,14 +23,16 @@ function UserPoints() { getPointsStatistics(); }, []); + const userCredit = formatNumber(statistics?.userCredit); + return (
当前可用算力积分
- {statistics?.userCredit ?? '--'} + {userCredit}
{ return option && option.label ? option.label : '--'; }; }; + + +/** + * 格式化数字 + * + * @param value - 值、 + * @param toFixed - 保留几位小数 + * @return 格式化的数字,如果不是数字,返回 '--' + */ +export const formatNumber = (value?: number | null, toFixed?: number) : number | string => { + if (typeof value !== "number") { + return '--' + } + + return toFixed ? Number(value).toFixed(toFixed) : value +} diff --git a/react-ui/src/utils/index.ts b/react-ui/src/utils/index.ts index 995f3501..a6fba453 100644 --- a/react-ui/src/utils/index.ts +++ b/react-ui/src/utils/index.ts @@ -348,12 +348,3 @@ export const convertEmptyStringToUndefined = (value?: string): string | undefine return value === '' ? undefined : value; }; - -export const formatNumber = (value?: number | null, toFixed?: number) : number | string => { - if (typeof value !== "number") { - return '--' - } - - return toFixed ? Number(value).toFixed(toFixed) : value -} - From 08fce258b642388e74ce8c428a2273cfcbd94a7d Mon Sep 17 00:00:00 2001 From: zhaowei Date: Fri, 9 May 2025 14:56:41 +0800 Subject: [PATCH 3/4] =?UTF-8?q?refactor:=20=E8=BF=90=E8=A1=8C=E6=97=B6?= =?UTF-8?q?=E9=95=BF=E6=8F=90=E5=8F=96=E6=88=90=E7=BB=84=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- react-ui/src/components/RunDuration/index.tsx | 35 +++++++++++++++++++ .../src/pages/ActiveLearn/Instance/index.tsx | 19 ---------- .../components/ActiveLearnBasic/index.tsx | 12 +++---- react-ui/src/pages/AutoML/Instance/index.tsx | 19 ---------- .../AutoML/components/AutoMLBasic/index.tsx | 15 +++----- .../ExperimentInstanceList/instance.tsx | 27 ++++---------- .../components/ExperimentList/index.tsx | 15 ++++++-- react-ui/src/pages/Experiment/Info/index.jsx | 20 ++--------- .../components/ExperimentDrawer/index.tsx | 25 +++---------- .../ExperimentInstanceList/instance.tsx | 27 ++++---------- react-ui/src/pages/Experiment/index.jsx | 15 ++++++-- .../pages/HyperParameter/Instance/index.tsx | 21 +---------- .../components/HyperParameterBasic/index.tsx | 8 ++--- 13 files changed, 91 insertions(+), 167 deletions(-) create mode 100644 react-ui/src/components/RunDuration/index.tsx diff --git a/react-ui/src/components/RunDuration/index.tsx b/react-ui/src/components/RunDuration/index.tsx new file mode 100644 index 00000000..f430d058 --- /dev/null +++ b/react-ui/src/components/RunDuration/index.tsx @@ -0,0 +1,35 @@ +import { useServerTime } from '@/hooks/useServerTime'; +import { elapsedTime } from '@/utils/date'; +import React, { useEffect, useState } from 'react'; + +type RunDurationProps = { + createTime?: string; + finishTime?: string; + className?: string; + style?: React.CSSProperties; +}; +function RunDuration({ createTime, finishTime, className, style }: RunDurationProps) { + const [now] = useServerTime(); + const [currentTime, setCurrentTime] = useState(now()); + + // 定时刷新耗时 + useEffect(() => { + if (finishTime) { + setCurrentTime(new Date(finishTime)); + } else { + const timer = setInterval(() => { + setCurrentTime(now()); + }, 1000); + return () => { + clearInterval(timer); + }; + } + }, [finishTime, now]); + return ( + + {elapsedTime(createTime, currentTime)} + + ); +} + +export default RunDuration; diff --git a/react-ui/src/pages/ActiveLearn/Instance/index.tsx b/react-ui/src/pages/ActiveLearn/Instance/index.tsx index ba62fae7..d16d5428 100644 --- a/react-ui/src/pages/ActiveLearn/Instance/index.tsx +++ b/react-ui/src/pages/ActiveLearn/Instance/index.tsx @@ -1,6 +1,5 @@ import KFIcon from '@/components/KFIcon'; import { AutoMLTaskType, ExperimentStatus } from '@/enums'; -import { useServerTime } from '@/hooks/useServerTime'; import { getActiveLearnInsReq } from '@/services/activeLearn'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; @@ -36,9 +35,6 @@ function ActiveLearnInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); - const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -50,20 +46,6 @@ function ActiveLearnInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getActiveLearnInsReq(instanceId)); @@ -171,7 +153,6 @@ function ActiveLearnInstance() { className={styles['active-learn-instance__basic']} info={experimentInfo} runStatus={workflowStatus} - finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx index e76fe67b..5c0d4e3e 100644 --- a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx +++ b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx @@ -1,4 +1,5 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; +import RunDuration from '@/components/RunDuration'; import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; import { useComputingResource } from '@/hooks/useComputingResource'; import { @@ -11,7 +12,6 @@ import { import { ActiveLearnData } from '@/pages/ActiveLearn/types'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { type NodeStatus } from '@/types'; -import { elapsedTime } from '@/utils/date'; import { formatBoolean, formatCodeConfig, @@ -31,10 +31,9 @@ type BasicInfoProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; - finishTime?: Date; }; -function BasicInfo({ info, className, runStatus, finishTime, isInstance = false }: BasicInfoProps) { +function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfoProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -215,12 +214,10 @@ function BasicInfo({ info, className, runStatus, finishTime, isInstance = false { label: '启动时间', value: formatDate(info.create_time), - ellipsis: true, }, { label: '执行时长', - value: elapsedTime(info.create_time, finishTime), - ellipsis: true, + value: , }, { label: '状态', @@ -243,10 +240,9 @@ function BasicInfo({ info, className, runStatus, finishTime, isInstance = false
), - ellipsis: true, }, ]; - }, [runStatus, info, finishTime]); + }, [runStatus, info]); return (
diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 675b02d4..5f1b5e34 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -1,6 +1,5 @@ import KFIcon from '@/components/KFIcon'; import { AutoMLTaskType, AutoMLType, ExperimentStatus } from '@/enums'; -import { useServerTime } from '@/hooks/useServerTime'; import { getExperimentInsReq } from '@/services/autoML'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; @@ -36,9 +35,6 @@ function AutoMLInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); - const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -50,20 +46,6 @@ function AutoMLInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getExperimentInsReq(instanceId)); @@ -174,7 +156,6 @@ function AutoMLInstance() { className={styles['auto-ml-instance__basic']} info={autoMLInfo} runStatus={workflowStatus} - finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx index e31c7ecb..c421c59e 100644 --- a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx +++ b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx @@ -1,4 +1,5 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; +import RunDuration from '@/components/RunDuration'; import { AutoMLTaskType, AutoMLType, @@ -10,7 +11,6 @@ import { AutoMLData } from '@/pages/AutoML/types'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { type NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; -import { elapsedTime } from '@/utils/date'; import { formatBoolean, formatDataset, formatDate, formatEnum } from '@/utils/format'; import { Flex } from 'antd'; import classNames from 'classnames'; @@ -40,16 +40,9 @@ type AutoMLBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; - finishTime?: Date; }; -function AutoMLBasic({ - info, - className, - runStatus, - finishTime, - isInstance = false, -}: AutoMLBasicProps) { +function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -303,7 +296,7 @@ function AutoMLBasic({ }, { label: '执行时长', - value: elapsedTime(info.create_time, finishTime), + value: , }, { label: '状态', @@ -328,7 +321,7 @@ function AutoMLBasic({ ), }, ]; - }, [runStatus, info, finishTime]); + }, [runStatus, info]); return (
diff --git a/react-ui/src/pages/AutoML/components/ExperimentInstanceList/instance.tsx b/react-ui/src/pages/AutoML/components/ExperimentInstanceList/instance.tsx index 831879f2..402d27dd 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentInstanceList/instance.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentInstanceList/instance.tsx @@ -1,11 +1,11 @@ +import RunDuration from '@/components/RunDuration'; import { ExperimentStatus } from '@/enums'; -import { useServerTime } from '@/hooks/useServerTime'; import { useSSE, type MessageHandler } from '@/hooks/useSSE'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { ExperimentCompleted } from '@/utils/constant'; -import { elapsedTime, formatDate } from '@/utils/date'; +import { formatDate } from '@/utils/date'; import { Typography } from 'antd'; -import React, { useCallback, useEffect, useState } from 'react'; +import React, { useCallback } from 'react'; import styles from './index.less'; type ExperimentInstanceProps = { @@ -25,9 +25,6 @@ function ExperimentInstance({ argo_ins_ns, experimentInsId, }: ExperimentInstanceProps) { - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); - const handleSSEMessage: MessageHandler = useCallback( (experimentInsId: number, status: string, finish_time: string) => { window.postMessage({ @@ -43,23 +40,11 @@ function ExperimentInstance({ ); useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - return ( -
{elapsedTime(create_time, currentTime)}
+
+ +
{formatDate(create_time)} diff --git a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx index b4eeb199..442f38f5 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx @@ -29,7 +29,7 @@ import { } from 'antd'; import { type SearchProps } from 'antd/es/input'; import classNames from 'classnames'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import ExperimentInstanceList from '../ExperimentInstanceList'; import { ExperimentListType, experimentListConfig } from './config'; import styles from './index.less'; @@ -58,6 +58,7 @@ function ExperimentList({ type }: ExperimentListProps) { }, ); const config = experimentListConfig[type]; + const timerRef = useRef | undefined>(); // 获取自主机器学习或超参数自动优化列表 const getAutoMLList = useCallback(async () => { @@ -140,7 +141,13 @@ function ExperimentList({ type }: ExperimentListProps) { : v, ), ); - setTimeout(() => { + + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = undefined; + } + + timerRef.current = setTimeout(() => { refreshExperimentList(); }, 10000); } @@ -149,6 +156,10 @@ function ExperimentList({ type }: ExperimentListProps) { window.addEventListener('message', handleMessage); return () => { window.removeEventListener('message', handleMessage); + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = undefined; + } }; }, [refreshExperimentList]); diff --git a/react-ui/src/pages/Experiment/Info/index.jsx b/react-ui/src/pages/Experiment/Info/index.jsx index 39526410..60424e52 100644 --- a/react-ui/src/pages/Experiment/Info/index.jsx +++ b/react-ui/src/pages/Experiment/Info/index.jsx @@ -16,6 +16,7 @@ import ParamsModal from '../components/ViewParamsModal'; import { experimentStatusInfo } from '../status'; import styles from './index.less'; import { useServerTime } from '@/hooks/useServerTime'; +import RunDuration from '@/components/RunDuration'; let graph = null; @@ -28,13 +29,10 @@ function ExperimentText() { const [paramsModalOpen, openParamsModal, closeParamsModal] = useVisible(false); const [propsDrawerOpen, openPropsDrawer, closePropsDrawer, propsDrawerOpenRef] = useVisible(false); - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); const navigate = useNavigate(); const evtSourceRef = useRef(); const width = 110; const height = 36; - const finish_time = experimentIns?.finish_time useEffect(() => { initGraph(); @@ -63,20 +61,6 @@ function ExperimentText() { }; }, []); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - // 获取流水线模版 const getWorkflow = async () => { const [res] = await to(getWorkflowById(locationParams.workflowId)); @@ -492,7 +476,7 @@ function ExperimentText() {
执行时长: - {elapsedTime(experimentIns?.create_time, currentTime)} +
状态: diff --git a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx index 766b8f9a..11d0ff2e 100644 --- a/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx +++ b/react-ui/src/pages/Experiment/components/ExperimentDrawer/index.tsx @@ -1,11 +1,11 @@ +import RunDuration from '@/components/RunDuration'; import { ExperimentStatus } from '@/enums'; -import { useServerTime } from '@/hooks/useServerTime'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { PipelineNodeModelSerialize } from '@/types'; -import { elapsedTime, formatDate } from '@/utils/date'; +import { formatDate } from '@/utils/date'; import { CloseOutlined, DatabaseOutlined, ProfileOutlined } from '@ant-design/icons'; import { Drawer, Tabs, Typography } from 'antd'; -import { useEffect, useMemo, useState } from 'react'; +import { useMemo } from 'react'; import ExperimentParameter from '../ExperimentParameter'; import ExperimentResult from '../ExperimentResult'; import LogList from '../LogList'; @@ -42,23 +42,6 @@ const ExperimentDrawer = ({ instanceNodeStartTime, instanceNodeEndTime, }: ExperimentDrawerProps) => { - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); - - // 定时刷新耗时 - useEffect(() => { - if (instanceNodeEndTime) { - setCurrentTime(new Date(instanceNodeEndTime)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [instanceNodeEndTime, now]); - // 如果性能有问题,可以进一步拆解 const items = useMemo( () => [ @@ -160,7 +143,7 @@ const ExperimentDrawer = ({
耗时: - {elapsedTime(instanceNodeStartTime, currentTime)} +
(now()); - const handleSSEMessage: MessageHandler = useCallback( (experimentInsId: number, status: string, finish_time: string) => { window.postMessage({ @@ -43,24 +40,12 @@ function ExperimentInstance({ ); useSSE(experimentInsId, status, argo_ins_name, argo_ins_ns, handleSSEMessage); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - return (
-
{elapsedTime(create_time, currentTime)}
+
+ +
{formatDate(create_time)} diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index e424de20..e94c625c 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -21,7 +21,7 @@ import tableCellRender, { TableCellValueType } from '@/utils/table'; import { modalConfirm } from '@/utils/ui'; import { App, Button, ConfigProvider, Dropdown, Input, Space, Table, Tooltip } from 'antd'; import classNames from 'classnames'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { useNavigate } from 'react-router-dom'; import { ComparisonType } from './Comparison/config'; import AddExperimentModal from './components/AddExperimentModal'; @@ -54,6 +54,7 @@ function Experiment() { }, ); const { message } = App.useApp(); + const timerRef = useRef(); // 获取实验列表 const getExperimentList = useCallback(async () => { @@ -126,7 +127,13 @@ function Experiment() { : v, ), ); - setTimeout(() => { + + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = undefined; + } + + timerRef.current = setTimeout(() => { refreshExperimentList(); }, 10000); } @@ -135,6 +142,10 @@ function Experiment() { window.addEventListener('message', handleMessage); return () => { window.removeEventListener('message', handleMessage); + if (timerRef.current) { + clearTimeout(timerRef.current); + timerRef.current = undefined; + } }; }, [refreshExperimentList]); diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx index 148a38e7..a0ebae5b 100644 --- a/react-ui/src/pages/HyperParameter/Instance/index.tsx +++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx @@ -1,6 +1,5 @@ import KFIcon from '@/components/KFIcon'; import { ExperimentStatus } from '@/enums'; -import { useServerTime } from '@/hooks/useServerTime'; import { getRayInsReq } from '@/services/hyperParameter'; import { NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; @@ -36,9 +35,6 @@ function HyperParameterInstance() { const params = useParams(); const instanceId = safeInvoke(Number)(params.id); const evtSourceRef = useRef(null); - const [now] = useServerTime(); - const [currentTime, setCurrentTime] = useState(now()); - const finish_time = workflowStatus?.finishedAt; useEffect(() => { if (instanceId) { @@ -50,20 +46,6 @@ function HyperParameterInstance() { // eslint-disable-next-line react-hooks/exhaustive-deps }, [instanceId]); - // 定时刷新耗时 - useEffect(() => { - if (finish_time) { - setCurrentTime(new Date(finish_time)); - } else { - const timer = setInterval(() => { - setCurrentTime(now()); - }, 1000); - return () => { - clearInterval(timer); - }; - } - }, [finish_time, now]); - // 获取实验实例详情 const getExperimentInsInfo = async (isStatusDetermined: boolean) => { const [res] = await to(getRayInsReq(instanceId)); @@ -71,7 +53,7 @@ function HyperParameterInstance() { const info = res.data as HyperParameterInstanceData; const { param, node_status, argo_ins_name, argo_ins_ns, status, create_time } = info; // 解析配置参数 - const paramJson = parseJsonText(param); + const paramJson = parseJsonText(param).data; if (paramJson) { // 实例详情返回的参数是字符串,需要转换 if (typeof paramJson.parameters === 'string') { @@ -186,7 +168,6 @@ function HyperParameterInstance() { className={styles['hyper-parameter-instance__basic']} info={experimentInfo} runStatus={workflowStatus} - finishTime={currentTime} isInstance /> ), diff --git a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx index e62bc6ff..3e526848 100644 --- a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx @@ -1,4 +1,5 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; +import RunDuration from '@/components/RunDuration'; import { hyperParameterOptimizedMode } from '@/enums'; import { useComputingResource } from '@/hooks/useComputingResource'; import { experimentStatusInfo } from '@/pages/Experiment/status'; @@ -8,7 +9,6 @@ import { } from '@/pages/HyperParameter/components/CreateForm/utils'; import { HyperParameterData } from '@/pages/HyperParameter/types'; import { type NodeStatus } from '@/types'; -import { elapsedTime } from '@/utils/date'; import { formatCodeConfig, formatDataset, @@ -33,14 +33,12 @@ type HyperParameterBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; - finishTime?: Date; }; function HyperParameterBasic({ info, className, runStatus, - finishTime, isInstance = false, }: HyperParameterBasicProps) { const getResourceDescription = useComputingResource()[1]; @@ -157,7 +155,7 @@ function HyperParameterBasic({ }, { label: '执行时长', - value: elapsedTime(info.create_time, finishTime), + value: , ellipsis: true, }, { @@ -184,7 +182,7 @@ function HyperParameterBasic({ ellipsis: true, }, ]; - }, [runStatus, info, finishTime]); + }, [runStatus, info]); return (
From 1c301a778cdb08aacc016facc37920f7563121eb Mon Sep 17 00:00:00 2001 From: zhaowei Date: Fri, 9 May 2025 16:19:36 +0800 Subject: [PATCH 4/4] =?UTF-8?q?fix:=20=E7=BB=88=E6=AD=A2=E5=AE=9E=E9=AA=8C?= =?UTF-8?q?=E6=97=B6=EF=BC=8C=E8=AF=A6=E6=83=85=E6=98=BE=E7=A4=BA=E5=A4=B1?= =?UTF-8?q?=E8=B4=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/pages/ActiveLearn/Instance/index.tsx | 1 + .../components/ActiveLearnBasic/index.tsx | 63 ++++------------- react-ui/src/pages/AutoML/Instance/index.tsx | 1 + .../AutoML/components/AutoMLBasic/index.tsx | 62 ++++------------ .../components/ExperimentList/index.tsx | 3 + .../components/ExperimentRunBasic/index.tsx | 70 +++++++++++++++++++ .../components/ResourceItem/index.less | 2 - react-ui/src/pages/Experiment/index.jsx | 3 + .../pages/HyperParameter/Instance/index.tsx | 1 + .../components/HyperParameterBasic/index.tsx | 14 ++-- 10 files changed, 115 insertions(+), 105 deletions(-) create mode 100644 react-ui/src/pages/AutoML/components/ExperimentRunBasic/index.tsx diff --git a/react-ui/src/pages/ActiveLearn/Instance/index.tsx b/react-ui/src/pages/ActiveLearn/Instance/index.tsx index d16d5428..5655e60d 100644 --- a/react-ui/src/pages/ActiveLearn/Instance/index.tsx +++ b/react-ui/src/pages/ActiveLearn/Instance/index.tsx @@ -153,6 +153,7 @@ function ActiveLearnInstance() { className={styles['active-learn-instance__basic']} info={experimentInfo} runStatus={workflowStatus} + instanceStatus={instanceInfo?.status} isInstance /> ), diff --git a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx index 5c0d4e3e..3c75eb61 100644 --- a/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx +++ b/react-ui/src/pages/ActiveLearn/components/ActiveLearnBasic/index.tsx @@ -1,6 +1,5 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; -import RunDuration from '@/components/RunDuration'; -import { AutoMLTaskType, autoMLTaskTypeOptions } from '@/enums'; +import { AutoMLTaskType, autoMLTaskTypeOptions, ExperimentStatus } from '@/enums'; import { useComputingResource } from '@/hooks/useComputingResource'; import { classifierAlgorithms, @@ -10,7 +9,7 @@ import { regressorAlgorithms, } from '@/pages/ActiveLearn/components/CreateForm/utils'; import { ActiveLearnData } from '@/pages/ActiveLearn/types'; -import { experimentStatusInfo } from '@/pages/Experiment/status'; +import ExperimentRunBasic from '@/pages/AutoML/components/ExperimentRunBasic'; import { type NodeStatus } from '@/types'; import { formatBoolean, @@ -21,7 +20,6 @@ import { formatMirror, formatModel, } from '@/utils/format'; -import { Flex } from 'antd'; import classNames from 'classnames'; import { useMemo } from 'react'; import styles from './index.less'; @@ -31,9 +29,16 @@ type BasicInfoProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + instanceStatus?: ExperimentStatus; }; -function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfoProps) { +function BasicInfo({ + info, + className, + runStatus, + instanceStatus, + isInstance = false, +}: BasicInfoProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -205,53 +210,13 @@ function BasicInfo({ info, className, runStatus, isInstance = false }: BasicInfo ]; }, [info, getResourceDescription]); - const instanceDatas = useMemo(() => { - if (!info || !runStatus) { - return []; - } - - return [ - { - label: '启动时间', - value: formatDate(info.create_time), - }, - { - label: '执行时长', - value: , - }, - { - label: '状态', - value: ( - - -
- {experimentStatusInfo[runStatus?.phase]?.label} -
-
- ), - }, - ]; - }, [runStatus, info]); - return (
{isInstance && runStatus && ( - )} {!isInstance && ( diff --git a/react-ui/src/pages/AutoML/Instance/index.tsx b/react-ui/src/pages/AutoML/Instance/index.tsx index 5f1b5e34..e0fb5e4d 100644 --- a/react-ui/src/pages/AutoML/Instance/index.tsx +++ b/react-ui/src/pages/AutoML/Instance/index.tsx @@ -156,6 +156,7 @@ function AutoMLInstance() { className={styles['auto-ml-instance__basic']} info={autoMLInfo} runStatus={workflowStatus} + instanceStatus={instanceInfo?.status} isInstance /> ), diff --git a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx index c421c59e..08c95ed9 100644 --- a/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx +++ b/react-ui/src/pages/AutoML/components/AutoMLBasic/index.tsx @@ -1,20 +1,19 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; -import RunDuration from '@/components/RunDuration'; import { AutoMLTaskType, AutoMLType, + ExperimentStatus, autoMLEnsembleClassOptions, autoMLTaskTypeOptions, } from '@/enums'; import { useComputingResource } from '@/hooks/useComputingResource'; import { AutoMLData } from '@/pages/AutoML/types'; -import { experimentStatusInfo } from '@/pages/Experiment/status'; import { type NodeStatus } from '@/types'; import { parseJsonText } from '@/utils'; import { formatBoolean, formatDataset, formatDate, formatEnum } from '@/utils/format'; -import { Flex } from 'antd'; import classNames from 'classnames'; import { useMemo } from 'react'; +import ExperimentRunBasic from '../ExperimentRunBasic'; import styles from './index.less'; // 格式化优化方向 @@ -40,9 +39,16 @@ type AutoMLBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + instanceStatus?: ExperimentStatus; }; -function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLBasicProps) { +function AutoMLBasic({ + info, + className, + runStatus, + instanceStatus, + isInstance = false, +}: AutoMLBasicProps) { const getResourceDescription = useComputingResource()[1]; const basicDatas: BasicInfoData[] = useMemo(() => { if (!info) { @@ -284,53 +290,13 @@ function AutoMLBasic({ info, className, runStatus, isInstance = false }: AutoMLB ]; }, [info]); - const instanceDatas = useMemo(() => { - if (!info || !runStatus) { - return []; - } - - return [ - { - label: '启动时间', - value: formatDate(info.create_time), - }, - { - label: '执行时长', - value: , - }, - { - label: '状态', - value: ( - - -
- {experimentStatusInfo[runStatus?.phase]?.label} -
-
- ), - }, - ]; - }, [runStatus, info]); - return (
{isInstance && runStatus && ( - )} {!isInstance && ( diff --git a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx index 442f38f5..b71952b2 100644 --- a/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx +++ b/react-ui/src/pages/AutoML/components/ExperimentList/index.tsx @@ -8,6 +8,7 @@ import KFIcon from '@/components/KFIcon'; import PageTitle from '@/components/PageTitle'; import { ExperimentStatus, autoMLTypeOptions } from '@/enums'; import { useCacheState } from '@/hooks/useCacheState'; +import { useServerTime } from '@/hooks/useServerTime'; import { AutoMLData } from '@/pages/AutoML/types'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import themes from '@/styles/theme.less'; @@ -51,6 +52,7 @@ function ExperimentList({ type }: ExperimentListProps) { const [experimentInsList, setExperimentInsList] = useState([]); const [expandedRowKeys, setExpandedRowKeys] = useState([]); const [experimentInsTotal, setExperimentInsTotal] = useState(0); + const [now] = useServerTime(); const [pagination, setPagination] = useState( cacheState?.pagination ?? { current: 1, @@ -275,6 +277,7 @@ function ExperimentList({ type }: ExperimentListProps) { return { ...item, status: ExperimentStatus.Terminated, + finish_time: now().toISOString(), }; } return item; diff --git a/react-ui/src/pages/AutoML/components/ExperimentRunBasic/index.tsx b/react-ui/src/pages/AutoML/components/ExperimentRunBasic/index.tsx new file mode 100644 index 00000000..e088c7e8 --- /dev/null +++ b/react-ui/src/pages/AutoML/components/ExperimentRunBasic/index.tsx @@ -0,0 +1,70 @@ +import ConfigInfo from '@/components/ConfigInfo'; +import RunDuration from '@/components/RunDuration'; +import { ExperimentStatus } from '@/enums'; +import { experimentStatusInfo } from '@/pages/Experiment/status'; +import { type NodeStatus } from '@/types'; +import { formatDate } from '@/utils/format'; +import { Flex } from 'antd'; +import { useMemo } from 'react'; + +type ExperimentRunBasicProps = { + create_time?: string; + runStatus?: NodeStatus; + instanceStatus?: ExperimentStatus; +}; + +function ExperimentRunBasic({ create_time, runStatus, instanceStatus }: ExperimentRunBasicProps) { + const instanceDatas = useMemo(() => { + if (!runStatus) { + return []; + } + + const status = + instanceStatus === ExperimentStatus.Terminated ? instanceStatus : runStatus.phase; + const statusInfo = experimentStatusInfo[status]; + + return [ + { + label: '启动时间', + value: formatDate(create_time), + }, + { + label: '执行时长', + value: , + }, + { + label: '状态', + value: ( + + +
+ {statusInfo?.label} +
+
+ ), + }, + ]; + }, [runStatus, create_time, instanceStatus]); + + return ( + + ); +} + +export default ExperimentRunBasic; diff --git a/react-ui/src/pages/Dataset/components/ResourceItem/index.less b/react-ui/src/pages/Dataset/components/ResourceItem/index.less index 01be647c..58b5be62 100644 --- a/react-ui/src/pages/Dataset/components/ResourceItem/index.less +++ b/react-ui/src/pages/Dataset/components/ResourceItem/index.less @@ -55,9 +55,7 @@ } &__time { display: flex; - flex: 0 1 content; align-items: center; - width: 100%; color: #808080; font-size: 13px; } diff --git a/react-ui/src/pages/Experiment/index.jsx b/react-ui/src/pages/Experiment/index.jsx index e94c625c..1ecc7df1 100644 --- a/react-ui/src/pages/Experiment/index.jsx +++ b/react-ui/src/pages/Experiment/index.jsx @@ -28,6 +28,7 @@ import AddExperimentModal from './components/AddExperimentModal'; import ExperimentInstanceList from './components/ExperimentInstanceList'; import styles from './index.less'; import { experimentStatusInfo } from './status'; +import { useServerTime } from '@/hooks/useServerTime'; // 定时器 const timerIds = new Map(); @@ -47,6 +48,7 @@ function Experiment() { const [cacheState, setCacheState] = useCacheState(); const [searchText, setSearchText] = useState(cacheState?.searchText); const [inputText, setInputText] = useState(cacheState?.searchText); + const [now] = useServerTime(); const [pagination, setPagination] = useState( cacheState?.pagination ?? { current: 1, @@ -384,6 +386,7 @@ function Experiment() { return { ...item, status: ExperimentStatus.Terminated, + finish_time: now().toISOString(), }; } return item; diff --git a/react-ui/src/pages/HyperParameter/Instance/index.tsx b/react-ui/src/pages/HyperParameter/Instance/index.tsx index a0ebae5b..79905c36 100644 --- a/react-ui/src/pages/HyperParameter/Instance/index.tsx +++ b/react-ui/src/pages/HyperParameter/Instance/index.tsx @@ -168,6 +168,7 @@ function HyperParameterInstance() { className={styles['hyper-parameter-instance__basic']} info={experimentInfo} runStatus={workflowStatus} + instanceStatus={instanceInfo?.status} isInstance /> ), diff --git a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx index 3e526848..f4b9852b 100644 --- a/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx +++ b/react-ui/src/pages/HyperParameter/components/HyperParameterBasic/index.tsx @@ -1,7 +1,8 @@ import ConfigInfo, { type BasicInfoData } from '@/components/ConfigInfo'; import RunDuration from '@/components/RunDuration'; -import { hyperParameterOptimizedMode } from '@/enums'; +import { ExperimentStatus, hyperParameterOptimizedMode } from '@/enums'; import { useComputingResource } from '@/hooks/useComputingResource'; +import ExperimentRunBasic from '@/pages/AutoML/components/ExperimentRunBasic'; import { experimentStatusInfo } from '@/pages/Experiment/status'; import { schedulerAlgorithms, @@ -33,12 +34,14 @@ type HyperParameterBasicProps = { className?: string; isInstance?: boolean; runStatus?: NodeStatus; + instanceStatus?: ExperimentStatus; }; function HyperParameterBasic({ info, className, runStatus, + instanceStatus, isInstance = false, }: HyperParameterBasicProps) { const getResourceDescription = useComputingResource()[1]; @@ -187,11 +190,10 @@ function HyperParameterBasic({ return (
{isInstance && runStatus && ( - )} {!isInstance && (