224 lines
6.3 KiB
Vue
224 lines
6.3 KiB
Vue
<template>
|
|
<v-card class="data-manager">
|
|
<v-card-title>
|
|
<v-icon left>mdi-database</v-icon>
|
|
Manajemen Data
|
|
</v-card-title>
|
|
|
|
<v-card-text>
|
|
<v-row>
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="store.metadata.patientId"
|
|
label="ID Pasien"
|
|
prepend-icon="mdi-account"
|
|
variant="outlined"
|
|
density="compact"
|
|
@input="store.saveCurrentData"
|
|
/>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="6">
|
|
<v-text-field
|
|
v-model="store.metadata.dentist"
|
|
label="Dokter Gigi"
|
|
prepend-icon="mdi-doctor"
|
|
variant="outlined"
|
|
density="compact"
|
|
@input="store.saveCurrentData"
|
|
/>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-row>
|
|
<v-col cols="12" md="4">
|
|
<v-btn color="success" variant="elevated" block @click="exportData">
|
|
<v-icon left>mdi-download</v-icon>
|
|
Simpan Data
|
|
</v-btn>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="4">
|
|
<v-file-input
|
|
ref="fileInput"
|
|
accept=".json"
|
|
style="display: none"
|
|
@change="handleFileImport"
|
|
/>
|
|
<v-btn color="info" variant="elevated" block @click="importData">
|
|
<v-icon left>mdi-upload</v-icon>
|
|
Load Data
|
|
</v-btn>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="4">
|
|
<v-btn color="error" variant="elevated" block @click="clearAllData">
|
|
<v-icon left>mdi-delete-forever</v-icon>
|
|
Hapus Semua
|
|
</v-btn>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<v-divider class="my-4" />
|
|
|
|
<div class="conditions-summary">
|
|
<h4>Ringkasan Kondisi Gigi ({{ store.conditions.length }})</h4>
|
|
<div class="d-flex flex-wrap align-center gap-3">
|
|
<v-chip
|
|
v-for="condition in store.conditions"
|
|
:key="`${condition.toothNumber}-${condition.surface}`"
|
|
size="small"
|
|
closable
|
|
:link="false"
|
|
@click:close="removeCondition(condition)"
|
|
:color="getSurfaceColor(condition.surface)"
|
|
>
|
|
{{ condition.toothNumber
|
|
}}{{ condition.surface ? "-" + condition.surface : " " }}
|
|
<span v-if="condition.mode === 18">
|
|
{{
|
|
condition.position &&
|
|
condition.position.toLowerCase().includes("start")
|
|
? "Start(Bridge)"
|
|
: ""
|
|
}}
|
|
{{
|
|
condition.position &&
|
|
condition.position.toLowerCase().includes("finish")
|
|
? "Finish(Bridge)"
|
|
: ""
|
|
}}
|
|
</span>
|
|
<span v-else> ({{ getModeLabel(condition.mode) }}) </span>
|
|
<!-- <CircleXIcon class="ml-2" start size="20" /> -->
|
|
</v-chip>
|
|
</div>
|
|
</div>
|
|
</v-card-text>
|
|
</v-card>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import {
|
|
MoodSmileIcon,
|
|
ChecksIcon,
|
|
UserCircleIcon,
|
|
CircleXIcon
|
|
} from "vue-tabler-icons";
|
|
import type { ToothCondition } from "~/types/apps/medical/odontogram";
|
|
import { OdontogramMode } from "~/types/apps/medical/odontogram";
|
|
import { useOdontogramStore } from "~/store/apps/medical/odontogram";
|
|
import { useDataStorage } from "~/composables/apps/medical/useDataStorage";
|
|
|
|
const store = useOdontogramStore();
|
|
const { exportData: exportDataUtil, importData: importDataUtil } =
|
|
useDataStorage();
|
|
|
|
const fileInput = ref();
|
|
|
|
const modeLabels = {
|
|
[OdontogramMode.DEFAULT]: "Normal",
|
|
[OdontogramMode.AMF]: "Amalgam",
|
|
[OdontogramMode.COF]: "Composite",
|
|
[OdontogramMode.FIS]: "Sealant",
|
|
[OdontogramMode.NVT]: "Non-vital",
|
|
[OdontogramMode.RCT]: "Saluran Akar",
|
|
[OdontogramMode.NON]: "Tidak Ada",
|
|
[OdontogramMode.UNE]: "Un-Erupted",
|
|
[OdontogramMode.PRE]: "Partial-Erupt",
|
|
[OdontogramMode.ANO]: "Anomali",
|
|
[OdontogramMode.CARIES]: "Caries",
|
|
[OdontogramMode.CFR]: "Fraktur",
|
|
[OdontogramMode.FMC]: "Metal Crown",
|
|
[OdontogramMode.POC]: "Porcelain Crown",
|
|
[OdontogramMode.RRX]: "Sisa Akar",
|
|
[OdontogramMode.MIS]: "Hilang",
|
|
[OdontogramMode.IPX]: "Implant",
|
|
[OdontogramMode.FRM_ACR]: "Denture",
|
|
[OdontogramMode.BRIDGE]: "Bridge",
|
|
[OdontogramMode.ARROW_TOP_LEFT]: "Top Left Arrow",
|
|
[OdontogramMode.ARROW_TOP_RIGHT]: "Top Right Arrow",
|
|
[OdontogramMode.ARROW_BOTTOM_LEFT]: "Bottom Left Arrow",
|
|
[OdontogramMode.ARROW_BOTTOM_RIGHT]: "Bottom Right Arrow",
|
|
[OdontogramMode.ARROW_TOP_TURN_LEFT]: "Top Turn Left Arrow",
|
|
[OdontogramMode.ARROW_TOP_TURN_RIGHT]: "Top Turn Right Arrow",
|
|
[OdontogramMode.ARROW_BOTTOM_TURN_LEFT]: "Bottom Turn Left Arrow",
|
|
[OdontogramMode.ARROW_BOTTOM_TURN_RIGHT]: "Bottom Turn Right Arrow",
|
|
[OdontogramMode.HAPUS]: "Hapus"
|
|
};
|
|
|
|
const getModeLabel = (mode: OdontogramMode) => {
|
|
return modeLabels[mode] || "Unknown";
|
|
};
|
|
|
|
const exportData = () => {
|
|
const data = store.exportCurrentData();
|
|
exportDataUtil(data);
|
|
};
|
|
|
|
const importData = () => {
|
|
fileInput.value?.$el.querySelector("input").click();
|
|
};
|
|
|
|
const handleFileImport = async (event: any) => {
|
|
const file = event.target.files?.[0];
|
|
if (!file) return;
|
|
|
|
const data = await importDataUtil(file);
|
|
if (data) {
|
|
store.importData(data);
|
|
// Clear file input
|
|
event.target.value = "";
|
|
} else {
|
|
alert("Error importing data. Please check the file format.");
|
|
}
|
|
};
|
|
|
|
const clearAllData = () => {
|
|
if (
|
|
confirm("Apakah Anda yakin ingin menghapus semua data termasuk metadata?")
|
|
) {
|
|
store.clearAllConditions();
|
|
store.metadata.patientId = "";
|
|
store.metadata.dentist = "";
|
|
store.metadata.date = new Date().toISOString().split("T")[0];
|
|
}
|
|
};
|
|
|
|
const removeCondition = (condition: ToothCondition) => {
|
|
store.removeCondition(condition.toothNumber, condition.surface);
|
|
};
|
|
|
|
const getSurfaceColor = (surface: string | undefined) => {
|
|
switch (surface) {
|
|
case "T":
|
|
return "primary"; // Vuetify blue
|
|
case "R":
|
|
return "success"; // Vuetify green
|
|
case "B":
|
|
return "error"; // Vuetify red
|
|
case "L":
|
|
return "info"; // Vuetify yellow
|
|
case "M":
|
|
return "secondary"; // Custom purple, will add style below
|
|
default:
|
|
return "secondary";
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.data-manager {
|
|
margin-bottom: 16px;
|
|
}
|
|
|
|
.conditions-summary {
|
|
margin-top: 16px;
|
|
}
|
|
|
|
.conditions-summary h4 {
|
|
margin-bottom: 12px;
|
|
color: #666;
|
|
}
|
|
</style>
|