remove checkin out of project & Refactoring code module 01_dashboard

This commit is contained in:
Warunee Tamkoo 2024-09-02 10:28:59 +07:00
parent ec80361a81
commit 75c0e27880
9 changed files with 105 additions and 1069 deletions

View file

@ -0,0 +1,34 @@
interface InboxList {
id: string;
subject: string;
body: string;
receiverUserId: string;
payload: Object | null;
isOpen: boolean;
receiveDate: Date | null;
openDate: Date | null;
createdFullName?: string;
createdAt?: Date;
}
interface InboxDetail {
no: string;
sender: string;
subject: string;
body: string;
ratingModel: number;
receiveDate?: string;
payload: Object | null;
isOpen: boolean;
}
interface MenuMainList {
icon: string;
title: string;
sub: string;
color: string;
path: string;
active: boolean;
}
export type { InboxList, InboxDetail, MenuMainList };

View file

@ -1,6 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, Static } from "vue";
const link = ref<number>(1);
import { ref, onMounted } from "vue";
import { useQuasar } from "quasar";
import router from "@/router";
import http from "@/plugins/http";
@ -9,23 +8,21 @@ import { useCounterMixin } from "@/stores/mixin";
import PopupReplyInbox from "@/components/PopupReplyInbox.vue";
import PopupDetailInbox from "@/components/PopupDetailInbox.vue";
import { tokenParsed } from "@/plugins/auth";
import {
InboxDetail,
InboxList,
MenuMainList,
} from "@/modules/01_dashboard/interface/Main";
const $q = useQuasar();
const mixin = useCounterMixin();
const { showLoader, hideLoader, date2Thai, messageError } = mixin;
const fullname = ref<string>("");
const inboxList = ref<any>([
// {
// no: 1,
// sender: "",
// subject: "",
// timereceive: "13/12/2565",
// body: " -",
// ratingModel: 0,
// },
]);
const items = ref<any>([
const fullname = ref<string>(""); //
const inboxList = ref<InboxDetail[]>([]); //
const idInboxActive = ref<string>(); // Id
//
const items = ref<MenuMainList[]>([
{
icon: "mdi-account-group-outline",
title: "แผนผังองค์กร",
@ -74,14 +71,6 @@ const items = ref<any>([
path: "/transfer",
active: false,
},
/*{
icon: "mdi-account-remove-outline",
title: "ลาออก",
sub: "ทำเรื่องลาออก",
color: "orange-3",
path: "/retire",
active: false,
},*/
{
icon: "mdi-scale-balance",
title: "อุทธรณ์ร้องทุกข์",
@ -114,44 +103,41 @@ const items = ref<any>([
path: "/scholarship",
active: false,
},
// {
// icon: "mdi-school",
// title: "",
// sub: "",
// color: "teal-2",
// path: "/probation",
// active: false,
// },
]);
onMounted(async () => {
await fetchlistInbox(1);
await fetchlistInbox(1); //
//
const user = await tokenParsed();
if (user) {
fullname.value = user.name;
}
});
/**
* งกนดงขอมลกลองขอความ
* @param index หนาทโหลดขอม
*/
const fetchlistInbox = async (index: number) => {
index === 1 && showLoader();
index != 0 &&
(await http
.get(config.API.msgInbox + `?page=${index}&pageSize=${10}`)
.then((res) => {
let data = res.data.result.data;
let data: InboxList[] = res.data.result.data;
totalInbox.value = res.data.result.total;
let listItem: any = [];
let listItem: InboxDetail[] = [];
if (data && data.length > 0) {
data.map((e: any) => {
console.log(data);
data.map((e: InboxList) => {
listItem.push({
no: e.id ?? "",
sender:
e.createdFullName == "" || e.createdFullName == null
? "เจ้าหน้าที่"
: e.createdFullName,
sender: !e.createdFullName ? "เจ้าหน้าที่" : e.createdFullName,
subject: e.subject ?? "",
timereceive: date2Thai(e.createdAt),
body: e.body ?? "-",
ratingModel: 0,
receiveDate: e.receiveDate,
receiveDate: date2Thai(e.receiveDate, false, true),
payload: e.payload,
isOpen: e.isOpen,
});
@ -159,44 +145,57 @@ const fetchlistInbox = async (index: number) => {
inboxList.value.push(...listItem);
}
})
// .catch((err) => {
// console.log(err);
// })
.finally(() => {
hideLoader();
}));
};
const transferToPage = (path?: string) => {
/**
* งก redirect ไปหนาระบบ
* @param path อยหน
*/
const goToPage = (path?: string) => {
router.push(`${path}`);
};
// Dialog Reply
const modalReply = ref<boolean>(false);
const contactNo = ref<string>();
const modalReply = ref<boolean>(false); // / dialog /
const contactNo = ref<string>(); // id
/**
* งกนเป dialog ตอบกลบขอความ
* @param id id อความ
*/
function dialogRepleOpen(id: string) {
contactNo.value = id;
modalReply.value = true;
contactNo.value = id; // id
modalReply.value = true; // dialog
}
/**
* งกนป dialog ตอบกลบขอความ
*/
function modalReplyClose() {
contactNo.value = "";
modalReply.value = false;
contactNo.value = ""; // id
modalReply.value = false; // dialog
}
const dataInbox = ref<any>();
const modalDetial = ref<boolean>(false);
async function onClickOpenPopupDetail(data: any) {
const dataInbox = ref<InboxDetail>(); //
const modalDetial = ref<boolean>(false); // / dialog
/**
* งกนเป dialog รายละเอยดขอความ
* @param data รายละเอยดขอความ
*/
async function onClickOpenPopupDetail(data: InboxDetail) {
showLoader();
await http
.get(config.API.msgInboxRead(data.no))
.then(() => {
const filterDate = inboxList.value.filter((r: any) => r.no == data.no);
const filterDate = inboxList.value.filter(
(r: InboxDetail) => r.no == data.no
);
for (const item of filterDate) {
item.isOpen = true;
}
dataInbox.value = data;
link.value = data.no;
idInboxActive.value = data.no;
modalDetial.value = !modalDetial.value;
})
.catch((err) => {
@ -207,13 +206,21 @@ async function onClickOpenPopupDetail(data: any) {
});
}
/**
* งกนกำหนดรายละเอยดขอความ งไปย dialog
*/
function updateModalDetail(val: boolean) {
modalDetial.value = val;
modalDetial.value = val; //
}
const scrollTargetRef = ref<any>(null);
const totalInbox = ref<number>(0);
async function onLoad(index: number, done: any) {
const scrollTargetRef = ref<any>(null); // scroll
const totalInbox = ref<number>(0); //
/**
* งกนโหลดขอมลกลองขอความ
* @param index หนาทโหลดขอม
* @param done งกนเมอโหลดขอมลเสร
*/
async function onLoad(index: number, done: Function) {
const num = index === 1 ? 0 : index++;
if (inboxList.value.length < totalInbox.value) {
setTimeout(() => {
@ -222,10 +229,6 @@ async function onLoad(index: number, done: any) {
}, 3000);
}
}
const thaiOptions: Intl.DateTimeFormatOptions = {
hour: "2-digit",
minute: "2-digit",
};
</script>
<template>
@ -245,11 +248,7 @@ const thaiOptions: Intl.DateTimeFormatOptions = {
v-for="(item, j) in items"
:key="j"
>
<q-card
bordered
@click="transferToPage(item.path)"
class="noactive col-12"
>
<q-card bordered @click="goToPage(item.path)" class="noactive col-12">
<div class="col-12">
<q-avatar
:color="item.color"
@ -312,20 +311,14 @@ const thaiOptions: Intl.DateTimeFormatOptions = {
clickable
v-ripple
class="'q-py-md q-mb-sm my-menu'"
:active="link === item.no"
:active="idInboxActive === item.no"
active-class="my-menu-link"
@click.stop.prevent="onClickOpenPopupDetail(item)"
>
<q-item-section>
<q-item-label caption class="text-weight-light">
{{ date2Thai(item.receiveDate) }}
{{
new Date(item.receiveDate).toLocaleTimeString(
"th-TH",
thaiOptions
)
}}
. <q-space />
{{ item.receiveDate }}
<q-space />
</q-item-label>
<q-item-label
:class="!item.isOpen ? 'text-weight-medium' : 'text-grey-7'"
@ -345,10 +338,6 @@ const thaiOptions: Intl.DateTimeFormatOptions = {
>
</q-item-section>
<q-item-section side top>
<q-item-label caption>{{ item.timereceive }}</q-item-label>
</q-item-section>
<q-item-section side top>
<q-btn
flat
@ -375,54 +364,6 @@ const thaiOptions: Intl.DateTimeFormatOptions = {
</q-infinite-scroll>
</div>
<!-- <q-scroll-area style="height: 64vh" v-if="inboxList.length > 0">
<q-list
v-for="(contact, index) in inboxList"
:key="index"
class="q-px-md"
>
<q-item
clickable
v-ripple
class="q-py-md q-mb-sm my-menu"
:active="link === contact.no"
active-class="my-menu-link"
@click="onClickOpenPopupDetail(contact)"
>
<q-item-section>
<q-item-label>
{{ contact.sender }}
<q-icon
v-if="contact.payload"
name="mdi-paperclip"
color="grey-6"
size="18px"
/></q-item-label>
<q-item-label caption class="text-grey-6" lines="2">{{
contact.subject
}}</q-item-label>
</q-item-section>
<q-item-section side top>
<q-item-label caption>{{ contact.timereceive }}</q-item-label>
</q-item-section>
<q-item-section side top>
<q-btn
flat
round
dense
icon="mdi-reply"
size="10px"
color="grey-7"
@click="dialogRepleOpen(contact.no)"
>
<q-tooltip>ตอบกลบขอความ</q-tooltip>
</q-btn>
</q-item-section>
</q-item>
</q-list>
</q-scroll-area> -->
<q-banner rounded class="bg-amber-1 text-center q-mx-sm" v-else>
<div class="text-yellow-10">
<q-icon

View file

@ -1,61 +0,0 @@
<script setup lang="ts">
import Child from "@/components/TestUpgrade.vue";
import { ref, computed, watchEffect } from "vue";
const count = ref<number>(0);
const total = ref<number>(0);
const first = ref<string>("firstName");
const last = ref<string>("lastName");
const isEven = computed(() => count.value % 2 === 0);
// watchEffect(() => isEven.value && submit()); // logs true
const inputValue = ref<string>("");
function submit() {
console.log("test");
}
</script>
<template>
<q-card class="q-pa-md">
<!-- Parent.vue -->
<div class="q-mb-md">
<div>Parent count is: {{ count }}</div>
<q-btn @click="count = 0">Reset count</q-btn>
</div>
<q-separator />
<div class="q-mb-md">
<Child
v-model="count"
v-model:total="total"
v-model:firstname.lastNameModifiers="first"
v-model:lastname.uppercase="last"
:name2="inputValue"
/>
</div>
<!-- <div class="q-mb-md">
<q-btn @click="refs.update">count ++</q-btn>
</div> -->
</q-card>
<q-separator />
<q-card class="q-pa-md">
<!-- Parent.vue -->
<div class="q-mb-md q-gutter-sm">
<div><h4>Test Vue</h4></div>
<div>
<q-input outlined dense type="text" v-model="inputValue"></q-input>
</div>
<q-btn @click="submit">submit</q-btn>
</div>
<!-- <div class="q-mb-md">
<Child :name="first" />
</div> -->
</q-card>
</template>

View file

@ -1,100 +0,0 @@
<template>
<div>
<div id="map"></div>
</div>
</template>
<script setup lang="ts">
import { onMounted } from "vue";
import Map from "ol/Map";
import View from "ol/View";
import { fromLonLat } from "ol/proj";
import { Tile as TileLayer } from "ol/layer";
import { OSM } from "ol/source";
import Feature from "ol/Feature";
import Point from "ol/geom/Point";
import Circle from "ol/geom/Circle";
import VectorLayer from "ol/layer/Vector";
import VectorSource from "ol/source/Vector";
import { Style, Icon, Fill, Stroke } from "ol/style";
onMounted(() => {
const map = new Map({
target: "map",
layers: [
new TileLayer({
source: new OSM(),
}),
],
view: new View({
center: fromLonLat([98.981716, 18.7883]),
zoom: 12,
}),
});
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition((position) => {
console.log(position);
const lon = position.coords.longitude;
const lat = position.coords.latitude;
const coordinates = fromLonLat([lon, lat]);
currentLocationFeature.setGeometry(new Point(coordinates));
map.getView().setCenter(coordinates);
});
}
// feature
const currentLocationFeature = new Feature({
geometry: new Point(fromLonLat([98.981716, 18.7883])),
});
currentLocationFeature.setStyle(
new Style({
image: new Icon({
src: "https://assets.untappd.com/site/beer_logos_hd/beer-4817317_108bb_hd.jpeg",
scale: 0.02,
}),
})
);
const currentLocationLayer = new VectorLayer({
source: new VectorSource({
features: [currentLocationFeature],
}),
});
map.addLayer(currentLocationLayer);
//
const circleFeature = new Feature({
geometry: new Circle(fromLonLat([98.981716, 18.7883]), 1000),
});
circleFeature.setStyle(
new Style({
fill: new Fill({
color: "rgba(2, 169, 152, 0.2)",
}),
stroke: new Stroke({
color: "rgb(2, 169, 152)",
width: 2,
}),
})
);
const circleLayer = new VectorLayer({
source: new VectorSource({
features: [circleFeature],
}),
});
map.addLayer(circleLayer);
});
</script>
<style scoped>
#map {
width: 100%;
height: 400px;
}
</style>

View file

@ -1,161 +0,0 @@
<template>
<div class="q-pb-sm row">
<div class="items-center col-12 row q-gutter-sm">
<!-- นหาขอความใน table -->
<datepicker menu-class-name="modalfix" v-model="yearly" :locale="'th'" autoApply year-picker :enableTimePicker="false">
<template #year="{ year }">{{ year + 543 }}</template>
<template #year-overlay-value="{ value }">{{ parseInt(value + 543) }}</template>
<template #trigger>
<q-input hide-bottom-space outlined dense lazy-rules :model-value="yearly + 543" :rules="[val => !!val || `${'กรุณาเลือกปีพ.ศ.'}`]" :label="`${'ปีพ.ศ.'}`" style="width: 150px">
<template v-slot:prepend>
<q-icon name="event" class="cursor-pointer" color="primary"> </q-icon>
</template>
</q-input>
</template>
</datepicker>
<q-space />
<q-input standout dense :model-value="inputfilter" ref="filterRef" @update:model-value="updateInput" outlined debounce="300" placeholder="ค้นหา" class="gt-xs" style="max-width: 200px">
<template v-slot:append>
<q-icon v-if="inputfilter == ''" name="search" />
<q-icon v-if="inputfilter !== ''" name="clear" class="cursor-pointer" @click="resetFilter" />
</template>
</q-input>
<!-- แสดงคอลมนใน table -->
<q-select
:model-value="inputvisible"
@update:model-value="updateVisible"
:display-value="$q.lang.table.columns"
multiple
outlined
dense
:options="attrs.columns"
options-dense
option-value="name"
map-options
emit-value
style="min-width: 150px"
class="gt-xs"
>
<template> </template>
</q-select>
</div>
</div>
<div>
<q-table
ref="table"
flat
bordered
class="custom-table2"
v-bind="attrs"
virtual-scroll
:virtual-scroll-sticky-size-start="48"
dense
:pagination-label="paginationLabel"
:pagination="initialPagination"
:rows-per-page-options="[0]"
:grid="grid"
>
<template v-slot:header="props">
<q-tr :props="props">
<q-th v-for="col in props.cols" :key="col.name" :props="props">
<span class="text-weight-medium" v-html="col.label" />
</q-th>
<q-th auto-width v-if="inputShow" />
</q-tr>
</template>
<template #body="props">
<slot v-bind="props" name="columns"></slot>
</template>
<template #item="props">
<slot v-bind="props" name="item"></slot>
</template>
</q-table>
</div>
</template>
<script setup lang="ts">
import { ref, useAttrs } from "vue"
const attrs = ref<any>(useAttrs())
const table = ref<any>(null)
const filterRef = ref<any>(null)
const initialPagination = ref({
rowsPerPage: 0,
})
const yearly = ref<number>(new Date().getFullYear())
const props = defineProps({
count: Number,
pass: Number,
notpass: Number,
inputfilter: String,
name: String,
icon: String,
inputvisible: Array,
editvisible: Boolean,
grid: Boolean,
inputShow: Boolean,
})
const emit = defineEmits(["update:inputfilter", "update:inputvisible", "update:editvisible"])
const updateInput = (value: string | number | null) => {
emit("update:inputfilter", value)
}
const updateVisible = (value: []) => {
emit("update:inputvisible", value)
}
const paginationLabel = (start: string, end: string, total: string) => {
return start + "-" + end + " ใน " + total
}
const resetFilter = () => {
// reset X
emit("update:inputfilter", "")
filterRef.value.focus()
}
</script>
<style lang="scss">
.icon-color {
color: #4154b3;
}
.custom-table2 {
.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;
}
.q-table td:nth-of-type(2) {
z-index: 3 !important;
}
.q-table th:nth-of-type(2),
.q-table td:nth-of-type(2) {
position: sticky;
left: 0;
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;
}
}
</style>

View file

@ -1,38 +0,0 @@
/**
* Router Checkin
*/
const Checkin = () => import("@/modules/04_checkin/views/Checkin.vue")
const History = () => import("@/modules/04_checkin/views/history.vue")
/* const Checkout = () => import("@/modules/04_checkin/views/Checkout.vue");
*/
export default [
{
path: "/check-in",
name: "Checkin",
component: Checkin,
meta: {
Auth: true,
Key: [7],
},
},
{
path: "/check-in/history",
name: "History",
component: History,
meta: {
Auth: true,
Key: [7],
},
},
/* {
path: "/check-out",
name: "Checkout",
component: Checkout,
meta: {
Auth: true,
Key: [7],
},
}, */
]

View file

@ -1,417 +0,0 @@
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<q-card flat class="row col-12 cardNone">
<div :class="getClass(checkIn)">
<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="checkIn">ลงเวลาเข้างาน</span>
<span v-else>ลงเวลาออกงาน</span>
</span>
<div class="col-2 text-right">
<q-btn
icon="mdi-history"
unelevated
rounded
dense
flat
color="white"
:label="$q.screen.gt.xs ? 'ประวัติการลงเวลา' : ''"
:class="$q.screen.gt.xs ? 'q-px-sm' : ''"
@click="router.push('/check-in/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"
>
{{ 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> -->
</div>
<div class="colunm">
<div class="text-h3 text-weight-bold">
{{ formattedM }}<span class="q-ma-md">:</span>
</div>
<!-- <div>นาท</div> -->
</div>
<div class="colunm">
<div class="text-h3 text-weight-bold">{{ formattedS }}</div>
<!-- <div>นาท</div> -->
</div>
</div>
</div>
<!-- <div class="col-12 text-center text-weight-medium items-center text-dark q-pt-md"><q-icon color="primary" name="mdi-calendar-outline" class="q-mr-sm"/>นท {{dateNow}}</div> -->
<div class="col-xs-12 col-md-11 row q-col-gutter-md">
<div class="col-12 col-sm-8">
<q-card
bordered
flat
class="col-12 bg-grey-2 shadow-0"
:style="$q.screen.gt.xs ? 'height: 350px;' : 'height: 220px;'"
>
<!-- <mapCheckin /> -->
<q-img
src="@/assets/map1.png"
:style="
$q.screen.gt.xs ? 'height: 350px;' : 'height: 168px;'
"
></q-img>
<div class="q-pa-md text-weight-medium text-grey-8">
นทใกลเคยง
<span class="q-px-sm">:</span>
{{ location }}
</div>
</q-card>
</div>
<div class="col-12 col-sm-4">
<q-card
flat
bordered
class="cardImg col-12 bg-grey-2 items-center row cursor-pointer shadow-0"
@click="photo()"
:style="$q.screen.gt.xs ? 'height: 350px;' : 'height: 220px;'"
>
<div class="column col-12" v-if="!camera">
<div class="text-center">
<q-icon
name="mdi-camera"
size="100px"
color="blue-grey-3"
/>
</div>
</div>
<div v-else>
<div v-if="hasPhoto">
<video
ref="video"
autoplay
:style="
$q.screen.gt.xs
? 'width: 375px; height: 350px;'
: 'width: 245px; height: 220px;'
"
></video>
<canvas
ref="canvas"
:style="
$q.screen.gt.xs
? 'width: 375px; height: 350px;'
: 'width: 252px; height: 190px;'
"
></canvas>
</div>
<div v-else>
<q-img
:src="img"
:style="
$q.screen.gt.xs
? 'width: 375px; height: 350px; border-radius: 5px;'
: 'width: 245px; height: 218px; border-radius: 5px;'
"
></q-img>
<canvas ref="canvas"></canvas>
</div>
<div class="absolute-bottom-right q-ma-md">
<q-btn
round
push
icon="mdi-camera"
size="md"
color="positive"
@click="capturePhoto"
/>
</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">
<q-select
v-if="workplace == 'off-site'"
dense
class="q-ml-md"
outlined
v-model="model"
:options="options"
prefix="ระบุสถานที่ :"
/>
</div>
</q-card>
</div>
</div>
</div>
</div>
<div class="col-12 text-right" v-if="camera">
<div class="col-12">
<q-separator />
</div>
<div class="col-12 q-pa-md">
<q-btn
:label="checkIn == true ? 'ลงเวลาเข้างาน' : 'ลงเวลาออกงาน'"
:color="checkIn == true ? 'primary' : 'red-9'"
push
size="14px"
:class="$q.screen.gt.xs ? 'q-px-md' : 'full-width'"
@click="confirm"
/>
</div>
</div>
</q-card>
</div>
</div>
<q-dialog v-model="dialogTime">
<q-card class="full-width cardNone">
<div :class="getClass(checkIn)">
<div class="text-body1 text-center col-12 text-weight-bold">
<span v-if="checkIn">ลงเวลาเข้างานของคุณ</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">
{{ 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>
<script setup lang="ts">
import type { QTableProps } from "quasar";
import { ref, onMounted } from "vue";
import { useQuasar } from "quasar";
import { useRouter } from "vue-router";
import moment from "moment";
import { useCounterMixin } from "@/stores/mixin";
const mixin = useCounterMixin();
const { dateThai } = mixin;
// import mapCheckin from "../components/mapCheck.vue";
const router = useRouter();
const $q = useQuasar();
const dateNow = ref(new Date());
const Thai = ref(dateThai(dateNow.value));
const location = ref("สำนักงาน ก.ก");
const coordinates = ref("13° 43 45” N 100° 31 26” E");
const workplace = ref("in-place");
const model = ref(null);
const options = ref([
"ปฏิบัติงานที่บ้าน",
"ลืมลงเวลาปฏิบัติงาน",
"ไปประชุม/อบรม/สัมมนา/ปฏิบัติงานที่บ้านนอกสถานที่",
"ขออนุญาตออกนอกสถานที่",
]);
const checkIn = ref(true); // () true 2 () false
const camera = ref(false);
const dialogTime = ref(false);
const photo = () => {
camera.value = true;
camera.value && setupCamera();
};
const confirm = () => {
dialogTime.value = true;
};
const mediaStream = ref<MediaStream | null>(null);
const video = ref<HTMLVideoElement | null>(null);
const canvas = ref<HTMLCanvasElement | null>(null);
const hasPhoto = ref<boolean>(true);
const img = ref<any>();
function capturePhoto() {
const videoElement = video.value;
const canvasElement = canvas.value;
if (!videoElement || !canvasElement) {
console.error("Video or Canvas element not available");
return;
}
const context = canvasElement.getContext("2d");
if (!context) {
console.error("Canvas context not available");
return;
}
const desiredWidth = 189;
const desiredHeight = 190;
const zoomFactor = 10;
const videoAspectRatio = videoElement.videoWidth / videoElement.videoHeight;
const canvasAspectRatio = desiredWidth / desiredHeight;
let drawWidth, drawHeight;
if (videoAspectRatio > canvasAspectRatio) {
drawWidth = desiredWidth * zoomFactor;
drawHeight = (desiredWidth * zoomFactor) / videoAspectRatio;
} else {
drawWidth = desiredHeight * zoomFactor * videoAspectRatio;
drawHeight = desiredHeight * zoomFactor;
}
canvasElement.width = drawWidth;
canvasElement.height = drawHeight;
if (context) {
context.imageSmoothingEnabled = true;
context.imageSmoothingQuality = "high";
}
// context.drawImage(
// videoElement,
// 0,
// 0,
// canvasElement.width,
// canvasElement.height
// );
context.drawImage(
videoElement,
0,
0,
videoElement.videoWidth,
videoElement.videoHeight,
0,
0,
drawWidth,
drawHeight
);
//
const dataURL = canvasElement.toDataURL(".image/.png");
img.value = dataURL;
console.log(img.value);
if (mediaStream.value) {
mediaStream.value.getTracks().forEach((track) => track.stop());
videoElement.srcObject = null;
hasPhoto.value = false;
}
}
const setupCamera = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: true });
if (video.value) {
video.value.srcObject = stream;
}
mediaStream.value = stream;
} catch (error) {
console.error("Error accessing camera:", error);
}
};
// var date = Date.now();
// let formattedH = moment(date).format("HH");
// let formattedM = moment(date).format("mm");
// let formattedS = moment(date).format("ss");
const time = new Date().toLocaleTimeString();
const formattedS = ref();
const formattedM = ref();
const formattedH = ref();
onMounted(() => {
updateClock();
});
//
function updateClock() {
const date = Date.now();
let hh = moment(date).format("HH");
let mm = moment(date).format("mm");
let ss = moment(date).format("ss");
formattedS.value = ss;
formattedM.value = mm;
formattedH.value = hh;
}
setInterval(updateClock, 1000); // 1
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>
<style>
.q-card.cardImg:hover {
border: 1px solid #02a998 !important;
}
</style>

View file

@ -1,160 +0,0 @@
<template>
<div class="col-12 row justify-center">
<div class="col-xs-12 col-sm-12 col-md-11">
<q-card flat class="row col-12 cardNone">
<div class="bg-secondary text-white col-12 row items-center q-px-md q-py-sm">
<div class="col-2">
<q-btn icon="mdi-arrow-left" unelevated round dense flat color="white" @click="router.go(-1)" />
</div>
<q-space />
<span class="text-body1 text-weight-bold col-8 text-center">ประวการลงเวลา</span>
<div class="col-2"></div>
</div>
<div class="col-12 q-pa-md text-grey-9">
<Table
:style="$q.screen.gt.xs ? 'max-height: 64vh' : ''"
:rows="rows"
:columns="columns"
:filter="filter"
:visible-columns="visibleColumns"
v-model:inputfilter="filter"
v-model:inputvisible="visibleColumns"
:pagination="initialPagination"
:inputShow="false"
:grid="$q.screen.gt.xs ? false : true"
>
<template #columns="props">
<q-tr :props="props">
<q-td key="no" :props="props">
{{ props.rowIndex + 1 }}
</q-td>
<q-td key="date" :props="props">
{{ props.row.date }}
</q-td>
<q-td key="in" :props="props">
{{ props.row.in }}
</q-td>
<q-td key="loIn" :props="props">
{{ props.row.loIn }}
</q-td>
<q-td key="out" :props="props">
{{ props.row.out }}
</q-td>
<q-td key="loOut" :props="props">
{{ props.row.loOut }}
</q-td>
<q-td key="status" :props="props">
<span :class="props.row.status == 'ลงเวลาเรียบร้อย' ? 'text-blue' : 'text-orange'">{{ props.row.status }}</span>
</q-td>
</q-tr>
</template>
<template #item="props">
<div class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 grid-style-transition">
<q-card bordered flat class="q-py-sm shadow-0">
<q-list dense>
<q-item v-for="col in props.cols" :key="col.name" :props="props">
<q-item-section>
<q-item-label caption>{{ col.label }}</q-item-label>
</q-item-section>
<q-item-section side>
<q-item-label>
<span v-if="col.name == 'status'" :class="props.row.status == 'ลงเวลาเรียบร้อย' ? 'text-blue' : 'text-orange'">{{ col.value }}</span>
<span v-else class="text-black">{{ col.value }}</span>
</q-item-label>
</q-item-section>
</q-item>
</q-list>
</q-card>
</div>
</template>
</Table>
</div>
</q-card>
</div>
</div>
</template>
<script setup lang="ts">
import type { QTableProps } from "quasar"
import { ref } from "vue"
import { useRouter } from "vue-router"
import Table from "@/modules/04_checkin/components/tableHistory.vue"
const router = useRouter()
const filter = ref<string>("")
const visibleColumns = ref<String[]>(["no", "date", "in", "loIn", "out", "loOut", "status"])
const columns = ref<QTableProps["columns"]>([
{
name: "no",
align: "left",
label: "ลำดับ",
sortable: true,
field: "no",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width:5%;",
},
{
name: "date",
align: "left",
label: "วัน/เดือน/ปี",
sortable: true,
field: "date",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width:15%;",
},
{
name: "in",
align: "left",
label: "เวลาเข้างาน",
sortable: true,
field: "in",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width:15%;",
},
{
name: "loIn",
align: "left",
label: "พิกัด",
sortable: true,
field: "loIn",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "out",
align: "left",
label: "เวลาออกงาน",
sortable: true,
field: "out",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width:15%;",
},
{
name: "loOut",
align: "left",
label: "พิกัด",
sortable: true,
field: "loOut",
headerStyle: "font-size: 14px",
style: "font-size: 14px",
},
{
name: "status",
align: "left",
label: "สถานะ",
sortable: true,
field: "status",
headerStyle: "font-size: 14px",
style: "font-size: 14px; width:10%;",
},
])
const rows = ref<any>([
{ no: "1", date: "13/08/66", in: "11:20", loIn: "สำนักงาน ก.ก ", out: "", loOut: "", status: "" },
{ no: "2", date: "12/08/66", in: "08:04", loIn: "สำนักงาน ก.ก ", out: "17:01", loOut: "สำนักงาน ก.ก ", status: "ลงเวลาเรียบร้อย" },
{ no: "3", date: "11/08/66", in: "08:34", loIn: "สำนักงาน ก.ก ", out: "17:36", loOut: "สำนักงาน ก.ก ", status: "สาย ทำงานครบ" },
{ no: "4", date: "10/08/66", in: "08:48", loIn: "สำนักงาน ก.ก ", out: "17:00", loOut: "สำนักงาน ก.ก ", status: "สาย ทำงานไม่ครบ" },
])
const initialPagination = ref({
rowsPerPage: 0,
})
</script>