588 lines
17 KiB
Vue
588 lines
17 KiB
Vue
<!-- tab รายการ หน้าปฏิทินวันหยุด -->
|
|
<template>
|
|
<q-card class="q-mt-md" flat bordered>
|
|
<!-- list รายการันหยุด -->
|
|
<q-tabs
|
|
dense
|
|
v-model="currentTab"
|
|
indicator-color="primary"
|
|
active-color="primary bg-teal-1"
|
|
class="text-body2 text-grey-7"
|
|
>
|
|
<q-tab
|
|
v-for="tab in tabs"
|
|
:key="tab.value"
|
|
v-on:click="changeTab(tab.value)"
|
|
:label="tab.label"
|
|
:name="tab.value"
|
|
class="q-py-xs col-6 row"
|
|
/>
|
|
</q-tabs>
|
|
<q-table
|
|
ref="table"
|
|
flat
|
|
bordered
|
|
class="custom-header-table"
|
|
virtual-scroll
|
|
:rows="calendarData"
|
|
:columns="columns"
|
|
dense
|
|
:rows-per-page-options="[0]"
|
|
hide-header
|
|
>
|
|
<template v-slot:body="props">
|
|
<q-tr :props="props">
|
|
<q-td v-for="col in props.cols" :key="col.name" :props="props">
|
|
<div v-if="col.name == 'week'" class="">
|
|
{{ dayThaiRange(props.row.dateRange) }}
|
|
</div>
|
|
<div v-else-if="col.name == 'holidayDate'" class="">
|
|
{{ dateThaiRange(props.row.dateRange) }}
|
|
</div>
|
|
<div v-else class="my-table-details">
|
|
{{ col.value }}
|
|
</div>
|
|
</q-td>
|
|
<q-td auto-width>
|
|
<q-btn
|
|
flat
|
|
round
|
|
color="grey"
|
|
@click.stop
|
|
size="10px"
|
|
icon="more_vert"
|
|
>
|
|
<q-menu>
|
|
<q-list>
|
|
<q-item
|
|
clickable
|
|
v-close-popup
|
|
@click="editCalendar(props.row)"
|
|
>
|
|
<q-item-section>
|
|
<q-item-label>แก้ไขวันหยุด</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
<q-item
|
|
clickable
|
|
v-close-popup
|
|
@click="deleteClick(props.row)"
|
|
>
|
|
<q-item-section>
|
|
<q-item-label>ลบวันหยุด</q-item-label>
|
|
</q-item-section>
|
|
</q-item>
|
|
</q-list>
|
|
</q-menu>
|
|
</q-btn>
|
|
</q-td>
|
|
</q-tr>
|
|
</template>
|
|
</q-table>
|
|
</q-card>
|
|
|
|
<!-- modal เพิ่มวันหยุด -->
|
|
<q-dialog v-model="modalAdd" persistent>
|
|
<q-card style="min-width: 550px">
|
|
<q-form ref="formDate" @submit.prevent.stop="editData">
|
|
<q-card-section class="row items-center q-pb-xs">
|
|
<div class="text-bold">แก้ไขวันหยุด</div>
|
|
<q-space />
|
|
<q-btn
|
|
icon="close"
|
|
unelevated
|
|
round
|
|
dense
|
|
v-close-popup
|
|
style="color: #ff8080; background-color: #ffdede"
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-section class="q-p-sm">
|
|
<div class="row col-12 q-col-gutter-sm">
|
|
<div class="col-2 subName">
|
|
<label>เลือกวันที่</label>
|
|
</div>
|
|
<div class="col-10">
|
|
<datepicker
|
|
v-model="dateAdd"
|
|
:locale="'th'"
|
|
autoApply
|
|
range
|
|
:enableTimePicker="false"
|
|
week-start="0"
|
|
>
|
|
<template #year="{ year }">
|
|
{{ year + 543 }}
|
|
</template>
|
|
<template #year-overlay-value="{ value }">
|
|
{{ parseInt(value + 543) }}
|
|
</template>
|
|
<template #trigger>
|
|
<q-input
|
|
outlined
|
|
dense
|
|
class="full-width datepicker"
|
|
:model-value="dateThaiRange(dateAdd)"
|
|
>
|
|
<template v-slot:prepend>
|
|
<q-icon
|
|
name="event"
|
|
class="cursor-pointer"
|
|
style="color: var(--q-primary)"
|
|
>
|
|
</q-icon>
|
|
</template>
|
|
</q-input>
|
|
</template>
|
|
</datepicker>
|
|
</div>
|
|
</div>
|
|
<div class="row col-12 q-col-gutter-sm">
|
|
<div class="col-2 subName">
|
|
<label>คำอธิบาย</label>
|
|
</div>
|
|
<div class="col-10">
|
|
<q-input
|
|
dense
|
|
borderless
|
|
class="full-width datepicker q-pb-none"
|
|
v-model="name"
|
|
type="textarea"
|
|
:rules="[(val) => (val && val.length > 0) || '']"
|
|
/>
|
|
</div>
|
|
</div>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-actions align="right" class="text-primary">
|
|
<q-btn
|
|
unelevated
|
|
label="บันทึก"
|
|
color="public"
|
|
type="submit"
|
|
|
|
> <!-- icon="mdi-content-save-outline"
|
|
<q-tooltip>บันทึก</q-tooltip> -->
|
|
</q-btn>
|
|
</q-card-actions>
|
|
</q-form>
|
|
</q-card>
|
|
</q-dialog>
|
|
|
|
<!-- modal ลบวันหยุด -->
|
|
<q-dialog v-model="modalDelete" persistent>
|
|
<q-card style="min-width: 550px">
|
|
<q-card-section class="row items-center q-pb-xs">
|
|
<div class="text-bold">ต้องการลบข้อมูลนี้หรือไม่?</div>
|
|
<q-space />
|
|
<q-btn
|
|
icon="close"
|
|
unelevated
|
|
round
|
|
dense
|
|
v-close-popup
|
|
style="color: #ff8080; background-color: #ffdede"
|
|
/>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-section class="row items-center">
|
|
<div class="q-pr-md">
|
|
<q-avatar
|
|
icon="mdi-trash-can-outline"
|
|
font-size="25px"
|
|
size="lg"
|
|
color="red-1"
|
|
text-color="red"
|
|
/>
|
|
</div>
|
|
<div class="col text-dark">
|
|
<span>ข้อมูลที่กำลังถูกลบนี้จะมีผลใช้งานทันที</span>
|
|
</div>
|
|
</q-card-section>
|
|
<q-separator />
|
|
<q-card-actions align="right" class="bg-white text-teal">
|
|
<q-btn label="ตกลง" color="primary" @click="deleteConfirm" />
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import type { QTableProps } from "quasar";
|
|
import { onMounted, ref, watch } from "vue";
|
|
import http from "@/plugins/http";
|
|
import config from "@/app.config";
|
|
import { useQuasar } from "quasar";
|
|
import { useCounterMixin } from "@/stores/mixin";
|
|
import type {
|
|
RequestItemsObject,
|
|
DataDateRowObject,
|
|
DataDateAddObject,
|
|
DataDateListsObject,
|
|
TabsObject,
|
|
} from "@/modules/01_metadata/interface/request/Calendar";
|
|
import { useDataStore } from "@/stores/data";
|
|
|
|
const props = defineProps({
|
|
dateYear: {
|
|
//filter ปี วันหยุด
|
|
type: Number,
|
|
required: true,
|
|
},
|
|
refreshData: {
|
|
//หน้า main มีการอัพเดทค่าให้ refresh data
|
|
type: Boolean,
|
|
required: true,
|
|
},
|
|
fetchDataSummaryCalendar: {
|
|
//ฟังก์ชันอัพเดทสรุปวันหยุด
|
|
type: Function,
|
|
default: () => console.log("not function"),
|
|
},
|
|
});
|
|
|
|
const store = useDataStore();
|
|
const { loaderPage } = store;
|
|
const mixin = useCounterMixin(); //เรียกฟังก์ชันกลาง
|
|
const {
|
|
success,
|
|
dateToISO,
|
|
dateMonth2Thai,
|
|
weekThai,
|
|
messageError,
|
|
showLoader,
|
|
hideLoader,
|
|
} = mixin;
|
|
const $q = useQuasar(); //ใช้ noti quasar
|
|
const calendarData = ref<DataDateListsObject[]>([]); //data วันหยุด
|
|
const modalAdd = ref<boolean>(false); //modal เพิ่มวันหยุด
|
|
const modalDelete = ref<boolean>(false); //modal ลบวันหยุด
|
|
const name = ref<string>(""); //ชื่อวันหยุด
|
|
const isSpecial = ref<boolean>(true); //เช็ควันหยุด
|
|
const dateAdd = ref<[Date, Date]>([new Date(), new Date()]); //วันที่ ที่เพิ่มเป็นวันหยุด
|
|
const rowData = ref<DataDateListsObject>(); //data ที่ถูกเลือกใน row นั้น
|
|
const formDate = ref<any>(); //ref เพิ่ม แก้ไข วันหยุดสำหรับ validate
|
|
|
|
const currentTab = ref<string>("normal"); //เลือก tab ประเภทวันหยุด
|
|
const tabs = ref<TabsObject[]>([
|
|
{ label: "ทำงานจันทร์-ศุกร์ (5 วัน)", value: "normal" },
|
|
{ label: "ทำงานจันทร์-เสาร์ (6 วัน)", value: "6day" },
|
|
]); //tab ประเภทวันหยุดทั้งหมด
|
|
|
|
//columns รายการวันหยุด
|
|
const columns = ref<any>([
|
|
{
|
|
name: "week",
|
|
align: "left",
|
|
label: "-",
|
|
sortable: true,
|
|
field: "week",
|
|
style: "font-size: 15px",
|
|
},
|
|
{
|
|
name: "holidayDate",
|
|
align: "left",
|
|
label: "-",
|
|
sortable: true,
|
|
field: "holidayDate",
|
|
style: "font-size: 15px",
|
|
},
|
|
{
|
|
name: "detail",
|
|
align: "left",
|
|
label: "-",
|
|
sortable: true,
|
|
field: "detail",
|
|
style: "font-size: 15px",
|
|
},
|
|
]);
|
|
|
|
/**
|
|
* เรียกฟังก์ชันทั้งหมดตอนเรียกใช้ไฟล์นี้
|
|
*/
|
|
onMounted(async () => {
|
|
await fetchData();
|
|
});
|
|
|
|
/**
|
|
* ค่า props(วันปีที่เลือก และเพิ่มหรือแก้ไข) ตอนอัพเดท ค่าฏิทินให้อัพเดทใหม่
|
|
*/
|
|
watch(props, async (count, prevCount) => {
|
|
await fetchData();
|
|
});
|
|
|
|
/**
|
|
* กดปุ่มแก้ไขวันหยุด
|
|
* @param val data วันหยุดทั้ง row
|
|
*/
|
|
const editCalendar = async (val: DataDateListsObject) => {
|
|
rowData.value = val;
|
|
dateAdd.value = [val.dateRange[0], val.dateRange[1]];
|
|
name.value = val.detail;
|
|
isSpecial.value = true;
|
|
modalAdd.value = true;
|
|
};
|
|
|
|
/**
|
|
* กดปุ่มลบวันหยุด
|
|
* @param val data วันหยุดทั้ง row
|
|
*/
|
|
const deleteClick = async (val: DataDateListsObject) => {
|
|
rowData.value = val;
|
|
modalDelete.value = true;
|
|
};
|
|
|
|
/**
|
|
* fetch วันหยุดในรายการ
|
|
*/
|
|
const fetchData = async () => {
|
|
calendarData.value = [];
|
|
showLoader();
|
|
await http
|
|
.get(config.API.listHolidayHistoryYear(props.dateYear))
|
|
.then((res) => {
|
|
let data = res.data.result.normal;
|
|
if (currentTab.value == "6day") {
|
|
data = res.data.result.sixDays;
|
|
}
|
|
const dateStart = ref<Date | null>();
|
|
const firstEvent = ref<boolean>(true);
|
|
const dateRow = ref<DataDateRowObject[]>([]);
|
|
data.map((e: RequestItemsObject, index: number) => {
|
|
dateRow.value.push({
|
|
holidayDate: new Date(e.holidayDate),
|
|
name: e.name,
|
|
isSpecial: true,
|
|
id: e.id,
|
|
});
|
|
if (
|
|
index == data.length - 1 ||
|
|
data[index + 1].name != e.name ||
|
|
(data[index + 1].name == e.name &&
|
|
dateToISO(new Date(data[index + 1].holidayDate)) !=
|
|
dateToISO(
|
|
new Date(
|
|
new Date(e.holidayDate).setDate(
|
|
new Date(e.holidayDate).getDate() + 1
|
|
)
|
|
)
|
|
))
|
|
) {
|
|
firstEvent.value = true;
|
|
calendarData.value.push({
|
|
id: e.id,
|
|
dateRange: [
|
|
dateStart.value ? dateStart.value : new Date(e.holidayDate),
|
|
new Date(e.holidayDate),
|
|
],
|
|
dataRangeRow: dateRow.value,
|
|
detail:
|
|
dateToISO(new Date(e.holidayDate)) ==
|
|
dateToISO(new Date(e.originalDate))
|
|
? e.name
|
|
: `ชดเชย ${e.name}`,
|
|
isSpecial: true,
|
|
});
|
|
dateStart.value = null;
|
|
dateRow.value = [];
|
|
} else if (firstEvent.value == true) {
|
|
firstEvent.value = false;
|
|
dateStart.value = new Date(e.holidayDate);
|
|
}
|
|
});
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
await props.fetchDataSummaryCalendar();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* ลบข้อมูลวันหยุด
|
|
*/
|
|
const deleteConfirm = async () => {
|
|
modalDelete.value = false;
|
|
const dataDelete = ref<DataDateAddObject[]>([]);
|
|
if (rowData.value != null) {
|
|
await rowData.value.dataRangeRow.map((e: DataDateRowObject) => {
|
|
dataDelete.value.push({
|
|
year: new Date(e.holidayDate).getFullYear(),
|
|
holidayDate: dateToISO(e.holidayDate),
|
|
name: e.name,
|
|
isSpecial: true,
|
|
});
|
|
});
|
|
} else {
|
|
return;
|
|
}
|
|
showLoader();
|
|
await http
|
|
.post(
|
|
config.API.listHolidayHistoryDelete(currentTab.value),
|
|
dataDelete.value
|
|
)
|
|
.then((res) => {
|
|
success($q, "ลบข้อมูลสำเร็จ");
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
await fetchData();
|
|
});
|
|
};
|
|
|
|
/**
|
|
* บันทึกแก้ไขวันหยุด
|
|
*/
|
|
const editData = async () => {
|
|
await formDate.value.validate().then(async (result: boolean) => {
|
|
if (result) {
|
|
const dataEdit = ref<DataDateAddObject[]>([]);
|
|
let i = 0;
|
|
const dateStart = ref<Date>(dateAdd.value[0]);
|
|
do {
|
|
i = i + 1;
|
|
dataEdit.value.push({
|
|
year: new Date(dateStart.value).getFullYear(),
|
|
holidayDate: dateToISO(new Date(dateStart.value)),
|
|
name: name.value,
|
|
isSpecial: true,
|
|
});
|
|
dateStart.value = new Date(
|
|
new Date(dateStart.value).setDate(
|
|
new Date(dateStart.value).getDate() + 1
|
|
)
|
|
);
|
|
} while (new Date(dateStart.value) <= new Date(dateAdd.value[1]));
|
|
const _dataHistory = ref<DataDateAddObject[]>([]);
|
|
if (rowData.value != null) {
|
|
rowData.value.dataRangeRow.map(
|
|
(e: DataDateRowObject, index: number) => {
|
|
_dataHistory.value.push({
|
|
year: new Date(e.holidayDate).getFullYear(),
|
|
holidayDate: dateToISO(e.holidayDate),
|
|
name: e.name,
|
|
isSpecial: true,
|
|
});
|
|
}
|
|
);
|
|
}
|
|
showLoader();
|
|
await http
|
|
.post(config.API.listHolidayHistoryEdit(currentTab.value), {
|
|
history: _dataHistory.value,
|
|
updated: dataEdit.value,
|
|
})
|
|
.then((res) => {
|
|
modalAdd.value = false;
|
|
success($q, "แก้ไขข้อมูลสำเร็จ");
|
|
})
|
|
.catch((e) => {
|
|
messageError($q, e);
|
|
})
|
|
.finally(async () => {
|
|
await fetchData();
|
|
});
|
|
} else {
|
|
}
|
|
});
|
|
};
|
|
|
|
/**
|
|
* เปลี่ยน tab ดูวันหยุดตามประเภท
|
|
* @param tab tab ประเภทวันหยุดที่เลือก
|
|
*/
|
|
const changeTab = async (tab: string) => {
|
|
currentTab.value = tab;
|
|
await fetchData();
|
|
};
|
|
|
|
/**
|
|
* แปลงช่วงวันที่ถ้า2ค่าเป็นวันเดียวกันจะโชววันเดียวแต่ถ้าไม่เท่ากันจะแสดงเป็นช่วง
|
|
* @param val ช่วงวันที่
|
|
*/
|
|
const dateThaiRange = (val: [Date, Date]) => {
|
|
if (val === null) {
|
|
return "";
|
|
} else if (dateMonth2Thai(val[0], true) === dateMonth2Thai(val[1], true)) {
|
|
return `${dateMonth2Thai(val[0], true)}`;
|
|
} else {
|
|
return `${dateMonth2Thai(val[0], true)} - ${dateMonth2Thai(val[1], true)}`;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* แปลงช่วงวันที่ถ้า2ค่าเป็นวันเดียวกันจะโชววันเดียวแต่ถ้าไม่เท่ากันจะแสดงเป็นช่วง(เช่นวันจันทร์ -วันศุกร์)
|
|
* @param val ช่วงวันที่
|
|
*/
|
|
const dayThaiRange = (val: [Date, Date]) => {
|
|
if (val === null) {
|
|
} else if (dateToISO(val[0]) == dateToISO(val[1])) {
|
|
return `${weekThai(new Date(val[0]).getDay())}`;
|
|
} else {
|
|
return `${weekThai(new Date(val[0]).getDay())} - ${weekThai(
|
|
new Date(val[1]).getDay()
|
|
)}`;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
.custom-header-table {
|
|
max-height: 64vh;
|
|
|
|
.q-table tr:nth-child(odd) td {
|
|
background: white;
|
|
}
|
|
|
|
.q-table tr:nth-child(even) td {
|
|
background: #f8f8f8;
|
|
}
|
|
|
|
.q-table thead tr {
|
|
background: #ecebeb;
|
|
}
|
|
|
|
.q-table thead tr th {
|
|
position: sticky;
|
|
z-index: 1;
|
|
}
|
|
|
|
/* this will be the loading indicator */
|
|
.q-table thead tr:last-child th {
|
|
/* height of all previous header rows */
|
|
top: 48px;
|
|
}
|
|
|
|
.q-table thead tr:first-child th {
|
|
top: 0;
|
|
}
|
|
}
|
|
|
|
.my-table-details {
|
|
white-space: -moz-pre-wrap !important;
|
|
/* Mozilla, since 1999 */
|
|
white-space: -webkit-pre-wrap;
|
|
/* Chrome & Safari */
|
|
white-space: -pre-wrap;
|
|
/* Opera 4-6 */
|
|
white-space: -o-pre-wrap;
|
|
/* Opera 7 */
|
|
white-space: pre-wrap;
|
|
/* CSS3 */
|
|
word-wrap: break-word;
|
|
/* Internet Explorer 5.5+ */
|
|
word-break: break-all;
|
|
white-space: normal;
|
|
}
|
|
|
|
.table_ellipsis {
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: wrap;
|
|
max-width: 250px;
|
|
}
|
|
</style>
|