เพิ่มลงเวลากรณีพิเศษ (USER) #32

This commit is contained in:
DESKTOP-1R2VSQH\Lenovo ThinkPad E490 2023-11-24 16:39:55 +07:00
parent 2dea65c4df
commit 0ec7e83d0d
8 changed files with 196 additions and 80 deletions

View file

@ -1,6 +1,8 @@
import env from './index' import env from './index'
const history = `${env.API_URI}/leave/check-in/history` const history = `${env.API_URI}/leave/check-in/history`
const TimeStamp = `${env.API_URI}/leave`
export default { export default {
history: () => `${history}`, history: () => `${history}`,
createTimeStamp: () => `${TimeStamp}/user/edit`,
} }

View file

@ -2,15 +2,19 @@
import { ref, watch, onMounted } from 'vue' import { ref, watch, onMounted } from 'vue'
import { useQuasar } from 'quasar' import { useQuasar } from 'quasar'
import moment from 'moment' import moment from 'moment'
import http from '@/plugins/http'
import config from '@/app.config'
import type { FormRef } from '@/interface/index/Main'
import type { FormTimeStemp } from '@/interface/response/checkin'
// importStores // importStores
import { useCounterMixin } from '@/stores/mixin' import { useCounterMixin } from '@/stores/mixin'
// importType // importType
import type { FormRef } from '@/interface/index/Main'
const $q = useQuasar() const $q = useQuasar()
const mixin = useCounterMixin() const mixin = useCounterMixin()
const { date2Thai, covertDateObject, dialogConfirm } = mixin const { date2Thai, success, dialogConfirm } = mixin
const props = defineProps({ const props = defineProps({
dataById: { dataById: {
@ -21,6 +25,10 @@ const props = defineProps({
type: Function, type: Function,
required: true, required: true,
}, },
fetcthDataTable: {
type: Function,
require: true,
},
}) })
const dataByIdVal = ref<any>([]) const dataByIdVal = ref<any>([])
@ -30,13 +38,6 @@ const checkboxOut = ref<boolean>(false)
const reason = ref<string>('') const reason = ref<string>('')
const statusAction = ref<boolean>(false) const statusAction = ref<boolean>(false)
onMounted(() => {
updateClock()
dataByIdVal.value = props.dataById
if (dataByIdVal.value == null) {
statusAction.value = true
}
})
const dateNow = ref<Date>(new Date()) const dateNow = ref<Date>(new Date())
const timeNoew = ref<string>('') const timeNoew = ref<string>('')
@ -55,7 +56,10 @@ const objectRef: FormRef = {
reason: reasonRef, reason: reasonRef,
} }
const checkstatusBox = ref<boolean>(false) const checkstatusBox = ref<boolean>(false)
/** function checkValidate*/
function onCkickSave() { function onCkickSave() {
props.fetcthDataTable?.()
const hasError = [] const hasError = []
for (const key in objectRef) { for (const key in objectRef) {
if (Object.prototype.hasOwnProperty.call(objectRef, key)) { if (Object.prototype.hasOwnProperty.call(objectRef, key)) {
@ -75,14 +79,50 @@ function onCkickSave() {
) )
) { ) {
dialogConfirm($q, async () => { dialogConfirm($q, async () => {
console.log('save') const data: FormTimeStemp = {
props.closePopup() checkDate: date.value,
checkInEdit: checkboxIn.value,
checkOutEdit: checkboxOut.value,
description: reason.value,
}
createListTime(data)
}) })
} else { } else {
console.log('ไม่ผ่าน ') console.log('ไม่ผ่าน ')
} }
} }
/**
* function เพมลงเวลากรณเศษ
* @param data body Request
*/
async function createListTime(data: FormTimeStemp) {
await http
.post(config.API.createTimeStamp(), data)
.then(() => {
success($q, 'บันทึกข้อมูลาำเร็จ')
})
.catch((err) => {
console.log(err)
})
.finally(() => {
props.fetcthDataTable?.()
props.closePopup?.()
})
}
/** Hook */
onMounted(() => {
updateClock()
dataByIdVal.value = props.dataById
if (dataByIdVal.value == null) {
statusAction.value = true
} else {
date.value = new Date(dataByIdVal.value.checkInDateTime)
}
})
watch( watch(
[() => checkboxIn.value, () => checkboxOut.value], [() => checkboxIn.value, () => checkboxOut.value],
([newCheckboxIn, newCheckboxOut]) => { ([newCheckboxIn, newCheckboxOut]) => {
@ -116,7 +156,7 @@ watch(
<q-card flat bordered class="col-12 q-mt-sm" v-if="statusAction"> <q-card flat bordered class="col-12 q-mt-sm" v-if="statusAction">
<div class="q-pa-sm"> <div class="q-pa-sm">
<VueDatePicker <datepicker
v-model="date" v-model="date"
:locale="'th'" :locale="'th'"
autoApply autoApply
@ -136,7 +176,7 @@ watch(
outlined outlined
dense dense
:model-value="date !== null ? date2Thai(date) : null" :model-value="date !== null ? date2Thai(date) : null"
:label="`${'กรอกวันที่'}`" :label="`${'วันที่ขอแก้ไข'}`"
:rules="[(val) => !!val || 'กรุณาเลือกวันที่']" :rules="[(val) => !!val || 'กรุณาเลือกวันที่']"
lazy-rules lazy-rules
hide-bottom-space hide-bottom-space
@ -150,7 +190,7 @@ watch(
</q-icon> </q-icon>
</template> </template>
</q-input> </template </q-input> </template
></VueDatePicker> ></datepicker>
</div> </div>
</q-card> </q-card>
@ -159,7 +199,7 @@ watch(
<div class="col-1"> <div class="col-1">
<q-icon color="grey-5" name="calendar_today" /> <q-icon color="grey-5" name="calendar_today" />
</div> </div>
<div class="col">{{ covertDateObject(dataByIdVal.date) }}</div> <div class="col">{{ dataByIdVal.checkInDate }}</div>
</div> </div>
</q-card> </q-card>
@ -199,7 +239,7 @@ watch(
> >
กรณาเลอก กรณาเลอก
</div> </div>
<q-card flat bordered class="q-pa-sm col-12 q-mt-sm"> <q-card flat bordered class="q-pa-sm col-12 q-mt-sm">
<q-input <q-input
ref="reasonRef" ref="reasonRef"

View file

@ -1,5 +1,6 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref, watch } from 'vue' import { ref, watch } from 'vue'
import HeaderPopup from '@/components/HeaderPopup.vue' import HeaderPopup from '@/components/HeaderPopup.vue'
import FormTime from '@/components/FormTime.vue' import FormTime from '@/components/FormTime.vue'
@ -20,24 +21,33 @@ const props = defineProps({
type: Object, type: Object,
default: null, default: null,
}, },
fetcthDataTable: {
type: Function,
require: true,
},
}) })
// -
const data = ref<any>() const data = ref<any>()
function clickClosePopup() { function clickClosePopup() {
props.clickClose() props.clickClose()
} }
watch(props, () => {
if (props.modal === true) { watch(
data.value = props.dataById () => props.modal,
() => {
data.value = props.modal ? props.dataById : null
} }
}) )
</script> </script>
<template> <template>
<q-dialog v-model="props.modal"> <q-dialog v-model="props.modal">
<q-card class="column" style="width: 300px; min-height: 600px;"> <q-card class="column" style="width: 300px; min-height: 600px">
<HeaderPopup :title="props.title" :clickClose="clickClosePopup" /> <HeaderPopup :title="props.title" :clickClose="clickClosePopup" />
<FormTime :dataById="data" :closePopup="clickClosePopup" /> <FormTime
:dataById="data"
:closePopup="clickClosePopup"
:fetcthDataTable="props.fetcthDataTable"
/>
</q-card> </q-card>
</q-dialog> </q-dialog>
</template> </template>

View file

@ -1,16 +1,24 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue' import { ref } from 'vue'
// import type { DataOption } from '@/interface/index/Main'
import Popup from '@/components/PopUp.vue' import Popup from '@/components/PopUp.vue'
// import HeaderPopup from "@/components/HeaderPopup.vue"; // import HeaderPopup from "@/components/HeaderPopup.vue";
// import FormTime from "@/components/FormTime.vue"; // import FormTime from "@/components/FormTime.vue";
const props = defineProps({
fetchData: {
type: Function,
require: true,
},
})
const emit = defineEmits(['update:year'])
const filterYear = ref<number>(new Date().getFullYear()) const filterYear = ref<number>(new Date().getFullYear())
// const yearOption = ref<DataOption[]>([{ id: '2566', name: '2566' }]) // const yearOption = ref<DataOption[]>([{ id: '2566', name: '2566' }])
const titleName = ref<string>('เพิ่มรายการลงเวลากรณีพิเศษ') const titleName = ref<string>('เพิ่มรายการลงเวลากรณีพิเศษ')
function filterYearFn() { function filterYearFn() {
console.log('test') emit('update:year', filterYear.value)
} }
const modalPopup = ref<boolean>(false) const modalPopup = ref<boolean>(false)
@ -57,16 +65,7 @@ function onClickClose() {
</q-input> </q-input>
</template> </template>
</datepicker> </datepicker>
<!-- <q-select
dense
outlined
style="width: 180px"
label="ปีงบประมาณ"
v-model="filterYear"
:options="yearOption"
option-label="name"
option-value="id"
/> -->
<q-space /> <q-space />
<q-btn <q-btn
unelevated unelevated
@ -80,7 +79,12 @@ function onClickClose() {
</div> </div>
</div> </div>
<Popup :modal="modalPopup" :title="titleName" :clickClose="onClickClose" /> <Popup
:modal="modalPopup"
:title="titleName"
:clickClose="onClickClose"
:fetcthDataTable="props.fetchData"
/>
</template> </template>
<style scoped></style> <style scoped></style>

View file

@ -6,11 +6,31 @@ interface FormRef {
interface FormData { interface FormData {
checkInId: string checkInId: string
checkInDate: string | null checkInDate: Date | null
checkInDateTime: Date
checkInTime: string checkInTime: string
checkOutTime: string checkOutTime: string
checkInStatus: string checkInStatus: string
checkOutStatus: string checkOutStatus: string
checkInLocation: string checkInLocation: string
checkOutLocation: string
} }
export type { FormRef, FormData } interface Datalist {
checkInId: string
checkInDate: string | null
checkInDateTime: Date | null
checkInTime: string
checkOutTime: string
checkInStatus: string
checkOutStatus: string
checkInLocation: string
checkOutLocation: string
}
interface FormTimeStemp {
checkDate: Date | null
checkInEdit: boolean
checkOutEdit: boolean
description: string
}
export type { FormRef, FormData, Datalist, FormTimeStemp }

View file

@ -1,7 +1,7 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import http from '@/plugins/http'
import config from '@/app.config' import type { FormData, Datalist } from '@/interface/response/checkin'
// importStores // importStores
import { useCounterMixin } from '@/stores/mixin' import { useCounterMixin } from '@/stores/mixin'
@ -10,14 +10,14 @@ const mixin = useCounterMixin()
const { date2Thai } = mixin const { date2Thai } = mixin
export const useChekIn = defineStore('checkin', () => { export const useChekIn = defineStore('checkin', () => {
const rows = ref<any>() const rows = ref<Datalist[]>()
async function fetchHistoryList(data: FormData) { async function fetchHistoryList(data: FormData[]) {
// console.log(data)
rows.value = [] rows.value = []
const datalist = await data.map((e: any) => ({ const datalist: Datalist[] = await data.map((e: FormData) => ({
checkInId: e.checkInId, checkInId: e.checkInId,
checkInDate: date2Thai(e.checkInDate), checkInDate: e.checkInDate ? date2Thai(e.checkInDate) : null,
checkInDateTime: e.checkInDate,
checkInTime: e.checkInTime, checkInTime: e.checkInTime,
checkOutTime: e.checkOutTime != '' ? e.checkOutTime : '-', checkOutTime: e.checkOutTime != '' ? e.checkOutTime : '-',
checkInStatus: convertStatus(e.checkInStatus), checkInStatus: convertStatus(e.checkInStatus),
@ -42,31 +42,31 @@ export const useChekIn = defineStore('checkin', () => {
return '' return ''
} }
} }
function convertStatusEdit(val: string) { // function convertStatusEdit(val: string) {
switch (val) { // switch (val) {
case 'edit': // case 'edit':
return 'ขอแก้ไข' // return 'ขอแก้ไข'
case 'wait': // case 'wait':
return 'รออนุมัติ' // return 'รออนุมัติ'
case 'approve': // case 'approve':
return 'อนุมัติ' // return 'อนุมัติ'
} // }
} // }
function classColorStatus(val: string) { // function classColorStatus(val: string) {
switch (val) { // switch (val) {
case 'wait': // case 'wait':
return 'orange' // return 'orange'
case 'approve': // case 'approve':
return 'green' // return 'green'
case 'reject': // case 'reject':
return 'red' // return 'red'
} // }
} // }
return { return {
rows, rows,
fetchHistoryList, fetchHistoryList,
classColorStatus, // classColorStatus,
// fetchlistHistory, // fetchlistHistory,
} }
}) })

View file

@ -208,6 +208,36 @@ export const useCounterMixin = defineStore('mixin', () => {
} }
} }
const success = (q: any, val: string) => {
// useQuasar ไม่สามารถใช้นอกไฟล์ .vue
if (val !== '') {
return q.notify({
message: val,
color: 'primary',
icon: 'mdi-information',
position: 'bottom-right',
multiLine: true,
timeout: 1000,
badgeColor: 'positive',
classes: 'my-notif-class',
})
}
}
function notify(q: any, val: string) {
if (val !== '') {
q.notify({
color: 'teal-10',
message: val,
icon: 'mdi-information',
position: 'bottom-right',
multiLine: true,
timeout: 7000,
actions: [{ label: 'ปิด', color: 'white', handler: () => {} }],
})
}
}
return { return {
date2Thai, date2Thai,
showLoader, showLoader,
@ -215,5 +245,7 @@ export const useCounterMixin = defineStore('mixin', () => {
covertDateObject, covertDateObject,
dialogConfirm, dialogConfirm,
messageError, messageError,
success,
notify,
} }
}) })

View file

@ -17,14 +17,10 @@ const { showLoader, hideLoader, messageError } = mixin
const { fetchHistoryList } = stores const { fetchHistoryList } = stores
const $q = useQuasar() // noti quasar const $q = useQuasar() // noti quasar
onMounted(() => {
fetchlistHistory()
})
// paging // paging
const page = ref<number>(1) const page = ref<number>(1)
const year = ref<number>(2023) const year = ref<number>(new Date().getFullYear())
const pageSize = ref<number>(2) const pageSize = ref<number>(10)
const total = ref<number>(0) const total = ref<number>(0)
const maxPage = ref<number>(1) const maxPage = ref<number>(1)
const filter = ref<string>('') //search data table const filter = ref<string>('') //search data table
@ -47,22 +43,20 @@ async function changePage(
/** /**
* งกนดงขอมลรายการประวการลงเวลาจาก api มาแสดง * งกนดงขอมลรายการประวการลงเวลาจาก api มาแสดง
* @param loading แสดง loading ไหม true อแสดง, false อไมแสดง * @param loading แสดง loading ไหม true อแสดง, false อไมแสดง
*/ */
const fetchlistHistory = async (loading = true) => { async function fetchlistHistory(loading = true) {
loading === true ?? showLoader() loading === true && showLoader()
await http await http
.get( .get(
config.API.history() + config.API.history() +
`?year=${year.value}&page=${page.value}&pageSize=${pageSize.value}&keyword=${filter.value}` `?year=${year.value}&page=${page.value}&pageSize=${pageSize.value}&keyword=${filter.value}`
) )
.then(async (res) => { .then(async (res) => {
const data = res.data.result const data = res.data.result.data
total.value = data.total ? data.total : 5 total.value = res.data.result.total
maxPage.value = await Math.ceil(total.value / pageSize.value) maxPage.value = await Math.ceil(total.value / pageSize.value)
maxPage.value = maxPage.value < 1 ? 1 : maxPage.value
fetchHistoryList(data) // total fetchHistoryList(data) // total
// fetchHistoryList(data.data) // total
}) })
.catch((err) => { .catch((err) => {
messageError($q, err) messageError($q, err)
@ -71,6 +65,20 @@ const fetchlistHistory = async (loading = true) => {
hideLoader() hideLoader()
}) })
} }
/**
* function updateYear
* @param y ปเดท
*/
async function updateYear(y: number) {
year.value = y
y && fetchlistHistory(true)
}
/** Hook*/
onMounted(() => {
fetchlistHistory()
})
</script> </script>
<template> <template>
<div class="col-12 row justify-center"> <div class="col-12 row justify-center">
@ -96,7 +104,7 @@ const fetchlistHistory = async (loading = true) => {
<div class="col-2"></div> <div class="col-2"></div>
</div> </div>
<div class="col-12 q-pa-md text-grey-9"> <div class="col-12 q-pa-md text-grey-9">
<ToolBar /> <ToolBar :fetchData="fetchlistHistory" @update:year="updateYear" />
<Table <Table
:page-size="pageSize" :page-size="pageSize"
:total="total" :total="total"