11/**
2- * @ai -context: 应用模式(本地/云端)切换 Hook,包装 ModeManager;模式影响同步与 AI 路由全链路。
2+ * @ai -context: 应用模式(本地/云端)切换 Hook,包含 ModeManager;模式影响同步与 AI 路由全链路。
33 */
4- import { useState , useEffect , useCallback , useRef } from 'react' ;
4+ import { useState , useEffect } from 'react' ;
55import { modeManager , type AppMode , type ModeConfig } from '../lib/mode/ModeManager' ;
6- import { useAuth } from '../lib/auth/AuthContext' ;
7- import { useToast } from '../components/ui/Toast' ;
8- import { useNetworkStatus } from './useNetworkStatus' ;
9- import { getUnsyncedLogs } from '../lib/storage/operationLog' ;
106
117/**
128 * 轻量版:仅订阅模式状态,不依赖 Auth/Toast 上下文
@@ -26,86 +22,3 @@ export function useModeState() {
2622
2723 return { mode, config } ;
2824}
29-
30- /**
31- * 完整版:包含模式切换逻辑(含过渡保护)+ 自动降级
32- * 必须在 AuthProvider + ToastProvider 内使用
33- */
34- export function useMode ( ) {
35- const { mode, config } = useModeState ( ) ;
36- const { isAuthenticated } = useAuth ( ) ;
37- const { toast } = useToast ( ) ;
38- const { isOnline, isWeak } = useNetworkStatus ( ) ;
39-
40- // 记录上次网络状态,避免重复触发降级
41- const prevOnlineRef = useRef ( isOnline ) ;
42- const prevWeakRef = useRef ( isWeak ) ;
43-
44- // v0.9.0: 网络状态变化时自动降级
45- useEffect ( ( ) => {
46- const wasOnline = prevOnlineRef . current ;
47- const wasWeak = prevWeakRef . current ;
48- prevOnlineRef . current = isOnline ;
49- prevWeakRef . current = isWeak ;
50-
51- // 只在状态实际发生变化时触发降级检查
52- const networkChanged = ( wasOnline !== isOnline ) || ( wasWeak !== isWeak ) ;
53- if ( ! networkChanged ) return ;
54-
55- const currentMode = modeManager . getMode ( ) ;
56-
57- // 只在 hybrid/full 模式下才需要降级
58- if ( currentMode === 'local' ) return ;
59-
60- const degraded = modeManager . autoDegrade ( isOnline , isWeak ) ;
61- if ( degraded ) {
62- // Toast 提示由 onDegrade 监听器处理(下方),此处无需重复
63- }
64- } , [ isOnline , isWeak ] ) ;
65-
66- // v0.9.0: 订阅降级事件,显示 Toast 提示
67- useEffect ( ( ) => {
68- const unsubscribe = modeManager . onDegrade ( ( _fromMode , _toMode , reason ) => {
69- toast ( { type : 'warning' , message : reason , duration : 5000 } ) ;
70- } ) ;
71- return unsubscribe ;
72- } , [ toast ] ) ;
73-
74- const changeMode = useCallback ( async ( newMode : AppMode ) : Promise < boolean > => {
75- const currentMode = modeManager . getMode ( ) ;
76- if ( currentMode === newMode ) return true ;
77-
78- // local → hybrid/full:检查是否已登录
79- if ( currentMode === 'local' && ( newMode === 'hybrid' || newMode === 'full' ) ) {
80- if ( ! isAuthenticated ) {
81- toast ( { type : 'warning' , message : '请先登录后再开启云同步' } ) ;
82- return false ;
83- }
84- }
85-
86- // hybrid/full → local:检查未同步数据
87- if ( ( currentMode === 'hybrid' || currentMode === 'full' ) && newMode === 'local' ) {
88- try {
89- const unsyncedLogs = await getUnsyncedLogs ( ) ;
90- if ( unsyncedLogs . length > 0 ) {
91- const confirmed = window . confirm (
92- `当前有 ${ unsyncedLogs . length } 条未同步的修改,切换到本地模式后这些数据将不会同步到云端。\n确定要切换吗?` ,
93- ) ;
94- if ( ! confirmed ) return false ;
95- }
96- } catch {
97- // 检查失败时仍允许切换
98- }
99- }
100-
101- modeManager . setMode ( newMode ) ;
102- const labels : Record < AppMode , string > = { local : '本地模式' , hybrid : '联网模式' , full : '云端模式' } ;
103- toast ( { type : 'success' , message : `已切换到${ labels [ newMode ] } ` } ) ;
104- return true ;
105- } , [ isAuthenticated , toast ] ) ;
106-
107- // 推荐模式(仅展示用,不强制切换)
108- const recommendedMode = modeManager . computeRecommendedMode ( isAuthenticated , isOnline ) ;
109-
110- return { mode, config, changeMode, recommendedMode } ;
111- }
0 commit comments