Done permohonan temujanji with BE
This commit is contained in:
parent
254b6334af
commit
7b1e5bbc13
@ -782,7 +782,24 @@ watch(
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="table-wrapper p-4 text-center">
|
||||
<p class="text-[rgb(var(--text-color))]">No data found</p>
|
||||
<div v-else class="table-wrapper p-4">
|
||||
<div
|
||||
class="border border-[rgb(var(--border-color))] rounded-lg overflow-hidden"
|
||||
>
|
||||
<div
|
||||
class="bg-[rgb(var(--bg-2))] p-4 border-b border-[rgb(var(--border-color))]"
|
||||
>
|
||||
<h3 class="text-lg font-semibold text-[rgb(var(--text-color))]"></h3>
|
||||
</div>
|
||||
<div class="p-8 text-center">
|
||||
<Icon name="mdi:table-off" class="text-gray-300 mb-4" size="48px" />
|
||||
<p class="text-[rgb(var(--text-color))] text-lg font-medium">
|
||||
Tiada data
|
||||
</p>
|
||||
<p class="text-gray-500 mt-2">
|
||||
Tiada entri untuk dipaparkan pada masa ini.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -81,6 +81,7 @@
|
||||
/>
|
||||
|
||||
<!-- Barang Section -->
|
||||
|
||||
<div class="mb-4">
|
||||
<h3 class="mb-2">Senarai Barang</h3>
|
||||
<table
|
||||
@ -97,7 +98,7 @@
|
||||
<tbody>
|
||||
<tr v-for="(barang, index) in barangList" :key="index">
|
||||
<td class="border border-gray-300 p-2">
|
||||
{{ barang.jenisBarang }}
|
||||
{{ getJenisBarangLabel(barang.jenisBarangDetail) }}
|
||||
</td>
|
||||
<td class="border border-gray-300 p-2">
|
||||
{{ barang.kuantitiBarang }}
|
||||
@ -165,23 +166,11 @@
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<rs-button type="button" @click="navigateBack" variant="danger"
|
||||
>Kembali</rs-button
|
||||
>
|
||||
<rs-button
|
||||
type="button"
|
||||
btn-type="submit"
|
||||
@click="simpan"
|
||||
variant="primary"
|
||||
<rs-button @click="navigateBack" variant="danger">Kembali</rs-button>
|
||||
<rs-button @click.prevent="simpan" variant="primary"
|
||||
>Simpan</rs-button
|
||||
>
|
||||
<rs-button
|
||||
type="submit"
|
||||
btn-type="submit"
|
||||
:disabled="!isFormValid"
|
||||
variant="success"
|
||||
>Hantar</rs-button
|
||||
>
|
||||
<rs-button btn-type="submit" variant="success">Hantar</rs-button>
|
||||
</div>
|
||||
</FormKit>
|
||||
</rs-card>
|
||||
@ -203,10 +192,11 @@
|
||||
#default="{ state: formState }"
|
||||
>
|
||||
<FormKit
|
||||
type="text"
|
||||
name="jenisBarang"
|
||||
type="select"
|
||||
name="jenisBarangDetail"
|
||||
label="Jenis Barang"
|
||||
v-model="currentBarang.jenisBarang"
|
||||
v-model="currentBarang.jenisBarangDetail"
|
||||
:options="jenisBarangDetailOptions"
|
||||
validation="required"
|
||||
:validation-messages="{
|
||||
required: 'Jenis Barang diperlukan',
|
||||
@ -248,18 +238,6 @@
|
||||
}"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
type="select"
|
||||
name="jenisBarangDetail"
|
||||
label="Jenis Barang Detail"
|
||||
v-model="currentBarang.jenisBarangDetail"
|
||||
:options="jenisBarangDetailOptions"
|
||||
validation="required"
|
||||
:validation-messages="{
|
||||
required: 'Jenis Barang Detail diperlukan',
|
||||
}"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
type="select"
|
||||
name="jenisBarangSiber"
|
||||
@ -295,9 +273,7 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, watch } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
|
||||
const { $swal } = useNuxtApp();
|
||||
const router = useRouter();
|
||||
|
||||
const namaPemohon = ref("");
|
||||
@ -317,44 +293,50 @@ const slotMasa = ref("");
|
||||
// State for single checkbox
|
||||
const isPenghantarSameAsPemohon = ref(false);
|
||||
|
||||
const isBarangModalOpen = ref(false);
|
||||
const editingBarangIndex = ref(null);
|
||||
const currentBarang = ref({
|
||||
jenisBarang: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangDetail: "",
|
||||
jenisBarangSiber: "",
|
||||
});
|
||||
|
||||
const jenisBarangDetailOptions = [
|
||||
"PASPORT",
|
||||
"MALPASS",
|
||||
"CAP KESELAMATAN",
|
||||
"CAP JARI",
|
||||
"PEMERIKSAAN",
|
||||
"I-KAD",
|
||||
"LAIN-LAIN",
|
||||
];
|
||||
|
||||
const jenisBarangSiberOptions = ["SIBER", "TULISAN TANGAN"];
|
||||
|
||||
// Watcher to update Penghantar fields when the single checkbox is checked
|
||||
watch(isPenghantarSameAsPemohon, (newValue) => {
|
||||
if (newValue) {
|
||||
// Copy values from Pemohon fields to Penghantar fields
|
||||
namaPenghantar.value = namaPemohon.value;
|
||||
pangkatPenghantar.value = pangkatPemohon.value;
|
||||
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
||||
} else {
|
||||
// Clear Penghantar fields when unchecked
|
||||
namaPenghantar.value = "";
|
||||
pangkatPenghantar.value = "";
|
||||
noPegawaiPenghantar.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
const isBarangModalOpen = ref(false);
|
||||
const editingBarangIndex = ref(null);
|
||||
const currentBarang = ref({
|
||||
jenisBarangDetail: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangSiber: "",
|
||||
});
|
||||
|
||||
const jenisBarangDetailOptions = ref([]);
|
||||
const jenisBarangSiberOptions = ref([]);
|
||||
|
||||
// Fetch lookup data from API
|
||||
const fetchLookupData = async (type) => {
|
||||
try {
|
||||
const response = await $fetch(`/api/lookup?type=${type}`);
|
||||
if (response.statusCode === 200) {
|
||||
// Data return with value and label
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error fetching ${type} lookup data:`, error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
jenisBarangDetailOptions.value = await fetchLookupData("jenis_barang");
|
||||
jenisBarangSiberOptions.value = await fetchLookupData("jenis_barang_siber");
|
||||
});
|
||||
|
||||
const navigateBack = () => {
|
||||
router.back();
|
||||
};
|
||||
@ -362,11 +344,10 @@ const navigateBack = () => {
|
||||
const openBarangModal = () => {
|
||||
editingBarangIndex.value = null;
|
||||
currentBarang.value = {
|
||||
jenisBarang: "",
|
||||
jenisBarangDetail: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangDetail: "",
|
||||
jenisBarangSiber: "",
|
||||
};
|
||||
isBarangModalOpen.value = true;
|
||||
@ -415,15 +396,11 @@ const isFormValid = () => {
|
||||
(field) => field.value !== "" && field.value !== 0
|
||||
);
|
||||
|
||||
const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||
Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||
);
|
||||
// const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||
// Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||
// );
|
||||
|
||||
return (
|
||||
areRequiredFieldsFilled &&
|
||||
areBarangFieldsValid &&
|
||||
barangList.value.length > 0
|
||||
);
|
||||
return areRequiredFieldsFilled && barangList.value.length > 0;
|
||||
};
|
||||
|
||||
const simpan = async () => {
|
||||
@ -446,17 +423,12 @@ const submitData = async (isDraft) => {
|
||||
namaPemohon: namaPemohon.value,
|
||||
pangkatPemohon: pangkatPemohon.value,
|
||||
noPegawaiPemohon: noPegawaiPemohon.value,
|
||||
namaPenghantar: isPenghantarSameAsPemohon.value
|
||||
? null
|
||||
: namaPenghantar.value,
|
||||
pangkatPenghantar: isPenghantarSameAsPemohon.value
|
||||
? null
|
||||
: pangkatPenghantar.value,
|
||||
noPegawaiPenghantar: isPenghantarSameAsPemohon.value
|
||||
? null
|
||||
: noPegawaiPenghantar.value,
|
||||
namaPenghantar: namaPenghantar.value,
|
||||
pangkatPenghantar: pangkatPenghantar.value,
|
||||
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
||||
isPenghantarSameAsPemohon: isPenghantarSameAsPemohon.value,
|
||||
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
||||
bilangan: bilangan.value,
|
||||
bilangan: bilangan.value.toString(),
|
||||
barangList: barangList.value,
|
||||
noKertasSiasatan: noKertasSiasatan.value,
|
||||
noLaporanPolis: noLaporanPolis.value,
|
||||
@ -466,16 +438,25 @@ const submitData = async (isDraft) => {
|
||||
},
|
||||
});
|
||||
|
||||
$swal.fire({
|
||||
title: "Berjaya!",
|
||||
text: response.message,
|
||||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
|
||||
// Redirect user based on action (draft or submission)
|
||||
if (!isDraft) {
|
||||
router.push("/permohonan-temujanji/success");
|
||||
if (response.statusCode === 200) {
|
||||
await $swal.fire({
|
||||
title: "Berjaya!",
|
||||
text: response.message,
|
||||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
|
||||
// Redirect to senarai page after successful submission
|
||||
if (!isDraft) {
|
||||
router.push('/permohonan-temujanji/senarai');
|
||||
}
|
||||
} else {
|
||||
$swal.fire({
|
||||
title: "Ralat!",
|
||||
text: response.message,
|
||||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
$swal.fire({
|
||||
@ -495,7 +476,12 @@ const submitData = async (isDraft) => {
|
||||
}
|
||||
};
|
||||
|
||||
const { $swal } = useNuxtApp();
|
||||
const getJenisBarangLabel = (value) => {
|
||||
const option = jenisBarangDetailOptions.value.find(
|
||||
(opt) => opt.__original === value
|
||||
);
|
||||
return option ? option.label : value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div>
|
||||
<div class="flex justify-between items-center">
|
||||
<h1>Permohonan Baru</h1>
|
||||
<h1>Kemaskini Permohonan</h1>
|
||||
</div>
|
||||
|
||||
<rs-card class="mt-4 p-4">
|
||||
@ -97,7 +97,7 @@
|
||||
<tbody>
|
||||
<tr v-for="(barang, index) in barangList" :key="index">
|
||||
<td class="border border-gray-300 p-2">
|
||||
{{ barang.jenisBarang }}
|
||||
{{ getJenisBarangLabel(barang.jenisBarangDetail) }}
|
||||
</td>
|
||||
<td class="border border-gray-300 p-2">
|
||||
{{ barang.kuantitiBarang }}
|
||||
@ -160,23 +160,11 @@
|
||||
|
||||
<!-- Action Buttons -->
|
||||
<div class="flex justify-end gap-2 mt-4">
|
||||
<rs-button type="button" @click="navigateBack" variant="danger"
|
||||
>Kembali</rs-button
|
||||
>
|
||||
<rs-button
|
||||
type="button"
|
||||
@click="simpan"
|
||||
btn-type="submit"
|
||||
variant="primary"
|
||||
>Simpan</rs-button
|
||||
>
|
||||
<rs-button
|
||||
type="submit"
|
||||
@click="submitForm"
|
||||
btn-type="submit"
|
||||
variant="success"
|
||||
>Hantar</rs-button
|
||||
<rs-button @click="navigateBack" variant="danger">Kembali</rs-button>
|
||||
<rs-button @click.prevent="simpan" variant="primary"
|
||||
>Kemaskini</rs-button
|
||||
>
|
||||
<rs-button btn-type="submit" variant="success">Hantar</rs-button>
|
||||
</div>
|
||||
</FormKit>
|
||||
</rs-card>
|
||||
@ -198,10 +186,11 @@
|
||||
#default="{ state: formState }"
|
||||
>
|
||||
<FormKit
|
||||
type="text"
|
||||
name="jenisBarang"
|
||||
type="select"
|
||||
name="jenisBarangDetail"
|
||||
label="Jenis Barang"
|
||||
v-model="currentBarang.jenisBarang"
|
||||
v-model="currentBarang.jenisBarangDetail"
|
||||
:options="jenisBarangDetailOptions"
|
||||
validation="required"
|
||||
:validation-messages="{
|
||||
required: 'Jenis Barang diperlukan',
|
||||
@ -243,18 +232,6 @@
|
||||
}"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
type="select"
|
||||
name="jenisBarangDetail"
|
||||
label="Jenis Barang Detail"
|
||||
v-model="currentBarang.jenisBarangDetail"
|
||||
:options="jenisBarangDetailOptions"
|
||||
validation="required"
|
||||
:validation-messages="{
|
||||
required: 'Jenis Barang Detail diperlukan',
|
||||
}"
|
||||
/>
|
||||
|
||||
<FormKit
|
||||
type="select"
|
||||
name="jenisBarangSiber"
|
||||
@ -290,15 +267,13 @@
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { useRouter, useRoute } from "vue-router";
|
||||
|
||||
const { $swal } = useNuxtApp();
|
||||
const router = useRouter();
|
||||
const route = useRoute();
|
||||
|
||||
const noSiri = ref(route.params.noSiri);
|
||||
|
||||
// Form data
|
||||
// Form data refs
|
||||
const namaPemohon = ref("");
|
||||
const pangkatPemohon = ref("");
|
||||
const noPegawaiPemohon = ref("");
|
||||
@ -316,58 +291,100 @@ const slotMasa = ref("");
|
||||
// State for single checkbox
|
||||
const isPenghantarSameAsPemohon = ref(false);
|
||||
|
||||
const jenisBarangDetailOptions = [
|
||||
"PASPORT",
|
||||
"MALPASS",
|
||||
"CAP KESELAMATAN",
|
||||
"CAP JARI",
|
||||
"PEMERIKSAAN",
|
||||
"I-KAD",
|
||||
"LAIN-LAIN",
|
||||
];
|
||||
|
||||
const jenisBarangSiberOptions = ["SIBER", "TULISAN TANGAN"];
|
||||
|
||||
// Barang modal state
|
||||
const isBarangModalOpen = ref(false);
|
||||
const editingBarangIndex = ref(null);
|
||||
const currentBarang = ref({
|
||||
jenisBarang: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangDetail: "",
|
||||
jenisBarangSiber: "",
|
||||
});
|
||||
|
||||
// Watcher to update Penghantar fields when the checkbox is checked
|
||||
// Remove computed properties and add watch
|
||||
watch(isPenghantarSameAsPemohon, (newValue) => {
|
||||
if (newValue) {
|
||||
// Copy values from Pemohon fields to Penghantar fields
|
||||
namaPenghantar.value = namaPemohon.value;
|
||||
pangkatPenghantar.value = pangkatPemohon.value;
|
||||
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
||||
} else {
|
||||
// Clear Penghantar fields when unchecked
|
||||
namaPenghantar.value = "";
|
||||
pangkatPenghantar.value = "";
|
||||
noPegawaiPenghantar.value = "";
|
||||
}
|
||||
});
|
||||
|
||||
const navigateBack = () => {
|
||||
router.back();
|
||||
// Update these to be reactive refs
|
||||
const jenisBarangDetailOptions = ref([]);
|
||||
const jenisBarangSiberOptions = ref([]);
|
||||
|
||||
// Fetch lookup data from API
|
||||
const fetchLookupData = async (type) => {
|
||||
try {
|
||||
const response = await $fetch(`/api/lookup?type=${type}`);
|
||||
if (response.statusCode === 200) {
|
||||
// Data return with value and label
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Error fetching ${type} lookup data:`, error);
|
||||
return [];
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch existing data
|
||||
const fetchExistingData = async (noSiri) => {
|
||||
try {
|
||||
const response = await $fetch(`/api/permohonan/${noSiri}`);
|
||||
if (response.statusCode === 200) {
|
||||
return response.data;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error fetching existing data:", error);
|
||||
$swal.fire({
|
||||
title: "Ralat!",
|
||||
text: "Gagal mendapatkan data permohonan.",
|
||||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(async () => {
|
||||
const existingData = await fetchExistingData(noSiri.value);
|
||||
|
||||
if (existingData) {
|
||||
// Set the form values based on the existingData
|
||||
namaPemohon.value = existingData.namaPemohon;
|
||||
pangkatPemohon.value = existingData.pangkatPemohon;
|
||||
noPegawaiPemohon.value = existingData.noPegawaiPemohon;
|
||||
namaPenghantar.value = existingData.namaPenghantar;
|
||||
pangkatPenghantar.value = existingData.pangkatPenghantar;
|
||||
noPegawaiPenghantar.value = existingData.noPegawaiPenghantar;
|
||||
ringkasanKenyataanKes.value = existingData.ringkasanKenyataanKes;
|
||||
bilangan.value = existingData.bilangan;
|
||||
barangList.value = existingData.barangList;
|
||||
noKertasSiasatan.value = existingData.noKertasSiasatan;
|
||||
noLaporanPolis.value = existingData.noLaporanPolis;
|
||||
tarikhTemujanji.value = existingData.tarikhTemujanji;
|
||||
slotMasa.value = existingData.slotMasa;
|
||||
isPenghantarSameAsPemohon.value = existingData.isPenghantarSameAsPemohon;
|
||||
}
|
||||
|
||||
// Fetch lookup data
|
||||
jenisBarangDetailOptions.value = await fetchLookupData("jenis_barang");
|
||||
jenisBarangSiberOptions.value = await fetchLookupData("jenis_barang_siber");
|
||||
});
|
||||
|
||||
// Barang modal state
|
||||
const isBarangModalOpen = ref(false);
|
||||
const editingBarangIndex = ref(null);
|
||||
const currentBarang = ref({
|
||||
jenisBarangDetail: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangSiber: "",
|
||||
});
|
||||
|
||||
// Barang modal functions
|
||||
const openBarangModal = () => {
|
||||
editingBarangIndex.value = null;
|
||||
currentBarang.value = {
|
||||
jenisBarang: "",
|
||||
jenisBarangDetail: "",
|
||||
tandaBarang: "",
|
||||
keadaanBarang: "",
|
||||
kuantitiBarang: 1,
|
||||
jenisBarangDetail: "",
|
||||
jenisBarangSiber: "",
|
||||
};
|
||||
isBarangModalOpen.value = true;
|
||||
@ -396,7 +413,10 @@ const saveBarangModal = () => {
|
||||
isBarangModalOpen.value = false;
|
||||
};
|
||||
|
||||
// Validate the form
|
||||
const navigateBack = () => {
|
||||
router.back();
|
||||
};
|
||||
|
||||
const isFormValid = () => {
|
||||
const requiredFields = [
|
||||
namaPemohon,
|
||||
@ -417,179 +437,88 @@ const isFormValid = () => {
|
||||
(field) => field.value !== "" && field.value !== 0
|
||||
);
|
||||
|
||||
const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||
Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||
);
|
||||
// const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||
// Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||
// );
|
||||
|
||||
return (
|
||||
areRequiredFieldsFilled &&
|
||||
areBarangFieldsValid &&
|
||||
barangList.value.length > 0
|
||||
);
|
||||
return areRequiredFieldsFilled && barangList.value.length > 0;
|
||||
};
|
||||
|
||||
const simpan = () => {
|
||||
$swal
|
||||
.fire({
|
||||
title: "Adakah anda pasti?",
|
||||
text: "Borang boleh dikemas kini selepas di simpan.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Ya, Hantar",
|
||||
cancelButtonText: "Batal",
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
// Handle form submission
|
||||
console.log({
|
||||
const simpan = async () => {
|
||||
const isDraft = true; // Simpan means saving as draft
|
||||
await submitData(isDraft);
|
||||
};
|
||||
|
||||
const submitForm = async () => {
|
||||
const isDraft = false; // Submit means final submission
|
||||
await submitData(isDraft);
|
||||
};
|
||||
|
||||
const submitData = async (isDraft) => {
|
||||
if (isFormValid()) {
|
||||
try {
|
||||
const response = await $fetch(`/api/permohonan/${noSiri.value}`, {
|
||||
method: "PUT",
|
||||
body: {
|
||||
namaPemohon: namaPemohon.value,
|
||||
pangkatPemohon: pangkatPemohon.value,
|
||||
noPegawaiPemohon: noPegawaiPemohon.value,
|
||||
namaPenghantar: namaPenghantar.value,
|
||||
pangkatPenghantar: pangkatPenghantar.value,
|
||||
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
||||
isPenghantarSameAsPemohon: isPenghantarSameAsPemohon.value,
|
||||
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
||||
bilangan: bilangan.value,
|
||||
bilangan: bilangan.value.toString(),
|
||||
barangList: barangList.value,
|
||||
noKertasSiasatan: noKertasSiasatan.value,
|
||||
noLaporanPolis: noLaporanPolis.value,
|
||||
tarikhTemujanji: tarikhTemujanji.value,
|
||||
slotMasa: slotMasa.value,
|
||||
});
|
||||
isDraft: isDraft,
|
||||
},
|
||||
});
|
||||
|
||||
// Show success message
|
||||
$swal.fire({
|
||||
if (response.statusCode === 200) {
|
||||
await $swal.fire({
|
||||
title: "Berjaya!",
|
||||
text: "Borang telah berjaya disimpan.",
|
||||
text: isDraft
|
||||
? "Permohonan telah berjaya disimpan sebagai draf."
|
||||
: "Permohonan telah berjaya dikemaskini.",
|
||||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const submitForm = () => {
|
||||
$swal
|
||||
.fire({
|
||||
title: "Adakah anda pasti?",
|
||||
text: "Borang boleh dikemaskini selepas di simpan.",
|
||||
icon: "warning",
|
||||
showCancelButton: true,
|
||||
confirmButtonText: "Ya, Hantar",
|
||||
cancelButtonText: "Batal",
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.isConfirmed) {
|
||||
if (isFormValid()) {
|
||||
// Handle form submission
|
||||
console.log({
|
||||
namaPemohon: namaPemohon.value,
|
||||
pangkatPemohon: pangkatPemohon.value,
|
||||
noPegawaiPemohon: noPegawaiPemohon.value,
|
||||
namaPenghantar: namaPenghantar.value,
|
||||
pangkatPenghantar: pangkatPenghantar.value,
|
||||
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
||||
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
||||
bilangan: bilangan.value,
|
||||
barangList: barangList.value,
|
||||
noKertasSiasatan: noKertasSiasatan.value,
|
||||
noLaporanPolis: noLaporanPolis.value,
|
||||
tarikhTemujanji: tarikhTemujanji.value,
|
||||
slotMasa: slotMasa.value,
|
||||
});
|
||||
|
||||
// Show success message
|
||||
$swal.fire({
|
||||
title: "Berjaya!",
|
||||
text: "Borang telah berjaya dihantar.",
|
||||
icon: "success",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
} else {
|
||||
// Show error message
|
||||
$swal.fire({
|
||||
title: "Ralat!",
|
||||
text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.",
|
||||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
// Redirect to senarai page after successful submission
|
||||
if (!isDraft) {
|
||||
router.push("/permohonan-temujanji/senarai");
|
||||
}
|
||||
} else {
|
||||
throw new Error(response.message);
|
||||
}
|
||||
} catch (error) {
|
||||
$swal.fire({
|
||||
title: "Ralat!",
|
||||
text: error.message || "Gagal mengemaskini permohonan. Sila cuba lagi.",
|
||||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$swal.fire({
|
||||
title: "Ralat!",
|
||||
text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.",
|
||||
icon: "error",
|
||||
confirmButtonText: "OK",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Function to generate sample data
|
||||
function generateSampleData(noSiri) {
|
||||
const randomNumber = (min, max) =>
|
||||
Math.floor(Math.random() * (max - min + 1) + min);
|
||||
const randomChoice = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
||||
|
||||
const namaPemohon = [
|
||||
"Ali bin Abu",
|
||||
"Siti binti Ahmad",
|
||||
"Muthu a/l Rajan",
|
||||
"Lim Wei Ling",
|
||||
];
|
||||
const pangkat = ["Inspektor", "Sarjan", "Koperal", "Konstabel"];
|
||||
const jenisBarangOptions = [
|
||||
"Dokumen",
|
||||
"Peralatan Elektronik",
|
||||
"Senjata",
|
||||
"Dadah",
|
||||
"Barang Kemas",
|
||||
];
|
||||
const keadaanBarangOptions = ["Baik", "Sederhana", "Rosak"];
|
||||
|
||||
const generateBarang = () => ({
|
||||
jenisBarang: randomChoice(jenisBarangOptions),
|
||||
tandaBarang: `TB-${randomNumber(1000, 9999)}`,
|
||||
keadaanBarang: randomChoice(keadaanBarangOptions),
|
||||
kuantitiBarang: randomNumber(1, 10),
|
||||
jenisBarangDetail: randomChoice(jenisBarangDetailOptions),
|
||||
jenisBarangSiber: randomChoice(jenisBarangSiberOptions),
|
||||
});
|
||||
|
||||
return {
|
||||
noSiri: noSiri,
|
||||
namaPemohon: randomChoice(namaPemohon),
|
||||
pangkatPemohon: randomChoice(pangkat),
|
||||
noPegawaiPemohon: `PG${randomNumber(10000, 99999)}`,
|
||||
namaPenghantar: randomChoice(namaPemohon),
|
||||
pangkatPenghantar: randomChoice(pangkat),
|
||||
noPegawaiPenghantar: `PG${randomNumber(10000, 99999)}`,
|
||||
ringkasanKenyataanKes: `Kes ${noSiri}: Penemuan barang bukti dalam serbuan di lokasi ${randomChoice(
|
||||
["A", "B", "C", "D"]
|
||||
)}`,
|
||||
bilangan: randomNumber(1, 5),
|
||||
barangList: Array.from({ length: randomNumber(1, 3) }, generateBarang),
|
||||
noKertasSiasatan: `KS-${randomNumber(10000, 99999)}`,
|
||||
noLaporanPolis: `RPT-${randomNumber(100000, 999999)}`,
|
||||
tarikhTemujanji: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000)
|
||||
.toISOString()
|
||||
.split("T")[0], // 7 days from now
|
||||
slotMasa: `${randomNumber(9, 16)}:00`, // Random hour between 9 AM and 4 PM
|
||||
};
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
const sampleData = generateSampleData(noSiri.value);
|
||||
|
||||
namaPemohon.value = sampleData.namaPemohon;
|
||||
pangkatPemohon.value = sampleData.pangkatPemohon;
|
||||
noPegawaiPemohon.value = sampleData.noPegawaiPemohon;
|
||||
namaPenghantar.value = sampleData.namaPenghantar;
|
||||
pangkatPenghantar.value = sampleData.pangkatPenghantar;
|
||||
noPegawaiPenghantar.value = sampleData.noPegawaiPenghantar;
|
||||
ringkasanKenyataanKes.value = sampleData.ringkasanKenyataanKes;
|
||||
bilangan.value = sampleData.bilangan;
|
||||
barangList.value = sampleData.barangList;
|
||||
noKertasSiasatan.value = sampleData.noKertasSiasatan;
|
||||
noLaporanPolis.value = sampleData.noLaporanPolis;
|
||||
tarikhTemujanji.value = sampleData.tarikhTemujanji;
|
||||
slotMasa.value = sampleData.slotMasa;
|
||||
});
|
||||
|
||||
const { $swal } = useNuxtApp();
|
||||
const getJenisBarangLabel = (value) => {
|
||||
const option = jenisBarangDetailOptions.value.find(
|
||||
(opt) => opt.__original === value
|
||||
);
|
||||
return option ? option.label : value;
|
||||
};
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
@ -60,7 +60,13 @@
|
||||
|
||||
<!-- Actions for each permohonan -->
|
||||
<template v-slot:butiran="data">
|
||||
<div class="flex flex-wrap gap-2" v-if="data.value.status !== 'Sah'">
|
||||
<div
|
||||
class="flex flex-wrap gap-2"
|
||||
v-if="
|
||||
data.value.status !== 'Sah' &&
|
||||
data.value.status !== 'Permohonan Dihantar'
|
||||
"
|
||||
>
|
||||
<!-- Button to navigate to the "Kemaskini" page for the selected permohonan -->
|
||||
<rs-button
|
||||
@click="kemaskini(data.value.noSiri)"
|
||||
@ -84,9 +90,13 @@
|
||||
</rs-button>
|
||||
</div>
|
||||
|
||||
<!-- If permohonan has been confirmed -->
|
||||
<!-- If permohonan has been confirmed or submitted -->
|
||||
<div v-else>
|
||||
<span>Permohonan telah disahkan</span>
|
||||
<span>{{
|
||||
data.value.status === "Sah"
|
||||
? "Permohonan telah disahkan"
|
||||
: "Permohonan telah dihantar"
|
||||
}}</span>
|
||||
</div>
|
||||
</template>
|
||||
</rs-table>
|
||||
@ -140,7 +150,6 @@ const hapus = async (noSiri) => {
|
||||
|
||||
if (confirmation.isConfirmed) {
|
||||
try {
|
||||
// Call API to delete the permohonan
|
||||
const response = await $fetch(`/api/permohonan/${noSiri}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
|
@ -89,18 +89,21 @@ model permohonan {
|
||||
penghantarID Int?
|
||||
status_permohonan String @db.VarChar(255)
|
||||
ringkasan_kenyataan_kes String? @db.Text
|
||||
bilangan String? @db.VarChar(255)
|
||||
bilangan Int?
|
||||
jenis_barang Int?
|
||||
tanda_barang String? @db.VarChar(255)
|
||||
keadaan_barang String? @db.VarChar(255)
|
||||
kuantiti_barang Int?
|
||||
jenis_barang_details String? @db.Text
|
||||
no_laporan_polis String? @db.VarChar(255)
|
||||
no_kertas_siasatan String? @db.VarChar(255)
|
||||
tarikh_temujanji DateTime? @db.DateTime(0)
|
||||
create_at DateTime @db.DateTime(0)
|
||||
penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_1")
|
||||
pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_2")
|
||||
slot_masa DateTime? @db.Time(0)
|
||||
create_at DateTime? @db.DateTime(0)
|
||||
modified_at DateTime? @db.DateTime(0)
|
||||
lookup lookup? @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_3")
|
||||
pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "permohonan_ibfk_2")
|
||||
penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "permohonan_ibfk_1")
|
||||
permohonan_assign_forensik permohonan_assign_forensik[]
|
||||
permohonan_jenis_barang permohonan_jenis_barang[]
|
||||
permohonan_penerimaan permohonan_penerimaan[]
|
||||
@ -279,10 +282,10 @@ model report {
|
||||
dapatan Int?
|
||||
create_at DateTime? @db.DateTime(0)
|
||||
create_by Int
|
||||
permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_1")
|
||||
document document? @relation(fields: [gambarID], references: [documentID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_2")
|
||||
lookup_report_dapatanTolookup lookup? @relation("report_dapatanTolookup", fields: [dapatan], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_3")
|
||||
lookup_report_jenis_barangTolookup lookup @relation("report_jenis_barangTolookup", fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "report_ibfk_4")
|
||||
permohonan permohonan @relation(fields: [permohonanID], references: [id], onDelete: Cascade, onUpdate: Restrict, map: "report_ibfk_1")
|
||||
report_doc_support report_doc_support[]
|
||||
|
||||
@@index([dapatan], map: "dapatan")
|
||||
|
@ -21,9 +21,18 @@ export default defineEventHandler(async (event) => {
|
||||
},
|
||||
});
|
||||
|
||||
// Transform the lookups data to the required format
|
||||
const transformedLookups = [
|
||||
{ label: "", value: null }, // Add an empty option as the first item
|
||||
...lookups.map((lookup) => ({
|
||||
label: lookup.lookupValue,
|
||||
value: lookup.lookupID,
|
||||
})),
|
||||
];
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
data: lookups,
|
||||
data: transformedLookups,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
|
56
server/api/permohonan/[noSiri].delete.js
Normal file
56
server/api/permohonan/[noSiri].delete.js
Normal file
@ -0,0 +1,56 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { noSiri } = event.context.params; // Get the noSiri from the request parameters
|
||||
|
||||
try {
|
||||
// Find the permohonan by its `no_siri`
|
||||
const permohonan = await prisma.permohonan.findUnique({
|
||||
where: { no_siri: noSiri },
|
||||
});
|
||||
|
||||
if (!permohonan) {
|
||||
return {
|
||||
statusCode: 404,
|
||||
message: `Permohonan with noSiri ${noSiri} not found.`,
|
||||
};
|
||||
}
|
||||
|
||||
// Delete pemohonan
|
||||
await prisma.pemohon.delete({
|
||||
where: {
|
||||
id: permohonan.pemohonID,
|
||||
},
|
||||
});
|
||||
|
||||
// Delete penghantar
|
||||
await prisma.penghantar.delete({
|
||||
where: {
|
||||
id: permohonan.penghantarID,
|
||||
},
|
||||
});
|
||||
|
||||
// Delete report
|
||||
await prisma.report.deleteMany({
|
||||
where: {
|
||||
permohonanID: permohonan.id,
|
||||
},
|
||||
});
|
||||
|
||||
// Delete permohonan
|
||||
await prisma.permohonan.delete({
|
||||
where: {
|
||||
id: permohonan.id,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Permohonan and related data successfully deleted.",
|
||||
};
|
||||
} catch (error) {
|
||||
console.error("Error deleting permohonan:", error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Failed to delete permohonan. Please try again.",
|
||||
};
|
||||
}
|
||||
});
|
77
server/api/permohonan/[noSiri].get.js
Normal file
77
server/api/permohonan/[noSiri].get.js
Normal file
@ -0,0 +1,77 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
// Get the `noSiri` from the request parameters
|
||||
const { noSiri } = event.context.params;
|
||||
|
||||
try {
|
||||
// Fetch the permohonan by `no_siri` from the Prisma database
|
||||
const permohonan = await prisma.permohonan.findUnique({
|
||||
where: {
|
||||
no_siri: noSiri, // Unique identifier for permohonan
|
||||
},
|
||||
include: {
|
||||
// Include related fields if necessary
|
||||
pemohon: {
|
||||
select: {
|
||||
user: {
|
||||
select: {
|
||||
userFullName: true,
|
||||
},
|
||||
},
|
||||
pangkat_pemohon: true,
|
||||
no_pegawai_pemohon: true,
|
||||
},
|
||||
},
|
||||
penghantar: true,
|
||||
report: true, // Assuming 'report' is where the `barang` (items) are stored
|
||||
},
|
||||
});
|
||||
|
||||
// If no permohonan found, return a 404 response
|
||||
if (!permohonan) {
|
||||
return {
|
||||
statusCode: 404,
|
||||
message: `Permohonan with noSiri ${noSiri} not found`,
|
||||
};
|
||||
}
|
||||
|
||||
// Map and return the data as expected by the frontend
|
||||
return {
|
||||
statusCode: 200,
|
||||
data: {
|
||||
namaPemohon: permohonan.pemohon?.user?.userFullName || "", // Get namaPemohon from userID
|
||||
pangkatPemohon: permohonan.pemohon?.pangkat_pemohon || "",
|
||||
noPegawaiPemohon: permohonan.pemohon?.no_pegawai_pemohon || "",
|
||||
namaPenghantar: permohonan.penghantar?.nama_penghantar || "",
|
||||
pangkatPenghantar: permohonan.penghantar?.pangkat_penghantar || "",
|
||||
noPegawaiPenghantar: permohonan.penghantar?.no_pegawai_penghantar || "",
|
||||
ringkasanKenyataanKes: permohonan.ringkasan_kenyataan_kes || "",
|
||||
bilangan: permohonan.bilangan || 0,
|
||||
barangList: permohonan.report.map((barang) => ({
|
||||
jenisBarangDetail: barang.jenis_barang || "",
|
||||
tandaBarang: barang.tanda_barang || "",
|
||||
keadaanBarang: barang.keadaan_barang || "",
|
||||
kuantitiBarang: barang.kuantiti_barang || 0,
|
||||
})),
|
||||
noKertasSiasatan: permohonan.no_kertas_siasatan || "",
|
||||
noLaporanPolis: permohonan.no_laporan_polis || "",
|
||||
tarikhTemujanji:
|
||||
permohonan.tarikh_temujanji?.toISOString().split("T")[0] || "",
|
||||
slotMasa: permohonan.slot_masa
|
||||
? new Date(permohonan.slot_masa).toLocaleTimeString("en-US", {
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
hour12: false,
|
||||
})
|
||||
: "",
|
||||
isPenghantarSameAsPemohon: !permohonan.penghantar,
|
||||
},
|
||||
};
|
||||
} catch (error) {
|
||||
// Handle any unexpected errors
|
||||
console.error("Error fetching permohonan:", error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Something went wrong while fetching permohonan data",
|
||||
};
|
||||
}
|
||||
});
|
@ -1,27 +0,0 @@
|
||||
// File: server/api/permohonan/[noSiri].delete.js
|
||||
export default defineEventHandler(async (event) => {
|
||||
const { noSiri } = event.context.params;
|
||||
|
||||
if (!noSiri) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message: "noSiri is required.",
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
await prisma.permohonan.delete({
|
||||
where: { no_siri: noSiri },
|
||||
});
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Permohonan successfully deleted.",
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Failed to delete permohonan.",
|
||||
};
|
||||
}
|
||||
});
|
210
server/api/permohonan/[noSiri].put.js
Normal file
210
server/api/permohonan/[noSiri].put.js
Normal file
@ -0,0 +1,210 @@
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event);
|
||||
const { userID } = event.context.user;
|
||||
const { noSiri } = event.context.params; // Permohonan identifier from URL
|
||||
|
||||
const {
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
namaPenghantar,
|
||||
pangkatPenghantar,
|
||||
noPegawaiPenghantar,
|
||||
ringkasanKenyataanKes,
|
||||
isPenghantarSameAsPemohon,
|
||||
bilangan,
|
||||
barangList,
|
||||
noKertasSiasatan,
|
||||
noLaporanPolis,
|
||||
tarikhTemujanji,
|
||||
slotMasa,
|
||||
isDraft,
|
||||
} = body;
|
||||
|
||||
// 1. Mandatory fields validation
|
||||
const mandatoryFields = [
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
ringkasanKenyataanKes,
|
||||
bilangan,
|
||||
noKertasSiasatan,
|
||||
noLaporanPolis,
|
||||
tarikhTemujanji,
|
||||
slotMasa,
|
||||
...barangList,
|
||||
];
|
||||
|
||||
if (mandatoryFields.some((field) => !field || field === "")) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message:
|
||||
"Setiap medan mandatori yang bertanda * telah diisi. (Ralat CMN-E001)",
|
||||
};
|
||||
}
|
||||
|
||||
// 2. Validate date for the appointment
|
||||
const appointmentDate = new Date(tarikhTemujanji);
|
||||
const currentDate = new Date();
|
||||
|
||||
if (appointmentDate <= currentDate) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message:
|
||||
"Perlu memastikan tarikh janji temu yang dimasukkan adalah tarikh selepas tarikh semasa. (Ralat CMN-E002)",
|
||||
};
|
||||
}
|
||||
|
||||
// 3. Check if the session is expired
|
||||
const sessionExpired = false; // Implement session logic here
|
||||
if (sessionExpired) {
|
||||
return {
|
||||
statusCode: 401,
|
||||
message:
|
||||
"Sesi aktif pengguna berada dalam sistem telah tamat. (Ralat CMN-E005)",
|
||||
};
|
||||
}
|
||||
|
||||
// 4. Check for invalid symbols in text fields
|
||||
const hasInvalidSymbols = (text) => /[^a-zA-Z0-9\s]/.test(text); // Allow alphanumeric and spaces
|
||||
|
||||
const fieldsToCheck = [
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
...barangList.map((barang) => barang.tandaBarang),
|
||||
];
|
||||
|
||||
if (fieldsToCheck.some((field) => hasInvalidSymbols(field))) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message:
|
||||
"Perlu memastikan tiada penggunaan simbol dalam medan yang ditetapkan. (Ralat CMN-E011)",
|
||||
};
|
||||
}
|
||||
|
||||
// 5. Update the permohonan in the database
|
||||
let permohonanStatus = isDraft ? "Permohonan Draf" : "Permohonan Dihantar";
|
||||
|
||||
try {
|
||||
// Update the existing `permohonan` record
|
||||
const updatedPermohonan = await prisma.permohonan.update({
|
||||
where: {
|
||||
no_siri: noSiri,
|
||||
},
|
||||
data: {
|
||||
status_permohonan: permohonanStatus,
|
||||
pemohon: {
|
||||
update: {
|
||||
userID: userID,
|
||||
pangkat_pemohon: pangkatPemohon,
|
||||
no_pegawai_pemohon: noPegawaiPemohon,
|
||||
},
|
||||
},
|
||||
penghantar: isPenghantarSameAsPemohon
|
||||
? null
|
||||
: {
|
||||
update: {
|
||||
nama_penghantar: namaPenghantar,
|
||||
pangkat_penghantar: pangkatPenghantar,
|
||||
no_pegawai_penghantar: noPegawaiPenghantar,
|
||||
},
|
||||
},
|
||||
ringkasan_kenyataan_kes: ringkasanKenyataanKes,
|
||||
bilangan: parseInt(bilangan),
|
||||
penghantar_sama_dengan_pemohon: isPenghantarSameAsPemohon ? 1 : 0,
|
||||
no_kertas_siasatan: noKertasSiasatan,
|
||||
no_laporan_polis: noLaporanPolis,
|
||||
tarikh_temujanji: new Date(tarikhTemujanji),
|
||||
slot_masa: new Date(`1970-01-01T${slotMasa}`),
|
||||
modified_at: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Delete old barang and create new ones
|
||||
await prisma.report.deleteMany({
|
||||
where: { permohonanID: updatedPermohonan.id },
|
||||
});
|
||||
|
||||
for (const barang of barangList) {
|
||||
// await prisma.report.create({
|
||||
// data: {
|
||||
// permohonanID: updatedPermohonan.id,
|
||||
// jenis_barang: barang.jenisBarangDetail,
|
||||
// kuantiti_barang: barang.kuantitiBarang,
|
||||
// tanda_barang: barang.tandaBarang,
|
||||
// keadaan_barang: barang.keadaanBarang,
|
||||
// create_by: userID,
|
||||
// create_at: new Date(),
|
||||
// },
|
||||
// });
|
||||
await prisma.report.create({
|
||||
data: {
|
||||
permohonanID: updatedPermohonan.id,
|
||||
jenis_barang: barang.jenisBarangDetail,
|
||||
create_by: userID,
|
||||
create_at: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 6. Send confirmation email if not a draft
|
||||
if (!isDraft) {
|
||||
await sendEmail({
|
||||
to: [
|
||||
/* pemohon, pegawai_kaunter, ketua_bahagian */
|
||||
],
|
||||
subject: `Kemaskini Permohonan: ${noSiri}`,
|
||||
body: `
|
||||
Case ID: ${noSiri}
|
||||
Appointment Date: ${tarikhTemujanji}
|
||||
Time Slot: ${slotMasa}
|
||||
Barang: ${barangList
|
||||
.map(
|
||||
(barang) =>
|
||||
`${barang.tandaBarang} - ${barang.kuantitiBarang} units`
|
||||
)
|
||||
.join(", ")}
|
||||
Pemohon Details: ${namaPemohon} (${pangkatPemohon})
|
||||
${
|
||||
isPenghantarSameAsPemohon
|
||||
? ""
|
||||
: `Penghantar Details: ${namaPenghantar} (${pangkatPenghantar})`
|
||||
}
|
||||
Ringkasan Kenyataan Kes: ${ringkasanKenyataanKes}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: isDraft
|
||||
? "Rekod telah berjaya disimpan. (Status CMN-S001)"
|
||||
: "Permohonan pemeriksaan forensik telah dikemaskini. (Status FOR-S001)",
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Terdapat masalah. Silakan cuba lagi.",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to generate case reference number
|
||||
const generateCaseReferenceID = () => {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear().toString();
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0"); // JS month is zero-indexed
|
||||
const day = String(now.getDate()).padStart(2, "0");
|
||||
const uniqueSerial = String(Math.floor(Math.random() * 1000000)).padStart(
|
||||
6,
|
||||
"0"
|
||||
);
|
||||
return `${year}${month}${day}-${uniqueSerial}`;
|
||||
};
|
||||
|
||||
const sendEmail = async ({ to, subject, body }) => {
|
||||
console.log("Sending email to", to);
|
||||
return true;
|
||||
};
|
@ -1,16 +1,40 @@
|
||||
// File: server/api/permohonan/index.post.js
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const body = await readBody(event);
|
||||
const { userID } = event.context.user;
|
||||
|
||||
// Step 1: Validation for required fields
|
||||
if (
|
||||
!body.namaPemohon ||
|
||||
!body.tarikhTemujanji ||
|
||||
!body.noLaporanPolis ||
|
||||
!body.slotMasa ||
|
||||
!body.barangList.length
|
||||
) {
|
||||
const {
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
namaPenghantar,
|
||||
pangkatPenghantar,
|
||||
noPegawaiPenghantar,
|
||||
ringkasanKenyataanKes,
|
||||
isPenghantarSameAsPemohon,
|
||||
bilangan,
|
||||
barangList,
|
||||
noKertasSiasatan,
|
||||
noLaporanPolis,
|
||||
tarikhTemujanji,
|
||||
slotMasa,
|
||||
isDraft,
|
||||
} = body;
|
||||
|
||||
// 1. Mandatory fields validation
|
||||
const mandatoryFields = [
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
ringkasanKenyataanKes,
|
||||
bilangan,
|
||||
noKertasSiasatan,
|
||||
noLaporanPolis,
|
||||
tarikhTemujanji,
|
||||
slotMasa,
|
||||
...barangList,
|
||||
];
|
||||
|
||||
if (mandatoryFields.some((field) => !field || field === "")) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message:
|
||||
@ -18,9 +42,10 @@ export default defineEventHandler(async (event) => {
|
||||
};
|
||||
}
|
||||
|
||||
// Step 2: Validate appointment date must be in the future
|
||||
// 2. Validate date for the appointment
|
||||
const appointmentDate = new Date(tarikhTemujanji);
|
||||
const currentDate = new Date();
|
||||
const appointmentDate = new Date(body.tarikhTemujanji);
|
||||
|
||||
if (appointmentDate <= currentDate) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
@ -29,102 +54,150 @@ export default defineEventHandler(async (event) => {
|
||||
};
|
||||
}
|
||||
|
||||
// Step 3: Generate Case ID
|
||||
const caseID = generateCaseID();
|
||||
// 3. Check if the session is expired
|
||||
const sessionExpired = false; // Implement session logic here
|
||||
if (sessionExpired) {
|
||||
return {
|
||||
statusCode: 401,
|
||||
message:
|
||||
"Sesi aktif pengguna berada dalam sistem telah tamat. (Ralat CMN-E005)",
|
||||
};
|
||||
}
|
||||
|
||||
// Step 4: Determine status (Draft or Submitted)
|
||||
const status = body.isDraft ? "Permohonan Draf" : "Permohonan Dihantar";
|
||||
// 4. Check for invalid symbols in text fields
|
||||
const hasInvalidSymbols = (text) => /[^a-zA-Z0-9\s]/.test(text); // Allow alphanumeric and spaces
|
||||
|
||||
const fieldsToCheck = [
|
||||
namaPemohon,
|
||||
pangkatPemohon,
|
||||
noPegawaiPemohon,
|
||||
...barangList.map((barang) => barang.tandaBarang),
|
||||
];
|
||||
|
||||
if (fieldsToCheck.some((field) => hasInvalidSymbols(field))) {
|
||||
return {
|
||||
statusCode: 400,
|
||||
message:
|
||||
"Perlu memastikan tiada penggunaan simbol dalam medan yang ditetapkan. (Ralat CMN-E011)",
|
||||
};
|
||||
}
|
||||
|
||||
// 5. Insert data into the database
|
||||
const caseReferenceID = generateCaseReferenceID();
|
||||
let permohonanStatus = isDraft ? "Permohonan Draf" : "Permohonan Dihantar";
|
||||
|
||||
try {
|
||||
// Step 5: Insert data into the permohonan table
|
||||
// Insert into `permohonan` table
|
||||
const newPermohonan = await prisma.permohonan.create({
|
||||
data: {
|
||||
no_siri: caseID,
|
||||
pemohonID: body.pemohonID,
|
||||
penghantarID: body.penghantarID || null, // If same as pemohon, this can be null
|
||||
penghantar_sama_dengan_pemohon: body.penghantarSamaDenganPemohon
|
||||
? 1
|
||||
: 0,
|
||||
status_permohonan: status, // Draf or Dihantar
|
||||
ringkasan_kenyataan_kes: body.ringkasanKenyataanKes,
|
||||
bilangan: body.bilangan?.toString(),
|
||||
no_laporan_polis: body.noLaporanPolis,
|
||||
tarikh_temujanji: new Date(body.tarikhTemujanji),
|
||||
create_at: currentDate,
|
||||
no_siri: caseReferenceID,
|
||||
status_permohonan: permohonanStatus,
|
||||
pemohon: {
|
||||
create: {
|
||||
userID: userID, // Assuming the user is authenticated, replace with actual user ID
|
||||
pangkat_pemohon: pangkatPemohon,
|
||||
no_pegawai_pemohon: noPegawaiPemohon,
|
||||
},
|
||||
},
|
||||
penghantar: {
|
||||
create: {
|
||||
nama_penghantar: namaPenghantar,
|
||||
pangkat_penghantar: pangkatPenghantar,
|
||||
no_pegawai_penghantar: noPegawaiPenghantar,
|
||||
},
|
||||
},
|
||||
ringkasan_kenyataan_kes: ringkasanKenyataanKes,
|
||||
bilangan: parseInt(bilangan),
|
||||
penghantar_sama_dengan_pemohon: isPenghantarSameAsPemohon ? 1 : 0,
|
||||
no_kertas_siasatan: noKertasSiasatan,
|
||||
no_laporan_polis: noLaporanPolis,
|
||||
tarikh_temujanji: new Date(tarikhTemujanji),
|
||||
slot_masa: new Date(`1970-01-01T${slotMasa}`), // Convert slotMasa string to Time
|
||||
create_at: new Date(),
|
||||
},
|
||||
});
|
||||
|
||||
// Step 6: Insert `barang` details into the `permohonan_jenis_barang` table
|
||||
const barangList = body.barangList.map((barang) => ({
|
||||
permohonanID: newPermohonan.id, // Foreign key to permohonan
|
||||
jenis_barang: barang.jenisBarang, // Foreign key to lookup(jenis_barang)
|
||||
barang_status: "ACTIVE", // Static value for now
|
||||
}));
|
||||
await prisma.permohonan_jenis_barang.createMany({ data: barangList });
|
||||
// Insert related `report` and `document` data
|
||||
for (const barang of barangList) {
|
||||
// await prisma.report.create({
|
||||
// data: {
|
||||
// permohonanID: newPermohonan.id,
|
||||
// jenis_barang: barang.jenisBarangDetail,
|
||||
// kuantiti_barang: barang.kuantitiBarang,
|
||||
// tanda_barang: barang.tandaBarang,
|
||||
// keadaan_barang: barang.keadaanBarang,
|
||||
// create_by: userID,
|
||||
// create_at: new Date(),
|
||||
// },
|
||||
// });
|
||||
|
||||
// Step 7: Insert data into the `report` table
|
||||
const newReport = await prisma.report.create({
|
||||
data: {
|
||||
permohonanID: newPermohonan.id,
|
||||
jenis_barang: body.barangList[0].jenisBarang, // The first barang's jenis_barang
|
||||
peralatan: body.peralatan || null, // Optional, based on frontend input
|
||||
langkah_langkah: body.langkahLangkah || null, // Optional, based on frontend input
|
||||
gambarID: body.gambarID || null, // Optional document ID, if any
|
||||
ulasan: body.ulasan || null, // Optional notes
|
||||
dapatan: body.dapatan || null, // Optional foreign key lookup(dapatan)
|
||||
create_at: currentDate,
|
||||
create_by: body.userID, // The user who created the report
|
||||
},
|
||||
});
|
||||
|
||||
// Step 8: Send confirmation email (pseudocode)
|
||||
sendEmail({
|
||||
case_id: caseID,
|
||||
selected_appointment_date: body.tarikhTemujanji,
|
||||
time_slot: body.slotMasa,
|
||||
barang_list: body.barangList
|
||||
.map((barang) => barang.jenisBarang)
|
||||
.join(", "),
|
||||
});
|
||||
|
||||
// Step 9: Return response depending on the action (draft or submit)
|
||||
if (body.isDraft) {
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: "Rekod telah berjaya disimpan. (Status CMN-S001)",
|
||||
data: { newPermohonan, newReport },
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
statusCode: 200,
|
||||
message:
|
||||
"Permohonan pemeriksaan forensik telah dihantar. (Status FOR-S001)",
|
||||
data: { newPermohonan, newReport },
|
||||
};
|
||||
await prisma.report.create({
|
||||
data: {
|
||||
permohonanID: newPermohonan.id,
|
||||
jenis_barang: barang.jenisBarangDetail,
|
||||
create_by: userID,
|
||||
create_at: new Date(),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// 6. Send confirmation email
|
||||
if (!isDraft) {
|
||||
await sendEmail({
|
||||
to: [
|
||||
/* pemohon, pegawai_kaunter, ketua_bahagian */
|
||||
],
|
||||
subject: `Permohonan Baru: ${caseReferenceID}`,
|
||||
body: `
|
||||
Case ID: ${caseReferenceID}
|
||||
Appointment Date: ${tarikhTemujanji}
|
||||
Time Slot: ${slotMasa}
|
||||
Barang: ${barangList
|
||||
.map(
|
||||
(barang) =>
|
||||
`${barang.tandaBarang} - ${barang.kuantitiBarang} units`
|
||||
)
|
||||
.join(", ")}
|
||||
Pemohon Details: ${namaPemohon} (${pangkatPemohon})
|
||||
${
|
||||
isPenghantarSameAsPemohon
|
||||
? ""
|
||||
: `Penghantar Details: ${namaPenghantar} (${pangkatPenghantar})`
|
||||
}
|
||||
Ringkasan Kenyataan Kes: ${ringkasanKenyataanKes}
|
||||
`,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
statusCode: 200,
|
||||
message: isDraft
|
||||
? "Rekod telah berjaya disimpan. (Status CMN-S001)"
|
||||
: "Permohonan pemeriksaan forensik telah dihantar. (Status FOR-S001)",
|
||||
};
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
return {
|
||||
statusCode: 500,
|
||||
message: "Failed to create permohonan and report. Please try again.",
|
||||
message: "Terdapat masalah. Silakan cuba lagi.",
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
// Helper function to generate unique case ID
|
||||
function generateCaseID() {
|
||||
const date = new Date();
|
||||
const year = date.getFullYear();
|
||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
||||
const day = date.getDate().toString().padStart(2, "0");
|
||||
const uniqueSerialNumber = Math.floor(Math.random() * 1000000)
|
||||
.toString()
|
||||
.padStart(6, "0");
|
||||
return `${year}${month}${day}-${uniqueSerialNumber}`;
|
||||
}
|
||||
// Helper function to generate case reference number
|
||||
const generateCaseReferenceID = () => {
|
||||
const now = new Date();
|
||||
const year = now.getFullYear().toString();
|
||||
const month = String(now.getMonth() + 1).padStart(2, "0"); // JS month is zero-indexed
|
||||
const day = String(now.getDate()).padStart(2, "0");
|
||||
const uniqueSerial = String(Math.floor(Math.random() * 1000000)).padStart(
|
||||
6,
|
||||
"0"
|
||||
);
|
||||
return `${year}${month}${day}-${uniqueSerial}`;
|
||||
};
|
||||
|
||||
// Pseudocode function for sending email
|
||||
function sendEmail(data) {
|
||||
// Email logic goes here
|
||||
console.log("Email sent with the following data: ", data);
|
||||
}
|
||||
const sendEmail = async ({ to, subject, body }) => {
|
||||
console.log("Sending email to", to);
|
||||
return true;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user