-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.html
More file actions
239 lines (212 loc) · 9.94 KB
/
index.html
File metadata and controls
239 lines (212 loc) · 9.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>活動報到系統</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdn.jsdelivr.net/npm/signature_pad@4.1.7/dist/signature_pad.umd.min.js"></script>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body class="font-sans bg-gray-100">
<div class="max-w-lg mx-auto my-8 p-8 bg-white rounded-lg shadow-md">
<h1 class="text-3xl font-bold text-center mb-6 text-gray-800">OO報到系統</h1>
<div id="searchSection">
<label for="attendeeIdInput" class="block text-sm font-medium text-gray-700 mb-1">請輸入您的ID:</label>
<input type="text" id="attendeeIdInput" class="w-full border border-gray-300 rounded-md p-2 mb-3" placeholder="例如:08888">
<button id="searchBtn" class="w-full bg-blue-500 text-white font-semibold py-2 rounded-md hover:bg-blue-600">查詢資料</button>
</div>
<div id="dataSection" class="hidden mt-6">
<h2 class="text-xl font-semibold mb-3 text-gray-700">請確認您的資料:</h2>
<div id="attendeeInfo" class="bg-gray-50 p-4 rounded-md shadow-sm mb-4 grid grid-cols-1 sm:grid-cols-2 gap-x-4 gap-y-2">
</div>
<div id="messageBox" class="hidden p-4 rounded-md font-medium"></div>
<div id="previousSignatureSection" class="hidden mt-4 p-4 border border-gray-300 rounded-md bg-gray-50">
<h3 class="text-lg font-semibold text-gray-700 mb-2">先前報到記錄:</h3>
<dl class="space-y-1">
<div>
<dt class="font-semibold text-gray-600">報到時間:</dt>
<dd id="previousTimestamp" class="text-gray-800"></dd>
</div>
<div>
<dt class="font-semibold text-gray-600">已簽署文件:</dt>
<dd>
<img id="previousSignatureImage" src="" alt="先前簽名" class="mt-1 w-full h-auto object-contain border border-gray-300 rounded-md bg-gray-100">
</dd>
</div>
</dl>
</div>
<div id="signatureArea" class="hidden">
<p class="text-sm font-medium text-gray-700 mb-1 mt-4">請在下方空白處簽名(若需重新簽署):</p>
<div class="border border-dashed border-gray-300 rounded-md mt-4 mb-4">
<canvas id="signatureCanvas" class="w-full h-48"></canvas>
</div>
<div class="flex space-x-2 mt-2 mb-4">
<button id="clearSignatureBtn" class="bg-gray-500 text-white text-sm py-2 px-3 rounded-md hover:bg-gray-600">清除簽名</button>
</div>
<button id="submitBtn" class="w-full bg-blue-500 text-white font-semibold py-2 rounded-md hover:bg-blue-600">確認報到並提交簽名</button>
</div>
</div>
</div>
<script>
const searchSection = document.getElementById('searchSection');
const dataSection = document.getElementById('dataSection');
const attendeeIdInput = document.getElementById('attendeeIdInput');
const searchBtn = document.getElementById('searchBtn');
const attendeeInfoDiv = document.getElementById('attendeeInfo');
const signatureArea = document.getElementById('signatureArea');
const canvas = document.getElementById('signatureCanvas');
const clearSignatureBtn = document.getElementById('clearSignatureBtn');
const submitBtn = document.getElementById('submitBtn');
const messageBox = document.getElementById('messageBox');
const previousSignatureSection = document.getElementById('previousSignatureSection');
const previousTimestampSpan = document.getElementById('previousTimestamp');
const previousSignatureImage = document.getElementById('previousSignatureImage');
let signaturePad;
// 初始化或調整簽名版大小
function initializeOrResizeSignaturePad() {
const ratio = Math.max(window.devicePixelRatio || 1, 1);
canvas.width = canvas.offsetWidth * ratio;
canvas.height = canvas.offsetHeight * ratio;
const ctx = canvas.getContext('2d');
ctx.scale(ratio, ratio);
if (!signaturePad) {
signaturePad = new SignaturePad(canvas, {
backgroundColor: null,
penColor: 'rgb(55, 65, 81)',
});
} else {
signaturePad.clear();
}
}
// 清除簽名
function clearSignature() {
if (signaturePad) {
signaturePad.clear();
}
}
clearSignatureBtn.addEventListener('click', clearSignature);
// 視窗大小改變時重新調整簽名版
window.addEventListener('resize', initializeOrResizeSignaturePad);
// 顯示訊息
function showMessage(message, isSuccess = true) {
messageBox.textContent = message;
messageBox.className = isSuccess
? 'p-4 rounded-md font-medium bg-green-100 text-green-800 border border-green-300'
: 'p-4 rounded-md font-medium bg-red-100 text-red-800 border border-red-300';
messageBox.classList.remove('hidden');
}
// 隱藏訊息
function hideMessage() {
messageBox.classList.add('hidden');
}
// 查詢按鈕事件
searchBtn.addEventListener('click', () => {
const attendeeId = attendeeIdInput.value.trim();
if (!attendeeId) {
showMessage('請輸入您的報名ID。', false);
return;
}
hideMessage();
searchBtn.disabled = true;
searchBtn.textContent = '查詢中...';
previousSignatureSection.classList.add('hidden');
signatureArea.classList.add('hidden');
google.script.run
.withSuccessHandler(attendeeData => {
searchBtn.disabled = false;
searchBtn.textContent = '查詢資料';
if (attendeeData && attendeeData.error) {
showMessage(attendeeData.error, false);
dataSection.classList.add('hidden');
} else if (attendeeData) {
displayAttendeeData(attendeeData);
searchSection.classList.add('hidden');
dataSection.classList.remove('hidden');
if (attendeeData.checkInStatus === '已報到') {
showMessage('您已完成報到。以下是您上次的報到記錄。', true);
signatureArea.classList.add('hidden');
if (attendeeData.signatureFileUrl && attendeeData.signatureTimestamp) {
previousTimestampSpan.textContent = new Date(attendeeData.signatureTimestamp).toLocaleString('zh-TW', { dateStyle: 'long', timeStyle: 'short' });
previousSignatureImage.src = attendeeData.signatureFileUrl;
previousSignatureImage.onerror = () => {
previousSignatureImage.alt = '簽名圖片載入失敗';
previousSignatureImage.src = 'https://placehold.co/400x150/eeeeee/999999?text=no signature';
};
previousSignatureSection.classList.remove('hidden');
} else {
signatureArea.classList.remove('hidden');
previousSignatureSection.classList.add('hidden');
showMessage('您已完成報到,但先前簽名記錄不完整,請重新簽名。', false);
initializeOrResizeSignaturePad();
}
} else {
signatureArea.classList.remove('hidden');
previousSignatureSection.classList.add('hidden');
initializeOrResizeSignaturePad();
}
} else {
showMessage('找不到您的報名資料,請確認ID是否正確或洽詢工作人員。', false);
dataSection.classList.add('hidden');
}
})
.withFailureHandler(error => {
searchBtn.disabled = false;
searchBtn.textContent = '查詢資料';
showMessage('查詢失敗:' + error.message, false);
})
.getAttendeeData(attendeeId);
});
// 顯示參與者資料
function displayAttendeeData(data) {
attendeeInfoDiv.innerHTML = `
<dl class="space-y-1">
<div><dt class="font-semibold text-gray-600">報名ID:</dt><dd class="font-mono">${data.id || 'N/A'}</dd></div>
<div><dt class="font-semibold text-gray-600">姓名:</dt><dd>${data.name || 'N/A'}</dd></div>
<div><dt class="font-semibold text-gray-600">Email:</dt><dd>${data.email || 'N/A'}</dd></div>
<div><dt class="font-semibold text-gray-600">驗證資訊:</dt><dd class="font-mono">${data.idNumber || 'N/A'}</dd></div>
</dl>
`;
}
// 提交報到與簽名按鈕事件
submitBtn.addEventListener('click', () => {
const attendeeId = document.querySelector('#attendeeInfo .font-mono')?.textContent;
if (!attendeeId) {
showMessage('無法獲取參與者ID,請重新查詢。', false);
return;
}
if (!signaturePad || signaturePad.isEmpty()) {
showMessage('請先簽名再提交。', false);
return;
}
const signatureDataUrl = signaturePad.toDataURL('image/png');
hideMessage();
submitBtn.disabled = true;
submitBtn.textContent = '提交中...';
google.script.run
.withSuccessHandler(response => {
submitBtn.disabled = false;
submitBtn.textContent = '確認報到並提交簽名';
if (response.success) {
showMessage(response.message, true);
signatureArea.classList.add('hidden');
} else {
showMessage(response.message || '報到失敗,請稍後再試。', false);
}
})
.withFailureHandler(error => {
submitBtn.disabled = false;
submitBtn.textContent = '確認報到並提交簽名';
showMessage('報到失敗:' + error.message, false);
})
.recordCheckIn(attendeeId, signatureDataUrl);
});
window.onload = () => {
attendeeIdInput.value = '';
dataSection.classList.add('hidden');
previousSignatureSection.classList.add('hidden');
signatureArea.classList.add('hidden');
};
</script>
</body>
</html>