# 📘 SKILL: LÀM & CẬP NHẬT TRANG HTML PORTAL KPH

> **Mục đích:** Hướng dẫn đầy đủ cách tạo mới và cập nhật trang web HTML tổng hợp báo cáo KPH (Khiếu nại – Phản ánh) của BTCHEM.
> **Bản ghi nhận:** 06/08/2026 — dựa trên phiên cập nhật thực tế 4 vụ (Hố Nai DD 834 · Minh Phát MP 394 · Hành Mỹ xù ghim · Bảo Hưng BH 432).
> **Đối tượng:** Người vận hành báo cáo (QC / Kỹ thuật / Trợ lý), hỗ trợ bởi Hermes Agent.

---

## 1. TỔNG QUAN

| Hạng mục | Giá trị |
|:---------|:--------|
| **Trang hiện tại** | `C:\antigra-DS\CLAW_LAM_VIEC\Bao cao - Hanh chinh\BAOCAOTONGHOP\HTML\KPH_TongHop_0508\index.html` |
| **Nguồn dữ liệu chính** | `...\KPH\BA0-CAO\` (15 thư mục vụ hoàn thiện, mỗi vụ có DOCX/PDF + ảnh) |
| **Nguồn hồ sơ gốc** | `...\KPH\Raw-Report\` (phiếu KPH gốc, mail KH, báo cáo KT/QC scan) |
| **Chế độ hiển thị** | **Nhúng nội dung** — đọc DOCX → nhúng text + ảnh vào HTML; KHÔNG link mở file gốc (user đã bác bỏ chế độ link-based 03/08/2026 vì bấm link không render được DOCX qua file://) |
| **Mở bằng** | Double-click `index.html` — chạy offline, không cần internet (không dùng CDN) |

### Cấu trúc trang (4 mục)
1. **01 Tổng quan bộ tài liệu** — KPI + nhóm lỗi + bảng 13 vụ (bấm dòng → nhảy tới chi tiết)
2. **02 Chi tiết từng vụ việc** — 13 vụ xếp accordion (bấm tiêu đề mở/đóng), mỗi vụ có hiện tượng/RCA/xử lý/phòng ngừa + gallery ảnh
3. **03 Bài học chung xuyên suốt** — bài học lặp lại (hũ lưu mẫu, khô ruột, chuẩn màu...)
4. **04 Danh sách tài liệu nguồn** — 26 file DOCX + ghi chú nguồn

### Dữ liệu nhúng trong trang (JS)
- `const SUMMARY = [...]` — 13 vụ: `["số","id","KH","Sản phẩm/Màu","Hiện tượng","status","số báo cáo"]` với `status ∈ {ok, watch, pend}`
- `const STATUS = {ok:"✅ Đã xử lý", watch:"👀 Theo dõi", pend:"🔴 Đang xử lý"}`
- Mỗi khối vụ: `<div class="inc" id="<id>" data-st="<status>">` + `.inc-head` + `.inc-body`
- Panel cập nhật mới: `<div class="upd" ...>` — khung viền vàng, đặt cuối `.inc-body` của vụ tương ứng

---

## 2. QUY TRÌNH TẠO MỚI (build từ đầu)

### Bước 1 — Trích dữ liệu thư mục → JSON
```bash
cd "C:\antigra-DS\CLAW_LAM_VIEC\Bao cao - Hanh chinh\BAOCAOTONGHOP"
python extract_kph_data.py        # quét KPH\BA0-CAO → kph_data.json
```

### Bước 2 — Đọc nội dung DOCX (bắt buộc khi user yêu cầu tổng hợp nội dung)
Dùng `python-docx`, đọc **theo thứ tự document body** (paragraph xen kẽ bảng):
```python
from docx import Document
from docx.oxml.ns import qn
d = Document("file.docx")
for child in d.element.body.iterchildren():
    tag = child.tag.split('}')[-1]
    if tag == 'p':   # đoạn văn
        text = ''.join(t.text or '' for t in child.iter(qn('w:t')))
    elif tag == 'tbl':  # bảng
        for tr in child.iter(qn('w:tr')):
            cells = [''.join(t.text or '' for t in tc.iter(qn('w:t'))) for tc in tr.iter(qn('w:tc'))]
```
> ⚠️ KHÔNG dùng `doc.paragraphs` + `doc.tables` riêng rẽ — mất thứ tự xen kẽ.

### Bước 3 — Build HTML
```bash
python build_kph_tong_hop_html.py   # đọc kph_data.json → sinh HTML 4 mục
```
- `templates/kph_template.html`, `templates/kph_tong_hop_template.html` = bản layout đã duyệt (tham chiếu khi sửa)
- Nhúng JSON vào `<script>`: `json.dumps(..., ensure_ascii=False)` + `.replace('</', '<\\/')` (chỉ escape trong JSON, KHÔNG escape HTML content nhúng thẳng)

### Bước 4 — Kiểm chứng (BẮT BUỘC)
1. `browser_navigate file:///C:/...` (URL-encode khoảng trắng = `%20`)
2. `browser_console` → **0 js_errors**
3. Test từng mục, bộ lọc, accordion
4. `browser_vision` → không chồng lấn, đúng bố cục
5. Gửi `MEDIA:<đường dẫn html>` + screenshot

---

## 3. QUY TRÌNH CẬP NHẬT (thêm vụ từ Raw-Report) ⭐

Quy trình chuẩn đã kiểm chứng 06/08/2026 khi user chỉ định thư mục sự cố trong `Raw-Report\`:

### Bước 1 — Đối chiếu vụ đã có
- Mở `index.html`, tìm vụ KH tương ứng (VD vụ Hố Nai D&D DD 834 đã có sẵn).
- **KHÔNG tạo vụ trùng** — chỉ thêm **panel `🆕 Cập nhật <ngày>`** vào cuối khối accordion vụ đó.
- ⚠️ User có thể **override quy ước "chỉ dùng BA0-CAO"** bằng cách chỉ định rõ thư mục Raw-Report — làm theo chỉ định, ghi nguồn đúng thư mục đó trong trang.

### Bước 2 — Đọc phiếu KPH gốc (DOCX)
- `1. NỘI DUNG KPH.docx` → trích như mục 2.Bước 2.
- Thông tin thường có: Mô tả · Ngày kiểm tra · Tên SP/màu (+ mã số vật tư) · Loại sai · Quy trình kiểm tra (các bước sơn) · Kết quả · Yêu cầu KT · Tình trạng hũ lưu.

### Bước 3 — Đọc PDF scan (không có text layer)
```python
import pymupdf
doc = pymupdf.open("file.pdf")
text = ''.join(pg.get_text() for pg in doc)   # rỗng = PDF scan
for i, page in enumerate(doc):
    page.get_pixmap(dpi=150).save(f"page_{i+1}.png")   # render → PNG
```
→ Dùng **vision_analyze TỪNG trang** để trích nội dung (bảng quy trình, công thức viết tay, chữ ký). Chuyển PNG → JPG (PIL, cap width ~1100, quality ~82) trước khi nhúng.

### Bước 4 — Copy ảnh vào `assets/images/`
- Tên đặt theo quy ước: `<vuviec>_<noidung>.jpg` (VD `dd834_new_hd_quytrinh.jpg`, `bh432_mail_tra_loi_kh.jpg`)
- **Xác minh nội dung ảnh bằng vision TRƯỚC khi viết caption** — không đoán theo tên file/bối cảnh.

### Bước 5 — Chèn panel cập nhật
- Anchor: dòng `class="src"` duy nhất cuối khối vụ + thẻ đóng + comment `<!-- ====== N. <KH> ====== -->`.
- Panel `.upd` dùng inline style với CSS vars sẵn có: `--brand`, `--accent`, `--chip`, `--line`, `--bg2`, `--warn`.
- Bảng quy trình: table inline-styled (header nền `var(--brand)`, chữ trắng).
- Ảnh: `<div class="gallery">` + `<figure class="fig">` + figcaption (dùng class sẵn có).
- Cuối panel: `<p class="src">Nguồn: KPH/Raw-Report/<thư mục>/ · <các file></p>`.

### Bước 6 — Cập nhật metadata
- **Ngày trang** (nếu là phiên bản mới): `<title>`, logo nav, `<h1>`, badge `📅 Tổng hợp <ngày>`.
- **Đổi tên KH / sửa tên**: tìm toàn bộ chuỗi cũ trong file (SUMMARY + tiêu đề khối) — VD "Bảo Hưng (Bảo Thắng)" → "Bảo Hưng".
- **Đổi trạng thái vụ** (đóng vụ): sửa `"pend"` → `"ok"` trong SUMMARY row + `data-st="pend"` → `data-st="ok"` trong `<div class="inc">`. Nút lọc + KPI tự cập nhật theo JS (KPI "đã xử lý xong" = ok; "đang theo dõi" = watch + pend).
- **Nhận định bổ sung** (ý kiến chuyên môn của BGĐ): thêm khối riêng viền nét đứt, ghi rõ **"Nhận định bổ sung (chuyên môn — không có trong nguồn)"** — không trộn với nội dung trích từ báo cáo.

### Bước 7 — Kiểm chứng (BẮT BUỘC)
1. `browser_navigate` → `browser_console`: **0 js_errors**
2. Mở rộng accordion vụ vừa sửa: click `.inc-head` → `scrollIntoView`
3. Verify panel tồn tại + ảnh load: `i.complete && i.naturalWidth > 0` — ⚠️ **ảnh `loading="lazy"` trong accordion đóng sẽ trả `false`** (chưa vào viewport) → phải mở accordion + scroll trước rồi mới kết luận; kiểm tra lại lần 2 sau ~1.2s
4. `browser_vision` → không chồng lấn, caption đúng
5. Gửi `MEDIA:<file html>` + screenshot

---

## 4. PITFALLS ⚠️

| Pitfall | Giải pháp |
|:--------|:-----------|
| Ảnh lazy-load trong accordion đóng báo `complete:false` | KHÔNG phải lỗi file — mở accordion + scroll, kiểm tra lại sau 1–2s |
| PDF scan `get_text()` rỗng | Render từng trang → vision_analyze; không tự suy diễn chữ viết tay |
| Mâu thuẫn số liệu/mã sản phẩm giữa các tài liệu (VD lót NC 1807 vs 1802; 110 sp vs 100 sp) | Giữ nguyên cả 2 bên + ⚠️ ghi chú "đề nghị kiểm tra" — KHÔNG tự sửa |
| Escape `</` cho HTML nhúng thẳng vào trang | CHỈ escape `</` cho JSON trong `<script>`; HTML content nhúng thẳng thì KHÔNG escape (escape sẽ hỏng mọi thẻ đóng) |
| `data-search` attribute chứa newline | Thay `\n` bằng space khi build search_text |
| Tên thư mục KPH không theo convention | Để trống trường parse được, không bịa |
| Ảnh trong thư mục con (`Hình ảnh\`, `images_kph\`) | Phải đếm/copy bằng `os.walk`, không chỉ root vụ |
| Báo cáo tổng hợp cũ (file có "TỔNG HỢP" trong tên) | Bỏ qua khi quét |

---

## 5. QUY ƯỚC NỘI DUNG (user duyệt)

1. **Nguyên văn nguồn** — số liệu, tên hóa chất, mã lô giữ nguyên; chỉ chuẩn hóa chính tả nhẹ (VD "qui trình" → "quy trình").
2. **Nhận định bổ sung phải ghi rõ** "không có trong nguồn" — phân biệt với nội dung trích dẫn.
3. **Caption ảnh trung thực** — vision xác minh trước; không chắc chắn → caption trung tính "theo báo cáo".
4. **Nguồn ghi đầy đủ** — `Nguồn: <thư mục>/<file>` cho mỗi khối nội dung.
5. **Gỗ Thông/Cao su/Tràm** ghi đúng loại gỗ; thuật ngữ kỹ thuật kèm 💡 giải thích (phễu DIN, 1 pass, lằn sóng carton, pot-life, xù ghim, xì vàng mắt gỗ...).

---

## 6. TÀI LIỆU THAM CHIẾU

| File | Vai trò |
|:-----|:--------|
| `BAOCAOTONGHOP\extract_kph_data.py` | Quét KPH\BA0-CAO → `kph_data.json` |
| `BAOCAOTONGHOP\build_kph_tong_hop_html.py` | Build HTML tổng hợp nội dung (chế độ nhúng) |
| `BAOCAOTONGHOP\build_kph_portal.py` | Build portal danh sách vụ (chế độ link — KHÔNG còn dùng làm chính) |
| `BAOCAOTONGHOP\kph_data.json`, `portal_data.json` | Dữ liệu JSON trung gian |
| `BAOCAOTONGHOP\HTML\KPH_TongHop_0508\` | Thư mục trang hiện tại (index.html + assets\images\) |
| `KPH\BA0-CAO\` | Báo cáo vụ đã hoàn thiện |
| `KPH\Raw-Report\` | Hồ sơ gốc (phiếu KPH, mail KH, scan KT/QC) |
| Skill Hermes | `kph-report-portal` (phiên bản agent, có scripts/templates) |

---

*File hướng dẫn tạo bởi Hermes Agent — 06/08/2026 · Lưu tại KPH\Raw-Report theo yêu cầu người dùng.*
