fix(FE) : fix edit delete in antrean spesialis and category

This commit is contained in:
Yusron alamsyah
2026-02-19 09:09:11 +07:00
parent 6ec4a9758c
commit fa7b6d2be3
5 changed files with 360 additions and 44 deletions
+2 -2
View File
@@ -78,7 +78,7 @@ watch(itemsPerPageLocal, (newVal) => {
<template>
<div class="table-container">
<div class="table-wrapper" :class="{ 'loading-overlay-wrapper': loading }">
<div class="" :class="{ 'loading-overlay-wrapper': loading }">
<!-- Loading Overlay -->
<div v-if="loading" class="loading-overlay">
<v-progress-circular
@@ -99,7 +99,7 @@ watch(itemsPerPageLocal, (newVal) => {
v-model:items-per-page="itemsPerPageLocal"
:search="serverSide ? undefined : search"
:loading="loading"
class="elevation-1"
elevation="0"
item-value="id"
hide-default-footer
striped="even"
+3
View File
@@ -118,6 +118,9 @@ const allHeaders = [
{ title: 'No Rekam Medis', key: 'NoRekamMedis', sortable: false, width: '180px' },
{ title: 'Nama Pasien', key: 'NamaPasien', sortable: false },
{ title: 'Jenis kelamin', key: 'JenisKelamin', sortable: false },
{ title : 'Kategori', key: 'Kategori', sortable: false },
{ title : 'Spesialis', key: 'Spesialis', sortable: false },
{ title : 'Sub Spesialis', key: 'SubSpesialis', sortable: false },
{ title: 'Status', key: 'StatusOperasi', sortable: false, width: '150px' },
{ title: 'Actions', key: 'actions', sortable: false, width: '120px' }
];
+125 -16
View File
@@ -1,10 +1,12 @@
<script setup lang="ts">
import TableAntrian from '@/components/pendaftaran/TableAntrian.vue';
import { getAntrianOperasi } from '~/services/antrean';
import { getAntrianOperasi, deleteAntrianOperasi } from '~/services/antrean';
import { statusOptions, STATUS } from '~/types/antrean';
import type { AntreanOperasi } from '~/types/antrean';
import { Icon } from '@iconify/vue';
import ModalPendaftaran from '@/components/pendaftaran/ModalPendaftaran.vue';
import ModalDetailPendaftaran from '@/components/pendaftaran/ModalDetailPendaftaran.vue';
import ModalUpdateStatus from '@/components/pendaftaran/ModalUpdateStatus.vue';
const route = useRoute();
const idKategori = route.params.id as string;
@@ -22,8 +24,23 @@ const totalItems = ref(0);
// Modal state
const showModal = ref(false);
const showEditModal = ref(false);
const showDetailModal = ref(false);
const showUpdateStatusModal = ref(false);
const selectedId = ref<string | number | null>(null);
const selectedIdForEdit = ref<string | number | null>(null);
const selectedIdForStatus = ref<string | number | null>(null);
// Snackbar state
const snackbar = ref(false);
const snackbarMessage = ref('');
const snackbarColor = ref('success');
const showSnackbar = (message: string, color: string = 'success') => {
snackbarMessage.value = message;
snackbarColor.value = color;
snackbar.value = true;
};
definePageMeta({
middleware: 'auth',
@@ -102,30 +119,70 @@ const headers = [
{ title: 'No Rekam Medis', key: 'NoRekamMedis', sortable: false, width: '180px' },
{ title: 'Nama Pasien', key: 'NamaPasien', sortable: false },
{ title: 'Jenis kelamin', key: 'JenisKelamin', sortable: false },
{ title : 'Spesialis', key: 'Spesialis', sortable: false },
{ title : 'Sub Spesialis', key: 'SubSpesialis', sortable: false },
{ title: 'Status', key: 'StatusOperasi', sortable: false, width: '150px' },
{ title: 'Actions', key: 'actions', sortable: false, width: '120px' }
];
const actions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
// Function to get actions based on item status
const getActionsForItem = (item: AntreanOperasi) => {
const allActions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-clipboard-check', color: 'success', tooltip: 'Update Status', event: 'updateStatus' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
const handleView = (item: unknown) => {
const data = item as any;
// If status is Selesai or Batal, only show View action
if (item.StatusOperasi === STATUS.SELESAI || item.StatusOperasi === STATUS.BATAL) {
return allActions.filter(action => action.event === 'view');
}
// For other statuses (Belum, Tunda), show all actions
return allActions;
};
const handleView = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedId.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showDetailModal.value = true;
};
const handleEdit = (item: unknown) => {
console.log('Edit', item);
const handleEdit = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForEdit.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showEditModal.value = true;
};
const handleDelete = (item: unknown) => {
const handleUpdateStatus = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForStatus.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showUpdateStatusModal.value = true;
};
const handleDelete = async (item: unknown) => {
const data = item as AntreanOperasi;
if(confirm('Apakah Anda yakin ingin menghapus data ini?')) {
console.log('Delete', item);
try {
const response = await deleteAntrianOperasi(data.id);
if (response.success) {
showSnackbar('Data berhasil dihapus.', 'success');
fetchData(); // Refresh the table after deletion
} else {
showSnackbar(response.message || 'Gagal menghapus data', 'error');
}
} catch (error: any) {
console.error('Error deleting antrian operasi:', error);
showSnackbar(error.response?.data?.message || 'Gagal menghapus data', 'error');
}
}
};
@@ -140,6 +197,14 @@ const handleItemsPerPageUpdate = (items: unknown) => {
const handleModalSuccess = () => {
fetchData(); // Refresh the table after successful submission
};
const handleEditModalSuccess = () => {
fetchData(); // Refresh the table after successful edit
};
const handleUpdateStatusSuccess = () => {
fetchData(); // Refresh the table after status update
};
</script>
<template>
<v-row>
@@ -161,14 +226,23 @@ const handleModalSuccess = () => {
</v-btn>
</div>
<TableAntrian :headers="headers" :actions="actions" :items="antreanList" :server-side="true"
:total-items="totalItems" :current-page="currentPage" :items-per-page="itemsPerPage"
:loading="loading" min-width="1500px"
<TableAntrian
:headers="headers"
:items="antreanList"
:get-actions="getActionsForItem"
:server-side="true"
:total-items="totalItems"
:current-page="currentPage"
:items-per-page="itemsPerPage"
:loading="loading"
min-width="1500px"
@view="handleView"
@edit="handleEdit"
@updateStatus="handleUpdateStatus"
@delete="handleDelete"
@update:page="handlePageUpdate"
@update:itemsPerPage="handleItemsPerPageUpdate">
@update:itemsPerPage="handleItemsPerPageUpdate"
>
<template #item.TglDaftar="{ item }">
{{ new Date(item.TglDaftar).toLocaleDateString('id-ID', {
year: 'numeric', month: 'short',
@@ -180,6 +254,24 @@ const handleModalSuccess = () => {
</v-col>
</v-row>
<!-- Snackbar for notifications -->
<v-snackbar
v-model="snackbar"
:color="snackbarColor"
:timeout="3000"
location="top"
>
{{ snackbarMessage }}
<template #actions>
<v-btn
variant="text"
@click="snackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar>
<!-- Modal Pendaftaran -->
<ModalPendaftaran
v-model="showModal"
@@ -188,10 +280,27 @@ const handleModalSuccess = () => {
@success="handleModalSuccess"
/>
<!-- Modal Edit Pendaftaran -->
<ModalPendaftaran
v-if="selectedIdForEdit"
v-model="showEditModal"
mode="edit"
:id="selectedIdForEdit"
@success="handleEditModalSuccess"
/>
<!-- Modal Detail Pendaftaran -->
<ModalDetailPendaftaran
v-if="selectedId"
v-model="showDetailModal"
:id="selectedId"
/>
<!-- Modal Update Status -->
<ModalUpdateStatus
v-if="selectedIdForStatus"
v-model="showUpdateStatusModal"
:id="selectedIdForStatus"
@success="handleUpdateStatusSuccess"
/>
</template>
+115 -13
View File
@@ -1,10 +1,12 @@
<script setup lang="ts">
import TableAntrian from '@/components/pendaftaran/TableAntrian.vue';
import { getAntrianOperasi } from '~/services/antrean';
import { getAntrianOperasi, deleteAntrianOperasi } from '~/services/antrean';
import { statusOptions, STATUS } from '~/types/antrean';
import type { AntreanOperasi } from '~/types/antrean';
import { Icon } from '@iconify/vue';
import ModalPendaftaran from '@/components/pendaftaran/ModalPendaftaran.vue';
import ModalDetailPendaftaran from '@/components/pendaftaran/ModalDetailPendaftaran.vue';
import ModalUpdateStatus from '@/components/pendaftaran/ModalUpdateStatus.vue';
const route = useRoute();
const kodeSpesialis = route.params.kode as string;
@@ -21,8 +23,23 @@ const totalItems = ref(0);
// Modal state
const showModal = ref(false);
const showEditModal = ref(false);
const showDetailModal = ref(false);
const showUpdateStatusModal = ref(false);
const selectedId = ref<string | number | null>(null);
const selectedIdForEdit = ref<string | number | null>(null);
const selectedIdForStatus = ref<string | number | null>(null);
// Snackbar state
const snackbar = ref(false);
const snackbarMessage = ref('');
const snackbarColor = ref('success');
const showSnackbar = (message: string, color: string = 'success') => {
snackbarMessage.value = message;
snackbarColor.value = color;
snackbar.value = true;
};
definePageMeta({
middleware: 'auth',
@@ -100,29 +117,70 @@ const headers = [
{ title: 'No Rekam Medis', key: 'NoRekamMedis', sortable: false, width: '180px' },
{ title: 'Nama Pasien', key: 'NamaPasien', sortable: false },
{ title: 'Jenis kelamin', key: 'JenisKelamin', sortable: false },
{ title : 'Kategori', key: 'Kategori', sortable: false },
{ title : 'Spesialis', key: 'Spesialis', sortable: false },
{ title : 'Sub Spesialis', key: 'SubSpesialis', sortable: false },
{ title: 'Status', key: 'StatusOperasi', sortable: false, width: '150px' },
{ title: 'Actions', key: 'actions', sortable: false, width: '120px' }
];
const actions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
// Function to get actions based on item status
const getActionsForItem = (item: AntreanOperasi) => {
const allActions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-clipboard-check', color: 'success', tooltip: 'Update Status', event: 'updateStatus' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
const handleView = (item: unknown) => {
const data = item as any;
// If status is Selesai or Batal, only show View action
if (item.StatusOperasi === STATUS.SELESAI || item.StatusOperasi === STATUS.BATAL) {
return allActions.filter(action => action.event === 'view');
}
// For other statuses (Belum, Tunda), show all actions
return allActions;
};
const handleView = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedId.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showDetailModal.value = true;
};
const handleEdit = (item: unknown) => {
console.log('Edit', item);
const handleEdit = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForEdit.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showEditModal.value = true;
};
const handleDelete = (item: unknown) => {
const handleUpdateStatus = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForStatus.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showUpdateStatusModal.value = true;
};
const handleDelete = async (item: unknown) => {
const data = item as AntreanOperasi;
if(confirm('Apakah Anda yakin ingin menghapus data ini?')) {
console.log('Delete', item);
try {
const response = await deleteAntrianOperasi(data.id);
if (response.success) {
showSnackbar('Data berhasil dihapus.', 'success');
fetchData(); // Refresh the table after deletion
} else {
showSnackbar(response.message || 'Gagal menghapus data', 'error');
}
} catch (error: any) {
console.error('Error deleting antrian operasi:', error);
showSnackbar(error.response?.data?.message || 'Gagal menghapus data', 'error');
}
}
};
@@ -137,6 +195,14 @@ const handleItemsPerPageUpdate = (items: unknown) => {
const handleModalSuccess = () => {
fetchData();
};
const handleEditModalSuccess = () => {
fetchData(); // Refresh the table after successful edit
};
const handleUpdateStatusSuccess = () => {
fetchData(); // Refresh the table after status update
};
</script>
<template>
@@ -161,8 +227,8 @@ const handleModalSuccess = () => {
<TableAntrian
:headers="headers"
:actions="actions"
:items="antreanList"
:get-actions="getActionsForItem"
:server-side="true"
:total-items="totalItems"
:current-page="currentPage"
@@ -171,6 +237,7 @@ const handleModalSuccess = () => {
min-width="1500px"
@view="handleView"
@edit="handleEdit"
@updateStatus="handleUpdateStatus"
@delete="handleDelete"
@update:page="handlePageUpdate"
@update:itemsPerPage="handleItemsPerPageUpdate"
@@ -186,6 +253,24 @@ const handleModalSuccess = () => {
</v-col>
</v-row>
<!-- Snackbar for notifications -->
<v-snackbar
v-model="snackbar"
:color="snackbarColor"
:timeout="3000"
location="top"
>
{{ snackbarMessage }}
<template #actions>
<v-btn
variant="text"
@click="snackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar>
<!-- Modal Pendaftaran -->
<ModalPendaftaran
v-model="showModal"
@@ -194,10 +279,27 @@ const handleModalSuccess = () => {
@success="handleModalSuccess"
/>
<!-- Modal Edit Pendaftaran -->
<ModalPendaftaran
v-if="selectedIdForEdit"
v-model="showEditModal"
mode="edit"
:id="selectedIdForEdit"
@success="handleEditModalSuccess"
/>
<!-- Modal Detail Pendaftaran -->
<ModalDetailPendaftaran
v-if="selectedId"
v-model="showDetailModal"
:id="selectedId"
/>
<!-- Modal Update Status -->
<ModalUpdateStatus
v-if="selectedIdForStatus"
v-model="showUpdateStatusModal"
:id="selectedIdForStatus"
@success="handleUpdateStatusSuccess"
/>
</template>
+115 -13
View File
@@ -1,10 +1,12 @@
<script setup lang="ts">
import TableAntrian from '@/components/pendaftaran/TableAntrian.vue';
import { getAntrianOperasi } from '~/services/antrean';
import { getAntrianOperasi, deleteAntrianOperasi } from '~/services/antrean';
import { statusOptions, STATUS } from '~/types/antrean';
import type { AntreanOperasi } from '~/types/antrean';
import { Icon } from '@iconify/vue';
import ModalPendaftaran from '@/components/pendaftaran/ModalPendaftaran.vue';
import ModalDetailPendaftaran from '@/components/pendaftaran/ModalDetailPendaftaran.vue';
import ModalUpdateStatus from '@/components/pendaftaran/ModalUpdateStatus.vue';
const route = useRoute();
const kodeSubSpesialis = route.params.kode as string;
@@ -22,8 +24,23 @@ const totalItems = ref(0);
// Modal state
const showModal = ref(false);
const showEditModal = ref(false);
const showDetailModal = ref(false);
const showUpdateStatusModal = ref(false);
const selectedId = ref<string | number | null>(null);
const selectedIdForEdit = ref<string | number | null>(null);
const selectedIdForStatus = ref<string | number | null>(null);
// Snackbar state
const snackbar = ref(false);
const snackbarMessage = ref('');
const snackbarColor = ref('success');
const showSnackbar = (message: string, color: string = 'success') => {
snackbarMessage.value = message;
snackbarColor.value = color;
snackbar.value = true;
};
definePageMeta({
middleware: 'auth',
@@ -100,29 +117,70 @@ const headers = [
{ title: 'No Rekam Medis', key: 'NoRekamMedis', sortable: false, width: '180px' },
{ title: 'Nama Pasien', key: 'NamaPasien', sortable: false },
{ title: 'Jenis kelamin', key: 'JenisKelamin', sortable: false },
{ title : 'Kategori', key: 'Kategori', sortable: false },
{ title : 'Spesialis', key: 'Spesialis', sortable: false },
{ title : 'Sub Spesialis', key: 'SubSpesialis', sortable: false },
{ title: 'Status', key: 'StatusOperasi', sortable: false, width: '150px' },
{ title: 'Actions', key: 'actions', sortable: false, width: '120px' }
];
const actions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
// Function to get actions based on item status
const getActionsForItem = (item: AntreanOperasi) => {
const allActions = [
{ icon: 'mdi-eye', color: 'info', tooltip: 'View', event: 'view' },
{ icon: 'mdi-pencil', color: 'primary', tooltip: 'Edit', event: 'edit' },
{ icon: 'mdi-clipboard-check', color: 'success', tooltip: 'Update Status', event: 'updateStatus' },
{ icon: 'mdi-delete', color: 'error', tooltip: 'Delete', event: 'delete' }
];
const handleView = (item: unknown) => {
const data = item as any;
// If status is Selesai or Batal, only show View action
if (item.StatusOperasi === STATUS.SELESAI || item.StatusOperasi === STATUS.BATAL) {
return allActions.filter(action => action.event === 'view');
}
// For other statuses (Belum, Tunda), show all actions
return allActions;
};
const handleView = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedId.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showDetailModal.value = true;
};
const handleEdit = (item: unknown) => {
console.log('Edit', item);
const handleEdit = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForEdit.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showEditModal.value = true;
};
const handleDelete = (item: unknown) => {
const handleUpdateStatus = async (item: unknown) => {
const data = item as AntreanOperasi;
selectedIdForStatus.value = data.id;
// Wait for DOM update before opening modal
await nextTick();
showUpdateStatusModal.value = true;
};
const handleDelete = async (item: unknown) => {
const data = item as AntreanOperasi;
if(confirm('Apakah Anda yakin ingin menghapus data ini?')) {
console.log('Delete', item);
try {
const response = await deleteAntrianOperasi(data.id);
if (response.success) {
showSnackbar('Data berhasil dihapus.', 'success');
fetchData(); // Refresh the table after deletion
} else {
showSnackbar(response.message || 'Gagal menghapus data', 'error');
}
} catch (error: any) {
console.error('Error deleting antrian operasi:', error);
showSnackbar(error.response?.data?.message || 'Gagal menghapus data', 'error');
}
}
};
@@ -138,6 +196,14 @@ const handleModalSuccess = () => {
fetchData();
};
const handleEditModalSuccess = () => {
fetchData(); // Refresh the table after successful edit
};
const handleUpdateStatusSuccess = () => {
fetchData(); // Refresh the table after status update
};
</script>
<template>
@@ -162,8 +228,8 @@ const handleModalSuccess = () => {
<TableAntrian
:headers="headers"
:actions="actions"
:items="antreanList"
:get-actions="getActionsForItem"
:server-side="true"
:total-items="totalItems"
:current-page="currentPage"
@@ -172,6 +238,7 @@ const handleModalSuccess = () => {
min-width="1500px"
@view="handleView"
@edit="handleEdit"
@updateStatus="handleUpdateStatus"
@delete="handleDelete"
@update:page="handlePageUpdate"
@update:itemsPerPage="handleItemsPerPageUpdate"
@@ -187,6 +254,24 @@ const handleModalSuccess = () => {
</v-col>
</v-row>
<!-- Snackbar for notifications -->
<v-snackbar
v-model="snackbar"
:color="snackbarColor"
:timeout="3000"
location="top"
>
{{ snackbarMessage }}
<template #actions>
<v-btn
variant="text"
@click="snackbar = false"
>
Close
</v-btn>
</template>
</v-snackbar>
<!-- Modal Pendaftaran -->
<ModalPendaftaran
v-model="showModal"
@@ -196,10 +281,27 @@ const handleModalSuccess = () => {
@success="handleModalSuccess"
/>
<!-- Modal Edit Pendaftaran -->
<ModalPendaftaran
v-if="selectedIdForEdit"
v-model="showEditModal"
mode="edit"
:id="selectedIdForEdit"
@success="handleEditModalSuccess"
/>
<!-- Modal Detail Pendaftaran -->
<ModalDetailPendaftaran
v-if="selectedId"
v-model="showDetailModal"
:id="selectedId"
/>
<!-- Modal Update Status -->
<ModalUpdateStatus
v-if="selectedIdForStatus"
v-model="showUpdateStatusModal"
:id="selectedIdForStatus"
@success="handleUpdateStatusSuccess"
/>
</template>