初始化管道系统(Initialization Pipeline)是一个管理应用启动流程的状态机系统,将复杂的异步初始化逻辑分解为清晰的、可管理的节点,每个节点负责特定的初始化任务,支持错误处理、用户交互和状态追踪。
| 概念 | 专业术语 | 业内对应方案 |
|---|---|---|
| 初始化管道 | Initialization Pipeline | React Query的查询管道 |
| 启动序列 | Bootstrap Sequence | Vuex的初始化模块 |
| 状态机流转 | State Machine Transition | XState状态机 |
| 用户参与点 | User Interaction Point | 表单验证流程 |
src/features/initializationPipeline/types/index.ts - 管道相关类型定义src/features/initializationPipeline/constants/nodes.ts - 节点常量定义src/features/initializationPipeline/constants/transitions.ts - 状态流转规则src/features/initializationPipeline/state/initializationSlice.ts - Redux slicesrc/features/initializationPipeline/state/pipelineManager.ts - 管道管理器src/features/initializationPipeline/components/PipelineProgress.tsx - 进度显示组件src/features/initializationPipeline/components/NodeStatusIndicator.tsx - 节点状态指示器src/features/initializationPipeline/components/ErrorHandler.tsx - 错误处理组件src/features/initializationPipeline/services/NodeExecutor.ts - 节点执行器src/features/initializationPipeline/services/PipelineService.ts - 管道服务src/features/initializationPipeline/utils/nodeHelpers.ts - 节点辅助函数src/features/initializationPipeline/utils/pipelineLogger.ts - 管道日志工具src/app.tsx - 集成管道系统,替换现有的初始化逻辑src/states/store.ts - 注册新的 initialization slicesrc/features/initializationPipeline/index.ts - 统一导出sequenceDiagram
participant User as 用户
participant App as App.tsx
participant Pipeline as PipelineManager
participant NodeExec as NodeExecutor
participant Redux as Redux Store
participant UI as UI Components
participant Services as 外部服务
App->>Pipeline: startPipeline()
Pipeline->>Redux: dispatch(INIT_PIPELINE)
loop 每个节点
Pipeline->>NodeExec: executeNode(nodeId)
NodeExec->>Redux: updateNodeStatus(RUNNING)
NodeExec->>Services: 执行节点任务
alt 任务成功
Services-->>NodeExec: 返回成功结果
NodeExec->>Redux: updateNodeStatus(SUCCESS)
NodeExec->>Pipeline: onNodeSuccess()
else 任务失败
Services-->>NodeExec: 返回错误
NodeExec->>Redux: updateNodeStatus(ERROR)
NodeExec->>Pipeline: onNodeError()
alt 需要用户输入
Pipeline->>UI: 显示配置界面
UI->>User: 请求用户输入
User->>UI: 提供配置信息
UI->>Pipeline: 用户输入完成
Pipeline->>NodeExec: retryNode()
else 可重试
Pipeline->>UI: 显示重试按钮
User->>UI: 点击重试
UI->>Pipeline: retryNode()
end
end
Pipeline->>Pipeline: checkTransition()
Pipeline->>Redux: updateCurrentNode()
end
Pipeline->>Redux: dispatch(PIPELINE_COMPLETED)
Pipeline->>App: onPipelineComplete()
App->>UI: 显示主应用界面
flowchart TD
subgraph "用户交互层"
UI[UI 组件] --> Actions[Redux Actions]
end
subgraph "状态管理层"
Actions --> Store[Redux Store]
Store --> State[Pipeline State]
State --> Selectors[Selectors]
Selectors --> UI
end
subgraph "业务逻辑层"
Actions --> PipelineSvc[PipelineService]
PipelineSvc --> NodeExec[NodeExecutor]
NodeExec --> PlatformSvc[Platform Service]
NodeExec --> ConfigSvc[Config Service]
NodeExec --> ApiSvc[API Service]
NodeExec --> I18nSvc[I18n Service]
end
subgraph "数据持久层"
ConfigSvc --> Storage[Local Storage]
Storage --> ConfigSvc
end
subgraph "外部服务层"
ApiSvc --> Backend[后端 API]
Backend --> ApiSvc
end
PipelineSvc --> Store
NodeExec --> Store
// src/features/initializationPipeline/types/index.ts
/**
* 管道节点状态
*/
export enum PipelineNodeStatus {
PENDING = 'pending',
RUNNING = 'running',
SUCCESS = 'success',
ERROR = 'error',
WAITING_USER_INPUT = 'waiting_user_input',
SKIPPED = 'skipped'
}
/**
* 管道节点定义
*/
export interface PipelineNode {
id: string;
name: string;
description: string;
status: PipelineNodeStatus;
requiresUserInteraction: boolean;
canRetry: boolean;
errorMessage?: string;
data?: any;
startTime?: number;
endTime?: number;
}
/**
* 管道状态
*/
export interface PipelineState {
currentNodeId: string | null;
nodes: Record<string, PipelineNode>;
isCompleted: boolean;
isRunning: boolean;
globalError?: string;
startTime: number;
}
/**
* 节点执行结果
*/
export interface NodeExecutionResult {
success: boolean;
data?: any;
error?: Error;
requiresUserInput?: boolean;
}
/**
* 节点执行器接口
*/
export interface INodeExecutor {
execute(nodeId: string): Promise<NodeExecutionResult>;
retry(nodeId: string): Promise<NodeExecutionResult>;
cancel(nodeId: string): Promise<void>;
}
// src/features/initializationPipeline/constants/nodes.ts
export enum PipelineNodes {
PLATFORM_DETECTION = 'platform_detection',
SERVER_CONNECTION_CHECK = 'server_connection_check',
PRODUCT_INITIALIZATION = 'product_initialization',
I18N_LOADING = 'i18n_loading',
APP_READY = 'app_ready'
}
export const NODE_DEFINITIONS: Record<PipelineNodes, Omit<PipelineNode, 'status' | 'data'>> = {
[PipelineNodes.PLATFORM_DETECTION]: {
id: PipelineNodes.PLATFORM_DETECTION,
name: '平台检测',
description: '检测当前运行的平台环境',
requiresUserInteraction: false,
canRetry: false
},
[PipelineNodes.SERVER_CONNECTION_CHECK]: {
id: PipelineNodes.SERVER_CONNECTION_CHECK,
name: '服务器连接检查',
description: '检查服务器配置和连接状态',
requiresUserInteraction: true, // 可能需要用户配置
canRetry: true
},
[PipelineNodes.PRODUCT_INITIALIZATION]: {
id: PipelineNodes.PRODUCT_INITIALIZATION,
name: '产品初始化',
description: '获取产品信息和基础配置',
requiresUserInteraction: false,
canRetry: true
},
[PipelineNodes.I18N_LOADING]: {
id: PipelineNodes.I18N_LOADING,
name: '多语言加载',
description: '加载对应语言的多语言资源',
requiresUserInteraction: false,
canRetry: true
},
[PipelineNodes.APP_READY]: {
id: PipelineNodes.APP_READY,
name: '应用就绪',
description: '所有初始化完成,应用可以正常使用',
requiresUserInteraction: false,
canRetry: false
}
};
起点:应用启动(非用户操作触发)
触发条件:
自动执行:应用启动后自动开始初始化管道
flowchart TD
Start([应用启动]) --> Init[初始化管道管理器]
Init --> PlatformCheck[执行 PLATFORM_DETECTION]
PlatformCheck --> PlatformSuccess{检测成功?}
PlatformCheck --> PlatformError{检测失败?}
PlatformError -->|是| ShowError[显示错误并退出]
PlatformSuccess -->|是| ServerCheck[执行 SERVER_CONNECTION_CHECK]
ServerCheck --> ServerSuccess{连接正常?}
ServerCheck --> ServerError{连接失败?}
ServerError -->|是| ShowConfig[显示配置对话框]
ShowConfig --> UserInput[等待用户输入]
UserInput --> ValidateConfig[验证配置]
ValidateConfig --> ConfigValid{配置有效?}
ConfigValid -->|否| ShowConfig
ConfigValid -->|是| SaveConfig[保存配置]
SaveConfig --> ServerCheck
ServerSuccess -->|是| ProductInit[执行 PRODUCT_INITIALIZATION]
ProductInit --> ProductSuccess{初始化成功?}
ProductInit --> ProductError{初始化失败?}
ProductError -->|是| ShowError2[显示错误]
ShowError2 --> CanRetry{可以重试?}
CanRetry -->|是| ProductInit
CanRetry -->|否| ShowConfig
ProductSuccess -->|是| I18nLoad[执行 I18N_LOADING]
I18nLoad --> I18nSuccess{加载成功?}
I18nLoad --> I18nError{加载失败?}
I18nError -->|是| UseDefaultLang[使用默认语言]
UseDefaultLang --> AppReady[执行 APP_READY]
I18nSuccess -->|是| AppReady
AppReady --> Complete[管道完成]
Complete --> ShowMainUI[显示主应用界面]
ShowError --> End([应用退出])
ShowMainUI --> End2([应用正常运行])
首次启动(无配置)
已有配置(连接正常)
已有配置(连接失败)
网络错误
服务器错误
语言包加载失败
# 测试首次启动
npm run build:electron
npm run start:electron
# 验证:显示配置对话框
# 测试已有配置
# 修改本地配置文件
# 重启应用
# 验证:直接进入应用
# 测试动态配置
npm run dev:h5
# 验证:自动使用当前 host
# 测试 Cordova 打包
npm run build:android
# 验证:配置持久化正常
准备环境:
执行测试:
验证结果:
http://192.168.1.100:8080)准备环境:
执行测试:
验证结果:
准备环境:
执行测试:
sequenceDiagram
participant App as 应用
participant Pipeline as 管道管理器
participant Node as 节点执行器
participant Store as Redux Store
participant UI as 用户界面
App->>Pipeline: startPipeline()
Pipeline->>Store: 初始化管道状态
Store-->>Pipeline: 状态初始化完成
Pipeline->>Node: executeNode(PLATFORM_DETECTION)
Node->>Store: 更新节点状态为 RUNNING
Node->>Node: 执行平台检测逻辑
Node->>Store: 更新节点状态为 SUCCESS
Pipeline->>Node: executeNode(SERVER_CONNECTION_CHECK)
Node->>Store: 更新节点状态为 RUNNING
Node->>Node: 检查服务器连接
alt 连接失败
Node->>Store: 更新节点状态为 WAITING_USER_INPUT
Pipeline->>UI: 显示配置对话框
UI->>UI: 等待用户输入
UI->>Pipeline: 用户完成配置
Pipeline->>Node: retryNode()
Node->>Node: 重新检查连接
end
Node->>Store: 更新节点状态为 SUCCESS
Pipeline->>Node: executeNode(PRODUCT_INITIALIZATION)
Node->>Store: 更新节点状态为 RUNNING
Node->>Node: 获取产品信息
Node->>Store: 更新节点状态为 SUCCESS
Pipeline->>Node: executeNode(I18N_LOADING)
Node->>Store: 更新节点状态为 RUNNING
Node->>Node: 加载多语言资源
Node->>Store: 更新节点状态为 SUCCESS
Pipeline->>Node: executeNode(APP_READY)
Node->>Store: 更新节点状态为 SUCCESS
Pipeline->>Store: 更新管道状态为 COMPLETED
Pipeline->>App: onPipelineComplete()
App->>UI: 显示主应用界面
classDiagram
class PipelineManager {
+startPipeline(): Promise<void>
+executeNode(nodeId: string): Promise<void>
+retryNode(nodeId: string): Promise<void>
+onNodeComplete(nodeId: string, result): void
+checkTransition(): string | null
-currentNodeId: string
-nodes: Record<string, PipelineNode>
}
class NodeExecutor {
+execute(nodeId: string): Promise<NodeExecutionResult>
+retry(nodeId: string): Promise<NodeExecutionResult>
+cancel(nodeId: string): Promise<void>
+validateResult(result): boolean
}
class PipelineService {
+initializePipeline(): PipelineState
+updateNodeStatus(nodeId, status): void
+getNodeStatus(nodeId): PipelineNodeStatus
+isPipelineCompleted(): boolean
+getCurrentNode(): PipelineNode | null
}
class InitializationSlice {
+startPipeline(): AsyncThunk
+executeNode(nodeId): AsyncThunk
+retryNode(nodeId): AsyncThunk
+updateNodeStatus(nodeId, status): Action
+setCurrentNode(nodeId): Action
+completePipeline(): Action
}
class PipelineProgress {
+render(): JSX.Element
+getNodeIcon(status): string
+getNodeColor(status): string
+onRetryClick(nodeId): void
}
class NodeStatusIndicator {
+render(): JSX.Element
+getStatusText(status): string
+getStatusIcon(status): IconComponent
+showRetryButton(): boolean
}
class ErrorHandler {
+render(): JSX.Element
+getErrorMessage(error): string
+getRecoveryAction(error): Action
+onRetryClick(): void
+onConfigClick(): void
}
PipelineManager --> NodeExecutor
PipelineManager --> PipelineService
NodeExecutor --> PipelineService
InitializationSlice --> PipelineService
PipelineProgress --> InitializationSlice
NodeStatusIndicator --> InitializationSlice
ErrorHandler --> InitializationSlice
flowchart TD
subgraph "开始状态"
START([开始]) --> INIT[初始化管道管理器]
end
subgraph "节点执行循环"
INIT --> CHECK_CURRENT{获取当前节点}
CHECK_CURRENT -->|有节点| EXECUTE_NODE[执行节点]
CHECK_CURRENT -->|无节点| COMPLETED[管道完成]
EXECUTE_NODE --> UPDATE_STATUS[更新节点状态为 RUNNING]
UPDATE_STATUS --> RUN_LOGIC[执行节点逻辑]
RUN_LOGIC --> CHECK_RESULT{检查执行结果}
CHECK_RESULT -->|成功| MARK_SUCCESS[标记节点成功]
CHECK_RESULT -->|失败| MARK_ERROR[标记节点失败]
CHECK_RESULT -->|需要用户输入| MARK_WAITING[标记等待用户输入]
MARK_SUCCESS --> TRANSITION[检查状态流转]
MARK_ERROR --> HANDLE_ERROR[错误处理]
MARK_WAITING --> WAIT_USER[等待用户输入]
HANDLE_ERROR --> CAN_RETRY{可以重试?}
CAN_RETRY -->|是| SHOW_RETRY[显示重试选项]
CAN_RETRY -->|否| SHOW_ERROR[显示错误信息]
SHOW_RETRY --> USER_RETRY{用户选择重试?}
USER_RETRY -->|是| RETRY_NODE[重试节点]
USER_RETRY -->|否| PIPELINE_FAILED[管道失败]
SHOW_ERROR --> PIPELINE_FAILED
WAIT_USER --> USER_INPUT[用户提供输入]
USER_INPUT --> VALIDATE_INPUT[验证用户输入]
VALIDATE_INPUT --> INPUT_VALID{输入有效?}
INPUT_VALID -->|否| WAIT_USER
INPUT_VALID -->|是| RETRY_NODE
RETRY_NODE --> EXECUTE_NODE
TRANSITION --> NEXT_NODE[设置下一个节点]
NEXT_NODE --> CHECK_CURRENT
end
subgraph "结束状态"
COMPLETED --> FINISH([完成])
PIPELINE_FAILED --> FINISH_ERROR([失败])
end
try {
const result = await executeNodeLogic(nodeId);
return { success: true, data: result };
} catch (error) {
console.error(`节点 ${nodeId} 执行失败:`, error);
return {
success: false,
error: error.message,
canRetry: isRetryableError(error)
};
}
try {
const nextNodeId = checkTransition(currentNodeId, result);
updateCurrentNode(nextNodeId);
} catch (transitionError) {
console.error('状态流转失败:', transitionError);
setGlobalError('初始化流程异常,请重启应用');
}
try {
return <PipelineProgress nodes={nodes} />;
} catch (renderError) {
console.error('UI 渲染失败:', renderError);
return <ErrorFallback message="界面渲染失败" />;
}
immer 或类似库优化深层状态更新React.memo 优化组件性能初始化管道系统是一个企业级的应用启动管理方案,具有以下优势:
这个初始化管道系统是现代 React 应用的最佳实践,特别适用于需要复杂初始化流程的企业级应用。
以下是对现有程序从启动到进入登录页面的完整流程分析。
从程序开始运行到显示登录页面,经历了两个主要层面的初始化:
程序的启动流程分为两个独立的层面:
第一层:环境层初始化(Environment Layer)
第二层:React 应用层初始化(Application Layer)
| 环境类型 | 环境层初始化 | 应用层初始化 |
|---|---|---|
| Electron | ✅ 单实例检查 ✅ 创建 BrowserWindow ✅ 加载 h5/index.html ✅ 设置 IPC 处理器 ✅ 服务器连接检查 |
✅ 产品初始化 ✅ 多语言加载 ✅ 注释管理器初始化 |
| 浏览器 | ❌ 无单实例检查 ❌ 无窗口创建 ❌ 无 IPC 处理器 ❌ 无服务器连接检查 |
✅ 产品初始化 ✅ 多语言加载 ✅ 注释管理器初始化 |
| Cordova | ✅ Cordova 插件初始化 ✅ 设备就绪检查 ✅ 服务器连接检查 |
✅ 产品初始化 ✅ 多语言加载 ✅ 注释管理器初始化 |
┌─────────────────────────────────────────────────────────────┐
│ 第一层:环境层初始化(Environment Layer) │
├─────────────────────────────────────────────────────────────┤
│ │
│ Electron 环境: │
│ ├─ 单实例检查(app.requestSingleInstanceLock) │
│ ├─ 等待应用就绪(app.whenReady) │
│ ├─ 创建 BrowserWindow │
│ ├─ 设置 IPC 处理器 │
│ └─ 加载 h5/index.html │
│ │
│ 浏览器环境: │
│ └─ 直接加载 index.html(无需额外初始化) │
│ │
│ Cordova 环境: │
│ ├─ Cordova 插件初始化 │
│ ├─ 设备就绪检查(deviceready 事件) │
│ └─ 加载应用主页面 │
│ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 第二层:React 应用层初始化(Application Layer) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 所有环境共享: │
│ ├─ React App 渲染 │
│ ├─ Redux Provider 初始化 │
│ ├─ 【并发执行阶段】 │
│ │ ├─ 【线程1】平台检测与服务器连接(app.tsx) │
│ │ │ ├─ 平台检测(platform.isBrowser/isElectron/isCordova) │
│ │ │ ├─ 服务器连接检查(仅非浏览器环境) │
│ │ │ └─ 如果连接失败 → 显示服务器配置对话框 │
│ │ └─ 【线程2】Taro路由加载云同步页面 │
│ │ ├─ 加载 cloud_sync_expired 页面 │
│ │ ├─ 调用 getQuota() API │
│ │ ├─ 检查 overdue 状态 │
│ │ ├─ 如果过期 → 显示提示并重试(最多10次) │
│ │ └─ 如果未过期 → 跳转到 pages/index/index │
│ ├─ 【阶段 2】应用状态初始化 │
│ │ ├─ 初始化产品状态(initializeProductState) │
│ │ ├─ 加载多语言资源(loadI18nMessages) │
│ │ ├─ 初始化注释管理器(initializeAnnotationManager) │
│ │ └─ 标记应用就绪(isI18nReady = true) │
│ │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 页面渲染层(Presentation Layer) │
├─────────────────────────────────────────────────────────────┤
│ │
│ ├─ 检查登录状态 │
│ ├─ 未登录 → 显示登录页面 │
│ ├─ 已登录但未初始化 → 显示初始化组件 │
│ └─ 已登录且已初始化 → 显示主应用界面 │
│ │
└─────────────────────────────────────────────────────────────┘
从程序开始运行到显示登录页面,经历了以下几个主要阶段:
入口文件:main.js
主要步骤:
main.jsapp.requestSingleInstanceLock())
app.whenReady())createWindow() 创建浏览器窗口
preload.jswin.loadFile(join(process.cwd(), 'h5/index.html'))win.once('ready-to-show', () => win.show())关键代码:
function createWindow() {
win = new BrowserWindow({
show: false,
frame: false,
titleBarStyle: 'hidden',
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: join(__dirname, 'preload.js'),
},
});
Menu.setApplicationMenu(null);
win.maximize();
win.loadFile(join(process.cwd(), 'h5/index.html'));
win.once('ready-to-show', () => win.show());
}
app.whenReady().then(createWindow);
入口组件:App 组件
主要逻辑:
App 组件,包裹 Redux ProviderAppContent 组件开始执行初始化逻辑触发时机:Taro 路由加载的第一个页面
配置位置:在 src/app.config.ts 中配置为第一个页面
export default defineAppConfig({
pages: [
'pages/security/cloud_sync_expired', // 第一个页面
'pages/index/index',
],
});
检查流程:
调用配额检查 API
const response = await getQuota();
const isOverdue = response.data.overdue;
overdue === false:授权有效,跳转到主入口页面
typescript
Taro.redirectTo({ url: '/pages/index/index' });
overdue === true:显示过期提示重试机制
显示状态:
关键代码:
const checkoverdue = async (currentRetry = 0) => {
try {
const response = await getQuota();
setoverdueStatus(response.data.overdue);
if (!response.data.overdue) {
// 未过期,跳转到主页面
Taro.redirectTo({ url: '/pages/index/index' });
} else {
// 过期,需要重试
if (currentRetry < maxRetries) {
setTimeout(() => checkoverdue(currentRetry + 1), 1000);
}
}
} catch (error) {
// 错误处理和重试逻辑
}
};
重要性:
环境检测与初始化:
浏览器环境:
platform.isBrowser 为 trueinitializeApp()
Electron/Cordova 环境:
dispatch(checkServerConnection())result.needsConfig 为 true:显示服务器配置对话框initializeApp()关键代码:
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);
});
}, [dispatch]);
执行步骤:
初始化产品状态
const productState = await dispatch(initializeProductState()).unwrap();
typescript
const languageCode = productState.language;
await dispatch(loadI18nMessages(languageCode)).unwrap();
初始化注释管理器
await initializeAnnotationManager();
typescript
setIsI18nReady(true);
错误处理:
路由配置 (src/app.config.ts):
export default defineAppConfig({
pages: [
'pages/security/cloud_sync_expired',
'pages/index/index',
],
// ...
});
入口页面渲染逻辑:
AppContent 组件根据状态决定渲染内容:
const AppContent: React.FC = () => {
const [initialized, setInitialized] = React.useState(false);
const userInfo = useSelector((state: RootState) => state.userInfo);
const loggedIn = isLoggedIn(userInfo);
// 1. 未登录 → 显示登录页面
if (!loggedIn) {
return <Login />;
}
// 2. 已登录但未初始化 → 显示初始化组件
if (!initialized) {
return <AppInitializer onInitialized={() => setInitialized(true)} />;
}
// 3. 已登录且已初始化 → 显示主布局
return (
<Router>
<BasicLayout children={undefined}></BasicLayout>
</Router>
);
};
状态判断逻辑:
isLoggedIn(userInfo))initialized 状态)token 过期处理:
useEffect(() => {
const handleTokenExpired = () => {
dispatch(clearUserInfo());
message.error('Your session has expired. Please log in again.');
};
emitter.on('tokenExpired', handleTokenExpired);
return () => {
emitter.off('tokenExpired', handleTokenExpired);
};
}, [dispatch]);
显示条件:
// 急诊模式下不显示登录页面
if (systemMode === SystemMode.Emergency) {
return null;
}
// 正常模式但已登录,不显示登录页面
if (systemMode === SystemMode.Normal && !!userInfo && userInfo.uid !== 0) {
return null;
}
登录页面功能:
用户名密码登录
loginApi(username, password)dispatch(setUserInfo(userInfo))dispatch(setSystemMode(SystemMode.Normal))急诊模式
handleEmergencyOperation()自动聚焦:
useEffect(() => {
if (usernameInputRef.current) {
usernameInputRef.current.focus();
}
}, []);
┌─────────────────────────────────────────────────────────────┐
│ 1. Electron 启动 │
│ └─ main.js 执行 │
│ ├─ 单实例检查 │
│ ├─ 等待应用就绪 (app.whenReady) │
│ ├─ 创建 BrowserWindow │
│ └─ 加载 h5/index.html │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 2. React App 渲染 (app.tsx) │
│ ├─ Redux Provider 初始化 │
│ └─ AppContent 组件渲染 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 3. 【并发执行】平台检测 + 页面路由加载 │
│ │
│ 【线程1: 平台检测与服务器连接】 │
│ ├─ 平台检测(platform.isBrowser/isElectron/isCordova) │
│ ├─ 服务器连接检查(仅非浏览器环境,异步API调用) │
│ └─ 如果连接失败 → 显示服务器配置对话框(IP输入框) │
│ │
│ 【线程2: Taro路由加载云同步页面】 │
│ ├─ 加载 cloud_sync_expired 页面 │
│ ├─ 调用 getQuota() API │
│ ├─ 检查 overdue 状态 │
│ ├─ 如果过期 → 显示提示并支持重试(重试提示) │
│ └─ 如果未过期 → 跳转到 pages/index/index │
│ │
│ 【结果】两个UI可能同时显示: │
│ ├─ 服务器配置对话框(IP输入框) │
│ └─ 云同步过期重试提示 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 4. 进入主页面后的应用初始化 │
│ ├─ initializeProductState() - 获取产品配置 │
│ ├─ loadI18nMessages() - 加载多语言资源 │
│ ├─ initializeAnnotationManager() - 初始化注释管理器 │
│ └─ setIsI18nReady(true) - 标记初始化完成 │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 5. 主页面状态判断 (pages/index/index.tsx) │
│ └─ AppContent 状态判断 │
│ ├─ !loggedIn → 渲染 <Login /> │
│ ├─ !initialized → 渲染 <AppInitializer /> │
│ └─ 已登录且已初始化 → 渲染 <BasicLayout /> │
└─────────────────────────────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────────┐
│ 6. 显示登录页面 (Login.tsx) │
│ ├─ 检查系统模式 (不在急诊模式) │
│ ├─ 检查登录状态 (未登录) │
│ └─ 渲染登录表单 │
│ ├─ 用户名输入框 (自动聚焦) │
│ ├─ 密码输入框 │
│ ├─ 登录按钮 │
│ └─ 急诊按钮 │
└─────────────────────────────────────────────────────────────┘
登录页面是否显示取决于以下条件:
| 条件 | 结果 |
|---|---|
systemMode === Emergency |
不显示登录页面 |
systemMode === Normal && isLoggedIn(userInfo) |
不显示登录页面 |
systemMode === Normal && !isLoggedIn(userInfo) |
显示登录页面 |
flowchart TD
Start([应用启动]) --> ElectronMain[Electron 主进程]
ElectronMain --> LoadHTML[加载 h5/index.html]
LoadHTML --> ReactApp[React App 初始化]
ReactApp --> PlatformCheck{平台检测}
PlatformCheck -->|浏览器| DirectInit[直接初始化应用]
PlatformCheck -->|Electron/Cordova| ServerCheck[检查服务器连接]
ServerCheck --> ServerOK{连接正常?}
ServerOK -->|否| ShowConfig[显示配置对话框]
ShowConfig --> UserConfig[用户输入配置]
UserConfig --> ServerCheck
ServerOK -->|是| InitApp[initializeApp]
DirectInit --> InitApp
InitApp --> ProductInit[初始化产品状态]
ProductInit --> I18nLoad[加载多语言资源]
I18nLoad --> AnnotationInit[初始化注释管理器]
AnnotationInit --> Ready[设置 isI18nReady = true]
Ready --> LoadPage[加载 pages/index/index]
LoadPage --> LoginCheck{用户已登录?}
LoginCheck -->|否| ShowLogin[显示登录页面]
LoginCheck -->|是| InitCheck{应用已初始化?}
InitCheck -->|否| ShowInitializer[显示初始化组件]
InitCheck -->|是| ShowMainUI[显示主应用界面]
ShowLogin --> LoginForm[登录表单]
LoginForm --> LoginAction[用户登录]
LoginAction --> SaveUserInfo[保存用户信息]
SaveUserInfo --> ShowMainUI
| 文件路径 | 作用 | 关键函数/组件 |
|---|---|---|
src/app.config.ts |
Taro 页面路由配置 | 页面顺序配置 |
src/pages/security/cloud_sync_expired.tsx |
云同步过期检查页面 | checkoverdue(), getQuota() |
main.js |
Electron 主进程入口 | createWindow(), app.whenReady() |
src/app.tsx |
React 应用入口 | App, AppContent, initializeApp() |
src/pages/index/index.tsx |
应用主入口页面 | AppContent, 登录状态判断 |
src/pages/security/Login.tsx |
登录页面 | Login, handleFinish(), handleEmergencyClick() |
src/states/user_info.ts |
用户信息状态管理 | setUserInfo, isLoggedIn |
src/states/productSlice.ts |
产品状态管理 | initializeProductState |
src/states/i18nSlice.ts |
国际化状态管理 | loadI18nMessages |
src/features/serverConfig/ |
服务器配置功能 | checkServerConnection, ServerConfigModal |
优点:
存在的问题:
改进方向:
📝 备注:以上分析基于当前代码库的实际情况,为设计新的初始化管道系统提供参考。