clone code

This commit is contained in:
Kittapath 2023-06-01 12:54:58 +07:00
parent c9597d1e38
commit d57bcd1719
362 changed files with 104804 additions and 0 deletions

View file

@ -0,0 +1,677 @@
<!-- card ผลการประเมนการปฏราชการ -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-pa-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="ผลการประเมินการปฏิบัติราชการ"
icon="mdi-clipboard-text"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div v-if="col.name == 'date'" class="table_ellipsis">
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader
tittle="ผลการประเมินการปฏิบัติราชการ"
:close="clickClose"
/>
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="date"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(date)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่ได้รับ'}`]"
hide-bottom-space
:label="`${'วันที่ได้รับ'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="point"
:rules="[(val) => !!val || `${'กรุณากรอกคะแนน'}`]"
hide-bottom-space
:label="`${'คะแนน'}`"
@update:modelValue="clickEditRow"
type="number"
/>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="name"
:rules="[(val) => !!val || `${'กรุณากรอกชื่อแบบประเมิน'}`]"
hide-bottom-space
:label="`${'ชื่อแบบประเมิน'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="col.name == 'date' || col.name == 'createdAt'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Assessment";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Assessment";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
profileType: {
type: String,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const name = ref<string>();
const point = ref<number>();
const date = ref<Date>(new Date());
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขผลการประเมินการปฏิบัติราชการ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.assessment.columns.length == 0
? (visibleColumns.value = ["name", "point", "date"])
: (visibleColumns.value = profileData.assessment.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วันที่ได้รับ",
sortable: true,
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "name",
align: "left",
label: "ชื่อแบบประเมิน",
sortable: true,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "point",
align: "left",
label: "คะแนน",
sortable: true,
field: "point",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วันที่ได้รับ",
sortable: true,
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "name",
align: "left",
label: "ชื่อแบบประเมิน",
sortable: true,
field: "name",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "point",
align: "left",
label: "คะแนน",
sortable: true,
field: "point",
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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"name",
"point",
"date",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("assessment", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileAssessmentId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
name: e.name,
point: e.point,
date: new Date(e.date),
createdAt: new Date(e.createdAt),
createdFullName: e.createdFullName,
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
name.value = row.name;
point.value = row.point;
date.value = row.date;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileAssessmentId(profileId.value), {
id: id.value,
name: name.value,
point: point.value,
date: dateToISO(date.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileAssessmentId(id.value), {
id: id.value,
name: name.value,
point: point.value,
date: dateToISO(date.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileAssessmentId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
name.value = props.row.name;
point.value = props.row.point;
date.value = props.row.date;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
name.value = "";
point.value = 0;
date.value = new Date();
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
tittleHistory.value = "ประวัติแก้ไขผลการประเมินการปฏิบัติราชการ";
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileAssessmentHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
name: e.name,
point: e.point,
date: new Date(e.date),
createdAt: new Date(e.createdAt),
createdFullName: e.createdFullName,
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

View file

@ -0,0 +1,688 @@
<!-- card ประกาศเกยรต -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-pa-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
:name="
profileType == 'employee' ? 'ประกาศลูกจ้างดีเด่น' : 'ประกาศเกียรติคุณ'
"
icon="mdi-script-text"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div v-if="col.name == 'issueDate'" class="table_ellipsis">
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader
:tittle="
profileType == 'employee'
? 'ประกาศลูกจ้างดีเด่น'
: 'ประกาศเกียรติคุณ'
"
:close="clickClose"
/>
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="issueDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(issueDate)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่ได้รับ'}`]"
hide-bottom-space
:label="`${'วันที่ได้รับ'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
autogrow
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="issuer"
:rules="[(val) => !!val || `${'กรุณากรอกหน่วยงานที่ออก'}`]"
hide-bottom-space
:label="`${'หน่วยงานที่ออก'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
autogrow
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="col.name == 'issueDate' || col.name == 'createdAt'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
Columns,
DataProps,
} from "@/modules/04_registry/interface/request/Coin";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Coin";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
profileType: {
type: String,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const issuer = ref<string>();
const detail = ref<string>();
const issueDate = ref<Date>(new Date());
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขประกาศเกียรติคุณ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.coined.columns.length == 0
? (visibleColumns.value = ["issuer", "detail", "issueDate"])
: (visibleColumns.value = profileData.coined.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "issueDate",
align: "left",
label: "วันที่ได้รับ",
sortable: true,
field: "issueDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issuer",
align: "left",
label: "หน่วยงานที่ออก",
sortable: true,
field: "issuer",
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" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "issueDate",
align: "left",
label: "วันที่ได้รับ",
sortable: true,
field: "issueDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issuer",
align: "left",
label: "หน่วยงานที่ออก",
sortable: true,
field: "issuer",
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"issuer",
"detail",
"issueDate",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("coined", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileHonorId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
issuer: e.issuer,
detail: e.detail,
issueDate: new Date(e.issueDate),
createdAt: new Date(e.createdAt),
createdFullName: e.createdFullName,
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
issuer.value = row.issuer;
detail.value = row.detail;
issueDate.value = row.issueDate;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileHonorId(profileId.value), {
id: id.value,
issuer: issuer.value,
detail: detail.value,
issueDate: dateToISO(issueDate.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileHonorId(id.value), {
id: id.value,
issuer: issuer.value,
detail: detail.value,
issueDate: dateToISO(issueDate.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileHonorId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
issuer.value = props.row.issuer;
detail.value = props.row.detail;
issueDate.value = props.row.issueDate;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
issuer.value = "";
detail.value = "";
issueDate.value = new Date();
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
tittleHistory.value =
props.profileType == "employee"
? "ประวัติแก้ไขประกาศลูกจ้างดีเด่น"
: "ประวัติแก้ไขประกาศเกียรติคุณ";
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileHonorHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
issuer: e.issuer,
detail: e.detail,
issueDate: new Date(e.issueDate),
createdAt: new Date(e.createdAt),
createdFullName: e.createdFullName,
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

View file

@ -0,0 +1,135 @@
<template>
<q-card-actions class="text-primary q-py-sm">
<q-btn
flat
round
icon="mdi-menu-left"
@click="clickPrevious"
v-if="modalEdit == true"
:disable="previous == false"
:color="!previous ? 'grey-7' : 'public'"
/>
<q-btn
flat
round
icon="mdi-menu-right"
@click="clickNext"
v-if="modalEdit == true"
:disable="next == false"
:color="!next ? 'grey-7' : 'public'"
/>
<q-space />
<q-btn
v-if="modalEdit == true"
flat
round
color="red"
@click="clickDelete"
icon="mdi-delete"
>
<q-tooltip>ลบขอม</q-tooltip>
</q-btn>
<q-btn
v-if="!editvisible"
flat
round
:disabled="editvisible"
:color="editvisible ? 'grey-7' : 'primary'"
@click="edit"
icon="mdi-pencil-outline"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<div v-else>
<q-btn
flat
round
:disabled="!editvisible"
:outline="!editvisible"
:color="!editvisible ? 'grey-7' : 'red'"
@click="cancel()"
icon="mdi-undo"
v-if="modalEdit == true"
>
<q-tooltip>ยกเล</q-tooltip>
</q-btn>
<q-btn
flat
round
:disabled="!editvisible"
:color="!editvisible ? 'grey-7' : 'public'"
@click="checkSave"
icon="mdi-content-save-outline"
>
<q-tooltip>นท</q-tooltip>
</q-btn>
</div>
</q-card-actions>
</template>
<script setup lang="ts">
const props = defineProps({
editvisible: Boolean,
next: Boolean,
previous: Boolean,
modalEdit: Boolean,
clickNext: {
type: Function,
default: () => console.log("not function"),
},
clickPrevious: {
type: Function,
default: () => console.log("not function"),
},
cancel: {
type: Function,
default: () => console.log("not function"),
},
edit: {
type: Function,
default: () => console.log("not function"),
},
save: {
type: Function,
default: () => console.log("not function"),
},
validate: {
type: Function,
default: () => console.log("not function"),
},
clickDelete: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits([
"update:editvisible",
"update:next",
"update:previous",
]);
const updateEdit = (value: Boolean) => {
emit("update:editvisible", value);
};
const cancel = async () => {
props.cancel();
};
const clickDelete = async () => {
props.clickDelete();
};
const edit = async () => {
updateEdit(!props.editvisible);
props.edit();
};
const checkSave = () => {
props.validate();
props.save();
};
const clickNext = async () => {
await props.clickNext();
};
const clickPrevious = async () => {
await props.clickPrevious();
};
</script>

View file

@ -0,0 +1,27 @@
<template>
<q-toolbar>
<q-toolbar-title class="text-subtitle2 text-bold">{{
tittle
}}</q-toolbar-title>
<q-btn
icon="close"
unelevated
round
dense
@click="close"
style="color: #ff8080; background-color: #ffdede"
/>
</q-toolbar>
</template>
<script setup lang="ts">
const props = defineProps({
tittle: String,
close: {
type: Function,
default: () => console.log("not function"),
},
});
const close = async () => {
props.close();
};
</script>

View file

@ -0,0 +1,45 @@
<template>
<q-dialog :model-value="modal" persistent>
<q-card style="width: 600px">
<DialogHeader :tittle="props.title" :close="close" />
<q-separator />
<q-card-section
:class="props.fix ? 'q-pa-md scroll' : 'q-pa-md'"
:style="props.fix ? 'height: 50vh' : ''"
>
<slot name="body" />
</q-card-section>
<q-separator />
<q-card-actions class="text-primary">
<slot name="footer" />
</q-card-actions>
</q-card>
</q-dialog>
</template>
<script setup lang="ts">
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
const props = defineProps({
title: {
required: true,
type: String,
default: "",
},
modal: {
required: true,
type: Boolean,
default: false,
},
fix: {
required: true,
type: Boolean,
default: true,
},
});
const emit = defineEmits(["update:modal"]);
const close = async () => {
emit("update:modal", false);
};
</script>

View file

@ -0,0 +1,883 @@
<!-- card -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="วินัย"
icon="mdi-scale-balance"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div
v-if="col.name == 'refCommandDate' || col.name == 'date'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader tittle="วินัย" :close="clickClose" />
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="date"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(date)"
:rules="[(val:string) => !!val || `${'กรุณาเลือกวัน เดือน ปี'}`]"
hide-bottom-space
:label="`${'วัน เดือน ปี'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="detail"
:rules="[(val:string) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<selector
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="level"
:rules="[(val:string) => !!val || `${'กรุณาเลือกระดับความผิด'}`]"
hide-bottom-space
:label="`${'ระดับความผิด'}`"
@update:modelValue="clickEditRow"
emit-value
map-options
option-label="name"
:options="Ops.levelOptions"
option-value="id"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'levelOptions'
) "
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="refCommandNo"
:rules="[
(val:string) =>
!!val || `${'กรุณากรอกเอกสารอ้างอิง (เลขที่คำสั่ง)'}`,
]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง (เลขที่คำสั่ง)'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
:readonly="!edit"
v-model="refCommandDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(refCommandDate)"
:rules="[
(val:string) =>
!!val || `${'กรุณาเลือกเอกสารอ้างอิง (ลงวันที่)'}`,
]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง (ลงวันที่)'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="
col.name == 'date' ||
col.name == 'refCommandDate' ||
col.name == 'createdAt'
"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Discipline";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Discipline";
import type {
DisciplineOps,
DataOption,
} from "@/modules/04_registry/interface/index/Main";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const level = ref<string>();
const Ops = ref<DisciplineOps>({
levelOptions: [
{
name: "ภาคทัณฑ์",
id: "ภาคทัณฑ์",
},
{
name: "ตัดเงินเดือน",
id: "ตัดเงินเดือน",
},
{
name: "ลดขั้นเงินเดือน",
id: "ลดขั้นเงินเดือน",
},
{
name: "ปลดออก",
id: "ปลดออก",
},
{
name: "ไล่ออก",
id: "ไล่ออก",
},
],
});
const OpsFilter = ref<DisciplineOps>({
levelOptions: [
{
name: "ภาคทัณฑ์",
id: "ภาคทัณฑ์",
},
{
name: "ตัดเงินเดือน",
id: "ตัดเงินเดือน",
},
{
name: "ลดขั้นเงินเดือน",
id: "ลดขั้นเงินเดือน",
},
{
name: "ปลดออก",
id: "ปลดออก",
},
{
name: "ไล่ออก",
id: "ไล่ออก",
},
],
});
const detail = ref<string>();
const refCommandNo = ref<string>();
const refCommandDate = ref<Date>(new Date());
const date = ref<Date>(new Date());
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขวินัย"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.discipline.columns.length == 0
? (visibleColumns.value = [
"level",
"detail",
"refCommandNo",
"refCommandDate",
"date",
])
: (visibleColumns.value = profileData.discipline.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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: "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",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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: "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",
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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"level",
"detail",
"refCommandNo",
"refCommandDate",
"date",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("discipline", count);
});
onMounted(async () => {
await fetchData();
});
const 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;
}
};
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileDisId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
level: e.level,
detail: e.detail,
refCommandNo: e.refCommandNo,
refCommandDate: new Date(e.refCommandDate),
date: new Date(e.date),
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
level.value = row.level;
detail.value = row.detail;
refCommandNo.value = row.refCommandNo;
refCommandDate.value = row.refCommandDate;
date.value = row.date;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileDisId(profileId.value), {
id: id.value,
level: level.value,
detail: detail.value,
refCommandNo: refCommandNo.value,
refCommandDate: dateToISO(refCommandDate.value),
date: dateToISO(date.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileDisId(id.value), {
id: id.value,
level: level.value,
detail: detail.value,
refCommandNo: refCommandNo.value,
refCommandDate: dateToISO(refCommandDate.value),
date: dateToISO(date.value),
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileDisId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
level.value = props.row.level;
detail.value = props.row.detail;
refCommandNo.value = props.row.refCommandNo;
refCommandDate.value = props.row.refCommandDate;
date.value = props.row.date;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
level.value = "";
detail.value = "";
refCommandNo.value = "";
refCommandDate.value = new Date();
date.value = new Date();
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileDisHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
level: e.level,
detail: e.detail,
refCommandNo: e.refCommandNo,
refCommandDate: new Date(e.refCommandDate),
date: new Date(e.date),
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

View file

@ -0,0 +1,264 @@
<template>
<q-card flat bordered class="col-12 row q-px-lg q-py-md">
<HeaderTop
v-model:edit="edit"
header="เอกสารหลักฐาน"
icon="mdi-file-document"
:history="false"
:changeBtn="changeBtn"
:disable="statusEdit"
:save="uploadData"
/>
<div class="row col-12 q-pt-sm">
<q-card bordered flat class="full-width">
<q-list separator>
<q-item v-for="file in files" :key="file.key" class="q-my-xs">
<q-item-section>
<q-item-label class="full-width ellipsis">
{{ file.fileName }}
</q-item-label>
<q-item-label caption> </q-item-label>
</q-item-section>
<q-item-section top side>
<div class="row col-12">
<q-btn
class="gt-xs"
size="12px"
flat
dense
round
color="blue"
icon="mdi-download-outline"
@click="downloadData(file.file)"
/>
<q-btn
class="gt-xs"
size="12px"
flat
dense
round
color="red"
icon="mdi-delete-outline"
v-show="edit"
@click="deleteData(file.id)"
/>
</div>
</q-item-section>
</q-item>
</q-list>
</q-card>
<q-input
v-if="edit"
class="q-mt-sm col-12 q-pb-xs"
outlined
dense
lazy-rules
v-model="name"
hide-bottom-space
:rules="[(val) => !!val || `${'กรุณากรอกชื่อเอกสาร'}`]"
:label="`${'ชื่อเอกสาร'}`"
/>
<q-uploader
v-if="edit"
color="gray"
type="file"
flat
@factory="uploadData"
ref="uploader"
class="full-width"
text-color="white"
:max-size="10000000"
accept=".jpg,.png,.pdf,.csv,.doc"
bordered
label="[ไฟล์ jpg,png,pdf,csv,doc ขนาดไม่เกิน 10MB]"
@added="fileAdd"
>
<template v-slot:header="scope">
<div class="row no-wrap items-center q-pa-sm q-gutter-xs">
<q-btn
v-if="scope.queuedFiles.length > 0"
icon="clear_all"
@click="scope.removeQueuedFiles"
round
dense
flat
>
<q-tooltip>ลบทงหมด</q-tooltip>
</q-btn>
<q-btn
v-if="scope.uploadedFiles.length > 0"
icon="done_all"
@click="scope.removeUploadedFiles"
round
dense
flat
>
<q-tooltip>ลบไฟลปโหลด</q-tooltip>
</q-btn>
<q-spinner v-if="scope.isUploading" class="q-uploader__spinner" />
<div class="col">
<div class="q-uploader__title">
{{ "[ไฟล์ jpg,png,pdf,csv,doc ขนาดไม่เกิน 10MB]" }}
</div>
<div class="q-uploader__subtitle">
{{ scope.uploadSizeLabel }} / {{ scope.uploadProgressLabel }}
</div>
</div>
<q-btn
v-if="scope.canAddFiles"
type="a"
icon="add_box"
@click="scope.pickFiles"
round
dense
flat
>
<q-uploader-add-trigger />
<q-tooltip>เลอกไฟล</q-tooltip>
</q-btn>
<q-btn
v-if="scope.isUploading"
icon="clear"
@click="scope.abort"
round
dense
flat
>
<q-tooltip>ยกเลกการอปโหลด</q-tooltip>
</q-btn>
</div>
</template>
</q-uploader>
</div>
</q-card>
</template>
<script setup lang="ts">
import { onMounted, computed, ref, watch } from "vue";
import { useQuasar, QForm } from "quasar";
import { useCounterMixin } from "@/stores/mixin";
import { useRoute } from "vue-router";
import { useDataStore } from "@/stores/data";
import HeaderTop from "@/modules/04_registry/components/Information/top.vue";
import http from "@/plugins/http";
import config from "@/app.config";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
notiNoEdit: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:statusEdit"]);
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const $q = useQuasar(); // show dialog
const mixin = useCounterMixin();
const route = useRoute();
const { success, messageError } = mixin;
const profileId = ref<string>(route.params.id.toString());
const edit = ref<boolean>(false);
const uploader = ref<any>();
const files = ref<any>([]);
const file = ref<any>([]);
const name = ref<string>("");
onMounted(async () => {
await getData();
});
const getData = async () => {
loaderPage(true);
await http
.get(config.API.profilePaperId(profileId.value))
.then((res) => {
const data = res.data.result;
files.value = data;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const deleteData = async (id: string) => {
loaderPage(true);
await http
.delete(config.API.profilePaperId(id))
.then((res) => {
const data = res.data.result;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await getData();
});
};
const uploadData = async () => {
if (file.value.length > 0) {
const blob = file.value.slice(0, file.value[0].size);
const newFile = new File(blob, name.value, {
type: file.value[0].type,
});
const formData = new FormData();
formData.append("", newFile);
loaderPage(true);
await http
.post(config.API.profilePaperId(profileId.value), formData)
.then((res) => {
const data = res.data.result;
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
uploader.value.reset();
name.value = "";
edit.value = false;
emit("update:statusEdit", false);
await getData();
});
} else {
// modalError(
// $q,
// "",
// ""
// );
getData();
}
};
const fileAdd = async (val: any) => {
name.value = val[0].name;
file.value = val;
};
const downloadData = async (path: string) => {
window.open(path);
};
const changeBtn = async () => {
name.value = "";
if (edit.value == true) {
if (props.statusEdit === true) {
edit.value = false;
props.notiNoEdit();
} else {
emit("update:statusEdit", true);
}
} else {
emit("update:statusEdit", false);
}
};
</script>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,833 @@
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md q-mt-md">
<HeaderTop
v-model:edit="edit"
header="ข้อมูลที่อยู่"
icon="mdi-map-marker"
:save="saveData"
:history="true"
:changeBtn="changeBtn"
:disable="statusEdit"
:cancel="refreshData"
:historyClick="clickHistory"
/>
<q-form ref="myform">
<div class="row col-12 items-center q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-12">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
type="textarea"
autogrow
:readonly="!edit"
:borderless="!edit"
v-model="addressData.address"
:rules="[(val:string) => !!val || `${'กรุณากรอก ที่อยู่ตามทะเบียนบ้าน'}`]"
:label="`${'ที่อยู่ตามทะเบียนบ้าน'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก จังหวัด'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.provinceId"
emit-value
map-options
option-label="name"
:options="Ops.provinceOps"
option-value="id"
:label="`${'จังหวัด'}`"
@update:model-value="(value:string) => selectProvince(value, '1')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'provinceOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก เขต / อำเภอ'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.districtId"
emit-value
map-options
option-label="name"
:options="Ops.districtOps"
option-value="id"
:label="`${'เขต / อำเภอ'}`"
@update:model-value="(value:string) => selectDistrict(value, '1')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'districtOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก ตำบล / แขวง'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.subdistrictId"
emit-value
map-options
option-label="name"
:options="Ops.subdistrictOps"
option-value="id"
:label="`${'ตำบล / แขวง'}`"
@update:model-value="(value:string) => selectSubDistrict(value, '1')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'subdistrictOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
v-model="codep"
:style="!edit ? '' : 'padding:0 12px;'"
:label="`${'รหัสไปรษณีย์'}`"
/>
</div>
<div class="col-12 q-pt-lg"><q-separator /></div>
<div class="col-xs-12 q-gutter-sm items-center flex q-my-sm">
<label class="text-bold"
>อยจจนตรงกบทอยตามทะเบยนบาน</label
>
<q-radio
v-model="addressData.same"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="1"
label="ใช่"
dense
:disable="!edit"
/>
<q-radio
v-model="addressData.same"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="0"
label="ไม่"
dense
:disable="!edit"
/>
</div>
<div class="col-xs-12" v-if="addressData.same == '0'">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
type="textarea"
autogrow
:readonly="!edit"
:borderless="!edit"
v-model="addressData.addressC"
:rules="[(val:string) => !!val || `${'กรุณากรอก ที่อยู่ปัจจุบัน'}`]"
:label="`${'ที่อยู่ปัจจุบัน'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3" v-if="addressData.same == '0'">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก จังหวัด'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.provinceIdC"
emit-value
map-options
option-label="name"
:options="Ops.provinceOps"
option-value="id"
:label="`${'จังหวัด'}`"
@update:model-value="(value:string) => selectProvince(value, '2')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'provinceOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3" v-if="addressData.same == '0'">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก เขต / อำเภอ'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.districtIdC"
emit-value
map-options
option-label="name"
:options="Ops.districtCOps"
option-value="id"
:label="`${'เขต / อำเภอ'}`"
@update:model-value="(value:string) => selectDistrict(value, '2')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'districtCOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3" v-if="addressData.same == '0'">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก ตำบล / แขวง'}`]"
:outlined="edit"
dense
lazy-rules
v-model="addressData.subdistrictIdC"
emit-value
map-options
option-label="name"
:options="Ops.subdistrictCOps"
option-value="id"
:label="`${'ตำบล / แขวง'}`"
@update:model-value="(value:string) => selectSubDistrict(value, '2')"
use-input
input-debounce="0"
@filter="(inputValue:string,
doneFn:Function) => filterSelector(inputValue, doneFn,'subdistrictCOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3" v-if="addressData.same == '0'">
<q-input
:class="getClass(edit)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
v-model="codec"
:style="!edit ? '' : 'padding:0 12px;'"
:label="`${'รหัสไปรษณีย์'}`"
/>
</div>
</div>
</q-form>
</q-card>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div v-if="col.name == 'createdAt'" class="table_ellipsis">
{{ date2Thai(col.value) }}
</div>
<div
v-else-if="col.name == 'registrationSame'"
class="table_ellipsis"
>
{{ col.value ? "ใช่" : "ไม่" }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
import type {
Address,
DataOption,
zipCodeOption,
} from "@/modules/04_registry/components/profileType";
import { defaultAddress } from "@/modules/04_registry/components/profileType";
import HeaderTop from "@/modules/04_registry/components/Information/top.vue";
import type { RequestItemsHistoryObject } from "@/modules/04_registry/interface/request/Address";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Address";
import HistoryTable from "@/components/TableHistory.vue";
import { useRoute } from "vue-router";
import type { AddressOps } from "@/modules/04_registry/interface/index/Main";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
notiNoEdit: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:statusEdit"]);
const route = useRoute();
const $q = useQuasar();
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, messageError } = mixin;
const edit = ref<boolean>(false);
const addressData = ref<Address>(defaultAddress);
const myform = ref<any>();
const codep = ref<string>("");
const codec = ref<string>("");
const rowsHistory = ref<RequestItemsHistoryObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขข้อมูลที่อยู่"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const Ops = ref<AddressOps>({
provinceOps: [],
districtOps: [],
districtCOps: [],
subdistrictOps: [],
subdistrictCOps: [],
});
const OpsFilter = ref<AddressOps>({
provinceOps: [],
districtOps: [],
districtCOps: [],
subdistrictOps: [],
subdistrictCOps: [],
});
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",
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",
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",
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: "registrationSame",
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",
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",
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",
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"currentAddress",
"currentDistrict",
"currentProvince",
"currentSubDistrict",
"currentZipCode",
"registrationAddress",
"registrationDistrict",
"registrationProvince",
"registrationSame",
"registrationSubDistrict",
"registrationZipCode",
"createdFullName",
"createdAt",
]);
onMounted(async () => {
await getNewData();
emit("update:statusEdit", false);
});
const filterSelector = (val: any, update: Function, refData: string) => {
switch (refData) {
case "provinceOps":
update(() => {
Ops.value.provinceOps = OpsFilter.value.provinceOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "districtOps":
update(() => {
Ops.value.districtOps = OpsFilter.value.districtOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "districtCOps":
update(() => {
Ops.value.districtCOps = OpsFilter.value.districtCOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "subdistrictOps":
update(() => {
Ops.value.subdistrictOps = OpsFilter.value.subdistrictOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "subdistrictCOps":
update(() => {
Ops.value.subdistrictCOps = OpsFilter.value.subdistrictCOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
*/
const clickHistory = async () => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileAdrsHisId(route.params.id.toString()))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: RequestItemsHistoryObject) => {
rowsHistory.value.push({
currentAddress: e.currentAddress,
currentDistrict: e.currentDistrict,
currentProvince: e.currentProvince,
currentSubDistrict: e.currentSubDistrict,
currentZipCode: e.currentZipCode,
registrationSame: e.registrationSame,
registrationAddress: e.registrationAddress,
registrationDistrict: e.registrationDistrict,
registrationProvince: e.registrationProvince,
registrationSubDistrict: e.registrationSubDistrict,
registrationZipCode: e.registrationZipCode,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const refreshData = async () => {
myform.value.reset();
await getNewData();
};
const getNewData = async () => {
await fetchData();
await fetchProvince();
await fetchDistrict(addressData.value.provinceId, "1");
await fetchDistrict(addressData.value.provinceIdC, "2");
await fetchSubDistrict(addressData.value.districtId, "1");
await fetchSubDistrict(addressData.value.districtIdC, "2");
await selectSubDistrict(addressData.value.subdistrictId, "1");
await selectSubDistrict(addressData.value.subdistrictIdC, "2");
};
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileAdrsId(route.params.id.toString()))
.then((res) => {
const data: ResponseObject = res.data.result;
addressData.value.address = data.registrationAddress;
addressData.value.addressC = data.currentAddress;
addressData.value.districtId = data.registrationDistrictId;
addressData.value.districtIdC = data.currentDistrictId;
addressData.value.provinceId = data.registrationProvinceId;
addressData.value.provinceIdC = data.currentProvinceId;
addressData.value.subdistrictId = data.registrationSubDistrictId;
addressData.value.subdistrictIdC = data.currentSubDistrictId;
addressData.value.same = data.registrationSame ? "1" : "0";
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const editData = async () => {
const body: ResponseObject = {
registrationSame: addressData.value.same == "1",
registrationAddress: addressData.value.address,
registrationSubDistrictId: addressData.value.subdistrictId,
registrationDistrictId: addressData.value.districtId,
registrationProvinceId: addressData.value.provinceId,
registrationZipCode: codep.value,
currentAddress:
addressData.value.same == "1"
? addressData.value.address
: addressData.value.addressC,
currentSubDistrictId:
addressData.value.same == "1"
? addressData.value.subdistrictId
: addressData.value.subdistrictIdC,
currentDistrictId:
addressData.value.same == "1"
? addressData.value.districtId
: addressData.value.districtIdC,
currentProvinceId:
addressData.value.same == "1"
? addressData.value.provinceId
: addressData.value.provinceIdC,
currentZipCode: addressData.value.same == "1" ? codep.value : codec.value,
createdAt: new Date(),
createdFullName: "-",
};
loaderPage(true);
await http
.put(config.API.profileAdrsId(route.params.id.toString()), body)
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
edit.value = false;
emit("update:statusEdit", false);
await getNewData();
});
};
const saveData = async () => {
await myform.value.validate().then(async (success: boolean) => {
if (success) {
await editData();
} else {
}
});
};
const selectProvince = async (e: string | null, name: string) => {
if (e != null) {
if (name == "1") {
addressData.value.districtId = "";
addressData.value.subdistrictId = "";
codep.value = "";
} else {
addressData.value.districtIdC = "";
addressData.value.subdistrictIdC = "";
codec.value = "";
}
myform.value.resetValidation();
await fetchDistrict(e, name);
}
};
const selectDistrict = async (e: string | null, name: string) => {
if (e != null) {
if (name == "1") {
addressData.value.subdistrictId = "";
codep.value = "";
} else {
addressData.value.subdistrictIdC = "";
codec.value = "";
}
myform.value.resetValidation();
await fetchSubDistrict(e, name);
}
};
const selectSubDistrict = (e: string | null, name: string) => {
if (e != null) {
if (name == "1") {
const findcode = Ops.value.subdistrictOps.filter((r) => r.id == e);
const namecode = findcode.length > 0 ? findcode[0].zipCode : "";
codep.value = namecode;
} else {
const findcode = Ops.value.subdistrictCOps.filter((r) => r.id == e);
const namecode = findcode.length > 0 ? findcode[0].zipCode : "";
codec.value = namecode;
}
}
};
const fetchProvince = async () => {
loaderPage(true);
await http
.get(config.API.province)
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
Ops.value.provinceOps = option;
OpsFilter.value.provinceOps = option;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const fetchDistrict = async (id: string | null, position: string) => {
if (id != null) {
loaderPage(true);
await http
.get(config.API.listDistrict(id))
.then((res) => {
const data = res.data.result;
let option: DataOption[] = [];
data.map((r: any) => {
option.push({ id: r.id.toString(), name: r.name.toString() });
});
if (position == "1") {
Ops.value.districtOps = option;
OpsFilter.value.districtOps = option;
} else {
Ops.value.districtCOps = option;
OpsFilter.value.districtCOps = option;
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
}
};
const fetchSubDistrict = async (id: string | null, position: string) => {
if (id != null) {
loaderPage(true);
await http
.get(config.API.listSubDistrict(id))
.then((res) => {
const data = res.data.result;
let option: zipCodeOption[] = [];
data.map((r: any) => {
option.push({
id: r.id.toString(),
name: r.name.toString(),
zipCode: r.zipCode.toString(),
});
});
if (position == "1") {
Ops.value.subdistrictOps = option;
OpsFilter.value.subdistrictOps = option;
} else {
Ops.value.subdistrictCOps = option;
OpsFilter.value.subdistrictCOps = option;
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
}
};
const changeBtn = async () => {
if (edit.value == true) {
if (props.statusEdit === true) {
edit.value = false;
props.notiNoEdit();
} else {
emit("update:statusEdit", true);
}
} else {
emit("update:statusEdit", false);
}
};
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

View file

@ -0,0 +1,826 @@
<!-- card ใบอนญาตประกอบอาช -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md q-mt-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
:name="
profileType == 'employee'
? 'ใบอนุญาตของลูกจ้าง'
: 'ใบอนุญาตประกอบอาชีพ'
"
icon="mdi-book"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div
v-if="col.name == 'issueDate' || col.name == 'expireDate'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader
:tittle="
profileType == 'employee'
? 'ใบอนุญาตของลูกจ้าง'
: 'ใบอนุญาตประกอบอาชีพ'
"
:close="clickClose"
/>
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center q-col-gutter-x-xs q-col-gutter-y-xs"
>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="certificateType"
:rules="[(val) => !!val || `${'กรุณากรอกชื่อใบอนุญาต'}`]"
hide-bottom-space
:label="`${'ชื่อใบอนุญาต'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="issuer"
:rules="[
(val) => !!val || `${'กรุณากรอกหน่วยงานผู้ออกใบอนุญาต'}`,
]"
hide-bottom-space
:label="`${'หน่วยงานผู้ออกใบอนุญาต'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="certificateNo"
:rules="[(val) => !!val || `${'กรุณากรอกเลขที่ใบอนุญาต'}`]"
hide-bottom-space
:label="`${'เลขที่ใบอนุญาต'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
:readonly="!edit"
v-model="issueDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(issueDate)"
:rules="[
(val) => !!val || `${'กรุณาเลือกวันที่ออกใบอนุญาต'}`,
]"
hide-bottom-space
:label="`${'วันที่ออกใบอนุญาต'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</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="expireDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
:min-date="minDate"
:readonly="!edit"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(expireDate)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่หมดอายุ'}`]"
hide-bottom-space
:label="`${'วันที่หมดอายุ'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="
col.name == 'expireDate' ||
col.name == 'issueDate' ||
col.name == 'createdAt'
"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Certificate";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Certificate";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
profileType: {
type: String,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const certificateNo = ref<string>();
const issuer = ref<string>();
const issueDate = ref<Date>(new Date());
const expireDate = ref<Date>(new Date());
const certificateType = ref<string>();
const minDate = ref<Date>();
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขใบอนุญาตประกอบอาชีพ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.certicate.columns.length == 0
? (visibleColumns.value = [
"certificateType",
"certificateNo",
"issuer",
"issueDate",
"expireDate",
])
: (visibleColumns.value = profileData.certicate.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "certificateType",
align: "left",
label: "ชื่อใบอนุญาต",
sortable: true,
field: "certificateType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issuer",
align: "left",
label: "หน่วยงานผู้ออกใบอนุญาต",
sortable: true,
field: "issuer",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "certificateNo",
align: "left",
label: "เลขที่ใบอนุญาต",
sortable: true,
field: "certificateNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issueDate",
align: "left",
label: "วันที่ออกใบอนุญาต",
sortable: true,
field: "issueDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "expireDate",
align: "left",
label: "วันที่หมดอายุ",
sortable: true,
field: "expireDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "certificateType",
align: "left",
label: "ชื่อใบอนุญาต",
sortable: true,
field: "certificateType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issuer",
align: "left",
label: "หน่วยงานผู้ออกใบอนุญาต",
sortable: true,
field: "issuer",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "certificateNo",
align: "left",
label: "เลขที่ใบอนุญาต",
sortable: true,
field: "certificateNo",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "issueDate",
align: "left",
label: "วันที่ออกใบอนุญาต",
sortable: true,
field: "issueDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "expireDate",
align: "left",
label: "วันที่หมดอายุ",
sortable: true,
field: "expireDate",
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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"certificateType",
"certificateNo",
"issuer",
"issueDate",
"expireDate",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("certicate", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileCertId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
certificateNo: e.certificateNo,
issuer: e.issuer,
issueDate: new Date(e.issueDate),
expireDate: new Date(e.expireDate),
certificateType: e.certificateType,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
certificateNo.value = row.certificateNo;
issuer.value = row.issuer;
issueDate.value = row.issueDate;
expireDate.value = row.expireDate;
certificateType.value = row.certificateType;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileCertId(profileId.value), {
id: id.value,
certificateNo: certificateNo.value,
issuer: issuer.value,
issueDate: dateToISO(issueDate.value),
expireDate: dateToISO(expireDate.value),
certificateType: certificateType.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileCertId(id.value), {
id: id.value,
certificateNo: certificateNo.value,
issuer: issuer.value,
issueDate: dateToISO(issueDate.value),
expireDate: dateToISO(expireDate.value),
certificateType: certificateType.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileCertId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true; //
modal.value = true; //modal
edit.value = false; // edit modal
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
certificateNo.value = props.row.certificateNo;
issuer.value = props.row.issuer;
issueDate.value = props.row.issueDate;
expireDate.value = props.row.expireDate;
certificateType.value = props.row.certificateType;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
certificateNo.value = "";
issuer.value = "";
issueDate.value = new Date();
expireDate.value = new Date();
certificateType.value = "";
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
tittleHistory.value =
props.profileType == "employee"
? "ประวัติแก้ไขใบอนุญาตของลูกจ้าง"
: "ประวัติแก้ไขใบอนุญาตประกอบอาชีพ";
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileCertHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
certificateNo: e.certificateNo,
issuer: e.issuer,
issueDate: new Date(e.issueDate),
expireDate: new Date(e.expireDate),
certificateType: e.certificateType,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,703 @@
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md q-mt-md">
<HeaderTop
v-model:edit="edit"
header="ข้อมูลราชการ"
icon="mdi-account-tie"
:save="saveData"
:history="true"
:changeBtn="changeBtn"
:disable="statusEdit"
:cancel="refreshData"
:historyClick="clickHistory"
/>
<q-form ref="myform" class="col-12">
<div class="row col-12 items-center q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-12">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.ocId"
:label="`${'สังกัด'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.positionId"
:label="`${'ตำแหน่ง'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.numberId"
:label="`${'เลขที่ตำแหน่ง'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.workId"
:label="`${'สายงาน'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.typeId"
:label="`${'ประเภท'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.levelId"
:label="`${'ระดับ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.businessId"
:label="`${'ตำแหน่งทางการบริหาร'}`"
/>
</div>
<div class="col-12 q-py-md"><q-separator /></div>
<div class="col-xs-6 col-sm-3 col-md-3">
<datepicker
v-model="govermentData.containDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:max-date="new Date()"
:disabled="!edit"
@update:model-value="handleDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
:model-value="date2Thai(new Date(govermentData.containDate))"
:rules="[(val) => !!val || `${'กรุณาเลือก วันที่สั่งบรรจุ'}`]"
:label="`${'วันที่สั่งบรรจุ'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit ? 'color: var(--q-primary)' : 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<datepicker
v-model="govermentData.workDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:max-date="new Date()"
:disabled="!edit"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
:model-value="date2Thai(new Date(govermentData.workDate))"
:rules="[
(val) => !!val || `${'กรุณาเลือก เริ่มปฎิบัติราชการ'}`,
]"
:label="`${'เริ่มปฎิบัติราชการ'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit ? 'color: var(--q-primary)' : 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
stack-label
:readonly="!edit"
:borderless="!edit"
v-model="govermentData.reasonSameDate"
:label="`${'เหตุผลกรณีไม่ตรงวัน'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.retireDate"
:label="`${'วันเกษียณอายุ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.ageAll"
:label="`${'อายุราชการ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.absent"
:label="`${'ขาดราชการ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:model-value="govermentData.age"
:label="`${'อายุราชการเกื้อกูล'}`"
/>
</div>
</div>
</q-form>
</q-card>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="
col.name == 'dateStart' ||
col.name == 'dateAppoint' ||
col.name == 'createdAt'
"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import { useQuasar } from "quasar";
import type { Goverment } from "@/modules/04_registry/components/profileType";
import { defaultGoverment } from "@/modules/04_registry/components/profileType";
import HeaderTop from "@/modules/04_registry/components/Information/top.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import HistoryTable from "@/components/TableHistory.vue";
import type { RequestItemsHistoryObject } from "@/modules/04_registry/interface/request/Government";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Government";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { storeToRefs } from "pinia";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
notiNoEdit: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:statusEdit"]);
const route = useRoute();
const $q = useQuasar();
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const profileStore = useProfileDataStore();
const { birthDate, retireText } = storeToRefs(profileStore);
const edit = ref<boolean>(false);
const govermentData = ref<Goverment>(defaultGoverment);
const myform = ref<any>();
const rowsHistory = ref<RequestItemsHistoryObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขข้อมูลราชการ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
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: "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: "dateAppoint",
align: "left",
label: "วันที่สั่งบรรจุ",
sortable: true,
field: "dateAppoint",
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",
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",
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"oc",
"position",
"posNo",
"positionLine",
"positionType",
"positionLevel",
"positionexecutive",
"dateAppoint",
"dateStart",
"retireDate",
"govAge",
"govAgeAbsent",
"govAgePlus",
"reasonSameDate",
"createdFullName",
"createdAt",
]);
onMounted(async () => {
await fetchData();
emit("update:statusEdit", false);
});
watch(birthDate, async () => {
await fetchData();
});
watch(retireText, async () => {
govermentData.value.retireDate = retireText.value;
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileGovId(route.params.id.toString()))
.then((res) => {
const data: ResponseObject = res.data.result;
govermentData.value.ocId = data.oc;
govermentData.value.positionId = data.position;
govermentData.value.workId = data.work;
govermentData.value.typeId = data.type;
govermentData.value.levelId = data.level;
govermentData.value.numberId = data.posNo;
govermentData.value.businessId = data.business;
govermentData.value.containDate = new Date(data.dateAppoint);
govermentData.value.workDate = new Date(data.dateStart);
govermentData.value.retireDate = data.retireDate;
govermentData.value.absent = data.govAgeAbsent;
govermentData.value.age = data.govAgePlus;
govermentData.value.ageAll = data.govAge;
govermentData.value.reasonSameDate = data.reasonSameDate;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
loaderPage(false);
});
};
const refreshData = async () => {
myform.value.reset();
await fetchData();
};
const editData = async () => {
loaderPage(true);
const body: ResponseObject = {
oc: govermentData.value.ocId,
business: govermentData.value.businessId,
dateAppoint: dateToISO(govermentData.value.containDate),
dateStart: dateToISO(govermentData.value.workDate),
govAge: govermentData.value.ageAll,
govAgeAbsent: govermentData.value.absent,
govAgePlus: govermentData.value.age,
level: govermentData.value.levelId,
posNo: govermentData.value.numberId,
position: govermentData.value.positionId,
retireDate: govermentData.value.retireDate,
type: govermentData.value.typeId,
work: govermentData.value.workId,
reasonSameDate: govermentData.value.reasonSameDate,
createdAt: new Date(),
createdFullName: "-",
};
await http
.put(config.API.profileGovId(route.params.id.toString()), body)
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
emit("update:statusEdit", false);
edit.value = false;
await refreshData();
});
};
const saveData = async () => {
await myform.value.validate().then(async (success: boolean) => {
if (success) {
await editData();
} else {
}
});
};
const handleDate = async (modelData: Date) => {
govermentData.value.containDate = modelData;
await fetchCalAgeGov(modelData);
};
const fetchCalAgeGov = async (date: Date) => {
loaderPage(true);
const body = {
dateAppoint: date,
};
await http
.post(config.API.profileCalGovId(route.params.id.toString()), body)
.then((res) => {
const result = res.data.result;
govermentData.value.ageAll = result;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
loaderPage(false);
});
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
*/
const clickHistory = async () => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileGovHisId(route.params.id.toString()))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: RequestItemsHistoryObject) => {
rowsHistory.value.push({
oc: e.oc,
position: e.position,
posNo: e.posNo,
positionLine: e.positionLine,
positionType: e.positionType,
positionLevel: e.positionLevel,
positionExecutive: e.positionExecutive,
dateAppoint: new Date(e.dateAppoint),
dateStart: new Date(e.dateStart),
retireDate: e.retireDate,
govAge: e.govAge,
govAgeAbsent: e.govAgeAbsent,
govAgePlus: e.govAgePlus,
reasonSameDate: e.reasonSameDate,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const changeBtn = async () => {
if (edit.value == true) {
if (props.statusEdit === true) {
edit.value = false;
props.notiNoEdit();
} else {
emit("update:statusEdit", true);
}
} else {
emit("update:statusEdit", false);
}
};
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

View file

@ -0,0 +1,983 @@
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<HeaderTop
v-model:edit="edit"
header="ข้อมูลส่วนตัว"
icon="mdi-account"
:save="saveData"
:history="true"
:changeBtn="changeBtn"
:disable="statusEdit"
:cancel="onCancel"
:historyClick="clickHistory"
/>
<q-form ref="myform" class="col-12">
<div class="row col-12 items-center q-col-gutter-x-sm q-col-gutter-y-sm">
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="informaData.cardid"
maxlength="13"
:rules="[
(val:string) => !!val || `${'กรุณากรอก เลขบัตรประจำตัวประชาชน'}`,
(val:string) =>
val.length >= 13 ||
`${'กรุณากรอกเลขบัตรประจำตัวประชาชนให้ครบ'}`,
]"
label="เลขบัตรประจำตัวประชาชน"
mask="#############"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก คำนำหน้า'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.prefixId"
emit-value
map-options
option-label="name"
:options="Ops.prefixOps"
option-value="id"
:label="`${'คำนำหน้า'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'prefixOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="informaData.firstname"
:rules="[(val:string) => !!val || `${'กรุณากรอก ชื่อ'}`]"
:label="`${'ชื่อ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="informaData.lastname"
:rules="[(val:string) => !!val || `${'กรุณากรอก นามสกุล'}`]"
:label="`${'นามสกุล'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<datepicker
v-model="informaData.birthDate"
:locale="'th'"
autoApply
:enableTimePicker="false"
week-start="0"
:max-date="new Date()"
:disabled="!edit"
@update:model-value="handleDate"
>
<template #year="{ year }">
{{ year + 543 }}
</template>
<template #year-overlay-value="{ value }">
{{ parseInt(value + 543) }}
</template>
<template #trigger>
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
:model-value="date2Thai(informaData.birthDate)"
:rules="[(val:string) => !!val || `${'กรุณาเลือก วัน/เดือน/ปี เกิด'}`]"
:label="`${'วัน/เดือน/ปี เกิด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit ? 'color: var(--q-primary)' : 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(false)"
hide-bottom-space
dense
lazy-rules
readonly
borderless
:style="!edit ? '' : 'padding:0 12px;'"
:model-value="informaData.age"
:label="`${'อายุ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก เพศ'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.genderId"
emit-value
map-options
option-label="name"
:options="Ops.genderOps"
option-value="id"
:label="`${'เพศ'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'genderOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก สถานภาพ'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.statusId"
emit-value
map-options
option-label="name"
:options="Ops.statusOps"
option-value="id"
:label="`${'สถานภาพ'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'statusOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก หมู่เลือด'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.bloodId"
emit-value
map-options
option-label="name"
:options="Ops.bloodOps"
option-value="id"
:label="`${'หมู่เลือด'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'bloodOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="informaData.nationality"
:rules="[(val:string) => !!val || `${'กรุณากรอก สัญชาติ'}`]"
:label="`${'สัญชาติ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
:class="getClass(edit)"
hide-bottom-space
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="informaData.ethnicity"
:rules="[(val:string) => !!val || `${'กรุณากรอก เชื้อชาติ'}`]"
:label="`${'เชื้อชาติ'}`"
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก ศาสนา'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.religionId"
emit-value
map-options
option-label="name"
:options="Ops.religionOps"
option-value="id"
:label="`${'ศาสนา'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'religionOps'
) "
/>
</div>
<div class="col-xs-6 col-sm-3 col-md-3">
<q-input
hide-bottom-space
:outlined="edit"
dense
lazy-rules
type="tel"
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
v-model="informaData.tel"
:rules="[
(val:string) => !!val || `${'กรุณากรอก เบอร์โทร'}`,
(val:string) => val.length >= 10 || `${'กรุณากรอกข้อมูลเบอร์โทรให้ครบ'}`,
]"
:label="`${'เบอร์โทร'}`"
mask="##########"
/>
</div>
<div
class="col-xs-6 col-sm-3 col-md-3"
v-if="informaData.profileType == 'employee'"
>
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก ประเภทการจ้าง'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.employeeType"
emit-value
map-options
option-label="name"
:options="Ops.employeeTypeOps"
option-value="id"
:label="`${'ประเภทการจ้าง'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'employeeTypeOps'
) "
/>
</div>
<div
class="col-xs-6 col-sm-3 col-md-3"
v-if="informaData.profileType == 'employee'"
>
<selector
:hide-dropdown-icon="!edit"
hide-bottom-space
:class="getClass(edit)"
:readonly="!edit"
:borderless="!edit"
:rules="[(val:string) => !!val || `${'กรุณาเลือก ประเภทลูกจ้าง'}`]"
:outlined="edit"
dense
lazy-rules
v-model="informaData.employeeClass"
emit-value
map-options
option-label="name"
:options="Ops.employeeClassOps"
option-value="id"
:label="`${'ประเภทลูกจ้าง'}`"
use-input
input-debounce="0"
@filter="(inputValue:any,
doneFn:Function) => filterSelector(inputValue, doneFn,'employeeClassOps'
) "
/>
</div>
</div>
</q-form>
</q-card>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="col.name == 'birthDate' || col.name == 'createdAt'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import { useQuasar } from "quasar";
import type {
Information,
DataOption,
} from "@/modules/04_registry/components/profileType";
import { defaultInformation } from "@/modules/04_registry/components/profileType";
import type {
RequestItemsHistoryObject,
Columns,
} from "@/modules/04_registry/interface/request/Information";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Information";
import type { InformationOps } from "@/modules/04_registry/interface/index/Main";
import HeaderTop from "@/modules/04_registry/components/Information/top.vue";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import type { QTableColumn, QForm } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
notiNoEdit: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:statusEdit"]);
const route = useRoute();
const $q = useQuasar();
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError, modalError } = mixin;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const profileStore = useProfileDataStore();
const { changeRetireText, changeBirth } = profileStore;
const edit = ref<boolean>(false);
const informaData = ref<Information>(defaultInformation);
const rowsHistory = ref<RequestItemsHistoryObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขข้อมูลส่วนตัว"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const age = ref<boolean>(true);
const myform = ref<QForm | null>(null);
const Ops = ref<InformationOps>({
prefixOps: [],
genderOps: [],
bloodOps: [],
statusOps: [],
religionOps: [],
employeeClassOps: [
{ id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" },
{ id: "bkk", name: "งบประมาณกรุงเทพมหานคร" },
],
employeeTypeOps: [
{ id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" },
{ id: "bkk", name: "งบประมาณกรุงเทพมหานคร" },
],
});
const OpsFilter = ref<InformationOps>({
prefixOps: [],
genderOps: [],
bloodOps: [],
statusOps: [],
religionOps: [],
employeeClassOps: [
{ id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" },
{ id: "bkk", name: "งบประมาณกรุงเทพมหานคร" },
],
employeeTypeOps: [
{ id: "gov", name: "งบประมาณเงินอุดหนุนรัฐบาล" },
{ id: "bkk", name: "งบประมาณกรุงเทพมหานคร" },
],
});
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: "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",
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: "race",
align: "left",
label: "เชื้อชาติ",
sortable: true,
field: "race",
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: "telephoneNumber",
align: "left",
label: "เบอร์โทร",
sortable: true,
field: "telephoneNumber",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "employeeType",
align: "left",
label: "ประเภทการจ้าง",
sortable: true,
field: "employeeType",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "employeeClass",
align: "left",
label: "ประเภทลูกจ้าง",
sortable: true,
field: "employeeClass",
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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"citizenId",
"prefix",
"firstName",
"lastName",
"birthDate",
"gender",
"relationship",
"bloodGroup",
"nationality",
"race",
"religion",
"telephoneNumber",
"employeeType",
"employeeClass",
"createdFullName",
"createdAt",
]);
onMounted(async () => {
await fetchPerson();
await fetchData();
emit("update:statusEdit", false);
});
const onCancel = async () => {
if (myform.value != null) {
myform.value.reset();
}
await fetchData();
};
/**
* get รายการ อมลเกยวกบบคคล
*/
const fetchPerson = async () => {
loaderPage(true);
await http
.get(config.API.person)
.then((res) => {
const data = res.data.result;
let optionbloodGroups: DataOption[] = [];
data.bloodGroups.map((r: any) => {
optionbloodGroups.push({
id: r.id.toString(),
name: r.name.toString(),
});
});
Ops.value.bloodOps = optionbloodGroups;
OpsFilter.value.bloodOps = optionbloodGroups;
let optiongenders: DataOption[] = [];
data.genders.map((r: any) => {
optiongenders.push({
id: r.id.toString(),
name: r.name.toString(),
});
});
Ops.value.genderOps = optiongenders;
OpsFilter.value.genderOps = optiongenders;
let optionprefixs: DataOption[] = [];
data.prefixs.map((r: any) => {
optionprefixs.push({
id: r.id.toString(),
name: r.name.toString(),
});
});
Ops.value.prefixOps = optionprefixs;
OpsFilter.value.prefixOps = optionprefixs;
let optionrelationships: DataOption[] = [];
data.relationships.map((r: any) => {
optionrelationships.push({
id: r.id.toString(),
name: r.name.toString(),
});
});
Ops.value.statusOps = optionrelationships;
OpsFilter.value.statusOps = optionrelationships;
let optionreligions: DataOption[] = [];
data.religions.map((r: any) => {
optionreligions.push({
id: r.id.toString(),
name: r.name.toString(),
});
});
Ops.value.religionOps = optionreligions;
OpsFilter.value.religionOps = optionreligions;
})
.catch((e: any) => {})
.finally(() => {
loaderPage(false);
});
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
*/
const clickHistory = async () => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileInforHisId(route.params.id.toString()))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: RequestItemsHistoryObject) => {
rowsHistory.value.push({
citizenId: e.citizenId,
prefix: e.prefix,
firstName: e.firstName,
lastName: e.lastName,
birthDate: new Date(e.birthDate),
gender: e.gender,
relationship: e.relationship,
bloodGroup: e.bloodGroup,
nationality: e.nationality,
race: e.race,
religion: e.religion,
telephoneNumber: e.telephoneNumber,
employeeType:
e.employeeType == "gov"
? "งบประมาณเงินอุดหนุนรัฐบาล"
: e.employeeType == "bkk"
? "งบประมาณกรุงเทพมหานคร"
: "-",
employeeClass:
e.employeeClass == "perm"
? "ลูกจ้างประจำ"
: e.employeeClass == "temp"
? "ลูกจ้างชั่วคราว"
: "-",
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const filterSelector = (val: any, update: Function, refData: string) => {
switch (refData) {
case "prefixOps":
update(() => {
Ops.value.prefixOps = OpsFilter.value.prefixOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "genderOps":
update(() => {
Ops.value.genderOps = OpsFilter.value.genderOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "bloodOps":
update(() => {
Ops.value.bloodOps = OpsFilter.value.bloodOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "statusOps":
update(() => {
Ops.value.statusOps = OpsFilter.value.statusOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "religionOps":
update(() => {
Ops.value.religionOps = OpsFilter.value.religionOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "employeeClassOps":
update(() => {
Ops.value.employeeClassOps = OpsFilter.value.employeeClassOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
case "employeeTypeOps":
update(() => {
Ops.value.employeeTypeOps = OpsFilter.value.employeeTypeOps.filter(
(v: DataOption) => v.name.indexOf(val) > -1
);
});
break;
default:
break;
}
};
const handleDate = async (modelData: Date) => {
informaData.value.birthDate = modelData;
await calRetire(modelData);
};
const calRetire = async (birth: Date) => {
const body = {
birthDate: dateToISO(birth),
};
loaderPage(true);
await http
.post(config.API.profileCalRetire, body)
.then((res: any) => {
const data = res.data.result;
informaData.value.age = data.age;
changeRetireText(data.retireDate);
age.value = true;
})
.catch((e: any) => {
age.value = false;
messageError($q, e);
const retire = new Date(`${birth.getFullYear() + 60}-09-30`);
changeRetireText(date2Thai(retire));
})
.finally(() => {
loaderPage(false);
});
};
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileInforId(route.params.id.toString()))
.then(async (res: any) => {
const data: ResponseObject = res.data.result;
informaData.value.cardid = data.citizenId;
informaData.value.prefix = "";
informaData.value.prefixId = data.prefixId;
informaData.value.firstname = data.firstName;
informaData.value.lastname = data.lastName;
informaData.value.birthDate = new Date(data.birthDate);
informaData.value.genderId = data.genderId;
informaData.value.bloodId = data.bloodGroupId;
informaData.value.nationality = data.nationality;
informaData.value.ethnicity = data.race;
informaData.value.statusId = data.relationshipId;
informaData.value.religionId = data.religionId;
informaData.value.tel = data.telephoneNumber;
informaData.value.age = data.age;
informaData.value.employeeType = data.employeeType;
informaData.value.employeeClass = data.employeeClass;
informaData.value.profileType = data.profileType;
await calRetire(new Date(dateToISO(new Date(data.birthDate))));
if (data.profileType == "officer" && columnsHistory.value.length >= 15) {
columnsHistory.value.splice(13, 1);
columnsHistory.value.splice(12, 1);
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const editData = async () => {
if (age.value == false) {
modalError($q, "พบข้อผิดพลาด", "วันเกิดไม่ถูกต้อง");
return;
}
const body: any = {
citizenId: informaData.value.cardid,
prefixId: informaData.value.prefixId,
firstName: informaData.value.firstname,
lastName: informaData.value.lastname,
genderId: informaData.value.genderId,
nationality: informaData.value.nationality,
race: informaData.value.ethnicity,
religionId: informaData.value.religionId,
birthDate: dateToISO(informaData.value.birthDate) ?? dateToISO(new Date()),
bloodGroupId: informaData.value.bloodId,
relationshipId: informaData.value.statusId,
telephoneNumber: informaData.value.tel,
createdAt: new Date(),
age: null,
employeeType: informaData.value.employeeType,
employeeClass: informaData.value.employeeClass,
profileType: informaData.value.profileType,
createdFullName: "-",
};
loaderPage(true);
await http
.put(config.API.profileInforId(route.params.id.toString()), body)
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
edit.value = false;
emit("update:statusEdit", false);
await fetchData();
await changeBirth(informaData.value.birthDate ?? new Date());
});
};
const saveData = async () => {
if (myform.value != null) {
await myform.value.validate().then(async (success: boolean) => {
if (success) {
await editData();
} else {
}
});
}
};
const changeBtn = async () => {
if (edit.value == true) {
if (props.statusEdit === true) {
edit.value = false;
props.notiNoEdit();
} else {
emit("update:statusEdit", true);
}
} else {
emit("update:statusEdit", false);
}
};
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

View file

@ -0,0 +1,62 @@
<template>
<Information :notiNoEdit="notiNoEdit" v-model:statusEdit="statusEdit" />
<Government :notiNoEdit="notiNoEdit" v-model:statusEdit="statusEdit" />
<Address :notiNoEdit="notiNoEdit" v-model:statusEdit="statusEdit" />
<Family :notiNoEdit="notiNoEdit" v-model:statusEdit="statusEdit" />
<!-- <Certicate v-model:statusEdit="statusEdit" :profileType="profileType" /> -->
<!-- <NotifyError
:modalError="modalNoEdit"
:modalErrorTittle="modalNoEditTittle"
:modalErrorDetail="modalNoEditDetail"
:close="closeModalError"
/> -->
</template>
<script setup lang="ts">
import { ref, onMounted, watch } from "vue";
import Information from "@/modules/04_registry/components/Information/Information.vue";
import Government from "@/modules/04_registry/components/Information/Government.vue";
import Address from "@/modules/04_registry/components/Information/Address.vue";
import Family from "@/modules/04_registry/components/Information/Family.vue";
import Certicate from "@/modules/04_registry/components/Information/Certicate.vue";
// import NotifyError from "@/components/NotifyError.vue";
import { useDataStore } from "@/stores/data";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
profileType: {
type: String,
required: true,
},
});
const emit = defineEmits(["update:statusEdit"]);
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const statusEdit = ref<boolean>(false);
const modalNoEdit = ref<boolean>(false);
const modalNoEditTittle = ref<string>("ไม่สามารถไม่สามารถแก้ไขข้อมูลได้?");
const modalNoEditDetail = ref<string>("มีข้อมูลที่ยังไม่ถูกบันทึกข้อมูล");
watch(statusEdit, (count: boolean, prevCount: boolean) => {
emit("update:statusEdit", count);
});
watch(props, (count: any, prevCount: any) => {
statusEdit.value = props.statusEdit;
});
onMounted(() => {
loaderPage(false);
});
const notiNoEdit = () => {
modalNoEdit.value = true;
};
const closeModalError = () => {
modalNoEdit.value = false;
};
</script>

View file

@ -0,0 +1,167 @@
<template>
<div class="flex items-center">
<div class="flex items-center">
<q-icon
:name="icon"
size="1.5em"
color="grey-5"
class="q-mr-md"
v-if="icon != ''"
/>
<div
class="text-bold text-subtitle2 col-12 row items-center"
v-if="header != ''"
>
{{ header }}
</div>
</div>
<div class="q-gutter-sm q-mx-sm" v-if="addData == false">
<q-btn
size="12px"
v-if="!edit"
flat
round
:disabled="disable"
:color="edit ? 'grey-7' : 'primary'"
@click="ClickEdit"
icon="mdi-pencil-outline"
>
<q-tooltip>แกไขขอม</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
round
v-if="edit"
:color="!edit ? 'grey-7' : 'public'"
@click="save"
icon="mdi-content-save-outline"
>
<q-tooltip>นทกขอม</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
round
v-if="edit"
:color="!edit ? 'grey-7' : 'red'"
@click="ClickCancel"
icon="mdi-undo"
>
<q-tooltip>ยกเล</q-tooltip>
</q-btn>
</div>
<div class="q-pl-sm" v-else>
<q-btn
size="12px"
flat
round
:disabled="disable"
color="add"
@click="add"
icon="mdi-plus"
>
<q-tooltip>เพมขอม</q-tooltip>
</q-btn>
</div>
<q-space />
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
v-if="history"
@click="historyClick"
>
<q-tooltip>ประว{{ header }}</q-tooltip>
</q-btn>
</div>
</template>
<script setup lang="ts">
const props = defineProps({
header: {
type: String,
default: "ข้อความ",
required: true,
},
icon: {
type: String,
default: "mdi-help",
required: true,
},
edit: {
type: Boolean,
default: true,
required: true,
},
history: {
type: Boolean,
default: true,
required: true,
},
addData: {
type: Boolean,
defualt: false,
},
disable: {
type: Boolean,
defualt: false,
},
historyClick: {
type: Function,
default: () => console.log("not function"),
},
add: {
type: Function,
default: () => console.log("not function"),
},
save: {
type: Function,
default: () => console.log("not function"),
},
deleted: {
type: Function,
default: () => console.log("not function"),
},
cancel: {
type: Function,
default: () => console.log("not function"),
},
changeBtn: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits(["update:edit"]);
const updateEdit = (value: any) => {
emit("update:edit", value);
};
const ClickEdit = () => {
updateEdit(!props.edit);
props.changeBtn();
};
const historyClick = async () => {
await props.historyClick();
};
const ClickCancel = () => {
updateEdit(!props.edit);
props.cancel();
props.changeBtn();
};
const save = () => {
props.save();
};
const add = () => {
props.add();
};
</script>
<style scoped></style>

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,614 @@
<!-- card นๆ -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="อื่นๆ"
icon="mdi-bookmark"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div v-if="col.name == 'date'" class="table_ellipsis">
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader tittle="อื่นๆ" :close="clickClose" />
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="date"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(date)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่'}`]"
hide-bottom-space
:label="`${'วันที่'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
autogrow
:readonly="!edit"
:borderless="!edit"
v-model="detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="col.name == 'date' || col.name == 'createdAt'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Other";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Other";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const date = ref<Date>(new Date());
const detail = ref<string>();
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขอื่นๆ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.other.columns.length == 0
? (visibleColumns.value = ["date", "detail"])
: (visibleColumns.value = profileData.other.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วันที่",
sortable: true,
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width: 50px;",
},
{
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" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วันที่",
sortable: true,
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width: 50px;",
},
{
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"date",
"detail",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("other", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileOtherId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
date: new Date(e.date),
detail: e.detail,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
date.value = row.date;
detail.value = row.detail;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileOtherId(profileId.value), {
id: id.value,
date: date.value,
detail: detail.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileOtherId(id.value), {
id: id.value,
date: date.value,
detail: detail.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileOtherId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
date.value = props.row.date;
detail.value = props.row.detail;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
date.value = new Date();
detail.value = "";
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileOtherHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
date: e.date,
detail: e.detail,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

View file

@ -0,0 +1,903 @@
<template>
<div class="col-12 row">
<div class="row col-12" style="padding-top: 80px">
<div id="information" name="1" class="row col-12 information">
<Informationvue v-model:statusEdit="statusEdit" :profileType="profileType" />
</div>
<div id="certicate" name="15" class="row col-12 q-mt-md">
<Certicate v-model:statusEdit="statusEdit" :profileType="profileType" />
</div>
<div id="education" name="2" class="row col-12 q-mt-md">
<EducationVue v-model:statusEdit="statusEdit" />
</div>
<div id="training" name="3" class="row col-12 q-mt-md">
<TrainVue v-model:statusEdit="statusEdit" />
</div>
<div id="insignia" name="4" class="row col-12 q-mt-md">
<InsigniaVue v-model:statusEdit="statusEdit" />
</div>
<div id="coined" name="5" class="row col-12 q-mt-md">
<CoinedVue v-model:statusEdit="statusEdit" :profileType="profileType" />
</div>
<div id="assessment" name="6" class="row col-12 q-mt-md">
<AssessmentVue v-model:statusEdit="statusEdit" :profileType="profileType" />
</div>
<div id="position" name="7" class="row col-12 q-mt-md">
<SalaryVue v-model:statusEdit="statusEdit" />
</div>
<div id="rule" name="8" class="row col-12 q-mt-md">
<DisciplineVue v-model:statusEdit="statusEdit" />
</div>
<div id="leave" name="9" class="row col-12 q-mt-md">
<LeaveVue v-model:statusEdit="statusEdit" />
</div>
<div id="talent" name="10" class="row col-12 q-mt-md">
<TalentVue v-model:statusEdit="statusEdit" />
</div>
<div id="work" name="11" class="row col-12 q-mt-md">
<WorkVue v-model:statusEdit="statusEdit" />
</div>
<div id="record" name="12" class="row col-12 q-mt-md">
<RecordVue v-model:statusEdit="statusEdit" />
</div>
<div id="other" name="13" class="row col-12 q-mt-md">
<OtherVue v-model:statusEdit="statusEdit" />
</div>
<div id="document" name="14" class="row col-12 q-my-md">
<DocumentVue v-model:statusEdit="statusEdit" />
</div>
</div>
<q-page-sticky
position="top"
expand
class="bg-grey-2 text-white"
style="z-index: 99; padding: 0% 1% 0% 1%"
>
<div class="row col-12 q-gutter-sm q-pb-sm text-dark no-wrap items-center">
<q-btn
flat
round
class="bg-teal-1 full-height"
color="primary"
icon="mdi-chevron-left"
dense
@click="router.go(-1)"
>
</q-btn>
<q-avatar v-if="imageUrl == null" size="65px" rounded class="containerimage">
<img
src="@/assets/avatar_user.jpg"
class="bg-grey-3"
style="object-fit: cover"
/>
<div
class="overlay absolute-bottom text-subtitle2 text-center cursor-pointer"
@click="clickImage()"
>
<q-icon name="mdi-camera" size="18px" color="blue">
<q-tooltip>ปเดตรปภาพ</q-tooltip>
</q-icon>
<input
type="file"
style="display: none"
ref="inputImage"
accept="image/*"
@change="uploadImage"
/>
</div>
</q-avatar>
<q-avatar v-else size="65px" rounded class="containerimage">
<img :src="imageUrl" class="bg-grey-3" style="object-fit: cover" />
<div
class="overlay absolute-bottom text-subtitle2 text-center cursor-pointer"
@click="clickImage()"
>
<q-icon name="mdi-camera" size="18px" color="blue">
<q-tooltip>ปเดตรปภาพ</q-tooltip>
</q-icon>
<input
type="file"
style="display: none"
ref="inputImage"
accept="image/*"
@change="uploadImage"
/>
</div>
</q-avatar>
<div class="row items-center text-dark q-ml-md">
<div class="column">
<div class="text-bold q-pb-xs text-name">{{ fullname }}{{ leaveReason }}</div>
<div>{{ position }}</div>
</div>
</div>
<q-space />
<q-btn
round
flat
:color="reasonStatus ? 'primary' : 'pink-5'"
@click="clickRetire()"
:icon="reasonStatus ? 'mdi-home-import-outline' : 'mdi-home-export-outline'"
>
<q-tooltip>{{ reasonStatus ? "กลับเข้าราชการ" : "ออกราชการ" }}</q-tooltip>
</q-btn>
<q-btn icon="mdi-file-eye-outline" round color="primary" flat>
<q-tooltip>ดาวนโหลดไฟล</q-tooltip>
<q-menu>
<q-list style="min-width: 100px">
<q-item clickable v-close-popup @click="clickKp7()">
<q-item-section class="text-blue">..7/..1</q-item-section>
</q-item>
<q-item clickable v-close-popup @click="clickKp7Short()">
<q-item-section class="text-primary">ประวแบบย</q-item-section>
</q-item>
</q-list>
</q-menu>
</q-btn>
</div>
</q-page-sticky>
</div>
<q-dialog v-model="dialog" persistent>
<q-card style="width: 90vw; max-width: 80vw">
<q-card-section class="row items-center q-pb-xs col-12">
<q-space />
<q-btn
@click="downloadKP7()"
unelevated
class="btn_purple q-mr-sm"
label="ดาวน์โหลด ก.พ.7/ก.ก.1"
></q-btn>
<q-btn
icon="close"
unelevated
round
dense
@click="closeKp7"
style="color: #ff8080; background-color: #ffdede"
/>
</q-card-section>
<q-card-section class="q-p-sm">
<!-- <viewpdf
:src="pdfSrc"
:currentpage="pdfCurrentPage"
:totalpage="pdfTotalPage"
></viewpdf> -->
</q-card-section>
</q-card>
</q-dialog>
<q-dialog v-model="dialogShort" persistent>
<q-card style="width: 90vw; max-width: 80vw">
<q-card-section class="row items-center q-pb-xs col-12">
<q-space />
<q-btn
@click="downloadKP7Short()"
unelevated
class="btn_purple q-mr-sm"
label="ดาวน์โหลด ประวัติแบบย่อ"
></q-btn>
<q-btn
icon="close"
unelevated
round
dense
@click="closeKp7Short"
style="color: #ff8080; background-color: #ffdede"
/>
</q-card-section>
<q-card-section class="q-p-sm">
<!-- <viewpdf
:src="pdfSrcShort"
:currentpage="pdfCurrentPageShort"
:totalpage="pdfTotalPageShort"
></viewpdf> -->
</q-card-section>
</q-card>
</q-dialog>
<!-- Dialog เลอก Image -->
<q-dialog v-model="dialogImage" persistent>
<q-card style="width: 100vw; max-width: 60vw">
<q-card-section class="q-py-sm row">
<div class="text-h6">เลอกรปภาพ</div>
<q-space />
<q-btn
icon="close"
unelevated
round
dense
@click="closeImage"
style="color: #ff8080; background-color: #ffdede"
>
<q-tooltip>ดหนาน</q-tooltip>
</q-btn>
</q-card-section>
<q-separator />
<q-card-section class="col-12 row">
<div
class="row wrap items-start col-12 q-col-gutter-sm"
style="height: 320px; overflow: auto"
>
<div class="col-3" @click="addNewImage">
<div
style="
height: 160px;
max-width: 15vw;
display: flex !important;
justify-content: center;
align-items: center;
"
class="column rounded-borders cursor-pointer bg-active-image text-white"
>
<q-icon name="add" size="60px" color="white" />
<strong>ปโหลดรปภาพ</strong>
</div>
</div>
<div v-for="n in images" :key="n" class="col-3" @click="imageActive(n)">
<div :class="getClass(n)">
<q-img v-if="n.avatar != null" :src="n.avatar" :class="imageClass(n)">
<!-- <div
class="absolute-top bg-transparent cursor-pointer text-right"
style="padding: 5px"
>
<q-btn
icon="delete"
unelevated
round
dense
@click="deletePhoto"
style="color: #ff8080"
/>
</div> -->
<div
class="absolute-bottom col-12 cursor-pointer flex justify-between items-center"
style="padding: 5px"
>
{{ date2Thai(n.createdDate) }}
<q-btn
icon="delete"
unelevated
dense
@click="deletePhoto(n.id)"
class="bg-white"
style="color: #ff8080"
/>
</div>
</q-img>
</div>
</div>
</div>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<!-- <q-btn
flat
round
color="red"
@click="() => {}"
icon="mdi-delete-outline"
>
<q-tooltip>ลบรปภาพ</q-tooltip>
</q-btn> -->
<q-btn
icon="check"
dense
flat
round
@click="selectAvatarHistory"
color="positive"
>
<q-tooltip>เลอกรปภาพ</q-tooltip>
</q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<!-- Dialog เลอก เกษยณ -->
<q-dialog v-model="dialogLeave" persistent>
<q-card style="width: 600px">
<q-toolbar>
<q-toolbar-title class="text-subtitle2 text-bold"
>ประเภทการพนราชการ
</q-toolbar-title>
<q-btn
icon="close"
unelevated
round
dense
@click="closeLeave"
style="color: #ff8080; background-color: #ffdede"
/>
</q-toolbar>
<q-separator />
<q-card-section class="q-p-sm">
<div class="row col-12 items-center q-col-gutter-x-xs q-col-gutter-y-xs">
<div class="col-xs-6 col-sm-6 col-md-6">
<q-select
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
v-model="reason"
:rules="[(val) => !!val || `${'กรุณาเลือกประเภทการพ้นราชการ'}`]"
hide-bottom-space
:label="`${'ประเภทการพ้นราชการ'}`"
emit-value
map-options
option-label="name"
:options="reasonOptions"
option-value="id"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="leaveDate"
: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
:model-value="date2Thai(leaveDate)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่พ้นราชการ'}`]"
hide-bottom-space
: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-6 col-sm-6 col-md-6">
<q-input
class="full-width inputgreen cursor-pointer"
outlined
dense
lazy-rules
autogrow
v-model="leaveDetail"
: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
lazy-rules
autogrow
v-model="leaveNumberOrder"
:rules="[(val) => !!val || `${'กรุณากรอกคำสั่ง/เอกสารอ้างอิง'}`]"
hide-bottom-space
:label="`${'คำสั่ง/เอกสารอ้างอิง'}`"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
v-model="leaveDateOrder"
: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
:model-value="date2Thai(leaveDateOrder)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่ออกคำสั่ง'}`]"
hide-bottom-space
: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>
</q-card-section>
<q-separator />
<q-card-actions align="right">
<q-btn flat round color="public" @click="Retire" icon="mdi-content-save-outline">
<q-tooltip>นท</q-tooltip>
</q-btn>
</q-card-actions>
</q-card>
</q-dialog>
<full-loader :visibility="loader"></full-loader>
</template>
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useDataStore } from "@/stores/data";
import { useRoute, useRouter } from "vue-router";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import Informationvue from "@/modules/04_registry/components/Information/layout.vue";
import EducationVue from "@/modules/04_registry/components/Education.vue";
import TrainVue from "@/modules/04_registry/components/Train.vue";
import InsigniaVue from "@/modules/04_registry/components/Insignia.vue";
import CoinedVue from "@/modules/04_registry/components/Coin.vue";
import AssessmentVue from "@/modules/04_registry/components/Assessment.vue";
import SalaryVue from "@/modules/04_registry/components/Salary.vue";
import DisciplineVue from "@/modules/04_registry/components/Discipline.vue";
import LeaveVue from "@/modules/04_registry/components/Leave.vue";
import TalentVue from "@/modules/04_registry/components/Talent.vue";
import WorkVue from "@/modules/04_registry/components/Work.vue";
import RecordVue from "@/modules/04_registry/components/Record.vue";
import OtherVue from "@/modules/04_registry/components/Other.vue";
import DocumentVue from "@/modules/04_registry/components/Document.vue";
import Certicate from "@/modules/04_registry/components/Information/Certicate.vue";
import type { DataOption } from "@/modules/04_registry/interface/index/Main";
import http from "@/plugins/http";
import config from "@/app.config";
const $q = useQuasar();
const store = useDataStore();
const { changeTab, loaderPage } = store;
const mixin = useCounterMixin();
const { date2Thai, dateToISO, modalConfirm, messageError, dialogMessage } = mixin;
const route = useRoute();
const router = useRouter();
const imageUrl = ref<any>(null);
const inputImage = ref<any>(null);
const fullname = ref<string>("");
const position = ref<string>("นักจัดการงานทั่วไป");
const pdfSrc = ref<string>("");
const pdfCurrentPage = ref<number>();
const pdfTotalPage = ref<number>();
const pdfSrcShort = ref<string>("");
const pdfCurrentPageShort = ref<number>();
const pdfTotalPageShort = ref<number>();
const dialog = ref<boolean>(false);
const dialogShort = ref<boolean>(false);
const dialogLeave = ref<boolean>(false);
const dialogImage = ref<boolean>(false);
const loader = ref<boolean>(false); //
const statusEdit = ref<boolean>(false);
const activeImage = ref<any | null>(null);
const images = ref<any>([]);
const profileId = ref<string>(route.params.id.toString());
const profileType = ref<string>("");
const leaveDate = ref<Date>(new Date());
const leaveDetail = ref<string>("");
const leaveNumberOrder = ref<string>("");
const leaveDateOrder = ref<Date>(new Date());
const reason = ref<string>("");
const reasonStatus = ref<boolean>(false);
const leaveReason = ref<string>("");
const reasonOptions = ref<DataOption[]>([
{
id: "retire",
name: "เกษียณอายุราชการ",
},
{
id: "resign",
name: "ลาออก",
},
{
id: "transfer",
name: "ให้โอน",
},
{
id: "death",
name: "ถึงแก่กรรม",
},
{
id: "layoff",
name: "ให้ออก",
},
{
id: "discharge",
name: "ปลดออก",
},
{
id: "dismiss",
name: "ไล่ออก",
},
// {
// id: "change",
// name: "",
// },
{
id: "other",
name: "อื่นๆ",
},
]);
onMounted(async () => {
await checkProfileData();
await fetchData();
await changeTab("information");
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileAvatarId(profileId.value))
.then((res) => {
const data = res.data.result;
fullname.value = data.fullname;
imageUrl.value = data.avatar;
position.value = data.position;
profileType.value = data.profileType;
const reason = reasonOptions.value.filter(
(r: DataOption) => r.id == data.leaveReason
);
if (reason.length > 0) {
leaveReason.value = ` (พ้นจากราชการด้วยสาเหตุ: ${reason[0].name})`;
} else {
leaveReason.value = "";
}
reasonStatus.value = reason.length > 0 ? true : false;
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const checkProfileData = async () => {
loaderPage(true);
await http
.get(config.API.profileCheckId(profileId.value))
.then((res) => {
let data = res.data.result;
if (data == false) router.push("/registry");
})
.catch((e) => {
router.push("/registry");
})
.finally(() => {
loaderPage(false);
});
};
const fetchAvatarHistory = async () => {
loaderPage(true);
await http
.get(config.API.profileAvatarHistoryId(profileId.value))
.then((res) => {
let data = res.data.result;
images.value = [];
data.map((e: any) => {
images.value.push({
id: e.id,
avatar: e.avatar,
avatarId: e.avatarId,
createdDate: new Date(e.createdDate),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const uploadImage = async (e: any) => {
let input = e.target.files;
if (input.length > 0) {
const formData = new FormData();
formData.append("FileData", input[0]);
loaderPage(true);
await http
.post(config.API.profileAvatarId(profileId.value), formData)
.then((res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
dialogImage.value = false;
});
return;
}
};
const deletePhoto = async (id: string) => {
// dialogMessage(
// $q,
// "",
// "",
// "delete",
// undefined,
// "red",
// undefined,
// undefined,
// false
// );
loaderPage(true);
await http
.delete(config.API.profileAvatarHistoryId(id))
.then((res) => {})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
dialogImage.value = false;
});
};
const selectAvatarHistory = async () => {
if (activeImage.value == null) {
dialogMessage(
$q,
"ไม่สามารถเปลี่ยนรูปได้",
"กรุณาเลือกรูปที่ต้องการเปลี่ยน",
"warning",
undefined,
"orange",
undefined,
undefined,
true
);
return;
}
loaderPage(true);
await http
.put(config.API.profileAvatarId(profileId.value), {
avatar: activeImage.value.avatarId,
})
.then((res) => {
dialogImage.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
const imageActive = (n: any) => {
activeImage.value = n;
};
const imageClass = (n: any) => {
const val = n == activeImage.value;
return {
"rounded-borders bg-grey-2 image-size-default": val,
"rounded-borders bg-grey-2 image-size-full": !val,
};
};
const getClass = (n: any) => {
const val = n == activeImage.value;
return {
"rounded-borders border-green shadow-1": val,
"rounded-borders shadow-1": !val,
};
};
const addNewImage = async () => {
inputImage.value.click();
await imageActive(null);
};
const clickImage = async () => {
await fetchAvatarHistory();
dialogImage.value = true;
};
const closeImage = () => {
dialogImage.value = false;
};
const closeLeave = () => {
dialogLeave.value = false;
};
const closeKp7 = () => {
dialog.value = false;
};
const closeKp7Short = () => {
dialogShort.value = false;
};
const downloadKP7 = () => {};
const downloadKP7Short = () => {};
const clickKp7 = async () => {
window.open(config.API.profileReportId(profileId.value));
// loaderPage(true);
// await http
// .get(config.API.profileReportId(profileId.value))
// .then((res) => {
// if (res.data) {
// pdfSrc.value = "data:application/pdf;base64," + res.data;
// pdfCurrentPage.value = 1;
// pdfTotalPage.value = 7;
// dialog.value = true;
// }
// })
// .catch((e) => {messageError($q, e);})
// .finally(() => {
// loaderPage(false);
// });
};
const downloadFilePDF = async (res: string, fileName: string) => {
const link = document.createElement("a");
// link.href = window.URL.createObjectURL(new Blob([res]));
link.href = window.URL.createObjectURL(
new Blob([res], {
type: "application/vnd.ms-excel",
})
);
link.setAttribute("download", fileName);
document.body.appendChild(link);
link.click();
};
const clickKp7Short = async () => {
window.open(config.API.profileKp7ShortId(profileId.value));
// loaderPage(true);
// await http
// .get(config.API.profileKp7ShortId(profileId.value))
// .then((res) => {
// if (res.data) {
// pdfSrcShort.value = "g==";
// pdfCurrentPageShort.value = 1;
// pdfTotalPageShort.value = 7;
// dialogShort.value = true;
// }
// })
// .catch((e) => {messageError($q, e);})
// .finally(() => {
// loaderPage(false);
// });
};
const clickRetire = async () => {
if (reasonStatus.value == true) {
modalConfirm(
$q,
"โปรดยืนยัน",
"ต้องการย้ายข้อมูลจากพ้นราชการไปถือครองใช่หรือไม่?",
Retire
);
} else {
leaveDate.value = new Date();
leaveDetail.value = "";
leaveNumberOrder.value = "";
leaveDateOrder.value = new Date();
reason.value = "";
dialogLeave.value = true;
}
};
const Retire = async () => {
if (reasonStatus.value == true) {
loaderPage(true);
await http
.put(config.API.profileReactive(profileId.value))
.then((res) => {
if (res.data) {
dialogLeave.value = false;
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
router.push("/registry");
});
} else {
loaderPage(true);
await http
.put(config.API.profileDeactive(profileId.value), {
leaveDate: dateToISO(leaveDate.value),
leaveDetail: leaveDetail.value,
leaveNumberOrder: leaveNumberOrder.value,
leaveDateOrder: dateToISO(leaveDateOrder.value),
reason: reason.value,
})
.then((res) => {
if (res.data) {
dialogLeave.value = false;
}
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
router.push("/registry");
});
}
};
</script>
<style>
.image-size-default {
height: 150px;
max-width: 15vw;
}
.image-size-full {
height: 160px;
max-width: 15vw;
}
.border-green {
border: 5px solid #52c688;
}
.area-div {
background-color: transparent;
}
.text-header {
font-size: 1.2em;
}
.containerimage {
position: relative;
}
.containerimage:hover .overlay {
opacity: 1;
}
.overlay {
background-color: #e4f2ffd2 !important;
opacity: 0;
padding: 2px !important;
}
.information:target {
padding-top: 84px;
}
.border-custom {
border: 0.5px solid #c3c3c3;
}
.bg-active-image {
background-color: #52c688;
}
.text-name {
font-size: 1.25em;
overflow: hidden;
}
</style>

View file

@ -0,0 +1,675 @@
<!-- card นทกวนทไมไดบเงนเดอนหรอไดบเงนเดอนไมเตมหรอวนทไดปฏหนาทอยในเขตทไดประดาศใชกฏอยการศ -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="วันที่มิได้ปฏิบัติหน้าที่อยู่ในเขตที่ได้มีประกาศใช้กฎอัยการศึก"
icon="mdi-calendar-remove"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div v-if="col.name == 'date'" class="table_ellipsis">
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader
tittle="วันที่มิได้ปฏิบัติหน้าที่อยู่ในเขตที่ได้มีประกาศใช้กฎอัยการศึก"
:close="clickClose"
/>
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="date"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(date)"
:rules="[(val) => !!val || `${'กรุณาเลือกวัน เดือน ปี'}`]"
hide-bottom-space
:label="`${'วัน เดือน ปี'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
autogrow
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="reference"
:rules="[(val) => !!val || `${'กรุณากรอกเอกสารอ้างอิง'}`]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
autogrow
lazy-rules
:readonly="!edit"
:borderless="!edit"
v-model="detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="col.name == 'date' || col.name == 'createdAt'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Record";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Record";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const date = ref<Date>(new Date());
const detail = ref<string>();
const reference = ref<string>();
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>(
"ประวัติแก้ไขวันที่มิได้ปฏิบัติหน้าที่อยู่ในเขตที่ได้มีประกาศใช้กฎอัยการศึก"
);
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const profileId = ref<string>(route.params.id.toString());
const checkValidate = ref<boolean>(false); //validate data
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.record.columns.length == 0
? (visibleColumns.value = ["date", "detail", "reference"])
: (visibleColumns.value = profileData.record.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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: "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" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "date",
align: "left",
label: "วัน เดือน ปี",
sortable: true,
field: "date",
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: "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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"date",
"detail",
"reference",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("record", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileNopaidId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
date: new Date(e.date),
detail: e.detail,
reference: e.reference,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
date.value = row.date;
detail.value = row.detail;
reference.value = row.reference;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileNopaidId(profileId.value), {
id: id.value,
date: dateToISO(date.value),
detail: detail.value,
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileNopaidId(id.value), {
id: id.value,
date: dateToISO(date.value),
detail: detail.value,
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileNopaidId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
date.value = props.row.date;
detail.value = props.row.detail;
reference.value = props.row.reference;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
date.value = new Date();
detail.value = "";
reference.value = "";
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileNopaidHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
date: new Date(e.date),
detail: e.detail,
reference: e.reference,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
<template>
<div class="q-pb-sm row">
<HeaderTop
v-model:edit="editBtn"
:header="name"
:icon="icon"
:add="checkAdd"
:addData="true"
:history="false"
:disable="statusEdit"
/>
<q-space />
<div class="items-center" style="display: flex" v-if="headerShow">
<!-- นหาขอความใน table -->
<q-input
standout
dense
:model-value="inputfilter"
ref="filterRef"
@update:model-value="updateInput"
outlined
debounce="300"
placeholder="ค้นหา"
style="max-width: 200px"
class="q-ml-sm"
>
<template v-slot:append>
<q-icon v-if="inputfilter == ''" name="search" />
<q-icon
v-if="inputfilter !== ''"
name="clear"
class="cursor-pointer"
@click="resetFilter"
/>
</template>
</q-input>
<!-- แสดงคอลมนใน table -->
<q-select
:model-value="inputvisible"
@update:model-value="updateVisible"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="attrs.columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 150px"
class="gt-xs q-ml-sm"
/>
</div>
</div>
<q-table
ref="table"
flat
bordered
class="custom-header-table"
v-bind="attrs"
virtual-scroll
:virtual-scroll-sticky-size-start="48"
dense
:pagination-label="paginationLabel"
:pagination="initialPagination"
:rows-per-page-options="[0]"
>
<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 #body="props">
<slot v-bind="props" name="columns"></slot>
</template>
</q-table>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
import HeaderTop from "@/modules/04_registry/components/Information/top.vue";
import type { Pagination } from "@/modules/04_registry/interface/index/Main";
const attrs = ref<any>(useAttrs());
const table = ref<any>(null);
const filterRef = ref<any>(null);
const editBtn = ref<boolean>(false);
const initialPagination = ref<Pagination>({
rowsPerPage: 0,
});
const props = defineProps({
inputfilter: String,
name: String,
icon: String,
inputvisible: Array,
editvisible: Boolean,
headerShow: {
type: Boolean,
default: true,
},
statusEdit: {
type: Boolean,
required: true,
},
edit: {
type: Function,
default: () => console.log("not function"),
},
add: {
type: Function,
default: () => console.log("not function"),
},
cancel: {
type: Function,
default: () => console.log("not function"),
},
validate: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits([
"update:inputfilter",
"update:inputvisible",
"update:editvisible",
]);
const updateEdit = (value: Boolean) => {
emit("update:editvisible", value);
};
const updateInput = (value: string | number | null) => {
emit("update:inputfilter", value);
};
const updateVisible = (value: []) => {
emit("update:inputvisible", value);
};
const paginationLabel = (start: string, end: string, total: string) => {
return start + "-" + end + " ใน " + total;
};
const checkAdd = () => {
props.add();
};
const edit = async () => {
updateEdit(!props.editvisible);
props.edit();
};
const cancel = async () => {
updateEdit(!props.editvisible);
props.cancel();
};
const resetFilter = () => {
// reset X
emit("update:inputfilter", "");
filterRef.value.focus();
};
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.custom-header-table {
max-height: 64vh;
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,443 @@
<template>
<q-table
ref="table"
flat
:class="
$q.screen.gt.xs
? 'q-px-md custom-header-table2'
: 'q-px-sm custom-header-table2 custom-table-height'
"
v-bind="attrs"
dense
virtual-scroll
:virtual-scroll-sticky-size-start="48"
:pagination-label="paginationLabel"
:pagination="initialPagination"
:rows-per-page-options="[0]"
>
<template v-slot:top="props">
<div class="q-py-sm col-12 row">
<q-space />
<div class="items-center row col-12 q-gutter-x-sm">
<q-btn
size="13px"
color="grey-7"
dense
flat
round
@click="onTab"
class="shadow-1"
icon="chevron_right"
v-if="!isTab"
>
<q-tooltip>เป</q-tooltip>
</q-btn>
<q-btn
size="12px"
flat
round
color="blue"
@click="clickSearchPanel"
icon="mdi-filter-variant"
v-show="searchPanel == false"
>
<q-tooltip>นหาขนส</q-tooltip>
</q-btn>
<q-space />
<q-input
v-show="searchPanel == false"
standout
dense
:model-value="inputfilter"
ref="filterRef"
@update:model-value="updateInput"
outlined
debounce="300"
placeholder="ค้นหา"
style="max-width: 200px"
>
<template v-slot:append>
<q-icon v-if="inputfilter == ''" name="search" />
<q-icon
v-if="inputfilter !== ''"
name="clear"
class="cursor-pointer"
@click="resetFilter"
/>
</template>
</q-input>
<!-- แสดงคอลมนใน table -->
<q-select
:model-value="inputvisible"
@update:model-value="updateVisible"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="attrs.columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 150px"
class="gt-xs q-ml-sm"
/>
</div>
</div>
<div class="items-center">
<q-slide-transition
v-show="searchPanel"
class="q-mb-sm"
:duration="150"
>
<div class="my-content">
<div
class="row q-pa-xs items-center bg-blue-1"
style="border-radius: 4px 4px 0px 0px"
>
<q-icon
size="20px"
color="blue-9"
name="mdi-filter-variant"
class="q-mx-sm"
/>
<div class="text-blue-9 text-subtitle2 text-weight-medium">
<span>นหาขอมลทะเบยนประว</span>
</div>
<q-space />
<q-btn
color="blue-9"
icon="mdi-close"
size="12px"
flat
round
dense
@click="clickSearchPanel"
/>
</div>
<q-separator color="blue-1" />
<div class="dialog-card-contain">
<q-card-section class="q-pa-md">
<div class="row col-12 q-col-gutter-sm">
<div class="col-xs-12 col-sm-4">
<q-input
clearable
dense
outlined
lazy-rules
:model-value="profileId"
hide-bottom-space
label="เลขประจำตัวประชาชน"
@update:model-value="updateProfileId"
type="number"
/>
</div>
<div class="col-xs-12 col-sm-4">
<q-input
clearable
dense
outlined
lazy-rules
:model-value="fullName"
hide-bottom-space
label="ชื่อ-นามสกุล"
@update:model-value="updateFullname"
/>
</div>
<div class="col-xs-12 col-sm-2">
<datepicker
menu-class-name="modalfix"
:model-value="retireYear"
:locale="'th'"
autoApply
year-picker
:enableTimePicker="false"
@update:model-value="updateRetireYear"
clearable
>
<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 q-mb-sm"
hide-bottom-space
outlined
dense
lazy-rules
borderless
:model-value="
retireYear == null ? null : retireYear + 543
"
:label="`${'ปีเกษียณ'}`"
clearable
@clear="clearDate"
>
<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-sm-2">
<q-input
clearable
dense
outlined
lazy-rules
:model-value="govAge"
hide-bottom-space
label="อายุราชการ(ปี)"
type="number"
@update:model-value="updateGovAge"
/>
</div>
<div class="col-12 row items-center q-col-gutter-md">
<q-toggle
dense
:model-value="isShowRetire"
color="primary"
@update:model-value="updateIsShowRetire"
>
แสดงขอมลผนจากราชการ/เกษยณอายราชการ/เสยช/โอน/ลาออก
</q-toggle>
<q-toggle
dense
:model-value="isProbation"
color="primary"
@update:model-value="updateIsProbation"
>
ทดลองปฏหนาทราชการ
</q-toggle>
</div>
<div class="col-12 row q-col-gutter-y-md">
<div class="row q-gutter-md">
<q-radio
dense
:model-value="profileType"
val="officer"
label="ข้าราชการสามัญ"
class="q-pt-sm"
@update:model-value="updateProfileType"
/>
<q-radio
dense
:model-value="profileType"
val="employee"
class="q-pt-sm"
@update:model-value="updateProfileType"
>
กจาง
</q-radio>
</div>
<q-space />
<div>
<q-btn
dense
color="primary"
icon="mdi-magnify"
label="ค้นหา"
class="q-px-md"
@click="doSearch"
/>
</div>
</div>
</div>
</q-card-section>
</div>
</div>
</q-slide-transition>
</div>
</template>
<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 #body="props">
<slot v-bind="props" name="columns"></slot>
</template>
</q-table>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue";
import type { Pagination } from "@/modules/04_registry/interface/index/Main";
const attrs = ref<any>(useAttrs());
const table = ref<any>(null);
const filterRef = ref<any>(null);
const searchPanel = ref<boolean>(true);
const initialPagination = ref<Pagination>({
rowsPerPage: 0,
});
const props = defineProps({
inputfilter: String,
inputvisible: Array,
profileId: String,
fullName: String,
oldFullName: String,
isShowRetire: Boolean,
isProbation: Boolean,
profileType: String,
retireYear: Number || null,
govAge: Number || null,
isTab: {
type: Boolean,
default: true,
},
doSearch: {
type: Function,
default: () => console.log("not function"),
},
onExport: {
type: Function,
default: () => console.log("not function"),
},
onTab: {
type: Function,
default: () => console.log("not function"),
},
});
const emit = defineEmits([
"update:inputfilter",
"update:inputvisible",
"update:profileId",
"update:fullName",
"update:oldFullName",
"update:oldName",
"update:retireYear",
"update:govAge",
"update:isShowRetire",
"update:profileType",
"update:isProbation",
]);
const updateInput = (value: string | number | null) => {
emit("update:inputfilter", value);
};
const updateVisible = (value: []) => {
emit("update:inputvisible", value);
};
const updateProfileId = (value: string | number | null) => {
emit("update:profileId", value);
};
const updateFullname = (value: string | number | null) => {
emit("update:fullName", value);
};
const updateRetireYear = (value: string | number | null) => {
emit("update:retireYear", value);
};
const updateGovAge = (value: string | number | null) => {
emit("update:govAge", value);
};
const updateIsShowRetire = (value: string | number | null) => {
emit("update:isShowRetire", value);
};
const updateIsProbation = (value: string | number | null) => {
emit("update:isProbation", value);
};
const updateProfileType = (value: string | number | null) => {
emit("update:profileType", value);
};
const clearDate = () => {
emit("update:retireYear", null);
};
const clickSearchPanel = () => {
emit("update:retireYear", null);
emit("update:govAge", null);
emit("update:oldName", null);
emit("update:oldFullName", null);
emit("update:fullName", null);
emit("update:profileId", null);
searchPanel.value = !searchPanel.value;
};
const paginationLabel = (start: string, end: string, total: string) => {
return start + "-" + end + " ใน " + total;
};
const doSearch = () => {
props.doSearch();
};
const onExport = () => {
props.onExport();
};
const onTab = () => {
props.onTab();
};
const resetFilter = () => {
// reset X
emit("update:inputfilter", "");
filterRef.value.focus();
};
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.my-content {
background: #fff;
border: 1px solid rgba(133, 133, 133, 0.2);
border-radius: 5px;
}
.custom-table-height {
height: auto !important;
}
.custom-header-table2 {
.q-table__top {
padding: 0px !important;
}
.q-table__bottom {
border-top: none !important;
}
.q-table__middle {
border-radius: 5px;
border: 1px solid rgba(133, 133, 133, 0.2) !important;
}
.q-table tr:nth-child(odd) td {
background: white;
}
.q-table tr:nth-child(even) td {
background: #f8f8f8;
}
.q-table thead tr {
background: #ecebeb;
}
.q-table thead tr th {
position: sticky;
z-index: 1;
}
/* this will be the loading indicator */
.q-table thead tr:last-child th {
/* height of all previous header rows */
top: 48px;
}
.q-table thead tr:first-child th {
top: 0;
}
}
</style>

View file

@ -0,0 +1,846 @@
<!-- card ความสามารถพเศษ -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="ความสามารถพิเศษ"
icon="mdi-folder-star"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div
v-if="col.name == 'dateStart' || col.name == 'dateEnd'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader tittle="ความสามารถพิเศษ" :close="clickClose" />
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center q-col-gutter-x-xs q-col-gutter-y-xs"
>
<div class="col-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
autogrow
:borderless="!edit"
v-model="field"
:rules="[(val) => !!val || `${'กรุณากรอกด้าน'}`]"
hide-bottom-space
:label="`${'ด้าน'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-6">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
autogrow
:borderless="!edit"
v-model="detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
autogrow
:borderless="!edit"
v-model="remark"
hide-bottom-space
:label="`${'หมายเหตุ'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
:readonly="!edit"
v-model="dateStart"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(dateStart)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
hide-bottom-space
:label="`${'วันที่เริ่มต้น'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-xs-6 col-sm-6 col-md-6">
<datepicker
menu-class-name="modalfix"
:readonly="!edit"
v-model="dateEnd"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(dateEnd)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่สิ้นสุด'}`]"
hide-bottom-space
:label="`${'วันที่สิ้นสุด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:readonly="!edit"
autogrow
:borderless="!edit"
v-model="reference"
:rules="[(val) => !!val || `${'กรุณากรอกเอกสารอ้างอิง'}`]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="
col.name == 'dateStart' ||
col.name == 'dateEnd' ||
col.name == 'createdAt'
"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Talent";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Talent";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const field = ref<string>();
const detail = ref<string>();
const remark = ref<string>();
const dateStart = ref<Date>(new Date());
const dateEnd = ref<Date>(new Date());
const reference = ref<string>();
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขความสามารถพิเศษ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.talent.columns.length == 0
? (visibleColumns.value = [
"field",
"detail",
"remark",
"dateStart",
"dateEnd",
"reference",
])
: (visibleColumns.value = profileData.talent.columns);
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: "dateStart",
align: "left",
label: "วันที่เริ่มต้น",
sortable: true,
field: "dateStart",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
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",
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 columnsHistory = 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: "dateStart",
align: "left",
label: "วันที่เริ่มต้น",
sortable: true,
field: "dateStart",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
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",
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"field",
"detail",
"remark",
"dateStart",
"dateEnd",
"reference",
"createdFullName",
"createdAt",
]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("talent", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileAbiliId(profileId.value))
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
field: e.field,
detail: e.detail,
remark: e.remark,
dateStart: new Date(e.dateStart),
dateEnd: new Date(e.dateEnd),
reference: e.reference,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
field.value = row.field;
detail.value = row.detail;
remark.value = row.remark;
dateStart.value = row.dateStart;
dateEnd.value = row.dateEnd;
reference.value = row.reference;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileAbiliId(profileId.value), {
id: id.value,
field: field.value,
detail: detail.value,
remark: remark.value,
dateStart: dateToISO(dateStart.value),
dateEnd: dateToISO(dateEnd.value),
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileAbiliId(id.value), {
id: id.value,
field: field.value,
detail: detail.value,
remark: remark.value,
dateStart: dateToISO(dateStart.value),
dateEnd: dateToISO(dateEnd.value),
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileAbiliId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
field.value = props.row.field;
detail.value = props.row.detail;
remark.value = props.row.remark;
dateStart.value = props.row.dateStart;
dateEnd.value = props.row.dateEnd;
reference.value = props.row.reference;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
field.value = "";
detail.value = "";
remark.value = "";
dateStart.value = new Date();
dateEnd.value = new Date();
reference.value = "";
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileAbiliHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
field: e.field,
detail: e.detail,
remark: e.remark,
dateStart: new Date(e.dateStart),
dateEnd: new Date(e.dateEnd),
reference: e.reference,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,757 @@
<!-- card ปฏราชการพเศษ -->
<template>
<q-card flat bordered class="col-12 q-px-lg q-py-md">
<q-form ref="myForm">
<ProfileTable
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:add="clickAdd"
name="ปฏิบัติราชการพิเศษ"
icon="mdi-bookmark"
:statusEdit="statusEdit"
>
<template #columns="props">
<q-tr :props="props">
<q-td
v-for="col in props.cols"
:key="col.name"
:props="props"
@click="selectData(props)"
class="cursor-pointer"
>
<div
v-if="col.name == 'dateStart' || col.name == 'dateEnd'"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
<q-td auto-width>
<q-btn
color="info"
flat
dense
round
size="14px"
icon="mdi-history"
@click="clickHistory(props.row)"
/>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-form>
</q-card>
<!-- popup Edit window-->
<q-dialog v-model="modal" persistent>
<q-card style="width: 600px">
<q-form ref="myForm">
<DialogHeader tittle="ปฏิบัติราชการพิเศษ" :close="clickClose" />
<q-separator />
<q-card-section class="q-p-sm">
<div
class="row col-12 items-center 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"
:readonly="!edit"
v-model="dateStart"
:locale="'th'"
autoApply
:enableTimePicker="false"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(dateStart)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่เริ่มต้น'}`]"
hide-bottom-space
:label="`${'วันที่เริ่มต้น'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</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="dateEnd"
:locale="'th'"
autoApply
:enableTimePicker="false"
:min-date="minDate"
:readonly="!edit"
@update:modelValue="clickEditRow"
week-start="0"
>
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{
parseInt(value + 543)
}}</template>
<template #trigger>
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
:borderless="!edit"
:model-value="date2Thai(dateEnd)"
:rules="[(val) => !!val || `${'กรุณาเลือกวันที่สิ้นสุด'}`]"
hide-bottom-space
:label="`${'วันที่สิ้นสุด'}`"
>
<template v-slot:prepend>
<q-icon
name="event"
class="cursor-pointer"
:style="
edit
? 'color: var(--q-primary)'
: 'color: var(--q-grey)'
"
>
</q-icon>
</template>
</q-input>
</template>
</datepicker>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
autogrow
:readonly="!edit"
:borderless="!edit"
v-model="reference"
:rules="[(val) => !!val || `${'กรุณากรอกเอกสารอ้างอิง'}`]"
hide-bottom-space
:label="`${'เอกสารอ้างอิง'}`"
@update:modelValue="clickEditRow"
/>
</div>
<div class="col-12">
<q-input
:class="getClass(edit)"
:outlined="edit"
dense
lazy-rules
autogrow
:readonly="!edit"
:borderless="!edit"
v-model="detail"
:rules="[(val) => !!val || `${'กรุณากรอกรายละเอียด'}`]"
hide-bottom-space
:label="`${'รายละเอียด'}`"
@update:modelValue="clickEditRow"
/>
</div>
</div>
</q-card-section>
<q-separator />
<DialogFooter
:cancel="clickCancel"
:edit="clickEdit"
:save="clickSave"
:validate="validateData"
:clickNext="clickNext"
:clickPrevious="clickPrevious"
:clickDelete="clickDelete"
v-model:editvisible="edit"
v-model:next="next"
v-model:previous="previous"
v-model:modalEdit="modalEdit"
/>
</q-form>
</q-card>
</q-dialog>
<HistoryTable
:rows="rowsHistory"
:columns="columnsHistory"
:filter="filterHistory"
:visible-columns="visibleColumnsHistory"
v-model:modal="modalHistory"
v-model:inputfilter="filterHistory"
v-model:inputvisible="visibleColumnsHistory"
v-model:tittle="tittleHistory"
>
<template #columns="props">
<q-tr :props="props">
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div
v-if="
col.name == 'dateStart' ||
col.name == 'dateEnd' ||
col.name == 'createdAt'
"
class="table_ellipsis"
>
{{ date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value }}
</div>
</q-td>
</q-tr>
</template>
</HistoryTable>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRoute } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import ProfileTable from "@/modules/04_registry/components/Table.vue";
import DialogHeader from "@/modules/04_registry/components/DialogHeader.vue";
import DialogFooter from "@/modules/04_registry/components/DialogFooter.vue";
import { useQuasar } from "quasar";
import type {
RequestItemsObject,
DataProps,
} from "@/modules/04_registry/interface/request/Work";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Work";
import HistoryTable from "@/components/TableHistory.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
const props = defineProps({
statusEdit: {
type: Boolean,
required: true,
},
});
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, success, dateToISO, messageError } = mixin;
const route = useRoute();
const id = ref<string>("");
const dateStart = ref<Date>(new Date());
const dateEnd = ref<Date>(new Date());
const detail = ref<string>();
const reference = ref<string>();
const minDate = ref<Date>();
const myForm = ref<any>(); //form data input
const edit = ref<boolean>(false); // dialog
const modal = ref<boolean>(false); //modal add detail
const modalEdit = ref<boolean>(false); //modal
const rawItem = ref<RequestItemsObject>(); // row
const rowIndex = ref<number>(0); //index row
const previous = ref<boolean>(); //
const next = ref<boolean>(); //
const editRow = ref<boolean>(false); //
const rowsHistory = ref<RequestItemsObject[]>([]); //select data history
const tittleHistory = ref<string>("ประวัติแก้ไขปฏิบัติราชการพิเศษ"); //
const filterHistory = ref<string>(""); //search data table history
const modalHistory = ref<boolean>(false); //modal
const checkValidate = ref<boolean>(false); //validate data
const profileId = ref<string>(route.params.id.toString());
const rows = ref<RequestItemsObject[]>([]);
const filter = ref<string>(""); //search data table
const visibleColumns = ref<String[]>([]);
profileData.work.columns.length == 0
? (visibleColumns.value = ["dateStart", "dateEnd", "detail", "reference"])
: (visibleColumns.value = profileData.work.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "เริ่มต้น",
sortable: true,
field: "dateStart",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
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",
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" }),
},
]);
const columnsHistory = ref<QTableProps["columns"]>([
{
name: "dateStart",
align: "left",
label: "เริ่มต้น",
sortable: true,
field: "dateStart",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
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",
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: "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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const visibleColumnsHistory = ref<String[]>([
"dateStart",
"dateEnd",
"detail",
"reference",
"createdFullName",
"createdAt",
]);
watch(dateStart, (count, prevCount) => {
minDate.value = new Date(dateStart.value);
});
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("work", count);
});
onMounted(async () => {
await fetchData();
});
const fetchData = async () => {
loaderPage(true);
await http
.get(config.API.profileDutyId(profileId.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,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* กดดอมลกอนหน
*/
const clickPrevious = async () => {
edit.value = false;
rowIndex.value -= 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const clickNext = async () => {
edit.value = false;
rowIndex.value += 1;
await getData();
await checkRowPage();
};
/**
* กดดอมลตอไป
*/
const getData = () => {
const row = rows.value[rowIndex.value];
dateStart.value = row.dateStart;
dateEnd.value = row.dateEnd;
detail.value = row.detail;
reference.value = row.reference;
id.value = row.id;
};
/**
* เชคปมดอม อน อไป าตองแสดงไหม
*/
const checkRowPage = () => {
editRow.value = false;
next.value = true;
previous.value = true;
if (rowIndex.value + 1 >= rows.value.length) {
next.value = false;
}
if (rowIndex.value - 1 < 0) {
previous.value = false;
}
};
/**
* กดปมแกไขใน dialog
*/
const clickEdit = () => {
editRow.value = false;
next.value = false;
previous.value = false;
};
/**
* กดปมเพมดานบน table
*/
const clickAdd = async () => {
editRow.value = false;
await addData();
};
/**
* กดบนทกใน dialog
*/
const clickSave = async () => {
myForm.value.validate().then(async (result: boolean) => {
if (result) {
if (modalEdit.value) {
await editData();
} else {
await saveData();
}
}
});
};
/**
* นทกเพมขอม
*/
const saveData = async () => {
loaderPage(true);
await http
.post(config.API.profileDutyId(profileId.value), {
id: id.value,
dateStart: dateToISO(dateStart.value),
dateEnd: dateToISO(dateEnd.value),
detail: detail.value,
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* นทกแกไขขอม
*/
const editData = async () => {
loaderPage(true);
await http
.put(config.API.profileDutyId(id.value), {
id: id.value,
dateStart: dateToISO(dateStart.value),
dateEnd: dateToISO(dateEnd.value),
detail: detail.value,
reference: reference.value,
})
.then((res) => {
success($q, "บันทึกข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
};
/**
* ลบลบขอม
*/
const clickDelete = async () => {
$q.dialog({
title: `ลบข้อมูล`,
message: `ต้องการทำการลบข้อมูลนี้ใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
})
.onOk(async () => {
loaderPage(true);
await http
.delete(config.API.profileDutyId(id.value))
.then((res) => {
success($q, "ลบข้อมูลสำเร็จ");
modal.value = false;
})
.catch((e) => {
messageError($q, e);
})
.finally(async () => {
await fetchData();
});
})
.onCancel(async () => {
await fetchData();
});
};
/**
* กดป dialog
*/
const clickClose = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันที่จะปิดโดยไม่บันทึกใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
modal.value = false;
next.value = false;
previous.value = false;
});
} else {
modal.value = false;
next.value = false;
previous.value = false;
}
};
/**
* กดเลอกขอมลทจะแกไข
* @param props props ใน row เลอก
*/
const selectData = async (props: DataProps) => {
modalEdit.value = true;
modal.value = true;
edit.value = false;
rawItem.value = props.row;
rowIndex.value = props.rowIndex;
dateStart.value = props.row.dateStart;
dateEnd.value = props.row.dateEnd;
detail.value = props.row.detail;
reference.value = props.row.reference;
id.value = props.row.id;
await checkRowPage();
};
/**
* กดปมเพมบน table
*/
const addData = () => {
modalEdit.value = false;
modal.value = true;
edit.value = true;
dateStart.value = new Date();
dateEnd.value = new Date();
detail.value = "";
reference.value = "";
};
/**
* งกนปมยกเลกการแกไขขอม
*/
const clickCancel = async () => {
if (editRow.value == true) {
$q.dialog({
title: `ข้อมูลมีการแก้ไข`,
message: `ยืนยันยกเลิกการแก้ไขใช่หรือไม่?`,
cancel: "ยกเลิก",
ok: "ยืนยัน",
persistent: true,
}).onOk(async () => {
edit.value = false;
await checkRowPage();
await getData();
});
} else {
edit.value = false;
await checkRowPage();
}
};
/**
* เชความการแกไขขอม
*/
const clickEditRow = () => {
editRow.value = true;
};
/**
* งชนดอมลประวแกไขขอมลทเลอก
* @param row อม row ประวการแกไข
*/
const clickHistory = async (row: RequestItemsObject) => {
modalHistory.value = true;
loaderPage(true);
await http
.get(config.API.profileDutyHisId(row.id))
.then((res) => {
let data = res.data.result;
rowsHistory.value = [];
data.map((e: ResponseObject) => {
rowsHistory.value.push({
id: e.id,
dateStart: new Date(e.dateStart),
dateEnd: new Date(e.dateEnd),
detail: e.detail,
reference: e.reference,
createdFullName: e.createdFullName,
createdAt: new Date(e.createdAt),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
/**
* validate input ใน dialog
*/
const validateData = async () => {
checkValidate.value = true;
await myForm.value.validate().then((result: boolean) => {
if (result == false) {
checkValidate.value = false;
}
});
};
/**
* class ดรปแบบแสดงระหวางขอมลทแกไขหรอแสดงเฉยๆ
* @param val อม input สำหรบแกไขหรอไม
*/
const getClass = (val: boolean) => {
return {
"full-width inputgreen cursor-pointer": val,
"full-width cursor-pointer": !val,
};
};
</script>
<style lang="scss">
.modalfix {
position: fixed !important;
}
</style>

View file

@ -0,0 +1,171 @@
//interface class array object {name string ,id number}
import type { childrenFamily } from "@/modules/04_registry/interface/response/Family";
interface ChangeActive {
name: string;
id: number;
}
//ข้อมูลส่วนตัว
interface Information {
cardid: string | null;
prefix: string | null;
age: string | null;
prefixId: string | null;
firstname: string | null;
lastname: string | null;
birthDate: Date;
genderId: string | null;
bloodId: string | null;
nationality: string | null;
ethnicity: string | null;
statusId: string | null;
religionId: string | null;
tel: string | null;
employeeType: string | null;
employeeClass: string | null;
profileType: string | null;
}
interface Family {
prefixC: string | null; // couple
prefixIdC: string | null;
firstnameC: string | null;
lastnameC: string | null;
lastnameCOld: string | null;
occupationC: string | null;
prefixM: string | null; // male
prefixIdM: string | null;
firstnameM: string | null;
lastnameM: string | null;
occupationM: string | null;
prefixF: string | null; // female
prefixIdF: string | null;
firstnameF: string | null;
lastnameF: string | null;
occupationF: string | null;
same: string | null;
childrens: childrenFamily[];
}
interface Address {
address: string | null;
provinceId: string | null;
districtId: string | null;
subdistrictId: string | null;
addressC: string | null;
provinceIdC: string | null;
districtIdC: string | null;
subdistrictIdC: string | null;
same: string | null;
}
interface Goverment {
ocId: string | null;
positionId: string | null;
workId: string | null;
typeId: string | null;
levelId: string | null;
numberId: string | null;
businessId: string | null;
containDate: Date;
workDate: Date;
retireDate: string | null;
absent: number | null;
age: number | null;
ageAll: string | null;
reasonSameDate: string | null;
}
interface DataOption {
id: string;
name: string;
zipCode?: string;
}
interface zipCodeOption {
id: string;
name: string;
zipCode: string;
}
const defaultGoverment: Goverment = {
ocId: null,
positionId: null,
workId: null,
typeId: null,
levelId: null,
numberId: null,
businessId: null,
containDate: new Date(),
workDate: new Date(),
retireDate: null,
absent: 0,
age: 0,
ageAll: null,
reasonSameDate: null,
};
const defaultAddress: Address = {
address: null,
provinceId: null,
districtId: null,
subdistrictId: null,
addressC: null,
provinceIdC: null,
districtIdC: null,
subdistrictIdC: null,
same: "0",
};
const defaultInformation: Information = {
cardid: null,
age: null,
prefix: null,
prefixId: null,
firstname: null,
lastname: null,
birthDate: new Date(),
genderId: null,
bloodId: null,
nationality: null,
ethnicity: null,
statusId: null,
religionId: null,
tel: null,
employeeType: null,
employeeClass: null,
profileType: null,
};
const defaultFamily: Family = {
prefixC: null,
prefixIdC: null,
firstnameC: null,
lastnameC: null,
lastnameCOld: null,
occupationC: null,
prefixM: null,
prefixIdM: null,
firstnameM: null,
lastnameM: null,
occupationM: null,
prefixF: null,
prefixIdF: null,
firstnameF: null,
lastnameF: null,
occupationF: null,
same: "0",
childrens: [],
};
export { defaultInformation, defaultFamily, defaultAddress, defaultGoverment };
export type {
ChangeActive,
Information,
Family,
Address,
Goverment,
DataOption,
zipCodeOption,
};

View file

@ -0,0 +1,70 @@
import type { zipCodeOption } from "../../components/profileType";
interface Pagination {
rowsPerPage: number;
}
interface DataOption {
id: string;
name: string;
disable?: boolean;
}
interface DataOptionInsignia {
id: string;
name: string;
typeName: string;
}
interface treeTab {
id: string;
label: string;
children: treeTab[];
}
interface InformationOps {
prefixOps: DataOption[];
genderOps: DataOption[];
bloodOps: DataOption[];
statusOps: DataOption[];
religionOps: DataOption[];
employeeClassOps: DataOption[];
employeeTypeOps: DataOption[];
}
interface AddressOps {
provinceOps: DataOption[];
districtOps: DataOption[];
districtCOps: DataOption[];
subdistrictOps: zipCodeOption[];
subdistrictCOps: zipCodeOption[];
}
interface FamilyOps {
prefixOps: DataOption[];
}
interface EduOps {
levelOptions: DataOption[];
positionPathOptions: DataOption[];
}
interface InsigniaOps {
insigniaOptions: DataOptionInsignia[];
}
interface DisciplineOps {
levelOptions: DataOption[];
}
export type {
Pagination,
DataOption,
DataOptionInsignia,
treeTab,
InformationOps,
AddressOps,
FamilyOps,
EduOps,
InsigniaOps,
DisciplineOps,
};

View file

@ -0,0 +1,55 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
currentAddress: String | null;
currentDistrictId: String | null;
currentProvinceId: String | null;
currentSubDistrictId: String | null;
currentZipCode: String | null;
registrationAddress: String | null;
registrationDistrictId: String | null;
registrationProvinceId: String | null;
registrationSame: Boolean | null;
registrationSubDistrictId: String | null;
registrationZipCode: String | null;
}
interface RequestItemsHistoryObject {
currentAddress: String | null;
currentDistrict: String | null;
currentProvince: String | null;
currentSubDistrict: String | null;
currentZipCode: String | null;
registrationAddress: String | null;
registrationDistrict: String | null;
registrationProvince: String | null;
registrationSame: Boolean | null;
registrationSubDistrict: String | null;
registrationZipCode: String | null;
createdFullName: String | null;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type {
RequestItemsObject,
Columns,
DataProps,
RequestItemsHistoryObject,
};

View file

@ -0,0 +1,29 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
point: number;
name: string;
date: Date;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,31 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
certificateNo: string;
issuer: string;
issueDate: Date;
expireDate: Date;
certificateType: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,29 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
issuer: string;
detail: string;
issueDate: Date;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,31 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
level: string;
detail: string;
refCommandNo: string;
refCommandDate: Date;
date: Date;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,19 @@
//ข้อมูล
interface RequestItemsObject {
name: String;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns };

View file

@ -0,0 +1,42 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
level: string;
levelId: string;
positionPath: string;
positionPathId: string;
institute: string;
degree: string;
field: string;
gpa: string;
country: string;
duration: string;
durationYear: number;
other: string;
fundName: string;
finishDate: Date;
startDate: number;
endDate: number;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,29 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
date: Date;
status: string;
level: string;
refNo: string;
refDate: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,53 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
date: Date;
status: string;
level: string;
refNo: string;
refDate: Date;
}
interface RequestItemsHistoryObject {
oc: string | null;
position: string | null;
posNo: string | null;
positionLine: string | null;
positionType: string | null;
positionLevel: string | null;
positionExecutive: string | null;
dateAppoint: Date;
dateStart: Date;
retireDate: string | null;
govAge: string | null;
govAgeAbsent: string | null;
govAgePlus: string | null;
reasonSameDate: string | null;
createdFullName: string | null;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type {
RequestItemsObject,
Columns,
DataProps,
RequestItemsHistoryObject,
};

View file

@ -0,0 +1,59 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
birthDate: Date | null;
bloodGroupId: string | null;
citizenId: string | null;
firstName: string | null;
genderId: string | null;
lastName: string | null;
nationality: string | null;
prefixId: string | null;
race: string | null;
relationshipId: string | null;
religionId: string | null;
telephoneNumber: string | null;
employeeType: string | null;
employeeClass: string | null;
}
interface RequestItemsHistoryObject {
citizenId: string | null;
prefix: string | null;
firstName: string | null;
lastName: string | null;
birthDate: Date;
gender: string | null;
relationship: string | null;
bloodGroup: string | null;
nationality: string | null;
race: string | null;
religion: string | null;
telephoneNumber: string | null;
createdFullName: string | null;
createdAt: Date;
employeeType: string | null;
employeeClass: string | null;
}
//columns
interface Columns {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
}
export type {
RequestItemsObject,
Columns,
DataProps,
RequestItemsHistoryObject,
};

View file

@ -0,0 +1,38 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
insigniaType: string;
insignia: string;
insigniaId: string;
year: number;
no: string;
issue: string;
volumeNo: string;
volume: string;
section: string;
page: string;
receiveDate: Date;
dateAnnounce: Date;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,38 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
year: number;
sickDay: number;
personalDay: number;
maternityDay: number;
wifeDay: number;
sickCount: number;
ordainDay: number;
absentDay: number;
studyDay: number;
agencyDay: number;
coupleDay: number;
therapyDay: number;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,34 @@
//ข้อมูล
interface RequestItemsObject {
id: number;
fullname: String;
avatar: String;
citizenId: String;
// oc: String;
position: String;
numberPosition: String;
positionLine: String;
positionType: String;
govAge: number;
positionLevel: String;
positionExecutive: String;
dateAppoint: Date | null;
dateStart: Date | null;
createdAt: Date | null;
salaryDate: Date | null;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns };

View file

@ -0,0 +1,28 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
date: Date;
detail: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,29 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
date: Date;
detail: string;
reference: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,50 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
date: Date;
amount: number;
positionSalaryAmount: number;
mouthSalaryAmount: number;
oc: string;
ocId: string;
position: string;
positionId: string;
posNo: string;
posNoId: string;
positionLine: string;
positionLineId: string;
positionPathSide: string;
positionPathSideId: string;
positionType: string;
positionTypeId: string;
positionLevel: string;
positionLevelId: string;
positionExecutive: string;
positionExecutiveId: string;
positionExecutiveSide: string;
positionExecutiveSideId: string;
salaryClass: string;
salaryRef: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,32 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
field: string;
detail: string;
remark: string;
dateStart: Date;
dateEnd: Date;
reference: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,36 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
name: string;
topic: string;
yearly: number;
place: string;
duration: string;
department: string;
numberOrder: string;
dateOrder: Date;
startDate: Date;
endDate: Date;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,30 @@
interface DataProps {
row: RequestItemsObject;
rowIndex: number;
}
//ข้อมูล
interface RequestItemsObject {
id: string;
dateStart: Date;
dateEnd: Date;
detail: string;
reference: string;
createdFullName: string;
createdAt: Date;
}
//columns
interface Columns {
[index: number]: {
name: String;
align: String;
label: String;
sortable: Boolean;
field: String;
headerStyle: String;
style: String;
};
}
export type { RequestItemsObject, Columns, DataProps };

View file

@ -0,0 +1,34 @@
//ข้อมูล
interface ResponseObject {
currentAddress: string | null;
currentDistrictId: string | null;
currentProvinceId: string | null;
currentSubDistrictId: string | null;
currentZipCode: string | null;
registrationAddress: string | null;
registrationDistrictId: string | null;
registrationProvinceId: string | null;
registrationSame: Boolean | null;
registrationSubDistrictId: string | null;
registrationZipCode: string | null;
createdFullName: string | null;
createdAt: Date;
}
interface ResponseHistory {
currentAddress: string | null;
currentDistrictId: string | null;
currentProvinceId: string | null;
currentSubDistrictId: string | null;
currentZipCode: string | null;
registrationAddress: string | null;
registrationDistrictId: string | null;
registrationProvinceId: string | null;
registrationSame: string | null;
registrationSubDistrictId: string | null;
registrationZipCode: string | null;
createdFullName: string | null;
createdAt: Date;
}
export type { ResponseObject, ResponseHistory };

View file

@ -0,0 +1,11 @@
//ข้อมูล
interface ResponseObject {
id: string;
point: number;
name: string;
date: Date;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,13 @@
//ข้อมูล
interface ResponseObject {
id: string;
certificateNo: string;
issuer: string;
issueDate: Date;
expireDate: Date;
certificateType: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,11 @@
//ข้อมูล
interface ResponseObject {
id: string;
issuer: string;
detail: string;
issueDate: Date;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,13 @@
//ข้อมูล
interface ResponseObject {
id: string;
level: string;
detail: string;
refCommandNo: string;
refCommandDate: Date;
date: Date;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,6 @@
//ข้อมูล
interface ResponseObject {
name: String;
}
export type { ResponseObject };

View file

@ -0,0 +1,24 @@
//ข้อมูล
interface ResponseObject {
id: string;
educationLevel: string;
educationLevelId: string;
positionPath: string;
positionPathId: string;
institute: string;
degree: string;
field: string;
gpa: string;
country: string;
duration: string;
durationYear: number;
other: string;
fundName: string;
finishDate: Date;
startDate: number;
endDate: number;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,50 @@
//ข้อมูล
interface ResponseObject {
couple: Boolean | null;
couplePrefixId: string | null;
coupleFirstName: string | null;
coupleLastName: string | null;
coupleLastNameOld: string | null;
coupleCareer: string | null;
fatherPrefixId: string | null;
fatherFirstName: string | null;
fatherLastName: string | null;
fatherCareer: string | null;
motherPrefixId: string | null;
motherFirstName: string | null;
motherLastName: string | null;
motherCareer: string | null;
createdFullName: string | null;
createdAt: Date;
childrens: childrenFamily[];
}
interface ResponseHistory {
couple: string | null;
couplePrefixId: string | null;
coupleFirstName: string | null;
coupleLastName: string | null;
coupleLastNameOld: string | null;
coupleCareer: string | null;
fatherPrefixId: string | null;
fatherFirstName: string | null;
fatherLastName: string | null;
fatherCareer: string | null;
motherPrefixId: string | null;
motherFirstName: string | null;
motherLastName: string | null;
motherCareer: string | null;
createdFullName: string | null;
createdAt: Date;
childrens: childrenFamily[];
}
interface childrenFamily {
id: string;
childrenPrefixId: string | null;
childrenFirstName: string | null;
childrenLastName: string | null;
childrenCareer: string | null;
}
export type { ResponseObject, childrenFamily, ResponseHistory };

View file

@ -0,0 +1,21 @@
//ข้อมูล
interface ResponseObject {
oc: string | null;
business: string | null;
dateAppoint: Date | string;
dateStart: Date | string;
govAge: string | null;
govAgeAbsent: number | null;
govAgePlus: number | null;
level: string | null;
posNo: string | null;
position: string | null;
retireDate: string | null;
type: string | null;
work: string | null;
createdFullName: string | null;
createdAt: Date;
reasonSameDate: string | null;
}
export type { ResponseObject };

View file

@ -0,0 +1,23 @@
//ข้อมูล
interface ResponseObject {
birthDate: Date;
bloodGroupId: string | null;
citizenId: string | null;
firstName: string | null;
genderId: string | null;
lastName: string | null;
nationality: string | null;
prefixId: string | null;
race: string | null;
relationshipId: string | null;
religionId: string | null;
telephoneNumber: string | null;
createdFullName: string | null;
createdAt: Date;
age: string | null;
employeeType: string | null;
employeeClass: string | null;
profileType: string | null;
}
export type { ResponseObject };

View file

@ -0,0 +1,20 @@
//ข้อมูล
interface ResponseObject {
id: string;
insigniaType: string;
insignia: string;
insigniaId: string;
year: number;
no: string;
issue: string;
volumeNo: string;
volume: string;
section: string;
page: string;
receiveDate: Date;
dateAnnounce: Date;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,20 @@
//ข้อมูล
interface ResponseObject {
id: string;
year: number;
sickDay: number;
personalDay: number;
maternityDay: number;
wifeDay: number;
sickCount: number;
ordainDay: number;
absentDay: number;
studyDay: number;
agencyDay: number;
coupleDay: number;
therapyDay: number;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,21 @@
//ข้อมูล
interface ResponseObject {
id: number;
fullname: String;
avatar: String;
citizenId: String;
oc: String;
position: String;
posNo: String;
positionLine: String;
positionType: String;
govAge: number;
positionLevel: String;
positionExecutive: String;
dateAppoint: Date | null;
dateStart: Date | null;
createdAt: Date | null;
salaryDate: Date | null;
}
export type { ResponseObject };

View file

@ -0,0 +1,10 @@
//ข้อมูล
interface ResponseObject {
id: string;
date: Date;
detail: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,11 @@
//ข้อมูล
interface ResponseObject {
id: string;
date: Date;
detail: string;
reference: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,32 @@
//ข้อมูล
interface ResponseObject {
id: string;
date: Date;
amount: number;
positionSalaryAmount: number;
mouthSalaryAmount: number;
oc: string;
ocId: string;
position: string;
positionId: string;
posNo: string;
posNoId: string;
positionLine: string;
positionLineId: string;
positionPathSide: string;
positionPathSideId: string;
positionType: string;
positionTypeId: string;
positionLevel: string;
positionLevelId: string;
positionExecutive: string;
positionExecutiveId: string;
positionExecutiveSide: string;
positionExecutiveSideId: string;
salaryClass: string;
salaryRef: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,14 @@
//ข้อมูล
interface ResponseObject {
id: string;
field: string;
detail: string;
remark: string;
dateStart: Date;
dateEnd: Date;
reference: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,18 @@
//ข้อมูล
interface ResponseObject {
id: string;
name: string;
topic: string;
yearly: number;
place: string;
duration: string;
department: string;
numberOrder: string;
dateOrder: Date;
startDate: Date;
endDate: Date;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,12 @@
//ข้อมูล
interface ResponseObject {
id: string;
dateStart: Date;
dateEnd: Date;
detail: string;
reference: string;
createdFullName: string;
createdAt: Date;
}
export type { ResponseObject };

View file

@ -0,0 +1,29 @@
/**
* Router (Registry)
*/
const Main = () => import("@/modules/04_registry/views/Main.vue");
const Detail = () => import("@/modules/04_registry/components/Profile.vue");
export default [
{
path: "/registry",
name: "registry",
component: Main,
meta: {
Auth: true,
Key: [7],
Role: "registry",
},
},
{
path: "/registry/:id",
name: "registryDetail",
component: Detail,
meta: {
Auth: true,
Key: [7],
Role: "registry",
},
},
];

View file

@ -0,0 +1,80 @@
import { ref, computed } from "vue";
import { defineStore } from "pinia";
export const useProfileDataStore = defineStore("profile", () => {
interface profile {
main: { columns: String[] };
education: { columns: String[] };
certicate: { columns: String[] };
train: { columns: String[] };
insignia: { columns: String[] };
coined: { columns: String[] };
assessment: { columns: String[] };
salary: { columns: String[] };
discipline: { columns: String[] };
leave: { columns: String[] };
talent: { columns: String[] };
work: { columns: String[] };
record: { columns: String[] };
other: { columns: String[] };
document: { columns: String[] };
}
const birthDate = ref<Date>(new Date());
const retireText = ref<string | null>(null);
const changeRetireText = (val: string | null) => {
retireText.value = val;
};
const changeBirth = (val: Date) => {
birthDate.value = val;
};
const profileData = ref<profile>({
main: { columns: [] },
education: { columns: [] },
certicate: { columns: [] },
train: { columns: [] },
insignia: { columns: [] },
coined: { columns: [] },
assessment: { columns: [] },
salary: { columns: [] },
discipline: { columns: [] },
leave: { columns: [] },
talent: { columns: [] },
work: { columns: [] },
record: { columns: [] },
other: { columns: [] },
document: { columns: [] },
});
const changeProfileColumns = (system: String, val: String[]) => {
if (system == "main") profileData.value.main.columns = val;
if (system == "education") profileData.value.education.columns = val;
if (system == "certicate") profileData.value.certicate.columns = val;
if (system == "train") profileData.value.train.columns = val;
if (system == "insignia") profileData.value.insignia.columns = val;
if (system == "coined") profileData.value.coined.columns = val;
if (system == "assessment") profileData.value.assessment.columns = val;
if (system == "salary") profileData.value.salary.columns = val;
if (system == "discipline") profileData.value.discipline.columns = val;
if (system == "leave") profileData.value.leave.columns = val;
if (system == "talent") profileData.value.talent.columns = val;
if (system == "work") profileData.value.work.columns = val;
if (system == "record") profileData.value.record.columns = val;
if (system == "other") profileData.value.other.columns = val;
if (system == "document") profileData.value.document.columns = val;
localStorage.setItem("profile", JSON.stringify(profileData.value));
};
if (localStorage.getItem("profile") !== null) {
profileData.value = JSON.parse(localStorage.getItem("profile") || "{}");
}
return {
profileData,
changeProfileColumns,
birthDate,
changeBirth,
retireText,
changeRetireText,
};
});

View file

@ -0,0 +1,567 @@
<!-- page:main page ทะเบยนประว -->
<template>
<div class="toptitle text-dark col-12 row items-center">ทะเบยนประว</div>
<div>
<q-card flat bordered class="col-12 q-mt-sm">
<q-layout
view="hHh Lpr lff"
container
class="shadow-2 rounded-borders page-relative"
style="height: 80vh"
>
<q-drawer
v-model="isDrawer"
class="bg-grey-1"
:width="220"
:breakpoint="400"
bordered
>
<q-btn
size="13px"
class="btn-absolute btnShadow"
color="white"
dense
round
unelevated
@click="isDrawer = false"
v-if="isDrawer"
>
<q-tooltip></q-tooltip>
<q-icon name="chevron_left" size="20px" color="grey-7" />
</q-btn>
<q-scroll-area class="fit">
<div class="row col-12 text-dark q-pt-sm">
<div class="col-12 q-pa-sm">
<q-tree
:nodes="nodesTree"
dense
class="text-subtitle2 text-weight-regular tree-node"
node-key="id"
v-model:selected="selected"
v-model:expanded="expanded"
no-selection-unset
selected-color="primary"
@update:selected="onSelected"
@update:expanded="clickTree"
/>
</div>
</div>
</q-scroll-area>
</q-drawer>
<q-page-container class="q-ma-sm">
<ProfileTable
style="height: 77vh"
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:pagination="initialPagination"
v-model:profileId="profileId"
v-model:fullName="fullName"
v-model:oldFullName="oldFullName"
v-model:isShowRetire="isShowRetire"
v-model:profileType="profileType"
v-model:retireYear="retireYear"
v-model:govAge="govAge"
v-model:isProbation="isProbation"
v-model:isTab="isDrawer"
:doSearch="doSearch"
:onExport="onExport"
:onTab="changeTab"
>
<template #columns="props">
<q-tr
:props="props"
@click="next(props.row.id)"
class="cursor-pointer"
>
<q-td v-for="col in props.cols" :key="col.name" :props="props">
<div v-if="col.name == 'no'" class="table_ellipsis">
{{ props.rowIndex + 1 }}
</div>
<div v-else-if="col.name == 'fullname'">
<div class="row col-12 wrap items-center">
<img
v-if="props.row.avatar == null"
src="@/assets/avatar_user.jpg"
class="col-4 img-info"
/>
<img
v-else
:src="props.row.avatar"
class="col-4 img-info"
/>
<div class="col-4">
<div class="text-weight-medium">
{{ props.row.fullname }}
</div>
<div class="text-weight-light">
{{ props.row.citizenId }}
</div>
</div>
</div>
</div>
<div
v-else-if="
col.name == 'dateAppoint' ||
col.name == 'dateStart' ||
col.name == 'createdAt' ||
col.name == 'salaryDate'
"
class="table_ellipsis"
>
{{ col.value == null ? "-" : date2Thai(col.value) }}
</div>
<div v-else class="table_ellipsis">
{{ col.value ?? "-" }}
</div>
</q-td>
</q-tr>
</template>
</ProfileTable>
</q-page-container>
</q-layout>
</q-card>
</div>
</template>
<script setup lang="ts">
import { onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router";
import { useProfileDataStore } from "@/modules/04_registry/store";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import { useQuasar } from "quasar";
import type { RequestItemsObject } from "@/modules/04_registry/interface/request/Main";
import type { ResponseObject } from "@/modules/04_registry/interface/response/Main";
import type {
Pagination,
treeTab,
} from "@/modules/04_registry/interface/index/Main";
import ProfileTable from "@/modules/04_registry/components/TableProfile.vue";
import http from "@/plugins/http";
import config from "@/app.config";
import type { QTableProps } from "quasar";
// import { jsontoexcel } from "vue-table-to-excel";
const $q = useQuasar();
const store = useProfileDataStore();
const { profileData, changeProfileColumns } = store;
const dataStore = useDataStore();
const { loaderPage } = dataStore;
const mixin = useCounterMixin();
const { date2Thai, messageError } = mixin;
const router = useRouter();
const isDrawer = ref<boolean>(true);
const filter = ref<string>(""); //search data table
const profileId = ref<string>("");
const fullName = ref<string>("");
const oldFullName = ref<string>("");
const isShowRetire = ref<boolean>(false);
const isProbation = ref<boolean>(false);
const profileType = ref<string>("officer");
const retireYear = ref<number>();
const govAge = ref<number>();
const initialPagination = ref<Pagination>({
rowsPerPage: 0,
});
const expanded = ref<string[]>([]);
const selected = ref<string>("");
const nodesTree = ref<treeTab[]>([]);
const visibleColumns = ref<String[]>([]);
visibleColumns.value = [
"no",
"fullname",
"position",
"numberPosition",
"positionLine",
"positionType",
"govAge",
"positionLevel",
"positionExecutive",
"dateAppoint",
"dateStart",
"createdAt",
"salaryDate",
];
// profileData.main.columns.length == 0
// ? (visibleColumns.value = [
// "no",
// "fullname",
// "position",
// "numberPosition",
// "positionLine",
// "positionType",
// "positionLevel",
// "positionExecutive",
// "dateAppoint",
// "dateStart",
// "createdAt",
// "salaryDate",
// ])
// : (visibleColumns.value = profileData.main.columns);
const columns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: true,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
sort: (a: string, b: string) =>
a.localeCompare(b, undefined, {
numeric: true,
sensitivity: "base",
}),
},
{
name: "fullname",
align: "left",
label: "ชื่อ-สกุล",
sortable: true,
field: "fullname",
headerStyle: "font-size: 14px; min-width: 200px",
style: "font-size: 14px; ",
},
{
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: "numberPosition",
align: "left",
label: "เลขที่ตำแหน่ง",
sortable: true,
field: "numberPosition",
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: "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: "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: "dateAppoint",
align: "left",
label: "วันที่สั่งบรรจุ",
sortable: true,
field: "dateAppoint",
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",
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: "createdAt",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
{
name: "salaryDate",
align: "left",
label: "วันที่เข้าสู่ตำแหน่ง",
sortable: true,
field: "salaryDate",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
// sort: (a: string, b: string) =>
// a.localeCompare(b, undefined, { numeric: true, sensitivity: "base" }),
},
]);
const rows = ref<RequestItemsObject[]>([]);
watch(visibleColumns, async (count: String[], prevCount: String[]) => {
await changeProfileColumns("main", count);
});
onMounted(async () => {
await nodeTree();
});
const changeTab = () => {
isDrawer.value = !isDrawer.value;
};
const onSelected = async (id: string) => {
await clickTree();
await doSearch();
};
const clickTree = () => {
dataStore.changeTreeRegister(expanded.value, selected.value);
};
const nodeTree = async () => {
loaderPage(true);
await http
.get(config.API.profileOrganizRoot)
.then((res: any) => {
const data = res.data.result;
nodesTree.value = data;
if (data.length > 0) {
selected.value =
dataStore.selectedRegister == ""
? data[0].id
: dataStore.selectedRegister;
expanded.value =
dataStore.expandedRegister.length == 0
? [data[0].id]
: dataStore.expandedRegister;
}
})
.catch((e: any) => {
messageError($q, e);
})
.finally(async () => {
await doSearch();
});
};
const doSearch = async () => {
let cirteria = [];
if (profileId.value !== null && profileId.value !== "") {
cirteria.push({
criteriaType: "profile_id",
criteriaValue: profileId.value,
});
}
if (fullName.value !== null && fullName.value !== "") {
cirteria.push({
criteriaType: "fullname",
criteriaValue: fullName.value,
});
}
if (oldFullName.value !== null && oldFullName.value !== "") {
cirteria.push({
criteriaType: "old_fullname",
criteriaValue: oldFullName.value,
});
}
if (isShowRetire.value !== null) {
cirteria.push({
criteriaType: "is_retire",
criteriaValue: isShowRetire.value.toString(),
});
}
if (isProbation.value !== null) {
cirteria.push({
criteriaType: "is_probation",
criteriaValue: isProbation.value.toString(),
});
}
if (retireYear.value !== null && retireYear.value !== undefined) {
cirteria.push({
criteriaType: "retire_year",
criteriaValue: retireYear.value,
});
}
if (govAge.value !== null && govAge.value !== undefined) {
cirteria.push({
criteriaType: "gov_age",
criteriaValue: govAge.value,
});
}
if (selected.value == null || selected.value == "") return;
loaderPage(true);
await http
.post(config.API.searchProfileByOcId(selected.value, profileType.value), {
criterias: cirteria,
})
.then((res) => {
let data = res.data.result;
rows.value = [];
data.map((e: ResponseObject) => {
rows.value.push({
id: e.id,
fullname: e.fullname,
avatar: e.avatar,
citizenId: e.citizenId,
position: e.position,
numberPosition: e.posNo,
positionLine: e.positionLine,
positionType: e.positionType,
govAge: e.govAge,
positionLevel: e.positionLevel,
positionExecutive: e.positionExecutive,
dateAppoint: e.dateAppoint == null ? null : new Date(e.dateAppoint),
dateStart: e.dateStart == null ? null : new Date(e.dateStart),
createdAt: e.createdAt == null ? null : new Date(e.createdAt),
salaryDate: e.salaryDate == null ? null : new Date(e.salaryDate),
});
});
})
.catch((e) => {
messageError($q, e);
})
.finally(() => {
loaderPage(false);
});
};
const onExport = () => {
const head = [
"ลำดับ",
"ชื่อ-สกุล",
"ตำแหน่ง",
"สายงาน",
"ตำแหน่งในสายงาน",
"ระดับ",
"ตำแหน่งทางการบริหาร",
"ตำแหน่งการบริหาร",
"เลขที่ตำแหน่ง",
"หน่วยงาน/ส่วนราชการ",
];
const data = rows.value.map((val, index) => ({
no: index + 1,
// id: val.id ? val.id : "",
fullname: val.fullname ? val.fullname : "",
// avatar: val.avatar ? val.avatar : "",
// citizenId: val.citizenId ? val.citizenId : "",
position: val.position ? val.position : "",
// line: val.line ? val.line : "",
// linePosition: val.linePosition ? val.linePosition : "",
// level: val.level ? val.level : "",
// positionFormalManage: val.positionFormalManage
// ? val.positionFormalManage
// : "",
// positionManage: val.positionManage ? val.positionManage : "",
// numberPosition: val.numberPosition ? val.numberPosition : "",
// government: val.government ? val.government : "",
}));
// jsontoexcel.getXlsx(data, head, ".csv");
};
const next = (id: string) => {
router.push(`/registry/${id}`);
};
</script>
<style lang="scss" scope>
.btn-absolute {
z-index: 50;
position: absolute;
left: 200px;
top: 12px;
}
.btnShadow {
box-shadow: 0 1px 2px rgb(0 0 0 / 10%), 3px 3px 7px 1px rgba(95, 95, 95, 0.15) !important;
}
.img-info {
width: 30px !important;
height: 30px !important;
border-radius: 50%;
object-fit: cover;
margin-right: 10px;
}
.tree-node .q-tree__node-header-content {
padding: 1px 5px;
color: #4a4a4a;
}
</style>