Skip to content

Instantly share code, notes, and snippets.

@cabraljv
Last active March 21, 2023 11:25
Show Gist options
  • Save cabraljv/a07e54847f9e445e3d94d6260f0fff7c to your computer and use it in GitHub Desktop.
Save cabraljv/a07e54847f9e445e3d94d6260f0fff7c to your computer and use it in GitHub Desktop.
<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