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,867 @@
<script setup lang="ts">
import { ref, reactive, watch, onMounted } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import type {
RequestItemsHistoryObject,
FormMain,
} from "@/modules/04_registryPerson/interface/index/government";
import DialogHeader from "@/components/DialogHeader.vue";
import { useQuasar } from "quasar";
import type { QTableProps } from "quasar";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
/** ฟังชั่นกลาง */
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dateToISO,
dialogConfirm,
messageError,
showLoader,
hideLoader,
success,
} = mixin;
const profileId = ref<string>(route.params.id.toString());
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
/** ตัวแปรข้อมูลหลัก */
const formMain = reactive<FormMain>({
ocId: "", //
positionId: "", //
positionLine: "", //
positionLevel: "", //
numberId: "", //
positionExecutive: "", //
positionExecutiveSide: "", //
positionType: "", //
positionPathSide: "", ///
containDate: null, //
workDate: null, //
reasonSameDate: "",
retireDate: null, //
ageAll: {
year: 0,
month: 0,
day: 0,
}, //
absent: 0, //
age: 0, //
});
/** dialog */
const modalEdit = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const rowsHistory = ref<RequestItemsHistoryObject[]>([]);
const filterKeyword = ref<string>("");
const containDate = ref<Date | null>(null);
const workDate = ref<Date | null>(null);
const reasonSameDate = ref<string | null>(null);
const containDateRef = ref<object | null>(null);
const workDateRef = ref<object | null>(null);
const reasonSameDateRef = ref<object | null>(null);
const visibleColumnsHistory = ref<String[]>([
"oc",
"position",
"positionPathSide",
"posNo",
"positionLine",
"positionType",
"positionLevel",
"positionExecutive",
"positionExecutiveSide",
"dateAppoint",
"dateStart",
"retireDate",
"govAge",
"govAgeAbsent",
"govAgePlus",
"reasonSameDate",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "oc",
align: "left",
label: "สังกัด",
sortable: true,
field: "oc",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionPathSide",
align: "left",
label: "ตำแหน่ง",
sortable: true,
field: "positionPathSide",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "position",
align: "left",
label: "ด้าน/สาขา",
sortable: true,
field: "position",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "posNo",
align: "left",
label: "ตำแหน่งเลขที่",
sortable: true,
field: "posNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionLine",
align: "left",
label: "สายงาน",
sortable: true,
field: "positionLine",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionType",
align: "left",
label: "ประเภท",
sortable: true,
field: "positionType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionLevel",
align: "left",
label: "ระดับ",
sortable: true,
field: "positionLevel",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionExecutive",
align: "left",
label: "ตำแหน่งทางการบริหาร",
sortable: true,
field: "positionExecutive",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "positionExecutiveSide",
align: "left",
label: "ด้านทางการบริหาร",
sortable: true,
field: "positionExecutiveSide",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "dateAppoint",
align: "left",
label: "วันที่บรรจุ",
sortable: true,
field: "dateAppoint",
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" }),
},
{
name: "dateStart",
align: "left",
label: "เริ่มปฎิบัติราชการ",
sortable: true,
field: "dateStart",
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" }),
},
{
name: "retireDate",
align: "left",
label: "วันเกษียณอายุ",
sortable: true,
field: "retireDate",
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" }),
},
{
name: "govAge",
align: "left",
label: "อายุราชการ",
sortable: true,
field: "govAge",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "govAgeAbsent",
align: "left",
label: "ขาดราชการ",
sortable: true,
field: "govAgeAbsent",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "govAgePlus",
align: "left",
label: "อายุราชการเกื้อกูล",
sortable: true,
field: "govAgePlus",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "reasonSameDate",
align: "left",
label: "เหตุผลกรณีไม่ตรงวัน",
sortable: true,
field: "reasonSameDate",
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" }),
},
]);
/** เปิด dialog */
function openDialogEdit() {
modalEdit.value = true;
containDate.value = formMain.containDate ? formMain.containDate : null;
workDate.value = formMain.workDate ? formMain.workDate : null;
reasonSameDate.value = formMain.reasonSameDate
? formMain.reasonSameDate
: null;
}
function openDialogHistory() {
modalHistory.value = true;
filterKeyword.value = "";
getDataHistory();
}
/** ปิด dialog */
function closeDialog() {
modalEdit.value = false;
containDate.value = null;
workDate.value = null;
reasonSameDate.value = null;
}
function onSubmit() {
dialogConfirm($q, () => {
showLoader();
http
.patch(
config.API.profileNewGovernmentById(profileId.value, empType.value),
{
dateAppoint: containDate.value,
dateStart: workDate.value,
reasonSameDate:
dateToISO(containDate.value as Date) ===
dateToISO(workDate.value as Date)
? ""
: reasonSameDate.value,
}
)
.then(() => {
getData();
success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
});
}
/** ดึงข้อมูลราชการ */
function getData() {
showLoader();
http
.get(config.API.profileNewGovernmentById(profileId.value, empType.value))
.then((res) => {
const data = res.data.result;
formMain.ocId = data.org ?? "-"; //
formMain.positionId = data.position ?? "-"; //
formMain.positionLine = data.positionField ?? "-"; //
formMain.positionLevel = data.posLevel ?? "-"; //
formMain.numberId = data.posMasterNo ?? "-"; //
formMain.positionType = data.posType ?? "-"; //
formMain.positionExecutive = data.posExecutive ?? "-"; //
formMain.positionPathSide = data.positionArea ?? "-"; //
formMain.positionExecutiveSide = data.positionExecutiveField ?? "-"; //
formMain.containDate = data.dateAppoint;
formMain.workDate = data.dateStart;
formMain.reasonSameDate = data.reasonSameDate;
formMain.retireDate = data.dateLeave;
formMain.dateRetireLaw = data.dateRetireLaw;
formMain.ageAll = data.govAge;
formMain.absent = data.govAgeAbsent;
formMain.age = data.govAgePlus;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/** ดึงข้อมูลประวัติ */
function getDataHistory() {
showLoader();
http
.get(config.API.profileNewGovernmentHistory(profileId.value, empType.value))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: RequestItemsHistoryObject) => {
rowsHistory.value.push({
oc: e.oc,
position: e.position,
positionPathSide: e.positionPathSide,
posNo: e.posNo,
positionLine: e.positionLine,
positionType: e.positionType,
positionLevel: e.positionLevel,
positionExecutive: e.positionExecutive,
positionExecutiveSide: e.positionExecutiveSide,
dateAppoint: new Date(e.dateAppoint),
dateStart: new Date(e.dateStart),
dateRetire: e.dateRetire,
dateRetireLaw: e.dateRetireLaw,
govAge: e.govAge,
govAgeAbsent: e.govAgeAbsent,
govAgePlus: e.govAgePlus,
reasonSameDate: e.reasonSameDate,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
lastUpdatedAt: e.lastUpdatedAt,
lastUpdateFullName: e.lastUpdateFullName,
});
});
})
.catch((e) => {
messageError($q, e);
modalHistory.value = false;
})
.finally(() => {
hideLoader();
});
}
onMounted(() => {
getData();
});
</script>
<template>
<div class="row">
<q-space />
<div class="q-gutter-x-sm">
<q-btn
color="primary"
icon="mdi-pencil-outline"
flat
dense
round
@click="openDialogEdit()"
><q-tooltip>แกไขขอม</q-tooltip></q-btn
>
<q-btn
color="info"
icon="mdi-history"
flat
dense
round
@click="openDialogHistory()"
><q-tooltip>ประวอมลราชการ</q-tooltip></q-btn
>
</div>
</div>
<q-card bordered class="bg-grey-1 q-pa-md q-mt-sm">
<div class="row q-col-gutter-md">
<div class="col-12 col-sm-6 col-md-6 q-gutter-y-sm">
<div class="row items-center">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>งก</div>
</div>
<div class="col-12 col-sm-12 col-md-7">{{ formMain.ocId }}</div>
</div>
<div class="row items-center">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>{{ empType === "" ? `ตำแหน่งในสายงาน` : `ตำแหน่ง` }}</div>
</div>
<div class="col-12 col-sm-12 col-md-7">{{ formMain.positionId }}</div>
</div>
<div class="row items-center">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>ตำแหนงเลขท</div>
</div>
<div class="col-12 col-sm-12 col-md-7">{{ formMain.numberId }}</div>
</div>
<div class="row items-center" v-if="empType === ''">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>ตำแหนงทางการบรหาร</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionExecutive }}
</div>
</div>
<div class="row items-center" v-if="empType === ''">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>านทางการบรหาร</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionExecutiveSide }}
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6 q-gutter-y-sm">
<div class="row items-center" v-if="empType === ''">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>สายงาน</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionLine }}
</div>
</div>
<div class="row items-center">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>{{ empType === "" ? "ตำแหน่งประเภท" : "กลุ่มงาน" }}</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionType }}
</div>
</div>
<div class="row items-center">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>{{ empType === "" ? "ระดับ" : "ระดับชั้นงาน" }}</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionLevel }}
</div>
</div>
<div class="row items-center" v-if="empType === ''">
<div class="col-12 col-sm-12 col-md-5 text-grey-6 text-weight-medium">
<div>าน/สาขา</div>
</div>
<div class="col-12 col-sm-12 col-md-7">
{{ formMain.positionPathSide }}
</div>
</div>
</div>
</div>
<q-separator color="grey-4" class="q-my-md" />
<div class="row q-col-gutter-md">
<div class="col-12 col-sm-6 col-md-6 q-gutter-y-sm">
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>นทงบรรจ</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.containDate ? date2Thai(formMain.containDate) : "-"
}}</span>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>นทเรมปฏราชการ</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.workDate !== null
? date2Thai(formMain.workDate as Date)
: "-"
}}</span>
</div>
</div>
</div>
<div
v-if="dateToISO(formMain.containDate as Date) !== dateToISO(formMain.workDate as Date)"
class="col-12 col-sm-6 col-md-6"
>
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>เหตผลทนทไมตรงก</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.reasonSameDate !== "" ? formMain.reasonSameDate : "-"
}}</span>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>นครบเกษยณอาย</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.retireDate
? date2Thai(formMain.retireDate as Date)
: "-"
}}</span>
</div>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6 q-gutter-y-sm">
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium">อายราชการ</span>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.ageAll
? `${formMain.ageAll.day} วัน ${formMain.ageAll.month} เดือน ${formMain.ageAll.year} ปี`
: "-"
}}</span>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium">ขาดราชการ</span>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{ formMain.absent ? formMain.absent : 0 }}</span>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>อายราชการเกอก</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{ formMain.age ? formMain.age : 0 }}</span>
</div>
</div>
</div>
<div class="col-12 col-sm-6 col-md-6">
<div class="row">
<div class="col-12 col-sm-12 col-md-5">
<span class="text-grey-6 text-weight-medium"
>นทเกษยณอายราชการตามกฏหมาย</span
>
</div>
<div class="col-12 col-sm-12 col-md-7">
<span>{{
formMain.dateRetireLaw
? date2Thai(formMain.dateRetireLaw as Date)
: "-"
}}</span>
</div>
</div>
</div>
</div>
</div>
</q-card>
<!-- dialog edit -->
<q-dialog v-model="modalEdit" persistent>
<q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit">
<DialogHeader tittle="แก้ไขข้อมูลราชการ" :close="closeDialog" />
<q-separator color="grey-4" />
<q-card-section>
<div class="row q-col-gutter-sm">
<div class="col-xs-12 col-md-6">
<datepicker
v-model="containDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="containDateRef"
class="full-width inputgreen cursor-pointer"
hide-bottom-space
dense
outlined
:model-value="containDate !== null
? date2Thai(containDate as Date)
: null
"
:rules="[
(val) => !!val || 'กรุณาเลือก วัน/เดือน/ปี ที่บรรจุ',
]"
label="วัน/เดือน/ปี ที่บรรจุ"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="'color: var(--q-primary)'"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-12 col-md-6">
<datepicker
v-model="workDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
ref="workDateRef"
class="full-width inputgreen cursor-pointer"
hide-bottom-space
dense
outlined
:model-value="workDate !== null
? date2Thai(workDate as Date)
: null
"
:rules="[(val) => !!val || 'กรุณาเลือกเริ่มปฎิบัติราชการ']"
label="วัน/เดือน/ปี เริ่มปฎิบัติราชการ"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="'color: var(--q-primary)'"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div
class="col-12"
v-if="containDate && workDate ? dateToISO(containDate as Date) !== dateToISO(workDate as Date) : false"
>
<q-input
ref="reasonSameDateRef"
class="full-width inputgreen cursor-pointer"
label="เหตุผลกรณีไม่ตรงกัน"
type="textarea"
outlined
dense
hide-bottom-space
:rules="[(val) => !!val || 'กรุณากรอก เหตุผลกรณีไม่ตรงกัน']"
v-model="reasonSameDate"
/>
</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>
<!-- dialog History -->
<q-dialog v-model="modalHistory" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขข้อมูลราชการ"
:close="() => (modalHistory = !modalHistory)"
/>
<q-separator color="grey-4" />
<q-card-section style="max-height: 50vh" class="scroll">
<div class="row q-pb-sm q-gutter-x-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
class="col-2"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
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"
:columns="columnsHistory"
:rows="rowsHistory"
flat
bordered
:paging="true"
dense
class="custom-header-table"
:filter="filterKeyword"
:visible-columns="visibleColumnsHistory"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th
v-for="col in props.cols"
:key="col.name"
:props="props"
style="color: #000000; font-weight: 500"
>
<span class="text-weight-medium">{{ col.label }}</span>
</q-th>
<q-th auto-width></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.name" :props="props">
<div>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>
<style scoped></style>

View file

@ -0,0 +1,743 @@
<script setup lang="ts">
import { ref, onMounted, reactive } from "vue";
import type { QTableProps } from "quasar";
import type {
RequestItemsObject,
FormFilter,
DataOption,
DisciplineOps,
} from "@/modules/04_registryPerson/interface/index/discipline";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import DialogHeader from "@/components/DialogHeader.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/02_DisciplineHistory.vue";
import { useRoute } from "vue-router";
const route = useRoute();
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dialogConfirm,
showLoader,
hideLoader,
messageError,
success,
dialogRemove,
} = mixin;
const disciplineData = reactive<RequestItemsObject>({
date: null,
level: "",
detail: "",
unStigma: "",
refCommandNo: "",
profileId: profileId.value,
refCommandDate: null,
});
const rows = ref<RequestItemsObject[]>([]);
const mode = ref<string>("table");
const filterKeyword = ref<string>("");
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const pagination = ref({
page: 1,
rowsPerPage: 10,
});
const visibleColumns = ref<String[]>([
"level",
"detail",
"unStigma",
"refCommandNo",
"refCommandDate",
"date",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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" }),
},
{
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: "level",
align: "left",
label: "ระดับการลงโทษทางวินัย",
sortable: true,
field: "level",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "unStigma",
align: "left",
label: "ประเภทคำสั่ง",
sortable: true,
field: "unStigma",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandDate",
align: "left",
label: "เอกสารอ้างอิง (ลงวันที่)",
sortable: true,
field: "refCommandDate",
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 dateRef = ref<object | null>(null);
const detailRef = ref<object | null>(null);
const refCommandNoRef = ref<object | null>(null);
/** dialog */
const edit = ref<boolean>(false);
const modal = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const id = ref<string>("");
const Ops = ref<any>({
levelOptions: [
{ id: "0", name: "ไม่ร้ายแรง", disable: true },
{ id: "ภาคทัณฑ์", name: "ภาคทัณฑ์", disable: false },
{
id: "ตัดเงินเดือน",
name: "ตัดเงินเดือน",
disable: false,
},
{
id: "ลดขั้นเงินเดือน",
name: "ลดขั้นเงินเดือน",
disable: false,
},
{ id: "4", name: "ร้ายแรง", disable: true },
{ id: "ปลดออก", name: "ปลดออก", disable: false },
{ id: "ไล่ออก", name: "ไล่ออก", disable: false },
{ id: "อื่นๆ", name: "อื่นๆ", disable: false },
],
});
const OpsFilter = ref<any>({
levelOptions: [
{ id: "0", name: "ไม่ร้ายแรง", disable: true },
{ id: "ภาคทัณฑ์", name: "ภาคทัณฑ์", disable: false },
{
id: "ตัดเงินเดือน",
name: "ตัดเงินเดือน",
disable: false,
},
{
id: "ลดขั้นเงินเดือน",
name: "ลดขั้นเงินเดือน",
disable: false,
},
{ id: "4", name: "ร้ายแรง", disable: true },
{ id: "ปลดออก", name: "ปลดออก", disable: false },
{ id: "ไล่ออก", name: "ไล่ออก", disable: false },
{ id: "อื่นๆ", name: "อื่นๆ", disable: false },
],
});
function filterSelector(val: string, update: Function, refData: string) {
switch (refData) {
case "levelOptions":
update(() => {
Ops.value.levelOptions = OpsFilter.value.levelOptions.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
}
/** ปิด dialog */
function closeDialog() {
modal.value = false;
edit.value = false;
disciplineData.date = null;
disciplineData.detail = "";
disciplineData.level = "";
disciplineData.unStigma = "";
disciplineData.refCommandNo = "";
disciplineData.refCommandDate = null;
}
function openDialogAdd() {
modal.value = true;
}
async function fetchData(id: string) {
showLoader();
await http
.get(config.API.profileNewDisciplineByProfileId(id, empType.value))
.then(async (res) => {
rows.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function addData() {
const body = {
date: disciplineData.date,
level: disciplineData.level,
detail: disciplineData.detail,
unStigma: disciplineData.unStigma,
refCommandNo: disciplineData.refCommandNo,
profileId: empType.value === "" ? disciplineData.profileId : undefined,
profileEmployeeId:
empType.value !== "" ? disciplineData.profileId : undefined,
refCommandDate: disciplineData.refCommandDate,
};
await http
.post(config.API.profileNewDiscipline(empType.value), body)
.then(() => {
fetchData(profileId.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
async function editData(idData: string) {
await http
.patch(
config.API.profileNewDisciplineByDisciplineId(idData, empType.value),
{
...disciplineData,
profileId: undefined,
}
)
.then(() => {
fetchData(profileId.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
// function deleteData(idData: string) {
// dialogRemove($q, () =>
// http
// .delete(config.API.profileNewDisciplineByDisciplineId(idData))
// .then(() => {
// fetchData(profileId.value);
// success($q, "");
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// })
// );
// }
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
function openDialogEdit(props: RequestItemsObject) {
modal.value = true;
edit.value = true;
id.value = props.id ? props.id : "";
disciplineData.date = props.date;
disciplineData.detail = props.detail;
disciplineData.level = props.level;
disciplineData.unStigma = props.unStigma;
disciplineData.refCommandNo = props.refCommandNo;
disciplineData.refCommandDate = props.refCommandDate;
}
function openDialogHistory(idOrder: string) {
modalHistory.value = true;
id.value = idOrder;
}
async function onSubmit() {
dialogConfirm(
$q,
async () => {
edit.value ? editData(id.value) : addData();
closeDialog();
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
onMounted(async () => {
await fetchData(profileId.value);
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn dense color="primary" icon="add" flat round @click="openDialogAdd()"
><q-tooltip>เพมขอม</q-tooltip></q-btn
>
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-if="mode == 'table'"
v-model="visibleColumns"
multiple
outlined
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
:card-container-class="mode === 'card' ? 'q-col-gutter-md' : ''"
:grid="mode === 'card'"
ref="table"
row-key="id"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
:filter="filterKeyword"
v-model:pagination="pagination"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<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="openDialogEdit(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="openDialogHistory(props.row.id)"
>
<q-tooltip>ประวแกไขว</q-tooltip>
</q-btn>
<!-- <q-btn
color="red"
flat
dense
round
size="14px"
icon="mdi-delete"
clickable
@click.stop="deleteData(props.row.id)"
v-close-popup
>
<q-tooltip>ลบขอม</q-tooltip>
</q-btn> -->
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize + props.rowIndex + 1
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-card flat bordered class="q-pa-none">
<div class="row bg-grey-3">
<q-space />
<div class="q-gutter-x-sm">
<q-btn
color="primary"
icon="mdi-pencil-outline"
flat
round
@click="openDialogEdit(props.row)"
><q-tooltip>แกไข</q-tooltip></q-btn
>
<q-btn
color="info"
icon="mdi-history"
flat
round
@click="openDialogHistory(props.row.id)"
><q-tooltip>ประวแกไขว</q-tooltip></q-btn
>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
ระดบการลงโทษทางว
</div>
<div class="col-3">
{{ props.row.level !== "" ? props.row.level : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">
/เดอน/
</div>
<div class="col-3">
{{ props.row.date ? date2Thai(props.row.date) : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">างมลท</div>
<div class="col-3">
{{ props.row.unStigma !== "" ? props.row.unStigma : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">
เลขทคำส
</div>
<div class="col-3">
{{
props.row.refCommandNo !== "" ? props.row.refCommandNo : "-"
}}
</div>
</div>
<q-separator />
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
เอกสารอางอ (ลงวนท)
</div>
<div class="col-3">
{{
props.row.refCommandDate
? date2Thai(props.row.refCommandDate)
: "-"
}}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">รายละเอยด</div>
<div class="col-9">
{{ props.row.detail !== "" ? props.row.detail : "-" }}
</div>
</div>
</q-card-section>
</q-card>
</div>
</template>
</d-table>
<!-- dialog add edit -->
<q-dialog v-model="modal" persistent>
<q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<DialogHeader
:tittle="edit ? 'แก้ไขข้อมูลวินัย' : 'เพิ่มข้อมูลวินัย'"
:close="closeDialog"
/>
<q-separator color="grey-4" />
<q-card-section style="max-height: 50vh" class="scroll">
<div class="row col-12 q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="disciplineData.date"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(disciplineData.date)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วัน/เดือน/ปี'}`]"
hide-bottom-space
:label="`${'วัน/เดือน/ปี'}`"
>
<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-12 col-sm-6 col-md-6">
<q-input
ref="detailRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="disciplineData.detail"
:rules="[(val:string) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<selector
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="disciplineData.level"
:label="`${'ระดับการลงโทษทางวินัย'}`"
emit-value
map-options
option-label="name"
:options="Ops.levelOptions"
option-value="id"
use-input
clearable
hide-bottom-space
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'levelOptions'
) "
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
v-model="disciplineData.unStigma"
hide-bottom-space
:label="`${'ประเภทคำสั่ง'}`"
/>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-input
ref="refCommandNoRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="disciplineData.refCommandNo"
hide-bottom-space
:label="`${'เลขที่คำสั่ง'}`"
:rules="[(val:string) => !!val || `${'กรุณากรอกเลขที่คำสั่ง'}`]"
>
<template v-slot:append>
<q-icon name="mdi-file" class="cursor-pointer" />
</template>
</q-input>
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="disciplineData.refCommandDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateRef"
class="full-width inputgreen cursor-pointer"
outlined
clearable
dense
:model-value="date2Thai(disciplineData.refCommandDate)"
hide-bottom-space
:label="`${'เอกสารอ้างอิง (ลงวันที่)'}`"
@clear="disciplineData.refCommandDate = null"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</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>
<DialogHistory v-model:modal="modalHistory" v-model:id="id" />
</template>
<style scoped></style>

View file

@ -0,0 +1,282 @@
<script setup lang="ts">
import { ref, watch, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar, type QTableProps } from "quasar";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
RequestItemsObject,
FormFilter,
} from "@/modules/04_registryPerson/interface/index/discipline";
const modal = defineModel<boolean>("modal", { required: true });
const id = defineModel<string>("id", { required: true });
const $q = useQuasar();
const route = useRoute();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError, date2Thai } = mixin;
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const filterKeyword = ref<string>("");
const rows = ref<RequestItemsObject[]>([]); //select data history
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
const visibleColumns = ref<String[]>([
"level",
"detail",
"unStigma",
"refCommandNo",
"refCommandDate",
"date",
"createdFullName",
"createdAt",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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" }),
},
{
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: "level",
align: "left",
label: "ระดับการลงโทษทางวินัย",
sortable: true,
field: "level",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "unStigma",
align: "left",
label: "ล้างมลทิน",
sortable: true,
field: "unStigma",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandDate",
align: "left",
label: "เอกสารอ้างอิง (ลงวันที่)",
sortable: true,
format: (v) => date2Thai(v),
field: "refCommandDate",
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 empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
function getHistory() {
showLoader();
http
.get(
config.API.profileNewDisciplineHisByDisciplineId(id.value, empType.value)
)
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: RequestItemsObject) => {
rows.value.push({
...e,
id: e.id,
level: e.level,
detail: e.detail,
unStigma: e.unStigma,
refCommandNo: e.refCommandNo,
refCommandDate:
e.refCommandDate == null ? null : new Date(e.refCommandDate),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
watch(modal, (status) => {
if (status == true) {
getHistory();
filterKeyword.value = "";
} else {
filterKeyword.value = "";
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80%">
<DialogHeader tittle="ประวัติแก้ไขวินัย" :close="() => (modal = false)" />
<q-separator color="grey-4" />
<q-card-section style="max-height: 60vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
v-model:pagination="historyPagination"
:filter="filterKeyword"
>
>
<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 v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize +
props.rowIndex +
1
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -0,0 +1,815 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import { useRoute } from "vue-router";
import { useQuasar, type QTableProps } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import DialogHeader from "@/components/DialogHeader.vue";
import type {
DetailData,
FormFilter,
DataOptionLeave,
DataOption,
ResponseTotalObject,
MyObjectRef,
} from "@/modules/04_registryPerson/interface/index/leave";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/03_LeaveHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
const rowsTotal = ref<ResponseTotalObject[]>([]);
const id = ref<string>("");
const route = useRoute();
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const $q = useQuasar();
const mixin = useCounterMixin();
const {
dialogConfirm,
messageError,
showLoader,
hideLoader,
success,
date2Thai,
dateToISO,
} = mixin;
const pagination = ref({
page: 1,
rowsPerPage: 10,
});
const mode = ref<string>("table");
const filterKeyword = ref<string>("");
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const rows = ref<DetailData[]>([]);
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const modal = ref<boolean>(false);
const edit = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const reason = ref<string>(""); //
const numLeave = ref<number>(1);
const dateRange = ref<[Date, Date]>([new Date(), new Date()]);
const numUsedLeave = ref<number>(0);
const typeLeave = ref<any>();
const typeLeaveOption = ref<DataOptionLeave[]>([]);
const typeLeaveOptionFilter = ref<DataOptionLeave[]>([]);
const statLeave = ref<string>("");
const statLeaveOption = ref<DataOption[]>([
{ id: "approve", name: "ผ่านการอนุมัติ" },
{ id: "reject", name: "ไม่ผ่านการอนุมัติ" },
{ id: "cancel", name: "ยกเลิก" },
{ id: "waitting", name: "รออนุมัติ" },
]);
const statLeaveOptionFilter = ref<DataOption[]>([
{ id: "approve", name: "ผ่านการอนุมัติ" },
{ id: "reject", name: "ไม่ผ่านการอนุมัติ" },
{ id: "cancel", name: "ยกเลิก" },
{ id: "waitting", name: "รออนุมัติ" },
]);
const statusLeave = (val: string) => {
switch (val) {
case "waitting":
return "รออนุมัติ";
case "reject":
return "ไม่ผ่านการอนุมัติ";
case "approve":
return "ผ่านการอนุมัติ";
case "cancel":
return "ยกเลิก";
default:
return "-";
}
};
const clickEditRowType = () => {
const filter = typeLeaveOptionFilter.value.filter(
(v: DataOptionLeave) => v.id == typeLeave.value
);
if (filter.length > 0) {
numUsedLeave.value = filter[0].totalLeave;
}
};
const typeLeaveRef = ref<object | null>(null);
const dateRangeRef = ref<object | null>(null);
const numLeaveRef = ref<object | null>(null);
const statLeaveRef = ref<object | null>(null);
const reasonRef = ref<object | null>(null);
const objectRef: MyObjectRef = {
typeLeave: typeLeaveRef,
dateRange: dateRangeRef,
numLeave: numLeaveRef,
statLeave: statLeaveRef,
reason: reasonRef,
};
const visibleColumns = ref<String[]>([
"no",
"typeLeave",
"dateLeave",
"numLeave",
"status",
"reason",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: false,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "typeLeave",
align: "left",
label: "ประเภทการลา",
sortable: true,
field: "typeLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "dateLeave",
align: "left",
label: "วัน เดือน ปี ที่ลา",
sortable: true,
field: "dateLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "numLeave",
align: "left",
label: "จำนวนวันลา",
sortable: true,
field: "numLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "status",
align: "left",
label: "สถานะ",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "reason",
align: "left",
label: "เหตุผล",
sortable: true,
field: "reason",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
function openDialogAdd() {
modal.value = true;
edit.value = false;
showLoader();
http
.get(config.API.profileNewLeaveType())
.then((res) => {
const dataOp = res.data.result.map((item: any) => ({
id: item.id,
name: item.name,
code: item.code,
}));
typeLeaveOption.value = dataOp;
typeLeaveOptionFilter.value = dataOp;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
function clickTotal() {
rowsTotal.value = [];
showLoader();
http
.get(config.API.profileNewLeaveType())
.then((res) => {
const dataOp = res.data.result.map((item: DataOption) => ({
id: item.id,
name: item.name,
}));
typeLeaveOption.value = dataOp;
typeLeaveOptionFilter.value = dataOp;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
function openDialogEdit(props: DetailData) {
edit.value = true;
modal.value = true;
id.value = props.id;
typeLeave.value = {
id: props.typeLeaveId,
name: props.typeLeave,
code: props.code,
};
statLeave.value = props.status;
reason.value = props.reason;
dateRange.value = [
new Date(props.dateStartLeave as Date),
new Date(props.dateEndLeave as Date),
];
numLeave.value = props.numLeave;
clickTotal();
if (rowsTotal.value.length > 0) {
let data: DataOptionLeave[] = [];
rowsTotal.value.map((e: ResponseTotalObject) => {
data.push({
id: e.typeLeaveId,
name: e.typeLeave,
totalLeave: e.totalLeave,
});
});
typeLeaveOption.value = data;
typeLeaveOptionFilter.value = data;
}
}
/** ปิด dialog */
function closeDialog() {
modal.value = false;
edit.value = false;
id.value = "";
typeLeave.value = "";
statLeave.value = "";
reason.value = "";
dateRange.value = [new Date(), new Date()];
numLeave.value = 1;
numUsedLeave.value = 0;
}
function filterSelector(val: any, update: Function, filtername: string) {
switch (filtername) {
case "typeLeaveOption":
update(() => {
typeLeaveOption.value = typeLeaveOptionFilter.value.filter(
(v: DataOptionLeave) =>
v.name.toLowerCase().indexOf(val.toLowerCase()) > -1
);
});
break;
case "statLeaveOption":
update(() => {
statLeaveOption.value = statLeaveOptionFilter.value.filter(
(v: DataOption) =>
v.name.toLowerCase().indexOf(val.toLowerCase()) > -1
);
});
break;
default:
break;
}
}
/**
* แปลงชวงวนทา2คาเปนวนเดยวกนจะโชววนเดยวแตาไมเทากนจะแสดงเปนชวง
* @param val วงวนท
*/
function dateThaiRange(val: [Date, Date]) {
if (val === null) {
} else if (date2Thai(val[0]) === date2Thai(val[1])) {
return `${date2Thai(val[0])}`;
} else {
return `${date2Thai(val[0])} - ${date2Thai(val[1])} `;
}
}
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
function openDialogHistory(idOrder: string) {
modalHistory.value = true;
id.value = idOrder;
}
/** validate check*/
function validateForm() {
const hasError = [];
for (const key in objectRef) {
if (Object.prototype.hasOwnProperty.call(objectRef, key)) {
const property = objectRef[key];
if (property.value && typeof property.value.validate === "function") {
const isValid = property.value.validate();
hasError.push(isValid);
}
}
}
if (hasError.every((result) => result === true)) {
dialogConfirm($q, async () => {
if (edit.value == false) {
saveData();
} else {
editData();
}
});
}
}
/**
* นทกเพมขอม
*/
function saveData() {
showLoader();
http
.post(config.API.profileNewLeave(empType.value), {
leaveTypeId: typeLeave.value.id,
dateLeaveStart: dateToISO(dateRange.value[0]),
dateLeaveEnd: dateToISO(dateRange.value[1]),
leaveDays: numLeave.value,
leaveCount: 0,
totalLeave: 0,
status: statLeave.value,
reason: reason.value,
profileId: empType.value === "" ? profileId.value : undefined,
profileEmployeeId: empType.value !== "" ? profileId.value : undefined,
})
.then(() => {
success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
getData();
});
}
/**
* นทกแกไขขอม
*/
const editData = async () => {
showLoader();
http
.patch(config.API.profileNewLeaveById(id.value, empType.value), {
leaveTypeId: typeLeave.value.id,
dateLeaveStart: dateToISO(dateRange.value[0]),
dateLeaveEnd: dateToISO(dateRange.value[1]),
leaveDays: numLeave.value,
leaveCount: 0,
totalLeave: 0,
status: statLeave.value,
reason: reason.value,
})
.then(() => {
success($q, "บันทึกข้อมูลสำเร็จ");
closeDialog();
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
getData();
});
};
function getData() {
showLoader();
http
.get(config.API.profileNewLeaveById(profileId.value, empType.value))
.then((res) => {
console.log(res.data.result);
const data = res.data.result;
rows.value = data.map((item: any) => ({
id: item.id,
typeLeave: item.leaveType.name,
code: item.leaveType.refCommandDate,
dateStartLeave: item.dateLeaveStart,
dateEndLeave: item.dateLeaveEnd,
numLeave: item.leaveDays,
status: item.status,
reason: item.reason,
typeLeaveId: item.leaveTypeId,
}));
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
onMounted(() => {
getData();
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn dense color="primary" icon="add" flat round @click="openDialogAdd()"
><q-tooltip>เพมขอม</q-tooltip></q-btn
>
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-if="mode == 'table'"
v-model="visibleColumns"
multiple
outlined
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
ref="table"
flat
bordered
dense
:card-container-class="mode === 'card' ? 'q-col-gutter-md' : ''"
:columns="columns"
:rows="rows"
:grid="mode === 'card'"
:paging="true"
v-model:pagination="pagination"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
:filter="filterKeyword"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<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="openDialogEdit(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="openDialogHistory(props.row.id)"
>
<q-tooltip>ประวแกไขการลา</q-tooltip>
</q-btn>
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize + props.rowIndex + 1
}}
</div>
<div v-else-if="col.name == 'dateLeave'">
{{
dateThaiRange([props.row.dateStartLeave, props.row.dateEndLeave])
}}
</div>
<div v-else-if="col.name == 'status'">
{{ statusLeave(col.value) }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div class="col-xs-12 col-sm-12 col-md-12 col-lg-6">
<q-card flat bordered class="q-pa-none">
<div class="row bg-grey-3">
<q-space />
<div class="q-gutter-x-sm">
<q-btn
color="primary"
icon="mdi-pencil-outline"
flat
round
@click="openDialogEdit(props.row)"
><q-tooltip>แกไขขอม</q-tooltip></q-btn
>
<q-btn
color="info"
icon="mdi-history"
flat
round
@click="openDialogHistory(props.row.id)"
><q-tooltip>ประวแกไขการลา</q-tooltip></q-btn
>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
ประเภทการลา
</div>
<div class="col-9">
{{ props.row.typeLeave !== "" ? props.row.typeLeave : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">
/เดอน/ ลา
</div>
<div class="col-3">
{{
props.row.dateStartLeave
? date2Thai(props.row.dateStartLeave)
: "-"
}}
</div>
<div class="col-3 text-grey-6 text-weight-medium">จำนวนวนลา</div>
<div class="col-3">
{{ props.row.numLeave ? props.row.numLeave : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">สถานะ</div>
<div class="col-3">
{{ props.row.status ? statusLeave(props.row.status) : "-" }}
</div>
<div class="col-3 text-grey-6 text-weight-medium">เหตผล</div>
<div class="col-3">
{{ props.row.reason !== "" ? props.row.reason : "-" }}
</div>
</div>
</q-card-section>
</q-card>
</div>
</template>
</d-table>
<!-- dialog add edit -->
<q-dialog v-model="modal" persistent>
<q-card>
<form @submit.prevent="validateForm">
<DialogHeader
:tittle="edit ? 'แก้ไขข้อมูลการลา' : 'เพิ่มข้อมูลการลา'"
:close="closeDialog"
/>
<q-separator color="grey-4" />
<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-select
ref="typeLeaveRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="typeLeave"
:rules="[(val:string) => !!val || `${'กรุณาเลือกประเภทการลา'}`]"
hide-bottom-space
:label="`${'ประเภทการลา'}`"
@update:modelValue="clickEditRowType"
map-options
option-label="name"
:options="typeLeaveOption"
option-value="id"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'typeLeaveOption'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
:readonly="!typeLeave"
menu-class-name="modalfix"
v-model="dateRange"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
range
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:readonly="!typeLeave"
class="full-width inputgreen cursor-pointer"
outlined
dense
ref="dateRangeRef"
:model-value="dateThaiRange(dateRange)"
:rules="[(val:string) => !!val || `${'กรุณาเลือกวัน เดือน ปีที่ลา'}`]"
hide-bottom-space
:label="`${'วัน เดือน ปีที่ลา'}`"
>
<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
ref="numLeaveRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="numLeave"
type="number"
:rules="[(val:string) => !!val || `${'กรุณากรอกจำนวนวันที่ลา'}`]"
hide-bottom-space
:label="`${'จำนวนวันที่ลา'}`"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
ref="statLeaveRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="statLeave"
:rules="[(val:string) => !!val || `${'กรุณาเลือกสถานะการลา'}`]"
hide-bottom-space
:label="`${'สถานะการลา'}`"
emit-value
map-options
option-label="name"
:options="statLeaveOption"
option-value="id"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'statLeaveOption'
) "
/>
</div>
<div class="col-xs-12 col-sm-12 col-md-12">
<q-input
ref="reasonRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="reason"
type="textarea"
:rules="[(val:string) => !!val || `${'กรุณากรอกเหตุผล'}`]"
hide-bottom-space
: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>
</form>
</q-card>
</q-dialog>
<DialogHistory v-model:modal="modalHistory" v-model:id="id" />
</template>
<style scoped></style>

View file

@ -0,0 +1,319 @@
<script setup lang="ts">
import { ref, watch, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar, type QTableProps } from "quasar";
import { useRoute } from "vue-router";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
DetailData,
FormFilter,
} from "@/modules/04_registryPerson/interface/index/leave";
const modal = defineModel<boolean>("modal", { required: true });
const id = defineModel<string>("id", { required: true });
const $q = useQuasar();
const route = useRoute();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError, date2Thai } = mixin;
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const filterKeyword = ref<string>("");
const rows = ref<DetailData[]>([]); //select data history
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
const visibleColumns = ref<String[]>([
"no",
"typeLeave",
"dateLeave",
"numLeave",
"sumLeave",
"totalLeave",
"status",
"reason",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: false,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "typeLeave",
align: "left",
label: "ประเภทการลา",
sortable: true,
field: "typeLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "dateLeave",
align: "left",
label: "วัน เดือน ปี ที่ลา",
sortable: true,
field: "dateLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "numLeave",
align: "left",
label: "จำนวนวันลา",
sortable: true,
field: "numLeave",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "status",
align: "left",
label: "สถานะ",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "reason",
align: "left",
label: "เหตุผล",
sortable: true,
field: "reason",
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" }),
},
]);
function getHistory() {
showLoader();
http
.get(config.API.profileNewLeaveHistory(id.value, empType.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: any) => {
rows.value.push({
...e,
id: e.id,
typeLeave: e.leaveType.name,
code: e.leaveType.refCommandDate,
dateStartLeave: e.dateLeaveStart,
dateEndLeave: e.dateLeaveEnd,
numLeave: e.leaveDays,
status: e.status,
reason: e.reason,
typeLeaveId:
e.typeLeaveId !== "00000000-0000-0000-0000-000000000000"
? e.typeLeaveId
: "",
});
});
})
.catch((e) => {
// messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
/**
* แปลงชวงวนทา2คาเปนวนเดยวกนจะโชววนเดยวแตาไมเทากนจะแสดงเปนชวง
* @param val วงวนท
*/
function dateThaiRange(val: [Date, Date]) {
if (val === null) {
} else if (date2Thai(val[0]) === date2Thai(val[1])) {
return `${date2Thai(val[0])}`;
} else {
return `${date2Thai(val[0])} - ${date2Thai(val[1])} `;
}
}
function statusLeave(val: string) {
switch (val) {
case "waitting":
return "รออนุมัติ";
case "reject":
return "ไม่ผ่านการอนุมัติ";
case "approve":
return "ผ่านการอนุมัติ";
case "cancel":
return "ยกเลิก";
default:
return "-";
}
}
watch(modal, (status) => {
if (status == true) {
getHistory();
filterKeyword.value = "";
} else {
filterKeyword.value = "";
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80%">
<DialogHeader tittle="ประวัติแก้ไขการลา" :close="() => (modal = false)" />
<q-separator color="grey-4" />
<q-card-section style="max-height: 60vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
v-model:pagination="historyPagination"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
:filter="filterKeyword"
>
>
<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 v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize +
props.rowIndex +
1
}}
</div>
<div v-else-if="col.name == 'dateLeave'">
{{
dateThaiRange([
props.row.dateStartLeave,
props.row.dateEndLeave,
])
}}
</div>
<div v-else-if="col.name == 'status'">
{{ statusLeave(col.value) }}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -0,0 +1,723 @@
<script setup lang="ts">
import { ref, reactive, onMounted } from "vue";
import { useQuasar, type QTableProps } from "quasar";
import type {
FormFilter,
RequestItemsObject,
} from "@/modules/04_registryPerson/interface/index/performSpecialWork";
import http from "@/plugins/http";
import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import DialogHeader from "@/components/DialogHeader.vue";
import DialogHistory from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWorkHistory.vue";
import { useRoute } from "vue-router";
const route = useRoute();
const profileId = ref<string>(
route.params.id ? route.params.id.toString() : ""
);
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const $q = useQuasar();
const mixin = useCounterMixin();
const {
date2Thai,
dialogConfirm,
messageError,
showLoader,
hideLoader,
success,
dialogRemove,
} = mixin;
const modal = ref<boolean>(false);
const edit = ref<boolean>(false);
const modalHistory = ref<boolean>(false);
const id = ref<string>("");
const dateStartRef = ref<object | null>(null);
const dateEndRef = ref<object | null>(null);
const detailRef = ref<object | null>(null);
const referenceRef = ref<object | null>(null);
const dutyData = reactive<RequestItemsObject>({
profileId: profileId.value,
dateStart: new Date(),
dateEnd: null,
detail: "",
reference: "",
refCommandNo: "",
refCommandDate: null,
});
const pagination = ref({
page: 1,
rowsPerPage: 10,
});
const rows = ref<RequestItemsObject[]>([]);
const filterKeyword = ref<string>("");
const mode = ref<string>("table");
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const visibleColumns = ref<String[]>([
"dateStart",
"dateEnd",
"detail",
"reference",
"refCommandNo",
"refCommandDate",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "เริ่มต้น",
sortable: true,
field: "dateStart",
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" }),
},
{
name: "dateEnd",
align: "left",
label: "สิ้นสุด",
sortable: true,
field: "dateEnd",
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" }),
},
{
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: "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: "refCommandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandDate",
align: "left",
label: "เอกสารอ้างอิง (ลงวันที่)",
sortable: true,
field: "refCommandDate",
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" }),
},
]);
/** เปิด dialog */
function openDialogAdd() {
modal.value = true;
}
/** กดแก้ไข */
function openDialogEdit(props: RequestItemsObject) {
modal.value = true;
edit.value = true;
id.value = props.id ? props.id : "";
dutyData.dateStart = props.dateStart;
dutyData.dateEnd = props.dateEnd;
dutyData.detail = props.detail;
dutyData.reference = props.reference;
dutyData.refCommandNo = props.refCommandNo;
dutyData.refCommandDate = props.refCommandDate;
}
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
function openDialogHistory(idOrder: string) {
modalHistory.value = true;
id.value = idOrder;
}
/** ปิด dialog */
function closeDialog() {
modal.value = false;
edit.value = false;
dutyData.dateStart = new Date();
dutyData.dateEnd = null;
dutyData.detail = "";
dutyData.reference = "";
dutyData.refCommandNo = "";
dutyData.refCommandDate = null;
}
/** fetch ข้อมูล */
async function fetchData(id: string) {
showLoader();
await http
.get(config.API.profileNewDutyByProfileId(id, empType.value))
.then(async (res) => {
rows.value = res.data.result;
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** เพิ่มข้อมูล */
async function addData() {
const body = {
profileId: empType.value === "" ? profileId.value : undefined,
profileEmployeeId: empType.value !== "" ? profileId.value : undefined,
dateStart: dutyData.dateStart,
dateEnd: dutyData.dateEnd,
detail: dutyData.detail,
reference: dutyData.reference,
refCommandNo: dutyData.refCommandNo,
refCommandDate: dutyData.refCommandDate,
};
await http
.post(config.API.profileNewDuty(empType.value), body)
.then(() => {
fetchData(profileId.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** แก้ไขข้อมูล */
async function editData(idData: string) {
await http
.patch(config.API.profileNewDutyByDutyId(idData, empType.value), {
...dutyData,
profileId: undefined,
})
.then(() => {
fetchData(profileId.value);
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((err) => {
messageError($q, err);
})
.finally(() => {
hideLoader();
});
}
/** ลบข้อมูล */
// function deleteData(idData: string) {
// dialogRemove($q, () =>
// http
// .delete(config.API.profileNewDutyByDutyId(idData))
// .then(() => {
// fetchData(profileId.value);
// success($q, "");
// })
// .catch((err) => {
// messageError($q, err);
// })
// .finally(() => {
// hideLoader();
// })
// );
// }
/** กด Submit */
async function onSubmit() {
dialogConfirm(
$q,
async () => {
edit.value ? editData(id.value) : addData();
closeDialog();
},
"ยืนยันการบันทึกข้อมูล",
"ต้องการยืนยันการบันทึกข้อมูลนี้หรือไม่ ?"
);
}
onMounted(async () => {
await fetchData(profileId.value);
});
</script>
<template>
<div class="row items-center q-gutter-x-sm q-pb-sm">
<q-btn dense color="primary" icon="add" flat round @click="openDialogAdd()"
><q-tooltip>เพมขอม</q-tooltip></q-btn
>
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-if="mode == 'table'"
v-model="visibleColumns"
multiple
outlined
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
ref="table"
flat
bordered
dense
:card-container-class="mode === 'card' ? 'q-col-gutter-md' : ''"
:columns="columns"
:rows="rows"
:grid="mode === 'card'"
:paging="true"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
:filter="filterKeyword"
v-model:pagination="pagination"
>
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th auto-width></q-th>
<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="openDialogEdit(props.row)"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="openDialogHistory(props.row.id)"
>
<q-tooltip>ประวแกไขปฏราชการพเศษ</q-tooltip>
</q-btn>
<!-- <q-btn
color="red"
flat
dense
round
size="14px"
icon="mdi-delete"
clickable
@click.stop="deleteData(props.row.id)"
v-close-popup
>
<q-tooltip>ลบขอม</q-tooltip>
</q-btn> -->
</q-td>
<q-td v-for="col in props.cols" :key="col.id">
<div v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize + props.rowIndex + 1
}}
</div>
<div v-else>
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
<template v-slot:item="props" v-else>
<div class="col-xs-12 col-sm-6 col-md-6">
<q-card flat bordered class="q-pa-none">
<div class="row bg-grey-3">
<q-space />
<div class="q-gutter-x-sm">
<q-btn
color="primary"
icon="mdi-pencil-outline"
flat
round
@click="openDialogEdit(props.row)"
><q-tooltip>แกไขขอม</q-tooltip></q-btn
>
<q-btn
color="info"
icon="mdi-history"
flat
round
@click="openDialogHistory(props.row.id)"
><q-tooltip>ประวแกไขปฏราชการพเศษ</q-tooltip></q-btn
>
</div>
</div>
<q-separator />
<q-card-section class="q-pa-none">
<div class="row q-pa-sm">
<div class="col text-grey-6 text-weight-medium">เรมต</div>
<div class="col">
{{ props.row.dateStart ? date2Thai(props.row.dateStart) : "-" }}
</div>
<div class="col text-grey-6 text-weight-medium">นส</div>
<div class="col">
{{ props.row.dateEnd ? date2Thai(props.row.dateEnd) : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">
เอกสารอางอ
</div>
<div class="col-3">
{{ props.row.reference ? props.row.reference : "-" }}
</div>
<div class="col text-grey-6 text-weight-medium">เลขทคำส</div>
<div class="col">
{{ props.row.refCommandNo ? props.row.refCommandNo : "-" }}
</div>
</div>
<q-separator />
<div class="row q-pa-sm">
<div class="col-3 text-grey-6 text-weight-medium">
เอกสารอางอ (ลงวนท)
</div>
<div class="col-3">
{{
props.row.refCommandDate
? date2Thai(props.row.refCommandDate)
: "-"
}}
</div>
</div>
<q-separator />
<div class="row q-pa-sm bg-grey-2">
<div class="col-3 text-grey-6 text-weight-medium">รายละเอยด</div>
<div class="col-9">
{{ props.row.detail ? props.row.detail : "-" }}
</div>
</div>
</q-card-section>
</q-card>
</div>
</template>
</d-table>
<q-dialog v-model="modal" persistent>
<q-card>
<q-form @submit.prevent greedy @validation-success="onSubmit()">
<DialogHeader
:tittle="
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">
<datepicker
menu-class-name="modalfix"
v-model="dutyData.dateStart"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateStartRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
:model-value="date2Thai(dutyData.dateStart)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
hide-bottom-space
:label="`${'วันที่เริ่มต้น'}`"
>
<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">
<datepicker
menu-class-name="modalfix"
v-model="dutyData.dateEnd"
:locale="'th'"
autoApply
:enableTimePicker="false"
:min-date="dutyData.dateStart"
:readonly="!dutyData.dateStart"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
ref="dateEndRef"
:readonly="!dutyData.dateStart"
class="full-width inputgreen cursor-pointer"
dense
outlined
:model-value="date2Thai(dutyData.dateEnd)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่สิ้นสุด'}`]"
hide-bottom-space
:label="`${'วันที่สิ้นสุด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-input
ref="referenceRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
autogrow
v-model="dutyData.reference"
:rules="[(val) => !!val || `${'กรุณากรอกเอกสารอ้างอิง'}`]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง'}`"
/>
</div>
<div class="col-12">
<q-input
ref="detailRef"
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
autogrow
v-model="dutyData.detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
v-model="dutyData.refCommandNo"
:label="`${'เลขที่คำสั่ง'}`"
>
<template v-slot:append>
<q-icon name="mdi-file" class="cursor-pointer" />
</template>
</q-input>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="dutyData.refCommandDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
:borderless="!edit"
:model-value="
dutyData.refCommandDate == null ? null : date2Thai(dutyData.refCommandDate as Date)
"
hide-bottom-space
:label="`${'เอกสารอ้างอิง (ลงวันที่)'}`"
clearable
@clear="dutyData.refCommandDate = null"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
color="primary"
>
</q-icon>
</template>
<template
v-if="dutyData.refCommandDate && edit"
v-slot:append
>
</template>
</q-input>
</template>
</datepicker>
</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>
<DialogHistory v-model:modal="modalHistory" v-model:id="id" />
</template>
<style scoped></style>

View file

@ -0,0 +1,284 @@
<script setup lang="ts">
import { ref, watch, reactive } from "vue";
import DialogHeader from "@/components/DialogHeader.vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar, type QTableProps } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
FormFilter,
ResponseObject,
} from "@/modules/04_registryPerson/interface/index/performSpecialWork";
import { useRoute } from "vue-router";
const modal = defineModel<boolean>("modal", { required: true });
const id = defineModel<string>("id", { required: true });
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const { showLoader, hideLoader, messageError, date2Thai } = mixin;
const empType = ref<string>(
route.name === "registryNewByid" ? "" : "-employee"
);
const currentPage = ref<number>(1);
const maxPage = ref<number>(1);
const filterKeyword = ref<string>("");
const rows = ref<ResponseObject[]>([]); //select data history
const formFilter = reactive<FormFilter>({
page: 1,
pageSize: 12,
keyword: "",
type: "",
posType: "",
posLevel: "",
retireYear: "",
rangeYear: { min: 0, max: 60 },
isShowRetire: false,
isProbation: false,
});
const historyPagination = ref({
page: 1,
rowsPerPage: 10,
});
const visibleColumns = ref<String[]>([
"dateStart",
"dateEnd",
"detail",
"reference",
"refCommandNo",
"refCommandDate",
"lastUpdateFullName",
"lastUpdatedAt",
]);
const columns = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "เริ่มต้น",
sortable: true,
field: "dateStart",
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" }),
},
{
name: "dateEnd",
align: "left",
label: "สิ้นสุด",
sortable: true,
field: "dateEnd",
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" }),
},
{
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: "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: "refCommandNo",
align: "left",
label: "เลขที่คำสั่ง",
sortable: true,
field: "refCommandNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "refCommandDate",
align: "left",
label: "เอกสารอ้างอิง (ลงวันที่)",
sortable: true,
field: "refCommandDate",
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" }),
},
{
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" }),
},
]);
function getHistory() {
showLoader();
http
.get(config.API.profileNewDutyHisByDutyId(id.value, empType.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
dateStart: new Date(e.dateStart),
dateEnd: new Date(e.dateEnd),
detail: e.detail,
reference: e.reference,
refCommandNo: e.refCommandNo,
refCommandDate:
e.refCommandDate == null ? null : new Date(e.refCommandDate),
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
lastUpdateFullName: e.lastUpdateFullName,
lastUpdatedAt: e.lastUpdatedAt,
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
hideLoader();
});
}
watch(modal, (status) => {
if (status == true) {
getHistory();
filterKeyword.value = "";
} else {
filterKeyword.value = "";
}
});
</script>
<template>
<q-dialog v-model="modal" persistent>
<q-card style="min-width: 80%">
<DialogHeader
tittle="ประวัติแก้ไขปฏิบัติราชการพิเศษ"
:close="() => (modal = false)"
/>
<q-card-section style="max-height: 60vh" class="scroll">
<div class="row q-gutter-sm q-mb-sm">
<q-space />
<q-input
standout
dense
v-model="filterKeyword"
ref="filterRef"
outlined
placeholder="ค้นหา"
debounce="300"
>
<template v-slot:append>
<q-icon
v-if="filterKeyword == ''"
name="search"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
<q-icon
v-if="filterKeyword"
name="cancel"
@click.stop.prevent="filterKeyword = ''"
class="cursor-pointer"
/>
</template>
</q-input>
<q-select
v-model="visibleColumns"
multiple
outlined
dense
options-dense
:display-value="$q.lang.table.columns"
emit-value
map-options
:options="columns"
option-value="name"
options-cover
style="min-width: 150px"
/>
</div>
<d-table
ref="table"
flat
bordered
dense
:columns="columns"
:rows="rows"
:paging="true"
v-model:pagination="historyPagination"
:rows-per-page-options="[10, 25, 50, 100]"
:visible-columns="visibleColumns"
:filter="filterKeyword"
>
>
<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 v-if="col.name === 'no'">
{{
(formFilter.page - 1) * formFilter.pageSize +
props.rowIndex +
1
}}
</div>
<div v-else class="table_ellipsis">
{{ col.value ? col.value : "-" }}
</div>
</q-td>
</q-tr>
</template>
</d-table>
</q-card-section>
</q-card>
</q-dialog>
</template>

View file

@ -0,0 +1,54 @@
<script setup lang="ts">
import { ref } from "vue";
/** importComponents*/
import Info from "@/modules/04_registryPerson/components/detail/GovernmentInformation/01_Info.vue";
import Discipline from "@/modules/04_registryPerson/components/detail/GovernmentInformation/02_Discipline.vue";
import Leave from "@/modules/04_registryPerson/components/detail/GovernmentInformation/03_Leave.vue";
import PerformSpecialWork from "@/modules/04_registryPerson/components/detail/GovernmentInformation/04_PerformSpecialWork.vue";
const tab = ref<string>("1");
</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-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-tabs>
<q-separator />
<q-tab-panels v-model="tab" animated>
<q-tab-panel name="1">
<Info />
</q-tab-panel>
<q-tab-panel name="2">
<Discipline />
</q-tab-panel>
<q-tab-panel name="3">
<Leave />
</q-tab-panel>
<q-tab-panel name="4">
<PerformSpecialWork />
</q-tab-panel>
</q-tab-panels>
</template>
<style scoped></style>