<!DOCTYPE html>
<html lang="en">
<head>
  <title>SOS Score Assessment</title>
  <meta http-equiv="Content-Language" content="th" />
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <script src="https://cdn.tailwindcss.com"></script>
  <script src="https://registry.npmmirror.com/vue/3.3.11/files/dist/vue.global.js"></script>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap">
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.3/css/all.min.css">
  <style>
    body {
      font-family: 'Roboto', sans-serif;
    }
    .bg-custom {
      background-color: #d3e2f2;
    }
    .text-custom {
      color: #262c40;
    }
    ul {
      list-style-type:decimal !important;
      padding: 0;
    }
    li {
      padding: 5px 0;
      border-bottom: 1px solid #ddd;
    }
  </style>
</head>
<body class="bg-gray-100 p-4">
  <div id="app" class="max-w-lg mx-auto bg-white p-2 rounded shadow relative">
    <div class="flex justify-between items-center mb-2 bg-gray-200 p-4 rounded">
      <div class="flex items-center">
        <i class="fas fa-heartbeat text-custom text-2xl mr-2"></i>
        <div class="text-2xl font-bold text-custom">SOS Score Assessment</div>
      </div>
      <button @click="showAbout = true" class="text-gray-700">
        <i class="fas fa-info-circle text-2xl"></i>
      </button>
    </div>
    <div class="mb-2 bg-gray-100 p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">AN หรือ ชื่อ-สกุลผู้ป่วย</div>
      </div>
      <div class="flex items-left mt-2 mb-2">
        <input type="text" class="border border-gray-300 rounded p-2 w-full text-center" v-model="patient" @input="validatePatient" />
      </div>
      <div v-if="patientError" class="text-red-500 text-sm mb-2">{{ patientError }}</div>
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">อุณหภูมิ (T: องศาเซลเซียส °C)</div>
        <div :class="getSosClass(temperatureSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ temperatureSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <input type="number" step="0.1" class="border border-gray-300 rounded p-2 w-full text-center" v-model="temperature" @input="validateTemperature" />
      </div>
      <div v-if="temperatureError" class="text-red-500 text-sm mb-2">{{ temperatureError }}</div>
    </div>
    <div class="mb-2 bg-white p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">ความดันโลหิต (BP: Systolic/Diastolic มิลลิเมตรปรอท)</div>
        <div :class="getSosClass(bloodPressureSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ medicationSos? medicationSos: bloodPressureSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <input type="number" class="border border-gray-300 rounded p-2 w-full text-center" v-model="systolic" @input="validateSystolic" />
        <span class="mx-2">/</span>
        <input type="number" class="border border-gray-300 rounded p-2 w-full text-center" v-model="diastolic" @input="validateDiastolic" />
      </div>
      <div v-if="bloodPressureError" class="text-red-500 text-sm mb-2">{{ bloodPressureError }}</div>
      <div class="flex items-center mt-2">
        <input type="checkbox" id="medication" v-model="medication" class="mr-2">
        <label for="medication" class="text-gray-700">ให้ยากระตุ้นความดันโลหิต
          <span class="bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">3</span>
        </label>
      </div>
    </div>
    <div class="mb-2 bg-gray-100 p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">ชีพจร (P: อัตราการเต้นของหัวใจ ครั้ง/นาที)</div>
        <div :class="getSosClass(pulseSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ pulseSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <input type="number" class="border border-gray-300 rounded p-2 w-full text-center" v-model="pulse" @input="validatePulse" />
      </div>
      <div v-if="pulseError" class="text-red-500 text-sm mb-2">{{ pulseError }}</div>
    </div>
    <div class="mb-2 bg-white p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">หายใจ (R: อัตราการหายใจ ครั้ง/นาที)</div>
        <div :class="getSosClass(breathingSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ ventilationSos? ventilationSos : breathingSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <input type="number" class="border border-gray-300 rounded p-2 w-full text-center" v-model="breathing" @input="validateBreathing" />
      </div>
      <div v-if="breathingError" class="text-red-500 text-sm mb-2">{{ breathingError }}</div>
      <div class="flex items-center mt-2">
        <input type="checkbox" id="ventilation" v-model="ventilation" class="mr-2">
        <label for="ventilation" class="text-gray-700">ใส่เครื่องช่วยหายใจ
          <span class="bg-blue-100 text-blue-800 text-sm font-medium me-2 px-2.5 py-0.5 rounded dark:bg-blue-900 dark:text-blue-300">2</span>
        </label>
      </div>
    </div>
    <div class="mb-2 bg-gray-100 p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">ปัสสาวะ (ปริมาณ มิลลิลิตร)</div>
        <div :class="getSosClass(urineSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ urineSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <input type="number" step="1" class="border border-gray-300 rounded p-2 w-full text-center" v-model="urine" @input="validateUrine" />
        <select class="border border-gray-300 rounded p-2 ml-2" v-model="urineInterval">
          <option value="24h">ต่อ 1 วัน</option>
          <option value="8h">ต่อ 8 ชม.</option>
          <option value="4h">ต่อ 4 ชม.</option>
          <option value="1h">ต่อ 1 ชม.</option>
        </select>
      </div>
      <div v-if="urineError" class="text-red-500 text-sm mb-2">{{ urineError }}</div>
    </div>
    <div class="mb-2 bg-white p-2 rounded">
      <div class="flex justify-between items-center">
        <div class="text-lg font-bold text-custom">ระดับความรู้สึกตัว</div>
        <div :class="getSosClass(consciousnessSos)" class="text-white text-xl font-bold w-10 h-10 flex items-center justify-center rounded">{{ consciousnessSos }}</div>
      </div>
      <div class="flex items-center mt-2">
        <select class="border border-gray-300 rounded p-2 w-full" v-model="consciousnessLevel">
          <option value="ตื่นดี">ตื่นดี (พูดคุยรู้เรื่อง)</option>
          <option value="ซึม">ซึม (แต่เรียกแล้วลืมตาสลึมสลือ)</option>
          <option value="สับสน">สับสน (กระสับกระส่ายที่เพิ่งเกิดขึ้น)</option>
          <option value="ซึมมาก">ซึมมาก (ต้องกระตุ้นจึงลืมตา)</option>
          <option value="ไม่รู้สึกตัว">ไม่รู้สีกตัว (แม้กระตุ้นแล้วก็ตาม)</option>
        </select>
      </div>
    </div>
    <div class="bg-yellow-300 p-4 rounded text-center text-3xl font-bold mb-2">
      SOS Score : {{ totalSosScore }}
    </div>
    <div class="flex items-center mt-2">
      <input type="checkbox" id="sendNotify" v-model="sendNotify" class="mr-2">
      <label for="sendNotify" class="text-gray-700">แจ้งเตือนผ่าน Line Notify
        <span class="bg-green-100 text-green-800 text-xs font-medium me-2 px-2.5 py-0.5 rounded dark:bg-green-900 dark:text-green-300">กลุ่มไลน์งานพยาบาลผู้ป่วยในโรงพยาบาลกุดข้าวปุ้น</span>
      </label>
    </div>
    <div class="bg-white p-4 rounded text-left">
      <p class="font-bold">แนวทางการดูแลผลสรุปการให้คะแนน SOS Score</p>
      <ul>
        <li v-for="(item, index) in sosDetailItems" :key="index">
          {{ item }}
        </li>
      </ul>
    </div>

    <!-- About Dialog -->
    <div v-if="showAbout" class="fixed inset-0 bg-gray-800 bg-opacity-75 flex items-center justify-center">
      <div class="bg-white p-6 rounded shadow-lg max-w-lg w-full">
        <div class="text-xl font-bold mb-2">SOS Score Assessment</div>
        <p class="mb-2">Search Out Severity Score (SOS Score) เครื่องมือคัดกรอง ติดตาม อาการผู้ป่วยและเพื่อวางแผนการประเมินติดตามอาการผู้ป่วยที่ต้องเฝ้าระวัง เป็นเครื่องมือที่พัฒนามาจาก MEWS เพื่อให้เข้ากับบริบทการทำงานและมีความแม่นยำมากขึ้น</p>
        <p class="mb-2"><strong>จัดทำโดย</strong> <br />งานผู้ป่วยใน กลุ่มการพยาบาล โรงพยาบาลกุดข้าวปุ้น</p>
        <button @click="showAbout = false" class="bg-blue-500 text-white px-4 py-2 rounded">Close</button>
      </div>
    </div>
  </div>
  <script>
    const { createApp, ref, computed, watch } = Vue
    createApp({
      setup() {
        const patient = ref('')
        const temperature = ref(36.5)
        const systolic = ref(120)
        const diastolic = ref(80)
        const pulse = ref(70)
        const breathing = ref(20)
        const urine = ref(1001)
        const urineInterval = ref('24h')
        const consciousnessLevel = ref('ตื่นดี')
        const medication = ref(false)
        const ventilation = ref(false)
        const showAbout = ref(false)
        const sendNotify = ref(false)

        const patientError = ref('')
        const temperatureError = ref('')
        const bloodPressureError = ref('')
        const pulseError = ref('')
        const breathingError = ref('')
        const urineError = ref('')

        // const sosDetailItems = ref([])
        
        const validatePatient = () => {
          if (patient.value == '') {
            patientError.value = 'กรอกข้อมูลผู้ป่วยที่ต้องการประเมิน'
          } else {
            patientError.value = ''
          }
        }

        const validateTemperature = () => {
          if (temperature.value < 30 || temperature.value > 45) {
            temperatureError.value = 'อุณหภูมิต้องอยู่ระหว่าง 30 ถึง 45 องศาเซลเซียส'
          } else {
            temperatureError.value = ''
          }
        }

        const validateSystolic = () => {
          if (systolic.value < 70 || systolic.value > 200) {
            bloodPressureError.value = 'ความดันโลหิต Systolic ต้องอยู่ระหว่าง 70 ถึง 200 mmHg'
          } else {
            bloodPressureError.value = ''
          }
        }

        const validateDiastolic = () => {
          if (diastolic.value < 40 || diastolic.value > 120) {
            bloodPressureError.value = 'ความดันโลหิต Diastolic ต้องอยู่ระหว่าง 40 ถึง 120 mmHg'
          } else {
            bloodPressureError.value = ''
          }
        }

        const validatePulse = () => {
          if (pulse.value < 30 || pulse.value > 200) {
            pulseError.value = 'ชีพจรต้องอยู่ระหว่าง 30 ถึง 200 ครั้งต่อนาที'
          } else {
            pulseError.value = ''
          }
        }

        const validateBreathing = () => {
          if (breathing.value < 8 || breathing.value > 50) {
            breathingError.value = 'อัตราการหายใจปกติผู้ใหญ่ระหว่าง 20-26 ครั้ง/นาที เด็กแรกเกิด 30-50 ครั้ง/นาที'
          } else {
            breathingError.value = ''
          }
        }

        const validateUrine = () => {
          if (urine.value < 0 || urine.value > 2000) {
            urineError.value = 'ปริมาณปัสสาวะต้องอยู่ระหว่าง 0 ถึง 2000 มิลลิลิตร'
          } else {
            urineError.value = ''
          }
        }

        const temperatureSos = computed(() => {
          var x = 0;
          switch (true) {
            case temperature.value <= 35.0 : 
              x=2;
              break;
            case temperature.value >= 35.1 && temperature.value <= 36.0 :
              x=1;
              break;
            case temperature.value >= 36.1 && temperature.value <= 38.0 :
              x=0;
              break;
            case temperature.value >= 38.1 && temperature.value <= 38.4 :
              x=1;
              break;
            case temperature.value >= 38.5 :
              x=2;
              break;
            default:
              x=0
          }
          // console.log(`T: ${temperature.value} : ${x}`);
          return x;
        });

        const bloodPressureSos = computed(() => {
          switch (true) {
            case systolic.value <= 80:
              return 3;
              break;
            case systolic.value >= 81 && systolic.value <= 90:
              return 2;
              break;
            case systolic.value >= 91 && systolic.value <= 100:
              return 1;
              break;
            case systolic.value >= 101 && systolic.value <= 180:
              return 0;
              break;
            case systolic.value >= 181 && systolic.value <= 199:
              return 1;
              break;
            case systolic.value >= 200:
              return 2;
              break;
            default:
              return 0;
          }
        });
        
        const medicationSos = computed(() => medication.value ? 3 : 0);
        const pulseSos = computed(() => {
          switch (true) {
            case pulse.value <= 40:
              return 3;
              break;
            case pulse.value >= 41 && pulse.value <= 50:
              return 1;
              break;
            case pulse.value >= 51 && pulse.value <= 100:
              return 0;
              break;
            case pulse.value >= 101 && pulse.value <= 120:
              return 1;
              break;
            case pulse.value >= 121 && pulse.value <= 139:
              return 2;
              break;
            case pulse.value >= 140:
              return 3;
              break;
            default:
              return 0;
          }
        });

        const breathingSos = computed(() => {
          switch (true) {
            case breathing.value <= 8:
              return 3;
              break;
            case breathing.value >= 9 && breathing.value <= 20:
              return 0;
              break;
            case breathing.value >= 21 && breathing.value <= 25:
              return 1;
              break;
            case breathing.value >= 26 && breathing.value <= 35:
              return 2;
              break;
            case breathing.value > 35:
              return 3;
              break;
          }
        });

        const ventilationSos = computed(() => ventilation.value ? 2 : 0);
        
        const urineSos = computed(() => {
          return calculateUrineScore(urineInterval.value, urine.value);
        });

        const consciousnessSos = computed(() => {
          switch (consciousnessLevel.value) {
            case 'สับสน':
              return 1;
              break;
            case 'ตื่นดี':
              return 0; 
              break;
            case 'ซึม':
              return 1;
              break;
            case 'ซึมมาก':
              return 2;
              break;
            case 'ไม่รู้สึกตัว':
              return 3; 
              break;
            default:
              return 0
          }
        });

        const totalSosScore = computed(() => {
          var bloodPressureCal = bloodPressureSos.value ? bloodPressureSos.value : medicationSos.value;
          var breathingCal = breathingSos.value ? breathingSos.value : ventilationSos.value;

          return temperatureSos.value + bloodPressureCal + pulseSos.value + breathingCal + urineSos.value + consciousnessSos.value
        });

        const getSosClass = (score) => {
          switch (score) {
            case 0:
              return 'bg-green-500'
            case 1:
              return 'bg-yellow-500'
            case 2:
              return 'bg-orange-500'
            case 3:
              return 'bg-orange-800'
            case 4:
              return 'bg-red-500'
            case 5:
              return 'bg-red-800'
            default:
              return 'bg-gray-500'
          }
        }

        const sosDetail = computed(() => {
          switch (true) {
            case (totalSosScore.value >= 1 && totalSosScore.value <= 3):
              return 'ผู้ช่วยเหลือคนไข้รายงานพยาบาล, Record V/S I/O ทุก 2-4 ชม., ประเมิน SOS Score ทุก 4 ชม., พยาบาลพิจารณารายงานแพทย์ตามความเหมาะสม';
              break;
            case (totalSosScore.value >= 4): 
              return 'ผู้ช่วยเหลือคนไข้รายงานพยาบาลและพยาบาลรายงานแพทย์ทันที, Record V/S, I/O ทุก 15-30 นาที, พิจารณาย้ายผู้ป่วยมาอยู่ในบริเวณที่สามารถดูแลได้อย่างใกล้ชิดร่วมกับพิจารณาย้าย ICU, ER, Monitor ผู้ป่วยทุก 15-30 นาทีจน SOS น้อยกว่า 4 หรือจนกว่าแพทย์บอกว่า Stable';
              break;
            default: 
              return 'Record V/S ตามปกติ ทุก 4 ชม.และประเมิน SOS Score ตามปกติ';
          }
        });

        const sosDetailItems = computed(() => {
          switch (true) {
            case (totalSosScore.value >= 1 && totalSosScore.value <= 3):
              return [
                'ผู้ช่วยเหลือคนไข้รายงานพยาบาล', 
                'Record V/S, I/O ทุก 2-4 ชม.', 
                'ประเมิน SOS Score ทุก 4 ชม.', 
                'พยาบาลพิจารณารายงานแพทย์ตามความเหมาะสม',
                'กรณีมีภาวะ Shock ให้รายงานแพทย์และปฏิบัติตาม Flow'
              ];
              break;
            case (totalSosScore.value >= 4): 
              return [
                'ผู้ช่วยเหลือคนไข้รายงานพยาบาลและพยาบาลรายงานแพทย์ทันที',
                'Record V/S, I/O ทุก 15-30 นาที',
                'พิจารณาย้ายผู้ป่วยมาอยู่ในบริเวณที่สามารถดูแลได้อย่างใกล้ชิดร่วมกับพิจารณาย้าย ICU, ER',
                'ค้นหาสาเหตุที่ทำให้ผู้ป่วยแย่ลง เช่น Severe Sepsis, Septic Shock Acute MI, Ac PE etc',
                'Monitor ผู้ป่วยทุก 15-30 นาทีจน SOS น้อยกว่า 4 หรือจนกว่าแพทย์บอกว่า Stable',
              ];
              break;
            default: 
              return [
                'Record V/S ตามปกติ ทุก 4 ชม.',
                'ประเมิน SOS Score ตามปกติ'
              ];
          }
        });

        const sendLineNotify = (message) => {
          const token = 'tsj7sW81mKlLvypWEpVooP7bo2hBiKEuXvBgUjEx1LA';
          const apiEndpoint = 'https://cors-anywhere.herokuapp.com/https://notify-api.line.me/api/notify';
          const header= '🚨 SOS Score Alert\n';
          const footer= 'ข้อมูล: ประเมิน SOS Score';
          
          fetch(apiEndpoint, {
            method: 'POST',
            headers: {
              'Content-Type': 'application/x-www-form-urlencoded',
              'Authorization': `Bearer ${token}`
            },
            body: new URLSearchParams({ message: `${header}${message}${footer}` }),
          })
          .then((response) => response.json())
          .then((data) => console.log(data))
          .catch((error) => console.error(error));
        };

        watch(totalSosScore, (newScore) => {
          const sosItems = [
            ["อุณหภูมิ", temperature.value, "°C"],
            ["BP", `${systolic.value}/${diastolic.value}`, "mmHg"],
            ["P", pulse.value, "ครั้ง/นาที"],
            ["R", breathing.value, "ครั้ง/นาที"],
            ["ปัสสาวะ", urine.value, "มิลลิลิตร"],
            ["ระดับความรู้สึกตัว", consciousnessLevel.value, " "]
          ];
          console.table(sosItems);
          const sosMessage = sosItems
            .map(([key, value, unit]) => {
              return unit ? `${key}: ${value} ${unit}` : `${key}: ${value}`;
            })
            .join("\n"); // Add newlines between items


          if (newScore >= 4 && sendNotify.value) {
            const alertMessage = `SOS Score is ${newScore}\n-----------\nผู้ป่วย (AN/ชื่อ-สกุล): ${patient.value}\nแนวทางการดูแล\n${sosDetail.value}\n-----------\n${sosMessage}\n`;
            sendLineNotify(alertMessage)
          }
        });

        // const sendNotifyCheck = computed(()=> sendNotify.value);

        function round(value, minimumFractionDigits, maximumFractionDigits) {
          const formattedValue = value.toLocaleString('en', {
            useGrouping: false,
            minimumFractionDigits,
            maximumFractionDigits
          });
          return Number(formattedValue);
        }

        function calculateUrineScore(scoreRate, value) {
          const scoreTable = {
            "24h": [
              { range: [-Infinity, 500], score: 2 },
              { range: [501, 999], score: 1 },
              { range: [1000, Infinity], score: 0 },
            ],
            "8h": [
              { range: [-Infinity, 160], score: 2 },
              { range: [161, 319], score: 1 },
              { range: [320, Infinity], score: 0 },
            ],
            "4h": [
              { range: [-Infinity, 80], score: 2 },
              { range: [81, 159], score: 1 },
              { range: [160, Infinity], score: 0 },
            ],
            "1h": [
              { range: [-Infinity, 20], score: 2 },
              { range: [21, 39], score: 1 },
              { range: [40, Infinity], score: 0 },
            ],
          };

          const ranges = scoreTable[scoreRate];
          if (!ranges) {
            throw new Error("Invalid rate provided");
          }

          for (const { range, score } of ranges) {
            if (value >= range[0] && value <= range[1]) {
              return score;
            }
          }

          throw new Error("Invalid value for the given rate");
        }

        // Example usage:
        // const trate = "24h";
        // const tvalue = 600;
        // console.log(`Score: ${calculateUrinieScore(trate, tvalue)}`); // Output: Score: 1

        return {
          patient,
          temperature,
          systolic,
          diastolic,
          pulse,
          breathing,
          urine,
          urineInterval,
          consciousnessLevel,
          medication,
          ventilation,
          showAbout,
          temperatureError,
          bloodPressureError,
          pulseError,
          breathingError,
          urineError,
          patientError,
          validateTemperature,
          validateSystolic,
          validateDiastolic,
          validatePulse,
          validateBreathing,
          validateUrine,
          validatePatient,
          temperatureSos,
          bloodPressureSos,
          medicationSos,
          pulseSos,
          breathingSos,
          ventilationSos,
          urineSos,
          consciousnessSos,
          totalSosScore,
          getSosClass,
          sosDetail,
          sosDetailItems,
          sendNotify
        }
      }
    }).mount('#app')
  </script>
</body>
</html>