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",
"@vuepic/vue-datepicker": "^3.6.3",
"bma-org-chart": "^0.0.7",
"exceljs": "^4.4.0",
"html-to-image": "^1.11.13",
"keycloak-js": "^20.0.2",
"moment": "^2.29.4",

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-gutter-md q-pa-sm">
<div class="row">
<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 class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -30,11 +32,33 @@ const props = defineProps({
</div>
<div class="row">
<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 class="row">
<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 class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -87,10 +111,12 @@ const props = defineProps({
target="_blank"
outline
color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`"
:label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px"
>
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip>
<q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn>
</div>
</div>

View file

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

View file

@ -18,7 +18,9 @@ const props = defineProps({
<div class="q-pa-sm q-gutter-md">
<div class="row">
<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 class="row">
<div class="col-xs-12 col-md-6 text-grey-8">เรอง</div>
@ -42,11 +44,33 @@ const props = defineProps({
</div>
<div class="row">
<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 class="row">
<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 class="row">
<div class="col-xs-12 col-md-6 text-grey-8">จำนวนวนทลา</div>
@ -91,10 +115,12 @@ const props = defineProps({
target="_blank"
outline
color="blue"
:label="`ดาวน์โหลดเอกสารแนบที่ ${index + 1}`"
:label="`ดาวน์โหลดเอกสารแนบที่ ${Number(index) + 1}`"
size="12px"
>
<q-tooltip>ดาวนโหลดเอกสารแนบท {{ index + 1 }}</q-tooltip>
<q-tooltip
>ดาวนโหลดเอกสารแนบท {{ Number(index) + 1 }}</q-tooltip
>
</q-btn>
</div>
</div>

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -7,6 +7,7 @@ import config from "@/app.config";
import { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
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";
@ -194,8 +195,11 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) {
showLoader();
try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank");
const res = await getPathUploadFlie(fileGroup.value, profileId, id);
await downloadBlobFile({
downloadUrl: res.downloadUrl,
fileName: `เอกสารวินัย`,
});
} catch (e) {
messageError($q, e);
} finally {
@ -208,7 +212,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.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 { useDataStore } from "@/stores/data";
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";
@ -297,8 +298,11 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) {
showLoader();
try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank");
const res = await getPathUploadFlie(fileGroup.value, profileId, id);
await downloadBlobFile({
downloadUrl: res.downloadUrl,
fileName: `เอกสารปฏิบัติราชการพิเศษ`,
});
} catch (e) {
messageError($q, e);
} finally {
@ -311,7 +315,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.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 { useCounterMixin } from "@/stores/mixin";
import { useDataStore } from "@/stores/data";
import { downloadBlobFile } from "@/modules/10_registry/utils/downloadFile";
import type { DutyFormType } from "@/modules/10_registry/interface/index/Main";
@ -302,12 +303,15 @@ async function onDownloadFile(id: string, profileId: string) {
"ช่วยราชการ",
profileId,
id,
"เอกสารหลักฐาน"
)
"เอกสารหลักฐาน",
),
)
.then(async (res) => {
const data = res.data;
window.open(data.downloadUrl, "_blank");
const downloadUrl = res.data.downloadUrl;
await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `เอกสารช่วยราชการ`,
});
})
.catch((err) => {
messageError($q, err);
@ -322,7 +326,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.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 { useDataStore } from "@/stores/data";
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";
@ -255,7 +256,7 @@ async function getHistory() {
rowsHistoryData.value = [];
await http
.get(
config.API.dataUserSalaryNopaidHistoryByType(link.value, idByRow.value)
config.API.dataUserSalaryNopaidHistoryByType(link.value, idByRow.value),
)
.then((res) => {
const data = res.data.result;
@ -278,8 +279,12 @@ async function getHistory() {
async function onDownloadFile(id: string, profileId: string) {
showLoader();
try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank");
const res = await getPathUploadFlie(fileGroup.value, profileId, id);
const downloadUrl = res.downloadUrl;
await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: `บันทึกวันที่ไม่ได้รับ${salaryText.value}`,
});
} catch (e) {
messageError($q, e);
} finally {
@ -292,7 +297,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.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 { useDataStore } from "@/stores/data";
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";
@ -253,8 +254,8 @@ async function getHistory() {
config.API.dataUserCertificateHistoryByType(
link.value,
"certificate",
idByRow.value
)
idByRow.value,
),
)
.then((res) => {
const data = res.data.result;
@ -278,7 +279,10 @@ async function onDownloadFile(id: string, profileId: string) {
showLoader();
try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank");
await downloadBlobFile({
downloadUrl: data.downloadUrl,
fileName: `เอกสารใบอนุญาตประกอบวิชาชีพ`,
});
} catch (error) {
messageError($q, error);
} finally {
@ -291,7 +295,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.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 { useDataStore } from "@/stores/data";
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";
@ -469,8 +470,8 @@ async function getHistory() {
config.API.dataUserCertificateHistoryByType(
link.value,
"insignia",
idByRow.value
)
idByRow.value,
),
)
.then((res) => {
const data = res.data.result;
@ -494,7 +495,10 @@ async function onDownloadFile(id: string, profileId: string) {
showLoader();
try {
const data = await getPathUploadFlie(fileGroup.value, profileId, id);
window.open(data.downloadUrl, "_blank");
await downloadBlobFile({
downloadUrl: data.downloadUrl,
fileName: `เอกสารเครื่องราชอิสริยาภรณ์`,
});
} catch (error) {
messageError($q, error);
} finally {
@ -507,7 +511,7 @@ function onSearch() {
rows.value = onSearchDataTable(
filter.value,
rowsData.value,
columns.value ? columns.value : []
columns.value ? columns.value : [],
);
}
@ -647,7 +651,6 @@ onMounted(async () => {
dense
round
size="14px"
class="absolute_button"
@click="onHistory(props.row.id)"
>
<q-tooltip>ประวแกไขเครองราชอสรยาภรณ</q-tooltip>

View file

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

View file

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

View file

@ -1,11 +1,12 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { ref, onMounted, watch } from "vue";
import { useCounterMixin } from "@/stores/mixin";
import { useQuasar } from "quasar";
import http from "@/plugins/http";
import config from "@/app.config";
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";
@ -18,14 +19,15 @@ const fileList = ref<FileFormType[]>([]);
/** ฟังก์ชันดึงข้อมูลไฟล์ */
async function getData() {
if (!store.citizenId) return;
isLoading.value = true;
await http
.get(
config.API.fileByFileUser(
"ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม",
store.citizenId
)
store.citizenId,
),
)
.then((res) => {
const data = res.data;
@ -51,12 +53,15 @@ async function downloadFile(fileName: string) {
"ระบบทะเบียนประวัติ",
"เอกสารหลักฐานเพิ่มเติม",
store.citizenId,
fileName
fileName,
),
)
)
.then((res) => {
const data = res.data.downloadUrl;
window.open(data, "_blank");
.then(async (res) => {
const downloadUrl = res.data.downloadUrl;
await downloadBlobFile({
downloadUrl: downloadUrl,
fileName: fileName,
});
})
.catch((e) => {
messageError($q, e);
@ -69,6 +74,15 @@ async function downloadFile(fileName: string) {
onMounted(() => {
getData();
});
watch(
() => store.citizenId,
(newVal) => {
if (newVal) {
getData();
}
},
);
</script>
<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 CurruncyInput from "@/components/CurruncyInput.vue";
import { exportToExcelPosition } from "@/modules/10_registry/utils/exportPosition";
const dataStore = useDataStore();
const store = useGovernmentPosDataStore();
const $q = useQuasar();
@ -323,20 +325,23 @@ async function fetchData() {
// .get(
// `${config.API.profileSalaryTemp}/${empType.value}/done/${profileId.value}`,
// )
http
.get(`${config.API.profileSalaryTemp}/${empType.value}/${profileId.value}`)
.then((res) => {
try {
await http.get(
`${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;
rowsMain.value = data;
rows.value = data;
serchDataTable();
})
.catch((err) => {
} catch (err) {
messageError($q, err);
})
.finally(() => {
} finally {
isLoad.value = false;
});
}
}
/** function ค้นหาข้อมูลรายการในตาราง*/
@ -442,67 +447,68 @@ function classColorRow(isDelete: boolean, isEdit: boolean, isEntry: boolean) {
/** ฟังก์ชันดาวน์โหลดไฟล Excel */
function exportToExcel() {
const newData = rows.value.map((e: DataPosition, index: number) => {
return {
no: index + 1,
commandDateAffect: date2Thai(e.commandDateAffect),
positionName: e.positionName,
positionType: e.positionType,
positionLevel: e.positionLevel
? e.positionLevel
: e.positionCee
? e.positionCee
: "",
positionExecutive: e.positionExecutive,
amount: e.amount,
mouthSalaryAmount: e.mouthSalaryAmount,
positionSalaryAmount: e.positionSalaryAmount,
organization: findOrgName({
root: e.orgRoot,
child1: e.orgChild1,
child2: e.orgChild2,
child3: e.orgChild3,
child4: e.orgChild4,
}),
posNo:
e.posNoAbb && e.posNo
? `${e.posNoAbb} ${e.posNo}`
: e.posNo
? e.posNo
: "",
posNumCodeSit:
e.posNumCodeSitAbb && e.posNumCodeSit
? `${e.posNumCodeSit} (${e.posNumCodeSitAbb})`
: e.posNumCodeSit
? e.posNumCodeSit
: "",
commandNo:
e.commandNo && e.commandYear
? `${e.commandNo}/${Number(e.commandYear) + 543}`
: "",
commandDateSign: date2Thai(e.commandDateSign),
commandCode: store.convertCommandCodeName(e.commandCode),
remark: e.remark,
};
});
exportToExcelPosition(rows.value);
// const newData = rows.value.map((e: DataPosition, index: number) => {
// return {
// no: index + 1,
// commandDateAffect: date2Thai(e.commandDateAffect),
// positionName: e.positionName,
// positionType: e.positionType,
// positionLevel: e.positionLevel
// ? e.positionLevel
// : e.positionCee
// ? e.positionCee
// : "",
// positionExecutive: e.positionExecutive,
// amount: e.amount,
// mouthSalaryAmount: e.mouthSalaryAmount,
// positionSalaryAmount: e.positionSalaryAmount,
// organization: findOrgName({
// root: e.orgRoot,
// child1: e.orgChild1,
// child2: e.orgChild2,
// child3: e.orgChild3,
// child4: e.orgChild4,
// }),
// posNo:
// e.posNoAbb && e.posNo
// ? `${e.posNoAbb} ${e.posNo}`
// : e.posNo
// ? e.posNo
// : "",
// posNumCodeSit:
// e.posNumCodeSitAbb && e.posNumCodeSit
// ? `${e.posNumCodeSit} (${e.posNumCodeSitAbb})`
// : e.posNumCodeSit
// ? e.posNumCodeSit
// : "",
// commandNo:
// e.commandNo && e.commandYear
// ? `${e.commandNo}/${Number(e.commandYear) + 543}`
// : "",
// commandDateSign: date2Thai(e.commandDateSign),
// commandCode: store.convertCommandCodeName(e.commandCode),
// remark: e.remark,
// };
// });
const headers = columns.value.map((item: any) => item.label) || []; //
const worksheet = XLSX.utils.json_to_sheet(newData, {
header: visibleColumns.value,
});
// const headers = columns.value.map((item: any) => item.label) || []; //
// const worksheet = XLSX.utils.json_to_sheet(newData, {
// header: visibleColumns.value,
// });
// ( 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
const workbook = XLSX.utils.book_new();
// const workbook = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(
workbook,
worksheet,
`รายการประวัติตำแหน่งเงินเดือน`,
);
XLSX.writeFile(workbook, "รายการประวัติตำแหน่งเงินเดือน.xlsx");
// XLSX.utils.book_append_sheet(
// workbook,
// worksheet,
// ``,
// );
// XLSX.writeFile(workbook, ".xlsx");
}
// const commandCodeOptions = ref<DataOption[]>(store.commandCodeData); //
@ -880,12 +886,20 @@ async function fetchDataCommandCode() {
// }
onMounted(async () => {
// delay dataStore fetch position
await new Promise((resolve) => setTimeout(resolve, 800));
if (dataStore.officerType && dataStore.profileId) {
await Promise.all([fetchData(), fetchDataCommandCode()]);
}
});
watch(
() => [dataStore.officerType, dataStore.profileId],
async ([officerType, profileId]) => {
if (officerType && profileId) {
await Promise.all([fetchData(), fetchDataCommandCode()]);
}
},
{ immediate: true },
);
</script>
<template>

View file

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

View file

@ -14,7 +14,7 @@ export const useCounterMixin = defineStore("mixin", () => {
const calAge = (
srcDate: Date,
birthCal: Date = new Date(),
eng: boolean = false
eng: boolean = false,
) => {
const year = eng ? "years" : "ปี";
const month = eng ? "months" : "เดือน";
@ -82,7 +82,7 @@ export const useCounterMixin = defineStore("mixin", () => {
function date2Thai(
srcDate: Date | null,
isFullMonth: boolean = false,
isTime: boolean = false
isTime: boolean = false,
) {
if (srcDate == null || !moment(srcDate).isValid()) return "";
@ -98,7 +98,7 @@ export const useCounterMixin = defineStore("mixin", () => {
function dateThai(
srcDate: Date,
isFullMonth: boolean = true,
isTime: boolean = false
isTime: boolean = false,
) {
if (srcDate == null) {
return null;
@ -490,7 +490,7 @@ export const useCounterMixin = defineStore("mixin", () => {
color: string | undefined,
ok?: Function | undefined,
cancel?: Function | undefined,
onlycancel: Boolean = false
onlycancel: Boolean = false,
) => {
q.dialog({
component: CustomComponent,
@ -529,7 +529,7 @@ export const useCounterMixin = defineStore("mixin", () => {
title: string,
message: string,
ok: Function,
cancel?: Function
cancel?: Function,
) {
q.dialog({
title: `<span class="text-red">${title}</span>`,
@ -559,7 +559,7 @@ export const useCounterMixin = defineStore("mixin", () => {
title: string,
message: string,
ok: Function,
cancel?: Function
cancel?: Function,
) {
q.dialog({
title: `<span class="text-primary">${title}</span>`,
@ -795,7 +795,7 @@ export const useCounterMixin = defineStore("mixin", () => {
ok?: Function,
title?: string, // ถ้ามี cancel action ใส่เป็น null
desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function
cancel?: Function,
) => {
q.dialog({
component: CustomComponent,
@ -824,7 +824,7 @@ export const useCounterMixin = defineStore("mixin", () => {
ok?: Function,
title?: string, // ถ้ามี cancel action ใส่เป็น null
desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function
cancel?: Function,
) => {
q.dialog({
component: CustomComponent,
@ -851,7 +851,7 @@ export const useCounterMixin = defineStore("mixin", () => {
const dialogMessageNotify = (
q: any,
desc?: string, // ถ้ามี cancel action ใส่เป็น null
cancel?: Function
cancel?: Function,
) => {
q.dialog({
component: CustomComponent,
@ -1252,9 +1252,15 @@ export const useCounterMixin = defineStore("mixin", () => {
// กรณีมีเฉพาะ date
function convertDateToAPI(date: Date | null) {
return date
? format(utcToZonedTime(date, "Asia/Bangkok"), "yyyy-MM-dd")
: null;
if (!date) return null;
const parsedDate = new Date(date);
if (parsedDate) {
return format(parsedDate, "yyyy-MM-dd");
} else {
return null;
}
}
// กรณี 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 () => {
// showLoader();
await http
.delete(config.API.msgId(id))
.then(() => {
notiList.value.splice(index, 1);
notiList.value.splice(Number(index), 1);
totalInbox.value--;
totalNoti.value--;
success($q, "ลบข้อมูลสำเร็จ");
@ -772,10 +772,10 @@ watch(
<q-footer class="bg-grey-1 text-dark q-pa-md">
<FooterContact />
</q-footer>
</q-layout>
<DialogResetPass v-model="modalResetPass" />
<DialogDebug v-model:modal="modalDebug" />
</q-layout>
</template>
<style>