lean.vn — LeanERP và hệ sinh thái AI
📖 Wiki-6S-HuongDan CiCC LeanERP SOP 🎬 Có Video Hướng Dẫn (V03)

Màn hình Treo thẻ

Treo thẻ 6S (tag hanging) — tạo thẻ Vàng/Đỏ tại hiện trường

🎬 Video Hướng Dẫn Thực Hành: Quy trình Treo Thẻ Vàng / Thẻ Đỏ tại Hiện trường (Gemba) V03 · 08:00 · Công nhân · Đánh giá viên
Tab: Treo thẻ (screen-treo)
File: app.js lines 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.

CODE
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)

ElementIDGhi chú
Radio Vànginput[name="tagType"][value="Vàng"]Màu border: #f9a825 (vàng)
Radio Đỏinput[name="tagType"][value="Đỏ"]Màu border: #d32f2f (đỏ)
Label VànglabelTagVangClick → selectTagType('Vàng')
Label ĐỏlabelTagDoClick → 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, ẩn sSelectVang (S6 - An toàn, cố định)

2.2. Phân loại S

ElementIDKhi ẩn/hiện
ContainersSelectionRowẨn khi chưa chọn loại thẻ
Select VàngsSelectVangOptions: 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 ĐỏsSelectDoHiển thị cố định: S6 - An toàn (màu đỏ)
HintsHintText hướng dẫn thay đổi theo loại thẻ
Nút TreobtnTreoDisabled → 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 param asset
  • 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ở #treePickerOverlay với mode treothe
  • treo-loc-display: Hiển thị tên khu vực đã chọn
  • treo-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ọn
  • onTreoLocationSelected(locId): Load assets cho location

2.5. Ảnh hiện trạng (Before)

ElementIDMô tả
Nút capturefileInputBeforeaccept="image/*" capture="environment" → mở camera điện thoại
PreviewimagePreviewBeforeAspect 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ại
  • croppedImageDataURL: Ảnh đã crop dạng base64

2.6. Mô tả & Gợi ý khắc phục

TrườngIDLoạiGhi chú
Mô tả điểm không đạtdescriptionTextareaBắt buộc — phải có
Hạn xử lýdueDateDate pickerTùy chọn. Mặc định: Đỏ = hôm nay, Vàng = +7 ngày
Gợi ý khắc phụcsolutionTextareaTùy chọn

2.7. Nút Treo thẻ

IDbtnTreo
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àngEnabled, 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)

CODE
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

JSON
{
  "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àmMô 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

🖼️
Nghe hướng dẫnĐường dẫn minh họa: audio/03-treo-the.mp3

Click play để nghe hướng dẫn bằng giọng đọc.


Screenshots

Tab Treo thẻ tổng quan
📸 Tab Treo thẻ tổng quan (Bấm vào ảnh để phóng to)

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

Chọn loại thẻ Vàng
📸 Chọn loại thẻ Vàng (Bấm vào ảnh để phóng to)

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

Chọn loại thẻ Đỏ
📸 Chọn loại thẻ Đỏ (Bấm vào ảnh để phóng to)

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

Quét QR tài sản
📸 Quét QR tài sản (Bấm vào ảnh để phóng to)

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

Chọn vị trí từ cây phả hệ
📸 Chọn vị trí từ cây phả hệ (Bấm vào ảnh để phóng to)

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

Form treo thẻ điền đầy đủ
📸 Form treo thẻ điền đầy đủ (Bấm vào ảnh để phóng to)

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

Thẻ mới treo thành công - In 2 liên
📸 Thẻ mới treo thành công - In 2 liên (Bấm vào ảnh để phóng to)

Chú thích: Modal hiển thị 2 liên in sau khi treo thẻ thành công

🖼️
QR đã quét thành côngĐường dẫn minh họa: images/treothe/05-qr-scanned.png

Chú thích: QR quét thành công — hiển thị mã tài sản + QR preview

Tree Picker mở rộng đầy đủ
📸 Tree Picker mở rộng đầy đủ (Bấm vào ảnh để phóng to)

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

Tree Picker đã chọn vị trí
📸 Tree Picker đã chọn vị trí (Bấm vào ảnh để phóng to)

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

Chụp ảnh Before — CropperJS
📸 Chụp ảnh Before — CropperJS (Bấm vào ảnh để phóng to)

Chú thích: CropperJS modal cắt ảnh Before

🖼️
Ảnh đã crop xongĐường dẫn minh họa: images/treothe/10-anh-da-crop.png

Chú thích: Preview ảnh Before sau khi crop

🖼️
Print Preview 2 liênĐường dẫn minh họa: images/treothe/13-print-preview.png

Chú thích: Print preview khi bấm In 2 liên