import { useEffect, useState } from 'react'; import { useModel } from 'umi'; import { Space, Button, Progress, Timeline, Checkbox, Typography, Tooltip, Tag, Spin, message, Empty, } from 'antd'; import { ProCard } from '@ant-design/pro-components'; import { CloseOutlined, QuestionCircleFilled, ReadFilled, CheckCircleFilled, CloseCircleFilled, } from '@ant-design/icons'; import useRequest from '@/utils/useRequest'; import { preCheck, preCheckStatus, installDeployment, createDeploymentConfig, recover, } from '@/services/ob-deploy-web/Deployments'; import { handleQuit, handleResponseError } from '@/utils'; import NP from 'number-precision'; import styles from './index.less'; const { Text } = Typography; const statusColorConfig = { PASSED: 'green', PENDING: 'gray', FAILED: 'red', }; let timerScroll: NodeJS.Timer; let timerFailed: NodeJS.Timer; const initDuration = 3; let durationScroll = initDuration; let durationFailed = initDuration; const errCodeUrl = 'https://www.oceanbase.com/product/ob-deployer/error-codes'; export default function PreCheckStatus() { const { setCurrentStep, configData, setCheckOK, handleQuitProgress, getInfoByName, setConfigData, } = useModel('global'); const oceanbase = configData?.components?.oceanbase; const name = configData?.components?.oceanbase?.appname; const [statusData, setStatusData] = useState({}); const [failedList, setFailedList] = useState([]); const [showFailedList, setShowFailedList] = useState([]); const [hasAuto, setHasAuto] = useState(false); const [hasManual, setHasManual] = useState(false); const [onlyManual, setOnlyManual] = useState(false); const [checkFinished, setCheckFinished] = useState(false); const [isScroll, setIsScroll] = useState(false); const [isScrollFailed, setIsScrollFailed] = useState(false); const [loading, setLoading] = useState(false); const [checkStatus, setCheckStatus] = useState(true); const [lastError, setLastError] = useState(''); const [currentPage, setCurrentPage] = useState(true); const [firstErrorTimestamp, setFirstErrorTimestamp] = useState(); const { run: fetchPreCheckStatus } = useRequest(preCheckStatus, { skipStatusError: true, skipTypeError: true, onSuccess: ({ success, data }: API.OBResponsePreCheckResult_) => { if (success) { let timer: NodeJS.Timer; setStatusData(data || {}); if (data?.status === 'RUNNING') { timer = setTimeout(() => { fetchPreCheckStatus({ name }); }, 1000); } if (data?.status === 'FAILED') { handleResponseError(data?.message); setCheckStatus(false); } else { if (data?.all_passed) { setFailedList([]); setShowFailedList([]); } else { const newFailedList = data?.info?.filter((item) => item.result === 'FAILED') || []; newFailedList.forEach((item) => { if (item.recoverable) { setHasAuto(true); } else { setHasManual(true); } }); setFailedList(newFailedList); setShowFailedList(newFailedList); } const isFinished = !!data?.total && data?.finished === data?.total; setCheckFinished(isFinished); if (isFinished) { clearTimeout(timer); } if (!isScroll && !isFinished) { setTimeout(() => { const timelineContainer = document.getElementById('timeline-container'); const runningItemDom = document.getElementById( 'running-timeline-item', ); timelineContainer.scrollTop = NP.minus( NP.strip(runningItemDom?.offsetTop), 150, ); }, 10); } if (!isScrollFailed && !isFinished && failedList) { setTimeout(() => { const failedContainer = document.getElementById('failed-container'); if (failedContainer) { failedContainer.scrollTop = NP.strip( failedContainer?.scrollHeight, ); } }, 10); } setCheckStatus(true); } if (loading) { setLoading(false); } } }, onError: ({ response, data, type }: any) => { const handleError = () => { const errorInfo = data?.msg || data?.detail || response?.statusText || '您的网络发生异常,无法连接服务器'; const errorInfoStr = errorInfo ? JSON.stringify(errorInfo) : ''; if (errorInfoStr && lastError !== errorInfoStr) { setLastError(errorInfoStr); handleResponseError(errorInfo); } }; if (response?.status === 504 || (!response && type === 'TypeError')) { const nowTime = new Date().getTime(); if (!firstErrorTimestamp) { setFirstErrorTimestamp(nowTime); } if (NP.divide(nowTime - firstErrorTimestamp) > 60000) { handleError(); setCheckStatus(false); if (loading) { setLoading(false); } } else { if (currentPage) { setTimeout(() => { fetchPreCheckStatus({ name }); }, 1000); } } } else { handleError(); } }, }); const { run: handlePreCheck, loading: preCheckLoading } = useRequest( preCheck, { onSuccess: ({ success }: API.OBResponse) => { if (success) { handleStartCheck(); } }, onError: () => { setCheckStatus(false); if (loading) { setLoading(false); } }, }, ); const { run: handleInstallConfirm } = useRequest(installDeployment); const handelCheck = async () => { setLoading(true); try { await handlePreCheck({ name }); } catch { setLoading(false); } }; const { run: handleCreateConfig, loading: createLoading } = useRequest( createDeploymentConfig, { onSuccess: ({ success }: API.OBResponse) => { if (success) { handelCheck(); } setLoading(false); }, onError: () => { setCheckStatus(false); if (loading) { setLoading(false); } }, }, ); const handleRetryCheck = (newConfigData?: any) => { setStatusData({}); setFailedList([]); setShowFailedList([]); setCheckFinished(false); let params = { ...configData }; if (newConfigData) { params = { ...newConfigData }; } setLoading(true); handleCreateConfig({ name: oceanbase?.appname }, { ...params }); }; const { run: handleRecover, loading: recoverLoading } = useRequest(recover, { onSuccess: async ({ success, }: API.OBResponseDataListRecoverChangeParameter_) => { if (success) { message.success('自动修复成功'); try { const { success: nameSuccess, data: nameData } = await getInfoByName({ name, }); if (nameSuccess) { const { config } = nameData; setConfigData(config || {}); handleRetryCheck(config); } else { message.error('获取配置信息失败'); } } catch (e: any) { const { response, data } = e; handleResponseError( data?.msg || data?.detail || response?.statusText, ); } } }, }); const handleStartCheck = () => { fetchPreCheckStatus({ name }); }; const prevStep = () => { setCheckOK(false); setCurrentStep(3); setCurrentPage(false); }; const handleInstall = async () => { const { success } = await handleInstallConfirm({ name }); if (success) { setCurrentStep(5); setCurrentPage(false); } }; const handleScrollTimeline = () => { if (!checkFinished) { setIsScroll(true); clearInterval(timerScroll); durationScroll = initDuration; timerScroll = setInterval(() => { if (durationScroll === 0) { clearInterval(timerScroll); setIsScroll(false); durationScroll = initDuration; } else { durationScroll -= 1; } }, 1000); } }; const handleScrollFailed = () => { if (!checkFinished) { setIsScrollFailed(true); clearInterval(timerFailed); durationFailed = initDuration; timerFailed = setInterval(() => { if (durationFailed === 0) { clearInterval(timerFailed); setIsScrollFailed(false); durationFailed = initDuration; } else { durationFailed -= 1; } }, 1000); } }; const handleAutoRepair = () => { setHasAuto(false); handleRecover({ name }); }; useEffect(() => { if (onlyManual) { const newShowFailedList = failedList.filter((item) => !item.recoverable); setShowFailedList(newShowFailedList); } else { setShowFailedList(failedList); } }, [onlyManual]); useEffect(() => { handelCheck(); const timelineContainer = document.getElementById('timeline-container'); timelineContainer.onmousewheel = handleScrollTimeline; // ie , chrome timelineContainer?.addEventListener('DOMMouseScroll', handleScrollTimeline); // firefox return () => { timelineContainer.onmousewheel = () => {}; timelineContainer?.removeEventListener( 'DOMMouseScroll', handleScrollTimeline, ); }; }, []); useEffect(() => { const addEventFailedContainer = () => { const failedContainer = document.getElementById('failed-container'); if (failedList?.length && failedContainer) { if (!failedContainer.onmousewheel) { failedContainer.onmousewheel = handleScrollFailed; // ie , chrome failedContainer?.addEventListener( 'DOMMouseScroll', handleScrollFailed, ); // firefox } } else { setTimeout(() => { addEventFailedContainer(); }, 3000); } }; addEventFailedContainer(); return () => { const failedContainer = document.getElementById('failed-container'); if (failedContainer) { failedContainer.onmousewheel = () => {}; failedContainer?.removeEventListener( 'DOMMouseScroll', handleScrollFailed, ); } }; }, [failedList]); let progressStatus = 'active'; if (statusData?.status === 'FAILED') { progressStatus = 'exception'; } else if (checkFinished) { if (statusData?.all_passed) { progressStatus = 'success'; } else { progressStatus = 'exception'; } } const shape = (
); return ( handleRetryCheck()} data-aspm-click="c307513.d317293" data-aspm-desc="预检查结果-重新检查" data-aspm-param={``} data-aspm-expo > 重新检查 } headStyle={{ paddingLeft: '16px', paddingRight: '16px' }} > {loading ? null : ( <> {statusData?.info?.map( (item: API.PreCheckInfo, index: number) => ( ) : ( ) ) : null } > {item?.name} {item?.server} ), )} )} {hasManual ? ( setOnlyManual(e.target.checked)} disabled={!checkFinished || statusData?.all_passed} > 只看手动修复项 ) : null} } > {showFailedList?.length ? (
{showFailedList?.map((item, index) => { let reason = ''; if (item?.description) { const index = item?.description.indexOf(':'); reason = item?.description.substring( index, item?.description.length, ); } return ( {item.name} 原因: OBD-{item.code} {' '} {reason} 建议: {item.recoverable ? ( 自动修复 ) : ( 手动修复 )}{' '} {item.advisement?.description}
了解更多方案
); })} {!checkFinished ? (
{shape}
) : null}
) : checkFinished ? ( 太棒了!无失败项 } /> ) : (
{shape}
暂未发现失败项
)} ); }