Last active
March 21, 2023 11:25
-
-
Save cabraljv/a07e54847f9e445e3d94d6260f0fff7c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<v-app style="overflow: hidden" v-if="!loading"> | |
<v-row> | |
<v-col | |
:cols="tabs === 'left' ? 10 : 6" | |
class="px-0 mx-0" | |
v-if="tabs !== 'right'" | |
> | |
<pacient-exam | |
v-if="dicom_image" | |
:onlyExam="tabs === 'left'" | |
:dicom_image="dicom_image" | |
></pacient-exam> | |
</v-col> | |
<v-col | |
:cols="tabs === 'right' ? 10 : 4" | |
v-if="tabs !== 'left'" | |
class="px-0 mx-0" | |
> | |
<v-card | |
v-if="!error" | |
flat | |
style="height: 100%; display: flex" | |
class="pa-0" | |
> | |
<atlas-exam | |
:activeClass="activeClass" | |
:classification="classification" | |
:sex="sex" | |
:onChangeClass="onChangeClass" | |
></atlas-exam> | |
</v-card> | |
</v-col> | |
<v-col cols="2" class="mt-10"> | |
<v-row justify="center" class="mb-4"> | |
<v-card class="px-6 py-2" v-if="sex === 'f'">FEMALE</v-card> | |
<v-card class="px-6 py-2" v-if="sex === 'm'">MALE</v-card> | |
</v-row> | |
<v-row justify="center"> | |
<v-btn | |
@click="activeClass = item.class" | |
class="ma-2 mr-3" | |
large | |
rounded | |
v-for="item of bestPercents" | |
:key="item.class" | |
>{{ formatPercent(item.prob) }}% <br /> | |
{{ item.classFullName }}</v-btn | |
> | |
</v-row> | |
<v-row justify="center" class="mt-10"> | |
<v-btn rounded color="primary" @click="copyDiagnostic"> | |
<v-icon class="pr-1">mdi-clipboard-account-outline</v-icon> copy | |
diagnostic | |
</v-btn> | |
</v-row> | |
<div class="logo-indicators"> | |
<span class="text-h3">BETA</span> | |
<img src="../assets/albert-einstein.svg" alt="Einstein" /> | |
<img src="../assets/logo_rad_white.png" alt="Rad Square" /> | |
</div> | |
</v-col> | |
</v-row> | |
<v-row class="tab-controls"> | |
<v-btn | |
@click="tabs = 'left'" | |
:color="tabs === 'left' ? 'primary' : ''" | |
fab | |
small | |
><v-icon small>mdi-arrow-collapse-left</v-icon></v-btn | |
> | |
<v-btn | |
@click="tabs = 'both'" | |
:color="tabs === 'both' ? 'primary' : ''" | |
fab | |
small | |
class="mx-6" | |
>||</v-btn | |
> | |
<v-btn | |
@click="tabs = 'right'" | |
:color="tabs === 'right' ? 'primary' : ''" | |
fab | |
small | |
><v-icon small>mdi-arrow-collapse-right</v-icon></v-btn | |
> | |
</v-row> | |
<v-dialog v-model="error" width="500"> | |
<v-card> | |
<v-row align="center" class="pa-6"> | |
<v-card-title class="text-h5"> Error on open exam </v-card-title> | |
<v-spacer></v-spacer> | |
<v-btn icon @click="error = false"><v-icon>mdi-close</v-icon></v-btn> | |
</v-row> | |
<v-card-text> | |
An unexpected error has occurred on exam load, try again later or | |
contact a administrator | |
</v-card-text> | |
</v-card> | |
</v-dialog> | |
<v-snackbar color="primary" timeout="1000" v-model="snackbar"> | |
Successfully copied diagnostic | |
</v-snackbar> | |
</v-app> | |
<v-app v-else> | |
<div | |
style=" | |
width: 100%; | |
margin-top: calc(50vh - 64px); | |
display: flex; | |
justify-content: center; | |
" | |
> | |
<v-progress-circular | |
indeterminate | |
color="blue" | |
size="128" | |
></v-progress-circular> | |
</div> | |
</v-app> | |
</template> | |
<script> | |
import { api } from "../infra/api"; | |
import PacientExam from "../components/PacientExam.vue"; | |
import AtlasExam from "../components/AtlasExam.vue"; | |
import atlas from "../assets/atlas/atlas.json"; | |
export default { | |
name: "Home", | |
components: { PacientExam, AtlasExam }, | |
data: () => ({ | |
dicom_image: null, | |
studyInstanceUID: null, | |
classification: null, | |
activeClass: "", | |
snackbar: false, | |
bestPercents: [], | |
tabs: "right", | |
sex: "", | |
loading: false, | |
error: false, | |
}), | |
async mounted() { | |
atlas.female.reverse(); | |
atlas.male.reverse(); | |
this.studyInstanceUID = this.$route.query.studyInstanceUID; | |
await this.fetchData(); | |
if (this.bestPercents && this.bestPercents.length > 0) { | |
this.activeClass = this.bestPercents[0].class; | |
} | |
}, | |
methods: { | |
formatPercent(prob) { | |
return (prob * 100).toFixed(2); | |
}, | |
onChangeClass(newClass) { | |
this.activeClass = newClass; | |
}, | |
copyDiagnostic() { | |
const active_exam = atlas[this.sex === "f" ? "female" : "male"].find( | |
(item) => item.class === this.activeClass | |
); | |
navigator.clipboard.writeText( | |
`Idade óssea compatível com ${ | |
active_exam.classFullName | |
} segundo atlas de Greulich-Pyle, para o sexo ${ | |
this.sex === "m" ? "masculino" : "feminino" | |
}.` | |
); | |
this.snackbar = true; | |
}, | |
async fetchData() { | |
if (this.studyInstanceUID) { | |
try { | |
this.loading = true; | |
const response = await api.get( | |
"/analysis?studyInstanceUID=" + this.studyInstanceUID, | |
{ crossDomain: true } | |
); | |
const { prediction } = response.data.classification; | |
this.dicom_image = response.data.dicom; | |
this.classification = prediction; | |
const sorted_classification = prediction.sort((a, b) => | |
a.prob < b.prob ? 1 : b.prob < a.prob ? -1 : 0 | |
); | |
this.sex = response.data.sex; | |
this.bestPercents = sorted_classification.slice(0, 3).map((item) => { | |
let atlas_item = atlas[this.sex === "f" ? "female" : "male"].find( | |
(item2) => `${item2.age}` === `${item.class}` | |
); | |
if (!atlas_item) { | |
atlas_item = { | |
class: `${this.sex}${item.class}`, | |
className: `${Math.floor(item.class / 12)} years ${ | |
item.class % 12 !== 0 ? `and ${item.class % 12} months` : "" | |
}`, | |
}; | |
} | |
return { ...item, ...atlas_item }; | |
}); | |
} catch (error) { | |
this.error = true; | |
} | |
this.loading = false; | |
} else { | |
this.error = true; | |
} | |
}, | |
}, | |
}; | |
</script> | |
<style scoped lang="scss"> | |
.logo-indicators { | |
position: absolute; | |
bottom: 30px; | |
right: 30px; | |
display: flex; | |
flex-direction: column; | |
align-content: center; | |
justify-content: center; | |
span { | |
margin-right: 10px; | |
} | |
img { | |
height: 3.5rem; | |
} | |
img:nth-child(2) { | |
margin: 15px 0; | |
} | |
img:first-of-type { | |
margin-right: 10px; | |
} | |
} | |
.tab-controls { | |
position: fixed; | |
top: 20px; | |
left: calc(50% - 72px); | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment