- run by vite

- change camera
This commit is contained in:
Warunee Tamkoo 2023-11-14 17:47:43 +07:00
parent 782fa7f59f
commit 85d163fb64
57 changed files with 1494 additions and 1375 deletions

View file

@ -0,0 +1,27 @@
<script lang="ts">
import { defineComponent } from "vue";
export default defineComponent({
name: "Error404NotFound",
});
</script>
<template>
<div
class="fullscreen bg-secondary text-white text-center q-pa-md flex flex-center"
>
<div>
<div class="text-h1">ไมพบหนาทองการ</div>
<div class="text-h2">(404 Page Not Found)</div>
<q-btn
class="q-mt-xl"
color="white"
text-color="secondary"
unelevated
to="/"
label="กลับไปหน้าหลัก"
no-caps
/>
</div>
</div>
</template>

View file

@ -1,103 +1,103 @@
<script setup lang="ts">
import type { QTableProps } from "quasar";
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import Table from "@/components/TableHistory.vue";
import ToolBar from "@/components/ToolBar.vue";
// importStores
import { useChekIn } from "@/stores/chekin";
const router = useRouter();
const stores = useChekIn();
onMounted(() => {
fetchlist();
});
function fetchlist() {
const listData = [
{
no: "1",
date: "13/08/66",
in: "11:20",
loIn: "สำนักงาน ก.ก ",
out: "",
loOut: "",
status: "",
Morningstatus: "1",
AfternoonStatus: "1",
statusEdit: "wait",
},
{
no: "2",
date: "12/08/66",
in: "08:04",
loIn: "สำนักงาน ก.ก ",
out: "17:01",
loOut: "สำนักงาน ก.ก ",
status: "ลงเวลาเรียบร้อย",
Morningstatus: "2",
AfternoonStatus: "2",
statusEdit: "edit",
},
{
no: "3",
date: "11/08/66",
in: "08:34",
loIn: "สำนักงาน ก.ก ",
out: "17:36",
loOut: "สำนักงาน ก.ก ",
status: "สาย ทำงานครบ",
Morningstatus: "3",
AfternoonStatus: "2",
statusEdit: "edit",
},
{
no: "4",
date: "10/08/66",
in: "08:48",
loIn: "สำนักงาน ก.ก ",
out: "17:00",
loOut: "สำนักงาน ก.ก ",
status: "สาย ทำงานไม่ครบ",
Morningstatus: "3",
AfternoonStatus: "3",
statusEdit: "approve",
},
];
stores.fetchHistoryList(listData);
}
</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="bg-secondary text-white col-12 row items-center q-px-md q-py-sm"
>
<div class="col-2">
<q-btn
icon="arrow_backt"
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">
<ToolBar />
<Table />
</div>
</q-card>
</div>
</div>
</template>
<script setup lang="ts">
import type { QTableProps } from 'quasar'
import { ref, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import Table from '@/components/TableHistory.vue'
import ToolBar from '@/components/ToolBar.vue'
// importStores
import { useChekIn } from '@/stores/chekin'
const router = useRouter()
const stores = useChekIn()
onMounted(() => {
fetchlist()
})
function fetchlist() {
const listData = [
{
no: '1',
date: '13/08/66',
in: '11:20',
loIn: 'สำนักงาน ก.ก ',
out: '',
loOut: '',
status: '',
Morningstatus: '1',
AfternoonStatus: '1',
statusEdit: 'wait',
},
{
no: '2',
date: '12/08/66',
in: '08:04',
loIn: 'สำนักงาน ก.ก ',
out: '17:01',
loOut: 'สำนักงาน ก.ก ',
status: 'ลงเวลาเรียบร้อย',
Morningstatus: '2',
AfternoonStatus: '2',
statusEdit: 'edit',
},
{
no: '3',
date: '11/08/66',
in: '08:34',
loIn: 'สำนักงาน ก.ก ',
out: '17:36',
loOut: 'สำนักงาน ก.ก ',
status: 'สาย ทำงานครบ',
Morningstatus: '3',
AfternoonStatus: '2',
statusEdit: 'edit',
},
{
no: '4',
date: '10/08/66',
in: '08:48',
loIn: 'สำนักงาน ก.ก ',
out: '17:00',
loOut: 'สำนักงาน ก.ก ',
status: 'สาย ทำงานไม่ครบ',
Morningstatus: '3',
AfternoonStatus: '3',
statusEdit: 'approve',
},
]
stores.fetchHistoryList(listData)
}
</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="bg-secondary text-white col-12 row items-center q-px-md q-py-sm"
>
<div class="col-2">
<q-btn
icon="arrow_backt"
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">
<ToolBar />
<Table />
</div>
</q-card>
</div>
</div>
</template>

View file

@ -1,202 +1,134 @@
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useQuasar } from "quasar";
import moment, { Moment } from "moment";
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 type { FormRef } from '@/interface/response/checkin'
// import components
import MapCheck from "@/components/MapCheckin.vue";
import MapCheck from '@/components/MapCheckin.vue'
// import Stores
import { useCounterMixin } from "@/stores/mixin";
import { useCounterMixin } from '@/stores/mixin'
const mixin = useCounterMixin();
const { date2Thai, dialogConfirm } = mixin;
const router = useRouter();
const $q = useQuasar();
const mixin = useCounterMixin()
const { date2Thai, dialogConfirm } = mixin
const router = useRouter()
const $q = useQuasar()
const stetusCheckin = ref(true);
const stetusCheckin = ref(true)
onMounted(() => {
updateClock();
});
updateClock()
})
//time
const dateNow = ref<Date>(new Date());
const Thai = ref<Date>(dateNow.value);
const formattedS = ref();
const formattedM = ref();
const formattedH = ref();
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();
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;
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);
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 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 = "";
if (model.value === 'อื่นๆ') {
useLocation.value = ''
} else {
useLocation.value = model.value;
useLocation.value = model.value
}
}
//camera
const camera = ref(false);
const hasPhoto = ref<boolean>(true);
const mediaStream = ref<MediaStream | null>(null);
const video = ref<HTMLVideoElement | null>(null);
const canvas = ref<HTMLCanvasElement | null>(null);
const img = ref<any>(null);
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 = () => {
camera.value = true;
camera.value && setupCamera();
};
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);
}
};
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 = 150;
const desiredHeight = 200;
const zoomFactor = 10;
cameraIsOn.value ? camera.value?.stop() : camera.value?.start()
cameraIsOn.value = !cameraIsOn.value
}
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 = "low";
}
// context.drawImage(
// videoElement,
// 0,
// 0,
// canvasElement.width,
// canvasElement.height
// );
context.drawImage(
videoElement,
0,
0,
videoElement.videoWidth,
videoElement.videoHeight,
0,
0,
drawWidth,
drawHeight
);
async function capturePhoto() {
const imageBlob: any = await camera.value?.snapshot(
{ width: photoWidth.value, height: photoHeight.value },
'image/png',
0.5
)
//
const dataURL = canvasElement.toDataURL(".image/.png");
img.value = dataURL;
console.log(img.value);
camera.value?.stop()
const url = URL.createObjectURL(imageBlob)
img.value = url
}
if (mediaStream.value) {
mediaStream.value.getTracks().forEach((track) => track.stop());
videoElement.srcObject = null;
hasPhoto.value = false;
}
}
function refreshPhoto() {
hasPhoto.value = true;
img.value = "";
img.value = undefined
camera.value?.start()
}
// validate
const useLocationRef = ref<object | null>(null);
const modelRef = ref<object | null>(null);
const useLocationRef = ref<object | null>(null)
const modelRef = ref<object | null>(null)
const objectRef: FormRef = {
model: modelRef,
useLocation: useLocationRef,
};
}
function validateForm() {
const hasError = [];
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);
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();
confirm()
} else {
console.log("ไม่ผ่าน ");
console.log('ไม่ผ่าน ')
}
}
//
const dialogTime = ref<boolean>(false);
const dialogTime = ref<boolean>(false)
const confirm = () => {
dialogConfirm(
$q,
async () => {
dialogTime.value = true;
},
"ยืนยันการบันทึกเวลา ?",
"ต้องการยืนยันการบันทึกการลงเวลานี้ใช่หรือไม่"
);
};
// 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,
};
};
'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>
@ -263,13 +195,12 @@ const getClass = (val: boolean) => {
<MapCheck />
</div>
<div class="col-12 col-sm-4">
<q-card
flat
bordered
class="card-container"
@click="openCamera()"
>
<div v-if="!camera" class="preview-placeholder">
<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"
@ -279,18 +210,26 @@ const getClass = (val: boolean) => {
/>
</div>
</div>
<div v-else>
<div v-if="hasPhoto" class="video-container">
<video ref="video" autoplay class="video-element"></video>
<canvas ref="canvas" class="canvas-element"></canvas>
</div>
<div v-else class="image-container">
<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>
<canvas ref="canvas" class="canvas-element"></canvas>
</div>
<div class="absolute-bottom-right q-ma-md">
<div
v-if="cameraIsOn"
class="absolute-bottom-right q-ma-md"
>
<q-btn
v-if="hasPhoto"
v-if="img == null"
round
push
icon="photo_camera"
@ -311,6 +250,7 @@ const getClass = (val: boolean) => {
</div>
</q-card>
</div>
<div class="col-12 q-mb-md">
<q-card
bordered
@ -377,6 +317,7 @@ const getClass = (val: boolean) => {
/>
</div>
</q-card>
<div class="col-12 text-right">
<q-separator />
<div class="col-12 q-pa-md">
@ -471,8 +412,6 @@ const getClass = (val: boolean) => {
height: 350px; /* Adjust as needed */
background: #f6f5f5;
}
.video-container,
.image-container {
position: absolute;
top: 0;
@ -481,7 +420,6 @@ const getClass = (val: boolean) => {
height: 100%;
}
.video-element,
.image-element {
width: 100%;
height: 100%;
@ -489,7 +427,8 @@ const getClass = (val: boolean) => {
border-radius: 5px; /* Adjust as needed */
}
.canvas-element {
display: none; /* Adjust as needed */
.preview-placeholder {
width: 100%;
height: 100%;
}
</style>

View file

@ -0,0 +1,42 @@
<script setup lang="ts">
import Camera from 'simple-vue-camera'
import { ref } from 'vue'
const camera = ref<InstanceType<typeof Camera>>();
const cameraIsOn = ref<boolean>(false)
const cameraOff = () => {
cameraIsOn.value ? camera.value?.stop() : camera.value?.start()
cameraIsOn.value = !cameraIsOn.value
}
// Use camera reference to call functions
const takePicture = async () => {
const imageBlob = await camera.value?.snapshot(
{ width: 640, height: 480 },
'image/png',
0.5
)
console.log('imageBlob', imageBlob)
camera.value?.stop()
}
</script>
<template>
<div class="row col-12">
<div class="col-3">
<Camera
:resolution="{ width: 500, height: 500 }"
ref="camera"
:autoplay="false"
>
<q-btn color="primary" @click="cameraOff"
>I'm on top of the video</q-btn
>
<q-btn color="primary" @click="takePicture">Take Picture</q-btn>
</Camera>
</div>
</div>
</template>