Аналог RPM-платформ: интеграция с приборами, вмешательства врача, блок образования

This commit is contained in:
Dauren777 2026-06-26 06:31:54 +00:00
parent ae242d1f96
commit 175b6181b5

View File

@ -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>Выполняйте 510 минут 34 раза в день, особенно при одышке.</li>"));
edu.appendChild(eduBlock("💊 Техника ингаляции",
"<li>Встряхните ДАИ, снимите колпачок, выдохните мимо ингалятора.</li>"+
"<li>Обхватите мундштук губами, начинайте вдох и нажмите на баллончик одновременно.</li>"+
"<li>Продолжайте медленный глубокий вдох 35 сек, задержите дыхание на 10 сек.</li>"+
"<li>После ингаляции ГКС — прополощите рот водой.</li>"));
edu.appendChild(eduBlock("🚦 План действий (светофор)",
"<li><b>🟢 Зелёная зона:</b> всё как обычно — базисная терапия, дневник.</li>"+
"<li><b>🟡 Жёлтая зона:</b> SpO₂ 9094% — спасатель, контроль, связаться с медсестрой.</li>"+
"<li><b>🔴 Красная зона:</b> SpO₂ &lt;90% — кислород, бронхолитик, положение, вызов скорой.</li>"));
edu.appendChild(eduBlock("🚑 Когда вызывать скорую",
"<li>SpO₂ &lt; 88% держится более 5 минут или нарастает одышка.</li>"+
"<li>Одышка в покое не уменьшается через 1520 минут после бронхолитика.</li>"+
"<li>Спутанность сознания, синюшность губ, боли в груди.</li>"+
"<li>Температура &gt; 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); // 8896
var hr = 64+Math.floor(Math.random()*42); // 64105
$("#spo2").value=v; $("#hr").value=hr;
toast("Пульсоксиметр: SpO₂ "+v+"%, ЧСС "+hr);
} else {
var s=116+Math.floor(Math.random()*34); // 116149
var d=74+Math.floor(Math.random()*20); // 7493
$("#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,"%, 50100"));
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){