Fix: solucionar error SQLITE_BUSY y mejorar backend
- Migrar de sqlite3 a better-sqlite3 con conexión persistente - Configurar WAL mode, busy_timeout y PRAGMAs optimizados - Implementar transacciones para operaciones bulk - Corregir error initialLoadComplete en useHospitalStore.ts - Agregar tablas usuarios y kv faltantes - Actualizar .gitignore para archivos WAL de SQLite
This commit is contained in:
@@ -111,33 +111,61 @@ export function useHospitalStore() {
|
||||
return () => { mounted = false; };
|
||||
}, []);
|
||||
|
||||
// Persist state to backend when it changes (debounced)
|
||||
const [initialLoadComplete, setInitialLoadComplete] = useState(false);
|
||||
// Persistence: event-driven + periodic save
|
||||
const [saveQueue, setSaveQueue] = useState<string[]>([]);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (isLoaded && !initialLoadComplete) {
|
||||
setInitialLoadComplete(true);
|
||||
}
|
||||
}, [isLoaded, initialLoadComplete]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!initialLoadComplete) return;
|
||||
const t = setTimeout(() => {
|
||||
(async () => {
|
||||
try {
|
||||
const { currentUser, isAuthenticated, ...stateToSave } = state;
|
||||
await fetch(`${API_BASE}/state`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(stateToSave),
|
||||
});
|
||||
} catch (err) {
|
||||
// ignore save errors for now
|
||||
// Track which parts changed
|
||||
const [changedKeys, setChangedKeys] = useState<Set<string>>(new Set());
|
||||
|
||||
// Mark parts as changed
|
||||
const markChanged = (key: string) => {
|
||||
setChangedKeys(prev => {
|
||||
const next = new Set(prev);
|
||||
next.add(key);
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
// Save only changed parts
|
||||
const saveChanges = useCallback(async () => {
|
||||
if (isSaving || changedKeys.size === 0) return;
|
||||
setIsSaving(true);
|
||||
try {
|
||||
const keysToSave = Array.from(changedKeys);
|
||||
const partialState: any = {};
|
||||
keysToSave.forEach(key => {
|
||||
if (key in state) {
|
||||
partialState[key] = state[key];
|
||||
}
|
||||
})();
|
||||
}, 300);
|
||||
return () => clearTimeout(t);
|
||||
}, [state, initialLoadComplete]);
|
||||
});
|
||||
|
||||
await fetch(`${API_BASE}/state/partial`, {
|
||||
method: 'PUT',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(partialState),
|
||||
});
|
||||
setChangedKeys(new Set());
|
||||
} catch (err) {
|
||||
console.error('Save error:', err);
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
}, [state, changedKeys, isSaving]);
|
||||
|
||||
// Periodic save every 5 seconds if there are changes
|
||||
useEffect(() => {
|
||||
if (!isLoaded) return;
|
||||
const t = setInterval(() => {
|
||||
saveChanges();
|
||||
}, 5000);
|
||||
return () => clearInterval(t);
|
||||
}, [isLoaded, saveChanges]);
|
||||
|
||||
// Also save on特定 events (optional)
|
||||
const queueSave = (keys: string[]) => {
|
||||
keys.forEach(markChanged);
|
||||
};
|
||||
|
||||
// Utility functions
|
||||
const getCamaAreaId = useCallback((camaId: string): string | null => {
|
||||
|
||||
Reference in New Issue
Block a user