nguyenhai266 commited on
Commit
c092dca
·
1 Parent(s): 711dab1
src/main/resources/static/css/dashboard/dashboard-employee.css CHANGED
@@ -235,6 +235,34 @@
235
  background: var(--bg-table);
236
  }
237
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  /* ===================================
239
  STATUS BADGE (SYSTEM UNIFIED)
240
  =================================== */
 
235
  background: var(--bg-table);
236
  }
237
 
238
+
239
+ /* ===================================
240
+ ATTENDANCE HISTORY
241
+ =================================== */
242
+
243
+ .attendance-history {
244
+ background: var(--bg-card);
245
+
246
+ border: 1px solid var(--border);
247
+
248
+ border-radius: 24px;
249
+
250
+ backdrop-filter: blur(20px);
251
+
252
+ overflow: hidden;
253
+ }
254
+
255
+ .attendance-history .section-title {
256
+ margin: 0;
257
+
258
+ padding: 20px 24px;
259
+
260
+ border-bottom: 1px solid var(--border);
261
+ }
262
+
263
+ .attendance-history .table-wrapper {
264
+ padding: 0;
265
+ }
266
  /* ===================================
267
  STATUS BADGE (SYSTEM UNIFIED)
268
  =================================== */
src/main/resources/static/css/document/document-list.css CHANGED
@@ -19,13 +19,13 @@
19
  }
20
 
21
  .document-table {
22
- width: 100%;
23
- min-width: 1200px;
24
  border-collapse: collapse;
25
  }
26
 
27
  .document-table thead {
28
- background: rgba(255, 255, 255, .03);
29
  }
30
 
31
  .document-table th {
@@ -40,7 +40,7 @@
40
  .document-table td {
41
  padding: 18px;
42
  color: #e2e8f0;
43
- border-bottom: 1px solid rgba(255, 255, 255, .05);
44
  vertical-align: middle;
45
  }
46
 
@@ -49,7 +49,7 @@
49
  }
50
 
51
  .document-table tbody tr:hover {
52
- background: rgba(255, 255, 255, .03);
53
  }
54
 
55
  /* ==========================
@@ -58,7 +58,7 @@
58
 
59
  .file-link {
60
  color: var(--indigo-06);
61
- font-weight: 600;
62
  text-decoration: none;
63
  transition: .25s;
64
  }
 
19
  }
20
 
21
  .document-table {
22
+ width: 78%;
23
+ min-width: 1180px;
24
  border-collapse: collapse;
25
  }
26
 
27
  .document-table thead {
28
+ background: rgba(8, 3, 31, 0.08);
29
  }
30
 
31
  .document-table th {
 
40
  .document-table td {
41
  padding: 18px;
42
  color: #e2e8f0;
43
+ border-bottom: 1px solid rgba(15, 8, 53, 0.05);
44
  vertical-align: middle;
45
  }
46
 
 
49
  }
50
 
51
  .document-table tbody tr:hover {
52
+ background: rgba(7, 2, 31, 0.03);
53
  }
54
 
55
  /* ==========================
 
58
 
59
  .file-link {
60
  color: var(--indigo-06);
61
+ font-weight: 500;
62
  text-decoration: none;
63
  transition: .25s;
64
  }
src/main/resources/static/css/faceID/faceID-create.css CHANGED
@@ -4,343 +4,588 @@
4
  FORM CARD SYSTEM
5
  =================================== */
6
 
7
- .dashboard-card{
8
- background:var(--bg-card);
9
 
10
- border:1px solid var(--border);
11
 
12
- border-radius:24px;
13
 
14
- backdrop-filter:blur(20px);
15
 
16
- overflow:hidden;
17
  }
 
18
  video {
19
  width: 100%;
20
  height: 100%;
21
  object-fit: contain;
22
  }
23
- .card-header{
24
- padding:18px;
25
 
26
- border-bottom:1px solid var(--border);
 
 
 
27
  }
28
 
29
- .card-header h2{
30
- font-size:1.1rem;
31
 
32
- font-weight:700;
33
 
34
- color:var(--text-white);
35
  }
36
 
37
- .card-body{
38
- padding:18px;
39
  }
40
 
41
  /* ===================================
42
  ROOM INPUT
43
  =================================== */
44
 
45
- .room-code-input{
46
- display:flex;
47
 
48
- flex-direction:column;
49
 
50
- gap:6px;
51
 
52
- margin-bottom:16px;
53
  }
54
 
55
- .room-code-input label{
56
- color:var(--text-light);
57
 
58
- font-size:.9rem;
59
 
60
- font-weight:600;
61
  }
62
 
63
- .room-code-input input{
64
- padding:12px 14px;
65
 
66
- border-radius:14px;
67
 
68
- border:1px solid var(--border);
69
 
70
- background:var(--bg-form);
71
 
72
- color:var(--text-white);
73
 
74
- outline:none;
75
 
76
- transition:.25s;
77
  }
78
 
79
- .room-code-input input:focus{
80
- border-color:var(--indigo-06);
81
 
82
- box-shadow:0 0 0 4px var(--indigo-15);
83
  }
84
 
85
  /* ===================================
86
  STUDENT SELECT AREA
87
  =================================== */
88
 
89
- .student-select{
90
- display:flex;
91
 
92
- align-items:end;
93
 
94
- gap:12px;
95
 
96
- margin-bottom:20px;
97
  }
98
 
99
- .student-select label{
100
- display:block;
101
 
102
- color:var(--text-light);
103
 
104
- font-size:.9rem;
105
 
106
- font-weight:600;
107
  }
108
 
109
- .student-select select{
110
- flex:1;
111
 
112
- padding:12px 14px;
113
 
114
- border-radius:14px;
115
 
116
- border:1px solid var(--border);
117
 
118
- background:var(--bg-table-06);
119
 
120
- color:var(--text-white);
121
 
122
- outline:none;
123
  }
124
 
125
- .sample-btn{
126
- padding:10px 14px;
127
 
128
- border-radius:14px;
129
 
130
- border:1px solid var(--border);
131
 
132
- background:var(--bg-table-06);
133
 
134
- color:var(--text-light);
135
 
136
- font-weight:600;
137
  }
138
 
139
  /* ===================================
140
  FACE GRID
141
  =================================== */
142
 
143
- .face-register-grid{
144
- display:grid;
145
 
146
- grid-template-columns:1fr;
147
 
148
- gap:16px;
149
  }
150
 
151
  /* ===================================
152
  PANEL (CAMERA BOX)
153
  =================================== */
154
 
155
- .panel{
156
- background:var(--bg-table);
157
 
158
- border:1px solid var(--border);
159
 
160
- border-radius:24px;
161
 
162
- padding:16px;
163
  }
164
 
165
- .panel-header{
166
- display:flex;
167
 
168
- justify-content:space-between;
169
 
170
- align-items:center;
171
 
172
- margin-bottom:12px;
173
  }
174
 
175
- .panel-header h3{
176
- font-size:1rem;
177
 
178
- color:white;
179
  }
180
 
181
- .panel-header button{
182
- padding:8px 12px;
183
 
184
- border-radius:12px;
185
 
186
- border:none;
187
 
188
- cursor:pointer;
189
 
190
- background:linear-gradient(to right, var(--indigo-06), var(--purple));
191
 
192
- color:var(--text-white);
193
 
194
- font-weight:600;
195
  }
196
 
197
  /* ===================================
198
  MODE TABS
199
  =================================== */
200
 
201
- .mode-tabs{
202
- display:flex;
203
 
204
- gap:10px;
205
 
206
- margin-bottom:12px;
207
  }
208
 
209
- .mode-tabs button{
210
- flex:1;
211
 
212
- padding:8px 10px;
213
 
214
- border-radius:12px;
215
 
216
- border:1px solid var(--border);
217
 
218
- background:var(--bg-table-06);
219
 
220
- color:var(--text-light);
221
 
222
- cursor:pointer;
223
 
224
- transition:.25s;
225
  }
226
 
227
- .mode-tabs button.active{
228
- background:var(--indigo-15);
229
 
230
- border-color:var(--indigo);
231
 
232
- color:var(--text-white);
233
  }
234
 
235
  /* ===================================
236
  GUIDE BOX
237
  =================================== */
238
 
239
- .guide-box{
240
- padding:12px;
241
 
242
- border-radius:14px;
243
 
244
- background:var(--bg-table);
245
 
246
- border:1px solid var(--border);
247
 
248
- margin-bottom:12px;
249
 
250
- color:var(--text-gray);
251
 
252
- font-size:.9rem;
253
  }
254
 
255
  /* ===================================
256
  VIDEO
257
  =================================== */
258
 
259
- .video-wrap{
260
- position:relative;
261
 
262
- width:96%;
263
 
264
- height:550px;
265
 
266
- border-radius:18px;
267
 
268
- overflow:hidden;
269
 
270
- background:#000;
271
 
272
- margin-bottom:12px;
273
  }
274
 
275
  .video-wrap video,
276
- .video-wrap canvas{
277
- position:absolute;
278
 
279
- inset:0;
280
 
281
- width:100%;
282
 
283
- height:100%;
284
 
285
- object-fit:cover;
286
  }
287
 
288
  /* ===================================
289
  ACTION ROW
290
  =================================== */
291
 
292
- .action-row{
293
- display:flex;
294
 
295
- gap:12px;
296
  }
297
 
298
- .action-row button{
299
- flex:1;
300
 
301
- padding:12px;
302
 
303
- border-radius:14px;
304
 
305
- border:none;
306
 
307
- cursor:pointer;
308
 
309
- font-weight:600;
310
 
311
- color:var(--text-white);
312
  }
313
 
314
  /* PRIMARY */
315
- #captureFaceBtn{
316
- background:linear-gradient(to right, var(--indigo-06), var(--purple));
317
  }
318
 
319
  /* SECONDARY */
320
- .action-row .secondary{
321
- background:var(--bg-table-06);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
322
 
323
- border:1px solid var(--border);
324
 
325
- color:var(--text-light);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
326
  }
327
 
328
  /* ===================================
329
  RESPONSIVE
330
  =================================== */
331
 
332
- @media(max-width:768px){
333
 
334
- .student-select{
335
- flex-direction:column;
336
- align-items:stretch;
337
  }
338
 
339
- .action-row{
340
- flex-direction:column;
341
  }
342
 
343
- .video-wrap{
344
- height:240px;
345
  }
346
  }
 
4
  FORM CARD SYSTEM
5
  =================================== */
6
 
7
+ .dashboard-card {
8
+ background: var(--bg-card);
9
 
10
+ border: 1px solid var(--border);
11
 
12
+ border-radius: 24px;
13
 
14
+ backdrop-filter: blur(20px);
15
 
16
+ overflow: hidden;
17
  }
18
+
19
  video {
20
  width: 100%;
21
  height: 100%;
22
  object-fit: contain;
23
  }
 
 
24
 
25
+ .card-header {
26
+ padding: 18px;
27
+
28
+ border-bottom: 1px solid var(--border);
29
  }
30
 
31
+ .card-header h2 {
32
+ font-size: 1.1rem;
33
 
34
+ font-weight: 700;
35
 
36
+ color: var(--text-white);
37
  }
38
 
39
+ .card-body {
40
+ padding: 18px;
41
  }
42
 
43
  /* ===================================
44
  ROOM INPUT
45
  =================================== */
46
 
47
+ .room-code-input {
48
+ display: flex;
49
 
50
+ flex-direction: column;
51
 
52
+ gap: 6px;
53
 
54
+ margin-bottom: 16px;
55
  }
56
 
57
+ .room-code-input label {
58
+ color: var(--text-light);
59
 
60
+ font-size: .9rem;
61
 
62
+ font-weight: 600;
63
  }
64
 
65
+ .room-code-input input {
66
+ padding: 12px 14px;
67
 
68
+ border-radius: 14px;
69
 
70
+ border: 1px solid var(--border);
71
 
72
+ background: var(--bg-form);
73
 
74
+ color: var(--text-white);
75
 
76
+ outline: none;
77
 
78
+ transition: .25s;
79
  }
80
 
81
+ .room-code-input input:focus {
82
+ border-color: var(--indigo-06);
83
 
84
+ box-shadow: 0 0 0 4px var(--indigo-15);
85
  }
86
 
87
  /* ===================================
88
  STUDENT SELECT AREA
89
  =================================== */
90
 
91
+ .student-select {
92
+ display: flex;
93
 
94
+ align-items: end;
95
 
96
+ gap: 12px;
97
 
98
+ margin-bottom: 20px;
99
  }
100
 
101
+ .student-select label {
102
+ display: block;
103
 
104
+ color: var(--text-light);
105
 
106
+ font-size: .9rem;
107
 
108
+ font-weight: 600;
109
  }
110
 
111
+ .student-select select {
112
+ flex: 1;
113
 
114
+ padding: 12px 14px;
115
 
116
+ border-radius: 14px;
117
 
118
+ border: 1px solid var(--border);
119
 
120
+ background: var(--bg-table-06);
121
 
122
+ color: var(--text-white);
123
 
124
+ outline: none;
125
  }
126
 
127
+ .sample-btn {
128
+ padding: 10px 14px;
129
 
130
+ border-radius: 14px;
131
 
132
+ border: 1px solid var(--border);
133
 
134
+ background: var(--bg-table-06);
135
 
136
+ color: var(--text-light);
137
 
138
+ font-weight: 600;
139
  }
140
 
141
  /* ===================================
142
  FACE GRID
143
  =================================== */
144
 
145
+ .face-register-grid {
146
+ display: grid;
147
 
148
+ grid-template-columns: 1fr;
149
 
150
+ gap: 16px;
151
  }
152
 
153
  /* ===================================
154
  PANEL (CAMERA BOX)
155
  =================================== */
156
 
157
+ .panel {
158
+ background: var(--bg-table);
159
 
160
+ border: 1px solid var(--border);
161
 
162
+ border-radius: 24px;
163
 
164
+ padding: 16px;
165
  }
166
 
167
+ .panel-header {
168
+ display: flex;
169
 
170
+ justify-content: space-between;
171
 
172
+ align-items: center;
173
 
174
+ margin-bottom: 12px;
175
  }
176
 
177
+ .panel-header h3 {
178
+ font-size: 1rem;
179
 
180
+ color: white;
181
  }
182
 
183
+ .panel-header button {
184
+ padding: 8px 12px;
185
 
186
+ border-radius: 12px;
187
 
188
+ border: none;
189
 
190
+ cursor: pointer;
191
 
192
+ background: linear-gradient(to right, var(--indigo-06), var(--purple));
193
 
194
+ color: var(--text-white);
195
 
196
+ font-weight: 600;
197
  }
198
 
199
  /* ===================================
200
  MODE TABS
201
  =================================== */
202
 
203
+ .mode-tabs {
204
+ display: flex;
205
 
206
+ gap: 10px;
207
 
208
+ margin-bottom: 12px;
209
  }
210
 
211
+ .mode-tabs button {
212
+ flex: 1;
213
 
214
+ padding: 8px 10px;
215
 
216
+ border-radius: 12px;
217
 
218
+ border: 1px solid var(--border);
219
 
220
+ background: var(--bg-table-06);
221
 
222
+ color: var(--text-light);
223
 
224
+ cursor: pointer;
225
 
226
+ transition: .25s;
227
  }
228
 
229
+ .mode-tabs button.active {
230
+ background: var(--indigo-15);
231
 
232
+ border-color: var(--indigo);
233
 
234
+ color: var(--text-white);
235
  }
236
 
237
  /* ===================================
238
  GUIDE BOX
239
  =================================== */
240
 
241
+ .guide-box {
242
+ padding: 12px;
243
 
244
+ border-radius: 14px;
245
 
246
+ background: var(--bg-table);
247
 
248
+ border: 1px solid var(--border);
249
 
250
+ margin-bottom: 12px;
251
 
252
+ color: var(--text-gray);
253
 
254
+ font-size: .9rem;
255
  }
256
 
257
  /* ===================================
258
  VIDEO
259
  =================================== */
260
 
261
+ .video-wrap {
262
+ position: relative;
263
 
264
+ width: 96%;
265
 
266
+ height: 550px;
267
 
268
+ border-radius: 18px;
269
 
270
+ overflow: hidden;
271
 
272
+ background: #000;
273
 
274
+ margin-bottom: 12px;
275
  }
276
 
277
  .video-wrap video,
278
+ .video-wrap canvas {
279
+ position: absolute;
280
 
281
+ inset: 0;
282
 
283
+ width: 100%;
284
 
285
+ height: 100%;
286
 
287
+ object-fit: cover;
288
  }
289
 
290
  /* ===================================
291
  ACTION ROW
292
  =================================== */
293
 
294
+ .action-row {
295
+ display: flex;
296
 
297
+ gap: 12px;
298
  }
299
 
300
+ .action-row button {
301
+ flex: 1;
302
 
303
+ padding: 12px;
304
 
305
+ border-radius: 14px;
306
 
307
+ border: none;
308
 
309
+ cursor: pointer;
310
 
311
+ font-weight: 600;
312
 
313
+ color: var(--text-white);
314
  }
315
 
316
  /* PRIMARY */
317
+ #captureFaceBtn {
318
+ background: linear-gradient(to right, var(--indigo-06), var(--purple));
319
  }
320
 
321
  /* SECONDARY */
322
+ .action-row .secondary {
323
+ background: var(--bg-table-06);
324
+
325
+ border: 1px solid var(--border);
326
+
327
+ color: var(--text-light);
328
+ }
329
+
330
+ /* ===================================
331
+ FACE REGISTER META
332
+ =================================== */
333
+
334
+ .face-register-meta {
335
+ display: flex;
336
+ flex-direction: column;
337
+
338
+ gap: 12px;
339
+
340
+ margin-bottom: 18px;
341
+ }
342
+
343
+ .face-register-meta h3 {
344
+ color: var(--text-white);
345
+ font-size: 1rem;
346
+ }
347
+
348
+ .face-register-meta label {
349
+ color: var(--text-light);
350
+ font-size: .9rem;
351
+ font-weight: 600;
352
+ }
353
+
354
+ .face-register-meta input {
355
+ padding: 12px 14px;
356
+
357
+ border-radius: 14px;
358
+
359
+ border: 1px solid var(--border);
360
+
361
+ background: var(--bg-form);
362
+
363
+ color: var(--text-white);
364
+
365
+ outline: none;
366
+
367
+ transition: .25s;
368
+ }
369
+
370
+ .face-register-meta input:focus {
371
+ border-color: var(--indigo-06);
372
+
373
+ box-shadow: 0 0 0 4px var(--indigo-15);
374
+ }
375
+
376
+ /* ===================================
377
+ SAMPLE SUMMARY
378
+ =================================== */
379
+
380
+ .face-sample-summary {
381
+ display: flex;
382
+
383
+ align-items: center;
384
+
385
+ gap: 12px;
386
+
387
+ margin-top: 6px;
388
+
389
+ flex-wrap: wrap;
390
+ }
391
+
392
+ .face-sample-count-btn {
393
+ padding: 10px 16px;
394
+
395
+ border-radius: 14px;
396
+
397
+ border: 1px solid var(--border);
398
+
399
+ background: var(--bg-table-06);
400
+
401
+ color: var(--text-white);
402
+
403
+ font-weight: 700;
404
+
405
+ cursor: default;
406
+ }
407
+
408
+ .face-sample-summary span {
409
+ color: var(--text-gray);
410
+
411
+ font-size: .9rem;
412
+ }
413
+
414
+ /* ===================================
415
+ FACE MODE HINT
416
+ =================================== */
417
+
418
+ .face-mode-hint {
419
+ margin-bottom: 12px;
420
+
421
+ color: var(--text-gray);
422
+
423
+ font-size: .9rem;
424
+
425
+ line-height: 1.5;
426
+ }
427
+
428
+ /* ===================================
429
+ MESSAGE
430
+ =================================== */
431
+
432
+ .message {
433
+ margin-top: 14px;
434
+
435
+ padding: 12px;
436
+
437
+ border-radius: 14px;
438
+
439
+ background: var(--bg-table);
440
+
441
+ border: 1px solid var(--border);
442
+
443
+ color: var(--text-light);
444
+
445
+ min-height: 48px;
446
 
447
+ display: flex;
448
 
449
+ align-items: center;
450
+ }
451
+
452
+ /* ===================================
453
+ GUIDE PANEL
454
+ =================================== */
455
+
456
+ .scan-tips {
457
+ list-style: none;
458
+
459
+ display: flex;
460
+
461
+ flex-direction: column;
462
+
463
+ gap: 10px;
464
+
465
+ margin-bottom: 16px;
466
+ }
467
+
468
+ .scan-tips li {
469
+ color: var(--text-light);
470
+
471
+ font-size: .95rem;
472
+ }
473
+
474
+ .muted {
475
+ color: var(--text-gray);
476
+
477
+ font-size: .9rem;
478
+
479
+ line-height: 1.6;
480
+ }
481
+
482
+ /* ===================================
483
+ REGISTER GRID 2 COLUMNS
484
+ =================================== */
485
+
486
+ .face-register-grid {
487
+ display: grid;
488
+
489
+ grid-template-columns: 2fr 1fr;
490
+
491
+ gap: 20px;
492
+ }
493
+
494
+ /* ===================================
495
+ STATUS BOX
496
+ =================================== */
497
+
498
+ .status-box {
499
+ display: flex;
500
+
501
+ flex-direction: column;
502
+
503
+ gap: 12px;
504
+ }
505
+
506
+ .status-item {
507
+ padding: 12px;
508
+
509
+ border-radius: 14px;
510
+
511
+ background: var(--bg-table);
512
+
513
+ border: 1px solid var(--border);
514
+ }
515
+
516
+ .status-item h4 {
517
+ margin-bottom: 6px;
518
+
519
+ color: var(--text-white);
520
+
521
+ font-size: .95rem;
522
+ }
523
+
524
+ .status-item p {
525
+ color: var(--text-gray);
526
+
527
+ font-size: .9rem;
528
+ }
529
+
530
+ /* ===================================
531
+ BUTTON EFFECTS
532
+ =================================== */
533
+
534
+ .panel-header button:hover,
535
+ .action-row button:hover {
536
+ transform: translateY(-2px);
537
+
538
+ transition: .25s;
539
+ }
540
+
541
+ #captureFaceBtn:hover {
542
+ box-shadow: 0 10px 25px rgba(99, 102, 241, .25);
543
+ }
544
+
545
+ /* ===================================
546
+ RESPONSIVE
547
+ =================================== */
548
+
549
+ @media (max-width: 1100px) {
550
+
551
+ .face-register-grid {
552
+ grid-template-columns: 1fr;
553
+ }
554
+
555
+ }
556
+
557
+ @media (max-width: 768px) {
558
+
559
+ .face-sample-summary {
560
+ flex-direction: column;
561
+ align-items: flex-start;
562
+ }
563
+
564
+ .action-row {
565
+ flex-direction: column;
566
+ }
567
+
568
+ .video-wrap {
569
+ height: 300px;
570
+ }
571
  }
572
 
573
  /* ===================================
574
  RESPONSIVE
575
  =================================== */
576
 
577
+ @media(max-width:768px) {
578
 
579
+ .student-select {
580
+ flex-direction: column;
581
+ align-items: stretch;
582
  }
583
 
584
+ .action-row {
585
+ flex-direction: column;
586
  }
587
 
588
+ .video-wrap {
589
+ height: 240px;
590
  }
591
  }
src/main/resources/static/css/faceID/faceID-list.css CHANGED
@@ -4,60 +4,60 @@
4
  CARD SYSTEM
5
  =================================== */
6
 
7
- .card{
8
- background:var(--bg-card);
9
 
10
- border:1px solid var(--border);
11
 
12
- border-radius:24px;
13
 
14
- backdrop-filter:blur(20px);
15
 
16
- overflow:hidden;
17
  }
18
 
19
  /* ===================================
20
  TABLE WRAPPER
21
  =================================== */
22
 
23
- .face-table{
24
- width:100%;
25
 
26
- border-collapse:collapse;
27
 
28
- color:var(--text-white);
29
  }
30
 
31
- .face-table thead{
32
- background:var(--bg-table);
33
  }
34
 
35
- .face-table th{
36
- text-align:left;
37
 
38
- padding:16px;
39
 
40
- font-size:.9rem;
41
 
42
- color:var(--text-light);
43
 
44
- border-bottom:1px solid var(--border);
45
  }
46
 
47
- .face-table td{
48
- padding:16px;
49
 
50
- border-bottom:1px solid var(--bg-form);
51
 
52
- font-size:.95rem;
53
  }
54
 
55
- .face-table tbody tr{
56
- transition:.2s;
57
  }
58
 
59
- .face-table tbody tr:hover{
60
- background:var(--bg-table);
61
  }
62
 
63
 
@@ -65,101 +65,193 @@
65
  BADGE
66
  =================================== */
67
 
68
- .sample-badge{
69
- display:inline-block;
70
 
71
- padding:6px 12px;
72
 
73
- border-radius:999px;
74
 
75
- font-size:.85rem;
76
 
77
- font-weight:600;
78
 
79
- background:var(--bg-table-015);
80
 
81
- color:var(--text-white );
82
 
83
- border:1px solid var(--indigo-15);
84
  }
85
 
86
  /* ===================================
87
  BUTTONS
88
  =================================== */
89
 
90
- .detail-btn{
91
- padding:8px 12px;
92
 
93
- border-radius:12px;
94
 
95
- border:1px solid var(--border);
96
 
97
- background:var(--bg-table-06);
98
 
99
- color:var(--text-light);
100
 
101
- cursor:pointer;
102
 
103
- transition:.25s;
104
  }
105
 
106
- .detail-btn:hover{
107
- background:var(--indigo-15);
108
 
109
- border-color:var(--indigo-06);
110
 
111
- color:white;
112
  }
113
 
114
  /* ===================================
115
  ACTION TEXT STATES
116
  =================================== */
117
 
118
- .status-accept{
119
- color:var(--success);
120
 
121
- font-weight:600;
122
  }
123
 
124
- .status-reject{
125
- color:var(--danger);
126
 
127
- font-weight:600;
128
  }
129
- .btn-secondery{
130
- background-color:var(--danger) ;
 
131
  color: var(--text-white);
132
  }
133
- .btn-primary{
134
- background-color:var(--success) ;
 
135
  color: var(--text-white);
136
  }
 
137
  /* ===================================
138
  TABLE WRAPPER IMPROVEMENT
139
  =================================== */
140
 
141
- .card{
142
- padding:0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  }
144
 
145
- .card table{
146
- width:100%;
 
 
 
 
 
 
 
 
147
  }
 
 
 
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  /* ===================================
150
  RESPONSIVE
151
  =================================== */
152
 
153
- @media(max-width:768px){
154
 
155
- .face-table{
156
- display:block;
157
 
158
- overflow-x:auto;
159
  }
160
 
161
  .face-table th,
162
- .face-table td{
163
- white-space:nowrap;
164
  }
165
  }
 
4
  CARD SYSTEM
5
  =================================== */
6
 
7
+ .card {
8
+ background: var(--bg-card);
9
 
10
+ border: 1px solid var(--border);
11
 
12
+ border-radius: 24px;
13
 
14
+ backdrop-filter: blur(20px);
15
 
16
+ overflow: hidden;
17
  }
18
 
19
  /* ===================================
20
  TABLE WRAPPER
21
  =================================== */
22
 
23
+ .face-table {
24
+ width: 100%;
25
 
26
+ border-collapse: collapse;
27
 
28
+ color: var(--text-white);
29
  }
30
 
31
+ .face-table thead {
32
+ background: var(--bg-table);
33
  }
34
 
35
+ .face-table th {
36
+ text-align: left;
37
 
38
+ padding: 16px;
39
 
40
+ font-size: .9rem;
41
 
42
+ color: var(--text-light);
43
 
44
+ border-bottom: 1px solid var(--border);
45
  }
46
 
47
+ .face-table td {
48
+ padding: 16px;
49
 
50
+ border-bottom: 1px solid var(--bg-form);
51
 
52
+ font-size: .95rem;
53
  }
54
 
55
+ .face-table tbody tr {
56
+ transition: .2s;
57
  }
58
 
59
+ .face-table tbody tr:hover {
60
+ background: var(--bg-table);
61
  }
62
 
63
 
 
65
  BADGE
66
  =================================== */
67
 
68
+ .sample-badge {
69
+ display: inline-block;
70
 
71
+ padding: 6px 12px;
72
 
73
+ border-radius: 999px;
74
 
75
+ font-size: .85rem;
76
 
77
+ font-weight: 600;
78
 
79
+ background: var(--bg-table-015);
80
 
81
+ color: var(--text-white);
82
 
83
+ border: 1px solid var(--indigo-15);
84
  }
85
 
86
  /* ===================================
87
  BUTTONS
88
  =================================== */
89
 
90
+ .detail-btn {
91
+ padding: 8px 12px;
92
 
93
+ border-radius: 12px;
94
 
95
+ border: 1px solid var(--border);
96
 
97
+ background: var(--bg-table-06);
98
 
99
+ color: var(--text-light);
100
 
101
+ cursor: pointer;
102
 
103
+ transition: .25s;
104
  }
105
 
106
+ .detail-btn:hover {
107
+ background: var(--indigo-15);
108
 
109
+ border-color: var(--indigo-06);
110
 
111
+ color: white;
112
  }
113
 
114
  /* ===================================
115
  ACTION TEXT STATES
116
  =================================== */
117
 
118
+ .status-accept {
119
+ color: var(--success);
120
 
121
+ font-weight: 600;
122
  }
123
 
124
+ .status-reject {
125
+ color: var(--danger);
126
 
127
+ font-weight: 600;
128
  }
129
+
130
+ .btn-secondery {
131
+ background-color: var(--danger);
132
  color: var(--text-white);
133
  }
134
+
135
+ .btn-primary {
136
+ background-color: var(--success);
137
  color: var(--text-white);
138
  }
139
+
140
  /* ===================================
141
  TABLE WRAPPER IMPROVEMENT
142
  =================================== */
143
 
144
+ .card {
145
+ padding: 0;
146
+ }
147
+
148
+ .card table {
149
+ width: 100%;
150
+ }
151
+
152
+
153
+ .face-gallery {
154
+ padding: 20px;
155
+
156
+ display: flex;
157
+
158
+ justify-content: center;
159
+
160
+ align-items: center;
161
+
162
+ min-height: 350px;
163
  }
164
 
165
+ .face-gallery img {
166
+ max-width: 400px;
167
+
168
+ width: 100%;
169
+
170
+ border-radius: 16px;
171
+
172
+ border: 1px solid var(--border);
173
+
174
+ object-fit: cover;
175
  }
176
+ /* ==========================
177
+ FACE MODAL
178
+ ========================== */
179
 
180
+ .face-modal {
181
+ display: none;
182
+
183
+ position: fixed;
184
+ top: 0;
185
+ left: 0;
186
+
187
+ width: 100%;
188
+ height: 100%;
189
+
190
+ background: rgba(0, 0, 0, 0.75);
191
+
192
+ justify-content: center;
193
+ align-items: center;
194
+
195
+ z-index: 9999;
196
+ }
197
+
198
+ .face-modal.show {
199
+ display: flex;
200
+ }
201
+
202
+ .face-modal-content {
203
+ width: 700px;
204
+ max-width: 90%;
205
+
206
+ background: var(--bg-card);
207
+
208
+ border: 1px solid var(--border);
209
+
210
+ border-radius: 20px;
211
+
212
+ overflow: hidden;
213
+
214
+ box-shadow: 0 0 30px rgba(0, 0, 0, .4);
215
+ }
216
+
217
+ .face-modal-header {
218
+ display: flex;
219
+
220
+ justify-content: space-between;
221
+ align-items: center;
222
+
223
+ padding: 16px 20px;
224
+
225
+ border-bottom: 1px solid var(--border);
226
+
227
+ color: var(--text-white);
228
+ }
229
+
230
+ .close-btn {
231
+ border: none;
232
+
233
+ background: transparent;
234
+
235
+ color: var(--text-white);
236
+
237
+ font-size: 22px;
238
+
239
+ cursor: pointer;
240
+ }
241
  /* ===================================
242
  RESPONSIVE
243
  =================================== */
244
 
245
+ @media(max-width:768px) {
246
 
247
+ .face-table {
248
+ display: block;
249
 
250
+ overflow-x: auto;
251
  }
252
 
253
  .face-table th,
254
+ .face-table td {
255
+ white-space: nowrap;
256
  }
257
  }
src/main/resources/templates/cms/absent/absent-create.html CHANGED
@@ -44,12 +44,12 @@
44
 
45
  <div class="form-group">
46
  <label>Từ ngày</label>
47
- <input type="date" th:field="*{startDate}" required>
48
  </div>
49
 
50
  <div class="form-group">
51
  <label>Đến ngày</label>
52
- <input type="date" th:field="*{endDate}" required>
53
  </div>
54
 
55
  </div>
@@ -57,7 +57,7 @@
57
  <!-- Lý do -->
58
  <div class="form-group">
59
  <label>Lý do</label>
60
- <textarea th:field="*{reason}" rows="5" placeholder="Nhập lý do xin nghỉ..."
61
  required></textarea>
62
  </div>
63
 
 
44
 
45
  <div class="form-group">
46
  <label>Từ ngày</label>
47
+ <input type="date" required>
48
  </div>
49
 
50
  <div class="form-group">
51
  <label>Đến ngày</label>
52
+ <input type="date" required>
53
  </div>
54
 
55
  </div>
 
57
  <!-- Lý do -->
58
  <div class="form-group">
59
  <label>Lý do</label>
60
+ <textarea rows="5" placeholder="Nhập lý do xin nghỉ..."
61
  required></textarea>
62
  </div>
63
 
src/main/resources/templates/cms/dashboard/dashboard-employee.html CHANGED
@@ -103,7 +103,7 @@
103
 
104
  <div class="quick-actions-grid">
105
 
106
- <a href="/useInformation" class="quick-action-card">
107
  <div class="quick-action-card__icon">
108
  <i class="bi bi-person-lines-fill"></i>
109
  </div>
 
103
 
104
  <div class="quick-actions-grid">
105
 
106
+ <a href="/userInformation" class="quick-action-card">
107
  <div class="quick-action-card__icon">
108
  <i class="bi bi-person-lines-fill"></i>
109
  </div>
src/main/resources/templates/cms/document/document-list.html CHANGED
@@ -36,7 +36,6 @@
36
  <th>File đính kèm</th>
37
  <th>Link tài liệu</th>
38
  <th>Trạng thái</th>
39
- <th>Chi tiết</th>
40
  <th>Thao tác</th>
41
  </tr>
42
  </thead>
@@ -87,11 +86,7 @@
87
 
88
  </td>
89
 
90
- <td>
91
- <a class="btn btn-detail">
92
- Xem
93
- </a>
94
- </td>
95
 
96
  <td>
97
 
 
36
  <th>File đính kèm</th>
37
  <th>Link tài liệu</th>
38
  <th>Trạng thái</th>
 
39
  <th>Thao tác</th>
40
  </tr>
41
  </thead>
 
86
 
87
  </td>
88
 
89
+
 
 
 
 
90
 
91
  <td>
92
 
src/main/resources/templates/cms/face-id/faceID-create.html CHANGED
@@ -4,7 +4,7 @@
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>Face Recognition Dashboard</title>
8
 
9
  <link rel="stylesheet" th:href="@{/css/faceID/faceID-create.css}">
10
  </head>
@@ -12,23 +12,24 @@
12
  <body>
13
 
14
  <div class="bg-image"></div>
 
15
  <div class="layout">
 
16
  <!-- SIDEBAR -->
17
  <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
18
 
19
- <!-- MAIN LAYOUT -->
20
  <div class="container-layout">
21
 
22
  <!-- HEADER -->
23
  <div class="container-header">
24
- <h1>Đăng face ID</h1>
25
- <p>Tạo face ID đăng vào phòng</p>
26
  </div>
27
 
28
- <!-- =========================
29
- FACE REGISTER
30
- ========================== -->
31
  <main class="main-container">
 
32
  <section class="dashboard-card">
33
 
34
  <div class="card-header">
@@ -37,10 +38,30 @@
37
 
38
  <div class="card-body">
39
 
40
- <!-- ROOM CODE -->
41
- <div class="room-code-input">
42
- <label>Mã phòng</label>
43
- <input type="text" id="roomCode" placeholder="Nhập mã phòng (VD: P101)">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44
  </div>
45
 
46
  <!-- GRID -->
@@ -51,67 +72,269 @@
51
 
52
  <div class="panel-header">
53
  <h3>Camera đăng ký</h3>
54
- <button id="faceRegisterToggleBtn">Bật camera</button>
 
 
 
 
55
  </div>
56
 
 
57
  <div class="mode-tabs">
58
- <button class="active">Thêm mẫu</button>
59
- <button>Quét lại</button>
 
 
 
 
 
 
 
60
  </div>
61
 
 
 
 
 
 
62
  <div class="guide-box">
63
- <div id="scanGuideCurrent">Nhìn thẳng vào camera</div>
64
- <div id="scanGuideSteps">Bước 1 / 5</div>
 
 
 
 
 
 
 
65
  </div>
66
 
 
67
  <div class="video-wrap">
68
- <video id="video" autoplay playsinline muted></video>
69
- </div>
70
 
 
 
 
 
 
 
 
 
 
71
 
 
72
 
73
  <!-- ACTION -->
74
  <div class="action-row">
75
 
76
- <button type="button" id="captureFaceBtn">
77
- 📷 Đăng ký Face ID
 
78
  </button>
79
 
80
- <button type="button" class="secondary">
 
 
81
  Làm lại
82
  </button>
83
 
84
  </div>
85
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  </div>
87
 
88
  </div>
89
 
90
  </div>
 
91
  </section>
 
92
  </main>
 
93
  <div th:replace="~{cms/layout/footer :: footer}"></div>
94
 
95
  </div>
 
96
  </div>
 
97
  <script>
98
  const video = document.getElementById("video");
99
- const btn = document.getElementById("faceRegisterToggleBtn");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
 
101
- btn.addEventListener("click", async () => {
102
  try {
103
- const stream = await navigator.mediaDevices.getUserMedia({
 
104
  video: true,
105
  audio: false
106
  });
107
 
108
  video.srcObject = stream;
109
- } catch (err) {
110
- console.error(err);
 
 
 
111
  alert("Không thể mở camera");
 
112
  }
113
  });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
114
  </script>
 
115
  </body>
116
 
117
  </html>
 
4
  <head>
5
  <meta charset="UTF-8">
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Đăng Face ID</title>
8
 
9
  <link rel="stylesheet" th:href="@{/css/faceID/faceID-create.css}">
10
  </head>
 
12
  <body>
13
 
14
  <div class="bg-image"></div>
15
+
16
  <div class="layout">
17
+
18
  <!-- SIDEBAR -->
19
  <div th:replace="~{cms/sidebar/sidebar-employee :: sidebar}"></div>
20
 
21
+ <!-- CONTENT -->
22
  <div class="container-layout">
23
 
24
  <!-- HEADER -->
25
  <div class="container-header">
26
+ <h1>Đăng Face ID</h1>
27
+ <p>Đăng khuôn mặt để sử dụng hệ thống ra vào phòng</p>
28
  </div>
29
 
30
+ <!-- MAIN -->
 
 
31
  <main class="main-container">
32
+
33
  <section class="dashboard-card">
34
 
35
  <div class="card-header">
 
38
 
39
  <div class="card-body">
40
 
41
+ <!-- THÔNG TIN -->
42
+ <div class="face-register-meta">
43
+
44
+ <h3>Thông tin đăng ký</h3>
45
+
46
+ <label for="roomCode">Mã phòng</label>
47
+ <input type="text"
48
+ id="roomCode"
49
+ placeholder="Ví dụ: P101">
50
+
51
+ <div class="face-sample-summary">
52
+
53
+ <button id="faceSampleCount"
54
+ class="face-sample-count-btn"
55
+ type="button">
56
+ 0 / 5 mẫu
57
+ </button>
58
+
59
+ <span id="faceSampleStatusText">
60
+ Nhập mã phòng và bắt đầu quét khuôn mặt.
61
+ </span>
62
+
63
+ </div>
64
+
65
  </div>
66
 
67
  <!-- GRID -->
 
72
 
73
  <div class="panel-header">
74
  <h3>Camera đăng ký</h3>
75
+
76
+ <button id="faceRegisterToggleBtn"
77
+ type="button">
78
+ Bật camera
79
+ </button>
80
  </div>
81
 
82
+ <!-- MODE -->
83
  <div class="mode-tabs">
84
+ <button class="active"
85
+ type="button">
86
+ Đăng ký mới
87
+ </button>
88
+
89
+ <button type="button"
90
+ id="rescanBtn">
91
+ Quét lại
92
+ </button>
93
  </div>
94
 
95
+ <p class="face-mode-hint">
96
+ Hệ thống yêu cầu 5 góc khuôn mặt để tăng độ chính xác nhận diện.
97
+ </p>
98
+
99
+ <!-- GUIDE -->
100
  <div class="guide-box">
101
+
102
+ <div id="scanGuideCurrent">
103
+ Nhìn thẳng vào camera
104
+ </div>
105
+
106
+ <div id="scanGuideSteps">
107
+ Bước 1 / 5
108
+ </div>
109
+
110
  </div>
111
 
112
+ <!-- VIDEO -->
113
  <div class="video-wrap">
 
 
114
 
115
+ <video id="video"
116
+ autoplay
117
+ playsinline
118
+ muted>
119
+ </video>
120
+
121
+ <canvas id="captureCanvas"
122
+ style="display:none;">
123
+ </canvas>
124
 
125
+ </div>
126
 
127
  <!-- ACTION -->
128
  <div class="action-row">
129
 
130
+ <button type="button"
131
+ id="captureFaceBtn">
132
+ 📷 Chụp mẫu
133
  </button>
134
 
135
+ <button type="button"
136
+ id="resetFaceScanBtn"
137
+ class="secondary">
138
  Làm lại
139
  </button>
140
 
141
  </div>
142
 
143
+ <!-- MESSAGE -->
144
+ <div id="faceRegisterMessage"
145
+ class="message">
146
+ </div>
147
+
148
+ </div>
149
+
150
+ <!-- GUIDE PANEL -->
151
+ <div class="panel">
152
+
153
+ <div class="panel-header">
154
+ <h3>Hướng dẫn quét</h3>
155
+ </div>
156
+
157
+ <ul class="scan-tips">
158
+ <li>✓ Bước 1: Nhìn thẳng.</li>
159
+ <li>✓ Bước 2: Quay mặt sang trái.</li>
160
+ <li>✓ Bước 3: Quay mặt sang phải.</li>
161
+ <li>✓ Bước 4: Ngẩng mặt lên.</li>
162
+ <li>✓ Bước 5: Cúi mặt xuống.</li>
163
+ </ul>
164
+
165
+ <p class="muted">
166
+ Đảm bảo khuôn mặt đủ sáng, không bị che bởi khẩu trang hoặc kính râm.
167
+ </p>
168
+
169
  </div>
170
 
171
  </div>
172
 
173
  </div>
174
+
175
  </section>
176
+
177
  </main>
178
+
179
  <div th:replace="~{cms/layout/footer :: footer}"></div>
180
 
181
  </div>
182
+
183
  </div>
184
+
185
  <script>
186
  const video = document.getElementById("video");
187
+ const canvas = document.getElementById("captureCanvas");
188
+ const toggleBtn = document.getElementById("faceRegisterToggleBtn");
189
+ const captureBtn = document.getElementById("captureFaceBtn");
190
+ const resetBtn = document.getElementById("resetFaceScanBtn");
191
+
192
+ const sampleCountBtn = document.getElementById("faceSampleCount");
193
+ const sampleStatusText = document.getElementById("faceSampleStatusText");
194
+ const scanGuideCurrent = document.getElementById("scanGuideCurrent");
195
+ const scanGuideSteps = document.getElementById("scanGuideSteps");
196
+ const messageBox = document.getElementById("faceRegisterMessage");
197
+
198
+ let stream = null;
199
+ let capturedSamples = [];
200
+
201
+ const guideSteps = [
202
+ "Nhìn thẳng vào camera",
203
+ "Quay mặt sang trái",
204
+ "Quay mặt sang phải",
205
+ "Ngẩng mặt lên",
206
+ "Cúi mặt xuống"
207
+ ];
208
+
209
+ // MỞ CAMERA
210
+ toggleBtn.addEventListener("click", async () => {
211
+
212
+ if (stream) {
213
+ stream.getTracks().forEach(track => track.stop());
214
+ stream = null;
215
+ video.srcObject = null;
216
+ toggleBtn.textContent = "Bật camera";
217
+ return;
218
+ }
219
 
 
220
  try {
221
+
222
+ stream = await navigator.mediaDevices.getUserMedia({
223
  video: true,
224
  audio: false
225
  });
226
 
227
  video.srcObject = stream;
228
+ toggleBtn.textContent = "Tắt camera";
229
+
230
+ } catch (error) {
231
+
232
+ console.error(error);
233
  alert("Không thể mở camera");
234
+
235
  }
236
  });
237
+
238
+ // CHỤP ẢNH
239
+ captureBtn.addEventListener("click", () => {
240
+
241
+ if (!video.srcObject) {
242
+ alert("Vui lòng bật camera trước.");
243
+ return;
244
+ }
245
+
246
+ if (capturedSamples.length >= 5) {
247
+ alert("Đã đủ 5 mẫu.");
248
+ return;
249
+ }
250
+
251
+ const ctx = canvas.getContext("2d");
252
+
253
+ canvas.width = video.videoWidth;
254
+ canvas.height = video.videoHeight;
255
+
256
+ ctx.drawImage(
257
+ video,
258
+ 0,
259
+ 0,
260
+ canvas.width,
261
+ canvas.height
262
+ );
263
+
264
+ const imageBase64 =
265
+ canvas.toDataURL("image/jpeg");
266
+
267
+ capturedSamples.push(imageBase64);
268
+
269
+ updateUI();
270
+
271
+ if (capturedSamples.length === 5) {
272
+
273
+ messageBox.innerHTML =
274
+ "✅ Đã thu thập đủ 5 mẫu khuôn mặt. Có thể gửi lên server.";
275
+
276
+ /*
277
+ Ví dụ gửi về Spring Boot
278
+
279
+ fetch('/face/register', {
280
+ method: 'POST',
281
+ headers: {
282
+ 'Content-Type': 'application/json'
283
+ },
284
+ body: JSON.stringify({
285
+ roomCode: document.getElementById('roomCode').value,
286
+ samples: capturedSamples
287
+ })
288
+ });
289
+ */
290
+ }
291
+ });
292
+
293
+ // RESET
294
+ resetBtn.addEventListener("click", () => {
295
+
296
+ capturedSamples = [];
297
+
298
+ updateUI();
299
+
300
+ messageBox.innerHTML =
301
+ "Đã làm lại quá trình quét.";
302
+
303
+ });
304
+
305
+ // UPDATE UI
306
+ function updateUI() {
307
+
308
+ const count = capturedSamples.length;
309
+
310
+ sampleCountBtn.textContent =
311
+ `${count} / 5 mẫu`;
312
+
313
+ sampleStatusText.textContent =
314
+ `Đã thu thập ${count}/5 mẫu khuôn mặt`;
315
+
316
+ if (count < 5) {
317
+
318
+ scanGuideCurrent.textContent =
319
+ guideSteps[count];
320
+
321
+ scanGuideSteps.textContent =
322
+ `Bước ${count + 1} / 5`;
323
+
324
+ } else {
325
+
326
+ scanGuideCurrent.textContent =
327
+ "Hoàn thành đăng ký";
328
+
329
+ scanGuideSteps.textContent =
330
+ "5 / 5";
331
+
332
+ }
333
+ }
334
+
335
+ updateUI();
336
  </script>
337
+
338
  </body>
339
 
340
  </html>
src/main/resources/templates/cms/face-id/faceID-list.html CHANGED
@@ -58,10 +58,9 @@
58
  </span>
59
  </td>
60
  <td>DE214</td>
61
- <td><button class="detail-btn" onclick="openFaceGallery()">
62
-
63
  Xem ảnh
64
-
65
  </button>
66
  </td>
67
 
@@ -91,7 +90,8 @@
91
  </button>
92
  </td>
93
  <td><button class="detail-btn btn-primary" type="submit">Chấp nhận</button>
94
- <button class="detail-btn btn-secondery" type="submit">Từ chối</button></td>
 
95
  </tr>
96
 
97
  </tbody>
@@ -105,7 +105,53 @@
105
 
106
  </div>
107
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
 
 
109
 
110
  </body>
111
 
 
58
  </span>
59
  </td>
60
  <td>DE214</td>
61
+ <td>
62
+ <button class="detail-btn" onclick="openFaceGallery()">
63
  Xem ảnh
 
64
  </button>
65
  </td>
66
 
 
90
  </button>
91
  </td>
92
  <td><button class="detail-btn btn-primary" type="submit">Chấp nhận</button>
93
+ <button class="detail-btn btn-secondery" type="submit">Từ chối</button>
94
+ </td>
95
  </tr>
96
 
97
  </tbody>
 
105
 
106
  </div>
107
  </div>
108
+ <div id="faceGalleryModal" class="face-modal">
109
+
110
+ <div class="face-modal-content">
111
+
112
+ <div class="face-modal-header">
113
+ <h2>Ảnh Face ID</h2>
114
+
115
+ <button class="close-btn" onclick="closeFaceGallery()">
116
+
117
+ </button>
118
+ </div>
119
+
120
+ <div class="face-gallery">
121
+
122
+ <img id="facePreviewImage" src="https://i.pinimg.com/736x/6a/5e/fc/6a5efc25bf7c7603afac79d7046f999c.jpg" alt="Face ID">
123
+
124
+ </div>
125
+
126
+ </div>
127
+
128
+ </div>
129
+ <script>
130
+ function openFaceGallery() {
131
+
132
+ document
133
+ .getElementById("faceGalleryModal")
134
+ .classList.add("show");
135
+ }
136
+
137
+ function closeFaceGallery() {
138
+
139
+ document
140
+ .getElementById("faceGalleryModal")
141
+ .classList.remove("show");
142
+ }
143
+
144
+ window.onclick = function (event) {
145
+
146
+ const modal =
147
+ document.getElementById("faceGalleryModal");
148
+
149
+ if (event.target === modal) {
150
+ closeFaceGallery();
151
+ }
152
+ };
153
 
154
+ </script>
155
 
156
  </body>
157
 
src/main/resources/templates/cms/sidebar/sidebar-employee.html CHANGED
@@ -42,7 +42,12 @@
42
  Đăng kí Face ID
43
  </a>
44
  </li>
45
-
 
 
 
 
 
46
  <li class="sidebar-option">
47
  <a href="/documentCreate" class="sidebar-link">
48
  <span>📄</span>
 
42
  Đăng kí Face ID
43
  </a>
44
  </li>
45
+ <li class="sidebar-option">
46
+ <a href="/documentList" class="sidebar-link">
47
+ <span>📝</span>
48
+ Báo cáo được chia sẻ
49
+ </a>
50
+ </li>
51
  <li class="sidebar-option">
52
  <a href="/documentCreate" class="sidebar-link">
53
  <span>📄</span>