|
|
<!DOCTYPE html> |
|
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="th" xml:lang="th"> |
|
|
<head> |
|
|
<title>journey</title> |
|
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> |
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0"/> |
|
|
<script src="https://cdn.tailwindcss.com"></script> |
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script> |
|
|
<style type="text/css"> |
|
|
@font-face { |
|
|
font-family: 'THSarabunNew'; |
|
|
src: url('fonts/THSarabunNew.ttf') format('truetype'); |
|
|
font-weight: normal; |
|
|
font-style: normal; |
|
|
unicode-range: U+0E00-0E7F, U+0020-007F, U+00A0-00FF; |
|
|
font-display: swap; |
|
|
} |
|
|
|
|
|
@font-face { |
|
|
font-family: 'THSarabunNew'; |
|
|
src: url('fonts/THSarabunNew Bold.ttf') format('truetype'); |
|
|
font-weight: bold; |
|
|
font-style: normal; |
|
|
unicode-range: U+0E00-0E7F, U+0020-007F, U+00A0-00FF; |
|
|
font-display: swap; |
|
|
} |
|
|
|
|
|
* { |
|
|
font-family: 'THSarabunNew', sans-serif !important; |
|
|
} |
|
|
|
|
|
.ft00 { font-size: 19px; color: #000000; } |
|
|
.ft01 { font-size: 25px; color: #000000; } |
|
|
.ft02 { font-size: 22px; color: #000000; } |
|
|
.ft03 { font-size: 22px; color: #000000; } |
|
|
.ft06 { font-size: 15px; line-height: 18px; color: #000000; } |
|
|
|
|
|
|
|
|
@media print { |
|
|
body { |
|
|
filter: grayscale(100%); |
|
|
} |
|
|
.controls-container { display: none !important; } |
|
|
body { margin: 0 !important; padding: 0 !important; } |
|
|
.page-div { width: 100% !important; |
|
|
height: auto !important; |
|
|
margin: 0 !important; |
|
|
padding: 0 !important; |
|
|
page-break-after: always; } |
|
|
.page-div:last-child { page-break-after: avoid; } |
|
|
.overlay-frame { display: none !important; } |
|
|
} |
|
|
|
|
|
.page-div { |
|
|
position: relative; |
|
|
width: 892px; |
|
|
height: 1261px; |
|
|
background: none; |
|
|
margin: 10px auto; |
|
|
} |
|
|
.page-div:last-child { |
|
|
margin-bottom: 0; |
|
|
} |
|
|
|
|
|
.controls-container { |
|
|
position: fixed; |
|
|
bottom: 16px; |
|
|
left: 16px; |
|
|
background: rgba(255, 255, 255, 0.95); |
|
|
padding: 16px; |
|
|
border-radius: 12px; |
|
|
width: 340px; |
|
|
max-width: calc(100vw - 32px); |
|
|
z-index: 1000; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
gap: 10px; |
|
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15); |
|
|
backdrop-filter: blur(10px); |
|
|
border: 1px solid rgba(255, 255, 255, 0.3); |
|
|
} |
|
|
|
|
|
|
|
|
.custom-dropdown { |
|
|
position: relative; |
|
|
width: 100%; |
|
|
} |
|
|
|
|
|
.dropdown-header { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 10px; |
|
|
padding: 10px 12px; |
|
|
background: white; |
|
|
border: 2px solid #e2e8f0; |
|
|
border-radius: 8px; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s ease; |
|
|
min-height: 48px; |
|
|
} |
|
|
|
|
|
.dropdown-header:hover { |
|
|
border-color: #3b82f6; |
|
|
} |
|
|
|
|
|
.dropdown-header:focus-within { |
|
|
border-color: #3b82f6; |
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.2); |
|
|
} |
|
|
|
|
|
.dropdown-header img { |
|
|
width: 32px; |
|
|
height: 32px; |
|
|
border-radius: 50%; |
|
|
object-fit: cover; |
|
|
flex-shrink: 0; |
|
|
} |
|
|
|
|
|
.dropdown-header-text { |
|
|
flex: 1; |
|
|
font-size: 15px; |
|
|
color: #1e293b; |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
.dropdown-arrow { |
|
|
width: 20px; |
|
|
height: 20px; |
|
|
transition: transform 0.3s ease; |
|
|
flex-shrink: 0; |
|
|
} |
|
|
|
|
|
.dropdown-arrow.open { |
|
|
transform: rotate(180deg); |
|
|
} |
|
|
|
|
|
.dropdown-menu { |
|
|
position: absolute; |
|
|
bottom: calc(100% + 8px); |
|
|
left: 0; |
|
|
right: 0; |
|
|
background: white; |
|
|
border-radius: 12px; |
|
|
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.2); |
|
|
opacity: 0; |
|
|
visibility: hidden; |
|
|
transform: translateY(10px); |
|
|
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); |
|
|
z-index: 1001; |
|
|
overflow: hidden; |
|
|
max-height: 400px; |
|
|
display: flex; |
|
|
flex-direction: column; |
|
|
} |
|
|
|
|
|
.dropdown-menu.open { |
|
|
opacity: 1; |
|
|
visibility: visible; |
|
|
transform: translateY(0); |
|
|
} |
|
|
|
|
|
.search-container { |
|
|
padding: 12px; |
|
|
border-bottom: 1px solid #e2e8f0; |
|
|
background: #f8fafc; |
|
|
position: sticky; |
|
|
top: 0; |
|
|
z-index: 10; |
|
|
} |
|
|
|
|
|
.search-input { |
|
|
width: 100%; |
|
|
padding: 10px 40px 10px 12px; |
|
|
border: 2px solid #e2e8f0; |
|
|
border-radius: 8px; |
|
|
font-size: 15px; |
|
|
outline: none; |
|
|
transition: all 0.2s ease; |
|
|
background: white; |
|
|
} |
|
|
|
|
|
.search-input:focus { |
|
|
border-color: #3b82f6; |
|
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.15); |
|
|
} |
|
|
|
|
|
.search-input::placeholder { |
|
|
color: #94a3b8; |
|
|
} |
|
|
|
|
|
.search-wrapper { |
|
|
position: relative; |
|
|
} |
|
|
|
|
|
.search-icon { |
|
|
position: absolute; |
|
|
right: 12px; |
|
|
top: 50%; |
|
|
transform: translateY(-50%); |
|
|
width: 20px; |
|
|
height: 20px; |
|
|
color: #94a3b8; |
|
|
pointer-events: none; |
|
|
} |
|
|
|
|
|
.clear-search { |
|
|
position: absolute; |
|
|
right: 12px; |
|
|
top: 50%; |
|
|
transform: translateY(-50%); |
|
|
width: 24px; |
|
|
height: 24px; |
|
|
background: #ef4444; |
|
|
color: white; |
|
|
border: none; |
|
|
border-radius: 50%; |
|
|
cursor: pointer; |
|
|
display: none; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
font-size: 14px; |
|
|
font-weight: bold; |
|
|
transition: background 0.2s; |
|
|
} |
|
|
|
|
|
.clear-search:hover { |
|
|
background: #dc2626; |
|
|
} |
|
|
|
|
|
.clear-search.visible { |
|
|
display: flex; |
|
|
} |
|
|
|
|
|
.dropdown-list { |
|
|
overflow-y: auto; |
|
|
max-height: 280px; |
|
|
overscroll-behavior: contain; |
|
|
} |
|
|
|
|
|
.dropdown-list::-webkit-scrollbar { |
|
|
width: 8px; |
|
|
} |
|
|
|
|
|
.dropdown-list::-webkit-scrollbar-track { |
|
|
background: #f1f5f9; |
|
|
} |
|
|
|
|
|
.dropdown-list::-webkit-scrollbar-thumb { |
|
|
background: #cbd5e1; |
|
|
border-radius: 4px; |
|
|
} |
|
|
|
|
|
.dropdown-list::-webkit-scrollbar-thumb:hover { |
|
|
background: #94a3b8; |
|
|
} |
|
|
|
|
|
.dropdown-item { |
|
|
display: flex; |
|
|
align-items: center; |
|
|
gap: 12px; |
|
|
padding: 12px 16px; |
|
|
cursor: pointer; |
|
|
transition: all 0.15s ease; |
|
|
border-bottom: 1px solid #f1f5f9; |
|
|
} |
|
|
|
|
|
.dropdown-item:last-child { |
|
|
border-bottom: none; |
|
|
} |
|
|
|
|
|
.dropdown-item:hover { |
|
|
background: #f0f9ff; |
|
|
} |
|
|
|
|
|
.dropdown-item.selected { |
|
|
background: #eff6ff; |
|
|
} |
|
|
|
|
|
.dropdown-item.active { |
|
|
background: #dbeafe; |
|
|
} |
|
|
|
|
|
.dropdown-item-image { |
|
|
width: 40px; |
|
|
height: 40px; |
|
|
border-radius: 50%; |
|
|
object-fit: cover; |
|
|
flex-shrink: 0; |
|
|
border: 2px solid #e2e8f0; |
|
|
} |
|
|
|
|
|
.dropdown-item-content { |
|
|
flex: 1; |
|
|
min-width: 0; |
|
|
} |
|
|
|
|
|
.dropdown-item-title { |
|
|
font-size: 14px; |
|
|
font-weight: 600; |
|
|
color: #1e293b; |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
.dropdown-item-subtitle { |
|
|
font-size: 12px; |
|
|
color: #64748b; |
|
|
white-space: nowrap; |
|
|
overflow: hidden; |
|
|
text-overflow: ellipsis; |
|
|
} |
|
|
|
|
|
.dropdown-item-checkbox { |
|
|
flex-shrink: 0; |
|
|
} |
|
|
|
|
|
.custom-checkbox { |
|
|
width: 22px; |
|
|
height: 22px; |
|
|
border: 2px solid #cbd5e1; |
|
|
border-radius: 6px; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s ease; |
|
|
background: white; |
|
|
} |
|
|
|
|
|
.custom-checkbox:hover { |
|
|
border-color: #3b82f6; |
|
|
} |
|
|
|
|
|
.custom-checkbox.checked { |
|
|
background: #3b82f6; |
|
|
border-color: #3b82f6; |
|
|
} |
|
|
|
|
|
.custom-checkbox svg { |
|
|
width: 14px; |
|
|
height: 14px; |
|
|
color: white; |
|
|
opacity: 0; |
|
|
transform: scale(0.5); |
|
|
transition: all 0.2s ease; |
|
|
} |
|
|
|
|
|
.custom-checkbox.checked svg { |
|
|
opacity: 1; |
|
|
transform: scale(1); |
|
|
} |
|
|
|
|
|
.dropdown-actions { |
|
|
padding: 12px; |
|
|
border-top: 1px solid #e2e8f0; |
|
|
background: #f8fafc; |
|
|
display: flex; |
|
|
gap: 8px; |
|
|
flex-wrap: wrap; |
|
|
} |
|
|
|
|
|
.action-btn { |
|
|
flex: 1; |
|
|
min-width: 100px; |
|
|
padding: 10px 16px; |
|
|
border: none; |
|
|
border-radius: 8px; |
|
|
font-size: 14px; |
|
|
font-weight: 600; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s ease; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
gap: 6px; |
|
|
} |
|
|
|
|
|
.action-btn:active { |
|
|
transform: scale(0.98); |
|
|
} |
|
|
|
|
|
.btn-select-all { |
|
|
background: #e2e8f0; |
|
|
color: #475569; |
|
|
} |
|
|
|
|
|
.btn-select-all:hover { |
|
|
background: #cbd5e1; |
|
|
} |
|
|
|
|
|
.btn-clear-selection { |
|
|
background: #fee2e2; |
|
|
color: #dc2626; |
|
|
} |
|
|
|
|
|
.btn-clear-selection:hover { |
|
|
background: #fecaca; |
|
|
} |
|
|
|
|
|
.selected-count { |
|
|
padding: 8px 12px; |
|
|
background: #dbeafe; |
|
|
color: #1d4ed8; |
|
|
border-radius: 8px; |
|
|
font-size: 13px; |
|
|
font-weight: 600; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
.no-results { |
|
|
padding: 40px 20px; |
|
|
text-align: center; |
|
|
color: #94a3b8; |
|
|
} |
|
|
|
|
|
.no-results svg { |
|
|
width: 48px; |
|
|
height: 48px; |
|
|
margin: 0 auto 12px; |
|
|
opacity: 0.5; |
|
|
} |
|
|
|
|
|
|
|
|
.control-btn { |
|
|
padding: 12px 16px; |
|
|
border-radius: 8px; |
|
|
font-size: 15px; |
|
|
font-weight: 600; |
|
|
cursor: pointer; |
|
|
transition: all 0.2s ease; |
|
|
border: none; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
gap: 8px; |
|
|
min-height: 48px; |
|
|
} |
|
|
|
|
|
.control-btn:active { |
|
|
transform: scale(0.98); |
|
|
} |
|
|
|
|
|
.control-btn:disabled { |
|
|
opacity: 0.5; |
|
|
cursor: not-allowed; |
|
|
} |
|
|
|
|
|
.btn-grayscale { |
|
|
background: #6b7280; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.btn-grayscale:hover:not(:disabled) { |
|
|
background: #4b5563; |
|
|
} |
|
|
|
|
|
.btn-download-current { |
|
|
background: white; |
|
|
color: #1e293b; |
|
|
border: 2px solid #e2e8f0; |
|
|
} |
|
|
|
|
|
.btn-download-current:hover:not(:disabled) { |
|
|
background: #f8fafc; |
|
|
border-color: #cbd5e1; |
|
|
} |
|
|
|
|
|
.btn-download-selected { |
|
|
background: #3b82f6; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.btn-download-selected:hover:not(:disabled) { |
|
|
background: #2563eb; |
|
|
} |
|
|
|
|
|
.btn-download-all { |
|
|
background: #10b981; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.btn-download-all:hover:not(:disabled) { |
|
|
background: #059669; |
|
|
} |
|
|
|
|
|
.btn-randomize { |
|
|
background: #8b5cf6; |
|
|
color: white; |
|
|
} |
|
|
|
|
|
.btn-randomize:hover:not(:disabled) { |
|
|
background: #7c3aed; |
|
|
} |
|
|
|
|
|
.overlay-frame { |
|
|
width: 300px; |
|
|
height: 320px; |
|
|
border: none; |
|
|
position: absolute; |
|
|
overflow: hidden; |
|
|
z-index: 50; |
|
|
background: transparent; |
|
|
} |
|
|
|
|
|
.overlay-image-container { |
|
|
width: 260px; |
|
|
height: 150px; |
|
|
background: transparent; |
|
|
display: flex; |
|
|
align-items: center; |
|
|
justify-content: center; |
|
|
position: absolute; |
|
|
transition: all 0.8s cubic-bezier(0.4, 0, 0.2, 1); |
|
|
transform-origin: center; |
|
|
} |
|
|
|
|
|
.overlay-image-container img { |
|
|
position: absolute; |
|
|
top: 0; |
|
|
left: 0; |
|
|
width: 100%; |
|
|
height: 100%; |
|
|
object-fit: cover; |
|
|
} |
|
|
|
|
|
#page1-overlay { |
|
|
top: 700px; |
|
|
right: 320px; |
|
|
} |
|
|
#page2-overlay { |
|
|
top: 1000px; |
|
|
left: 500px; |
|
|
} |
|
|
|
|
|
|
|
|
@media (max-width: 480px) { |
|
|
.controls-container { |
|
|
width: calc(100% - 32px); |
|
|
left: 16px; |
|
|
bottom: 16px; |
|
|
padding: 12px; |
|
|
} |
|
|
|
|
|
.dropdown-menu { |
|
|
max-height: 350px; |
|
|
} |
|
|
|
|
|
.dropdown-list { |
|
|
max-height: 200px; |
|
|
} |
|
|
|
|
|
.overlay-frame { |
|
|
width: 250px; |
|
|
height: 260px; |
|
|
} |
|
|
.overlay-image-container { |
|
|
width: 200px; |
|
|
height: 120px; |
|
|
} |
|
|
.stamp-text { |
|
|
font-size: 12px; |
|
|
} |
|
|
#page1-overlay { |
|
|
top: 700px; |
|
|
right: 320px; |
|
|
} |
|
|
#page2-overlay { |
|
|
top: 1000px; |
|
|
left: 500px; |
|
|
} |
|
|
.page-div { |
|
|
width: 100%; |
|
|
height: auto; |
|
|
margin: 10px 0; |
|
|
} |
|
|
|
|
|
.control-btn { |
|
|
font-size: 14px; |
|
|
padding: 10px 12px; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
.loading-spinner { |
|
|
width: 20px; |
|
|
height: 20px; |
|
|
border: 2px solid transparent; |
|
|
border-top-color: currentColor; |
|
|
border-radius: 50%; |
|
|
animation: spin 0.8s linear infinite; |
|
|
} |
|
|
|
|
|
@keyframes spin { |
|
|
to { transform: rotate(360deg); } |
|
|
} |
|
|
|
|
|
|
|
|
.progress-container { |
|
|
display: none; |
|
|
padding: 12px; |
|
|
background: #f0fdf4; |
|
|
border-radius: 8px; |
|
|
border: 1px solid #bbf7d0; |
|
|
} |
|
|
|
|
|
.progress-container.visible { |
|
|
display: block; |
|
|
} |
|
|
|
|
|
.progress-bar { |
|
|
height: 8px; |
|
|
background: #e2e8f0; |
|
|
border-radius: 4px; |
|
|
overflow: hidden; |
|
|
margin-bottom: 8px; |
|
|
} |
|
|
|
|
|
.progress-fill { |
|
|
height: 100%; |
|
|
background: linear-gradient(90deg, #10b981, #34d399); |
|
|
border-radius: 4px; |
|
|
transition: width 0.3s ease; |
|
|
} |
|
|
|
|
|
.progress-text { |
|
|
font-size: 13px; |
|
|
color: #166534; |
|
|
text-align: center; |
|
|
} |
|
|
|
|
|
|
|
|
.highlight { |
|
|
background: #fef08a; |
|
|
padding: 0 2px; |
|
|
border-radius: 2px; |
|
|
} |
|
|
</style> |
|
|
</head> |
|
|
<body class="bg-gray-100"> |
|
|
<div class="controls-container" role="region" aria-label="Controls"> |
|
|
|
|
|
<div class="custom-dropdown" id="customDropdown"> |
|
|
<div class="dropdown-header" |
|
|
id="dropdownHeader" |
|
|
tabindex="0" |
|
|
role="combobox" |
|
|
aria-expanded="false" |
|
|
aria-haspopup="listbox" |
|
|
aria-label="เลือกพนักงาน"> |
|
|
<img id="dropdownProfilePic" src="https://via.placeholder.com/32?text=..." alt="Profile"/> |
|
|
<span class="dropdown-header-text" id="selectedText">กรุณาเลือกพนักงาน</span> |
|
|
<svg class="dropdown-arrow" id="dropdownArrow" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<polyline points="6,9 12,15 18,9"></polyline> |
|
|
</svg> |
|
|
</div> |
|
|
<div class="dropdown-menu" id="dropdownMenu" role="listbox" aria-label="รายชื่อพนักงาน"> |
|
|
<div class="search-container"> |
|
|
<div class="search-wrapper"> |
|
|
<input type="text" |
|
|
class="search-input" |
|
|
id="searchInput" |
|
|
placeholder="ค้นหา ชื่อ, เลขที่, หรือ ID..." |
|
|
aria-label="ค้นหาพนักงาน" |
|
|
autocomplete="off"/> |
|
|
<svg class="search-icon" id="searchIcon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<circle cx="11" cy="11" r="8"></circle> |
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line> |
|
|
</svg> |
|
|
<button class="clear-search" id="clearSearch" aria-label="ล้างการค้นหา">×</button> |
|
|
</div> |
|
|
</div> |
|
|
<div class="dropdown-list" id="dropdownList"> |
|
|
|
|
|
</div> |
|
|
<div class="dropdown-actions"> |
|
|
<div class="selected-count" id="selectedCount">เลือกแล้ว 0 รายการ</div> |
|
|
<button class="action-btn btn-select-all" id="selectAllBtn" aria-label="เลือกทั้งหมด"> |
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<polyline points="9,11 12,14 22,4"></polyline> |
|
|
<path d="M21,12v7a2,2,0,0,1-2,2H5a2,2,0,0,1-2-2V5A2,2,0,0,1,5,3h11"></path> |
|
|
</svg> |
|
|
เลือกทั้งหมด |
|
|
</button> |
|
|
<button class="action-btn btn-clear-selection" id="clearSelectionBtn" aria-label="ล้างการเลือก"> |
|
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<line x1="18" y1="6" x2="6" y2="18"></line> |
|
|
<line x1="6" y1="6" x2="18" y2="18"></line> |
|
|
</svg> |
|
|
ล้าง |
|
|
</button> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div class="progress-container" id="progressContainer"> |
|
|
<div class="progress-bar"> |
|
|
<div class="progress-fill" id="progressFill" style="width: 0%"></div> |
|
|
</div> |
|
|
<div class="progress-text" id="progressText">กำลังดาวน์โหลด...</div> |
|
|
</div> |
|
|
|
|
|
|
|
|
<button type="button" id="grayscaleBtn" class="control-btn btn-grayscale"> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<circle cx="12" cy="12" r="10"></circle> |
|
|
<path d="M12 2a10 10 0 0 1 0 20"></path> |
|
|
</svg> |
|
|
Grayscale: ปิด |
|
|
</button> |
|
|
|
|
|
<button id="downloadCurrentBtn" class="control-btn btn-download-current"> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> |
|
|
<polyline points="7,10 12,15 17,10"></polyline> |
|
|
<line x1="12" y1="15" x2="12" y2="3"></line> |
|
|
</svg> |
|
|
ดาวน์โหลด PDF ปัจจุบัน |
|
|
</button> |
|
|
|
|
|
<button id="downloadSelectedBtn" class="control-btn btn-download-selected" disabled> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> |
|
|
<polyline points="7,10 12,15 17,10"></polyline> |
|
|
<line x1="12" y1="15" x2="12" y2="3"></line> |
|
|
</svg> |
|
|
ดาวน์โหลด PDF ที่เลือก (0) |
|
|
</button> |
|
|
|
|
|
<button id="downloadAllBtn" class="control-btn btn-download-all"> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> |
|
|
<polyline points="7,10 12,15 17,10"></polyline> |
|
|
<line x1="12" y1="15" x2="12" y2="3"></line> |
|
|
</svg> |
|
|
ดาวน์โหลด PDF ทั้งหมด |
|
|
</button> |
|
|
|
|
|
<button id="randomizeBtn" class="control-btn btn-randomize"> |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<polyline points="16,3 21,3 21,8"></polyline> |
|
|
<line x1="4" y1="20" x2="21" y2="3"></line> |
|
|
<polyline points="21,16 21,21 16,21"></polyline> |
|
|
<line x1="15" y1="15" x2="21" y2="21"></line> |
|
|
<line x1="4" y1="4" x2="9" y2="9"></line> |
|
|
</svg> |
|
|
สุ่มตำแหน่งภาพ |
|
|
</button> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="page1-div" class="page-div"> |
|
|
<img width="892" height="1261" src="bg3.svg" alt="Background"/> |
|
|
<div id="overlayContainer1" class="overlay-frame" style="width: 300px; height: 200px; position: absolute; top: 700px; right: 320px;"></div> |
|
|
<img class="absolute top-[46px] left-[725px] w-[110px] h-[138px] object-cover z-[100]" id="profilePic" src="https://via.placeholder.com/110x138?text=Loading" alt="Profile Picture"/> |
|
|
<img class="absolute top-[977px] left-[762.5px] w-[69px] h-[69px] object-cover" id="qrCode" src="https://via.placeholder.com/69?text=Loading" alt="QR Code"/> |
|
|
<p class="absolute top-[32px] left-[134px] whitespace-nowrap text-[21px] font-bold">ทะเบียนใบอนุญาตทำงานของคนต่างด้าวตามมติคณะรัฐมนตรี เมื่อวันที่ 24 กันยายน 2567</p> |
|
|
<p class="absolute top-[57px] left-[134px] whitespace-nowrap text-[21px] font-bold">เอกสารฉบับนี้ใช้แทนใบอนุญาตทำงาน</p> |
|
|
<p class="absolute top-[87px] left-[158px] whitespace-nowrap text-[15px]">เลขรับที่ (No.)</p> |
|
|
<p class="absolute top-[87px] left-[224px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[87px] left-[238px] whitespace-nowrap text-[14px] font-bold" id="requestNumber">xxxxxxx</p> |
|
|
<p class="absolute top-[87px] left-[417px] whitespace-nowrap text-[15px]">วันที่อนุมัติ (Date)</p> |
|
|
<p class="absolute top-[87px] left-[500px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[87px] left-[514px] whitespace-nowrap text-[15px] font-bold">06 มีนาคม 2568</p> |
|
|
<p class="absolute top-[114px] left-[62px] whitespace-nowrap text-[15px]">ชื่อคนต่างด้าว (Name of Applicant)</p> |
|
|
<p class="absolute top-[114px] left-[224px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[114px] left-[238px] whitespace-nowrap text-[14px] font-bold" id="englishName">xxxxxxxxxxxxx</p> |
|
|
<p class="absolute top-[140px] left-[94px] whitespace-nowrap text-[15px]">เจ้าหน้าที่ (Name of Officer)</p> |
|
|
<p class="absolute top-[140px] left-[224px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[140px] left-[238px] whitespace-nowrap text-[15px] font-bold">นายสมมาตร อนันต์ธราทรัพย์</p> |
|
|
<p class="absolute top-[140px] left-[440px] whitespace-nowrap text-[15px]">นายทะเบียน</p> |
|
|
<p class="absolute top-[140px] left-[500px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[167px] left-[238px] whitespace-nowrap text-[15px]">จัดหางานจังหวัดระยอง</p> |
|
|
<p class="absolute top-[163px] left-[449px] whitespace-nowrap text-[15px]">(Registrar)</p> |
|
|
<p class="absolute top-[163px] left-[546px] whitespace-nowrap text-[15px]">นายสมชาย มรกตศรีวรรณ</p> |
|
|
<p class="absolute top-[182px] left-[555px] whitespace-nowrap text-[15px]">อธิบดีกรมการจัดหางาน</p> |
|
|
<p class="absolute top-[201px] left-[577px] whitespace-nowrap text-[15px]">นายทะเบียน</p> |
|
|
<p class="absolute top-[227px] left-[171px] whitespace-nowrap text-[16px] font-bold">ลงเลขรับและชำระค่ายื่นแบบคำขอ (REGISTERING APPLICATION FORM AND PAYING APPLICATION FEE)</p> |
|
|
<p class="absolute top-[254px] left-[55px] whitespace-nowrap text-[15px] font-bold leading-[21px]">ข้อมูลคนต่างด้าว</p> |
|
|
<p class="absolute top-[278px] left-[55px] whitespace-nowrap text-[14px]">สถานะใบอนุญาต</p> |
|
|
<p class="absolute top-[278px] left-[199px] whitespace-nowrap text-[14px]">: อนุมัติ (รอพิมพ์บัตร)</p> |
|
|
<p class="absolute top-[278px] left-[440px] whitespace-nowrap text-[14px]">ออกให้ ณ จังหวัด</p> |
|
|
<p class="absolute top-[278px] left-[586px] whitespace-nowrap text-[14px]">: สำนักงานจัดหางานจังหวัดระยอง</p> |
|
|
<p class="absolute top-[300px] left-[55px] whitespace-nowrap text-[14px]">เลขประจำตัวคนต่างด้าว</p> |
|
|
<p class="absolute top-[300px] left-[199px] whitespace-nowrap text-[14px]" id="personalID">: 6685490000472</p> |
|
|
<p class="absolute top-[300px] left-[440px] whitespace-nowrap text-[14px]">ใบอนุญาตทำงานเลขที่</p> |
|
|
<p class="absolute top-[300px] left-[586px] whitespace-nowrap text-[14px]" id="workPermitNumber">: 5400689000472</p> |
|
|
<p class="absolute top-[321px] left-[55px] whitespace-nowrap text-[14px]">ชื่อภาษาไทย</p> |
|
|
<p class="absolute top-[321px] left-[199px] whitespace-nowrap text-[14px]" id="thaiName">: นาง เมย์ เท็ท โช</p> |
|
|
<p class="absolute top-[321px] left-[440px] whitespace-nowrap text-[14px]">ชื่อภาษาอังกฤษ</p> |
|
|
<p class="absolute top-[321px] left-[586px] whitespace-nowrap text-[14px]">:</p> |
|
|
<p class="absolute top-[321px] left-[592px] whitespace-nowrap text-[14px]" id="englishNameDuplicate">MRS. MAY THET CHO</p> |
|
|
<p class="absolute top-[343px] left-[55px] whitespace-nowrap text-[14px]">วัน/เดือน/ปี (พ.ศ.) เกิด</p> |
|
|
<p class="absolute top-[343px] left-[199px] whitespace-nowrap text-[14px]" id="birthDate">: xx/xx/xx</p> |
|
|
<p class="absolute top-[343px] left-[440px] whitespace-nowrap text-[14px]">อายุ (ปี)</p> |
|
|
<p class="absolute top-[343px] left-[586px] whitespace-nowrap text-[14px]" id="age">: xx</p> |
|
|
<p class="absolute top-[365px] left-[55px] whitespace-nowrap text-[14px]">สัญชาติ</p> |
|
|
<p class="absolute top-[365px] left-[199px] whitespace-nowrap text-[14px]" id="nationality">: เมียนมา</p> |
|
|
<p class="absolute top-[365px] left-[440px] whitespace-nowrap text-[14px]">สถานภาพ</p> |
|
|
<p class="absolute top-[365px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[386px] left-[55px] whitespace-nowrap text-[14px]">ชื่อ-สกุล บิดา</p> |
|
|
<p class="absolute top-[386px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[386px] left-[440px] whitespace-nowrap text-[14px]">ชื่อ-สกุล มารดา</p> |
|
|
<p class="absolute top-[386px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[408px] left-[55px] whitespace-nowrap text-[14px]">เลขอ้างอิงคนต่างด้าว</p> |
|
|
<p class="absolute top-[408px] left-[199px] whitespace-nowrap text-[14px]" id="alienReferenceNumber">: xxxxxxxxxxxxx</p> |
|
|
<p class="absolute top-[429px] left-[55px] whitespace-nowrap text-[14px]">ที่อยู่อาศัย</p> |
|
|
<p class="absolute top-[429px] left-[199px] whitespace-nowrap text-[14px]">: 36/6 หมู่ที่ 8 ตำบลมาบข่า อำเภอนิคมพัฒนา จังหวัดระยอง 21180</p> |
|
|
<p class="absolute top-[449px] left-[55px] whitespace-nowrap text-[15px] font-bold leading-[21px]">ข้อมูลหนังสือเดินทาง และข้อมูลการตรวจลงตรา</p> |
|
|
<p class="absolute top-[469px] left-[55px] whitespace-nowrap text-[14px]">เลขที่หนังสือเดินทาง</p> |
|
|
<p class="absolute top-[472px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[472px] left-[440px] whitespace-nowrap text-[14px]">ประเภทหนังสือเดินทาง</p> |
|
|
<p class="absolute top-[472px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[494px] left-[55px] whitespace-nowrap text-[14px]">สถานที่ออกหนังสือเดินทาง</p> |
|
|
<p class="absolute top-[494px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[494px] left-[440px] whitespace-nowrap text-[14px]">ประเทศที่ออกหนังสือเดินทาง</p> |
|
|
<p class="absolute top-[494px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[516px] left-[55px] whitespace-nowrap text-[14px]">วันที่ออกหนังสือเดินทาง</p> |
|
|
<p class="absolute top-[516px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[516px] left-[440px] whitespace-nowrap text-[14px]">วันหมดอายุ</p> |
|
|
<p class="absolute top-[516px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[537px] left-[55px] whitespace-nowrap text-[14px]">เลขที่ตรวจลงตรา</p> |
|
|
<p class="absolute top-[537px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[559px] left-[55px] whitespace-nowrap text-[14px]">ออกให้วันที่</p> |
|
|
<p class="absolute top-[559px] left-[199px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[559px] left-[440px] whitespace-nowrap text-[14px]">ใช้ได้ถึงวันที่</p> |
|
|
<p class="absolute top-[559px] left-[586px] whitespace-nowrap text-[14px]">: -</p> |
|
|
<p class="absolute top-[578px] left-[55px] whitespace-nowrap text-[15px] font-bold leading-[21px]">ข้อมูลนายจ้าง/สถานประกอบการ</p> |
|
|
<p class="absolute top-[598px] left-[55px] whitespace-nowrap text-[14px]">เลขประจำตัวนายจ้าง</p> |
|
|
<p class="absolute top-[602px] left-[199px] whitespace-nowrap text-[14px]">: 0415567000061</p> |
|
|
<p class="absolute top-[602px] left-[440px] whitespace-nowrap text-[14px]">ชื่อนายจ้าง/สถานประกอบการ</p> |
|
|
<p class="absolute top-[602px] left-[586px] whitespace-nowrap text-[14px]">: บริษัท บาน กง เอ็นจิเนียริ่ง จำกัด</p> |
|
|
<p class="absolute top-[623px] left-[55px] whitespace-nowrap text-[14px]">ประเภทกิจการ</p> |
|
|
<p class="absolute top-[623px] left-[199px] whitespace-nowrap text-[14px]">: BT04 - กิจการก่อสร้าง</p> |
|
|
<p class="absolute top-[645px] left-[55px] whitespace-nowrap text-[14px]">ที่ตั้งสำนักงาน</p> |
|
|
<p class="absolute top-[645px] left-[199px] whitespace-nowrap text-[14px]">: 102 หมู่ที่ 8 ถนนอุดรธานี-ขอนแก่น ตำบลโนนสูง อำเภอเมืองอุดรธานี จังหวัดอุดรธานี 41000</p> |
|
|
<p class="absolute top-[666px] left-[55px] whitespace-nowrap text-[15px] font-bold leading-[21px]">ข้อมูลการทำงาน</p> |
|
|
<p class="absolute top-[684px] left-[55px] whitespace-nowrap text-[14px]">ทำงานในตำแหน่ง</p> |
|
|
<p class="absolute top-[688px] left-[199px] whitespace-nowrap text-[14px]">: กรรมกร</p> |
|
|
<p class="absolute top-[688px] left-[440px] whitespace-nowrap text-[14px]">ลักษณะงาน</p> |
|
|
<p class="absolute top-[688px] left-[586px] whitespace-nowrap text-[14px]">: กรรมกร (กิจการก่อสร้าง)</p> |
|
|
<p class="absolute top-[710px] left-[55px] whitespace-nowrap text-[14px]">สถานที่ทำงาน</p> |
|
|
<p class="absolute top-[710px] left-[199px] whitespace-nowrap text-[14px]">: 36/6 หมู่ที่ 8 ตำบลมาบข่า อำเภอนิคมพัฒนา จังหวัดระยอง 21180</p> |
|
|
<p class="absolute top-[731px] left-[55px] whitespace-nowrap text-[14px]">อนุญาตให้ทำงานถึงวันที่</p> |
|
|
<p class="absolute top-[731px] left-[199px] whitespace-nowrap text-[14px]">: 31 มีนาคม 2569</p> |
|
|
<p class="absolute top-[755px] left-[55px] whitespace-nowrap text-[15px] font-bold leading-[21px]">ข้อมูลสิทธิการรักษาพยาบาล</p> |
|
|
<p class="absolute top-[775px] left-[55px] whitespace-nowrap text-[15px] leading-[21px]">ประกันสังคม</p> |
|
|
<p class="absolute top-[796px] left-[55px] whitespace-nowrap text-[15px] leading-[21px]">ประกันสุขภาพ สิ้นสุดวันที่ 30/09/2025</p> |
|
|
<p class="absolute top-[825px] left-[55px] whitespace-nowrap text-[14px] font-bold leading-[19px]">เงื่อนไข</p> |
|
|
<p class="absolute top-[841px] left-[85px] whitespace-nowrap text-[14px] leading-[19px]">คนต่างด้าวจะต้องทำประกันสุขภาพตลอดระยะเวลาการอนุญาตให้ทำงาน หากปรากฎว่าระยะเวลาการทำประกันสุขภาพสิ้นสุดลง ก่อนระยะเวลาการอนุญาตให้ทำงาน</p> |
|
|
<p class="absolute top-[857px] left-[55px] whitespace-nowrap text-[14px] leading-[19px]">นายทะเบียนจะเพิกถอนใบอนุญาตทำงาน ซึ่งมีผลให้การอนุญาตให้อยู่ในราชอาณาจักรสิ้นสุดลง</p> |
|
|
<p class="absolute top-[885px] left-[55px] whitespace-nowrap text-[14px] font-bold leading-[19px]">คำเตือน</p> |
|
|
<p class="absolute top-[905px] left-[85px] whitespace-nowrap text-[14px] leading-[19px]">เมื่อได้รับอนุญาตให้ทำงานแล้วคนต่างด้าวต้องดำเนินการดังต่อไปนี้ มิเช่นนั้น การอนุญาตให้ทำงานและการอนุญาตให้อยู่ในราชอาณาจักรของคนต่างด้าวจะสิ้นสุดลง</p> |
|
|
<p class="absolute top-[922px] left-[55px] whitespace-nowrap text-[14px] leading-[19px]">1. จัดเก็บข้อมูลอัตลักษณ์บุคคล ภายในวันที่ 28 มิถุนายน 2568</p> |
|
|
<p class="absolute top-[939px] left-[55px] whitespace-nowrap text-[14px] leading-[19px]">2. จัดทำหรือปรับปรุงทะเบียนประวัติตามกฎหมายว่าด้วยการทะเบียนราษฎร ภายในวันที่ 31 มีนาคม 2569</p> |
|
|
<p class="absolute top-[1000px] left-[55px] text-[14px] leading-[19px]" id="timestamp">Loading...</p> |
|
|
</div> |
|
|
|
|
|
|
|
|
<div id="page2-div" class="page-div"> |
|
|
<img width="892" height="1261" src="bg2.svg" alt="Receipt Background"/> |
|
|
<div id="overlayContainer2" class="overlay-frame" style="position: absolute; top: 1000px; left: 500px;"></div> |
|
|
<img class="absolute top-[925px] left-[120px] w-[90px] h-[90px] object-cover" id="receiptQrCode" src="https://via.placeholder.com/90?text=Loading" alt="Receipt QR Code"/> |
|
|
<p style="position:absolute;top:147px;left:86px;white-space:nowrap" class="ft00">กรมการจัดหางาน</p> |
|
|
<p style="position:absolute;top:170px;left:88px;white-space:nowrap" class="ft00">กระทรวงแรงงาน</p> |
|
|
<p style="position:absolute;top:90px;left:397px;white-space:nowrap" class="ft01"><b>ใบเสร็จรับเงิน</b></p> |
|
|
<p style="position:absolute;top:120px;left:418px;white-space:nowrap" class="ft01"><b>ต้นฉบับ</b></p> |
|
|
<p style="position:absolute;top:60px;left:598px;white-space:nowrap" class="ft00">เลขที่</p> |
|
|
<p style="position:absolute;top:60px;left:640px;white-space:nowrap" class="ft00" id="receiptNumberReceipt">xxxxxxx</p> |
|
|
<p style="position:absolute;top:149px;left:582px;white-space:nowrap" class="ft00">ที่ทำการ   สำนักบริหารแรงงานต่างด้าว</p> |
|
|
<p style="position:absolute;top:188px;left:602px;white-space:nowrap" class="ft00">วันที่   19 มีนาคม 2568</p> |
|
|
<p style="position:absolute;top:227px;left:540px;white-space:nowrap" class="ft00">เลขที่ใบชำระเงิน  </p> |
|
|
<p style="position:absolute;top:227px;left:640px;white-space:nowrap" class="ft00" id="paymentNumberReceipt">IV680329/002308</p> |
|
|
<p style="position:absolute;top:271px;left:60px;white-space:nowrap" class="ft00">เลขรับคำขอที่</p> |
|
|
<p style="position:absolute;top:271px;left:180px;white-space:nowrap" class="ft00" id="requestNumberReceipt">xxxxxxx</p> |
|
|
<p style="position:absolute;top:310px;left:60px;white-space:nowrap" class="ft00">ชื่อผู้ชำระเงิน</p> |
|
|
<p style="position:absolute;top:310px;left:180px;white-space:nowrap" class="ft00" id="payerNameReceipt">xxxxxxxxxxxxx</p> |
|
|
<p style="position:absolute;top:310px;left:471px;white-space:nowrap" class="ft00">สัญชาติ</p> |
|
|
<p style="position:absolute;top:310px;left:520px;white-space:nowrap" class="ft00" id="nationalityReceipt">เมียนมา</p> |
|
|
<p style="position:absolute;top:354px;left:60px;white-space:nowrap" class="ft00">เลขอ้างอิงคนต่างด้าว</p> |
|
|
<p style="position:absolute;top:354px;left:180px;white-space:nowrap" class="ft00" id="alienReferenceReceipt">xxxxxxxxxxxxx</p> |
|
|
<p style="position:absolute;top:354px;left:432px;white-space:nowrap" class="ft00">หมายเลขประจำตัวคนต่างด้าว</p> |
|
|
<p style="position:absolute;top:354px;left:640px;white-space:nowrap" class="ft00" id="personalIDReceipt">xxxxxxxxxxxxx</p> |
|
|
<p style="position:absolute;top:399px;left:60px;white-space:nowrap" class="ft00">ชื่อนายจ้าง / สถานประกอบการ   บริษัท บาน กง เอ็นจิเนียริ่ง จำกัด</p> |
|
|
<p style="position:absolute;top:438px;left:60px;white-space:nowrap" class="ft00">เลขประจำตัวนายจ้าง</p> |
|
|
<p style="position:absolute;top:437px;left:233px;white-space:nowrap" class="ft00">  0415567000061</p> |
|
|
<p style="position:absolute;top:526px;left:345px;white-space:nowrap" class="ft02"><b>รายการ</b></p> |
|
|
<p style="position:absolute;top:526px;left:688px;white-space:nowrap" class="ft02"><b>จำนวนเงิน</b></p> |
|
|
<p style="position:absolute;top:572px;left:118px;white-space:nowrap" class="ft03">1. ค่าธรรมเนียมในการยื่นคำขอ ฉบับละ 100 บาท</p> |
|
|
<p style="position:absolute;top:572px;left:736px;white-space:nowrap" class="ft03">100.00</p> |
|
|
<p style="position:absolute;top:616px;left:118px;white-space:nowrap" class="ft03">2. ค่าธรรมเนียมใบอนุญาตทำงาน</p> |
|
|
<p style="position:absolute;top:616px;left:736px;white-space:nowrap" class="ft03">900.00</p> |
|
|
<p style="position:absolute;top:694px;left:97px;white-space:nowrap" class="ft03"> </p> |
|
|
<p style="position:absolute;top:694px;left:648px;white-space:nowrap" class="ft03"> </p> |
|
|
<p style="position:absolute;top:772px;left:174px;white-space:nowrap" class="ft02"><b>รวมเป็นเงินทั้งสิ้น (บาท)</b></p> |
|
|
<p style="position:absolute;top:799px;left:188px;white-space:nowrap" class="ft02"><b>( หนึ่งพันบาทถ้วน )</b></p> |
|
|
<p style="position:absolute;top:786px;left:385px;white-space:nowrap" class="ft03"> </p> |
|
|
<p style="position:absolute;top:774px;left:722px;white-space:nowrap" class="ft02"><b>1,000.00</b></p> |
|
|
<p style="position:absolute;top:894px;left:94px;white-space:nowrap" class="ft00">ได้รับเงินไว้เป็นการถูกต้องแล้ว</p> |
|
|
<p style="position:absolute;top:977px;left:481px;white-space:nowrap" class="ft00">(ลงชื่อ)</p> |
|
|
<p style="position:absolute;top:977px;left:564px;white-space:nowrap" class="ft00">นางสาวอารีวรรณ โพธิ์นิ่มแดง</p> |
|
|
<p style="position:absolute;top:977px;left:762px;white-space:nowrap" class="ft00">(ผู้รับเงิน)</p> |
|
|
<p style="position:absolute;top:1017px;left:473px;white-space:nowrap" class="ft00">ตำแหน่ง</p> |
|
|
<p style="position:absolute;top:1016px;left:562px;white-space:nowrap" class="ft00">นักวิชาการแรงงานชำนาญการ</p> |
|
|
<p style="position:absolute;top:1133px;left:55px;white-space:nowrap" class="ft06" id="receiptTimestamp">Loading...</p> |
|
|
</div> |
|
|
|
|
|
<script type="text/javascript"> |
|
|
let allWorkerData = []; |
|
|
let currentIndex = 0; |
|
|
let isGrayscaleEnabled = false; |
|
|
let selectedWorkers = new Set(); |
|
|
let isDropdownOpen = false; |
|
|
let filteredData = []; |
|
|
|
|
|
|
|
|
const dropdownHeader = document.getElementById('dropdownHeader'); |
|
|
const dropdownMenu = document.getElementById('dropdownMenu'); |
|
|
const dropdownArrow = document.getElementById('dropdownArrow'); |
|
|
const dropdownList = document.getElementById('dropdownList'); |
|
|
const searchInput = document.getElementById('searchInput'); |
|
|
const searchIcon = document.getElementById('searchIcon'); |
|
|
const clearSearch = document.getElementById('clearSearch'); |
|
|
const selectedText = document.getElementById('selectedText'); |
|
|
const selectedCountEl = document.getElementById('selectedCount'); |
|
|
const selectAllBtn = document.getElementById('selectAllBtn'); |
|
|
const clearSelectionBtn = document.getElementById('clearSelectionBtn'); |
|
|
const downloadSelectedBtn = document.getElementById('downloadSelectedBtn'); |
|
|
const downloadCurrentBtn = document.getElementById('downloadCurrentBtn'); |
|
|
const downloadAllBtn = document.getElementById('downloadAllBtn'); |
|
|
const grayscaleBtn = document.getElementById('grayscaleBtn'); |
|
|
const randomizeBtn = document.getElementById('randomizeBtn'); |
|
|
const progressContainer = document.getElementById('progressContainer'); |
|
|
const progressFill = document.getElementById('progressFill'); |
|
|
const progressText = document.getElementById('progressText'); |
|
|
|
|
|
|
|
|
function normalizeText(text) { |
|
|
if (!text) return ''; |
|
|
return text.toString().toLowerCase().trim() |
|
|
.replace(/\s+/g, ' '); |
|
|
} |
|
|
|
|
|
|
|
|
function searchWorkers(query) { |
|
|
const normalizedQuery = normalizeText(query); |
|
|
if (!normalizedQuery) { |
|
|
filteredData = [...allWorkerData]; |
|
|
return filteredData; |
|
|
} |
|
|
|
|
|
filteredData = allWorkerData.filter(worker => { |
|
|
const searchFields = [ |
|
|
worker.requestNumber, |
|
|
worker.englishName, |
|
|
worker.thaiName, |
|
|
worker.personalID, |
|
|
worker.workPermitNumber, |
|
|
worker.alienReferenceNumber, |
|
|
worker.nationality |
|
|
]; |
|
|
|
|
|
return searchFields.some(field => { |
|
|
const normalizedField = normalizeText(field); |
|
|
return normalizedField.includes(normalizedQuery); |
|
|
}); |
|
|
}); |
|
|
|
|
|
return filteredData; |
|
|
} |
|
|
|
|
|
|
|
|
function highlightText(text, query) { |
|
|
if (!text || !query) return text || ''; |
|
|
const normalizedQuery = normalizeText(query); |
|
|
if (!normalizedQuery) return text; |
|
|
|
|
|
const regex = new RegExp(`(${escapeRegex(query)})`, 'gi'); |
|
|
return text.replace(regex, '<span class="highlight">$1</span>'); |
|
|
} |
|
|
|
|
|
function escapeRegex(string) { |
|
|
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); |
|
|
} |
|
|
|
|
|
|
|
|
function toggleDropdown(forceClose = false) { |
|
|
if (forceClose || isDropdownOpen) { |
|
|
isDropdownOpen = false; |
|
|
dropdownMenu.classList.remove('open'); |
|
|
dropdownArrow.classList.remove('open'); |
|
|
dropdownHeader.setAttribute('aria-expanded', 'false'); |
|
|
} else { |
|
|
isDropdownOpen = true; |
|
|
dropdownMenu.classList.add('open'); |
|
|
dropdownArrow.classList.add('open'); |
|
|
dropdownHeader.setAttribute('aria-expanded', 'true'); |
|
|
searchInput.focus(); |
|
|
renderDropdownList(); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function renderDropdownList(query = '') { |
|
|
const workers = searchWorkers(query); |
|
|
|
|
|
if (workers.length === 0) { |
|
|
dropdownList.innerHTML = ` |
|
|
<div class="no-results"> |
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<circle cx="11" cy="11" r="8"></circle> |
|
|
<line x1="21" y1="21" x2="16.65" y2="16.65"></line> |
|
|
</svg> |
|
|
<p>ไม่พบผลลัพธ์สำหรับ "${query}"</p> |
|
|
</div> |
|
|
`; |
|
|
return; |
|
|
} |
|
|
|
|
|
dropdownList.innerHTML = workers.map((worker, idx) => { |
|
|
const originalIndex = allWorkerData.findIndex(w => w.requestNumber === worker.requestNumber); |
|
|
const isChecked = selectedWorkers.has(originalIndex); |
|
|
const isActive = originalIndex === currentIndex; |
|
|
|
|
|
const displayName = query ? highlightText(worker.englishName || worker.thaiName || 'N/A', query) : (worker.englishName || worker.thaiName || 'N/A'); |
|
|
const displayId = query ? highlightText(worker.requestNumber || 'N/A', query) : (worker.requestNumber || 'N/A'); |
|
|
|
|
|
return ` |
|
|
<div class="dropdown-item ${isChecked ? 'selected' : ''} ${isActive ? 'active' : ''}" |
|
|
data-index="${originalIndex}" |
|
|
role="option" |
|
|
aria-selected="${isActive}" |
|
|
tabindex="0"> |
|
|
<img class="dropdown-item-image" |
|
|
src="${worker.profileImage || 'https://via.placeholder.com/40?text=N/A'}" |
|
|
alt="${worker.englishName || 'Worker'}" |
|
|
onerror="this.src='https://via.placeholder.com/40?text=N/A'"/> |
|
|
<div class="dropdown-item-content"> |
|
|
<div class="dropdown-item-title">${displayName}</div> |
|
|
<div class="dropdown-item-subtitle">เลขที่: ${displayId}</div> |
|
|
</div> |
|
|
<div class="dropdown-item-checkbox" onclick="event.stopPropagation(); toggleWorkerSelection(${originalIndex})"> |
|
|
<div class="custom-checkbox ${isChecked ? 'checked' : ''}" role="checkbox" aria-checked="${isChecked}"> |
|
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="3"> |
|
|
<polyline points="20,6 9,17 4,12"></polyline> |
|
|
</svg> |
|
|
</div> |
|
|
</div> |
|
|
</div> |
|
|
`; |
|
|
}).join(''); |
|
|
|
|
|
|
|
|
dropdownList.querySelectorAll('.dropdown-item').forEach(item => { |
|
|
item.addEventListener('click', (e) => { |
|
|
if (!e.target.closest('.dropdown-item-checkbox')) { |
|
|
const index = parseInt(item.dataset.index); |
|
|
selectWorker(index); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
item.addEventListener('keydown', (e) => { |
|
|
if (e.key === 'Enter' || e.key === ' ') { |
|
|
e.preventDefault(); |
|
|
const index = parseInt(item.dataset.index); |
|
|
if (e.shiftKey) { |
|
|
toggleWorkerSelection(index); |
|
|
} else { |
|
|
selectWorker(index); |
|
|
} |
|
|
} |
|
|
}); |
|
|
}); |
|
|
} |
|
|
|
|
|
|
|
|
function selectWorker(index) { |
|
|
currentIndex = index; |
|
|
displayWorkerData(index); |
|
|
updateDropdownHeader(); |
|
|
randomizeBothOverlays(); |
|
|
} |
|
|
|
|
|
|
|
|
function toggleWorkerSelection(index) { |
|
|
if (selectedWorkers.has(index)) { |
|
|
selectedWorkers.delete(index); |
|
|
} else { |
|
|
selectedWorkers.add(index); |
|
|
} |
|
|
updateSelectionUI(); |
|
|
renderDropdownList(searchInput.value); |
|
|
} |
|
|
|
|
|
|
|
|
function updateSelectionUI() { |
|
|
const count = selectedWorkers.size; |
|
|
selectedCountEl.textContent = `เลือกแล้ว ${count} รายการ`; |
|
|
downloadSelectedBtn.disabled = count === 0; |
|
|
downloadSelectedBtn.innerHTML = ` |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path> |
|
|
<polyline points="7,10 12,15 17,10"></polyline> |
|
|
<line x1="12" y1="15" x2="12" y2="3"></line> |
|
|
</svg> |
|
|
ดาวน์โหลด PDF ที่เลือก (${count}) |
|
|
`; |
|
|
} |
|
|
|
|
|
|
|
|
function updateDropdownHeader() { |
|
|
if (currentIndex >= 0 && currentIndex < allWorkerData.length) { |
|
|
const worker = allWorkerData[currentIndex]; |
|
|
selectedText.textContent = `${worker.requestNumber || 'N/A'} - ${worker.englishName || worker.thaiName || 'N/A'}`; |
|
|
setImageSrc('dropdownProfilePic', worker.profileImage, 'https://via.placeholder.com/32?text=N/A', worker.englishName, 'dropdown profile'); |
|
|
} else { |
|
|
selectedText.textContent = 'กรุณาเลือกพนักงาน'; |
|
|
document.getElementById('dropdownProfilePic').src = 'https://via.placeholder.com/32?text=...'; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function selectAllWorkers() { |
|
|
const currentFiltered = searchWorkers(searchInput.value); |
|
|
currentFiltered.forEach(worker => { |
|
|
const idx = allWorkerData.findIndex(w => w.requestNumber === worker.requestNumber); |
|
|
if (idx !== -1) selectedWorkers.add(idx); |
|
|
}); |
|
|
updateSelectionUI(); |
|
|
renderDropdownList(searchInput.value); |
|
|
} |
|
|
|
|
|
|
|
|
function clearAllSelections() { |
|
|
selectedWorkers.clear(); |
|
|
updateSelectionUI(); |
|
|
renderDropdownList(searchInput.value); |
|
|
} |
|
|
|
|
|
|
|
|
dropdownHeader.addEventListener('click', () => toggleDropdown()); |
|
|
dropdownHeader.addEventListener('keydown', (e) => { |
|
|
if (e.key === 'Enter' || e.key === ' ') { |
|
|
e.preventDefault(); |
|
|
toggleDropdown(); |
|
|
} |
|
|
}); |
|
|
|
|
|
searchInput.addEventListener('input', (e) => { |
|
|
const query = e.target.value; |
|
|
renderDropdownList(query); |
|
|
|
|
|
if (query) { |
|
|
searchIcon.style.display = 'none'; |
|
|
clearSearch.classList.add('visible'); |
|
|
} else { |
|
|
searchIcon.style.display = 'block'; |
|
|
clearSearch.classList.remove('visible'); |
|
|
} |
|
|
}); |
|
|
|
|
|
clearSearch.addEventListener('click', () => { |
|
|
searchInput.value = ''; |
|
|
searchIcon.style.display = 'block'; |
|
|
clearSearch.classList.remove('visible'); |
|
|
renderDropdownList(''); |
|
|
searchInput.focus(); |
|
|
}); |
|
|
|
|
|
selectAllBtn.addEventListener('click', selectAllWorkers); |
|
|
clearSelectionBtn.addEventListener('click', clearAllSelections); |
|
|
|
|
|
|
|
|
document.addEventListener('click', (e) => { |
|
|
if (!e.target.closest('.custom-dropdown')) { |
|
|
toggleDropdown(true); |
|
|
} |
|
|
}); |
|
|
|
|
|
|
|
|
grayscaleBtn.addEventListener('click', toggleGrayscale); |
|
|
downloadCurrentBtn.addEventListener('click', downloadCurrentPDF); |
|
|
downloadSelectedBtn.addEventListener('click', downloadSelectedPDFs); |
|
|
downloadAllBtn.addEventListener('click', downloadAllPDFs); |
|
|
randomizeBtn.addEventListener('click', randomizeBothOverlays); |
|
|
|
|
|
function setImageSrc(imgElementId, src, defaultSrc, workerName, type) { |
|
|
const imgElement = document.getElementById(imgElementId); |
|
|
if (!imgElement) { |
|
|
console.error(`Image element with ID "${imgElementId}" not found.`); |
|
|
return; |
|
|
} |
|
|
imgElement.src = src || defaultSrc; |
|
|
imgElement.alt = workerName || type; |
|
|
imgElement.crossOrigin = "anonymous"; |
|
|
imgElement.onerror = function() { |
|
|
imgElement.src = defaultSrc; |
|
|
imgElement.alt = 'No Image'; |
|
|
}; |
|
|
} |
|
|
|
|
|
function getCurrentTimestamp() { |
|
|
const now = new Date(); |
|
|
return now.toLocaleString('th-TH', { |
|
|
hour: '2-digit', |
|
|
minute: '2-digit', |
|
|
hour12: false |
|
|
}).replace(',', ' น.') + ' น.'; |
|
|
} |
|
|
|
|
|
function toggleGrayscale() { |
|
|
isGrayscaleEnabled = !isGrayscaleEnabled; |
|
|
document.body.style.filter = isGrayscaleEnabled ? 'grayscale(100%)' : 'grayscale(0%)'; |
|
|
grayscaleBtn.innerHTML = ` |
|
|
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"> |
|
|
<circle cx="12" cy="12" r="10"></circle> |
|
|
<path d="M12 2a10 10 0 0 1 0 20"></path> |
|
|
</svg> |
|
|
Grayscale: ${isGrayscaleEnabled ? 'เปิด' : 'ปิด'} |
|
|
`; |
|
|
} |
|
|
|
|
|
function jitter(base, maxDelta = 5) { |
|
|
return base + (Math.random() * 2 - 1) * maxDelta; |
|
|
} |
|
|
|
|
|
const borImages = ['bor01.png', 'bor02.png', 'bor03.png', 'bor04.png']; |
|
|
let borCounter = 0; |
|
|
|
|
|
function randomizeOverlayPosition(containerId, startIdx, useSetA = false, borIndex = 0, opacity = 1, refPos = null) { |
|
|
const container = document.getElementById(containerId); |
|
|
if (!container) return []; |
|
|
|
|
|
const setA = ['a1.png','a2.png','a3.png','a4.png','a5.png','a6.png']; |
|
|
const setB = ['b1.png','b2.png','b3.png','b4.png','b5.png','b6.png']; |
|
|
const imageFiles = useSetA ? setA : setB; |
|
|
|
|
|
const borSrc = borImages[borCounter % borImages.length]; |
|
|
borCounter++; |
|
|
|
|
|
container.innerHTML = ''; |
|
|
|
|
|
const imgs = []; |
|
|
for (let i = 0; i < 3; i++) { |
|
|
const img = document.createElement('img'); |
|
|
img.src = imageFiles[(startIdx + i) % 6]; |
|
|
img.style.zIndex = [1,2,3][i]; |
|
|
img.style.position = 'absolute'; |
|
|
container.appendChild(img); |
|
|
imgs.push(img); |
|
|
} |
|
|
|
|
|
const borImg = document.createElement('img'); |
|
|
borImg.src = borSrc; |
|
|
borImg.style.opacity = opacity; |
|
|
borImg.style.zIndex = 0; |
|
|
borImg.style.position = 'absolute'; |
|
|
container.insertBefore(borImg, container.firstChild); |
|
|
|
|
|
Promise.all([ |
|
|
...imgs.map(i => new Promise(r => { i.onload = r; if (i.complete) r(); })), |
|
|
new Promise(r => { borImg.onload = r; if (borImg.complete) r(); }) |
|
|
]).then(() => { |
|
|
const w = container.offsetWidth; |
|
|
const h = container.offsetHeight; |
|
|
|
|
|
const positions = imgs.map((img, i) => { |
|
|
const imgW = img.offsetWidth; |
|
|
const imgH = img.offsetHeight; |
|
|
const maxX = w - imgW; |
|
|
const maxY = h - imgH; |
|
|
|
|
|
const baseX = refPos && refPos[i] ? refPos[i].x : Math.random() * maxX; |
|
|
const baseY = refPos && refPos[i] ? refPos[i].y : Math.random() * maxY; |
|
|
const x = jitter(baseX); |
|
|
const y = jitter(baseY); |
|
|
|
|
|
const rotation = (Math.random() - 0.5) * 10 + (startIdx + i) * 0.3; |
|
|
let transform = `rotate(${rotation}deg)`; |
|
|
|
|
|
if (parseInt(img.style.zIndex) === 3) { |
|
|
const scale = 1 + (Math.random() - 0.5) * 0.3; |
|
|
transform += ` scale(${scale})`; |
|
|
} |
|
|
|
|
|
img.style.left = `${Math.max(0, Math.min(x, maxX))}px`; |
|
|
img.style.top = `${Math.max(0, Math.min(y, maxY))}px`; |
|
|
img.style.transform = transform; |
|
|
|
|
|
if (i === 0) { |
|
|
borImg.style.left = img.style.left; |
|
|
borImg.style.top = img.style.top; |
|
|
borImg.style.transform = transform; |
|
|
} |
|
|
|
|
|
return { x: parseFloat(img.style.left), y: parseFloat(img.style.top) }; |
|
|
}); |
|
|
|
|
|
container._lastPositions = positions; |
|
|
}); |
|
|
|
|
|
return container._lastPositions || []; |
|
|
} |
|
|
|
|
|
function randomizeBothOverlays() { |
|
|
const useSetA = Math.random() < 0.5; |
|
|
const useReverse = Math.random() < 0.5; |
|
|
const start1 = useReverse ? 3 : 0; |
|
|
const start2 = useReverse ? 0 : 3; |
|
|
|
|
|
const borIndex1 = borCounter % 4; |
|
|
const borIndex2 = (borCounter + 1) % 4; |
|
|
borCounter++; |
|
|
|
|
|
const baseOpacity = 0.75 + Math.random() * 0.15; |
|
|
const opacity1 = Math.min(1, baseOpacity + 0.05); |
|
|
const opacity2 = Math.max(0.6, baseOpacity - 0.05); |
|
|
|
|
|
const ref = randomizeOverlayPosition('overlayContainer1', start1, useSetA, borIndex1, opacity1); |
|
|
randomizeOverlayPosition('overlayContainer2', start2, useSetA, borIndex2, opacity2, ref); |
|
|
} |
|
|
|
|
|
function loadWorkerData() { |
|
|
const urlParams = new URLSearchParams(window.location.search); |
|
|
const requestNumberFromUrl = urlParams.get('id'); |
|
|
|
|
|
|
|
|
document.getElementById('requestNumber').innerHTML = '<b>Loading data...</b>'; |
|
|
document.getElementById('englishName').innerHTML = '<b>Loading data...</b>'; |
|
|
document.getElementById('englishNameDuplicate').innerHTML = 'Loading data...'; |
|
|
document.getElementById('thaiName').innerHTML = ': Loading data...'; |
|
|
document.getElementById('personalID').innerHTML = ': Loading data...'; |
|
|
document.getElementById('workPermitNumber').innerHTML = ': Loading data...'; |
|
|
document.getElementById('alienReferenceNumber').innerHTML = ': Loading data...'; |
|
|
document.getElementById('nationality').innerHTML = ': Loading data...'; |
|
|
document.getElementById('age').innerHTML = ': Loading data...'; |
|
|
document.getElementById('birthDate').innerHTML = ': Loading data...'; |
|
|
document.getElementById('timestamp').innerHTML = 'Loading data...'; |
|
|
document.getElementById('requestNumberReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('receiptNumberReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('paymentNumberReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('payerNameReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('nationalityReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('alienReferenceReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('personalIDReceipt').innerHTML = 'Loading data...'; |
|
|
document.getElementById('receiptTimestamp').innerHTML = 'Loading data...'; |
|
|
|
|
|
fetch('combined-data.json') |
|
|
.then(response => { |
|
|
if (!response.ok) throw new Error('Failed to load combined-data.json'); |
|
|
return response.json(); |
|
|
}) |
|
|
.then(data => { |
|
|
if (!Array.isArray(data) || data.length === 0) throw new Error('Data is empty or not a valid array.'); |
|
|
allWorkerData = data; |
|
|
filteredData = [...data]; |
|
|
|
|
|
currentIndex = requestNumberFromUrl |
|
|
? allWorkerData.findIndex(w => w.requestNumber && w.requestNumber.toString() === requestNumberFromUrl.toString()) |
|
|
: 0; |
|
|
if (currentIndex === -1) currentIndex = 0; |
|
|
|
|
|
displayWorkerData(currentIndex); |
|
|
updateDropdownHeader(); |
|
|
renderDropdownList(); |
|
|
updateSelectionUI(); |
|
|
}) |
|
|
.catch(error => { |
|
|
console.error('Error loading JSON:', error); |
|
|
showError(error.message); |
|
|
}); |
|
|
} |
|
|
|
|
|
function showError(message) { |
|
|
const errorDiv = document.createElement('div'); |
|
|
errorDiv.className = 'text-red-500 text-center mt-5 p-2 bg-red-100 border border-red-500 rounded'; |
|
|
errorDiv.innerHTML = `<p>Error loading: ${message}</p>`; |
|
|
document.body.appendChild(errorDiv); |
|
|
clearWorkerData(); |
|
|
setImageSrc('profilePic', null, 'https://via.placeholder.com/110x138?text=Error', 'N/A', 'profile picture'); |
|
|
setImageSrc('qrCode', null, 'https://via.placeholder.com/69?text=Error', 'N/A', 'work permit QR code'); |
|
|
setImageSrc('receiptQrCode', null, 'https://via.placeholder.com/90?text=Error', 'N/A', 'receipt QR code'); |
|
|
setImageSrc('dropdownProfilePic', null, 'https://via.placeholder.com/32?text=Error', 'N/A', 'dropdown profile picture'); |
|
|
const timestamp = getCurrentTimestamp(); |
|
|
const workPermitTimestamp = `เอกสารอิเล็กทรอนิกส์ฉบับนี้ถูกสร้างจากระบบอนุญาตทำงานคนต่างด้าวที่มีสถานะการทำงานไม่ถูกต้องตามกฎหมาย ตามมติคณะรัฐมนตรีเมื่อวันที่ 24 กันยายน 2567<br>โดยกรมการจัดหางาน กระทรวงแรงงาน<br>พิมพ์เอกสาร วันที่ 10/04/2568 ${timestamp} `; |
|
|
document.getElementById('timestamp').innerHTML = workPermitTimestamp; |
|
|
document.getElementById('receiptTimestamp').innerHTML = workPermitTimestamp; |
|
|
} |
|
|
|
|
|
function displayWorkerData(index) { |
|
|
const defaultProfileSrc = 'https://via.placeholder.com/110x138?text=No+Image'; |
|
|
const defaultQrCodeSrc = 'https://via.placeholder.com/69?text=No+QR'; |
|
|
const defaultReceiptQrCodeSrc = 'https://via.placeholder.com/90?text=No+QR'; |
|
|
|
|
|
if (!allWorkerData || !Array.isArray(allWorkerData) || index < 0 || index >= allWorkerData.length) { |
|
|
clearWorkerData(); |
|
|
setImageSrc('profilePic', null, defaultProfileSrc, 'N/A', 'profile picture'); |
|
|
setImageSrc('qrCode', null, defaultQrCodeSrc, 'N/A', 'work permit QR code'); |
|
|
setImageSrc('receiptQrCode', null, defaultReceiptQrCodeSrc, 'N/A', 'receipt QR code'); |
|
|
const timestamp = getCurrentTimestamp(); |
|
|
const workPermitTimestamp = `เอกสารอิเล็กทรอนิกส์ฉบับนี้ถูกสร้างจากระบบอนุญาตทำงานคนต่างด้าวที่มีสถานะการทำงานไม่ถูกต้องตามกฎหมาย ตามมติคณะรัฐมนตรีเมื่อวันที่ 24 กันยายน 2567<br>โดยกรมการจัดหางาน กระทรวงแรงงาน<br>พิมพ์เอกสาร วันที่ 10/04/2568 ${timestamp} `; |
|
|
document.getElementById('timestamp').innerHTML = workPermitTimestamp; |
|
|
document.getElementById('receiptTimestamp').innerHTML = workPermitTimestamp; |
|
|
return; |
|
|
} |
|
|
|
|
|
const worker = allWorkerData[index]; |
|
|
document.getElementById('requestNumber').innerHTML = `<b>${worker.requestNumber || 'N/A'}</b>`; |
|
|
document.getElementById('englishName').innerHTML = `<b>${worker.englishName || 'N/A'}</b>`; |
|
|
document.getElementById('englishNameDuplicate').innerHTML = worker.englishName || 'N/A'; |
|
|
document.getElementById('thaiName').innerHTML = `: ${worker.thaiName || 'N/A'}`; |
|
|
document.getElementById('personalID').innerHTML = `: ${worker.personalID || 'N/A'}`; |
|
|
document.getElementById('workPermitNumber').innerHTML = `: ${worker.workPermitNumber || 'N/A'}`; |
|
|
document.getElementById('alienReferenceNumber').innerHTML = `: ${worker.alienReferenceNumber || 'N/A'}`; |
|
|
document.getElementById('nationality').innerHTML = `: ${worker.nationality || 'N/A'}`; |
|
|
document.getElementById('age').innerHTML = `: ${worker.age || 'N/A'}`; |
|
|
document.getElementById('birthDate').innerHTML = `: ${worker.birthDate || 'N/A'}`; |
|
|
document.getElementById('requestNumberReceipt').innerHTML = worker.requestNumber || 'N/A'; |
|
|
document.getElementById('receiptNumberReceipt').innerHTML = worker.receiptNumber || 'N/A'; |
|
|
document.getElementById('paymentNumberReceipt').innerHTML = worker.paymentNumber || 'N/A'; |
|
|
document.getElementById('payerNameReceipt').innerHTML = worker.englishName || worker.thaiName || 'N/A'; |
|
|
document.getElementById('nationalityReceipt').innerHTML = worker.nationality || 'N/A'; |
|
|
document.getElementById('alienReferenceReceipt').innerHTML = worker.alienReferenceNumber || 'N/A'; |
|
|
document.getElementById('personalIDReceipt').innerHTML = worker.personalID || 'N/A'; |
|
|
setImageSrc('profilePic', worker.profileImage, defaultProfileSrc, worker.englishName, 'profile picture'); |
|
|
|
|
|
const currentDomain = window.location.origin; |
|
|
|
|
|
const workerPageUrl = `${currentDomain}/worker.html?id=${encodeURIComponent(worker.requestNumber || '')}`; |
|
|
const receiptUrl = `${currentDomain}/pdf.html?id=${encodeURIComponent(worker.requestNumber || '')}`; |
|
|
|
|
|
setImageSrc('qrCode', `https://api.qrserver.com/v1/create-qr-code/?size=300x300&ecc=H&data=${encodeURIComponent(workerPageUrl)}`, defaultQrCodeSrc, worker.englishName, 'work permit QR code'); |
|
|
setImageSrc('receiptQrCode', `https://api.qrserver.com/v1/create-qr-code/?size=300x300&ecc=H&data=${encodeURIComponent(receiptUrl)}`, defaultReceiptQrCodeSrc, worker.englishName, 'receipt QR code'); |
|
|
|
|
|
const timestamp = getCurrentTimestamp(); |
|
|
const workPermitTimestamp = `เอกสารอิเล็กทรอนิกส์ฉบับนี้ถูกสร้างจากระบบอนุญาตทำงานคนต่างด้าวที่มีสถานะการทำงานไม่ถูกต้องตามกฎหมาย ตามมติคณะรัฐมนตรีเมื่อวันที่ 24 กันยายน 2567<br>โดยกรมการจัดหางาน กระทรวงแรงงาน<br>พิมพ์เอกสาร วันที่ 10/04/2568 ${timestamp} `; |
|
|
document.getElementById('timestamp').innerHTML = workPermitTimestamp; |
|
|
document.getElementById('receiptTimestamp').innerHTML = workPermitTimestamp; |
|
|
} |
|
|
|
|
|
function clearWorkerData() { |
|
|
document.getElementById('requestNumber').innerHTML = '<b>N/A</b>'; |
|
|
document.getElementById('englishName').innerHTML = '<b>N/A</b>'; |
|
|
document.getElementById('englishNameDuplicate').innerHTML = 'N/A'; |
|
|
document.getElementById('thaiName').innerHTML = ': N/A'; |
|
|
document.getElementById('personalID').innerHTML = ': N/A'; |
|
|
document.getElementById('workPermitNumber').innerHTML = ': N/A'; |
|
|
document.getElementById('alienReferenceNumber').innerHTML = ': N/A'; |
|
|
document.getElementById('nationality').innerHTML = ': N/A'; |
|
|
document.getElementById('age').innerHTML = ': N/A'; |
|
|
document.getElementById('birthDate').innerHTML = ': N/A'; |
|
|
document.getElementById('requestNumberReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('receiptNumberReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('paymentNumberReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('payerNameReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('nationalityReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('alienReferenceReceipt').innerHTML = 'N/A'; |
|
|
document.getElementById('personalIDReceipt').innerHTML = 'N/A'; |
|
|
} |
|
|
|
|
|
|
|
|
function showProgress(show, current = 0, total = 0) { |
|
|
if (show) { |
|
|
progressContainer.classList.add('visible'); |
|
|
const percent = total > 0 ? Math.round((current / total) * 100) : 0; |
|
|
progressFill.style.width = `${percent}%`; |
|
|
progressText.textContent = `กำลังดาวน์โหลด ${current}/${total} (${percent}%)`; |
|
|
} else { |
|
|
progressContainer.classList.remove('visible'); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
function setButtonsDisabled(disabled) { |
|
|
downloadCurrentBtn.disabled = disabled; |
|
|
downloadSelectedBtn.disabled = disabled || selectedWorkers.size === 0; |
|
|
downloadAllBtn.disabled = disabled; |
|
|
randomizeBtn.disabled = disabled; |
|
|
grayscaleBtn.disabled = disabled; |
|
|
} |
|
|
|
|
|
async function downloadPDF(workerItem, filenameSuffix = '') { |
|
|
try { |
|
|
randomizeBothOverlays(); |
|
|
const elements = [document.getElementById('page1-div'), document.getElementById('page2-div')]; |
|
|
const reqNum = workerItem.requestNumber || 'worker'; |
|
|
const english = (workerItem.englishName || '').replace(/\s+/g, ''); |
|
|
const last4 = reqNum.slice(-4); |
|
|
|
|
|
|
|
|
const filename = `${last4}_${english || 'noname'}.pdf`; |
|
|
|
|
|
const controls = document.querySelector('.controls-container'); |
|
|
if (controls) controls.style.display = 'none'; |
|
|
|
|
|
if (allWorkerData[currentIndex].requestNumber !== workerItem.requestNumber) { |
|
|
const tempIndex = allWorkerData.findIndex(w => w.requestNumber === workerItem.requestNumber); |
|
|
if (tempIndex !== -1) displayWorkerData(tempIndex); |
|
|
} |
|
|
|
|
|
const images = document.querySelectorAll('img'); |
|
|
await Promise.all(Array.from(images).map(img => { |
|
|
return new Promise(resolve => { |
|
|
if (img.complete && img.naturalWidth > 0) resolve(); |
|
|
else { |
|
|
img.onload = resolve; |
|
|
img.onerror = () => { |
|
|
console.error(`Image failed to load: ${img.src}`); |
|
|
resolve(); |
|
|
}; |
|
|
} |
|
|
}); |
|
|
})); |
|
|
|
|
|
const container = document.createElement('div'); |
|
|
container.style.width = '892px'; |
|
|
container.style.height = '2522px'; |
|
|
container.className = 'pdf-export-container'; |
|
|
|
|
|
const page1Clone = elements[0].cloneNode(true); |
|
|
const page2Clone = elements[1].cloneNode(true); |
|
|
page1Clone.style.marginBottom = '0'; |
|
|
page2Clone.style.marginTop = '0'; |
|
|
|
|
|
container.appendChild(page1Clone); |
|
|
container.appendChild(page2Clone); |
|
|
document.body.appendChild(container); |
|
|
|
|
|
const allImages = container.querySelectorAll('img'); |
|
|
allImages.forEach(img => { |
|
|
img.style.filter = 'grayscale(100%)'; |
|
|
img.style.webkitFilter = 'grayscale(100%)'; |
|
|
}); |
|
|
|
|
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 100)); |
|
|
|
|
|
const opt = { |
|
|
margin: [0, 0, 0, 0], |
|
|
filename: filename, |
|
|
image: { type: 'jpeg', quality: 0.98 }, |
|
|
html2canvas: { |
|
|
scale: 3, |
|
|
useCORS: true, |
|
|
width: 892, |
|
|
height: 2522, |
|
|
logging: false, |
|
|
allowTaint: true, |
|
|
backgroundColor: '#ffffff' |
|
|
}, |
|
|
jsPDF: { |
|
|
unit: 'px', |
|
|
format: [892, 1261], |
|
|
orientation: 'portrait', |
|
|
compress: true |
|
|
} |
|
|
}; |
|
|
|
|
|
await html2pdf().set(opt).from(container).save(); |
|
|
|
|
|
document.body.removeChild(container); |
|
|
if (controls) controls.style.display = 'block'; |
|
|
|
|
|
if (allWorkerData[currentIndex].requestNumber !== workerItem.requestNumber) { |
|
|
displayWorkerData(currentIndex); |
|
|
} |
|
|
} catch (error) { |
|
|
console.error('Error generating PDF:', error); |
|
|
alert('เกิดข้อผิดพลาดในการสร้าง PDF กรุณาลองใหม่อีกครั้ง'); |
|
|
const controls = document.querySelector('.controls-container'); |
|
|
if (controls) controls.style.display = 'block'; |
|
|
} |
|
|
} |
|
|
|
|
|
async function downloadCurrentPDF() { |
|
|
if (currentIndex >= 0 && currentIndex < allWorkerData.length) { |
|
|
setButtonsDisabled(true); |
|
|
try { |
|
|
await downloadPDF(allWorkerData[currentIndex]); |
|
|
} catch (error) { |
|
|
alert('เกิดข้อผิดพลาดในการสร้าง PDF กรุณาลองใหม่อีกครั้ง'); |
|
|
} |
|
|
setButtonsDisabled(false); |
|
|
} else { |
|
|
alert('ไม่มีข้อมูลพนักงานที่เลือก'); |
|
|
} |
|
|
} |
|
|
|
|
|
async function downloadSelectedPDFs() { |
|
|
if (selectedWorkers.size === 0) { |
|
|
alert('กรุณาเลือกพนักงานอย่างน้อย 1 รายการ'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const selectedArray = Array.from(selectedWorkers).sort((a, b) => a - b); |
|
|
const confirmDownload = confirm(`คุณต้องการดาวน์โหลดใบอนุญาตทำงานสำหรับพนักงาน ${selectedArray.length} รายการใช่หรือไม่?`); |
|
|
if (!confirmDownload) return; |
|
|
|
|
|
setButtonsDisabled(true); |
|
|
showProgress(true, 0, selectedArray.length); |
|
|
|
|
|
for (let i = 0; i < selectedArray.length; i++) { |
|
|
const workerIndex = selectedArray[i]; |
|
|
try { |
|
|
showProgress(true, i + 1, selectedArray.length); |
|
|
displayWorkerData(workerIndex); |
|
|
await downloadPDF(allWorkerData[workerIndex], `work_permit_${i + 1}`); |
|
|
await new Promise(resolve => setTimeout(resolve, 800)); |
|
|
} catch (error) { |
|
|
console.error(`Error downloading PDF for worker at index ${workerIndex}:`, error); |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
showProgress(false); |
|
|
setButtonsDisabled(false); |
|
|
alert(`ดาวน์โหลดใบอนุญาตทำงานเรียบร้อยแล้ว ${selectedArray.length} รายการ`); |
|
|
|
|
|
if (currentIndex >= 0 && currentIndex < allWorkerData.length) { |
|
|
displayWorkerData(currentIndex); |
|
|
} |
|
|
} |
|
|
|
|
|
async function downloadAllPDFs() { |
|
|
if (!allWorkerData || allWorkerData.length === 0) { |
|
|
alert('ไม่มีข้อมูลพนักงาน'); |
|
|
return; |
|
|
} |
|
|
|
|
|
const confirmDownload = confirm(`คุณต้องการดาวน์โหลดใบอนุญาตทำงานสำหรับพนักงานทั้งหมด ${allWorkerData.length} รายการใช่หรือไม่?`); |
|
|
if (!confirmDownload) return; |
|
|
|
|
|
setButtonsDisabled(true); |
|
|
showProgress(true, 0, allWorkerData.length); |
|
|
|
|
|
for (let i = 0; i < allWorkerData.length; i++) { |
|
|
try { |
|
|
showProgress(true, i + 1, allWorkerData.length); |
|
|
displayWorkerData(i); |
|
|
await downloadPDF(allWorkerData[i], `work_permit_${i + 1}`); |
|
|
await new Promise(resolve => setTimeout(resolve, 800)); |
|
|
} catch (error) { |
|
|
console.error(`Error downloading PDF for worker at index ${i}:`, error); |
|
|
continue; |
|
|
} |
|
|
} |
|
|
|
|
|
showProgress(false); |
|
|
setButtonsDisabled(false); |
|
|
alert(`ดาวน์โหลดใบอนุญาตทำงานเรียบร้อยแล้ว ${allWorkerData.length} รายการ`); |
|
|
|
|
|
if (currentIndex >= 0 && currentIndex < allWorkerData.length) { |
|
|
displayWorkerData(currentIndex); |
|
|
} else if (allWorkerData.length > 0) { |
|
|
displayWorkerData(0); |
|
|
} |
|
|
} |
|
|
|
|
|
window.onload = async () => { |
|
|
try { |
|
|
await loadWorkerData(); |
|
|
randomizeBothOverlays(); |
|
|
} catch (e) { |
|
|
console.error('Error initializing application:', e); |
|
|
} |
|
|
}; |
|
|
</script> |
|
|
</body> |
|
|
</html> |