fix(number-fields): избегаем потери точности длинных чисел
- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
This commit is contained in:
34
server/utils/userActivity.ts
Normal file
34
server/utils/userActivity.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { db } from "../db";
|
||||
import { users } from "@shared/schema";
|
||||
import { eq } from "drizzle-orm";
|
||||
|
||||
// In-memory throttle to avoid writing last_activity_at on every authenticated request.
|
||||
// Maps userId -> timestamp (ms) of the last DB update.
|
||||
const lastActivityUpdate = new Map<number, number>();
|
||||
|
||||
const THROTTLE_MS = 60_000; // 1 minute
|
||||
|
||||
/**
|
||||
* Updates users.last_activity_at for the given user, throttled to once per minute.
|
||||
* Fire-and-forget: does not block the caller.
|
||||
*/
|
||||
export function trackUserActivity(userId: number): void {
|
||||
const now = Date.now();
|
||||
const lastUpdate = lastActivityUpdate.get(userId);
|
||||
if (lastUpdate && now - lastUpdate < THROTTLE_MS) return;
|
||||
|
||||
lastActivityUpdate.set(userId, now);
|
||||
|
||||
// Run async without awaiting so the request is not delayed.
|
||||
db.update(users)
|
||||
.set({ lastActivityAt: new Date() })
|
||||
.where(eq(users.id, userId))
|
||||
.then(() => {
|
||||
// No-op on success
|
||||
})
|
||||
.catch((err) => {
|
||||
// Reset the throttle timestamp on error so the next request retries.
|
||||
lastActivityUpdate.delete(userId);
|
||||
console.error("[trackUserActivity] failed to update user activity:", err);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user