315 lines
11 KiB
Vue
315 lines
11 KiB
Vue
<script setup lang="ts">
|
|
import { ref, computed } from 'vue'
|
|
import http from '@/plugins/http'
|
|
import config from '@/app.config'
|
|
|
|
const modal = defineModel<boolean>('modal', {
|
|
required: true,
|
|
})
|
|
|
|
// Privacy content data
|
|
const privacyContent = {
|
|
title: 'การคุ้มครองข้อมูลส่วนบุคคล',
|
|
mainText:
|
|
'ระบบนี้มีการเก็บ และใช้ภาพถ่ายของท่าน เพื่อยืนยันตัวตนในการลงเวลาปฏิบัติราชการ ข้อมูลจะถูกใช้เฉพาะตามวัตถุประสงค์ของระบบ และจัดเก็บอย่างปลอดภัยตามกฎหมายคุ้มครองข้อมูลส่วนบุคคล (PDPA)',
|
|
warningText: '* หากท่านไม่กดยอมรับ อาจทำให้ไม่สามารถใช้งานระบบได้',
|
|
detailIntro:
|
|
'ข้าพเจ้าตกลงให้กรุงเทพมหานครเก็บ ใช้ และประมวลผลข้อมูลส่วนบุคคลประเภทภาพถ่ายของข้าพเจ้า ซึ่งได้มาจากการใช้งานระบบลงเวลาปฏิบัติราชการอิเล็กทรอนิกส์ ของระบบบริหารทรัพยากรบุคคลของกรุงเทพมหานคร (BMA - HRMS) ทั้งนี้ เพื่อวัตถุประสงค์ดังต่อไปนี้',
|
|
purposes: {
|
|
title: 'วัตถุประสงค์การใช้ข้อมูล',
|
|
items: [
|
|
'เพื่อยืนยันตัวตนของผู้ปฏิบัติงานในการบันทึกเวลาเข้า-ออกการปฏิบัติราชการ',
|
|
'เพื่อใช้เป็นหลักฐานประกอบการบริหารงานด้านทรัพยากรบุคคล การจ่ายค่าตอบแหน และการกำกับ ดูแลการปฏิบัติราชการ',
|
|
'เพื่อรักษาความถูกต้อง โปร่งใส และป้องกันการทุจริตในการบันทึกเวลาการปฏิบัติงานข้าพเจ้าทราบและเข้าใจว่า',
|
|
],
|
|
},
|
|
understanding: {
|
|
items: [
|
|
'การเก็บ ใช้ และประมวลผลข้อมูลส่วนบุคคลดังกล่าว จะดำเนินการ เท่าที่จำเป็นตามวัตถุประสงค์ที่ระบุไว้เท่านั้น',
|
|
'หน่วยงานจะจัดให้มีมาตรการรักษาความมั่นคงปลอดภัยของข้อมูลส่วนบุคคล ตามที่กฎหมายกำหนด',
|
|
'ข้อมูลส่วนบุคคลของข้าพเจ้าจะถูกเก็บรักษา ตามระยะเวลาที่จำเป็น ต่อการปฏิบัติงานหรือเป็นไปตามที่กฎหมายกำหนด',
|
|
],
|
|
},
|
|
rights: {
|
|
title:
|
|
'ข้าพเจ้าทราบถึง สิทธิของเจ้าของข้อมูลส่วนบุคคล ตามพระราชบัญญัติคุ้มครองข้อมูลส่วนบุคคล พ.ศ. ๒๕๖๒ ได้แก่',
|
|
items: [
|
|
'สิทธิขอเข้าถึงและขอรับสำเนาข้อมูล',
|
|
'สิทธิขอแก้ไขข้อมูลให้ถูกต้อง',
|
|
'สิทธิขอถอนความยินยอม (ทั้งนี้ การถอนความยินยอมอาจส่งผลต่อการใช้งานระบบลงเวลาการปฏิบัติราชการ)',
|
|
'สิทธิร้องเรียนต่อคณะกรรมการคุ้มครองข้อมูลส่วนบุคคล',
|
|
],
|
|
},
|
|
consentText:
|
|
'ข้าพเจ้าได้อ่านและเข้าใจรายละเอียดทั้งหมดแล้ว และยินยอมให้เก็บ ใช้ และประมวลผลข้อมูลส่วนบุคคล ประเภทภาพถ่ายของข้าพเจ้า ตามที่ระบุไว้ข้างต้นโดยสมัครใจ',
|
|
buttons: {
|
|
accept: 'ยอมรับ',
|
|
decline: 'ไม่ยอมรับ',
|
|
},
|
|
}
|
|
|
|
const hasScrolledToBottom = ref(false)
|
|
const acceptPrivacy = ref(false)
|
|
const isAcceptDisabled = computed(() => !acceptPrivacy.value)
|
|
|
|
const handleScroll = (event: Event) => {
|
|
const target = event.target as HTMLElement
|
|
if (!target) return
|
|
|
|
const { scrollTop, scrollHeight, clientHeight } = target
|
|
// Enable checkbox when scrolled to near bottom (within 20px)
|
|
if (scrollTop + clientHeight >= scrollHeight - 20) {
|
|
hasScrolledToBottom.value = true
|
|
}
|
|
}
|
|
|
|
const handleAccept = async () => {
|
|
try {
|
|
await http.put(config.API.privacy, {
|
|
system: 'checkin',
|
|
accept: true,
|
|
})
|
|
} catch (error) {}
|
|
}
|
|
|
|
const handleDecline = () => {
|
|
modal.value = false
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<q-dialog
|
|
v-model="modal"
|
|
persistent
|
|
transition-show="slide-up"
|
|
transition-hide="slide-down"
|
|
:maximized="$q.screen.lt.sm"
|
|
>
|
|
<q-card class="privacy-card" style="max-width: 520px; max-height: 95vh">
|
|
<!-- Header -->
|
|
<q-card-section class="bg-primary text-white q-pa-lg">
|
|
<div class="text-h5 text-center">
|
|
{{ privacyContent.title }}
|
|
</div>
|
|
<q-btn
|
|
icon="close"
|
|
flat
|
|
round
|
|
dense
|
|
class="absolute-top-right q-ma-sm"
|
|
style="opacity: 0.8"
|
|
v-close-popup
|
|
@click="handleDecline"
|
|
/>
|
|
</q-card-section>
|
|
|
|
<!-- Scrollable Content -->
|
|
<q-card-section
|
|
ref="scrollContainer"
|
|
class="col scroll q-px-md"
|
|
@scroll="handleScroll"
|
|
>
|
|
<!-- Main Content -->
|
|
<div class="q-pt-lg q-pb-md">
|
|
<p class="main-text">{{ privacyContent.mainText }}</p>
|
|
|
|
<q-banner
|
|
inline-actions
|
|
class="bg-amber-1 q-mt-md rounded-borders text-center"
|
|
style="border-left: 4px solid #f0ad4e; color: #f0ad4e"
|
|
>
|
|
{{ privacyContent.warningText }}
|
|
</q-banner>
|
|
</div>
|
|
|
|
<!-- Details Section -->
|
|
<div class="bg-white q-mb-md q-pa-sm rounded-borders details-section">
|
|
<p class="detail-intro q-mb-md text-grey-8">
|
|
{{ privacyContent.detailIntro }}
|
|
</p>
|
|
|
|
<!-- วัตถุประสงค์ -->
|
|
<div class="q-mb-md">
|
|
<div class="section-header text-blue-grey-10">
|
|
{{ privacyContent.purposes.title }}
|
|
</div>
|
|
<ol class="q-pl-lg text-grey-8 list-style">
|
|
<li
|
|
v-for="(item, index) in privacyContent.purposes.items"
|
|
:key="`p-${index}`"
|
|
class="q-mb-xs"
|
|
>
|
|
{{ item }}
|
|
</li>
|
|
</ol>
|
|
</div>
|
|
|
|
<!-- ข้าพเจ้าทราบและเข้าใจว่า -->
|
|
<div class="q-ml-md q-mb-md">
|
|
<ul class="q-pl-lg text-grey-8 list-style-disc">
|
|
<li
|
|
v-for="(item, index) in privacyContent.understanding.items"
|
|
:key="`u-${index}`"
|
|
class="q-mb-xs"
|
|
>
|
|
{{ item }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<!-- สิทธิ์ของเจ้าของข้อมูล -->
|
|
<div>
|
|
<div class="section-header text-blue-grey-10">
|
|
{{ privacyContent.rights.title }}
|
|
</div>
|
|
<ul class="q-pl-lg text-grey-8 list-style-disc">
|
|
<li
|
|
v-for="(item, index) in privacyContent.rights.items"
|
|
:key="`r-${index}`"
|
|
class="q-mb-xs"
|
|
>
|
|
{{ item }}
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</q-card-section>
|
|
|
|
<!-- Fixed Bottom Section -->
|
|
<q-card-section class="bg-white q-pa-md">
|
|
<q-separator class="q-mb-md" />
|
|
|
|
<!-- Checkbox -->
|
|
<div
|
|
class="consent-box rounded-borders q-pa-md row items-center cursor-pointer"
|
|
:class="{
|
|
'consent-checked': acceptPrivacy,
|
|
'consent-disabled': !hasScrolledToBottom,
|
|
}"
|
|
@click="hasScrolledToBottom && (acceptPrivacy = !acceptPrivacy)"
|
|
>
|
|
<q-checkbox
|
|
v-model="acceptPrivacy"
|
|
color="primary"
|
|
size="md"
|
|
:disable="!hasScrolledToBottom"
|
|
class="q-mr-sm"
|
|
/>
|
|
<span class="col text-grey-9 consent-text">{{
|
|
privacyContent.consentText
|
|
}}</span>
|
|
</div>
|
|
</q-card-section>
|
|
|
|
<!-- Action Buttons -->
|
|
<q-card-actions
|
|
align="center"
|
|
class="bg-white q-pa-md q-gutter-md"
|
|
:class="$q.screen.lt.sm ? 'row-reverse' : ''"
|
|
>
|
|
<q-btn
|
|
:label="privacyContent.buttons.accept"
|
|
color="primary"
|
|
unelevated
|
|
no-caps
|
|
class="action-btn"
|
|
:disable="isAcceptDisabled"
|
|
@click="handleAccept"
|
|
v-close-popup
|
|
/>
|
|
<q-btn
|
|
:label="privacyContent.buttons.decline"
|
|
color="grey-7"
|
|
unelevated
|
|
no-caps
|
|
class="action-btn"
|
|
@click="handleDecline"
|
|
v-close-popup
|
|
/>
|
|
</q-card-actions>
|
|
</q-card>
|
|
</q-dialog>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.privacy-card {
|
|
display: flex;
|
|
flex-direction: column;
|
|
border-radius: 8px;
|
|
border: 1px solid #dee2e6;
|
|
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
|
|
}
|
|
|
|
.main-text {
|
|
font-size: 15px;
|
|
line-height: 1.8;
|
|
text-indent: 2em;
|
|
}
|
|
|
|
.details-section {
|
|
border: 1px solid #e9ecef;
|
|
}
|
|
|
|
.detail-intro {
|
|
font-size: 13px;
|
|
line-height: 1.7;
|
|
text-indent: 2em;
|
|
}
|
|
|
|
.section-header {
|
|
font-weight: 600;
|
|
font-size: 15px;
|
|
margin-bottom: 10px;
|
|
padding-bottom: 6px;
|
|
border-bottom: 1px solid #e9ecef;
|
|
}
|
|
|
|
.list-style,
|
|
.list-style-disc {
|
|
font-size: 13px;
|
|
line-height: 1.8;
|
|
}
|
|
|
|
.list-style {
|
|
list-style-type: decimal;
|
|
}
|
|
|
|
.list-style-disc {
|
|
list-style-type: disc;
|
|
}
|
|
|
|
.consent-box {
|
|
background: #f8f9fa;
|
|
border: 1px solid #ced4da;
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
.consent-box:hover {
|
|
background: #e9ecef;
|
|
}
|
|
|
|
.consent-checked {
|
|
border-color: var(--q-primary);
|
|
background: #e7f1ff;
|
|
}
|
|
|
|
.consent-disabled {
|
|
opacity: 0.7;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.consent-disabled:hover {
|
|
background: #f8f9fa;
|
|
}
|
|
|
|
.consent-text {
|
|
font-size: 13px;
|
|
line-height: 1.5;
|
|
}
|
|
|
|
.action-btn {
|
|
flex: 1;
|
|
max-width: 180px;
|
|
font-weight: 500;
|
|
}
|
|
</style>
|