import { useState, useEffect, ReactNode } from 'react';
import { useLaunch } from '@tarojs/taro';
import { IntlProvider } from 'react-intl';
import { ConfigProvider } from 'antd';
import { Provider } from 'react-redux';
import store, { useAppDispatch, useAppSelector } from './states/store';
import { initializeProductState } from './states/productSlice';
import { loadI18nMessages } from './states/i18nSlice';
import { checkServerConnection } from './features/serverConfig';
import { initializeAnnotationManager, cleanupAnnotationManager } from './features/imageAnnotation';
import { platform } from './utils/platform';
import './app.css';
import ProductSelector from './components/ProductSelector';
import ThemeSwitcher from './components/ThemeSwitcher';
import QuotaAlertModal from './pages/security/QuotaAlertModal';
import AcquisitionTracer from './pages/exam/components/acquisitionTracer';
import FeatureNotAvailableFeedback from './components/FeatureNotAvailableFeedback';
import { setFeatureNotAvailableOpen } from './states/featureNotAvailableSlice';
import { setBusinessFlow } from './states/BusinessFlowSlice';
import { logger } from './log/logger';
import { theme } from 'antd';
import ServerConfigModal from './features/serverConfig/components/ServerConfigModal';
console.log = logger.log;
console.warn = logger.warn;
console.error = logger.error;
console.debug = logger.debug;
console.log(`process.env.USE_MSW: ${process.env.USE_MSW}`);
console.log(`process.env.NODE_ENV: ${process.env.NODE_ENV}`);
console.debug('debug level')
if (process.env.NODE_ENV === 'development' && process.env.USE_MSW === 'true') {
import('../mocks/server')
.then(({ server }): void => {
server.start({
onUnhandledRequest: 'error', // 未处理的请求触发网络错误
});
console.log(`启动了MSW`);
})
.catch((err): void => {
console.warn('Mock server module not found:', err);
});
}
function AppContent({ children }: { children: ReactNode }): JSX.Element {
const dispatch = useAppDispatch();
const { messages, loading, error, currentLocale } = useAppSelector(
(state) => state.i18n
);
const isFeatureNotAvailableOpen = useAppSelector(
(state) => state.featureNotAvailable.isOpen
);
const { currentTheme, themeType } = useAppSelector((state) => state.theme);
const [isI18nReady, setIsI18nReady] = useState(false);
const [showConfigModal, setShowConfigModal] = useState(false);
const [connectionChecked, setConnectionChecked] = useState(false);
const themeWithAlgorithm = {
...currentTheme,
algorithm:
themeType === 'light' ? theme.defaultAlgorithm : theme.darkAlgorithm,
};
useLaunch((): void => {
console.log('App launched.');
});
useEffect(() => {
// 浏览器环境不需要服务器连接检查,直接初始化应用
if (platform.isBrowser) {
console.log('浏览器环境,跳过服务器连接检查,直接初始化应用');
initializeApp();
return;
}
// Electron/Cordova 环境:检查服务器连接
dispatch(checkServerConnection())
.unwrap()
.then((result) => {
setConnectionChecked(true);
if (result.needsConfig) {
// 需要配置,显示对话框
console.log('检测到需要服务器配置,显示配置对话框');
setShowConfigModal(true);
} else {
// 连接正常,继续正常初始化
console.log('服务器连接正常,开始应用初始化');
return initializeApp();
}
})
.catch((error) => {
console.error('连接检查失败:', error);
setConnectionChecked(true);
setShowConfigModal(true);
});
// 应用退出时清理注释管理器
return () => {
cleanupAnnotationManager().catch(console.error);
};
}, [dispatch]);
// 应用正常初始化函数
const initializeApp = async () => {
try {
const productState = await dispatch(initializeProductState()).unwrap();
console.log(`初始化,拉取到产品信息:${JSON.stringify(productState)}`);
const languageCode = productState.language;
await dispatch(loadI18nMessages(languageCode)).unwrap();
// ✅ 初始化注释管理器(在产品状态和国际化之后)
await initializeAnnotationManager();
setIsI18nReady(true);
} catch (error) {
console.error('应用初始化失败:', error);
// 显示配置对话框,让用户重新配置
setShowConfigModal(true);
}
};
// 配置保存后的处理
const handleConfigSaved = () => {
setShowConfigModal(false);
// 重新检查连接并初始化应用
dispatch(checkServerConnection())
.unwrap()
.then((result) => {
if (!result.needsConfig) {
initializeApp();
}
})
.catch((error) => {
console.error('重新检查连接失败:', error);
});
};
console.log('当前语言:', currentLocale);
console.log('messages', messages);
// children 是将要会渲染的页面
// IntlProvider 始终存在,使用默认值避免 useIntl 报错
return (
en,提供默认值
messages={(messages as Record) || {}} // 提供空对象作为默认值
>
{/* 加载状态覆盖层 */}
{(loading || (!isI18nReady && !connectionChecked)) && (
)}
{/* 服务器配置对话框 */}
setShowConfigModal(false)}
/>
{/* 错误状态覆盖层 */}
{error && (
多语言资源加载失败: {error}
)}
{/* children 始终被渲染,满足 Taro 框架要求 */}
dispatch(setFeatureNotAvailableOpen(false))}
onContinue={() => {
dispatch(setFeatureNotAvailableOpen(false));
dispatch(setBusinessFlow('continueAfterFeatureNotAvailable'));
}}
/>
{children}
{process.env.NODE_ENV === 'development' && }
);
}
function App({ children }: { children: ReactNode }): JSX.Element {
// 只在 Cypress 测试环境下暴露 store 到 window 对象
if (
typeof window !== 'undefined' &&
(window as unknown as { Cypress: unknown }).Cypress
) {
(window as unknown as { store: typeof store }).store = store;
}
return (
{children}
);
}
export default App;