From a1b9cbb17521f2d87d8b47c94e9b72cb37a95075 Mon Sep 17 00:00:00 2001 From: pqhuy1987 Date: Wed, 5 Aug 2026 16:52:12 +0700 Subject: [PATCH] =?UTF-8?q?[CLAUDE]=20Contract:=20UAT=20S174=20dot-A=20?= =?UTF-8?q?=E2=80=94=203=20LOI=20THAT=20+=20O2=20bo=20chu=20SAP=20+=20bo?= =?UTF-8?q?=20nut=20Tu=20choi=20(FE-only,=200-mig)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nguon: /fable-clone frontend-designer ensemble 5 lane (wf_016b1bed-b85, 5/5 xong, 0 chet, 755K tok). Spec day du: runs/2026-08-05-S174-khkk-style-audit/spec-khkk-style-dong-bo-05-08-2026.md === DOT A — LOI THAT (khong phai style) === A1 🔴 Nut "Tai xuong" file dinh kem KHKK BI 401 — lane L1 bat, lead verify. Cu: TRAN. JWT chi gan boi interceptor axios (lib/api.ts:18); the KHONG di qua axios => request toi [Authorize(Policy="KeHoachKyKet.Read")] (ContractSigningPlansController.cs:222-223) di TAY KHONG => 401, nut khong tai duoc. Moi: ham downloadAttachment() dung khuon PE (PeWorkflowPanel.tsx:327-342) — api.get(responseType:'blob') -> createObjectURL -> click ngam -> revoke. A2 🔴 REGRESSION DO CHINH LEAD GAY RA TRONG PHIEN NAY (lane L3 bat). Man Thao tac dung
=> duoi lg chi con panel-1, KHONG co form => MOBILE KHONG TAO DUOC PHIEU (bam phieu xong khong co cho bam "Tao"). Va 2 ve: (1)
bo hidden, hien moi kho; (2) mobile xep DOC voi panel-1 chot tran 14rem — khong chot thi danh sach dai day form roi khoi man, dung cai ngo cut vua va. A3 Tra no da khai voi owner: trang chi tiet KHKK tren mobile mat nut Gui duyet / Xoa phieu. Giu KhkkWorkflowPanel o DUNG lg:hidden — desktop van sach (panel-3 lo), mobile thao tac duoc. === OWNER CHOT VONG NAY === O2 "Dung bo chu sap di" — go SoonChip(). Lane L4 do: KHONG giai doan nao con dung nghia "sap" (ca 4 deu fetch API that); SoonChip KHONG export, 8 hit noi bo => 0 host ngoai phu thuoc. 🔴 Go != "thay het bang 0". BA ca, BA cach xu dung nghia: · 2 ca dem-duoc -> luon in SO (ke ca 0) · ca KHOA-QUYEN -> BO TRANG (in 0 la NOI DOI: co the day phieu, chi la khong duoc xem, va cung khong duoc phep goi API de biet). O khoa + title du. · ca FAILED (dau —) -> GIU NGUYEN ("khong tai duoc" khac "co 0 phieu", dung gop) Cau-4 "vay thi bo luon tu choi ~ tuong tu PE" — go nut TU CHOI khoi KhkkWorkflowPanel. PE co code tu-choi nhung THUC TE khong hien (BE go khoi nextPhases + FE loc, UAT S60). 🔴 Chi go DUONG BAM o UI. May BE (KhkkTransitionAction.Reject, phase TuChoi=99) GIU NGUYEN: phieu cu da tu-choi van hien dung, mo lai sau chi la them nut. B4 Grid man Thao tac 300/340 -> 260/320 dung so cua PE (PurchaseEvaluationWorkspacePage:80). === HAI GIA-DINH CUA LEAD BI LANE BAC (lead da tu verify, lane DUNG) === - O3 hang-muc N-dong KHONG can migration. ContractSigningPlanLineConfiguration.cs:37-38 unique index 3 COT (PlanId, SupplierId, CatalogEntryId) => 1 NCC DA duoc phep N dong x N hang muc tu Mig 71. May rong san, chi UI hep. Lead tung bao owner "nang nhat, can migration" — SAI, da dinh chinh. - O4 shopdrawing dinh kem = FE-only 0-BE (rail dossierItemId da land du 6 tang tu Mig 69). Verify: build 2 app PASS; mirror SHA256 4/4 cap KHOP; control-am: Tu choi"=0 · a-href=0; control-duong: responseType=2 + downloadAttachment=2 CA HAI app. 🔴 CHUA co screenshot — ca 5 lane deu khong chup duoc (dev-rig chan: chi :8080 LISTENING, API :5443 khong co, trang sau ProtectedRoute — gotcha #3). Phai soi that 375/1366/1440 tren prod sau deploy truoc khi tuyen PASS. Co-Authored-By: Claude Opus 5 --- .../src/components/khkk/KhkkWorkflowPanel.tsx | 50 +++++++++++++------ .../pipeline/PipelineStageFolders.tsx | 34 ++++++------- fe-admin/src/pages/khkk/KhkkCreatePage.tsx | 12 ++++- fe-admin/src/pages/khkk/KhkkDetailPage.tsx | 19 ++++--- .../src/components/khkk/KhkkWorkflowPanel.tsx | 50 +++++++++++++------ .../pipeline/PipelineStageFolders.tsx | 34 ++++++------- fe-user/src/pages/khkk/KhkkCreatePage.tsx | 12 ++++- fe-user/src/pages/khkk/KhkkDetailPage.tsx | 19 ++++--- 8 files changed, 144 insertions(+), 86 deletions(-) diff --git a/fe-admin/src/components/khkk/KhkkWorkflowPanel.tsx b/fe-admin/src/components/khkk/KhkkWorkflowPanel.tsx index 2296ff0..5601048 100644 --- a/fe-admin/src/components/khkk/KhkkWorkflowPanel.tsx +++ b/fe-admin/src/components/khkk/KhkkWorkflowPanel.tsx @@ -33,7 +33,7 @@ import { useMemo, useRef, useState } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' -import { Check, History, Paperclip, Send, Trash2, Undo2, Workflow, X } from 'lucide-react' +import { Check, History, Paperclip, Send, Trash2, Undo2, Workflow } from 'lucide-react' import { Button } from '@/components/ui/Button' import { Dialog } from '@/components/ui/Dialog' import { Label } from '@/components/ui/Label' @@ -243,6 +243,29 @@ export function KhkkWorkflowPanel({ action === KhkkTransitionAction.Return || action === KhkkTransitionAction.Reject const confirmDisabled = transition.isPending || (commentRequired && !comment.trim()) + // [S174 · A1 — LỖI THẬT, không phải style] Trước đây tải file bằng `` TRẦN. + // 🔴 JWT chỉ được gắn bởi interceptor axios (`lib/api.ts:18`); thẻ `` KHÔNG đi qua axios + // ⇒ request tới `[Authorize(Policy="KeHoachKyKet.Read")]` + // (`ContractSigningPlansController.cs:222-223`) đi TAY KHÔNG ⇒ **401, nút không tải được**. + // Bê đúng khuôn PE (`PeWorkflowPanel.tsx:327-342`): axios lấy blob → objectURL → click ngầm. + // Phát hiện bởi lane L1 của ensemble; lead verify bằng đối chứng `responseType:'blob'` ở PE. + async function downloadAttachment(a: KhkkAttachmentDto) { + try { + const r = await api.get( + `/contract-signing-plans/${plan.id}/attachments/${a.id}/download`, + { responseType: 'blob' }, + ) + const url = window.URL.createObjectURL(r.data as Blob) + const link = document.createElement('a') + link.href = url + link.download = a.fileName + link.click() + window.URL.revokeObjectURL(url) + } catch (e) { + toast.error(getErrorMessage(e)) + } + } + return (
{/* ── 1. Header + meta {code} v{NN} · {name} ───────────────────────────── */} @@ -453,18 +476,12 @@ export function KhkkWorkflowPanel({ > Trả lại - + {/* 🧊 [S174 owner] Nút "TỪ CHỐI" ĐÃ GỠ — anh chốt "vậy thì bỏ luôn từ chối + ~ tương tự PE". Duyệt NCC có code từ-chối nhưng THỰC TẾ không hiện + (BE gỡ khỏi `nextPhases` + FE lọc, UAT S60) ⇒ KHKK còn hiện là lệch. + 🔴 Chỉ gỡ ĐƯỜNG BẤM ở UI. Máy BE (`KhkkTransitionAction.Reject`, + phase `TuChoi=99`) GIỮ NGUYÊN: phiếu cũ đã từ-chối vẫn hiển thị đúng, + và mở lại sau này chỉ là thêm nút. Gỡ cả máy = mất dữ-liệu lịch sử. */} )} {canDeletePlan && ( @@ -497,12 +514,13 @@ export function KhkkWorkflowPanel({
{a.fileName}
{formatSize(a.fileSize)} · {formatDateTime(a.createdAt)}
-
downloadAttachment(a)} className="shrink-0 text-[11px] font-medium text-brand-600 hover:underline" > Tải xuống - + ))} diff --git a/fe-admin/src/components/pipeline/PipelineStageFolders.tsx b/fe-admin/src/components/pipeline/PipelineStageFolders.tsx index 7db2447..3da59e1 100644 --- a/fe-admin/src/components/pipeline/PipelineStageFolders.tsx +++ b/fe-admin/src/components/pipeline/PipelineStageFolders.tsx @@ -96,15 +96,11 @@ function stageCount(stage: PipelineStage): number { return stage.content !== undefined ? (stage.count ?? 0) : stage.leaves.length } -function SoonChip() { - // Token lấy verbatim từ dải strip (PePipelineStrip.tsx:50-52) — uppercase CSS - // nên chữ "Sắp" hiển thị "SẮP" đúng như owner gõ. - return ( - - Sắp - - ) -} +// 🧊 [S174 owner O2] `SoonChip()` ĐÃ GỠ — owner: "Bỏ hết đi đổi thành 0". Lane L4 đo được +// KHÔNG giai đoạn nào còn đúng nghĩa "sắp" (cả 4 đều fetch API thật), và `SoonChip` KHÔNG +// export (8 hit nội bộ) ⇒ 0 host ngoài phụ thuộc, gỡ an toàn. +// 🔴 Gỡ KHÔNG đồng nghĩa "thay hết bằng 0": 2 ca đếm-được thì in số, ca KHOÁ-QUYỀN thì bỏ +// trắng (xem chú thích tại chỗ) — in 0 cho ca khoá là nói dối về dữ-liệu. type StageStyle = (typeof STAGE_STYLE)[PipelineStageNo] @@ -189,11 +185,10 @@ function GroupFolder({ group, style }: { group: PipelineGroup; style: StageStyle {group.label} )} - {count > 0 ? ( - {count} - ) : ( - - )} + {/* [S174 owner O2] "Bỏ hết đi đổi thành 0" — luôn in SỐ, kể cả 0. Chữ "SẮP" cũ nói + "giai đoạn chưa xây"; nay CẢ 4 giai đoạn đều gọi API thật (lane L4 đo) ⇒ 0 nghĩa + là "chưa có phiếu", không phải "chưa có tính năng". */} + {count}
{empty ? ( @@ -229,8 +224,11 @@ function StageFolder({ stage, currentStage }: { stage: PipelineStage; currentSta + {/* [S174 owner O2] KHÔNG in "0" ở đây. Đây là ca "chưa có QUYỀN xem", không phải + "có 0 phiếu" — in 0 là NÓI DỐI về dữ-liệu (thực tế có thể đầy phiếu, chỉ là mình + không được xem, và cũng không được phép gọi API để biết). Ổ khoá + `title` đã + mang trọn nghĩa; bỏ chip là đúng, không thay bằng số. */} {label} -
) } @@ -267,10 +265,10 @@ function StageFolder({ stage, currentStage }: { stage: PipelineStage; currentSta > — - ) : count > 0 ? ( - {count} ) : ( - + /* [S174 owner O2] luôn in SỐ (kể cả 0). Nhánh `—` ở trên GIỮ: đó là ca + "không tải được dữ-liệu", khác hẳn "có 0 phiếu" — đừng gộp hai thứ. */ + {count} )} diff --git a/fe-admin/src/pages/khkk/KhkkCreatePage.tsx b/fe-admin/src/pages/khkk/KhkkCreatePage.tsx index b893b22..3284aa6 100644 --- a/fe-admin/src/pages/khkk/KhkkCreatePage.tsx +++ b/fe-admin/src/pages/khkk/KhkkCreatePage.tsx @@ -176,7 +176,15 @@ export function KhkkCreatePage() { -
+ {/* [S174 · B4] Bề ngang cột về ĐÚNG số của Duyệt NCC (`PurchaseEvaluationWorkspacePage.tsx:80` + `260px` / `xl:320px`) — trước đó lead tự đặt 300/340, lệch chuẩn không lý do. + [S174 · A2 — VÁ REGRESSION DO CHÍNH LEAD GÂY RA TRONG PHIÊN NÀY] `
` từng mang + `hidden … lg:block` ⇒ dưới `lg` chỉ còn panel-1, KHÔNG có form ⇒ **mobile không tạo + được phiếu**: bấm phiếu ở cột trái xong thì không có chỗ nào để bấm "Tạo kế hoạch". + 🔴 Vá bằng 2 vế, thiếu vế nào cũng hỏng: (1) `
` bỏ `hidden`, hiện mọi khổ; + (2) mobile xếp DỌC với panel-1 chốt trần `14rem` — không chốt thì panel-1 (danh sách + dài) đẩy form rơi khỏi màn, đúng cái ngõ cụt vừa vá. Từ `lg` trở lên về 1 hàng như cũ. */} +
-
+
{/* (a) Đang XEM một kế hoạch — read-only, có đường quay về form tạo. */} {viewPlanId && (
diff --git a/fe-admin/src/pages/khkk/KhkkDetailPage.tsx b/fe-admin/src/pages/khkk/KhkkDetailPage.tsx index 76723cb..aa05a08 100644 --- a/fe-admin/src/pages/khkk/KhkkDetailPage.tsx +++ b/fe-admin/src/pages/khkk/KhkkDetailPage.tsx @@ -19,6 +19,7 @@ import { Input } from '@/components/ui/Input' import { Label } from '@/components/ui/Label' import { Select } from '@/components/ui/Select' import { KhkkDetailContent } from '@/components/khkk/KhkkDetailContent' +import { KhkkWorkflowPanel } from '@/components/khkk/KhkkWorkflowPanel' import { useAuth } from '@/contexts/AuthContext' import { usePermission } from '@/hooks/usePermission' import { api } from '@/lib/api' @@ -158,13 +159,17 @@ export function KhkkDetailPage() { } /> - {/* [S174 owner] Khối "Quy trình duyệt" (sơ-đồ Bước/Cấp + HÀNH ĐỘNG + 2 lịch sử) ĐÃ GỠ - khỏi trang này — anh chốt "bỏ hết, nó sẽ hiển thị ở Menu duyệt". Nhà của nó nay là - Panel-3 của màn danh sách (`KhkkListPage.tsx:196` — cùng `KhkkWorkflowPanel`), nên - gỡ ở đây là bỏ BẢN SAO THỨ HAI, không phải bỏ tính năng. - 🔴 Hệ quả CÒN LẠI phải biết: ``. */} + {/* [S174 owner] Khối "Quy trình duyệt" GỠ khỏi bản DESKTOP của trang này — anh chốt + "bỏ hết, nó sẽ hiển thị ở Menu duyệt". Nhà của nó ở desktop là Panel-3 màn danh sách + (`KhkkListPage.tsx:196`), nên gỡ = bỏ BẢN SAO THỨ HAI, không phải bỏ tính năng. + 🔴 [A3] NHƯNG ` + navigate(backToList)} /> +
+ {bridgeOpen && setBridgeOpen(false)} />} diff --git a/fe-user/src/components/khkk/KhkkWorkflowPanel.tsx b/fe-user/src/components/khkk/KhkkWorkflowPanel.tsx index 2296ff0..5601048 100644 --- a/fe-user/src/components/khkk/KhkkWorkflowPanel.tsx +++ b/fe-user/src/components/khkk/KhkkWorkflowPanel.tsx @@ -33,7 +33,7 @@ import { useMemo, useRef, useState } from 'react' import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { toast } from 'sonner' -import { Check, History, Paperclip, Send, Trash2, Undo2, Workflow, X } from 'lucide-react' +import { Check, History, Paperclip, Send, Trash2, Undo2, Workflow } from 'lucide-react' import { Button } from '@/components/ui/Button' import { Dialog } from '@/components/ui/Dialog' import { Label } from '@/components/ui/Label' @@ -243,6 +243,29 @@ export function KhkkWorkflowPanel({ action === KhkkTransitionAction.Return || action === KhkkTransitionAction.Reject const confirmDisabled = transition.isPending || (commentRequired && !comment.trim()) + // [S174 · A1 — LỖI THẬT, không phải style] Trước đây tải file bằng `` TRẦN. + // 🔴 JWT chỉ được gắn bởi interceptor axios (`lib/api.ts:18`); thẻ `` KHÔNG đi qua axios + // ⇒ request tới `[Authorize(Policy="KeHoachKyKet.Read")]` + // (`ContractSigningPlansController.cs:222-223`) đi TAY KHÔNG ⇒ **401, nút không tải được**. + // Bê đúng khuôn PE (`PeWorkflowPanel.tsx:327-342`): axios lấy blob → objectURL → click ngầm. + // Phát hiện bởi lane L1 của ensemble; lead verify bằng đối chứng `responseType:'blob'` ở PE. + async function downloadAttachment(a: KhkkAttachmentDto) { + try { + const r = await api.get( + `/contract-signing-plans/${plan.id}/attachments/${a.id}/download`, + { responseType: 'blob' }, + ) + const url = window.URL.createObjectURL(r.data as Blob) + const link = document.createElement('a') + link.href = url + link.download = a.fileName + link.click() + window.URL.revokeObjectURL(url) + } catch (e) { + toast.error(getErrorMessage(e)) + } + } + return (
{/* ── 1. Header + meta {code} v{NN} · {name} ───────────────────────────── */} @@ -453,18 +476,12 @@ export function KhkkWorkflowPanel({ > Trả lại - + {/* 🧊 [S174 owner] Nút "TỪ CHỐI" ĐÃ GỠ — anh chốt "vậy thì bỏ luôn từ chối + ~ tương tự PE". Duyệt NCC có code từ-chối nhưng THỰC TẾ không hiện + (BE gỡ khỏi `nextPhases` + FE lọc, UAT S60) ⇒ KHKK còn hiện là lệch. + 🔴 Chỉ gỡ ĐƯỜNG BẤM ở UI. Máy BE (`KhkkTransitionAction.Reject`, + phase `TuChoi=99`) GIỮ NGUYÊN: phiếu cũ đã từ-chối vẫn hiển thị đúng, + và mở lại sau này chỉ là thêm nút. Gỡ cả máy = mất dữ-liệu lịch sử. */} )} {canDeletePlan && ( @@ -497,12 +514,13 @@ export function KhkkWorkflowPanel({
{a.fileName}
{formatSize(a.fileSize)} · {formatDateTime(a.createdAt)}
- downloadAttachment(a)} className="shrink-0 text-[11px] font-medium text-brand-600 hover:underline" > Tải xuống - + ))} diff --git a/fe-user/src/components/pipeline/PipelineStageFolders.tsx b/fe-user/src/components/pipeline/PipelineStageFolders.tsx index 7db2447..3da59e1 100644 --- a/fe-user/src/components/pipeline/PipelineStageFolders.tsx +++ b/fe-user/src/components/pipeline/PipelineStageFolders.tsx @@ -96,15 +96,11 @@ function stageCount(stage: PipelineStage): number { return stage.content !== undefined ? (stage.count ?? 0) : stage.leaves.length } -function SoonChip() { - // Token lấy verbatim từ dải strip (PePipelineStrip.tsx:50-52) — uppercase CSS - // nên chữ "Sắp" hiển thị "SẮP" đúng như owner gõ. - return ( - - Sắp - - ) -} +// 🧊 [S174 owner O2] `SoonChip()` ĐÃ GỠ — owner: "Bỏ hết đi đổi thành 0". Lane L4 đo được +// KHÔNG giai đoạn nào còn đúng nghĩa "sắp" (cả 4 đều fetch API thật), và `SoonChip` KHÔNG +// export (8 hit nội bộ) ⇒ 0 host ngoài phụ thuộc, gỡ an toàn. +// 🔴 Gỡ KHÔNG đồng nghĩa "thay hết bằng 0": 2 ca đếm-được thì in số, ca KHOÁ-QUYỀN thì bỏ +// trắng (xem chú thích tại chỗ) — in 0 cho ca khoá là nói dối về dữ-liệu. type StageStyle = (typeof STAGE_STYLE)[PipelineStageNo] @@ -189,11 +185,10 @@ function GroupFolder({ group, style }: { group: PipelineGroup; style: StageStyle {group.label} )} - {count > 0 ? ( - {count} - ) : ( - - )} + {/* [S174 owner O2] "Bỏ hết đi đổi thành 0" — luôn in SỐ, kể cả 0. Chữ "SẮP" cũ nói + "giai đoạn chưa xây"; nay CẢ 4 giai đoạn đều gọi API thật (lane L4 đo) ⇒ 0 nghĩa + là "chưa có phiếu", không phải "chưa có tính năng". */} + {count}
{empty ? ( @@ -229,8 +224,11 @@ function StageFolder({ stage, currentStage }: { stage: PipelineStage; currentSta + {/* [S174 owner O2] KHÔNG in "0" ở đây. Đây là ca "chưa có QUYỀN xem", không phải + "có 0 phiếu" — in 0 là NÓI DỐI về dữ-liệu (thực tế có thể đầy phiếu, chỉ là mình + không được xem, và cũng không được phép gọi API để biết). Ổ khoá + `title` đã + mang trọn nghĩa; bỏ chip là đúng, không thay bằng số. */} {label} -
) } @@ -267,10 +265,10 @@ function StageFolder({ stage, currentStage }: { stage: PipelineStage; currentSta > — - ) : count > 0 ? ( - {count} ) : ( - + /* [S174 owner O2] luôn in SỐ (kể cả 0). Nhánh `—` ở trên GIỮ: đó là ca + "không tải được dữ-liệu", khác hẳn "có 0 phiếu" — đừng gộp hai thứ. */ + {count} )} diff --git a/fe-user/src/pages/khkk/KhkkCreatePage.tsx b/fe-user/src/pages/khkk/KhkkCreatePage.tsx index b893b22..3284aa6 100644 --- a/fe-user/src/pages/khkk/KhkkCreatePage.tsx +++ b/fe-user/src/pages/khkk/KhkkCreatePage.tsx @@ -176,7 +176,15 @@ export function KhkkCreatePage() {
-
+ {/* [S174 · B4] Bề ngang cột về ĐÚNG số của Duyệt NCC (`PurchaseEvaluationWorkspacePage.tsx:80` + `260px` / `xl:320px`) — trước đó lead tự đặt 300/340, lệch chuẩn không lý do. + [S174 · A2 — VÁ REGRESSION DO CHÍNH LEAD GÂY RA TRONG PHIÊN NÀY] `
` từng mang + `hidden … lg:block` ⇒ dưới `lg` chỉ còn panel-1, KHÔNG có form ⇒ **mobile không tạo + được phiếu**: bấm phiếu ở cột trái xong thì không có chỗ nào để bấm "Tạo kế hoạch". + 🔴 Vá bằng 2 vế, thiếu vế nào cũng hỏng: (1) `
` bỏ `hidden`, hiện mọi khổ; + (2) mobile xếp DỌC với panel-1 chốt trần `14rem` — không chốt thì panel-1 (danh sách + dài) đẩy form rơi khỏi màn, đúng cái ngõ cụt vừa vá. Từ `lg` trở lên về 1 hàng như cũ. */} +
-
+
{/* (a) Đang XEM một kế hoạch — read-only, có đường quay về form tạo. */} {viewPlanId && (
diff --git a/fe-user/src/pages/khkk/KhkkDetailPage.tsx b/fe-user/src/pages/khkk/KhkkDetailPage.tsx index 76723cb..aa05a08 100644 --- a/fe-user/src/pages/khkk/KhkkDetailPage.tsx +++ b/fe-user/src/pages/khkk/KhkkDetailPage.tsx @@ -19,6 +19,7 @@ import { Input } from '@/components/ui/Input' import { Label } from '@/components/ui/Label' import { Select } from '@/components/ui/Select' import { KhkkDetailContent } from '@/components/khkk/KhkkDetailContent' +import { KhkkWorkflowPanel } from '@/components/khkk/KhkkWorkflowPanel' import { useAuth } from '@/contexts/AuthContext' import { usePermission } from '@/hooks/usePermission' import { api } from '@/lib/api' @@ -158,13 +159,17 @@ export function KhkkDetailPage() { } /> - {/* [S174 owner] Khối "Quy trình duyệt" (sơ-đồ Bước/Cấp + HÀNH ĐỘNG + 2 lịch sử) ĐÃ GỠ - khỏi trang này — anh chốt "bỏ hết, nó sẽ hiển thị ở Menu duyệt". Nhà của nó nay là - Panel-3 của màn danh sách (`KhkkListPage.tsx:196` — cùng `KhkkWorkflowPanel`), nên - gỡ ở đây là bỏ BẢN SAO THỨ HAI, không phải bỏ tính năng. - 🔴 Hệ quả CÒN LẠI phải biết: ``. */} + {/* [S174 owner] Khối "Quy trình duyệt" GỠ khỏi bản DESKTOP của trang này — anh chốt + "bỏ hết, nó sẽ hiển thị ở Menu duyệt". Nhà của nó ở desktop là Panel-3 màn danh sách + (`KhkkListPage.tsx:196`), nên gỡ = bỏ BẢN SAO THỨ HAI, không phải bỏ tính năng. + 🔴 [A3] NHƯNG ` + navigate(backToList)} /> +
+ {bridgeOpen && setBridgeOpen(false)} />}