index.ts 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import { create } from 'zustand';
  2. import type { ClientState, EmotionType } from '@/types';
  3. export type PageType = 'welcome' | 'loading' | 'video' | 'naming' | 'chatbot';
  4. interface AppState {
  5. // 页面状态
  6. currentPage: PageType;
  7. // 状态
  8. currentState: ClientState;
  9. currentRequestId: string | null;
  10. currentEmotion: EmotionType;
  11. recognizedText: string;
  12. errorMessage: string | null;
  13. isConnected: boolean;
  14. conversationProgress: number; // 当前进度 0-100
  15. progressLoopCount: number; // 已完成的整圈数量
  16. // Actions
  17. setPage: (page: PageType) => void;
  18. setState: (state: ClientState) => void;
  19. setRequestId: (id: string | null) => void;
  20. setEmotion: (emotion: EmotionType) => void;
  21. setRecognizedText: (text: string) => void;
  22. setError: (message: string | null) => void;
  23. setConnected: (connected: boolean) => void;
  24. updateProgressByDuration: (durationMs: number) => void; // 根据说话时长更新进度(30秒=100%)
  25. setProgress: (progress: number, loopCount?: number) => void; // 直接设置进度值(0-100),可选指定整圈数量
  26. reset: () => void;
  27. }
  28. export const useAppStore = create<AppState>((set) => ({
  29. // 初始状态
  30. currentPage: 'welcome',
  31. currentState: 'idle',
  32. currentRequestId: null,
  33. currentEmotion: 'neutral',
  34. recognizedText: '',
  35. errorMessage: null,
  36. isConnected: false,
  37. conversationProgress: 0,
  38. progressLoopCount: 0,
  39. // Actions
  40. setPage: (page) => {
  41. set({ currentPage: page });
  42. // 保存当前页面到 localStorage
  43. try {
  44. localStorage.setItem('Lyrria_current_page', page);
  45. } catch (error) {
  46. // 保存页面状态失败,静默处理
  47. }
  48. },
  49. setState: (state) => set({ currentState: state }),
  50. setRequestId: (id) => set({ currentRequestId: id }),
  51. setEmotion: (emotion) => set({ currentEmotion: emotion }),
  52. setRecognizedText: (text) => set({ recognizedText: text }),
  53. setError: (message) => set({ errorMessage: message, currentState: message ? 'error' : 'idle' }),
  54. setConnected: (connected) => set({ isConnected: connected }),
  55. updateProgressByDuration: (durationMs) => set((state) => {
  56. // 30秒 = 100% 进度
  57. const PROGRESS_FULL_DURATION_MS = 30 * 1000; // 30000ms
  58. // 计算本次增加的进度百分比
  59. const progressIncrement = (durationMs / PROGRESS_FULL_DURATION_MS) * 100;
  60. // 计算新的进度值
  61. const newProgress = state.conversationProgress + progressIncrement;
  62. // 🔍 日志:记录状态更新
  63. console.log('[Progress] [store] updateProgressByDuration:', {
  64. durationMs,
  65. progressIncrement: progressIncrement.toFixed(2),
  66. currentProgress: state.conversationProgress,
  67. currentLoopCount: state.progressLoopCount,
  68. newProgress: newProgress.toFixed(2),
  69. willLoop: newProgress >= 100,
  70. });
  71. // 如果超过100%,转一圈后再继续
  72. // 例如:当前90%,说话31秒,则:90% + 103.33% = 193.33% → 转一圈后剩余 93.33%
  73. if (newProgress >= 100) {
  74. const cycles = Math.floor(newProgress / 100); // 转了几圈
  75. const remainder = newProgress % 100; // 剩余进度
  76. console.log('[Progress] [store] 转圈:', {
  77. cycles,
  78. remainder: remainder.toFixed(2),
  79. newLoopCount: state.progressLoopCount + cycles,
  80. });
  81. return {
  82. conversationProgress: remainder,
  83. progressLoopCount: state.progressLoopCount + cycles,
  84. };
  85. }
  86. console.log('[Progress] [store] 更新进度(不转圈):', {
  87. newProgress: newProgress.toFixed(2),
  88. });
  89. return { conversationProgress: newProgress };
  90. }),
  91. setProgress: (progress, loopCount) =>
  92. set((state) => ({
  93. conversationProgress: Math.max(0, Math.min(100, progress)),
  94. progressLoopCount:
  95. typeof loopCount === 'number'
  96. ? Math.max(0, Math.floor(loopCount))
  97. : state.progressLoopCount,
  98. })),
  99. reset: () =>
  100. set({
  101. currentState: 'idle',
  102. currentRequestId: null,
  103. currentEmotion: 'neutral',
  104. recognizedText: '',
  105. errorMessage: null,
  106. }),
  107. }));