Done permohonan temujanji with BE
This commit is contained in:
parent
254b6334af
commit
7b1e5bbc13
@ -782,7 +782,24 @@ watch(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div v-else class="table-wrapper p-4 text-center">
|
<div v-else class="table-wrapper p-4">
|
||||||
<p class="text-[rgb(var(--text-color))]">No data found</p>
|
<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>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -81,6 +81,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- Barang Section -->
|
<!-- Barang Section -->
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<h3 class="mb-2">Senarai Barang</h3>
|
<h3 class="mb-2">Senarai Barang</h3>
|
||||||
<table
|
<table
|
||||||
@ -97,7 +98,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(barang, index) in barangList" :key="index">
|
<tr v-for="(barang, index) in barangList" :key="index">
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
{{ barang.jenisBarang }}
|
{{ getJenisBarangLabel(barang.jenisBarangDetail) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
{{ barang.kuantitiBarang }}
|
{{ barang.kuantitiBarang }}
|
||||||
@ -165,23 +166,11 @@
|
|||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="flex justify-end gap-2 mt-4">
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
<rs-button type="button" @click="navigateBack" variant="danger"
|
<rs-button @click="navigateBack" variant="danger">Kembali</rs-button>
|
||||||
>Kembali</rs-button
|
<rs-button @click.prevent="simpan" variant="primary"
|
||||||
>
|
|
||||||
<rs-button
|
|
||||||
type="button"
|
|
||||||
btn-type="submit"
|
|
||||||
@click="simpan"
|
|
||||||
variant="primary"
|
|
||||||
>Simpan</rs-button
|
>Simpan</rs-button
|
||||||
>
|
>
|
||||||
<rs-button
|
<rs-button btn-type="submit" variant="success">Hantar</rs-button>
|
||||||
type="submit"
|
|
||||||
btn-type="submit"
|
|
||||||
:disabled="!isFormValid"
|
|
||||||
variant="success"
|
|
||||||
>Hantar</rs-button
|
|
||||||
>
|
|
||||||
</div>
|
</div>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -203,10 +192,11 @@
|
|||||||
#default="{ state: formState }"
|
#default="{ state: formState }"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="select"
|
||||||
name="jenisBarang"
|
name="jenisBarangDetail"
|
||||||
label="Jenis Barang"
|
label="Jenis Barang"
|
||||||
v-model="currentBarang.jenisBarang"
|
v-model="currentBarang.jenisBarangDetail"
|
||||||
|
:options="jenisBarangDetailOptions"
|
||||||
validation="required"
|
validation="required"
|
||||||
:validation-messages="{
|
:validation-messages="{
|
||||||
required: 'Jenis Barang diperlukan',
|
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
|
<FormKit
|
||||||
type="select"
|
type="select"
|
||||||
name="jenisBarangSiber"
|
name="jenisBarangSiber"
|
||||||
@ -295,9 +273,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, watch } from "vue";
|
const { $swal } = useNuxtApp();
|
||||||
import { useRouter } from "vue-router";
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
const namaPemohon = ref("");
|
const namaPemohon = ref("");
|
||||||
@ -317,44 +293,50 @@ const slotMasa = ref("");
|
|||||||
// State for single checkbox
|
// State for single checkbox
|
||||||
const isPenghantarSameAsPemohon = ref(false);
|
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) => {
|
watch(isPenghantarSameAsPemohon, (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
// Copy values from Pemohon fields to Penghantar fields
|
|
||||||
namaPenghantar.value = namaPemohon.value;
|
namaPenghantar.value = namaPemohon.value;
|
||||||
pangkatPenghantar.value = pangkatPemohon.value;
|
pangkatPenghantar.value = pangkatPemohon.value;
|
||||||
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
||||||
} else {
|
} else {
|
||||||
// Clear Penghantar fields when unchecked
|
|
||||||
namaPenghantar.value = "";
|
namaPenghantar.value = "";
|
||||||
pangkatPenghantar.value = "";
|
pangkatPenghantar.value = "";
|
||||||
noPegawaiPenghantar.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 = () => {
|
const navigateBack = () => {
|
||||||
router.back();
|
router.back();
|
||||||
};
|
};
|
||||||
@ -362,11 +344,10 @@ const navigateBack = () => {
|
|||||||
const openBarangModal = () => {
|
const openBarangModal = () => {
|
||||||
editingBarangIndex.value = null;
|
editingBarangIndex.value = null;
|
||||||
currentBarang.value = {
|
currentBarang.value = {
|
||||||
jenisBarang: "",
|
jenisBarangDetail: "",
|
||||||
tandaBarang: "",
|
tandaBarang: "",
|
||||||
keadaanBarang: "",
|
keadaanBarang: "",
|
||||||
kuantitiBarang: 1,
|
kuantitiBarang: 1,
|
||||||
jenisBarangDetail: "",
|
|
||||||
jenisBarangSiber: "",
|
jenisBarangSiber: "",
|
||||||
};
|
};
|
||||||
isBarangModalOpen.value = true;
|
isBarangModalOpen.value = true;
|
||||||
@ -415,15 +396,11 @@ const isFormValid = () => {
|
|||||||
(field) => field.value !== "" && field.value !== 0
|
(field) => field.value !== "" && field.value !== 0
|
||||||
);
|
);
|
||||||
|
|
||||||
const areBarangFieldsValid = barangList.value.every((barang) =>
|
// const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||||
Object.values(barang).every((value) => value !== "" && value !== 0)
|
// Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||||
);
|
// );
|
||||||
|
|
||||||
return (
|
return areRequiredFieldsFilled && barangList.value.length > 0;
|
||||||
areRequiredFieldsFilled &&
|
|
||||||
areBarangFieldsValid &&
|
|
||||||
barangList.value.length > 0
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const simpan = async () => {
|
const simpan = async () => {
|
||||||
@ -446,17 +423,12 @@ const submitData = async (isDraft) => {
|
|||||||
namaPemohon: namaPemohon.value,
|
namaPemohon: namaPemohon.value,
|
||||||
pangkatPemohon: pangkatPemohon.value,
|
pangkatPemohon: pangkatPemohon.value,
|
||||||
noPegawaiPemohon: noPegawaiPemohon.value,
|
noPegawaiPemohon: noPegawaiPemohon.value,
|
||||||
namaPenghantar: isPenghantarSameAsPemohon.value
|
namaPenghantar: namaPenghantar.value,
|
||||||
? null
|
pangkatPenghantar: pangkatPenghantar.value,
|
||||||
: namaPenghantar.value,
|
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
||||||
pangkatPenghantar: isPenghantarSameAsPemohon.value
|
isPenghantarSameAsPemohon: isPenghantarSameAsPemohon.value,
|
||||||
? null
|
|
||||||
: pangkatPenghantar.value,
|
|
||||||
noPegawaiPenghantar: isPenghantarSameAsPemohon.value
|
|
||||||
? null
|
|
||||||
: noPegawaiPenghantar.value,
|
|
||||||
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
||||||
bilangan: bilangan.value,
|
bilangan: bilangan.value.toString(),
|
||||||
barangList: barangList.value,
|
barangList: barangList.value,
|
||||||
noKertasSiasatan: noKertasSiasatan.value,
|
noKertasSiasatan: noKertasSiasatan.value,
|
||||||
noLaporanPolis: noLaporanPolis.value,
|
noLaporanPolis: noLaporanPolis.value,
|
||||||
@ -466,16 +438,25 @@ const submitData = async (isDraft) => {
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
$swal.fire({
|
if (response.statusCode === 200) {
|
||||||
|
await $swal.fire({
|
||||||
title: "Berjaya!",
|
title: "Berjaya!",
|
||||||
text: response.message,
|
text: response.message,
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
});
|
});
|
||||||
|
|
||||||
// Redirect user based on action (draft or submission)
|
// Redirect to senarai page after successful submission
|
||||||
if (!isDraft) {
|
if (!isDraft) {
|
||||||
router.push("/permohonan-temujanji/success");
|
router.push('/permohonan-temujanji/senarai');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$swal.fire({
|
||||||
|
title: "Ralat!",
|
||||||
|
text: response.message,
|
||||||
|
icon: "error",
|
||||||
|
confirmButtonText: "OK",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
$swal.fire({
|
$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>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<div class="flex justify-between items-center">
|
<div class="flex justify-between items-center">
|
||||||
<h1>Permohonan Baru</h1>
|
<h1>Kemaskini Permohonan</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<rs-card class="mt-4 p-4">
|
<rs-card class="mt-4 p-4">
|
||||||
@ -97,7 +97,7 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr v-for="(barang, index) in barangList" :key="index">
|
<tr v-for="(barang, index) in barangList" :key="index">
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
{{ barang.jenisBarang }}
|
{{ getJenisBarangLabel(barang.jenisBarangDetail) }}
|
||||||
</td>
|
</td>
|
||||||
<td class="border border-gray-300 p-2">
|
<td class="border border-gray-300 p-2">
|
||||||
{{ barang.kuantitiBarang }}
|
{{ barang.kuantitiBarang }}
|
||||||
@ -160,23 +160,11 @@
|
|||||||
|
|
||||||
<!-- Action Buttons -->
|
<!-- Action Buttons -->
|
||||||
<div class="flex justify-end gap-2 mt-4">
|
<div class="flex justify-end gap-2 mt-4">
|
||||||
<rs-button type="button" @click="navigateBack" variant="danger"
|
<rs-button @click="navigateBack" variant="danger">Kembali</rs-button>
|
||||||
>Kembali</rs-button
|
<rs-button @click.prevent="simpan" variant="primary"
|
||||||
>
|
>Kemaskini</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 btn-type="submit" variant="success">Hantar</rs-button>
|
||||||
</div>
|
</div>
|
||||||
</FormKit>
|
</FormKit>
|
||||||
</rs-card>
|
</rs-card>
|
||||||
@ -198,10 +186,11 @@
|
|||||||
#default="{ state: formState }"
|
#default="{ state: formState }"
|
||||||
>
|
>
|
||||||
<FormKit
|
<FormKit
|
||||||
type="text"
|
type="select"
|
||||||
name="jenisBarang"
|
name="jenisBarangDetail"
|
||||||
label="Jenis Barang"
|
label="Jenis Barang"
|
||||||
v-model="currentBarang.jenisBarang"
|
v-model="currentBarang.jenisBarangDetail"
|
||||||
|
:options="jenisBarangDetailOptions"
|
||||||
validation="required"
|
validation="required"
|
||||||
:validation-messages="{
|
:validation-messages="{
|
||||||
required: 'Jenis Barang diperlukan',
|
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
|
<FormKit
|
||||||
type="select"
|
type="select"
|
||||||
name="jenisBarangSiber"
|
name="jenisBarangSiber"
|
||||||
@ -290,15 +267,13 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, onMounted, watch } from "vue";
|
const { $swal } = useNuxtApp();
|
||||||
import { useRouter, useRoute } from "vue-router";
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
|
|
||||||
const noSiri = ref(route.params.noSiri);
|
const noSiri = ref(route.params.noSiri);
|
||||||
|
|
||||||
// Form data
|
// Form data refs
|
||||||
const namaPemohon = ref("");
|
const namaPemohon = ref("");
|
||||||
const pangkatPemohon = ref("");
|
const pangkatPemohon = ref("");
|
||||||
const noPegawaiPemohon = ref("");
|
const noPegawaiPemohon = ref("");
|
||||||
@ -316,58 +291,100 @@ const slotMasa = ref("");
|
|||||||
// State for single checkbox
|
// State for single checkbox
|
||||||
const isPenghantarSameAsPemohon = ref(false);
|
const isPenghantarSameAsPemohon = ref(false);
|
||||||
|
|
||||||
const jenisBarangDetailOptions = [
|
// Remove computed properties and add watch
|
||||||
"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
|
|
||||||
watch(isPenghantarSameAsPemohon, (newValue) => {
|
watch(isPenghantarSameAsPemohon, (newValue) => {
|
||||||
if (newValue) {
|
if (newValue) {
|
||||||
// Copy values from Pemohon fields to Penghantar fields
|
|
||||||
namaPenghantar.value = namaPemohon.value;
|
namaPenghantar.value = namaPemohon.value;
|
||||||
pangkatPenghantar.value = pangkatPemohon.value;
|
pangkatPenghantar.value = pangkatPemohon.value;
|
||||||
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
noPegawaiPenghantar.value = noPegawaiPemohon.value;
|
||||||
} else {
|
} else {
|
||||||
// Clear Penghantar fields when unchecked
|
|
||||||
namaPenghantar.value = "";
|
namaPenghantar.value = "";
|
||||||
pangkatPenghantar.value = "";
|
pangkatPenghantar.value = "";
|
||||||
noPegawaiPenghantar.value = "";
|
noPegawaiPenghantar.value = "";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const navigateBack = () => {
|
// Update these to be reactive refs
|
||||||
router.back();
|
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
|
// Barang modal functions
|
||||||
const openBarangModal = () => {
|
const openBarangModal = () => {
|
||||||
editingBarangIndex.value = null;
|
editingBarangIndex.value = null;
|
||||||
currentBarang.value = {
|
currentBarang.value = {
|
||||||
jenisBarang: "",
|
jenisBarangDetail: "",
|
||||||
tandaBarang: "",
|
tandaBarang: "",
|
||||||
keadaanBarang: "",
|
keadaanBarang: "",
|
||||||
kuantitiBarang: 1,
|
kuantitiBarang: 1,
|
||||||
jenisBarangDetail: "",
|
|
||||||
jenisBarangSiber: "",
|
jenisBarangSiber: "",
|
||||||
};
|
};
|
||||||
isBarangModalOpen.value = true;
|
isBarangModalOpen.value = true;
|
||||||
@ -396,7 +413,10 @@ const saveBarangModal = () => {
|
|||||||
isBarangModalOpen.value = false;
|
isBarangModalOpen.value = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate the form
|
const navigateBack = () => {
|
||||||
|
router.back();
|
||||||
|
};
|
||||||
|
|
||||||
const isFormValid = () => {
|
const isFormValid = () => {
|
||||||
const requiredFields = [
|
const requiredFields = [
|
||||||
namaPemohon,
|
namaPemohon,
|
||||||
@ -417,96 +437,73 @@ const isFormValid = () => {
|
|||||||
(field) => field.value !== "" && field.value !== 0
|
(field) => field.value !== "" && field.value !== 0
|
||||||
);
|
);
|
||||||
|
|
||||||
const areBarangFieldsValid = barangList.value.every((barang) =>
|
// const areBarangFieldsValid = barangList.value.every((barang) =>
|
||||||
Object.values(barang).every((value) => value !== "" && value !== 0)
|
// Object.values(barang).every((value) => value !== "" && value !== 0)
|
||||||
);
|
// );
|
||||||
|
|
||||||
return (
|
return areRequiredFieldsFilled && barangList.value.length > 0;
|
||||||
areRequiredFieldsFilled &&
|
|
||||||
areBarangFieldsValid &&
|
|
||||||
barangList.value.length > 0
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const simpan = () => {
|
const simpan = async () => {
|
||||||
$swal
|
const isDraft = true; // Simpan means saving as draft
|
||||||
.fire({
|
await submitData(isDraft);
|
||||||
title: "Adakah anda pasti?",
|
};
|
||||||
text: "Borang boleh dikemas kini selepas di simpan.",
|
|
||||||
icon: "warning",
|
const submitForm = async () => {
|
||||||
showCancelButton: true,
|
const isDraft = false; // Submit means final submission
|
||||||
confirmButtonText: "Ya, Hantar",
|
await submitData(isDraft);
|
||||||
cancelButtonText: "Batal",
|
};
|
||||||
})
|
|
||||||
.then((result) => {
|
const submitData = async (isDraft) => {
|
||||||
if (result.isConfirmed) {
|
if (isFormValid()) {
|
||||||
// Handle form submission
|
try {
|
||||||
console.log({
|
const response = await $fetch(`/api/permohonan/${noSiri.value}`, {
|
||||||
|
method: "PUT",
|
||||||
|
body: {
|
||||||
namaPemohon: namaPemohon.value,
|
namaPemohon: namaPemohon.value,
|
||||||
pangkatPemohon: pangkatPemohon.value,
|
pangkatPemohon: pangkatPemohon.value,
|
||||||
noPegawaiPemohon: noPegawaiPemohon.value,
|
noPegawaiPemohon: noPegawaiPemohon.value,
|
||||||
namaPenghantar: namaPenghantar.value,
|
namaPenghantar: namaPenghantar.value,
|
||||||
pangkatPenghantar: pangkatPenghantar.value,
|
pangkatPenghantar: pangkatPenghantar.value,
|
||||||
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
noPegawaiPenghantar: noPegawaiPenghantar.value,
|
||||||
|
isPenghantarSameAsPemohon: isPenghantarSameAsPemohon.value,
|
||||||
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
ringkasanKenyataanKes: ringkasanKenyataanKes.value,
|
||||||
bilangan: bilangan.value,
|
bilangan: bilangan.value.toString(),
|
||||||
barangList: barangList.value,
|
barangList: barangList.value,
|
||||||
noKertasSiasatan: noKertasSiasatan.value,
|
noKertasSiasatan: noKertasSiasatan.value,
|
||||||
noLaporanPolis: noLaporanPolis.value,
|
noLaporanPolis: noLaporanPolis.value,
|
||||||
tarikhTemujanji: tarikhTemujanji.value,
|
tarikhTemujanji: tarikhTemujanji.value,
|
||||||
slotMasa: slotMasa.value,
|
slotMasa: slotMasa.value,
|
||||||
|
isDraft: isDraft,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// Show success message
|
if (response.statusCode === 200) {
|
||||||
$swal.fire({
|
await $swal.fire({
|
||||||
title: "Berjaya!",
|
title: "Berjaya!",
|
||||||
text: "Borang telah berjaya disimpan.",
|
text: isDraft
|
||||||
|
? "Permohonan telah berjaya disimpan sebagai draf."
|
||||||
|
: "Permohonan telah berjaya dikemaskini.",
|
||||||
icon: "success",
|
icon: "success",
|
||||||
confirmButtonText: "OK",
|
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",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
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 {
|
} else {
|
||||||
// Show error message
|
|
||||||
$swal.fire({
|
$swal.fire({
|
||||||
title: "Ralat!",
|
title: "Ralat!",
|
||||||
text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.",
|
text: "Sila isi semua medan yang diperlukan dan tambah sekurang-kurangnya satu barang.",
|
||||||
@ -514,82 +511,14 @@ const submitForm = () => {
|
|||||||
confirmButtonText: "OK",
|
confirmButtonText: "OK",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Function to generate sample data
|
const getJenisBarangLabel = (value) => {
|
||||||
function generateSampleData(noSiri) {
|
const option = jenisBarangDetailOptions.value.find(
|
||||||
const randomNumber = (min, max) =>
|
(opt) => opt.__original === value
|
||||||
Math.floor(Math.random() * (max - min + 1) + min);
|
);
|
||||||
const randomChoice = (arr) => arr[Math.floor(Math.random() * arr.length)];
|
return option ? option.label : value;
|
||||||
|
|
||||||
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();
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
|
@ -60,7 +60,13 @@
|
|||||||
|
|
||||||
<!-- Actions for each permohonan -->
|
<!-- Actions for each permohonan -->
|
||||||
<template v-slot:butiran="data">
|
<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 -->
|
<!-- Button to navigate to the "Kemaskini" page for the selected permohonan -->
|
||||||
<rs-button
|
<rs-button
|
||||||
@click="kemaskini(data.value.noSiri)"
|
@click="kemaskini(data.value.noSiri)"
|
||||||
@ -84,9 +90,13 @@
|
|||||||
</rs-button>
|
</rs-button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- If permohonan has been confirmed -->
|
<!-- If permohonan has been confirmed or submitted -->
|
||||||
<div v-else>
|
<div v-else>
|
||||||
<span>Permohonan telah disahkan</span>
|
<span>{{
|
||||||
|
data.value.status === "Sah"
|
||||||
|
? "Permohonan telah disahkan"
|
||||||
|
: "Permohonan telah dihantar"
|
||||||
|
}}</span>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
</rs-table>
|
</rs-table>
|
||||||
@ -140,7 +150,6 @@ const hapus = async (noSiri) => {
|
|||||||
|
|
||||||
if (confirmation.isConfirmed) {
|
if (confirmation.isConfirmed) {
|
||||||
try {
|
try {
|
||||||
// Call API to delete the permohonan
|
|
||||||
const response = await $fetch(`/api/permohonan/${noSiri}`, {
|
const response = await $fetch(`/api/permohonan/${noSiri}`, {
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
});
|
});
|
||||||
|
@ -89,18 +89,21 @@ model permohonan {
|
|||||||
penghantarID Int?
|
penghantarID Int?
|
||||||
status_permohonan String @db.VarChar(255)
|
status_permohonan String @db.VarChar(255)
|
||||||
ringkasan_kenyataan_kes String? @db.Text
|
ringkasan_kenyataan_kes String? @db.Text
|
||||||
bilangan String? @db.VarChar(255)
|
bilangan Int?
|
||||||
jenis_barang Int?
|
jenis_barang Int?
|
||||||
tanda_barang String? @db.VarChar(255)
|
tanda_barang String? @db.VarChar(255)
|
||||||
keadaan_barang String? @db.VarChar(255)
|
keadaan_barang String? @db.VarChar(255)
|
||||||
kuantiti_barang Int?
|
kuantiti_barang Int?
|
||||||
jenis_barang_details String? @db.Text
|
jenis_barang_details String? @db.Text
|
||||||
no_laporan_polis String? @db.VarChar(255)
|
no_laporan_polis String? @db.VarChar(255)
|
||||||
|
no_kertas_siasatan String? @db.VarChar(255)
|
||||||
tarikh_temujanji DateTime? @db.DateTime(0)
|
tarikh_temujanji DateTime? @db.DateTime(0)
|
||||||
create_at DateTime @db.DateTime(0)
|
slot_masa DateTime? @db.Time(0)
|
||||||
penghantar penghantar? @relation(fields: [penghantarID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_1")
|
create_at DateTime? @db.DateTime(0)
|
||||||
pemohon pemohon? @relation(fields: [pemohonID], references: [id], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_2")
|
modified_at DateTime? @db.DateTime(0)
|
||||||
lookup lookup? @relation(fields: [jenis_barang], references: [lookupID], onDelete: NoAction, onUpdate: NoAction, map: "permohonan_ibfk_3")
|
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_assign_forensik permohonan_assign_forensik[]
|
||||||
permohonan_jenis_barang permohonan_jenis_barang[]
|
permohonan_jenis_barang permohonan_jenis_barang[]
|
||||||
permohonan_penerimaan permohonan_penerimaan[]
|
permohonan_penerimaan permohonan_penerimaan[]
|
||||||
@ -279,10 +282,10 @@ model report {
|
|||||||
dapatan Int?
|
dapatan Int?
|
||||||
create_at DateTime? @db.DateTime(0)
|
create_at DateTime? @db.DateTime(0)
|
||||||
create_by Int
|
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")
|
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_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")
|
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[]
|
report_doc_support report_doc_support[]
|
||||||
|
|
||||||
@@index([dapatan], map: "dapatan")
|
@@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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
data: lookups,
|
data: transformedLookups,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
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) => {
|
export default defineEventHandler(async (event) => {
|
||||||
const body = await readBody(event);
|
const body = await readBody(event);
|
||||||
|
const { userID } = event.context.user;
|
||||||
|
|
||||||
// Step 1: Validation for required fields
|
const {
|
||||||
if (
|
namaPemohon,
|
||||||
!body.namaPemohon ||
|
pangkatPemohon,
|
||||||
!body.tarikhTemujanji ||
|
noPegawaiPemohon,
|
||||||
!body.noLaporanPolis ||
|
namaPenghantar,
|
||||||
!body.slotMasa ||
|
pangkatPenghantar,
|
||||||
!body.barangList.length
|
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 {
|
return {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
message:
|
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 currentDate = new Date();
|
||||||
const appointmentDate = new Date(body.tarikhTemujanji);
|
|
||||||
if (appointmentDate <= currentDate) {
|
if (appointmentDate <= currentDate) {
|
||||||
return {
|
return {
|
||||||
statusCode: 400,
|
statusCode: 400,
|
||||||
@ -29,102 +54,150 @@ export default defineEventHandler(async (event) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Generate Case ID
|
// 3. Check if the session is expired
|
||||||
const caseID = generateCaseID();
|
const sessionExpired = false; // Implement session logic here
|
||||||
|
if (sessionExpired) {
|
||||||
// Step 4: Determine status (Draft or Submitted)
|
|
||||||
const status = body.isDraft ? "Permohonan Draf" : "Permohonan Dihantar";
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Step 5: Insert data into the 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,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
// 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 });
|
|
||||||
|
|
||||||
// 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 {
|
return {
|
||||||
statusCode: 200,
|
statusCode: 401,
|
||||||
message: "Rekod telah berjaya disimpan. (Status CMN-S001)",
|
|
||||||
data: { newPermohonan, newReport },
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
statusCode: 200,
|
|
||||||
message:
|
message:
|
||||||
"Permohonan pemeriksaan forensik telah dihantar. (Status FOR-S001)",
|
"Sesi aktif pengguna berada dalam sistem telah tamat. (Ralat CMN-E005)",
|
||||||
data: { newPermohonan, newReport },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
// Insert into `permohonan` table
|
||||||
|
const newPermohonan = await prisma.permohonan.create({
|
||||||
|
data: {
|
||||||
|
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(),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 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(),
|
||||||
|
// },
|
||||||
|
// });
|
||||||
|
|
||||||
|
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) {
|
} catch (error) {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
return {
|
return {
|
||||||
statusCode: 500,
|
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
|
// Helper function to generate case reference number
|
||||||
function generateCaseID() {
|
const generateCaseReferenceID = () => {
|
||||||
const date = new Date();
|
const now = new Date();
|
||||||
const year = date.getFullYear();
|
const year = now.getFullYear().toString();
|
||||||
const month = (date.getMonth() + 1).toString().padStart(2, "0");
|
const month = String(now.getMonth() + 1).padStart(2, "0"); // JS month is zero-indexed
|
||||||
const day = date.getDate().toString().padStart(2, "0");
|
const day = String(now.getDate()).padStart(2, "0");
|
||||||
const uniqueSerialNumber = Math.floor(Math.random() * 1000000)
|
const uniqueSerial = String(Math.floor(Math.random() * 1000000)).padStart(
|
||||||
.toString()
|
6,
|
||||||
.padStart(6, "0");
|
"0"
|
||||||
return `${year}${month}${day}-${uniqueSerialNumber}`;
|
);
|
||||||
}
|
return `${year}${month}${day}-${uniqueSerial}`;
|
||||||
|
};
|
||||||
|
|
||||||
// Pseudocode function for sending email
|
const sendEmail = async ({ to, subject, body }) => {
|
||||||
function sendEmail(data) {
|
console.log("Sending email to", to);
|
||||||
// Email logic goes here
|
return true;
|
||||||
console.log("Email sent with the following data: ", data);
|
};
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user