hrms-checkin/src/views/HomeView.vue
2023-11-14 17:47:43 +07:00

434 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useQuasar } from 'quasar'
import moment from 'moment'
import Camera from 'simple-vue-camera'
// import Type
import type { FormRef } from '@/interface/response/checkin'
// import components
import MapCheck from '@/components/MapCheckin.vue'
// import Stores
import { useCounterMixin } from '@/stores/mixin'
const mixin = useCounterMixin()
const { date2Thai, dialogConfirm } = mixin
const router = useRouter()
const $q = useQuasar()
const stetusCheckin = ref(true)
onMounted(() => {
updateClock()
})
//time
const dateNow = ref<Date>(new Date())
const Thai = ref<Date>(dateNow.value)
const formattedS = ref()
const formattedM = ref()
const formattedH = ref()
function updateClock() {
const date = Date.now()
const hh = moment(date).format('HH')
const mm = moment(date).format('mm')
const ss = moment(date).format('ss')
formattedS.value = ss
formattedM.value = mm
formattedH.value = hh
}
setInterval(updateClock, 1000)
//location
const location = ref<string>('')
const coordinates = ref<string>('13° 43 45” N 100° 31 26” E')
const workplace = ref<string>('in-place')
const useLocation = ref<string | null>('')
const model = ref<string | null>('')
const options = ref<string[]>([
'ปฏิบัติงานที่บ้าน',
'ลืมลงเวลาปฏิบัติงาน',
'ไปประชุม/อบรม/สัมมนา/ปฏิบัติงานที่บ้านนอกสถานที่',
'ขออนุญาตออกนอกสถานที่',
'อื่นๆ',
])
function selectLocation() {
if (model.value === 'อื่นๆ') {
useLocation.value = ''
} else {
useLocation.value = model.value
}
}
//camera
const camera = ref<InstanceType<typeof Camera>>()
const cameraIsOn = ref<boolean>(false)
const img = ref<any>(undefined)
const photoWidth = ref<number>(350)
const photoHeight = ref<number>(350)
const openCamera = () => {
cameraIsOn.value ? camera.value?.stop() : camera.value?.start()
cameraIsOn.value = !cameraIsOn.value
}
async function capturePhoto() {
const imageBlob: any = await camera.value?.snapshot(
{ width: photoWidth.value, height: photoHeight.value },
'image/png',
0.5
)
//ไฟล์รูป
camera.value?.stop()
const url = URL.createObjectURL(imageBlob)
img.value = url
}
function refreshPhoto() {
img.value = undefined
camera.value?.start()
}
// validate
const useLocationRef = ref<object | null>(null)
const modelRef = ref<object | null>(null)
const objectRef: FormRef = {
model: modelRef,
useLocation: useLocationRef,
}
function validateForm() {
const hasError = []
for (const key in objectRef) {
if (Object.prototype.hasOwnProperty.call(objectRef, key)) {
const property = objectRef[key]
if (property.value && typeof property.value.validate === 'function') {
const isValid = property.value.validate()
hasError.push(isValid)
}
}
}
if (hasError.every((result) => result === true)) {
confirm()
} else {
console.log('ไม่ผ่าน ')
}
}
// ยืนยันการลงเวลา
const dialogTime = ref<boolean>(false)
const confirm = () => {
// ยิงไปที่ api แล้วแสดง popup
dialogTime.value = true
}
// class
const getClass = (val: boolean) => {
return {
'bg-primary text-white col-12 row items-center q-px-md q-py-sm': val,
'bg-red-9 text-white col-12 row items-center q-px-md q-py-sm': !val,
}
}
</script>
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-12">
<q-card flat class="row col-12 cardNone">
<div :class="getClass(stetusCheckin)">
<div class="col-2">
<!-- <q-btn
icon="mdi-arrow-left"
unelevated
round
dense
flat
color="white"
@click="router.go(-1)"
/> -->
</div>
<span class="text-body1 text-weight-bold col-8 text-center">
<span v-if="stetusCheckin">ลงเวลาเข้างาน</span>
<span v-else>ลงเวลาออกงาน</span>
</span>
<div class="col-2 text-right">
<q-btn
icon="history"
unelevated
rounded
dense
flat
color="white"
:label="$q.screen.gt.xs ? 'ประวัติการลงเวลา' : ''"
:class="$q.screen.gt.xs ? 'q-px-md' : ''"
@click="router.push('/history')"
/>
</div>
</div>
<div class="col-12 q-pa-md text-grey-9">
<div class="col-12 row justify-center">
<div class="col-12 row q-py-sm justify-center">
<div
class="col-xs-12 col-sm-10 text-h6 text-center text-weight-bold"
>
{{ date2Thai(Thai) }}
</div>
<div class="row col-12 justify-center q-py-sm">
<div class="colunm">
<div class="text-h3 text-weight-bold">
{{ formattedH }}<span class="q-ma-md">:</span>
</div>
</div>
<div class="colunm">
<div class="text-h3 text-weight-bold">
{{ formattedM }}<span class="q-ma-md">:</span>
</div>
</div>
<div class="colunm">
<div class="text-h3 text-weight-bold">{{ formattedS }}</div>
</div>
</div>
</div>
<div class="col-xs-12 col-md-11 row q-col-gutter-md">
<div class="col-12 col-sm-8">
<MapCheck />
</div>
<div class="col-12 col-sm-4">
<q-card flat bordered class="card-container">
<div
v-if="!cameraIsOn && img == null"
class="preview-placeholder"
@click="openCamera()"
>
<div class="text-center">
<q-icon
name="photo_camera"
color="blue-grey-3"
size="100px"
class="center-icon"
/>
</div>
</div>
<div>
<!-- แสดงกลองตอนกดถายภาพ -->
<Camera
:resolution="{ width: photoWidth, height: photoHeight }"
ref="camera"
:autoplay="false"
:style="!img ? 'display: block' : 'display: none'"
/>
<!-- แสดงรปเมอกด capture -->
<div v-if="img" class="image-container">
<q-img :src="img" class="image-element"></q-img>
</div>
<div
v-if="cameraIsOn"
class="absolute-bottom-right q-ma-md"
>
<q-btn
v-if="img == null"
round
push
icon="photo_camera"
size="md"
color="positive"
@click="capturePhoto"
/>
<q-btn
v-else
round
push
icon="refresh"
size="md"
color="negative"
@click="refreshPhoto"
/>
</div>
</div>
</q-card>
</div>
<div class="col-12 q-mb-md">
<q-card
bordered
flat
:class="
$q.screen.gt.xs
? 'q-px-md q-py-sm row items-center shadow-0'
: 'q-pa-md row items-center shadow-0'
"
>
<div class="text-weight-bold">สถานททำงาน</div>
<div
:class="
$q.screen.gt.xs
? 'row q-gutter-md q-pl-md col-sm-6 col-md-3'
: 'column col-12'
"
>
<q-radio
v-model="workplace"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="in-place"
label="ในสถานที่"
/>
<q-radio
v-model="workplace"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="off-site"
label="นอกสถานที่"
/>
</div>
<div
class="col-xs-12 col-sm-6 col-md-4"
v-if="workplace == 'off-site'"
>
<q-select
ref="modelRef"
dense
class="q-ml-md"
outlined
v-model="model"
:options="options"
prefix="ระบุสถานที่ :"
:rules="[(val) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
@update:model-value="selectLocation()"
/>
</div>
<div
class="col-xs-12 col-sm-6 col-md-4"
v-if="model == 'อื่นๆ' && workplace === 'off-site'"
>
<q-input
ref="useLocationRef"
dense
class="q-ml-md"
outlined
v-model="useLocation"
label="ระบุสถานที่"
:rules="[(val) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
/>
</div>
</q-card>
<div class="col-12 text-right">
<q-separator />
<div class="col-12 q-pa-md">
<p
:class="
$q.screen.gt.xs
? 'text-red text-caption '
: 'text-red text-caption text-center'
"
>
*หมายเหต คลกลงเวลาเขางานแลวระบบจะลงเวลาทนท
</p>
<q-btn
:label="
stetusCheckin == true ? 'ลงเวลาเข้างาน' : 'ลงเวลาออกงาน'
"
:color="
stetusCheckin == true && img == null
? 'grey-6'
: 'primary'
"
push
size="14px"
:class="$q.screen.gt.xs ? 'q-px-md' : 'full-width'"
:disable="camera && img ? false : true"
@click="validateForm"
/>
</div>
</div>
</div>
</div>
</div>
</div>
</q-card>
</div>
</div>
<q-dialog v-model="dialogTime">
<q-card class="full-width cardNone">
<div :class="getClass(stetusCheckin)">
<div class="text-body1 text-center col-12 text-weight-bold">
<span v-if="stetusCheckin">ลงเวลาเข้างานของคุณ</span>
<span v-else>ลงเวลาออกงานของคุณ</span>
</div>
</div>
<q-card-section class="row col-12 justify-center">
<div class="bg-grey-2 rounded-borders q-pa-md col-11">
<div class="col-12 text-subtitle1 text-center text-weight-medium">
{{ date2Thai(Thai) }}
</div>
<div class="row col-12 justify-center q-pt-sm">
<div class="text-h3 text-weight-bold">
{{ formattedH }}<span class="q-ma-md">:</span>
</div>
<div class="text-h3 text-weight-bold">{{ formattedM }}</div>
</div>
</div>
<div class="col-12 text-center row q-pt-md">
<div class="col-12 text-subtitle1 text-weight-medium text-secondary">
{{ location }}
</div>
<div class="col-12 text-grey-7">{{ coordinates }}</div>
</div>
</q-card-section>
<q-card-actions align="center" class="q-mb-md row">
<q-btn
class="col-xs-11 col-sm-6"
push
label="ตกลง"
color="secondary"
v-close-popup
/>
</q-card-actions>
</q-card>
</q-dialog>
</template>
<style scoped>
.q-card.cardImg:hover {
border: 1px solid #02a998 !important;
}
.center-icon {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
.card-container {
position: relative;
overflow: hidden;
height: 350px; /* Adjust as needed */
background: #f6f5f5;
}
.image-container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.image-element {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 5px; /* Adjust as needed */
}
.preview-placeholder {
width: 100%;
height: 100%;
}
</style>