fix(checkin): improve camera functionality and fix iOS Live Mode issue

- Add playsinline prop to fix iOS Live Mode photo capture issue
- Change default camera to front camera (facingMode: 'user')
- Improve photo quality: change from PNG to JPEG with quality 0.8
- Fix memory leak: add URL.revokeObjectURL() cleanup
- Add error handling for camera operations (openCamera, capturePhoto, refreshPhoto)
- Add timestamp to photo filename for uniqueness

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Warunee Tamkoo 2026-05-07 16:47:35 +07:00
parent 9efac056e9
commit cd433af194
2 changed files with 114 additions and 56 deletions

View file

@ -347,18 +347,23 @@ async function openCamera() {
} }
if (!isPermissionCameraDenied.value) { if (!isPermissionCameraDenied.value) {
// change camera device try {
if (cameraIsOn.value) { // change camera device
camera.value?.stop() if (cameraIsOn.value) {
} else { camera.value?.stop()
await camera.value?.start() } else {
const devices: any = await camera.value?.devices(['videoinput']) await camera.value?.start()
if (devices) { const devices: any = await camera.value?.devices(['videoinput'])
availableCameras.value = devices if (devices) {
await changeCamera() availableCameras.value = devices
await changeCamera()
}
} }
cameraIsOn.value = !cameraIsOn.value
} catch (error) {
console.error('Error opening camera:', error)
messageError($q, error, 'ไม่สามารถเปิดกล้องได้ กรุณาลองใหม่อีกครั้ง')
} }
cameraIsOn.value = !cameraIsOn.value
} else { } else {
messageError( messageError(
$q, $q,
@ -428,26 +433,49 @@ async function switchCamera() {
/** function ถ่ายรูป*/ /** function ถ่ายรูป*/
async function capturePhoto() { async function capturePhoto() {
const imageBlob: any = await camera.value?.snapshot( try {
{ width: photoWidth.value, height: photoHeight.value }, const imageBlob: any = await camera.value?.snapshot(
'image/png', { width: photoWidth.value, height: photoHeight.value },
0.5 'image/jpeg',
) 0.8
if (!imageBlob) return )
const fileName = 'photo.jpg' if (!imageBlob) {
// messageError($q, '', 'ไม่สามารถถ่ายรูปได้ กรุณาลองใหม่อีกครั้ง')
const file = new File([imageBlob], fileName, { type: 'image/png' }) return
fileImg.value = file }
// const fileName = `photo_${Date.now()}.jpg`
camera.value?.stop() //
const url = URL.createObjectURL(imageBlob) const file = new File([imageBlob], fileName, { type: 'image/jpeg' })
img.value = url fileImg.value = file
// URL ( memory leak)
if (img.value) {
URL.revokeObjectURL(img.value)
}
//
camera.value?.stop()
const url = URL.createObjectURL(imageBlob)
img.value = url
} catch (error) {
console.error('Error capturing photo:', error)
messageError($q, error, 'ไม่สามารถถ่ายรูปได้ กรุณาลองใหม่อีกครั้ง')
}
} }
/** function เปลี่ยนรูปภาพ*/ /** function เปลี่ยนรูปภาพ*/
function refreshPhoto() { async function refreshPhoto() {
img.value = undefined try {
camera.value?.start() // URL ( memory leak)
if (img.value) {
URL.revokeObjectURL(img.value)
img.value = undefined
}
await camera.value?.start()
} catch (error) {
console.error('Error refreshing photo:', error)
messageError($q, error, 'ไม่สามารถเปิดกล้องได้ กรุณาลองใหม่อีกครั้ง')
}
} }
/** ref validate*/ /** ref validate*/
@ -627,7 +655,11 @@ async function onClickConfirm() {
try { try {
showLoader() showLoader()
cameraIsOn.value = false cameraIsOn.value = false
img.value = undefined // URL ( memory leak)
if (img.value) {
URL.revokeObjectURL(img.value)
img.value = undefined
}
modalTime.value = false modalTime.value = false
if (!statusCheckin.value) { if (!statusCheckin.value) {
statusCheckin.value = true statusCheckin.value = true
@ -665,7 +697,9 @@ const inQueue = ref<boolean>(false)
// //
function resetCameraAndImage() { function resetCameraAndImage() {
// URL ( memory leak)
if (img.value) { if (img.value) {
URL.revokeObjectURL(img.value)
img.value = undefined img.value = undefined
} }
if (cameraIsOn.value && camera.value) { if (cameraIsOn.value && camera.value) {
@ -885,14 +919,12 @@ watch(
</div> </div>
<div class="col-12 row items-center"> <div class="col-12 row items-center">
<!-- แสดงกลองตอนกดถายภาพ --> <!-- แสดงกลองตอนกดถายภาพ -->
<Camera <Camera
:resolution="{ width: photoWidth, height: photoHeight }" :resolution="{ width: photoWidth, height: photoHeight }"
ref="camera" ref="camera"
:autoplay="false" :autoplay="false"
:playsinline="true" :playsinline="true"
:facingMode="'user'" :facingMode="'user'"
:style="!img ? 'display: block' : 'display: none'"
/> />
<!-- แสดงรปเมอกด capture --> <!-- แสดงรปเมอกด capture -->
@ -998,7 +1030,6 @@ watch(
</div> </div>
<div class="col-12 row items-center"> <div class="col-12 row items-center">
<!-- แสดงกลองตอนกดถายภาพ --> <!-- แสดงกลองตอนกดถายภาพ -->
<Camera <Camera
:resolution="{ :resolution="{
width: photoWidth, width: photoWidth,
@ -1008,7 +1039,6 @@ watch(
:autoplay="false" :autoplay="false"
:playsinline="true" :playsinline="true"
:facingMode="'user'" :facingMode="'user'"
:style="!img ? 'display: block' : 'display: none'"
/> />
<!-- แสดงรปเมอกด capture --> <!-- แสดงรปเมอกด capture -->

View file

@ -133,14 +133,19 @@ const photoHeight = ref<number>(350)
/** function เปิดกล้อง */ /** function เปิดกล้อง */
async function openCamera() { async function openCamera() {
// change camera device try {
if (cameraIsOn.value) { // change camera device
camera.value?.stop() if (cameraIsOn.value) {
} else { camera.value?.stop()
await camera.value?.start() } else {
changeCamera() await camera.value?.start()
changeCamera()
}
cameraIsOn.value = !cameraIsOn.value
} catch (error) {
console.error('Error opening camera:', error)
messageError($q, error, 'ไม่สามารถเปิดกล้องได้ กรุณาลองใหม่อีกครั้ง')
} }
cameraIsOn.value = !cameraIsOn.value
} }
/** change camera device */ /** change camera device */
@ -152,25 +157,49 @@ async function changeCamera() {
/** function ถ่ายรูป*/ /** function ถ่ายรูป*/
async function capturePhoto() { async function capturePhoto() {
const imageBlob: any = await camera.value?.snapshot( try {
{ width: photoWidth.value, height: photoHeight.value }, const imageBlob: any = await camera.value?.snapshot(
'image/png', { width: photoWidth.value, height: photoHeight.value },
0.5 'image/jpeg',
) 0.8
const fileName = 'photo.png' )
// if (!imageBlob) {
const file = new File([imageBlob], fileName, { type: 'image/png' }) messageError($q, '', 'ไม่สามารถถ่ายรูปได้ กรุณาลองใหม่อีกครั้ง')
fileImg.value = file return
// }
camera.value?.stop() const fileName = `photo_${Date.now()}.jpg`
const url = URL.createObjectURL(imageBlob) //
img.value = url const file = new File([imageBlob], fileName, { type: 'image/jpeg' })
fileImg.value = file
// URL ( memory leak)
if (img.value) {
URL.revokeObjectURL(img.value)
}
//
camera.value?.stop()
const url = URL.createObjectURL(imageBlob)
img.value = url
} catch (error) {
console.error('Error capturing photo:', error)
messageError($q, error, 'ไม่สามารถถ่ายรูปได้ กรุณาลองใหม่อีกครั้ง')
}
} }
/** function เปลี่ยนรูปภาพ*/ /** function เปลี่ยนรูปภาพ*/
function refreshPhoto() { async function refreshPhoto() {
img.value = undefined try {
camera.value?.start() // URL ( memory leak)
if (img.value) {
URL.revokeObjectURL(img.value)
img.value = undefined
}
await camera.value?.start()
} catch (error) {
console.error('Error refreshing photo:', error)
messageError($q, error, 'ไม่สามารถเปิดกล้องได้ กรุณาลองใหม่อีกครั้ง')
}
} }
/** ref validate*/ /** ref validate*/
@ -337,7 +366,6 @@ onMounted(async () => {
:autoplay="false" :autoplay="false"
:playsinline="true" :playsinline="true"
:facingMode="'user'" :facingMode="'user'"
:style="!img ? 'display: block' : 'display: none'"
/> />
<!-- แสดงรปเมอกด capture --> <!-- แสดงรปเมอกด capture -->