Аналог RPM-платформ: интеграция с приборами, вмешательства врача, блок образования
This commit is contained in:
parent
ae242d1f96
commit
175b6181b5
104
index.html
104
index.html
@ -179,6 +179,19 @@ a{color:inherit}
|
||||
.back-link:hover{color:var(--ink)}
|
||||
|
||||
.section-title{font-size:13px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--gray-500);margin:6px 0 12px}
|
||||
.devbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px;padding:12px;background:var(--cyan-50);border-radius:10px}
|
||||
.devlbl{font-size:13px;color:var(--gray-500);font-weight:600}
|
||||
details.edu{border:1px solid var(--gray-200);border-radius:10px;padding:0;margin-bottom:10px;overflow:hidden}
|
||||
details.edu summary{padding:13px 16px;font-weight:700;font-size:15px;cursor:pointer;list-style:none;background:var(--gray-100)}
|
||||
details.edu summary::-webkit-details-marker{display:none}
|
||||
details.edu[open] summary{border-bottom:1px solid var(--gray-200)}
|
||||
details.edu .edu-body{padding:14px 16px;font-size:14px;color:var(--gray-500)}
|
||||
details.edu .edu-body b{color:var(--ink)}
|
||||
details.edu .edu-body li{margin-bottom:6px}
|
||||
.iv-line{padding:11px 0;border-bottom:1px solid var(--gray-100)}
|
||||
.iv-line:last-child{border-bottom:none}
|
||||
.iv-line b{font-size:14px}
|
||||
.iv-line .iv-meta{font-size:12px;color:var(--gray-500);margin-top:2px}
|
||||
|
||||
.stat-line{display:flex;justify-content:space-between;padding:8px 0;border-bottom:1px solid var(--gray-100);font-size:14px}
|
||||
.stat-line:last-child{border-bottom:none}
|
||||
@ -225,7 +238,7 @@ a{color:inherit}
|
||||
"use strict";
|
||||
|
||||
/* ============ ДАННЫЕ (localStorage как «БД») ============ */
|
||||
var STORE_KEY = "copd_monitor_v1";
|
||||
var STORE_KEY = "copd_monitor_v2";
|
||||
|
||||
function seed(){
|
||||
var now = Date.now();
|
||||
@ -276,6 +289,10 @@ function seed(){
|
||||
],
|
||||
entries:[
|
||||
entry("p3",1,8,{spo2:88,sys:142,dia:90,hr:112,rr:26,mmrc:3,cat:[3,3,2,4,4,3,2,3],meds:{"m1@08:00":{taken:false}},note:"усилилась одышка, мокрота гнойная"})
|
||||
],
|
||||
interventions:[
|
||||
{ts:Date.now()-3600000*3, text:"Связался с пациентом. Усилить О₂ до 3 л/мин, начать преднизолон 30 мг/сут 5 дней, резервный амоксиклав."},
|
||||
{ts:Date.now()-3600000*26, text:"Пациент в красной зоне. Повторить SpO₂ через 30 мин, при <88% — госпитализация."}
|
||||
]
|
||||
},
|
||||
{
|
||||
@ -532,6 +549,30 @@ function renderPatient(){
|
||||
app.appendChild(emptyCard("Пока нет записей. Нажмите «Новая запись», чтобы начать."));
|
||||
}
|
||||
|
||||
// Образование и самопомощь
|
||||
var edu = el("div","card");
|
||||
edu.appendChild(el("h3","","📚 Образование и самопомощь",{"style":"margin-bottom:14px"}));
|
||||
edu.appendChild(el("div","muted","Краткие рекомендации при ХОБЛ. Нажмите, чтобы раскрыть.",{"style":"margin-bottom:12px"}));
|
||||
edu.appendChild(eduBlock("🌬 Дыхательная гимнастика",
|
||||
"<li><b>Диафрагмальное дыхание:</b> одна рука на животе, вдох через нос — живот надувается; выдох через рот медленно.</li>"+
|
||||
"<li><b>Дыхание через сжатые губы:</b> вдох носом 2 сек, выдох через губы трубочкой 4 сек. Удлиняйте выдох.</li>"+
|
||||
"<li>Выполняйте 5–10 минут 3–4 раза в день, особенно при одышке.</li>"));
|
||||
edu.appendChild(eduBlock("💊 Техника ингаляции",
|
||||
"<li>Встряхните ДАИ, снимите колпачок, выдохните мимо ингалятора.</li>"+
|
||||
"<li>Обхватите мундштук губами, начинайте вдох и нажмите на баллончик одновременно.</li>"+
|
||||
"<li>Продолжайте медленный глубокий вдох 3–5 сек, задержите дыхание на 10 сек.</li>"+
|
||||
"<li>После ингаляции ГКС — прополощите рот водой.</li>"));
|
||||
edu.appendChild(eduBlock("🚦 План действий (светофор)",
|
||||
"<li><b>🟢 Зелёная зона:</b> всё как обычно — базисная терапия, дневник.</li>"+
|
||||
"<li><b>🟡 Жёлтая зона:</b> SpO₂ 90–94% — спасатель, контроль, связаться с медсестрой.</li>"+
|
||||
"<li><b>🔴 Красная зона:</b> SpO₂ <90% — кислород, бронхолитик, положение, вызов скорой.</li>"));
|
||||
edu.appendChild(eduBlock("🚑 Когда вызывать скорую",
|
||||
"<li>SpO₂ < 88% держится более 5 минут или нарастает одышка.</li>"+
|
||||
"<li>Одышка в покое не уменьшается через 15–20 минут после бронхолитика.</li>"+
|
||||
"<li>Спутанность сознания, синюшность губ, боли в груди.</li>"+
|
||||
"<li>Температура > 38,5 °C с нарастающей одышкой.</li>"));
|
||||
app.appendChild(edu);
|
||||
|
||||
// История
|
||||
if(p.entries.length){
|
||||
var hc = el("div","card");
|
||||
@ -560,6 +601,12 @@ function bpZone(s,d){
|
||||
}
|
||||
function mmrcTxt(m){ return ["одышки нет","при быстрой ходьбе","иду медленнее","останавливаюсь ~100м","не могу выйти из дома"][m]||"—"; }
|
||||
|
||||
function eduBlock(title, html){
|
||||
var d=el("details","edu");
|
||||
d.innerHTML='<summary>'+title+'</summary><div class="edu-body"><ul style="padding-left:18px;margin:0">'+html+'</ul></div>';
|
||||
return d;
|
||||
}
|
||||
|
||||
function renderMedsCard(p, entry, showActions){
|
||||
var c = el("div","card");
|
||||
c.appendChild(el("h3","","💊 Базисные препараты",{"style":"margin-bottom:6px"}));
|
||||
@ -595,6 +642,21 @@ function markMed(p, med, time){
|
||||
save(state); render(); toast("Приём отмечен: "+med.name);
|
||||
}
|
||||
|
||||
/* mock-чтение с прибора (имитация Bluetooth) */
|
||||
function readDevice(kind){
|
||||
if(kind==="oxy"){
|
||||
var v = 88+Math.floor(Math.random()*9); // 88–96
|
||||
var hr = 64+Math.floor(Math.random()*42); // 64–105
|
||||
$("#spo2").value=v; $("#hr").value=hr;
|
||||
toast("Пульсоксиметр: SpO₂ "+v+"%, ЧСС "+hr);
|
||||
} else {
|
||||
var s=116+Math.floor(Math.random()*34); // 116–149
|
||||
var d=74+Math.floor(Math.random()*20); // 74–93
|
||||
$("#bpSys").value=s; $("#bpDia").value=d;
|
||||
toast("Тонометр: АД "+s+"/"+d);
|
||||
}
|
||||
}
|
||||
|
||||
function historyTable(p){
|
||||
var t = el("table","hist");
|
||||
var thead = el("thead"); thead.innerHTML='<tr><th>Дата</th><th>SpO₂</th><th>АД</th><th>ЧСС</th><th>ЧДД</th><th>mMRC</th><th>CAT</th><th>Зона</th></tr>';
|
||||
@ -633,6 +695,15 @@ function openDiaryModal(p){
|
||||
|
||||
// Жизненные показатели
|
||||
body.appendChild(el("div","section-title","Показатели"));
|
||||
// приборы (mock Bluetooth)
|
||||
var devBar = el("div","devbar");
|
||||
devBar.appendChild(el("span","devlbl","📡 Считать с прибора:"));
|
||||
var bOxy = el("button","btn ghost sm","🩸 Пульсоксиметр");
|
||||
bOxy.onclick=function(){ readDevice("oxy"); };
|
||||
var bBp = el("button","btn ghost sm","🩺 Тонометр");
|
||||
bBp.onclick=function(){ readDevice("bp"); };
|
||||
devBar.appendChild(bOxy); devBar.appendChild(bBp);
|
||||
body.appendChild(devBar);
|
||||
var fg = el("div","form-grid");
|
||||
fg.appendChild(field('spo2','number','🩸 Сатурация (SpO₂)','90',true,"%, 50–100"));
|
||||
fg.appendChild(bpField());
|
||||
@ -890,6 +961,37 @@ function openPatientDetail(id){
|
||||
} else {
|
||||
app.appendChild(emptyCard("Нет записей по пациенту."));
|
||||
}
|
||||
|
||||
// вмешательства и назначения врача
|
||||
app.appendChild(interventionsCard(p));
|
||||
}
|
||||
|
||||
function interventionsCard(p){
|
||||
var c=el("div","card");
|
||||
c.appendChild(el("h3","","📝 Вмешательства и назначения врача",{"style":"margin-bottom:14px"}));
|
||||
if(!p.interventions) p.interventions=[];
|
||||
if(p.interventions.length){
|
||||
p.interventions.slice().reverse().forEach(function(iv){
|
||||
var row=el("div","iv-line");
|
||||
row.innerHTML='<b>'+iv.text+'</b><div class="iv-meta">'+fmtTime(iv.ts)+'</div>';
|
||||
c.appendChild(row);
|
||||
});
|
||||
} else {
|
||||
c.appendChild(el("div","muted","Пока нет записей.",{"style":"margin-bottom:12px"}));
|
||||
}
|
||||
var ta=el("textarea","input"); ta.id="ivText"; ta.rows=2; ta.placeholder="Записать вмешательство/назначение (напр.: «Усилить О₂ до 3 л/мин, добавить преднизолон 30 мг»)"; ta.style.marginBottom="10px"; ta.style.width="100%";
|
||||
c.appendChild(ta);
|
||||
var btn=el("button","btn sm","Добавить запись");
|
||||
btn.onclick=function(){ addIntervention(p); };
|
||||
c.appendChild(btn);
|
||||
return c;
|
||||
}
|
||||
function addIntervention(p){
|
||||
var ta=$("#ivText"); var t=(ta&&ta.value||"").trim();
|
||||
if(!t){ toast("Введите текст вмешательства"); return; }
|
||||
if(!p.interventions) p.interventions=[];
|
||||
p.interventions.push({ts:Date.now(), text:t});
|
||||
save(state); openPatientDetail(p.id); toast("Вмешательство записано");
|
||||
}
|
||||
|
||||
function trendCard(p){
|
||||
|
||||
Loading…
Reference in New Issue
Block a user