Compare commits

...

35 commits
v1.0.2 ... dev

Author SHA1 Message Date
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
b845cdaeab Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m30s
2026-05-11 09:24:58 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
9bee07eb7c refactor:(genreport) : import downloadBlobFile 2026-05-11 09:24:23 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
0a68951571 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m16s
2026-05-08 17:57:05 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
ebd514a33a fix:downloadFileName 2026-05-08 17:56:45 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
58c6150ef8 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m18s
2026-05-08 17:39:28 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
f07cf25489 refactor(registry): downloadBlobFile 2026-05-08 17:39:01 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
814c17d4c9 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m21s
2026-05-07 09:36:46 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
9eaa28711d refactor(convertDateToAPI): parsedDate new Date 2026-05-07 09:36:31 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
d00d4ac692 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m21s
2026-05-06 17:46:26 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
780a815a24 refactor(date): function convertDateToAPI delete utcToZonedTime Asia/Bangkok 2026-05-06 17:46:04 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
6ad798a2a2 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m18s
2026-05-01 11:24:41 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
e54d936b19 fix: test load file iOS Safari 2026-05-01 11:24:22 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
b403054348 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m31s
2026-05-01 09:43:32 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
e5d9800294 refactor(file): replace window.open with blob download pattern in registry 2026-05-01 09:43:00 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
1cb83bd0c5 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m23s
2026-04-30 15:18:05 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
14195e972f refactor(file): replace window.open with blob download pattern in ChangeName
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 15:17:49 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
e67f064421 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m21s
2026-04-30 15:05:05 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
ab63afc56d refactor(file): replace window.open with blob download pattern
Co-authored-by: Copilot <copilot@github.com>
2026-04-30 15:04:45 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
992a420bcd Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m23s
2026-04-29 11:05:14 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
e3df43421b refactor(leave): display dateSendLeave when status is not DRAFT
Co-authored-by: Copilot <copilot@github.com>
2026-04-29 11:00:15 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
f7f4da2583 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m43s
2026-04-24 10:35:44 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
a5ba0290d9 fix: Move dialogs inside q-layout in MainLayout.vue 2026-04-24 10:35:30 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
dca9102a8d Merge branch 'develop' into dev 2026-04-24 10:08:55 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
0f0ffd57e5 feat(leave): add display leaveWaitingSummary 2026-04-24 10:08:36 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
91486251b8 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m43s
2026-04-23 18:10:13 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
ab1ea1f614 fix: fetchData position review 2026-04-23 18:09:48 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
1903d5a843 Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m31s
2026-04-23 15:23:15 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
3da965dc0e fix: formatDateToDDMMYYYY 2026-04-23 15:22:33 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
87f091f15b fix: formatDate 2026-04-23 10:11:14 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
803ba41a79 refactor: add column commandCode 2026-04-23 10:00:20 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
573a76448e refactor(registry): exportToExcelPosition 2026-04-23 09:13:05 +07:00
4f7a8c86bc Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m17s
* develop:
  fixed ฟอร์มแจ้งปัญหาบังคับอีเมล
2026-04-20 10:08:12 +07:00
3cedcddbac fixed ฟอร์มแจ้งปัญหาบังคับอีเมล 2026-04-20 10:08:02 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
fd5e32e53c Merge branch 'develop' into dev
All checks were successful
Build & Deploy on Dev / build (push) Successful in 1m49s
2026-04-17 14:38:55 +07:00
DESKTOP-1R2VSQH\Lenovo ThinkPad E490
e87f441c00 refactor:(position-review) add Call API profileSalaryTemp /done 2026-04-17 14:38:31 +07:00
36 changed files with 679 additions and 236 deletions

View file

@ -26,6 +26,7 @@
"@tato30/vue-pdf": "^1.5.1", "@tato30/vue-pdf": "^1.5.1",
"@vuepic/vue-datepicker": "^3.6.3", "@vuepic/vue-datepicker": "^3.6.3",
"bma-org-chart": "^0.0.7", "bma-org-chart": "^0.0.7",
"exceljs": "^4.4.0",
"html-to-image": "^1.11.13", "html-to-image": "^1.11.13",
"keycloak-js": "^20.0.2", "keycloak-js": "^20.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",

View file

@ -316,6 +316,9 @@ function onClose() {
</q-uploader> </q-uploader>
</div> </div>
<div class="col-12"> <div class="col-12">
<div class="text-caption text-grey-7 q-mb-sm">
แลระบบจะตดตอกลบผานทางอเมลทานระบ กรณาตรวจสอบอเมลของทานเปนระยะ
</div>
<div class="row col-12 q-col-gutter-sm"> <div class="row col-12 q-col-gutter-sm">
<div class="col-xs-12 col-md-6 col-lg-6"> <div class="col-xs-12 col-md-6 col-lg-6">
<q-input <q-input
@ -326,10 +329,11 @@ function onClose() {
class="inputgreen" class="inputgreen"
hide-bottom-space hide-bottom-space
:rules="[ :rules="[
() => (val: string) => !!val || 'กรุณากรอกที่อยู่อีเมล',
!!formData.email || (val: string) => {
!!formData.phone || const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
'กรุณากรอกอีเมลหรือเบอร์โทรติดต่อกลับ', return emailPattern.test(val) || 'กรุณากรอกที่อยู่อีเมลในรูปแบบที่ถูกต้อง';
}
]" ]"
/> />
</div> </div>
@ -341,12 +345,6 @@ function onClose() {
v-model="formData.phone" v-model="formData.phone"
class="inputgreen" class="inputgreen"
hide-bottom-space hide-bottom-space
:rules="[
() =>
!!formData.email ||
!!formData.phone ||
'กรุณากรอกอีเมลหรือเบอร์โทรติดต่อกลับ',
]"
/> />
</div> </div>
</div> </div>

View file

@ -206,7 +206,7 @@ async function fetchDataDetail(id: string) {
formData.leaveDateEnd = data.leaveEndDate && date2Thai(data.leaveEndDate); formData.leaveDateEnd = data.leaveEndDate && date2Thai(data.leaveEndDate);
formData.leaveCount = calculateDurationYmd( formData.leaveCount = calculateDurationYmd(
data.leaveStartDate, data.leaveStartDate,
data.leaveEndDate data.leaveEndDate,
); );
formData.leaveWrote = data.leaveWrote ?? "-"; formData.leaveWrote = data.leaveWrote ?? "-";
formData.leaveAddress = data.leaveAddress ?? "-"; formData.leaveAddress = data.leaveAddress ?? "-";
@ -255,8 +255,7 @@ async function fetchDataDetail(id: string) {
formData.studyDaySubject = data.studyDaySubject ?? "-"; formData.studyDaySubject = data.studyDaySubject ?? "-";
formData.studyDayDegreeLevel = data.studyDayDegreeLevel ?? "-"; formData.studyDayDegreeLevel = data.studyDayDegreeLevel ?? "-";
formData.studyDayUniversityName = data.studyDayUniversityName ?? "-"; formData.studyDayUniversityName = data.studyDayUniversityName ?? "-";
formData.studyDayTrainingSubject = formData.studyDayTrainingSubject = data.studyDayTrainingSubject ?? "-";
data.studyDayTrainingSubject ?? "-" ?? "-";
formData.studyDayTrainingName = data.studyDayTrainingName ?? "-"; formData.studyDayTrainingName = data.studyDayTrainingName ?? "-";
formData.studyDayCountry = data.studyDayCountry ?? "-"; formData.studyDayCountry = data.studyDayCountry ?? "-";
formData.studyDayScholarship = data.studyDayScholarship ?? "-"; formData.studyDayScholarship = data.studyDayScholarship ?? "-";
@ -383,7 +382,7 @@ async function onClickSave() {
onSubmit(); onSubmit();
}, },
"ยืนยันการบันทึกข้อมูล", "ยืนยันการบันทึกข้อมูล",
"ต้องการยินยันการบันทึกข้อมูลนี้หรือไม่ ?" "ต้องการยินยันการบันทึกข้อมูลนี้หรือไม่ ?",
); );
} else { } else {
} }
@ -425,7 +424,7 @@ watch(
? props.leaveId && fetchDataCancelDetail(props.leaveId) ? props.leaveId && fetchDataCancelDetail(props.leaveId)
: props.leaveId && fetchDataDetail(props.leaveId); : props.leaveId && fetchDataDetail(props.leaveId);
} }
} },
); );
</script> </script>

View file

@ -131,11 +131,11 @@ function onValidate() {
formData.append("leaveRangeEnd", formDataSick.leaveRangeEnd); formData.append("leaveRangeEnd", formDataSick.leaveRangeEnd);
formData.append( formData.append(
"leaveStartDate", "leaveStartDate",
convertDateToAPI(formDataSick.leaveStartDate) ?? "" convertDateToAPI(formDataSick.leaveStartDate) ?? "",
); );
formData.append( formData.append(
"leaveEndDate", "leaveEndDate",
convertDateToAPI(formDataSick.leaveEndDate) ?? "" convertDateToAPI(formDataSick.leaveEndDate) ?? "",
); );
formData.append("leaveWrote", formDataSick.leaveWrote); formData.append("leaveWrote", formDataSick.leaveWrote);
formData.append("leaveAddress", dataStore.currentAddress); formData.append("leaveAddress", dataStore.currentAddress);
@ -202,7 +202,6 @@ function mapPropsToFormData() {
statusCheck.value = props.data.status; statusCheck.value = props.data.status;
leaveId.value = props.data.id; leaveId.value = props.data.id;
formDataSick.leaveDocument = []; formDataSick.leaveDocument = [];
console.log(props.data.leaveDocument);
} }
} }
@ -211,7 +210,7 @@ watch(
() => { () => {
mapPropsToFormData(); mapPropsToFormData();
}, },
{ deep: true } { deep: true },
); );
/** Hook */ /** Hook */

View file

@ -293,7 +293,7 @@ function getSearch() {
/> />
<q-input <q-input
v-if="props.model === 'LV-005'" v-if="props.model === 'LV-005'"
class="col-12 col-sm-4" class="col-md-3 col-sm-6"
dense dense
outlined outlined
readonly readonly
@ -302,7 +302,7 @@ function getSearch() {
label="จำนวนสิทธิ์การลาที่ได้รับ" label="จำนวนสิทธิ์การลาที่ได้รับ"
/> />
<q-input <q-input
class="col-12 col-sm-4" class="col-md-3 col-sm-6"
dense dense
outlined outlined
readonly readonly
@ -312,7 +312,7 @@ function getSearch() {
/> />
<q-input <q-input
v-if="props.model === 'LV-005'" v-if="props.model === 'LV-005'"
class="col-12 col-sm-4" class="col-md-3 col-sm-6"
dense dense
outlined outlined
readonly readonly
@ -320,6 +320,15 @@ function getSearch() {
v-model="dataStore.leaveRemain" v-model="dataStore.leaveRemain"
label="จำนวนสิทธิ์การลาคงเหลือ" label="จำนวนสิทธิ์การลาคงเหลือ"
/> />
<q-input
class="col-md-3 col-sm-6"
dense
outlined
readonly
bg-color="white"
v-model="dataStore.leaveWaitingSummary"
label="จำนวนวันที่อยู่ระหว่างการพิจารณา"
/>
</div> </div>
</q-card> </q-card>

View file

@ -163,7 +163,7 @@ async function updatePagination(p: number, ps: number, s: string, d: boolean) {
function convert(val: any) { function convert(val: any) {
if (leaveType.value) { if (leaveType.value) {
const filtertype = leaveType.value.find( const filtertype = leaveType.value.find(
(e: any) => e.id === val.leaveTypeId (e: any) => e.id === val.leaveTypeId,
); );
const type = filtertype?.code; const type = filtertype?.code;
if (type == "LV-006" && val.hajjDayStatus == false) { if (type == "LV-006" && val.hajjDayStatus == false) {
@ -242,7 +242,7 @@ onMounted(async () => {
:props="props" :props="props"
@click="onClickView(props.row.id, props.row.status)" @click="onClickView(props.row.id, props.row.status)"
> >
{{ props.row.dateSendLeave }} {{ props.row.status === "DRAFT" ? "-" : props.row.dateSendLeave }}
</q-td> </q-td>
<q-td key="status" :props="props"> <q-td key="status" :props="props">
@ -419,7 +419,7 @@ onMounted(async () => {
<q-item-label v-if="col.name === 'no'"> <q-item-label v-if="col.name === 'no'">
{{ (page - 1) * pageSize + props.rowIndex + 1 }} {{ (page - 1) * pageSize + props.rowIndex + 1 }}
</q-item-label> </q-item-label>
<q-item-label v-if="col.name === 'status'"> <q-item-label v-else-if="col.name === 'status'">
<q-icon <q-icon
v-if="props.row.status == 'DRAFT'" v-if="props.row.status == 'DRAFT'"
size="10px" size="10px"
@ -468,7 +468,12 @@ onMounted(async () => {
<span class="q-pr-md">{{ props.row.statusConvert }}</span> <span class="q-pr-md">{{ props.row.statusConvert }}</span>
</q-item-label> </q-item-label>
<q-item-label v-else>{{ col.value }}</q-item-label> <q-item-label v-else-if="col.name === 'dateSendLeave'">
{{
props.row.status === "DRAFT" ? "-" : props.row.dateSendLeave
}}
</q-item-label>
<q-item-label v-else>{{ col.value }} </q-item-label>
</q-item-section> </q-item-section>
</q-item> </q-item>
</q-list> </q-list>

View file

@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-gutter-md q-pa-sm"> <div class="q-gutter-md q-pa-sm">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -30,11 +32,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -87,10 +111,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store' import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore() const store = useLeaveStore();
const { converstType } = store const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -17,7 +17,9 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -29,11 +31,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -82,10 +106,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -42,11 +44,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -91,10 +115,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -18,7 +18,7 @@ const props = defineProps({
<div class="q-pa-md q-gutter-md"> <div class="q-pa-md q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -98,10 +98,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -18,7 +18,7 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -77,10 +77,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store' import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore() const store = useLeaveStore();
const { converstType } = store const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -30,11 +32,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -87,10 +111,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -1,8 +1,8 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLeaveStore } from '@/modules/05_leave/store' import { useLeaveStore } from "@/modules/05_leave/store";
const store = useLeaveStore() const store = useLeaveStore();
const { converstType } = store const { converstType } = store;
/** /**
* prop จาก component * prop จาก component
*/ */
@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -30,11 +32,33 @@ const props = defineProps({
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาตงแตนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateStart }} {{ `${props.data.leaveRange && props.data.leaveRange !== 'ALL' ? `(${converstType(props.data.leaveRange)})`:''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateStart }}
{{
`${
props.data.leaveRange && props.data.leaveRange !== "ALL"
? `(${converstType(props.data.leaveRange)})`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div> <div class="col-xs-12 col-md-6 text-grey-8">ลาถงวนท</div>
<div class="col-xs-12 col-md-6">{{ props.data.leaveDateEnd }} {{ `${props.data.leaveDateStart !== props.data.leaveDateEnd ? `${props.data.leaveRangeEnd && props.data.leaveRangeEnd !== 'ALL' ? `(${converstType(props.data.leaveRangeEnd)})`:''}` :''}` }}</div> <div class="col-xs-12 col-md-6">
{{ props.data.leaveDateEnd }}
{{
`${
props.data.leaveDateStart !== props.data.leaveDateEnd
? `${
props.data.leaveRangeEnd && props.data.leaveRangeEnd !== "ALL"
? `(${converstType(props.data.leaveRangeEnd)})`
: ""
}`
: ""
}`
}}
</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div> <div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -111,10 +135,12 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -132,10 +132,10 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -80,10 +80,10 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -145,10 +145,10 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -17,7 +17,7 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md"> <div class="q-pa-sm q-gutter-md">
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div> <div class="col-xs-12 col-md-6 text-grey-8">นทนใบลา</div>
<div class="col-xs-12 col-md-6">{{ props.data.dateSendLeave }}</div> <div class="col-xs-12 col-md-6">{{ props.data.status === "DRAFT" ? "-" : props.data.dateSendLeave }}</div>
</div> </div>
<div class="row"> <div class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div> <div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -80,10 +80,10 @@ const props = defineProps({
target="_blank" target="_blank"
outline outline
color="blue" color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`" :label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px" size="12px"
> >
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip> <q-tooltip>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip>
</q-btn> </q-btn>
</div> </div>
</div> </div>

View file

@ -33,7 +33,7 @@ export const useLeaveStore = defineStore("Leave", () => {
/** /**
* function Table * function Table
* @param data Table * @param data TableleaveWaitingSummary
*/ */
async function fetchListLeave(data: ListLeave[]) { async function fetchListLeave(data: ListLeave[]) {
let datalist: ListLeaveTable[] = data.map((e: ListLeave) => ({ let datalist: ListLeaveTable[] = data.map((e: ListLeave) => ({
@ -66,7 +66,6 @@ export const useLeaveStore = defineStore("Leave", () => {
isDelete: e.isDelete, isDelete: e.isDelete,
})); }));
rows.value = datalist; rows.value = datalist;
console.log(datalist);
} }
//ฟังก์ชั่นแปลง Status //ฟังก์ชั่นแปลง Status
@ -309,6 +308,7 @@ export const useLeaveStore = defineStore("Leave", () => {
const telephoneNumber = ref<string>(""); const telephoneNumber = ref<string>("");
const currentAddress = ref<string>(""); const currentAddress = ref<string>("");
const leaveWaitingSummary = ref<number>(0);
//ดึงข้อมูล profile จาก API //ดึงข้อมูล profile จาก API
async function fetchProfile() { async function fetchProfile() {
@ -347,6 +347,7 @@ export const useLeaveStore = defineStore("Leave", () => {
: "-"; : "-";
restDayCurrentTotal.value = restDayCurrentTotal.value =
Number(data.leaveLimit) - Number(data.restDayTotalOld); Number(data.leaveLimit) - Number(data.restDayTotalOld);
leaveWaitingSummary.value = data.leaveWaitingSummary || 0;
}) })
.catch((e: any) => { .catch((e: any) => {
console.log(e); console.log(e);
@ -409,6 +410,7 @@ export const useLeaveStore = defineStore("Leave", () => {
salaryText.value = ""; salaryText.value = "";
leaveLast.value = undefined; leaveLast.value = undefined;
restDayCurrentTotal.value = 0; restDayCurrentTotal.value = 0;
leaveWaitingSummary.value = 0;
} }
/** ฟังก์ชันเรียกข้อมูลประเภทการลา */ /** ฟังก์ชันเรียกข้อมูลประเภทการลา */
@ -480,6 +482,7 @@ export const useLeaveStore = defineStore("Leave", () => {
currentAddress, currentAddress,
rangeOptions, rangeOptions,
converstType, converstType,
leaveWaitingSummary,
fetchLeaveTypeData, fetchLeaveTypeData,
isLoadingProfile, isLoadingProfile,

View file

@ -3,6 +3,7 @@ import { ref, onMounted } from "vue";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
@ -114,7 +115,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }
@ -132,12 +133,15 @@ async function onDownloadFile(id: string, profileId: string) {
"ประวัติการเปลี่ยนชื่อ-นามสกุล", "ประวัติการเปลี่ยนชื่อ-นามสกุล",
profileId, profileId,
id, id,
"เอกสารหลักฐาน" "เอกสารหลักฐาน",
) ),
) )
.then(async (res) => { .then(async (res) => {
const data = res.data.downloadUrl; const downloadUrl = res.data.downloadUrl;
window.open(data, "_blank"); await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `ประวัติการเปลี่ยนชื่อ-นามสกุล`,
});
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);

View file

@ -6,6 +6,7 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
/** import type */ /** import type */
import type { AbilityRows } from "@/modules/10_registry/interface/index/Main"; import type { AbilityRows } from "@/modules/10_registry/interface/index/Main";
@ -240,7 +241,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }
@ -258,12 +259,15 @@ async function onDownloadFile(id: string, profileId: string) {
"เอกสารความสามารถพิเศษ", "เอกสารความสามารถพิเศษ",
profileId, profileId,
id, id,
"เอกสารหลักฐาน" "เอกสารหลักฐาน",
) ),
) )
.then(async (res) => { .then(async (res) => {
const data = res.data; const downloadUrl = res.data.downloadUrl;
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `เอกสารความสามารถพิเศษ`,
});
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { DisciplineDetail } from "@/modules/10_registry/interface/index/Main"; import type { DisciplineDetail } from "@/modules/10_registry/interface/index/Main";
@ -194,8 +195,11 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) { async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const res = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: res.downloadUrl,
fileName: `เอกสารวินัย`,
});
} catch (e) { } catch (e) {
messageError($q, e); messageError($q, e);
} finally { } finally {
@ -208,7 +212,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { DutyFormType } from "@/modules/10_registry/interface/index/Main"; import type { DutyFormType } from "@/modules/10_registry/interface/index/Main";
@ -297,8 +298,11 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) { async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const res = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: res.downloadUrl,
fileName: `เอกสารปฏิบัติราชการพิเศษ`,
});
} catch (e) { } catch (e) {
messageError($q, e); messageError($q, e);
} finally { } finally {
@ -311,7 +315,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }

View file

@ -6,6 +6,7 @@ import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { DutyFormType } from "@/modules/10_registry/interface/index/Main"; import type { DutyFormType } from "@/modules/10_registry/interface/index/Main";
@ -302,12 +303,15 @@ async function onDownloadFile(id: string, profileId: string) {
"ช่วยราชการ", "ช่วยราชการ",
profileId, profileId,
id, id,
"เอกสารหลักฐาน" "เอกสารหลักฐาน",
) ),
) )
.then(async (res) => { .then(async (res) => {
const data = res.data; const downloadUrl = res.data.downloadUrl;
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `เอกสารช่วยราชการ`,
});
}) })
.catch((err) => { .catch((err) => {
messageError($q, err); messageError($q, err);
@ -322,7 +326,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { NopaidFormType } from "@/modules/10_registry/interface/index/Main"; import type { NopaidFormType } from "@/modules/10_registry/interface/index/Main";
@ -255,7 +256,7 @@ async function getHistory() {
rowsHistoryData.value = []; rowsHistoryData.value = [];
await http await http
.get( .get(
config.API.dataUserSalaryNopaidHistoryByType(link.value, idByRow.value) config.API.dataUserSalaryNopaidHistoryByType(link.value, idByRow.value),
) )
.then((res) => { .then((res) => {
const data = res.data.result; const data = res.data.result;
@ -278,8 +279,12 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) { async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const res = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); const downloadUrl = res.downloadUrl;
await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `บันทึกวันที่ไม่ได้รับ${salaryText.value}`,
});
} catch (e) { } catch (e) {
messageError($q, e); messageError($q, e);
} finally { } finally {
@ -292,7 +297,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { CertificateDetail } from "@/modules/10_registry/interface/index/Main"; import type { CertificateDetail } from "@/modules/10_registry/interface/index/Main";
@ -253,8 +254,8 @@ async function getHistory() {
config.API.dataUserCertificateHistoryByType( config.API.dataUserCertificateHistoryByType(
link.value, link.value,
"certificate", "certificate",
idByRow.value idByRow.value,
) ),
) )
.then((res) => { .then((res) => {
const data = res.data.result; const data = res.data.result;
@ -278,7 +279,10 @@ async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: data.downloadUrl,
fileName: `เอกสารใบอนุญาตประกอบวิชาชีพ`,
});
} catch (error) { } catch (error) {
messageError($q, error); messageError($q, error);
} finally { } finally {
@ -291,7 +295,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { InsigniaFormType } from "@/modules/10_registry/interface/index/Main"; import type { InsigniaFormType } from "@/modules/10_registry/interface/index/Main";
@ -469,8 +470,8 @@ async function getHistory() {
config.API.dataUserCertificateHistoryByType( config.API.dataUserCertificateHistoryByType(
link.value, link.value,
"insignia", "insignia",
idByRow.value idByRow.value,
) ),
) )
.then((res) => { .then((res) => {
const data = res.data.result; const data = res.data.result;
@ -494,7 +495,10 @@ async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: data.downloadUrl,
fileName: `เอกสารเครื่องราชอิสริยาภรณ์`,
});
} catch (error) { } catch (error) {
messageError($q, error); messageError($q, error);
} finally { } finally {
@ -507,7 +511,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }
@ -647,7 +651,6 @@ onMounted(async () => {
dense dense
round round
size="14px" size="14px"
class="absolute_button"
@click="onHistory(props.row.id)" @click="onHistory(props.row.id)"
> >
<q-tooltip>ประวแกไขเครองราชอสรยาภรณ</q-tooltip> <q-tooltip>ประวแกไขเครองราชอสรยาภรณ</q-tooltip>

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data"; import { useDataStore } from "@/stores/data";
import { useRegistryDataStore } from "@/modules/10_registry/store/Main"; import { useRegistryDataStore } from "@/modules/10_registry/store/Main";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { HonorFormData } from "@/modules/10_registry/interface/index/Main"; import type { HonorFormData } from "@/modules/10_registry/interface/index/Main";
@ -278,7 +279,10 @@ async function onDownloadFile(id: string, profileId: string) {
showLoader(); showLoader();
try { try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id); const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank"); await downloadBlobFile({
downloadUrl: data.downloadUrl,
fileName: `เอกสารประกาศเกียรติคุณ`,
});
} catch (error) { } catch (error) {
messageError($q, error); messageError($q, error);
} finally { } finally {
@ -291,7 +295,7 @@ function onSearch() {
rows.value = onSearchDataTable( rows.value = onSearchDataTable(
filter.value, filter.value,
rowsData.value, rowsData.value,
columns.value ? columns.value : [] columns.value ? columns.value : [],
); );
} }
@ -429,7 +433,6 @@ onMounted(async () => {
dense dense
round round
size="14px" size="14px"
class="absolute_button"
@click="onHistory(props.row.id)" @click="onHistory(props.row.id)"
> >
<q-tooltip>ประวแกไขประกาศเกยรต</q-tooltip> <q-tooltip>ประวแกไขประกาศเกยรต</q-tooltip>

View file

@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { is, useQuasar } from "quasar"; import { useQuasar } from "quasar";
import { ref, onMounted } from "vue"; import { ref, onMounted, watch } from "vue";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useRegistryInFormationStore } from "@/modules/10_registry/store/registry"; import { useRegistryInFormationStore } from "@/modules/10_registry/store/registry";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { FileFormType } from "@/modules/10_registry/interface/index/Main"; import type { FileFormType } from "@/modules/10_registry/interface/index/Main";
@ -18,14 +19,15 @@ const fileList = ref<FileFormType[]>([]);
/** ฟังก์ชันดึงข้อมูลไฟล์ */ /** ฟังก์ชันดึงข้อมูลไฟล์ */
async function getData() { async function getData() {
if (!store.profileId) return;
isLoading.value = true; isLoading.value = true;
await http await http
.get( .get(
config.API.fileByFileUser( config.API.fileByFileUser(
"ระบบทะเบียนประวัติ", "ระบบทะเบียนประวัติ",
"เอกสารหลักฐาน", "เอกสารหลักฐาน",
store.profileId store.profileId,
) ),
) )
.then((res) => { .then((res) => {
const data = res.data; const data = res.data;
@ -51,12 +53,15 @@ async function downloadFile(fileName: string) {
"ระบบทะเบียนประวัติ", "ระบบทะเบียนประวัติ",
"เอกสารหลักฐาน", "เอกสารหลักฐาน",
store.profileId, store.profileId,
fileName fileName,
),
) )
) .then(async (res) => {
.then((res) => { const downloadUrl = res.data.downloadUrl;
const data = res.data.downloadUrl; await downloadBlobFile({
window.open(data, "_blank"); downloadUrl: downloadUrl,
fileName: fileName,
});
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
@ -69,6 +74,15 @@ async function downloadFile(fileName: string) {
onMounted(() => { onMounted(() => {
getData(); getData();
}); });
watch(
() => store.profileId,
(newVal) => {
if (newVal) {
getData();
}
},
);
</script> </script>
<template> <template>

View file

@ -1,11 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, onMounted } from "vue"; import { ref, onMounted, watch } from "vue";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar"; import { useQuasar } from "quasar";
import http from "@/plugins/http"; import http from "@/plugins/http";
import config from "@/app.config"; import config from "@/app.config";
import { useRegistryInFormationStore } from "@/modules/10_registry/store/registry"; import { useRegistryInFormationStore } from "@/modules/10_registry/store/registry";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { FileFormType } from "@/modules/10_registry/interface/index/Main"; import type { FileFormType } from "@/modules/10_registry/interface/index/Main";
@ -18,14 +19,15 @@ const fileList = ref<FileFormType[]>([]);
/** ฟังก์ชันดึงข้อมูลไฟล์ */ /** ฟังก์ชันดึงข้อมูลไฟล์ */
async function getData() { async function getData() {
if (!store.citizenId) return;
isLoading.value = true; isLoading.value = true;
await http await http
.get( .get(
config.API.fileByFileUser( config.API.fileByFileUser(
"ระบบทะเบียนประวัติ", "ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม", "เอกสารหลักฐานเพิ่มเติม",
store.citizenId store.citizenId,
) ),
) )
.then((res) => { .then((res) => {
const data = res.data; const data = res.data;
@ -51,12 +53,15 @@ async function downloadFile(fileName: string) {
"ระบบทะเบียนประวัติ", "ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม", "เอกสารหลักฐานเพิ่มเติม",
store.citizenId, store.citizenId,
fileName fileName,
),
) )
) .then(async (res) => {
.then((res) => { const downloadUrl = res.data.downloadUrl;
const data = res.data.downloadUrl; await downloadBlobFile({
window.open(data, "_blank"); downloadUrl: downloadUrl,
fileName: fileName,
});
}) })
.catch((e) => { .catch((e) => {
messageError($q, e); messageError($q, e);
@ -69,6 +74,15 @@ async function downloadFile(fileName: string) {
onMounted(() => { onMounted(() => {
getData(); getData();
}); });
watch(
() => store.citizenId,
(newVal) => {
if (newVal) {
getData();
}
},
);
</script> </script>
<template> <template>

View file

@ -24,6 +24,8 @@ import type { DataPosition } from "@/modules/10_registry/interface/review/Edit";
// import DialogSort from "@/modules/04_registryPerson/views/edit/components/DialogSort.vue"; // import DialogSort from "@/modules/04_registryPerson/views/edit/components/DialogSort.vue";
// import CurruncyInput from "@/components/CurruncyInput.vue"; // import CurruncyInput from "@/components/CurruncyInput.vue";
import { exportToExcelPosition } from "@/modules/10_registry/utils/exportPosition";
const dataStore = useDataStore(); const dataStore = useDataStore();
const store = useGovernmentPosDataStore(); const store = useGovernmentPosDataStore();
const $q = useQuasar(); const $q = useQuasar();
@ -323,20 +325,23 @@ async function fetchData() {
// .get( // .get(
// `${config.API.profileSalaryTemp}/${empType.value}/done/${profileId.value}`, // `${config.API.profileSalaryTemp}/${empType.value}/done/${profileId.value}`,
// ) // )
http try {
.get(`${config.API.profileSalaryTemp}/${empType.value}/${profileId.value}`) await http.get(
.then((res) => { `${config.API.profileSalaryTemp}/${empType.value}/${profileId.value}`,
);
const res = await http.get(
`${config.API.profileSalaryTemp}/${empType.value}/done/${profileId.value}`,
);
const data = res.data.result; const data = res.data.result;
rowsMain.value = data; rowsMain.value = data;
rows.value = data; rows.value = data;
serchDataTable(); serchDataTable();
}) } catch (err) {
.catch((err) => {
messageError($q, err); messageError($q, err);
}) } finally {
.finally(() => {
isLoad.value = false; isLoad.value = false;
}); }
} }
/** function ค้นหาข้อมูลรายการในตาราง*/ /** function ค้นหาข้อมูลรายการในตาราง*/
@ -442,67 +447,68 @@ function classColorRow(isDelete: boolean, isEdit: boolean, isEntry: boolean) {
/** ฟังก์ชันดาวน์โหลดไฟล Excel */ /** ฟังก์ชันดาวน์โหลดไฟล Excel */
function exportToExcel() { function exportToExcel() {
const newData = rows.value.map((e: DataPosition, index: number) => { exportToExcelPosition(rows.value);
return { // const newData = rows.value.map((e: DataPosition, index: number) => {
no: index + 1, // return {
commandDateAffect: date2Thai(e.commandDateAffect), // no: index + 1,
positionName: e.positionName, // commandDateAffect: date2Thai(e.commandDateAffect),
positionType: e.positionType, // positionName: e.positionName,
positionLevel: e.positionLevel // positionType: e.positionType,
? e.positionLevel // positionLevel: e.positionLevel
: e.positionCee // ? e.positionLevel
? e.positionCee // : e.positionCee
: "", // ? e.positionCee
positionExecutive: e.positionExecutive, // : "",
amount: e.amount, // positionExecutive: e.positionExecutive,
mouthSalaryAmount: e.mouthSalaryAmount, // amount: e.amount,
positionSalaryAmount: e.positionSalaryAmount, // mouthSalaryAmount: e.mouthSalaryAmount,
organization: findOrgName({ // positionSalaryAmount: e.positionSalaryAmount,
root: e.orgRoot, // organization: findOrgName({
child1: e.orgChild1, // root: e.orgRoot,
child2: e.orgChild2, // child1: e.orgChild1,
child3: e.orgChild3, // child2: e.orgChild2,
child4: e.orgChild4, // child3: e.orgChild3,
}), // child4: e.orgChild4,
posNo: // }),
e.posNoAbb && e.posNo // posNo:
? `${e.posNoAbb} ${e.posNo}` // e.posNoAbb && e.posNo
: e.posNo // ? `${e.posNoAbb} ${e.posNo}`
? e.posNo // : e.posNo
: "", // ? e.posNo
posNumCodeSit: // : "",
e.posNumCodeSitAbb && e.posNumCodeSit // posNumCodeSit:
? `${e.posNumCodeSit} (${e.posNumCodeSitAbb})` // e.posNumCodeSitAbb && e.posNumCodeSit
: e.posNumCodeSit // ? `${e.posNumCodeSit} (${e.posNumCodeSitAbb})`
? e.posNumCodeSit // : e.posNumCodeSit
: "", // ? e.posNumCodeSit
commandNo: // : "",
e.commandNo && e.commandYear // commandNo:
? `${e.commandNo}/${Number(e.commandYear) + 543}` // e.commandNo && e.commandYear
: "", // ? `${e.commandNo}/${Number(e.commandYear) + 543}`
commandDateSign: date2Thai(e.commandDateSign), // : "",
commandCode: store.convertCommandCodeName(e.commandCode), // commandDateSign: date2Thai(e.commandDateSign),
remark: e.remark, // commandCode: store.convertCommandCodeName(e.commandCode),
}; // remark: e.remark,
}); // };
// });
const headers = columns.value.map((item: any) => item.label) || []; // // const headers = columns.value.map((item: any) => item.label) || []; //
const worksheet = XLSX.utils.json_to_sheet(newData, { // const worksheet = XLSX.utils.json_to_sheet(newData, {
header: visibleColumns.value, // header: visibleColumns.value,
}); // });
// ( A1, B1, C1 ) // ( A1, B1, C1 )
XLSX.utils.sheet_add_aoa(worksheet, [headers], { origin: "A1" }); // XLSX.utils.sheet_add_aoa(worksheet, [headers], { origin: "A1" });
// Create a new workbook and append the worksheet // Create a new workbook and append the worksheet
const workbook = XLSX.utils.book_new(); // const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet( // XLSX.utils.book_append_sheet(
workbook, // workbook,
worksheet, // worksheet,
`รายการประวัติตำแหน่งเงินเดือน`, // ``,
); // );
XLSX.writeFile(workbook, "รายการประวัติตำแหน่งเงินเดือน.xlsx"); // XLSX.writeFile(workbook, ".xlsx");
} }
// const commandCodeOptions = ref<DataOption[]>(store.commandCodeData); // // const commandCodeOptions = ref<DataOption[]>(store.commandCodeData); //
@ -880,12 +886,20 @@ async function fetchDataCommandCode() {
// } // }
onMounted(async () => { onMounted(async () => {
// delay dataStore fetch position
await new Promise((resolve) => setTimeout(resolve, 800));
if (dataStore.officerType && dataStore.profileId) { if (dataStore.officerType && dataStore.profileId) {
await Promise.all([fetchData(), fetchDataCommandCode()]); await Promise.all([fetchData(), fetchDataCommandCode()]);
} }
}); });
watch(
() => [dataStore.officerType, dataStore.profileId],
async ([officerType, profileId]) => {
if (officerType && profileId) {
await Promise.all([fetchData(), fetchDataCommandCode()]);
}
},
{ immediate: true },
);
</script> </script>
<template> <template>

View file

@ -71,6 +71,7 @@ interface DataPosition {
status: string; status: string;
posNumCodeSitAbb: string; posNumCodeSitAbb: string;
posNumCodeSit: string; posNumCodeSit: string;
positionExecutiveField: string;
} }
export type { DataSalaryPos, DataPosition }; export type { DataSalaryPos, DataPosition };

View file

@ -0,0 +1,60 @@
export interface DownloadFileOptions {
downloadUrl: string;
fileName: string;
}
const isMobile =
/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(
navigator.userAgent,
);
export async function downloadBlobFile({
downloadUrl,
fileName,
}: DownloadFileOptions): Promise<void> {
// Use window.open for desktop, blob download for mobile
if (!isMobile) {
window.open(downloadUrl, "_blank");
return;
}
const response = await fetch(downloadUrl);
const blob = await response.blob();
const contentType: string | null = response.headers.get("Content-Type");
const extensionMap: Record<string, string> = {
"application/pdf": "pdf",
"image/jpeg": "jpg",
"image/png": "png",
"image/gif": "gif",
"application/zip": "zip",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document":
"docx",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "xlsx",
};
let extension = contentType ? extensionMap[contentType] : undefined;
if (!extension) {
const urlWithoutQuery = downloadUrl.split("?")[0];
extension = urlWithoutQuery.includes(".")
? urlWithoutQuery.split(".").pop()
: "pdf";
}
const blobForDownload = new Blob([blob], {
type: "application/octet-stream",
});
const url = URL.createObjectURL(blobForDownload);
const link = document.createElement("a");
link.href = url;
const downloadFileName = fileName.includes(".") ? fileName : `${fileName}.${extension}`;
link.download = downloadFileName;
document.body.appendChild(link);
link.click();
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 100);
}

View file

@ -0,0 +1,157 @@
import ExcelJS from "exceljs";
import { useGovernmentPosDataStore } from "@/modules/10_registry/store/Position";
import type { DataPosition } from "@/modules/10_registry/interface/review/Edit";
const store = useGovernmentPosDataStore();
// ฟังก์ชันแปลงวันที่จาก ISO format เป็นรูปแบบ dd/mm/yyyy (เช่น 18/05/2564)
function formatDateToDDMMYYYY(dateString: string | null | Date): string {
if (!dateString) return "";
const date = new Date(dateString);
if (isNaN(date.getTime())) return "";
const day = String(date.getDate()).padStart(2, "0");
const month = String(date.getMonth() + 1).padStart(2, "0");
const year = date.getFullYear() + 543; // แปลงเป็นปีพุทธศักราช
return `${day}/${month}/${year}`;
}
export async function exportToExcelPosition(data: DataPosition[]) {
const workbook = new ExcelJS.Workbook();
const worksheet = workbook.addWorksheet("รายการประวัติตำแหน่งเงินเดือน");
// --- ส่วนที่ 1: สร้าง Master Data Sheet สำหรับอ้างอิง ID ---
// เราจะซ่อนแผ่นงานนี้ไว้ (hidden) เพื่อใช้ทำ Dropdown และ VLOOKUP
const masterSheet = workbook.addWorksheet("MasterData", { state: "hidden" });
const masterData = store.commandCodeData; // [{id: 1, name: "ย้าย"}, ...]
masterData.forEach((item, index) => {
masterSheet.getCell(`A${index + 1}`).value = item.name;
masterSheet.getCell(`B${index + 1}`).value = item.id;
});
// --- ส่วนที่ 2: กำหนด Columns ---
worksheet.columns = [
{ header: "ลำดับ", key: "no", width: 8 },
{ header: "วันที่คำสั่งมีผล", key: "commandDateAffect", width: 18 },
{ header: "ตำแหน่งในสายงาน", key: "positionName", width: 25 },
{ header: "ตำแหน่งประเภท", key: "positionType", width: 18 },
{ header: "ระดับ", key: "positionLevel", width: 12 },
{ header: "ระดับซี", key: "positionCee", width: 12 },
{ header: "สายงาน", key: "positionLine", width: 20 },
{ header: "ด้าน/สาขา", key: "positionPathSide", width: 15 },
{ header: "ตำแหน่งทางการบริหาร", key: "positionExecutive", width: 20 },
{ header: "ด้านทางการบริหาร", key: "positionExecutiveField", width: 20 },
{ header: "เงินเดือน", key: "amount", width: 15 },
{ header: "เงินค่าตอบแทนรายเดือน", key: "mouthSalaryAmount", width: 15 },
{ header: "เงินประจำตำแหน่ง", key: "positionSalaryAmount", width: 15 },
{ header: "เงินค่าตอบแทนพิเศษ", key: "amountSpecial", width: 15 },
{ header: "หน่วยงาน", key: "organization", width: 30 },
{ header: "ส่วนราชการระดับ 1", key: "orgChild1", width: 20 },
{ header: "ส่วนราชการระดับ 2", key: "orgChild2", width: 20 },
{ header: "ส่วนราชการระดับ 3", key: "orgChild3", width: 20 },
{ header: "ส่วนราชการระดับ 4", key: "orgChild4", width: 20 },
{ header: "ตัวย่อเลขที่ตำแหน่ง", key: "posNoAbb", width: 15 },
{ header: "เลขที่ตำแหน่ง", key: "posNo", width: 15 },
{ header: "หน่วยงานที่ออกคำสั่ง", key: "posNumCodeSit", width: 20 },
{
header: "ตัวย่อหน่วยงานที่ออกคำสั่ง",
key: "posNumCodeSitAbb",
width: 15,
},
{ header: "เลขที่คำสั่ง", key: "commandNo", width: 15 },
{ header: "ปีเลขที่คำสั่ง", key: "commandYear", width: 12 },
{ header: "วันที่ลงนาม", key: "commandDateSign", width: 18 },
{ header: "ประเภทคำสั่ง", key: "commandCodeName", width: 25 }, // AA
{ header: "หมายเหตุ", key: "remark", width: 20 },
{ header: "commandId", key: "commandId", width: 20 }, // AC (ลำดับที่ 29)
{ header: "commandCode", key: "commandCode", width: 20 }, // AD (ลำดับที่ 30)
];
// 3. Map ข้อมูล
const newData = data.map((e, index) => ({
no: index + 1,
commandDateAffect: e.commandDateAffect
? formatDateToDDMMYYYY(e.commandDateAffect)
: "",
positionName: e.positionName,
positionType: e.positionType,
positionLevel: e.positionLevel,
positionCee: e.positionCee,
positionLine: e.positionLine || "",
positionPathSide: e.positionPathSide || "",
positionExecutive: e.positionExecutive,
positionExecutiveField: e.positionExecutiveField || "",
amount: e.amount || 0,
mouthSalaryAmount: e.mouthSalaryAmount || 0,
positionSalaryAmount: e.positionSalaryAmount || 0,
amountSpecial: e.amountSpecial || 0,
organization: e.orgRoot,
orgChild1: e.orgChild1,
orgChild2: e.orgChild2,
orgChild3: e.orgChild3,
orgChild4: e.orgChild4,
posNoAbb: e.posNoAbb,
posNo: e.posNo,
posNumCodeSit: e.posNumCodeSit,
posNumCodeSitAbb: e.posNumCodeSitAbb,
commandNo: e.commandNo,
commandYear: e.commandYear ? Number(e.commandYear) + 543 : "",
commandDateSign: e.commandDateSign
? formatDateToDDMMYYYY(e.commandDateSign)
: "",
commandCodeName: store.convertCommandCodeName(e.commandCode),
remark: e.remark,
commandId: e.commandId || "",
commandCode: e.commandCode || "", // ใส่ค่าเริ่มต้นไว้
}));
worksheet.addRows(newData);
// 4. ตกแต่งสี, Dropdown และ สูตร VLOOKUP
newData.forEach((_, index) => {
const rowIndex = index + 2;
// --- ตั้งค่า Format สำหรับเซลล์วันที่ ---
// เซลล์ B (commandDateAffect) และ Z (commandDateSign)
const dateAffectCell = worksheet.getCell(`B${rowIndex}`);
const dateSignCell = worksheet.getCell(`Z${rowIndex}`);
[dateAffectCell, dateSignCell].forEach((cell) => {
cell.numFmt = "dd/mm/yyyy";
});
// --- ทำ Dropdown คอลัมน์ AA ---
// อ้างอิงรายการจาก MasterData Sheet จะทำให้ Excel ทำงานได้เสถียรกว่า (กรณีรายการเยอะ)
worksheet.getCell(`AA${rowIndex}`).dataValidation = {
type: "list",
allowBlank: true,
formulae: [`MasterData!$A$1:$A$${masterData.length}`],
};
// --- ผูกสูตรให้ commandCode (AD) เปลี่ยนตามการเลือกใน AA ---
// AA คือประเภทคำสั่ง, AD คือ commandCode
worksheet.getCell(`AD${rowIndex}`).value = {
formula: `=IFERROR(VLOOKUP(AA${rowIndex}, MasterData!$A$1:$B$${masterData.length}, 2, FALSE), "")`,
};
});
// 5. สไตล์ Header
worksheet.getRow(1).font = { bold: true };
worksheet.getRow(1).alignment = { vertical: "middle", horizontal: "center" };
// 6. เขียนไฟล์
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
});
const url = window.URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = "รายการประวัติตำแหน่งเงินเดือน.xlsx";
a.click();
window.URL.revokeObjectURL(url);
}

View file

@ -2,6 +2,7 @@ import axios from "axios";
import config from "@/app.config"; import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin"; import { useCounterMixin } from "@/stores/mixin";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
const mixin = useCounterMixin(); const mixin = useCounterMixin();
const { showLoader, hideLoader } = mixin; const { showLoader, hideLoader } = mixin;
@ -19,7 +20,7 @@ async function genReport(data: any, fileName: string, type: string = "docx") {
}, },
responseType: "arraybuffer", responseType: "arraybuffer",
}) })
.then((res) => { .then(async (res) => {
const responseData = res.data; const responseData = res.data;
if (responseData) { if (responseData) {
const mimeType = const mimeType =
@ -31,18 +32,11 @@ async function genReport(data: any, fileName: string, type: string = "docx") {
const url = URL.createObjectURL(blob); const url = URL.createObjectURL(blob);
const baseName = fileName.trim(); const baseName = fileName.trim();
const extension = type === "docx" ? "docx" : "pdf"; // const extension = type === "docx" ? "docx" : "pdf";
await downloadBlobFile({
const link = document.createElement("a"); downloadUrl: url,
link.href = url; fileName: baseName,
link.download = `${baseName}.${extension}`; });
document.body.appendChild(link);
link.click();
setTimeout(() => {
document.body.removeChild(link);
URL.revokeObjectURL(url);
}, 100);
} }
}) })
.catch((err) => { .catch((err) => {

View file

@ -14,7 +14,7 @@ export const useCounterMixin = defineStore("mixin", () => {
const calAge = ( const calAge = (
srcDate: Date, srcDate: Date,
birthCal: Date = new Date(), birthCal: Date = new Date(),
eng: boolean = false eng: boolean = false,
) => { ) => {
const year = eng ? "years" : "ปี"; const year = eng ? "years" : "ปี";
const month = eng ? "months" : "เดือน"; const month = eng ? "months" : "เดือน";
@ -82,7 +82,7 @@ export const useCounterMixin = defineStore("mixin", () => {
function date2Thai( function date2Thai(
srcDate: Date | null, srcDate: Date | null,
isFullMonth: boolean = false, isFullMonth: boolean = false,
isTime: boolean = false isTime: boolean = false,
) { ) {
if (srcDate == null || !moment(srcDate).isValid()) return ""; if (srcDate == null || !moment(srcDate).isValid()) return "";
@ -98,7 +98,7 @@ export const useCounterMixin = defineStore("mixin", () => {
function dateThai( function dateThai(
srcDate: Date, srcDate: Date,
isFullMonth: boolean = true, isFullMonth: boolean = true,
isTime: boolean = false isTime: boolean = false,
) { ) {
if (srcDate == null) { if (srcDate == null) {
return null; return null;
@ -490,7 +490,7 @@ export const useCounterMixin = defineStore("mixin", () => {
color: string | undefined, color: string | undefined,
ok?: Function | undefined, ok?: Function | undefined,
cancel?: Function | undefined, cancel?: Function | undefined,
onlycancel: Boolean = false onlycancel: Boolean = false,
) => { ) => {
q.dialog({ q.dialog({
component: CustomComponent, component: CustomComponent,
@ -529,7 +529,7 @@ export const useCounterMixin = defineStore("mixin", () => {
title: string, title: string,
message: string, message: string,
ok: Function, ok: Function,
cancel?: Function cancel?: Function,
) { ) {
q.dialog({ q.dialog({
title: `<span class="text-red">${title}</span>`, title: `<span class="text-red">${title}</span>`,
@ -559,7 +559,7 @@ export const useCounterMixin = defineStore("mixin", () => {
title: string, title: string,
message: string, message: string,
ok: Function, ok: Function,
cancel?: Function cancel?: Function,
) { ) {
q.dialog({ q.dialog({
title: `<span class="text-primary">${title}</span>`, title: `<span class="text-primary">${title}</span>`,
@ -795,7 +795,7 @@ export const useCounterMixin = defineStore("mixin", () => {
ok?: Function, ok?: Function,
title?: string, // ถ้ามี cancel action ใส่เป็น null title?: string, // ถ้ามี cancel action ใส่เป็น null
desc?: string, // ถ้ามี cancel action ใส่เป็น null desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function cancel?: Function,
) => { ) => {
q.dialog({ q.dialog({
component: CustomComponent, component: CustomComponent,
@ -824,7 +824,7 @@ export const useCounterMixin = defineStore("mixin", () => {
ok?: Function, ok?: Function,
title?: string, // ถ้ามี cancel action ใส่เป็น null title?: string, // ถ้ามี cancel action ใส่เป็น null
desc?: string, // ถ้ามี cancel action ใส่เป็น null desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function cancel?: Function,
) => { ) => {
q.dialog({ q.dialog({
component: CustomComponent, component: CustomComponent,
@ -851,7 +851,7 @@ export const useCounterMixin = defineStore("mixin", () => {
const dialogMessageNotify = ( const dialogMessageNotify = (
q: any, q: any,
desc?: string, // ถ้ามี cancel action ใส่เป็น null desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function cancel?: Function,
) => { ) => {
q.dialog({ q.dialog({
component: CustomComponent, component: CustomComponent,
@ -1252,9 +1252,15 @@ export const useCounterMixin = defineStore("mixin", () => {
// กรณีมีเฉพาะ date // กรณีมีเฉพาะ date
function convertDateToAPI(date: Date | null) { function convertDateToAPI(date: Date | null) {
return date if (!date) return null;
? format(utcToZonedTime(date, "Asia/Bangkok"), "yyyy-MM-dd")
: null; const parsedDate = new Date(date);
if (parsedDate) {
return format(parsedDate, "yyyy-MM-dd");
} else {
return null;
}
} }
// กรณี datetime // กรณี datetime

View file

@ -172,13 +172,13 @@ const doLogout = () => {
); );
}; };
const clickDelete = async (id: string, index: number) => { const clickDelete = async (id: string, index: number | string) => {
dialogRemove($q, async () => { dialogRemove($q, async () => {
// showLoader(); // showLoader();
await http await http
.delete(config.API.msgId(id)) .delete(config.API.msgId(id))
.then(() => { .then(() => {
notiList.value.splice(index, 1); notiList.value.splice(Number(index), 1);
totalInbox.value--; totalInbox.value--;
totalNoti.value--; totalNoti.value--;
success($q, "ลบข้อมูลสำเร็จ"); success($q, "ลบข้อมูลสำเร็จ");
@ -772,10 +772,10 @@ watch(
<q-footer class="bg-grey-1 text-dark q-pa-md"> <q-footer class="bg-grey-1 text-dark q-pa-md">
<FooterContact /> <FooterContact />
</q-footer> </q-footer>
</q-layout>
<DialogResetPass v-model="modalResetPass" /> <DialogResetPass v-model="modalResetPass" />
<DialogDebug v-model:modal="modalDebug" /> <DialogDebug v-model:modal="modalDebug" />
</q-layout>
</template> </template>
<style> <style>