ปรับหน้า ui เช็คอิน ในส่วนของมือถือ

This commit is contained in:
Tanyalak 2025-03-14 17:37:11 +07:00
parent 90cc20554b
commit feb78d06ce
5 changed files with 482 additions and 247 deletions

View file

@ -1,3 +1,2 @@
VITE_API_URI_CONFIG=VITE_API_URI_CONFIG
VITE_URL_SSO=VITE_URL_SSO
VITE_URL_LANDING=VITE_URL_LANDING
VITE_API_URI_CONFIG: "https://bma-ehr.frappet.synology.me/api/v1"
VITE_URL_SSO: "https://bma-sso.frappet.synology.me"

View file

@ -198,23 +198,52 @@ onMounted(async () => {
<template>
<!-- Loading skeleton -->
<div v-if="!poiPlaceName" class="col-12">
<q-skeleton height="35vh" width="100%" class="bg-grey-4" />
<div v-if="!poiPlaceName" class="col-12 ">
<q-skeleton :height="$q.screen.gt.xs? '35vh': '45px'" width="100%" :style="$q.screen.gt.xs? ';':'border-radius: 20px'" class="bg-grey-4" />
</div>
<q-card v-show="poiPlaceName" bordered flat class="col-12 bg-grey-2 shadow-0">
<div id="mapViewDisplay" style="height: 35vh"></div>
<q-card v-show="poiPlaceName" bordered flat class="col-12 bg-grey-2 shadow-0" :style="$q.screen.gt.xs? ';':'border-radius: 20px'" >
<div v-if="$q.screen.gt.xs" >
<div id="mapViewDisplay" style="height: 35vh;"></div>
<div
:class="
$q.screen.gt.xs
? 'q-pa-xs text-weight-medium text-grey-8'
: 'q-pa-xs text-weight-medium text-grey-8'
"
>
นทใกลเคยง
<span class="q-px-sm">:</span>
{{ poiPlaceName }}
<div
:class="
$q.screen.gt.xs
? 'q-pa-xs text-weight-medium text-grey-8'
: 'q-pa-xs text-weight-medium text-grey-8'
"
>
นทใกลเคยง
<span class="q-px-sm">:</span>
{{ poiPlaceName }}
</div>
</div>
<q-card v-else style="border-radius: 20px;">
<q-expansion-item
class="shadow-1 overflow-hidden bg-grey-4 text-left"
style="border-radius: 20px"
dense
>
<template v-slot:header>
<q-item-section avatar class="q-pr-none expanAS">
<q-avatar icon="mdi-map-marker" />
</q-item-section>
<q-item-section>
{{ poiPlaceName }}
</q-item-section>
</template>
<div id="mapViewDisplay" style="height: 20vh;"></div>
</q-expansion-item>
</q-card>
</q-card>
</template>
<style >
.expanAS.q-item__section--avatar{
min-width: 40px !important;
}
</style>

View file

@ -13,7 +13,7 @@ const router = createRouter({
routes: [
{
path: '/',
name: 'home',
name: 'main',
component: MainView,
children: [
{

View file

@ -50,6 +50,8 @@ const Thai = ref<Date>(dateNow.value)
const formattedS = ref()
const formattedM = ref()
const formattedH = ref()
const formattedHH = ref()
const formattedA = ref()
/** function อัพเดทเวลา*/
function updateClock() {
@ -57,9 +59,14 @@ function updateClock() {
const hh = moment(date).format('HH')
const mm = moment(date).format('mm')
const ss = moment(date).format('ss')
const HH = moment(date).format('hh');
const A = moment(date).format('a');
formattedS.value = ss
formattedM.value = mm
formattedH.value = hh
formattedHH.value = HH
formattedA.value = A
}
setInterval(updateClock, 1000)
@ -254,11 +261,17 @@ function updateWorkplace() {
*/
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,
'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,
}
}
const getClassXS = (val: boolean) => {
return {
'bg-topIn text-white q-pa-lg col-12 row': val,
'bg-topOut text-white q-pa-lg col-12 row': !val,
}
}
const inQueue = ref<boolean>(false)
async function fetchCheckStatus() {
@ -312,252 +325,423 @@ onMounted(async () => {
</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">
<!-- <q-header elevated class="bg-purple"> -->
<q-toolbar :class="getClass(stetusCheckin)">
<div class="row col-12 justify-center">
<!-- <strong v-if="stetusCheckin" style="font-size: 1rem">
ลงเวลาเขางาน
</strong> -->
<!-- <strong v-else style="font-size: 1rem">ลงเวลาออกงาน</strong> -->
<strong v-if="!stetusCheckin && inQueue" style="font-size: 1rem">
<q-page :style="$q.screen.xs ? 'padding-top: 90px':''">
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-12">
<q-card flat :class="$q.screen.gt.xs ? 'row col-12 cardNone': 'row col-12 bg-grey-2'">
<!-- <q-header elevated class="bg-purple"> -->
<div :class="getClass(stetusCheckin)" class="gt-xs">
<div class="col">
<div class="row col-12 justify-center q-py-sm text-subtitle1">
<!-- <strong v-if="stetusCheckin" style="font-size: 1rem">
ลงเวลาเขางาน
</strong> -->
<!-- <strong v-else style="font-size: 1rem">ลงเวลาออกงาน</strong> -->
<strong v-if="!stetusCheckin && inQueue" >
ลงเวลาออกงาน (ระบบกำลงประมวลผล)
</strong>
<strong
v-else-if="stetusCheckin && inQueue"
>
ลงเวลาเขางาน (ระบบกำลงประมวลผล)
</strong>
<strong
v-else-if="stetusCheckin && !inQueue"
>
ลงเวลาเขางาน
</strong>
<strong v-else > ลงเวลาออกงาน </strong>
</div>
</div>
</div>
<div class="col-12 text-grey-9">
<div class="col-12 row justify-center">
<div class="col-12 row q-pt-md justify-center gt-xs">
<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 q-pa-md q-col-gutter-md row q-pt-lg">
<div class="col-12" v-if="$q.screen.xs">
<MapCheck @update:location="updateLocation" />
</div>
<div class="col-xs-12 col-sm-8 gt-xs">
<div class="col-12">
<MapCheck @update:location="updateLocation" />
</div>
<!-- <AscMaps /> -->
</div>
<div class="col-xs-12 col-sm-4">
<q-card :class="$q.screen.xs? 'card-container-xs':'card-container'">
<div
v-if="!cameraIsOn && img == null"
class="preview-placeholder"
@click="() => !isDisabledCheckTime && openCamera()"
>
<div class="text-center">
<q-icon
name="mdi-camera"
color="blue-grey-3"
size="100px"
class="center-icon"
/>
</div>
</div>
<div class="col-12 row items-center">
<!-- แสดงกลองตอนกดถายภาพ -->
<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"
>
<div v-if="$q.screen.gt.xs" 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 v-else>
<div class="absolute-bottom text-subtitle2 text-center q-py-sm" style="background:#00000021">
<q-btn
round
v-if="img == null"
icon="photo_camera"
size="18px"
style="background: #263238; color: white;"
@click="capturePhoto"
unelevated
/>
<q-btn
v-else
round
icon="refresh"
size="18px"
style="background: #263238; color: white;"
@click="refreshPhoto"
/>
</div>
</div>
</div>
</div>
</q-card>
</div>
<!-- กรอกขอม หนามอถ -->
<div class="col-12 row q-col-gutter-y-md" v-if="$q.screen.xs">
<div class="col-12" v-if="!isDisabledCheckTime">
<q-card flat bordered class="row col-12" style="border-radius: 10px">
<q-input
v-model="remark"
filled
type="textarea"
label="กรอกหมายเหตุ"
input-style="border-radius: 10px 10px 0 0;"
class="col-12"
bg-color="white"
/>
<div class="col-12"><q-separator /></div>
<q-btn-toggle
v-model="workplace"
@update:model-value="updateWorkplace"
spread
no-caps
toggle-color="blue-grey-10"
color="white"
text-color="black"
class="col-12"
style="min-height:3em"
size="15px"
:options="[
{label: 'ในสถานที่', value: 'in-place'},
{label: 'นอกสถานที่', value: 'off-site'}
]"
/>
</q-card>
</div>
<div class="col-12" v-if="workplace == 'off-site'">
<q-card class="col-12">
<q-select
ref="modelRef"
filled
v-model="model"
:options="options"
label="เลือกสถานที่"
bg-color="white"
:rules="[(val:string) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
@update:model-value="selectLocation()"
hide-bottom-space
/>
</q-card>
</div>
<div
class="col-12"
v-if="model == 'อื่นๆ' && workplace === 'off-site'"
>
<q-card class="col-12">
<q-input
ref="useLocationRef"
filled
v-model="useLocation"
label="ระบุสถานที่"
bg-color="white"
:rules="[(val:string) => !!val || 'กรุณาระบุสถานที่']"
hide-bottom-space
lazy-rules
/>
</q-card>
</div>
</div>
<!-- กรอกขอม หนามอถ -->
<div
v-if="!isDisabledCheckTime"
class="col-xs-12 col-sm-12 items-center gt-xs"
>
<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="ในสถานที่"
@update:model-value="updateWorkplace"
/>
<q-radio
v-model="workplace"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="off-site"
label="นอกสถานที่"
@update:model-value="updateWorkplace"
/>
</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:string) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
@update:model-value="selectLocation()"
hide-bottom-space
/>
</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:string) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
/>
</div>
</q-card>
</div>
<div v-if="!isDisabledCheckTime" class="col-xs-12 col-sm-12 gt-xs">
<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="col-12 q-pt-sm">
<q-input outlined v-model="remark" lazy-rules dense />
</div>
</q-card>
</div>
</div>
</div>
<div v-if="!isDisabledCheckTime && $q.screen.gt.xs" 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 ? 'ลงเวลาเข้างาน' : 'ลงเวลาออกงาน'"
:color="img == null ? 'grey-6' : 'primary'"
push
size="18px"
:class="$q.screen.gt.xs ? 'q-px-md' : 'full-width q-pa-sm'"
:disable="camera && img ? false : true"
@click="validateForm"
:loading="inQueue"
/>
</div>
</div>
<div v-if="isDisabledCheckTime && $q.screen.gt.xs" class="col-12">
<q-separator />
<div class="text-red q-pa-md">*{{ msgCheckTime }}</div>
</div>
</div>
</q-card>
</div>
</div>
</q-page>
<!-- top page sticky หนามอถ-->
<q-page-sticky expand position="top" v-if="$q.screen.xs">
<div :class="getClassXS(stetusCheckin)" >
<div class="col">
<div class="row col-12 justify-right items-center text-body1">
<strong v-if="!stetusCheckin && inQueue" >
ลงเวลาออกงาน (ระบบกำลงประมวลผล)
</strong>
<strong
v-else-if="stetusCheckin && inQueue"
style="font-size: 1rem"
>
ลงเวลาเขางาน (ระบบกำลงประมวลผล)
</strong>
<strong
v-else-if="stetusCheckin && !inQueue"
style="font-size: 1rem"
>
ลงเวลาเขางาน
</strong>
<strong v-else style="font-size: 1rem"> ลงเวลาออกงาน </strong>
<strong v-else > ลงเวลาออกงาน </strong>
</div>
<div class="text-white text-body2 row col-12" style="line-height:1.5rem">
{{ date2Thai(Thai) }}
</div>
</q-toolbar>
<div class="col-12 text-grey-9">
<div class="col-12 row justify-center">
<div class="col-12 row q-pt-md justify-center">
<div
class="col-xs-12 col-sm-10 text-h6 text-center text-weight-bold"
>
{{ date2Thai(Thai) }}
</div>
<div class="col-6 row items-center" >
<div class="row col-12 justify-end">
<div class="colunm">
<div class="text-h4 text-weight-bold">
{{ formattedHH }}<span class="q-ma-xs">:</span>
</div>
</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 class="colunm">
<div class="text-h4 text-weight-bold">
{{ formattedM }}
</div>
</div>
<div class="colunm">
<div class="text-caption q-pl-sm">{{ formattedA }}</div>
</div>
</div>
<div class="col-xs-12 col-md-11 q-pa-md q-col-gutter-md row">
<div class="col-xs-12 col-sm-8">
<div class="col-12">
<MapCheck @update:location="updateLocation" />
</div>
<!-- <AscMaps /> -->
</div>
<div class="col-xs-12 col-sm-4">
<q-card flat bordered class="card-container">
<div
v-if="!cameraIsOn && img == null"
class="preview-placeholder"
@click="() => !isDisabledCheckTime && openCamera()"
>
<div class="text-center">
<q-icon
name="photo_camera"
color="blue-grey-3"
size="100px"
class="center-icon"
/>
</div>
</div>
<div class="col-12 row items-center">
<!-- แสดงกลองตอนกดถายภาพ -->
<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
v-if="!isDisabledCheckTime"
class="col-xs-12 col-sm-12 items-center"
>
<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="ในสถานที่"
@update:model-value="updateWorkplace"
/>
<q-radio
v-model="workplace"
checked-icon="task_alt"
unchecked-icon="panorama_fish_eye"
val="off-site"
label="นอกสถานที่"
@update:model-value="updateWorkplace"
/>
</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:string) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
@update:model-value="selectLocation()"
hide-bottom-space
/>
</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:string) => !!val || 'กรุณาระบุสถานที่']"
lazy-rules
/>
</div>
</q-card>
</div>
<div v-if="!isDisabledCheckTime" class="col-xs-12 col-sm-12">
<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="col-12 q-pt-sm">
<q-input outlined v-model="remark" lazy-rules dense />
</div>
</q-card>
</div>
</div>
</div>
<div v-if="!isDisabledCheckTime" 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 ? 'ลงเวลาเข้างาน' : 'ลงเวลาออกงาน'"
:color="img == null ? 'grey-6' : 'primary'"
push
size="18px"
:class="$q.screen.gt.xs ? 'q-px-md' : 'full-width q-pa-sm'"
:disable="camera && img ? false : true"
@click="validateForm"
:loading="inQueue"
/>
</div>
</div>
<div v-else class="col-12">
<q-separator />
<div class="text-red q-pa-md">*{{ msgCheckTime }}</div>
</div>
</div>
</q-card>
</div>
</div>
</div>
</q-page-sticky>
<!-- footer หนามอถ-->
<q-footer reveal v-if="!isDisabledCheckTime && $q.screen.xs" class="bg-grey-2">
<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 ? 'ลงเวลาเข้างาน' : 'ลงเวลาออกงาน'"
:color="img == null ? 'grey-6' : 'primary'"
push
size="18px"
:class="$q.screen.gt.xs ? 'q-px-md' : 'full-width q-pa-sm'"
:disable="camera && img ? false : true"
@click="validateForm"
:loading="inQueue"
/>
</div>
</q-footer>
<!-- แสดงการลงเวลา -->
<q-dialog v-model="modalTime" persistent>
@ -605,6 +789,8 @@ onMounted(async () => {
</q-dialog>
</template>
<style scoped>
.q-card.cardImg:hover {
border: 1px solid #02a998 !important;
}
@ -619,8 +805,19 @@ onMounted(async () => {
position: relative;
overflow: hidden;
height: autu; /* Adjust as needed */
background: #f6f5f5;
background: #f5f5f5;
height: 35vh !important;
box-shadow: none !important;;
border: 1px solid #EDEDED;
}
.card-container-xs {
position: relative;
overflow: hidden;
height: autu; /* Adjust as needed */
background: #ffffff;
height: 35vh !important;
border-radius: 10px;
}
.image-container {
position: absolute;
@ -641,4 +838,14 @@ onMounted(async () => {
width: 100%;
height: 100%;
}
.bg-topOut{
background: rgb(39,50,56);
background: linear-gradient(175deg, rgba(39,50,56,1) 76%, rgba(198,40,40,1) 100%);
}
.bg-topIn{
background: rgb(39,50,56);
background: linear-gradient(175deg, rgba(39,50,56,1) 76%, rgba(2,169,152,1) 100%);
}
</style>

View file

@ -517,7 +517,7 @@ onMounted(async () => {
:style="
$q.screen.gt.xs
? 'padding: 1.8% 2%; margin-top: -200px;'
: 'padding: 5% 4%; margin-top: -200px;'
: 'padding: 0% 0%; margin-top: -200px;'
"
>
<router-view :key="$route.fullPath" />