624 lines
20 KiB
Vue
624 lines
20 KiB
Vue
<script setup lang="ts">
|
|
import { ref, watch } from "vue";
|
|
import { useQuasar } from "quasar";
|
|
|
|
import { useCounterMixin } from "@/stores/mixin";
|
|
import { calculateAge } from "@/utils/function";
|
|
import http from "@/plugins/http";
|
|
import config from "@/app.config";
|
|
|
|
import type { QTableProps } from "quasar";
|
|
import type { DataEducation } from "@/modules/05_placement/interface/index/Main";
|
|
import type {
|
|
DataPerson,
|
|
Education,
|
|
} from "@/modules/05_placement/interface/response/Main";
|
|
|
|
import DialogHeader from "@/components/DialogHeader.vue";
|
|
|
|
const $q = useQuasar();
|
|
const mixin = useCounterMixin(); //เรียกฟังก์ชันกลาง
|
|
const { showLoader, hideLoader, date2Thai, messageError } = mixin;
|
|
|
|
/** รับค่ามาจากหน้าหลัก */
|
|
const props = defineProps({
|
|
Modal: Boolean,
|
|
close: {
|
|
type: Function,
|
|
default: () => console.log("not function"),
|
|
},
|
|
personalId: {
|
|
type: String,
|
|
default: "",
|
|
},
|
|
validate: {
|
|
type: Function,
|
|
default: () => console.log("not function"),
|
|
},
|
|
});
|
|
|
|
const rows = ref<DataEducation[]>([]);
|
|
const personalForm = ref<DataPerson>();
|
|
const age = ref<string | null>(""); //อายุ
|
|
|
|
// ข้อมูลแปลงจาก ID เป็นชื่อ
|
|
const currentProvinceName = ref<string>("");
|
|
const currentDistrictName = ref<string>("");
|
|
const currentSubDistrictName = ref<string>("");
|
|
const registProvinceName = ref<string>("");
|
|
const registDistrictName = ref<string>("");
|
|
const registSubDistrictName = ref<string>("");
|
|
|
|
// Cache ข้อมูล
|
|
const provincesCache = ref<any[]>([]);
|
|
const districtsCache = ref<Map<string, any[]>>(new Map()); // key: provinceId, value: districts[]
|
|
const subDistrictsCache = ref<Map<string, any[]>>(new Map()); // key: districtId, value: subDistricts[]
|
|
|
|
/**หัวตาราง */
|
|
const columns = ref<QTableProps["columns"]>([
|
|
{
|
|
name: "university",
|
|
align: "center",
|
|
label: "สถานศึกษา",
|
|
sortable: true,
|
|
field: "university",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
},
|
|
{
|
|
name: "degree",
|
|
align: "center",
|
|
label: "วุฒิการศึกษา",
|
|
sortable: true,
|
|
field: "degree",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
sort: (a: string, b: string) =>
|
|
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
|
|
},
|
|
{
|
|
name: "major",
|
|
align: "center",
|
|
label: "สาขาวิชาเอก",
|
|
sortable: true,
|
|
field: "major",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
},
|
|
{
|
|
name: "graduation",
|
|
align: "center",
|
|
label: "วันที่สำเร็จการศึกษา",
|
|
sortable: true,
|
|
field: "graduation",
|
|
headerStyle: "font-size: 14px",
|
|
style: "font-size: 14px",
|
|
sort: (a: string, b: string) =>
|
|
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
|
|
},
|
|
]);
|
|
|
|
/**
|
|
* ฟังก์ชันดึงข้อมูลรายละเอียด
|
|
*/
|
|
async function fetchData() {
|
|
// Reset ข้อมูลเก่าก่อนโหลดข้อมูลใหม่
|
|
resetData();
|
|
|
|
showLoader();
|
|
await http
|
|
.get(config.API.getDatapersonal(props.personalId))
|
|
.then((res) => {
|
|
personalForm.value = res.data.result;
|
|
if (res.data.result.dateOfBirth) {
|
|
// กำหนดอายุ ส่งวันเกิดไปคำนวน
|
|
age.value = calculateAge(res.data.result.dateOfBirth);
|
|
} else {
|
|
age.value = null;
|
|
}
|
|
personalForm.value?.education.map((e: Education) => {
|
|
rows.value.push({
|
|
university: e.institute,
|
|
degree: e.degree,
|
|
major: e.field,
|
|
graduation: date2Thai(e.finishDate),
|
|
});
|
|
});
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(() => {
|
|
hideLoader();
|
|
});
|
|
|
|
// แปลง ID เป็นชื่อ
|
|
await convertAddressIds();
|
|
}
|
|
|
|
/**
|
|
* Reset ข้อมูลทุกครั้งที่เปิดคนใหม่
|
|
*/
|
|
function resetData() {
|
|
// Reset ข้อมูลส่วนตัว
|
|
personalForm.value = undefined;
|
|
age.value = "";
|
|
rows.value = [];
|
|
|
|
// Reset ข้อมูลที่อยู่
|
|
currentProvinceName.value = "";
|
|
currentDistrictName.value = "";
|
|
currentSubDistrictName.value = "";
|
|
registProvinceName.value = "";
|
|
registDistrictName.value = "";
|
|
registSubDistrictName.value = "";
|
|
}
|
|
|
|
/**
|
|
* ฟังก์ชันแปลง ID เป็นชื่อจริงของที่อยู่ (แบบ optimize)
|
|
*/
|
|
async function convertAddressIds() {
|
|
if (!personalForm.value) return;
|
|
|
|
try {
|
|
// โหลดข้อมูลจังหวัดครั้งเดียวถ้ายังไม่มี
|
|
await loadProvinces();
|
|
|
|
// แปลงข้อมูลที่อยู่ปัจจุบัน
|
|
if (personalForm.value.currentProvinceId && personalForm.value.currentProvinceId.trim() !== "") {
|
|
currentProvinceName.value = getProvinceNameFromCache(
|
|
personalForm.value.currentProvinceId
|
|
);
|
|
|
|
if (personalForm.value.currentDistrictId && personalForm.value.currentDistrictId.trim() !== "") {
|
|
currentDistrictName.value = await getDistrictNameOptimized(
|
|
personalForm.value.currentProvinceId,
|
|
personalForm.value.currentDistrictId
|
|
);
|
|
|
|
if (personalForm.value.currentSubDistrictId && personalForm.value.currentSubDistrictId.trim() !== "") {
|
|
currentSubDistrictName.value = await getSubDistrictNameOptimized(
|
|
personalForm.value.currentDistrictId,
|
|
personalForm.value.currentSubDistrictId
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// แปลงข้อมูลที่อยู่ตามทะเบียน
|
|
if (personalForm.value.registProvinceId && personalForm.value.registProvinceId.trim() !== "") {
|
|
registProvinceName.value = getProvinceNameFromCache(
|
|
personalForm.value.registProvinceId
|
|
);
|
|
|
|
if (personalForm.value.registDistrictId && personalForm.value.registDistrictId.trim() !== "") {
|
|
registDistrictName.value = await getDistrictNameOptimized(
|
|
personalForm.value.registProvinceId,
|
|
personalForm.value.registDistrictId
|
|
);
|
|
|
|
if (personalForm.value.registSubDistrictId && personalForm.value.registSubDistrictId.trim() !== "") {
|
|
registSubDistrictName.value = await getSubDistrictNameOptimized(
|
|
personalForm.value.registDistrictId,
|
|
personalForm.value.registSubDistrictId
|
|
);
|
|
}
|
|
}
|
|
}
|
|
} catch (error) {
|
|
console.error("Error converting address IDs:", error);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* โหลดข้อมูลจังหวัดทั้งหมด (ครั้งเดียว)
|
|
*/
|
|
async function loadProvinces() {
|
|
if (provincesCache.value.length === 0) {
|
|
try {
|
|
const res = await http.get(config.API.province);
|
|
provincesCache.value = res.data.result;
|
|
} catch (error) {
|
|
console.error("Error loading provinces:", error);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ดึงชื่อจังหวัดจาก cache
|
|
*/
|
|
function getProvinceNameFromCache(provinceId: string): string {
|
|
const province = provincesCache.value.find(
|
|
(p: any) => p.id.toString() === provinceId
|
|
);
|
|
return province ? province.name : "-";
|
|
}
|
|
|
|
/**
|
|
* ดึงชื่ออำเภอแบบ optimize (เรียก API เฉพาะจังหวัดที่ต้องการ)
|
|
* @param provinceId ID ของจังหวัด
|
|
* @param districtId ID ของอำเภอ
|
|
*/
|
|
async function getDistrictNameOptimized(
|
|
provinceId: string,
|
|
districtId: string
|
|
): Promise<string> {
|
|
try {
|
|
// เช็ค cache ว่ามีข้อมูล districts ของ province นี้หรือไม่
|
|
if (!districtsCache.value.has(provinceId)) {
|
|
const res = await http.get(config.API.listDistrict(provinceId));
|
|
districtsCache.value.set(provinceId, res.data.result.districts);
|
|
}
|
|
|
|
const districts = districtsCache.value.get(provinceId) || [];
|
|
const district = districts.find((d: any) => d.id.toString() === districtId);
|
|
return district ? district.name : "-";
|
|
} catch (error) {
|
|
console.error("Error loading district:", error);
|
|
return "-";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ดึงชื่อตำบลแบบ optimize (เรียก API เฉพาะอำเภอที่ต้องการ)
|
|
* @param districtId ID ของอำเภอ
|
|
* @param subDistrictId ID ของตำบล
|
|
*/
|
|
async function getSubDistrictNameOptimized(
|
|
districtId: string,
|
|
subDistrictId: string
|
|
): Promise<string> {
|
|
try {
|
|
// เช็ค cache ว่ามีข้อมูล subDistricts ของ district นี้หรือไม่
|
|
if (!subDistrictsCache.value.has(districtId)) {
|
|
const res = await http.get(config.API.listSubDistrict(districtId));
|
|
subDistrictsCache.value.set(districtId, res.data.result.subDistricts);
|
|
}
|
|
|
|
const subDistricts = subDistrictsCache.value.get(districtId) || [];
|
|
const subDistrict = subDistricts.find(
|
|
(sd: any) => sd.id.toString() === subDistrictId
|
|
);
|
|
return subDistrict ? subDistrict.name : "-";
|
|
} catch (error) {
|
|
console.error("Error loading subdistrict:", error);
|
|
return "-";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ฟังก์ชันแปลงประเภทข้าราชการ เป็นไทย
|
|
* @param val ประเภทข้าราชการ
|
|
*/
|
|
function formBmaofficer(val: string) {
|
|
switch (val) {
|
|
case "OFFICER":
|
|
return "ขรก.กทม. สามัญ";
|
|
case "EMPLOYEE_PERM":
|
|
return "ลูกจ้างประจำ";
|
|
case "EMPLOYEE_TEMP":
|
|
return "ลูกจ้างชั่วคราว";
|
|
default:
|
|
return "";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ปิด POPUP ข้อมูล
|
|
*/
|
|
async function close() {
|
|
props.close();
|
|
resetData(); // Reset ข้อมูลเมื่อปิด dialog
|
|
}
|
|
|
|
/**
|
|
* เมื่อ props.Modal เป็น true จะเรียกข้อมูลการศึกษา
|
|
*/
|
|
watch(props, () => {
|
|
if (props.Modal === true) {
|
|
fetchData();
|
|
}
|
|
});
|
|
</script>
|
|
<template>
|
|
<q-dialog v-model="props.Modal" persistent>
|
|
<q-card style="max-width: 100%; width: 80%">
|
|
<q-form>
|
|
<DialogHeader
|
|
:tittle="`รายละเอียดของ ${personalForm?.fullName}`"
|
|
:close="close"
|
|
/>
|
|
|
|
<q-separator />
|
|
|
|
<div class="contanier-box-main">
|
|
<div class="contanier-box-mini">
|
|
<q-card bordered class="card-panding">
|
|
<div class="row items-center q-pa-xs header-text">
|
|
ข้อมูลทั่วไป
|
|
<span
|
|
v-if="personalForm?.bmaOfficer != null"
|
|
class="check-officer"
|
|
>
|
|
<q-icon name="mdi-check" />
|
|
{{ formBmaofficer(personalForm.bmaOfficer) }}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="row q-pa-xs">
|
|
<div class="col-3 header-sub-text">
|
|
<div class="q-pb-sm">เลขประจำตัวประชาชน</div>
|
|
<div class="q-pb-sm">วัน/เดือน/ปีเกิด</div>
|
|
<div class="q-pb-sm">อายุ</div>
|
|
<div class="q-pb-sm">สัญชาติ</div>
|
|
<div>หมู่เลือด</div>
|
|
</div>
|
|
|
|
<div class="col-4 sub-text">
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.idCard }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ date2Thai(personalForm?.dateOfBirth) }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ age ? age : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{
|
|
personalForm?.nationality ? personalForm.nationality : "-"
|
|
}}
|
|
</div>
|
|
<div>
|
|
{{
|
|
personalForm?.bloodGroup ? personalForm.bloodGroup : "-"
|
|
}}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="col-2 header-sub-text">
|
|
<div class="q-pb-sm">ชื่อ-นามสกุล</div>
|
|
<div class="q-pb-sm">เพศ</div>
|
|
<div class="q-pb-sm">เชื้อชาติ</div>
|
|
<div class="q-pb-sm">ศาสนา</div>
|
|
<div>เบอร์โทรศัพท์</div>
|
|
</div>
|
|
<div class="col-3 sub-text">
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.fullName }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.gender }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.race ? personalForm.race : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.religion ? personalForm.religion : "-" }}
|
|
</div>
|
|
<div class="q-mt-sm">
|
|
{{ personalForm?.telephone ? personalForm.telephone : "-" }}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-card>
|
|
</div>
|
|
|
|
<div class="contanier-box-mini">
|
|
<q-card bordered class="card-panding">
|
|
<div class="row items-center q-pa-xs header-text">ภูมิลำเนา</div>
|
|
<div class="row q-pa-xs">
|
|
<!-- ที่อยู่ปัจจุบัน -->
|
|
<div class="col-6">
|
|
<div class="q-pb-sm text-weight-medium text-primary">
|
|
ที่อยู่ปัจจุบัน
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-4 header-sub-text">
|
|
<div class="q-pb-sm">ที่อยู่</div>
|
|
<div class="q-pb-sm">จังหวัด</div>
|
|
<div class="q-pb-sm">เขต/อำเภอ</div>
|
|
<div class="q-pb-sm">แขวง/ตำบล</div>
|
|
<div>รหัสไปรษณีย์</div>
|
|
</div>
|
|
<div class="col-8 sub-text">
|
|
<div class="q-pb-sm">
|
|
{{
|
|
personalForm?.currentAddress
|
|
? personalForm.currentAddress
|
|
: "-"
|
|
}}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ currentProvinceName ? currentProvinceName : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ currentDistrictName ? currentDistrictName : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{
|
|
currentSubDistrictName ? currentSubDistrictName : "-"
|
|
}}
|
|
</div>
|
|
<div class="q-mt-sm">
|
|
{{
|
|
personalForm?.currentZipCode
|
|
? personalForm.currentZipCode
|
|
: "-"
|
|
}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ที่อยู่ตามทะเบียนบ้าน -->
|
|
<div class="col-6">
|
|
<div class="q-pb-sm text-weight-medium text-primary">
|
|
ที่อยู่ตามทะเบียนบ้าน
|
|
</div>
|
|
<div class="row">
|
|
<div class="col-4 header-sub-text">
|
|
<div class="q-pb-sm">ที่อยู่</div>
|
|
<div class="q-pb-sm">จังหวัด</div>
|
|
<div class="q-pb-sm">เขต/อำเภอ</div>
|
|
<div class="q-pb-sm">แขวง/ตำบล</div>
|
|
<div>รหัสไปรษณีย์</div>
|
|
</div>
|
|
<div class="col-8 sub-text">
|
|
<div class="q-pb-sm">
|
|
{{
|
|
personalForm?.registAddress
|
|
? personalForm.registAddress
|
|
: "-"
|
|
}}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ registProvinceName ? registProvinceName : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{ registDistrictName ? registDistrictName : "-" }}
|
|
</div>
|
|
<div class="q-pb-sm">
|
|
{{
|
|
registSubDistrictName ? registSubDistrictName : "-"
|
|
}}
|
|
</div>
|
|
<div class="q-mt-sm">
|
|
{{
|
|
personalForm?.registZipCode
|
|
? personalForm.registZipCode
|
|
: "-"
|
|
}}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-card>
|
|
</div>
|
|
|
|
<div class="contanier-box-mini">
|
|
<q-card bordered class="card-panding">
|
|
<div class="row items-center q-pa-xs header-text">การศึกษา</div>
|
|
<q-table
|
|
ref="table"
|
|
:rows="rows"
|
|
:columns="columns"
|
|
flat
|
|
bordered
|
|
class="custom-header-table"
|
|
virtual-scroll
|
|
:virtual-scroll-sticky-size-start="48"
|
|
dense
|
|
hide-bottom
|
|
>
|
|
</q-table>
|
|
</q-card>
|
|
</div>
|
|
|
|
<div class="contanier-box-mini">
|
|
<q-card bordered class="card-panding">
|
|
<div class="row items-center q-pa-xs header-text">การสอบ</div>
|
|
<div class="row q-pa-xs">
|
|
<div class="col-6 q-pt-sm q-pl-lg">
|
|
<div class="row">
|
|
<div class="col-7 header-sub-text">
|
|
<div class="q-pb-sm">ผลการสอบ</div>
|
|
<div class="q-pb-sm">ลำดับที่สอบได้</div>
|
|
<div class="q-pb-sm">จำนวนครั้งที่สมัครสอบ</div>
|
|
</div>
|
|
<div class="col-5 sub-text-exam">
|
|
<div class="q-pb-sm">
|
|
{{ personalForm?.pass }}
|
|
</div>
|
|
<div class="q-pb-sm">{{ personalForm?.examNumber }}</div>
|
|
<div class="q-pb-sm">{{ personalForm?.examRound }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</q-card>
|
|
</div>
|
|
</div>
|
|
</q-form>
|
|
</q-card>
|
|
</q-dialog>
|
|
</template>
|
|
<style lang="scss" scoped>
|
|
.icon-officer {
|
|
color: #00aa86;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.check-officer {
|
|
font-size: 17px;
|
|
font-weight: 500;
|
|
line-height: 26px;
|
|
color: #00aa86;
|
|
padding-left: 20px;
|
|
}
|
|
|
|
.contanier-box-main {
|
|
padding: 10px 21px 10px 21px;
|
|
}
|
|
|
|
.contanier-box-mini {
|
|
padding: 10px 0px 10px 0px;
|
|
}
|
|
|
|
.card-panding {
|
|
padding: 15px 21px 15px 21px;
|
|
}
|
|
|
|
.header-text {
|
|
font-size: 18px;
|
|
font-weight: 600;
|
|
color: #4f4f4f;
|
|
}
|
|
|
|
.header-sub-text {
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
line-height: 150%;
|
|
color: #818181;
|
|
}
|
|
|
|
.sub-text {
|
|
font-weight: 400;
|
|
font-size: 16px;
|
|
line-height: 22px;
|
|
letter-spacing: 0.0025em;
|
|
color: #35373c;
|
|
}
|
|
|
|
.card-exam {
|
|
border-radius: 5px;
|
|
background: #fafafa;
|
|
}
|
|
|
|
.header-sub-text-exam {
|
|
font-size: 15px;
|
|
font-weight: 500;
|
|
line-height: 150%;
|
|
color: #818181;
|
|
}
|
|
|
|
.header-sub-text-exam-2 {
|
|
font-size: 15px;
|
|
font-weight: 500;
|
|
line-height: 150%;
|
|
color: #00aa86;
|
|
}
|
|
|
|
.sub-text-exam {
|
|
font-size: 15px;
|
|
font-weight: 500;
|
|
color: #000000;
|
|
}
|
|
|
|
.checkbox-group {
|
|
font-size: 16px;
|
|
font-weight: 400;
|
|
color: #35373c;
|
|
}
|
|
</style>
|