baldav/frontend/js/bmr.js
4aiman 19282ded78 Sensors, walk limits, GPS fixes, water UI, manual routes, Gridnev products, OTA router
GPS altitude: accel-based glitch filter (accel=0 + speed = GPS drift), altitude
  jump >100m filter, timestamp sanity (>24h = remove). Per-point Crr from accel
  vibration (smooth/mixed/gravel). Gap interpolation on map with dashed lines
  when accel confirms movement. Walk/run separate speed limits (configurable).
  Adaptive GPS accuracy (auto x2 when signal bad). Dead reckoning points when
  GPS silent but accel shows movement. Locale.US fix for sensor JSON.

Sensors: accelerometer + gyroscope in GpsRecorderService (RMS, max, pitch, yaw).
  Columns in gps_points. Dynamic addGpsPoint INSERT (safe if columns missing).

Manual routes: draw on map by tapping points, elevation from past tracks +
  open-meteo API, realistic timestamps by activity speed. Manual sessions
  skip glitch filtering on recalculate. Speed from GPS.config not hardcoded.

Water tracking: water_pct field in product add/edit forms, searchProducts
  returns water_pct, "ml" label for liquids, recipe water from ingredients.

BMR: moving average weight (7 days), fixed charts using dailyBase not raw bmr.

BLE: ble_clear_hr on stop, recovery toast, serde alias for ts/timestamp.

Products: 217 Gridnev products (bakery, desserts, bread, ready meals).
  Magnit scraper fix (NUXT_DATA name/value pairs, not indices). Supplements
  addSupplement with all 41 columns. Nutrient fallback RDI includes omega/EPA/DHA.

Export/import: custom products + recipes + supplements in single JSON bundle.
  Export all or single product. Dedup on import by name_lower + source.

OTA: router upload (LAN, always), VPS upload (-u flag). Kotlin checks router
  first (2s timeout), then VPS. Update URL from update_info.json.

Session detail: renderToken prevents stale setTimeout callbacks after recalculate.
WAL disabled (PRAGMA journal_mode=DELETE).
2026-06-18 22:54:45 +03:00

71 lines
2.6 KiB
JavaScript

// Mifflin-St Jeor BMR formula.
// Males: BMR = 10*weight + 6.25*height - 5*age - 5
// Females: BMR = 10*weight + 6.25*height - 5*age + 161
function calculateBmr(weightKg, heightCm, age, sex) {
const base = 10 * weightKg + 6.25 * heightCm - 5 * age;
return Math.round(sex === "m" ? base - 5 : base + 161);
}
function getAge(birthYear) {
return new Date().getFullYear() - birthYear;
}
// RDI loaded from DB (rdi_standards + rdi_values tables).
// Fallback hardcoded RU values used until DB is ready.
let RDI_TYPES = {}; // { nutrient_key: "rdi" | "aup" }
let RDI = {
vit_a_mcg: 800, vit_c_mg: 60, vit_e_mg: 10, vit_b1_mg: 1.4, vit_b2_mg: 1.6,
vit_b3_mg: 18, vit_b5_mg: 6, vit_b6_mg: 2, vit_b7_mcg: 50, folate_mcg: 200,
vit_b12_mcg: 1, vit_d_mcg: 5, vit_k_mcg: 120, calcium_mg: 1000, magnesium_mg: 400,
zinc_mg: 15, iron_mg: 14, iodine_mg: 0.15, selenium_mcg: 70, molybdenum_mcg: 70,
manganese_mg: 2, copper_mg: 1, chromium_mg: 0.05, phosphorus_mg: 800,
potassium_mg: 3500, sodium_mg: 2400,
omega3_mg: 1000, epa_mg: 250, dha_mg: 250,
lutein_mg: 5, lycopene_mg: 5, silicon_mg: 30, vanadium_mg: 0.04,
};
// Load RDI from DB for selected standard. Called after DB ready.
async function loadRDI(standardCode) {
try {
const std = await window.__TAURI__.core.invoke("plugin:sql|select", {
db: "sqlite:baldav.db",
query: "SELECT id FROM rdi_standards WHERE code = ?1",
values: [standardCode || "RU"],
});
if (!std.length) return;
const vals = await window.__TAURI__.core.invoke("plugin:sql|select", {
db: "sqlite:baldav.db",
query: "SELECT nutrient_key, value, norm_type FROM rdi_values WHERE standard_id = ?1",
values: [std[0].id],
});
const loaded = {};
RDI_TYPES = {};
for (const v of vals) {
loaded[v.nutrient_key] = v.value;
RDI_TYPES[v.nutrient_key] = v.norm_type || "rdi";
}
if (Object.keys(loaded).length > 0) RDI = loaded;
} catch (e) { console.error("[BMR] loadRDI error:", e); }
}
// Nutrient half-life data loaded from DB
let HALFLIFE = {}; // { nutrient_key: halflife_avg_days }
async function loadHalflife() {
try {
const rows = await window.__TAURI__.core.invoke("plugin:sql|select", {
db: "sqlite:baldav.db",
query: "SELECT nutrient_key, halflife_avg_days FROM nutrient_halflife",
values: [],
});
HALFLIFE = {};
for (const r of rows) HALFLIFE[r.nutrient_key] = r.halflife_avg_days;
} catch (e) { console.error("[BMR] loadHalflife error:", e); }
}
window.BMR = { calculateBmr, getAge, loadRDI, loadHalflife,
get RDI() { return RDI; },
get RDI_TYPES() { return RDI_TYPES; },
get HALFLIFE() { return HALFLIFE; },
};