This commit is contained in:
Warunee Tamkoo 2024-08-01 12:12:28 +07:00
parent 46533bbd62
commit 15d3ac574d
128 changed files with 347 additions and 322 deletions

View file

@ -0,0 +1,899 @@
<script setup lang="ts">
import { onMounted, watch, ref, reactive } from "vue";
import { useRoute } from "vue-router";
import { useQuasar } from "quasar";
import type { QTableColumn, QForm } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useProfileDataStore } from "@/modules/04_registryPerson/stores/profile";
import DialogHeader from "@/components/DialogHeader.vue";
import type { RequestObject } from "@/modules/04_registryPerson/interface/request/Profile";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Profile";
const $q = useQuasar();
const route = useRoute();
const mixin = useCounterMixin();
const store = useProfileDataStore();
const {
success,
showLoader,
hideLoader,
date2Thai,
messageError,
dialogConfirm,
dialogMessageNotify,
} = mixin;
const { calculateAge, fetchPerson, filterSelector } = store;
const props = defineProps({
fetchDataPersonal: { type: Function, require: true },
});
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const modal = ref<boolean>(false);
const informaData = ref<ResponseObject>();
const rowsHistory = ref<ResponseObject[]>([]);
const filterHistory = ref<string>("");
const modalHistory = ref<boolean>(false);
const id = ref<string>("");
const age = ref<string | null>("");
const formData = reactive<RequestObject>(store.defaultProfile);
const pagination = ref({
page: 1,
rowsPerPage: 10,
});
const dataLabel = {
citizenId: "เลขประจำตัวประชาชน",
name: "ชื่อ - สกุล",
birthDate: "วัน/เดือน/ปีเกิด",
age: "อายุ",
gender: "เพศ",
relationship: "สถานภาพ",
nationality: "สัญชาติ",
ethnicity: "เชื้อชาติ",
religion: "ศาสนา",
bloodGroup: "หมู่เลือด",
phone: "เบอร์โทร",
prefix: "คำนำหน้าชื่อ",
rank: "ยศ",
firstName: "ชื่อ",
lastName: "นามสกุล",
};
const columnsHistory = ref<QTableColumn[]>([
{
name: "citizenId",
align: "left",
label: "เลขประจำตัวประชาชน",
sortable: true,
field: "citizenId",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "prefix",
align: "left",
label: "คำนำหน้าชื่อ",
sortable: true,
field: "prefix",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "rank",
align: "left",
label: "ยศ",
sortable: true,
field: "rank",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "firstName",
align: "left",
label: "ชื่อ",
sortable: true,
field: "firstName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lastName",
align: "left",
label: "นามสกุล",
sortable: true,
field: "lastName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "birthDate",
align: "left",
label: "วัน/เดือน/ปี เกิด",
sortable: true,
field: "birthDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => {
return v ? date2Thai(v) : "";
},
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "gender",
align: "left",
label: "เพศ",
sortable: true,
field: "gender",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "relationship",
align: "left",
label: "สถานภาพ",
sortable: true,
field: "relationship",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "bloodGroup",
align: "left",
label: "หมู่เลือด",
sortable: true,
field: "bloodGroup",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "nationality",
align: "left",
label: "สัญชาติ",
sortable: true,
field: "nationality",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "ethnicity",
align: "left",
label: "เชื้อชาติ",
sortable: true,
field: "ethnicity",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "religion",
align: "left",
label: "ศาสนา",
sortable: true,
field: "religion",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "phone",
align: "left",
label: "เบอร์โทร",
sortable: true,
field: "phone",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "createdFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "createdFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "createdAt",
align: "left",
label: "วันที่แก้ไข",
sortable: true,
field: "lastUpdatedAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => date2Thai(v),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"citizenId",
"prefix",
"rank",
"firstName",
"lastName",
"birthDate",
"gender",
"relationship",
"bloodGroup",
"nationality",
"ethnicity",
"religion",
"phone",
"createdFullName",
"createdAt",
]);
async function getData() {
showLoader();
http
.get(config.API.registryNewByProfileId(profileId.value, empType.value))
.then((res) => {
informaData.value = res.data.result;
id.value = res.data.result.id;
if (res.data.result.birthDate) {
console.log("birthDate===>", res.data.result.birthDate);
age.value = calculateAge(res.data.result.birthDate);
console.log("age===>", age.value);
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
const calculateMaxDate = () => {
const today = new Date();
today.setFullYear(today.getFullYear() - 18);
return today;
};
async function editData() {
showLoader();
await http
.put(config.API.profileNewProfileById(id.value, empType.value), {
...formData,
employeeClass: route.name === "registry-employeeId" ? "TEMP" : undefined,
})
.then(() => {
success($q, "บันทึกข้อมูลสำเร็จ");
getData(), (modal.value = false);
props.fetchDataPersonal?.();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function onClickOpenDialog() {
if (!informaData.value) return;
modal.value = true;
console.log("onClickOpenDialog birthDate===>", informaData.value.birthDate);
id.value = informaData.value.id;
age.value = calculateAge(informaData.value.birthDate);
formData.citizenId = informaData.value.citizenId;
formData.prefix = informaData.value.prefix;
formData.rank = informaData.value.rank;
formData.firstName = informaData.value.firstName;
formData.lastName = informaData.value.lastName;
formData.birthDate = informaData.value.birthDate;
formData.gender = informaData.value.gender;
formData.relationship = informaData.value.relationship;
formData.nationality = informaData.value.nationality;
formData.ethnicity = informaData.value.ethnicity;
formData.religion = informaData.value.religion;
formData.bloodGroup = informaData.value.bloodGroup;
formData.phone = informaData.value.phone;
}
function onSubmit() {
dialogConfirm(
$q,
async () => {
editData();
modal.value = false;
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
async function clickHistory() {
modalHistory.value = true;
await http
.get(config.API.profileNewProfileHisById(id.value, empType.value))
.then((res) => {
rowsHistory.value = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function changeCardID(citizenId: string | number | null) {
if (citizenId != null && typeof citizenId == "string") {
if (citizenId.length == 13 && citizenId) {
http
.put(config.API.profileNewCitizenId(citizenId), {
citizenId: citizenId,
})
.then(() => {})
.catch((err) => {
if (err.response.data.status === 500) {
dialogMessageNotify($q, err.response.data.message);
} else {
messageError($q, err);
}
});
}
}
}
watch(
() => formData.birthDate,
(v) => {
console.log("v===>", v);
if (v) {
age.value = calculateAge(v);
}
}
);
onMounted(async () => {
await getData();
if (store.Ops && store.Ops.prefixOps && store.Ops.prefixOps.length === 0) {
fetchPerson();
}
// store.Ops.prefixOps.length === 0 ||
// store.Ops.genderOps.length === 0 ||
// store.Ops.bloodOps.length === 0 ||
// store.Ops.statusOps.length === 0 ||
// store.Ops.religionOps.length === 0
});
</script>
<template>
<div class="row q-gutter-sm items-center">
<div class="toptitle col text-right q-gutter-x-sm">
<q-btn
flat
round
dense
icon="mdi-pencil-outline"
color="primary"
@click="onClickOpenDialog"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
dense
flat
round
icon="mdi-history"
color="info"
@click="clickHistory"
>
<q-tooltip>ประวแกไขขอมลสวนต</q-tooltip>
</q-btn>
</div>
</div>
<q-card bordered class="my-card bg-grey-1 q-pa-md">
<div v-if="informaData" :class="$q.screen.gt.xs ? 'row' : 'column'">
<!-- column 1 -->
<div class="col-md-7 col-12 row">
<div class="col-5 text-grey-6 text-weight-medium">
<div
v-for="label in Object.keys(dataLabel).slice(0, 6)"
class="q-py-xs"
>
{{ dataLabel[label as keyof typeof dataLabel] }}
</div>
</div>
<!-- data -->
<div class="col-7">
<div class="q-py-xs">
{{ informaData.citizenId }}
</div>
<div class="q-py-xs">
{{
`${
informaData.rank ? informaData.rank : informaData.prefix ?? ""
} ${informaData.firstName} ${informaData.lastName}`
}}
</div>
<div class="q-py-xs">
{{ informaData.birthDate ? date2Thai(informaData.birthDate) : "" }}
</div>
<div class="q-py-xs">
{{ age ? age : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.gender ? informaData.gender : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.relationship ? informaData.relationship : "-" }}
</div>
</div>
</div>
<!-- column 2 -->
<div class="col-md-5 col-12 row">
<div class="col-5 col text-grey-6 text-weight-medium">
<div
v-for="label in Object.keys(dataLabel).slice(6, 11)"
class="q-py-xs"
>
{{ dataLabel[label as keyof typeof dataLabel] }}
</div>
</div>
<!-- data -->
<div class="col-7">
<div class="q-py-xs">
{{ informaData.nationality ? informaData.nationality : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.ethnicity ? informaData.ethnicity : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.religion ? informaData.religion : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.bloodGroup ? informaData.bloodGroup : "-" }}
</div>
<div class="q-py-xs">
{{ informaData.phone ? informaData.phone : "-" }}
</div>
</div>
</div>
</div>
</q-card>
<!-- Edit Dialog -->
<q-dialog v-model="modal" persistent>
<q-card>
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader
tittle="แก้ไขประวัติส่วนตัว"
:close="() => (modal = false)"
/>
<q-separator />
<q-card-section>
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
maxlength="13"
mask="#############"
v-model="formData.citizenId"
class="inputgreen"
:label="dataLabel.citizenId"
:rules="[
(val: string) => !!val || `${'กรุณากรอก เลขประจำตัวประชาชน'}`,
(val: string) =>
val.length >= 13 ||
`${'กรุณากรอกเลขประจำตัวประชาชนให้ครบ'}`,
]"
@update:model-value="changeCardID"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
input-debounce="0"
option-label="name"
option-value="name"
v-model="formData.prefix"
class="inputgreen"
:options="store.Ops.prefixOps"
:label="dataLabel.prefix"
:rules="[(val: string) => !!val || `${'กรุณาเลือก คำนำหน้าชื่อ'}`]"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'prefixOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
clearable
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
input-debounce="0"
option-label="name"
option-value="name"
v-model="formData.rank"
class="inputgreen"
:options="store.Ops.rankOps"
:label="dataLabel.rank"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'rankOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
v-model="formData.firstName"
class="inputgreen"
:label="dataLabel.firstName"
:rules="[(val: string) => !!val || `${'กรุณากรอก ชื่อ'}`]"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
v-model="formData.lastName"
class="inputgreen"
:label="dataLabel.lastName"
:rules="[(val: string) => !!val || `${'กรุณากรอก นามสกุล'}`]"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
autoApply
:max-date="calculateMaxDate()"
borderless
:enableTimePicker="false"
week-start="0"
menu-class-name="modalfix"
v-model="formData.birthDate"
:locale="'th'"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
for="inputDatereceive"
ref="dateReceivedRef"
outlined
dense
hide-bottom-space
class="inputgreen"
:model-value="
formData.birthDate ? date2Thai(formData.birthDate) : null
"
:label="dataLabel.birthDate"
:rules="[
(val) => !!val || `${'กรุณาเลือก วัน/เดือน/ปี เกิด'}`,
]"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
readonly
v-model="age"
:label="dataLabel.age"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
clearable
lazy-rules
emit-value
map-options
hide-bottom-space
input-debounce="0"
option-label="name"
option-value="name"
v-model="formData.gender"
class="inputgreen"
:options="store.Ops.genderOps"
:label="dataLabel.gender"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'genderOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
clearable
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="name"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.relationship"
:options="store.Ops.statusOps"
:label="dataLabel.relationship"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'statusOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
class="inputgreen"
v-model="formData.nationality"
:label="dataLabel.nationality"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
class="inputgreen"
v-model="formData.ethnicity"
:label="dataLabel.ethnicity"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
clearable
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="name"
option-label="name"
input-debounce="0"
v-model="formData.religion"
class="inputgreen"
:options="store.Ops.religionOps"
:label="dataLabel.religion"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'religionOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
clearable
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="name"
option-label="name"
input-debounce="0"
v-model="formData.bloodGroup"
class="inputgreen"
:options="store.Ops.bloodOps"
:label="dataLabel.bloodGroup"
@filter="(inputValue: any,
doneFn: Function) => filterSelector(inputValue, doneFn, 'bloodOps'
)"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
mask="##########"
class="inputgreen"
v-model="formData.phone"
:label="dataLabel.phone"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn
label="บันทึก"
id="onSubmit"
type="submit"
color="public"
class="q-px-md"
>
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="modalHistory" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขข้อมูลส่วนตัว"
:close="() => (modalHistory = false)"
/>
<q-separator />
<q-card-section style="max-height: 50vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterHistory"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterHistory == ''"
name="search"
@click.stop.prevent="filterHistory = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterHistory"
name="cancel"
@click.stop.prevent="filterHistory = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-model="visibleColumnsHistory"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columnsHistory"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columnsHistory"
:rows="rowsHistory"
class="custom-header-table"
v-model:pagination="pagination"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumnsHistory"
:filter="filterHistory"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id">
<div>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
<q-separator />
<q-card-actions align="right"> </q-card-actions>
</q-card>
</q-dialog>
</template>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

View file

@ -0,0 +1,934 @@
<script setup lang="ts">
import { onMounted, ref, reactive, watch } from "vue";
import { useRoute } from "vue-router";
import { useQuasar } from "quasar";
import type { QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useAddressDataStore } from "@/modules/04_registryPerson/stores/Address";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/Address";
import type { RequestObject } from "@/modules/04_registryPerson/interface/request/Address";
const $q = useQuasar();
const store = useAddressDataStore();
const mixin = useCounterMixin();
const route = useRoute();
const {
fetchProvince,
fetchDistrict,
fetchSubDistrict,
findData,
filterSelector,
} = store;
const {
date2Thai,
success,
messageError,
showLoader,
hideLoader,
dialogConfirm,
} = mixin;
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const modal = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const rowsHistory = ref<ResponseObject[]>([]);
const filterHistory = ref<string>("");
const id = ref<string>("");
const rawSameAddress = ref<string>("0");
const sameAddress = ref<string>("0");
const addressData = reactive<ResponseObject>(store.defaultAddress);
const formData = reactive<RequestObject>(store.defaultAddressForm);
const adsName = reactive({
regisP: "",
regisD: "",
regisSD: "",
currentP: "",
currentD: "",
currentSD: "",
});
const dataLabel = {
registrationAddress: "ที่อยู่ตามทะเบียนบ้าน",
registrationProvince: "จังหวัด",
registrationDistrict: "เขต/อำเภอ",
registrationSubDistrict: "แขวง / ตำบล",
registrationZipCode: "รหัสไปรษณีย์",
currentAddress: "ที่อยู่ปัจจุบัน",
currentProvince: "จังหวัด",
currentDistrict: "เขต/อำเภอ",
currentSubDistrict: "แขวง / ตำบล",
currentZipCode: "รหัสไปรษณีย์",
registrationSame: "ที่อยู่ปัจจุบันตรงกับที่อยู่ตามทะเบียนบ้าน",
};
const visibleColumnsHistory = ref<String[]>([
"currentAddress",
"currentDistrict",
"currentSubDistrict",
"currentZipCode",
"registrationAddress",
"registrationDistrict",
"registrationProvince",
"registrationSame",
"registrationSubDistrict",
"registrationZipCode",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "registrationAddress",
align: "left",
label: "ที่อยู่ตามทะเบียนบ้าน",
sortable: true,
field: "registrationAddress",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "registrationProvince",
align: "left",
label: "จังหวัดตามทะเบียนบ้าน",
sortable: true,
field: "registrationProvince",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "registrationDistrict",
align: "left",
label: "เขต/อำเภอตามทะเบียนบ้าน",
sortable: true,
field: "registrationDistrict",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "registrationSubDistrict",
align: "left",
label: "แขวง/ตำบลตามทะเบียนบ้าน",
sortable: true,
field: "registrationSubDistrict",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "registrationZipCode",
align: "left",
label: "รหัสไปรษณีย์ตามทะเบียนบ้าน",
sortable: true,
field: "registrationZipCode",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "registrationSame",
align: "left",
label: "ที่อยู่ปัจจุบันตรงกับที่อยู่ตามทะเบียนบ้าน",
sortable: true,
field: (v) =>
v.registrationAddress === v.currentAddress &&
v.registrationZipCode === v.currentZipCode
? "ใช่"
: "ไม่",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentAddress",
align: "left",
label: "ที่อยู่ปัจจุบัน",
sortable: true,
field: "currentAddress",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentProvince",
align: "left",
label: "จังหวัดปัจจุบัน",
sortable: true,
field: "currentProvince",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentDistrict",
align: "left",
label: "เขต/อำเภอปัจจุบัน",
sortable: true,
field: "currentDistrict",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentSubDistrict",
align: "left",
label: "แขวง/ตำบลปัจจุบัน",
sortable: true,
field: "currentSubDistrict",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => (v ? v.name : "-"),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "currentZipCode",
align: "left",
label: "รหัสไปรษณีย์ปัจจุบัน",
sortable: true,
field: "currentZipCode",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lastUpdateFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "lastUpdateFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lastUpdatedAt",
align: "left",
label: "วันที่แก้ไข",
sortable: true,
field: "lastUpdatedAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
format: (v) => date2Thai(v),
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
async function getData() {
showLoader();
await http
.get(
config.API.profileNewAddressByProfileId(profileId.value, empType.value)
)
.then((res) => {
Object.assign(addressData, res.data.result);
if (addressData) {
id.value = addressData.id;
addressData.currentAddress === addressData.registrationAddress &&
addressData.currentZipCode === addressData.registrationZipCode &&
addressData.currentAddress &&
addressData.registrationAddress &&
addressData.currentZipCode &&
addressData.registrationZipCode
? (rawSameAddress.value = "1")
: (rawSameAddress.value = "0");
}
sameAddress.value = rawSameAddress.value;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
async function selectProvince(e: string | null, name: string) {
if (!e) return;
if (name == "1") {
formData.registrationDistrictId = "";
formData.registrationSubDistrictId = "";
formData.registrationZipCode = "";
} else {
formData.currentDistrictId = "";
formData.currentSubDistrictId = "";
formData.currentZipCode = "";
}
await fetchDistrict(e, name);
}
async function selectDistrict(e: string | null, name: string) {
if (!e) return;
if (name == "1") {
formData.registrationSubDistrictId = "";
formData.registrationZipCode = "";
} else {
formData.currentSubDistrictId = "";
formData.currentZipCode = "";
}
await fetchSubDistrict(e, name);
}
function selectSubDistrict(e: string | null, name: string) {
if (!e) return;
if (name == "1") {
const findcode = store.Ops.subdistrictOps.filter((r) => r.id == e);
const namecode = findcode.length > 0 ? findcode[0].zipCode : "";
formData.registrationZipCode = namecode;
} else {
const findcode = store.Ops.subdistrictCOps.filter((r) => r.id == e);
const namecode = findcode.length > 0 ? findcode[0].zipCode : "";
formData.currentZipCode = namecode;
}
}
async function fetchAll() {
await getData();
if (!store.profileIdBefore) {
store.profileIdBefore = profileId.value;
}
if (
store.Ops.provinceOps.length === 0 ||
store.Ops.districtOps.length === 0 ||
store.Ops.districtCOps.length === 0 ||
store.Ops.subdistrictOps.length === 0 ||
store.Ops.subdistrictCOps.length === 0 ||
store.profileIdBefore !== profileId.value
) {
await fetchProvince();
await fetchDistrict(addressData.registrationProvinceId, "1");
await fetchDistrict(addressData.currentProvinceId, "2");
await fetchSubDistrict(addressData.registrationDistrictId, "1");
await fetchSubDistrict(addressData.currentDistrictId, "2");
store.profileIdBefore = profileId.value;
}
adsName.regisP = findData(
store.Ops.provinceOps,
addressData.registrationProvinceId
).name;
adsName.regisD = findData(
store.Ops.districtOps,
addressData.registrationDistrictId
).name;
adsName.regisSD = findData(
store.Ops.subdistrictOps,
addressData.registrationSubDistrictId
).name;
adsName.currentP = findData(
store.Ops.provinceOps,
addressData.currentProvinceId
).name;
adsName.currentD = findData(
store.Ops.districtCOps,
addressData.currentDistrictId
).name;
adsName.currentSD = findData(
store.Ops.subdistrictCOps,
addressData.currentSubDistrictId
).name;
}
async function editData() {
showLoader();
await http
.patch(config.API.profileNewAddressById(id.value, empType.value), {
...formData,
id: undefined,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
fetchAll();
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function clickClose() {
Object.assign(formData, store.defaultAddressForm);
modal.value = false;
}
async function onClickOpenDialog() {
if (!addressData) return;
await Object.assign(formData, addressData);
const checkDistrict = await store.Ops.districtOps.some(
(e: any) => e.id === addressData.registrationDistrictId
);
const checkSubDistrict = await store.Ops.subdistrictOps.some(
(e: any) => e.id === addressData.registrationSubDistrictId
);
const checkDistrictC = await store.Ops.districtCOps.some(
(e: any) => e.id === addressData.currentDistrictId
);
const checkSubDistrictC = await store.Ops.subdistrictCOps.some(
(e: any) => e.id === addressData.currentSubDistrictId
);
modal.value = true;
sameAddress.value = rawSameAddress.value;
if (!checkDistrict || !checkSubDistrict) {
await fetchDistrict(addressData.registrationProvinceId, "1");
await fetchSubDistrict(addressData.registrationDistrictId, "1");
}
if (!checkDistrictC || !checkSubDistrictC) {
await fetchDistrict(addressData.currentProvinceId, "2");
await fetchSubDistrict(addressData.currentDistrictId, "2");
}
}
async function clickHistory() {
modalHistory.value = true;
await http
.get(config.API.profileNewAddressHisById(id.value, empType.value))
.then((res) => {
rowsHistory.value = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function onSubmit() {
dialogConfirm(
$q,
async () => {
if (sameAddress.value === "1") {
formData.currentAddress = formData.registrationAddress;
formData.currentProvinceId = formData.registrationProvinceId;
formData.currentDistrictId = formData.registrationDistrictId;
formData.currentSubDistrictId = formData.registrationSubDistrictId;
formData.currentZipCode = formData.registrationZipCode;
store.Ops.districtCOps = store.Ops.districtOps;
store.Ops.subdistrictCOps = store.Ops.subdistrictOps;
}
editData();
modal.value = false;
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
function sameAddressToggle(v: string) {
if (v === "0") {
formData.currentAddress = "";
formData.currentProvinceId = "";
formData.currentDistrictId = "";
formData.currentSubDistrictId = "";
formData.currentZipCode = "";
store.Ops.districtCOps = [];
store.Ops.subdistrictCOps = [];
}
}
watch(
() => sameAddress.value,
(v) => {
sameAddressToggle(v);
}
);
onMounted(async () => {
await fetchAll();
});
</script>
<template>
<div class="row q-gutter-sm items-center">
<div class="toptitle col text-right q-gutter-x-sm">
<q-btn
flat
round
dense
icon="mdi-pencil-outline"
color="primary"
@click="onClickOpenDialog"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
dense
flat
round
icon="mdi-history"
color="info"
@click="clickHistory"
>
<q-tooltip>ประวอมลทอย</q-tooltip>
</q-btn>
</div>
</div>
<div class="row">
<div class="col-md-6 col-12">
<q-card bordered class="bg-grey-1 q-ma-sm">
<q-card-section>
<div class="text-bold">อยตามทะเบยนบาน</div>
</q-card-section>
<q-separator />
<q-card-section>
<div :class="$q.screen.gt.xs ? '' : 'column'">
<!-- column 1 -->
<div class="col-md-6 col-12 row">
<div class="col-5 text-grey-6 text-weight-medium">อย</div>
<div class="col-7">
<div class="q-py-xs">
{{ addressData.registrationAddress || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">แขวง/ตำบล</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.regisSD || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">เขต/อำเภอ</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.regisD || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">งหว</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.regisP || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">
รหสไปรษณ
</div>
<div class="col-7">
<div class="q-py-xs">
{{ addressData.registrationZipCode || "-" }}
</div>
</div>
</div>
</div>
</q-card-section>
</q-card>
</div>
<div class="col-md-6 col-12">
<q-card bordered class="bg-grey-1 q-ma-sm">
<q-card-section>
<div class="text-bold">อยจจ</div>
</q-card-section>
<q-separator />
<q-card-section>
<div :class="$q.screen.gt.xs ? '' : 'column'">
<div class="col-md-6 col-12 row">
<div class="col-5 text-grey-6 text-weight-medium">อย</div>
<div class="col-7">
<div class="q-py-xs">
{{ addressData.currentAddress || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">แขวง/ตำบล</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.currentSD || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">เขต/อำเภอ</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.currentD || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">งหว</div>
<div class="col-7">
<div class="q-py-xs">
{{ adsName.currentP || "-" }}
</div>
</div>
<div class="col-5 text-grey-6 text-weight-medium">
รหสไปรษณ
</div>
<div class="col-7">
<div class="q-py-xs">
{{ addressData.currentZipCode || "-" }}
</div>
</div>
</div>
</div>
</q-card-section>
</q-card>
</div>
</div>
<!-- Edit Dialog -->
<q-dialog v-model="modal" persistent>
<q-card>
<q-form greedy @submit.prevent @validation-success="onSubmit">
<DialogHeader tittle="แก้ไขข้อมูลที่อยู่" :close="clickClose" />
<q-separator />
<q-card-section>
<div class="col-12 q-pb-xs">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
type="textarea"
class="inputgreen"
v-model="formData.registrationAddress"
:label="dataLabel.registrationAddress"
:rules="[(val:string) => !!val || `${'กรุณากรอก ที่อยู่ตามทะเบียนบ้าน'}`]"
/>
</div>
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.registrationProvinceId"
:options="store.Ops.provinceOps"
:label="dataLabel.registrationProvince"
:rules="[(val:string) => !!val || `${'กรุณาเลือก จังหวัด'}`]"
@update:model-value="(value:string) => selectProvince(value, '1')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'provinceOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.registrationDistrictId"
:options="store.Ops.districtOps"
:label="dataLabel.registrationDistrict"
:rules="[(val:string) => !!val || `${'กรุณาเลือก เขต / อำเภอ'}`]"
@update:model-value="(value:string) => selectDistrict(value, '1')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'districtOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.registrationSubDistrictId"
:options="store.Ops.subdistrictOps"
:label="dataLabel.registrationSubDistrict"
:rules="[(val:string) => !!val || `${'กรุณาเลือก แขวง / ตำบล'}`]"
@update:model-value="(value:string) => selectSubDistrict(value, '1')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'subdistrictOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
readonly
outlined
lazy-rules
hide-bottom-space
v-model="formData.registrationZipCode"
:label="dataLabel.registrationZipCode"
/>
</div>
</div>
<!-- same address ? -->
<div class="col-xs-12 q-gutter-sm items-center flex q-my-sm">
<label class="text-medium"
>อยจจนตรงกบทอยตามทะเบยนบาน</label
>
<q-radio
dense
val="1"
label="ใช่"
checked-icon="task_alt"
class="inputgreen"
v-model="sameAddress"
unchecked-icon="panorama_fish_eye"
/>
<q-radio
dense
val="0"
label="ไม่"
checked-icon="task_alt"
class="inputgreen"
v-model="sameAddress"
unchecked-icon="panorama_fish_eye"
/>
</div>
<!-- current address -->
<div v-if="sameAddress === '0'">
<div class="col-12 q-pb-xs">
<q-input
dense
outlined
lazy-rules
hide-bottom-space
type="textarea"
class="inputgreen"
v-model="formData.currentAddress"
:label="dataLabel.currentAddress"
:rules="[(val:string) => !!val || `${'กรุณากรอก ที่อยู่ปัจจุบัน'}`]"
/>
</div>
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.currentProvinceId"
:options="store.Ops.provinceOps"
:label="dataLabel.currentProvince"
:rules="[(val:string) => !!val || `${'กรุณาเลือก จังหวัด'}`]"
@update:model-value="(value:string) => selectProvince(value, '2')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'provinceOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.currentDistrictId"
:options="store.Ops.districtCOps"
:label="dataLabel.currentDistrict"
:rules="[(val:string) => !!val || `${'กรุณาเลือก เขต / อำเภอ'}`]"
@update:model-value="(value:string) => selectDistrict(value, '2')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'districtCOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
dense
outlined
use-input
lazy-rules
emit-value
map-options
hide-bottom-space
option-value="id"
option-label="name"
input-debounce="0"
class="inputgreen"
v-model="formData.currentSubDistrictId"
:options="store.Ops.subdistrictCOps"
:label="dataLabel.currentSubDistrict"
:rules="[(val:string) => !!val || `${'กรุณาเลือก แขวง / ตำบล'}`]"
@update:model-value="(value:string) => selectSubDistrict(value, '2')"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'subdistrictCOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
dense
readonly
outlined
lazy-rules
hide-bottom-space
v-model="formData.currentZipCode"
:label="dataLabel.registrationZipCode"
/>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" id="onSubmit" type="submit" color="public">
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="modalHistory" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขข้อมูลที่อยู่"
:close="() => (modalHistory = false)"
/>
<q-separator color="grey-4" />
<q-card-section style="max-height: 50vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterHistory"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterHistory == ''"
name="search"
@click.stop.prevent="filterHistory = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterHistory"
name="cancel"
@click.stop.prevent="filterHistory = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-model="visibleColumnsHistory"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columnsHistory"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columnsHistory"
:rows="rowsHistory"
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumnsHistory"
:filter="filterHistory"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id">
<div>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>
<style scoped></style>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,670 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import { QForm, useQuasar } from "quasar";
import dialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import type { RequestItemsObject } from "@/modules/04_registryPerson/interface/request/SpecialSkill";
import type { ResponseObject } from "@/modules/04_registryPerson/interface/response/SpecialSkill";
import type { QTableProps } from "quasar";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
const mixin = useCounterMixin();
const $q = useQuasar();
const mode = ref<string>("table");
const {
dialogRemove,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
date2Thai,
} = mixin;
const columns = ref<QTableProps["columns"]>([
{
name: "field",
align: "left",
label: "ด้าน",
sortable: true,
field: "field",
headerStyle: "font-size: 14px; width: 50px;",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "detail",
align: "left",
label: "รายละเอียด",
sortable: true,
field: "detail",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "remark",
align: "left",
label: "หมายเหตุ",
sortable: true,
field: "remark",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "reference",
align: "left",
label: "เอกสารอ้างอิง",
sortable: true,
field: "reference",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const historyColumns = ref<QTableProps["columns"]>([
{
name: "field",
align: "left",
label: "ด้าน",
sortable: true,
field: "field",
headerStyle: "font-size: 14px; width: 50px;",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "detail",
align: "left",
label: "รายละเอียด",
sortable: true,
field: "detail",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "remark",
align: "left",
label: "หมายเหตุ",
sortable: true,
field: "remark",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "reference",
align: "left",
label: "เอกสารอ้างอิง",
sortable: true,
field: "reference",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lastUpdateFullName",
align: "left",
label: "ผู้ดำเนินการ",
sortable: true,
field: "lastUpdateFullName",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "lastUpdatedAt",
align: "left",
label: "วันที่แก้ไข",
sortable: true,
field: "lastUpdatedAt",
format: (v) => date2Thai(v),
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const historyDialog = ref<boolean>(false);
const dialog = ref<boolean>(false);
const dialogStatus = ref<string>("create");
const rows = ref<ResponseObject[]>([]);
const historyRows = ref<ResponseObject[]>([]);
const route = useRoute();
const id = ref<string>(route.params.id.toString());
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const editId = ref<string>("");
const keyword = ref<string>("");
const historyKeyword = ref<string>("");
const specialSkill = reactive<RequestItemsObject>({
field: "",
detail: "",
remark: "",
reference: "",
profileId: id.value,
dateStart: null,
dateEnd: null,
});
const pagination = ref({
page: 1,
rowsPerPage: 10,
});
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
const visibleColumns = ref<string[]>([
"field",
"detail",
"remark",
"reference",
]);
const historyVisibleColumns = ref<string[]>([
"field",
"detail",
"remark",
"reference",
"lastUpdateFullName",
"lastUpdatedAt",
]);
function closeDialog() {
dialog.value = false;
}
function closeHistoryDialog() {
historyDialog.value = false;
}
async function onSubmit() {
dialogConfirm(
$q,
async () => {
dialogStatus.value === "create" ? addData() : editData(editId.value);
closeDialog();
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
function clearForm() {
specialSkill.detail = "";
specialSkill.field = "";
specialSkill.reference = "";
specialSkill.remark = "";
}
function editForm(row: any) {
dialogStatus.value = "edit";
editId.value = row.id;
specialSkill.detail = row.detail;
specialSkill.field = row.field;
specialSkill.reference = row.reference;
specialSkill.remark = row.remark;
dialog.value = true;
}
async function fetchData(id: string) {
showLoader();
await http
.get(config.API.profileNewAbilityByProfileId(id, empType.value))
.then(async (res) => {
rows.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function fetchHistoryData(id: string) {
showLoader();
await http
.get(config.API.profileNewAbilityHisByAbilityId(id, empType.value))
.then(async (res) => {
historyRows.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function addData() {
await http
.post(config.API.profileNewAbility(empType.value), {
...specialSkill,
dateStart: null,
dateEnd: null,
profileId: empType.value === "" ? id.value : undefined,
profileEmployeeId: empType.value !== "" ? id.value : undefined,
})
.then(() => {
fetchData(id.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function editData(idData: string) {
await http
.patch(config.API.profileNewAbilityByAbilityId(idData, empType.value), {
...specialSkill,
dateStart: null,
dateEnd: null,
profileId: undefined,
})
.then(() => {
fetchData(id.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function deleteData(idData: string) {
dialogRemove($q, () =>
http
.delete(config.API.profileNewAbilityByAbilityId(idData, empType.value))
.then(() => {
fetchData(id.value);
success($q, "ลบข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
})
);
}
onMounted(async () => {
await fetchData(id.value);
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn
flat
round
color="primary"
dense
icon="add"
@click="() => ((dialogStatus = 'create'), clearForm(), (dialog = true))"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
<q-space />
<q-input dense outlined v-model="keyword" label="ค้นหา">
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
v-if="mode === 'table'"
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
<q-btn-toggle
v-model="mode"
dense
class="no-shadow toggle-borderd"
toggle-color="grey-4"
:options="[
{ value: 'table', slot: 'table' },
{ value: 'card', slot: 'card' },
]"
>
<template v-slot:table>
<q-icon
name="format_list_bulleted"
size="24px"
:style="{
color: mode === 'table' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
<template v-slot:card>
<q-icon
name="mdi-view-grid-outline"
size="24px"
:style="{
color: mode === 'card' ? '#787B7C' : '#C9D3DB',
}"
/>
</template>
</q-btn-toggle>
</div>
<d-table
:grid="mode === 'card'"
ref="table"
row-key="id"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
:filter="keyword"
v-model:pagination="pagination"
:rows-per-page-options="[20, 50, 100]"
:visible-columns="visibleColumns"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width />
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
</q-tr>
</template>
<template v-slot:body="props" v-if="mode === 'table'">
<q-tr :props="props" class="cursor-pointer">
<q-td auto-width>
<q-btn
color="primary"
flat
dense
round
class="q-mr-xs"
size="14px"
icon="mdi-pencil-outline"
clickable
@click="
() => {
editForm(props.row);
}
"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="
fetchHistoryData(props.row.id);
historyDialog = true;
"
>
<q-tooltip>ประวแกไขความสามารถพเศษ</q-tooltip>
</q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div>{{ col.value ? col.value : "-" }}</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div
class="q-pa-xs col-xs-12 col-sm-6 col-md-6 col-lg-6 grid-style-transition"
>
<q-card bordered>
<q-card-actions align="right" class="bg-grey-3">
<q-btn
flat
round
color="primary"
icon="mdi-pencil-outline"
size="14px"
@click="
() => {
editForm(props.row);
}
"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
flat
class="no-shadow toggle-borderd"
round
size="14px"
color="info"
icon="mdi-history"
@click="
fetchHistoryData(props.row.id);
historyDialog = true;
"
>
<q-tooltip>ประวแกไขความสามารถพเศษ</q-tooltip>
</q-btn>
</q-card-actions>
<q-separator />
<div class="row">
<div class="col q-pa-sm label-color">าน</div>
<div class="col q-pa-sm">{{ props.cols[0].value }}</div>
<div class="col q-pa-sm label-color">รายละเอยด</div>
<div class="col q-pa-sm">{{ props.cols[1].value }}</div>
</div>
<div :class="`row bg-color`">
<div class="col q-pa-sm label-color">หมายเหต</div>
<div class="col q-pa-sm">{{ props.cols[2].value }}</div>
<div class="col q-pa-sm label-color">เอกสารอางอ</div>
<div class="col q-pa-sm">{{ props.cols[3].value }}</div>
</div>
</q-card>
</div>
</template>
</d-table>
<q-dialog v-model="dialog" class="dialog" persistent>
<q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<dialog-header
:tittle="
dialogStatus == 'edit'
? 'แก้ไขข้อมูลความสามารถพิเศษ'
: 'เพิ่มข้อมูลความสามารถพิเศษ'
"
:close="closeDialog"
/>
<q-separator />
<q-card-section>
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
outlined
class="inputgreen"
dense
bg-color="white"
v-model="specialSkill.field"
label="ด้าน"
hide-bottom-space
:rules="[(val) => !!val || `${'กรุณากรอกด้านความสามารถพิเศษ'}`]"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
outlined
dense
class="inputgreen"
bg-color="white"
v-model="specialSkill.detail"
label="รายละเอียด"
hide-bottom-space
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
class="inputgreen"
outlined
dense
bg-color="white"
v-model="specialSkill.remark"
label="หมายเหตุ"
/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
class="inputgreen"
outlined
dense
bg-color="white"
v-model="specialSkill.reference"
label="เอกสารอ้างอิง"
/>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn label="บันทึก" id="onSubmit" type="submit" color="public">
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
</q-card-actions>
</q-form>
</q-card>
</q-dialog>
<q-dialog v-model="historyDialog" class="dialog" persistent>
<q-layout
view="lHh lpr lFf"
container
style="height: 500px; min-width: 80%"
class="bg-white"
>
<q-header>
<q-toolbar>
<dialog-header
tittle="ประวัติแก้ไขความสามารถพิเศษ"
:close="closeHistoryDialog"
/>
</q-toolbar>
<q-separator color="grey-4" />
</q-header>
<q-page-container>
<q-page class="q-pa-md">
<q-toolbar style="padding: 0px" class="text-primary q-mb-sm">
<q-space />
<q-input
dense
outlined
bg-color="white"
v-model="historyKeyword"
label="ค้นหา"
class="q-mr-sm"
>
<template v-slot:append>
<q-icon name="search" />
</template>
</q-input>
<q-select
v-model="historyVisibleColumns"
multiple
outlined
dense
bg-color="white"
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="historyColumns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</q-toolbar>
<d-table
ref="table"
:columns="historyColumns"
:rows="historyRows"
row-key="name"
flat
bordered
:paging="true"
dense
:filter="historyKeyword"
v-model:pagination="historyPagination"
:rows-per-page-options="[20, 50, 100]"
class="custom-header-table"
:visible-columns="historyVisibleColumns"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
<q-th auto-width />
</q-tr>
</template>
<template v-slot:body="props" v-if="mode === 'table'">
<q-tr :props="props" class="cursor-pointer">
<q-td v-for="col in props.cols" :key="col.id">
<div>{{ col.value ? col.value : "-" }}</div>
</q-td>
<q-td auto-width> </q-td>
</q-tr>
</template>
</d-table>
</q-page>
</q-page-container>
</q-layout>
</q-dialog>
</template>
<style scoped>
.label-color {
color: #747474cc;
}
.bg-color {
background-color: #fafafa;
}
</style>

View file

@ -0,0 +1,74 @@
<script setup lang="ts">
import { ref } from "vue";
/** importComponents*/
import Profile from "@/modules/04_registryPerson/components/detail/PersonalInformation/01_Profile.vue";
import NameChangeHistory from "@/modules/04_registryPerson/components/detail/PersonalInformation/02_NameChangeHistory.vue";
import Address from "@/modules/04_registryPerson/components/detail/PersonalInformation/03_Address.vue";
import Family from "@/modules/04_registryPerson/components/detail/PersonalInformation/04_Family.vue";
import Education from "@/modules/04_registryPerson/components/detail/PersonalInformation/05_Education.vue";
import SpecialSkill from "@/modules/04_registryPerson/components/detail/PersonalInformation/06_SpecialSkill.vue";
import FamilyNew from "@/modules/04_registryPerson/components/detail/PersonalInformation/04_FamilyNew.vue";
const tab = ref<string>("1");
const props = defineProps({
fetchDataPersonal: { type: Function, require: true },
});
</script>
<template>
<div class="row items-center q-my-md">
<div class="text-dark row items-center q-px-md">
<q-icon name="mdi-account" class="q-mr-md" size="22px" />
<div class="text-subtitle1 text-weight-bold">อมลสวนต</div>
</div>
</div>
<q-separator />
<q-card>
<q-tabs
v-model="tab"
active-color="blue-8"
align="left"
bordered
narrow-indicator
indicator-color="transparent"
dense
class="text-grey q-pl-sm"
>
<q-tab name="1" label="ประวัติส่วนตัว" />
<q-tab name="2" label="ประวัติการเปลี่ยนชื่อ-นามสกุล" />
<q-tab name="3" label="ข้อมูลที่อยู่" />
<q-tab name="4" label="ข้อมูลครอบครัว" />
<q-tab name="5" label="ประวัติการศึกษา" />
<q-tab name="6" label="ความสามารถพิเศษ" />
</q-tabs>
<q-separator />
<q-tab-panels v-model="tab" animated>
<q-tab-panel name="1">
<Profile :fetchDataPersonal="props.fetchDataPersonal" />
</q-tab-panel>
<q-tab-panel name="2">
<NameChangeHistory :fetchDataPersonal="props.fetchDataPersonal" />
</q-tab-panel>
<q-tab-panel name="3">
<Address />
</q-tab-panel>
<q-tab-panel name="4">
<FamilyNew />
</q-tab-panel>
<q-tab-panel name="5">
<Education />
</q-tab-panel>
<q-tab-panel name="6">
<SpecialSkill />
</q-tab-panel>
<!-- <q-tab-panel name="7">
<FamilyNew />
</q-tab-panel> -->
</q-tab-panels>
</q-card>
</template>
<style scoped></style>