import { intl } from '@/utils/intl'; 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, deployAndStartADeployment, createDeploymentConfig, recover, } from '@/services/ob-deploy-web/Deployments'; import { handleQuit, getErrorInfo } from '@/utils'; import NP from 'number-precision'; import { getLocale } from 'umi'; import EnStyles from './indexEn.less'; import ZhStyles from './indexZh.less'; const locale = getLocale(); const styles = locale === 'zh-CN' ? ZhStyles : EnStyles; 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, setErrorVisible, setErrorsList, errorsList, } = 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 [currentPage, setCurrentPage] = useState(true); const [firstErrorTimestamp, setFirstErrorTimestamp] = useState(); const { run: fetchPreCheckStatus } = useRequest(preCheckStatus, { 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') { let errorInfo: API.ErrorInfo = { title: intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.RequestError', defaultMessage: '请求错误', }), desc: data?.message, }; setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); 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 = getErrorInfo({ response, data, type }); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); }; if (response?.status === 504 || (!response && type === 'TypeError')) { const nowTime = Date.now(); 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: (e: any) => { setCheckStatus(false); if (loading) { setLoading(false); } const errorInfo = getErrorInfo(e); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); }, }, ); const { run: handleInstallConfirm } = useRequest(deployAndStartADeployment, { onError: (e: any) => { const errorInfo = getErrorInfo(e); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); }, }); 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: (e: any) => { setCheckStatus(false); if (loading) { setLoading(false); } const errorInfo = getErrorInfo(e); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); }, }, ); 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( intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.AutomaticRepairSucceeded', defaultMessage: '自动修复成功', }), ); try { const { success: nameSuccess, data: nameData } = await getInfoByName({ name, }); if (nameSuccess) { const { config } = nameData; setConfigData(config || {}); handleRetryCheck(config); } else { message.error( intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.FailedToObtainConfigurationInformation', defaultMessage: '获取配置信息失败', }), ); } } catch (e: any) { const errorInfo = getErrorInfo(e); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); } } }, onError: (e: any) => { const errorInfo = getErrorInfo(e); setErrorVisible(true); setErrorsList([...errorsList, errorInfo]); }, }); const handleStartCheck = () => { fetchPreCheckStatus({ name }); }; const prevStep = () => { setCheckOK(false); setCurrentStep(3); setCurrentPage(false); setErrorVisible(false); setErrorsList([]); window.scrollTo(0, 0); }; const handleInstall = async () => { const { success } = await handleInstallConfirm({ name }); if (success) { setCurrentStep(5); setCurrentPage(false); setErrorVisible(false); setErrorsList([]); } }; 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 = (
); const checkItemLength = `${statusData?.finished || 0}/${ statusData?.total || 0 }`; const failedItemLength = failedList?.length; return ( handleRetryCheck()} data-aspm-click="c307513.d317293" data-aspm-desc={intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.PreCheckResultReCheck', defaultMessage: '预检查结果-重新检查', })} data-aspm-param={``} data-aspm-expo > {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.ReCheck', defaultMessage: '重新检查', })} } 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} > {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.OnlyManualFixes', defaultMessage: '只看手动修复项', })} ) : 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} {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.Reason', defaultMessage: '原因:', })} OBD-{item.code} {' '} {reason} {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.Suggestions', defaultMessage: '建议:', })} {item.recoverable ? ( {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.AutomaticRepair', defaultMessage: '自动修复', })} ) : ( {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.ManualRepair', defaultMessage: '手动修复', })} )}{' '} {item.advisement?.description}
{intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.LearnMore', defaultMessage: '了解更多方案', })}
); })} {!checkFinished ? (
{shape}
) : null}
) : checkFinished ? ( {intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.GreatNoFailedItems', defaultMessage: '太棒了!无失败项', })} } /> ) : (
{shape}
{intl.formatMessage({ id: 'OBD.pages.components.PreCheckStatus.NoFailedItemsFoundYet', defaultMessage: '暂未发现失败项', })}
)} ); }