Tab: Treo thẻ (screen-treo)
File:app.jslines 351-970
1. Tổng quan
Màn hình chính để công nhân/trưởng nhóm tạo thẻ 6S tại hiện trường.
Header: [🏷️ 6S CiCC Tagging] [User] [ON] [🔄] [🚪]
─────────────────────────────────────────────────────────────────
Tab: [➕ Treo thẻ] [📝 Đánh giá] [📋 Danh sách] [📊 Báo cáo]
─────────────────────────────────────────────────────────────────
Loại thẻ cần treo: 🟡 Thẻ Vàng 🔴 Thẻ Đỏ
Phân loại (S): [S1 - Sàng lọc ▼] Thẻ Vàng → S1-S5
Chọn loại thẻ và phân loại S để bắt đầu.
[📷 Quét QR] [📍 Chọn từ cây phả hệ ▼]
[Nhãn QR] [-- Chọn tài sản -- ▼]
[📷 Chụp ảnh] Mô tả điểm không đạt: [_______________]
[Preview ảnh] Hạn xử lý: [____-__-__]
Gợi ý khắc phục: [_______________]
[CHỌN LOẠI THẺ ĐỂ TIẾP TỤC]
2. Từng trường chi tiết
2.1. Chọn loại thẻ (Tag Type)
| Element | ID | Ghi chú |
|---|---|---|
| Radio Vàng | input[name="tagType"][value="Vàng"] | Màu border: #f9a825 (vàng) |
| Radio Đỏ | input[name="tagType"][value="Đỏ"] | Màu border: #d32f2f (đỏ) |
| Label Vàng | labelTagVang | Click → selectTagType('Vàng') |
| Label Đỏ | labelTagDo | Click → selectTagType('Đỏ') |
Hành vi khi chọn:
- Chọn Vàng → hiện
sSelectVang(dropdown S1-S5), hint: "Chọn phân loại S1-S5 cho Thẻ Vàng" - Chọn Đỏ → hiện
sSelectDo, ẩnsSelectVang(S6 - An toàn, cố định)
2.2. Phân loại S
| Element | ID | Khi ẩn/hiện |
|---|---|---|
| Container | sSelectionRow | Ẩn khi chưa chọn loại thẻ |
| Select Vàng | sSelectVang | Options: S1-Sàng lọc, S2-Sắp xếp, S3-Sạch sẽ, S4-Săn sóc, S5-Sẵn sàng |
| Div Đỏ | sSelectDo | Hiển thị cố định: S6 - An toàn (màu đỏ) |
| Hint | sHint | Text hướng dẫn thay đổi theo loại thẻ |
| Nút Treo | btnTreo | Disabled → Enabled, text đổi thành "TẠO THẺ VÀNG" hoặc "TẠO THẺ ĐỎ" |
2.3. Quét QR (Trái)
Nút: btnScan — "📷 Quét QR"
Hành vi:
- Bấm → Mở fullscreen overlay
#qrScannerOverlay - Camera sau (
facingMode: "environment"), độ phân giải 1280x720 - Khi quét được mã → rung haptic (
navigator.vibrate(200)) - Parse mã QR theo format:
CICC-ASSET:XXXX→ lấy phần sau dấu:CICC-6S-XXXX→ lấy phần sau-- URL có
?asset=XXXX→ lấy paramasset - Gọi
loadAssetToForm(assetCode)→ điền location + asset - Đóng scanner
QR Preview: #asset-qr-preview — Hiển thị ảnh QR + mã tài sản sau khi quét
#asset-qr-img: Ảnh QR (300x300)#asset-code-display: Mã asset🖨️ Xem / In nhãn: Mở popup in nhãn tài sản
2.4. Chọn vị trí từ cây phả hệ (Phải)
Hàng 1 — Khu vực:
- Ô click: Mở
#treePickerOverlayvới modetreothe treo-loc-display: Hiển thị tên khu vực đã chọntreo-loc-chip: Chip path đầy đủ, có nút × để xóa
Hàng 2 — Mã vị trí / tài sản:
#locationCode: Select dropdown- Khi chọn khu vực → tự động load assets từ API
/assets?location_id=X - Nếu chỉ có 1 asset → tự động chọn
Hàm xử lý:
clearTreoLocSelection(): Xóa chọnonTreoLocationSelected(locId): Load assets cho location
2.5. Ảnh hiện trạng (Before)
| Element | ID | Mô tả |
|---|---|---|
| Nút capture | fileInputBefore | accept="image/*" capture="environment" → mở camera điện thoại |
| Preview | imagePreviewBefore | Aspect ratio 4:3, hiển thị ảnh sau crop |
Cropper: Dùng thư viện CropperJS — ảnh được crop trước khi lưu
- Aspect ratio: 4/3
- Output: 1080x810, JPEG quality 0.7
- Crop modal:
#cropModal currentCropper: Instance cropper hiện tạicroppedImageDataURL: Ảnh đã crop dạng base64
2.6. Mô tả & Gợi ý khắc phục
| Trường | ID | Loại | Ghi chú |
|---|---|---|---|
| Mô tả điểm không đạt | description | Textarea | Bắt buộc — phải có |
| Hạn xử lý | dueDate | Date picker | Tùy chọn. Mặc định: Đỏ = hôm nay, Vàng = +7 ngày |
| Gợi ý khắc phục | solution | Textarea | Tùy chọn |
2.7. Nút Treo thẻ
| ID | btnTreo |
|---|---|
| Khi chưa chọn loại thẻ | Disabled, text: "CHỌN LOẠI THẺ ĐỂ TIẾP TỤC", class: btn-xam |
| Sau khi chọn Vàng | Enabled, text: "TẠO THẺ VÀNG", class: btn-vang |
| Sau khi chọn Đỏ | Enabled, text: "TẠO THẺ ĐỎ", class: btn-do |
3. Luồng xử lý Treo thẻ (treoThe)
1. Lấy user từ localStorage('6s_user')
2. Validate: loại thẻ? description? location?
3. Sinh mã thẻ local (sinhMa)
- Vàng: Y-2026-00001
- Đỏ: R-2026-00001
4. Lưu vào localStorage trước (offline-first)
- tags.unshift(newTag)
5. Gọi API POST /tags
- Thành công: dùng mã thẻ từ server, upload ảnh, toast success
- Thất bại: lưu offline, toast warning
6. Reset form → chuyển sang tab Danh sách
7. Hiển thị thẻ mới (2 liên in)
Dữ liệu gửi lên API
{
"tag_no": "Y-2026-00001",
"tag_type": "yellow",
"s_category": "S1",
"description": "Mô tả lỗi",
"solution": "Cách khắc phục",
"asset_code": "ASSET-001",
"location_id": 8,
"reporter_id": 1,
"reporter": "Nguyễn Văn A",
"tenant_id": 1,
"due_date": "2026-06-30"
}
4. In thẻ 2 liên (hienThiTheMoi)
Sau khi treo thẻ thành công, hiển thị modal 2 liên để in:
- LIÊN 1: Treo tại vị trí phát hiện
- LIÊN 2: Treo tại Bảng 6S
Nội dung mỗi liên:
- Số thẻ, ngày, bộ phận, vị trí
- Người phát hiện, mô tả hiện trạng
- Điểm không phù hợp (S1-S6)
- Ảnh before (nếu có)
- Dành cho bộ phận phụ trách: Người xử lý, Kiểm tra, Hoàn thành, Rút thẻ (☐ OK / ☐ NG)
- S-checklist (tích vào ô tương ứng)
Nút:
- 🖨️ In 2 liên →
window.print() - ✅ Đã tạo → đóng modal
5. Các hàm liên quan
| Hàm | Mô tả |
|---|---|
sinhMa(type) | Sinh mã thẻ local (prefix Y/R + năm + sequence 5 số) |
uploadPhoto(tagNo) | Upload ảnh before lên server |
dataURLtoBlob(dataURL) | Convert base64 → Blob để upload |
compressImage(file, maxW, quality, callback) | Nén ảnh trước khi upload |
resetForm() | Reset toàn bộ form về trạng thái ban đầu |
previewImage(input, type) | Mở cropper khi chọn ảnh |
applyCrop() | Crop ảnh và lưu vào preview |
printAssetLabel() | In nhãn tài sản (mở cửa sổ mới) |
6. Lưu ý
- Luôn lưu localStorage trước khi gọi server (offline-first)
- Mã thẻ do backend cấp nếu local sinh trùng
- Không được bỏ trống Mô tả và Vị trí
- Ảnh chụp được crop tự động trước khi dùng
- Nếu offline, thẻ vẫn được tạo local và sync sau
Audio thuyết minh
audio/03-treo-the.mp3Click play để nghe hướng dẫn bằng giọng đọc.
Screenshots

Chú thích: Giao diện tab Treo thẻ khi mới vào

Chú thích: Đã chọn Thẻ Vàng, dropdown S1-S5 hiện ra

Chú thích: Đã chọn Thẻ Đỏ, hiển thị S6 - An toàn

Chú thích: Overlay quét mã QR tài sản bằng camera

Chú thích: Tree Picker overlay để chọn khu vực treo thẻ

Chú thích: Form treo thẻ đã điền đầy đủ: loại thẻ, phân loại S, mô tả, vị trí

Chú thích: Modal hiển thị 2 liên in sau khi treo thẻ thành công
images/treothe/05-qr-scanned.pngChú thích: QR quét thành công — hiển thị mã tài sản + QR preview

Chú thích: Cây phả hệ mở rộng đến cấp Chuyền

Chú thích: Đã chọn radio button vị trí

Chú thích: CropperJS modal cắt ảnh Before
images/treothe/10-anh-da-crop.pngChú thích: Preview ảnh Before sau khi crop
images/treothe/13-print-preview.pngChú thích: Print preview khi bấm In 2 liên