253 lines
9.0 KiB
JavaScript
253 lines
9.0 KiB
JavaScript
var EXERCISES = [
|
|
{ ico: "🌬️", name: "Тыныс алу жаттығуы", dur: 60, desc: "Диафрагмамен терең тыныста: ішті үрлеп жұт, баяу шығар" },
|
|
{ ico: "🙆", name: "Мойын қозғалыстары", dur: 60, desc: "Мойынды баяу алға-артқа, солға-оңға еңкейт (айналдырмай)" },
|
|
{ ico: "🤸", name: "Иық айналдыру", dur: 60, desc: "Иықты алға, содан артқа айналдыр — әр бағытта 10 рет" },
|
|
{ ico: "✊", name: "Қол буындарын қозғау", dur: 45, desc: "Жұдырық жұм, аш; саусақтарды веермен жаз" },
|
|
{ ico: "🐱", name: "«Мысық пен сиыр»", dur: 60, desc: "Төрт аяқтап тұрып, арқаны дөңгелектеп, содан иілдір" },
|
|
{ ico: "🦵", name: "Жамбас буындары", dur: 60, desc: "Шалқадан жатып, тізені кеудеге тарт, екінші аяқты түзу ұста" },
|
|
{ ico: "🦿", name: "Тізе қозғалыстары", dur: 60, desc: "Отырып немесе жатып, тізені баяу бүк-жаз" },
|
|
{ ico: "🦶", name: "Тобық айналдыру", dur: 45, desc: "Әр аяқтың тобығын сағат тілімен және қарсы айналдыр" }
|
|
];
|
|
|
|
var state = {
|
|
list: document.getElementById("exList"),
|
|
ring: document.getElementById("ring"),
|
|
time: document.getElementById("time"),
|
|
name: document.getElementById("timerName"),
|
|
startBtn: document.getElementById("startBtn"),
|
|
resetBtn: document.getElementById("resetBtn"),
|
|
skipBtn: document.getElementById("skipBtn"),
|
|
autoBtn: document.getElementById("autoBtn"),
|
|
progText: document.getElementById("progText"),
|
|
progBar: document.getElementById("progBar"),
|
|
index: 0,
|
|
running: false,
|
|
auto: false,
|
|
left: EXERCISES[0].dur,
|
|
total: 0,
|
|
int: null
|
|
};
|
|
|
|
function fmt(s) {
|
|
var m = Math.floor(s / 60), ss = s % 60;
|
|
return (m < 10 ? "0" : "") + m + ":" + (ss < 10 ? "0" : "") + ss;
|
|
}
|
|
|
|
function render() {
|
|
var html = EXERCISES.map(function (e, i) {
|
|
var cls = i === state.index ? " active" : "";
|
|
if (state.auto && i === state.index) cls = " on";
|
|
if (state.auto && i < state.index) cls = " done";
|
|
var st = i < state.index ? "✓" : (i === state.index && state.running ? "…" : fmt(e.dur));
|
|
return '<div class="ex' + cls + '" data-i="' + i + '">' +
|
|
'<div class="ex-ico">' + e.ico + '</div>' +
|
|
'<div class="ex-body"><div class="ex-name">' + e.name + '</div>' +
|
|
'<div class="ex-time">' + e.desc + '</div></div>' +
|
|
'<div class="ex-state">' + st + '</div></div>';
|
|
}).join("");
|
|
state.list.innerHTML = html;
|
|
state.list.querySelectorAll(".ex").forEach(function (el) {
|
|
el.addEventListener("click", function () { pick(parseInt(el.dataset.i, 10)); });
|
|
});
|
|
updateRing();
|
|
updateProg();
|
|
}
|
|
|
|
function updateRing() {
|
|
var done = state.total - state.left;
|
|
var pct = state.total > 0 ? (done / state.total) * 360 : 0;
|
|
state.ring.style.background = "conic-gradient(var(--cyan) " + pct + "deg, #223043 0deg)";
|
|
state.time.textContent = fmt(state.left);
|
|
state.name.textContent = EXERCISES[state.index].name;
|
|
}
|
|
|
|
function updateProg() {
|
|
if (!state.auto) {
|
|
state.progText.textContent = "Жеке жаттығу";
|
|
state.progBar.style.width = "0%";
|
|
return;
|
|
}
|
|
var done = state.index;
|
|
state.progText.textContent = (done + 1) + " / " + EXERCISES.length;
|
|
state.progBar.style.width = (done / EXERCISES.length * 100) + "%";
|
|
}
|
|
|
|
function beep() {
|
|
try {
|
|
var ctx = new (window.AudioContext || window.webkitAudioContext)();
|
|
var o = ctx.createOscillator(), g = ctx.createGain();
|
|
o.connect(g); g.connect(ctx.destination);
|
|
o.frequency.value = 660; g.gain.value = 0.18;
|
|
o.start();
|
|
setTimeout(function () { o.stop(); ctx.close(); }, 350);
|
|
} catch (e) {}
|
|
}
|
|
|
|
function stop() {
|
|
clearInterval(state.int);
|
|
state.int = null;
|
|
state.running = false;
|
|
state.startBtn.textContent = "▶ Бастау";
|
|
}
|
|
|
|
function tick() {
|
|
state.left--;
|
|
if (state.left <= 0) {
|
|
beep();
|
|
next();
|
|
return;
|
|
}
|
|
updateRing();
|
|
}
|
|
|
|
function start() {
|
|
if (state.running) { stop(); render(); return; }
|
|
state.running = true;
|
|
state.startBtn.textContent = "⏸ Тоқтау";
|
|
state.int = setInterval(tick, 1000);
|
|
render();
|
|
}
|
|
|
|
function next() {
|
|
clearInterval(state.int);
|
|
state.int = null;
|
|
if (state.auto) {
|
|
state.index++;
|
|
if (state.index >= EXERCISES.length) {
|
|
state.auto = false;
|
|
state.index = 0;
|
|
state.left = EXERCISES[0].dur;
|
|
state.total = EXERCISES[0].dur;
|
|
state.running = false;
|
|
state.autoBtn.textContent = "🎯 Толық кешенді бастау (барлық 8 жаттығу)";
|
|
state.startBtn.textContent = "▶ Бастау";
|
|
beep(); beep();
|
|
render();
|
|
return;
|
|
}
|
|
state.left = EXERCISES[state.index].dur;
|
|
state.total = state.left;
|
|
render();
|
|
state.running = true;
|
|
state.int = setInterval(tick, 1000);
|
|
return;
|
|
}
|
|
state.index = (state.index + 1) % EXERCISES.length;
|
|
state.left = EXERCISES[state.index].dur;
|
|
state.total = state.left;
|
|
state.running = false;
|
|
render();
|
|
}
|
|
|
|
function pick(i) {
|
|
stop();
|
|
state.auto = false;
|
|
state.autoBtn.textContent = "🎯 Толық кешенді бастау (барлық 8 жаттығу)";
|
|
state.index = i;
|
|
state.left = EXERCISES[i].dur;
|
|
state.total = state.left;
|
|
render();
|
|
}
|
|
|
|
function reset() {
|
|
stop();
|
|
state.left = EXERCISES[state.index].dur;
|
|
state.total = state.left;
|
|
render();
|
|
}
|
|
|
|
function startAuto() {
|
|
stop();
|
|
state.auto = true;
|
|
state.index = 0;
|
|
state.left = EXERCISES[0].dur;
|
|
state.total = state.left;
|
|
state.autoBtn.textContent = "⏸ Кешен жүріп жатыр…";
|
|
state.startBtn.textContent = "▶ Бастау";
|
|
render();
|
|
start();
|
|
}
|
|
|
|
state.startBtn.addEventListener("click", start);
|
|
state.resetBtn.addEventListener("click", reset);
|
|
state.skipBtn.addEventListener("click", function () { stop(); next(); });
|
|
state.autoBtn.addEventListener("click", startAuto);
|
|
|
|
render();
|
|
|
|
var io = new IntersectionObserver(function (entries) {
|
|
entries.forEach(function (e) { if (e.isIntersecting) e.target.classList.add("in"); });
|
|
}, { threshold: .15 });
|
|
document.querySelectorAll(".reveal").forEach(function (el) { io.observe(el); });
|
|
|
|
var chatBox = document.getElementById("chatBox");
|
|
var chatInput = document.getElementById("chatInput");
|
|
var chatSend = document.getElementById("chatSend");
|
|
|
|
function addMsg(who, text) {
|
|
var d = document.createElement("div");
|
|
d.className = "msg " + who;
|
|
d.textContent = text;
|
|
chatBox.appendChild(d);
|
|
chatBox.scrollTop = chatBox.scrollHeight;
|
|
}
|
|
|
|
function addQuickLinks(text) {
|
|
var t = text.toLowerCase();
|
|
var links = [];
|
|
if (t.indexOf("жаттығу") !== -1 || t.indexOf("жаттыгу") !== -1 || t.indexOf("қозғал") !== -1 || t.indexOf("козгал") !== -1) {
|
|
links.push({ href: "#timer", label: "▶ Жаттығу бөлімі" });
|
|
}
|
|
if (t.indexOf("мазь") !== -1 || t.indexOf("укол") !== -1 || t.indexOf("дәрі") !== -1 || t.indexOf("дәр") !== -1 || t.indexOf("дори") !== -1 || t.indexOf("гель") !== -1) {
|
|
links.push({ href: "#drugs", label: "💊 Дәрілер бөлімі" });
|
|
links.push({ href: "#pharm", label: "🛒 Онлайн-аптека" });
|
|
}
|
|
if (!links.length) return;
|
|
var row = document.createElement("div");
|
|
row.className = "msg-quick";
|
|
links.forEach(function (l) {
|
|
var a = document.createElement("a");
|
|
a.className = "btn btn-ghost btn-quick";
|
|
a.href = l.href;
|
|
a.textContent = l.label;
|
|
a.addEventListener("click", function () {
|
|
var sec = document.querySelector(l.href);
|
|
if (sec) sec.scrollIntoView({ behavior: "smooth" });
|
|
});
|
|
row.appendChild(a);
|
|
});
|
|
chatBox.appendChild(row);
|
|
chatBox.scrollTop = chatBox.scrollHeight;
|
|
}
|
|
|
|
async function sendChat() {
|
|
var text = chatInput.value.trim();
|
|
if (!text) return;
|
|
addMsg("user", text);
|
|
chatInput.value = "";
|
|
var waiting = document.createElement("div");
|
|
waiting.className = "msg bot typing";
|
|
waiting.textContent = "Жазып жатыр…";
|
|
chatBox.appendChild(waiting);
|
|
chatBox.scrollTop = chatBox.scrollHeight;
|
|
try {
|
|
var r = await fetch("/api/advice", {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ text: text })
|
|
});
|
|
var j = await r.json();
|
|
waiting.remove();
|
|
if (j.ok) { addMsg("bot", j.answer); addQuickLinks(j.answer); }
|
|
else addMsg("bot", "Кешіріңіз, жауап қазір келмеді. Кейінірек қайталап көріңіз немесе шағымыңды басқаша жазып жіберіңіз.");
|
|
} catch (e) {
|
|
waiting.remove();
|
|
addMsg("bot", "Қате болды. Байланысты тексеріп, қайталап көріңіз.");
|
|
}
|
|
}
|
|
|
|
chatSend.addEventListener("click", sendChat);
|
|
chatInput.addEventListener("keydown", function (e) {
|
|
if (e.key === "Enter" && !e.shiftKey) { e.preventDefault(); sendChat(); }
|
|
});
|