first commit
This commit is contained in:
@@ -0,0 +1,223 @@
|
||||
<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>
|
||||
Reference in New Issue
Block a user