[CLAUDE] Contract: KHKK UAT S175 dot-F — gom nut thao tac + hang muc du an + loc nhom (0-mig)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m11s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 6m11s
Anh review truc tiep tren prod, khoanh do tung cho. Land tron cum:
=== 1. GOM NUT THAO TAC (anh: "Bo het di" + "phia duoi them cac nut thao tac"
+ "cho menu dang duyet -> Duyet/Tra lai vay thoi") ===
· THANH NUT DAY moi o `KhkkDetailContent` (sticky bottom-0, khuon PE workspace):
[Xoa phieu] · dong "Cac thay doi da tu dong luu" · [Luu & Gui duyet ->]
· Panel 3 GO "Gui duyet" + "Xoa phieu" => nay CHI con **Duyet / Tra lai**.
· GO nut "+ Lap ke hoach" (header) · nut "Sua" (muc 1) · dai banner "Dang xem ke hoach".
🔴 THU TU CO CHU DICH: KHONG go "Gui duyet" o panel 3 TRUOC khi thanh day co mat — go truoc
la nguoi soan mat duong trinh duyet, phieu ket o Nhap. Vi vay ca cum di CHUNG 1 commit.
🔴 Thanh day chi om nhanh **Submit** — nhanh Approve/Return (o-tich level-finalize + upload
file sau transition) O LAI panel 3. Nhan ban nhanh do sang day la de su-that thu hai cho
duong DUYET.
🔸 KHONG lam nut "Luu" roi: moi o o man nay luu NGAY khi roi o. Them nut khong lam gi la
hua hao — noi thang bang dong chu ben canh thay vi ve nut gia.
🔸 Giu lai dung 1 dong nho "Ve form tao" — bo han thi mo 1 phieu la ket, khong co duong lui.
· `onDeleted` noi vao ca 3 host (List / Create / Detail) de xoa xong khong dung o phieu ma.
=== 2. HANG MUC CUA DU AN (anh: "hang muc cua Du an -. Duyet NCC ay") ===
🔴 Lead bay NHAM o luot truoc: bay `line.tenHangMuc` = danh-muc **SP-002** (86 dong, dung
phan loai HOP DONG). Anh muon **hang muc CONG VIEC cua du an** tu phieu Duyet NCC
(`PE.WorkItemId`). Hai thu trung ten tieng Viet nhung KHAC TRUC — tron la chi sai goi thau.
· BE: `ContractSigningPlanDetailDto` +`PeWorkItemName`; handler join `WorkItems` (loose-Guid
Mig 49, KHONG FK vat ly => join tay null-safe).
· FE: o "Hang muc (du an)" doc `plan.peWorkItemName`; go het khoi liet-ke SP-002 khoi muc 1.
=== 3. MUC 2 RUT VE "HANG MUC + GIA -> TONG" ===
Anh: "Cho nay doi lai la hang muc la dc roi, chon hang muc tien -> thanh tong con lai bo het"
+ "cho chon nhieu dong nhap gia thanh gia tong, ko can so sanh j voi so duyet PRO hay CCM".
· Tieu de: "2. Gia de xuat theo NCC trung thau" -> "2. Hang muc".
· Cot: 6 -> 3 (HANG MUC | GIA | thao-tac). GO **Nha cung cap · Gia tham chieu · Gia duyet**.
· Ghi chu xuong DONG PHU duoi o hang muc (van nhap duoc, khong chiem cot).
· +hang TONG = Sigma gia cac dong.
🔸 Du-lieu 2 cot go di VAN trong DTO; `peReferenceAmount` con dung lam DAU phan biet
dong-goc / dong-them-tay o nut xoa.
=== 4. LOC THEO NHOM (anh: "Loc theo quy trinh luon") ===
Tang duoi man Thao tac hien phieu N1/N7 trong khi dang dung o leaf N2 => doc nham "nhom nay
dang co viec". Nay loc theo `approvalGroup` cua leaf menu. `group == null` => khong loc
(giu duong cu cho host khong truyen).
=== 5. GO DAI ACCENT + 2 O LINK HO SO/GHI CHU ===
· `card-accent` boc `KhkkDetailContent` GO HAN (dai xanh doc man Thao tac). GO CLASS chu
KHONG de `border-0` — class nay ngoai `@layer` nen thang utility (gotcha #66).
· Khoi "Link ho so + Ghi chu" GO TRON ca 2 nhanh ternary. Luot truoc lead moi go o luoi tren
nen 2 o van hien o khoi duoi — anh chup lai dung cho do.
=== CON NO ===
🔴 Cay man Thao tac: anh muon **Nam > Du an > Hang muc > 4 giai doan** (giong cay o man Danh
sach). Hien moi co Du an > Hang muc (gap/mo duoc). Chua land.
🔴 CHUA soi mat prod 375/1366/1440.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@ -28,7 +28,7 @@
|
||||
// tái-hiện vá-5 (đi từ leaf nhóm 2 sang leaf nhóm 5 phải F5 mới đúng). ĐỪNG ĐỘNG.
|
||||
import { useState, type FormEvent, type ReactNode } from 'react'
|
||||
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
import { FileCheck, Pencil, X } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { EmptyState } from '@/components/EmptyState'
|
||||
@ -39,7 +39,6 @@ import { KhkkDetailContent } from '@/components/khkk/KhkkDetailContent'
|
||||
import { KhkkWorkListPanel } from '@/components/khkk/KhkkWorkListPanel'
|
||||
import { api } from '@/lib/api'
|
||||
import { getErrorMessage } from '@/lib/apiError'
|
||||
import { cn } from '@/lib/cn'
|
||||
import { useAuth } from '@/contexts/AuthContext'
|
||||
import {
|
||||
KHKK_APPROVAL_GROUP_DEFAULT,
|
||||
@ -67,7 +66,6 @@ interface WorkflowDto {
|
||||
// chỉnh"). Giữ lại thành hàm chết thì lượt sau có người gọi lại.
|
||||
|
||||
export function KhkkCreatePage() {
|
||||
const navigate = useNavigate()
|
||||
const [searchParams] = useSearchParams()
|
||||
|
||||
const groupParam = searchParams.get('group')
|
||||
@ -203,6 +201,7 @@ export function KhkkCreatePage() {
|
||||
selectedPeId={purchaseEvaluationId || null}
|
||||
selectedPlanId={viewPlanId}
|
||||
onEditPlan={(id) => { setViewPlanId(id); setEditPlan(true) }}
|
||||
group={approvalGroup}
|
||||
/>
|
||||
|
||||
<main className="min-h-0 overflow-y-auto bg-slate-50 p-4 lg:p-6">
|
||||
@ -220,44 +219,35 @@ export function KhkkCreatePage() {
|
||||
const readOnly = !editPlan || !canEdit
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className={cn(
|
||||
'flex flex-wrap items-center justify-between gap-2 rounded-lg border px-4 py-2',
|
||||
readOnly ? 'border-violet-200 bg-violet-50' : 'border-emerald-300 bg-emerald-50',
|
||||
)}>
|
||||
<span className={cn('text-[12px] font-medium', readOnly ? 'text-violet-800' : 'text-emerald-800')}>
|
||||
{readOnly
|
||||
? (editPlan && !canEdit
|
||||
? 'Kế hoạch này không sửa được (đã gửi duyệt / đã duyệt, hoặc bạn không phải người soạn) — chỉ xem.'
|
||||
: 'Đang xem kế hoạch — chỉ xem. Bấm bút chì ở danh sách để sửa.')
|
||||
: '✎ Đang SỬA kế hoạch — thay đổi lưu thẳng vào phiếu.'}
|
||||
</span>
|
||||
<div className="flex items-center gap-2">
|
||||
{readOnly && canEdit && (
|
||||
<Button variant="outline" size="sm" onClick={() => setEditPlan(true)}>
|
||||
<Pencil className="mr-1.5 h-3.5 w-3.5" />
|
||||
Sửa
|
||||
</Button>
|
||||
)}
|
||||
{!readOnly && (
|
||||
<Button variant="outline" size="sm" onClick={() => setEditPlan(false)}>
|
||||
Xong
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="outline" size="sm" onClick={() => navigate(`/khkk/${viewPlanId}`)}>
|
||||
Mở trang đầy đủ
|
||||
</Button>
|
||||
<Button variant="ghost" size="sm" onClick={() => { setViewPlanId(null); setEditPlan(false) }}>
|
||||
<X className="mr-1.5 h-3.5 w-3.5" />
|
||||
Về form tạo
|
||||
</Button>
|
||||
</div>
|
||||
{/* 🧊 [S175 — anh: "bỏ mấy dòng này đi"] Dải banner "Đang xem kế hoạch…" ĐÃ GỠ.
|
||||
Nút của nó đi đâu: **Sửa** → bút chì ở danh sách (đường duy nhất, đúng như
|
||||
banner cũ vẫn dặn) · **Xóa phiếu / Gửi duyệt** → THANH NÚT ĐÁY của
|
||||
`KhkkDetailContent`. Chỉ giữ đúng 1 dòng nhỏ để quay về form tạo — bỏ hẳn
|
||||
thì người dùng mở 1 phiếu xong là kẹt, không có đường lùi. */}
|
||||
<div className="flex items-center justify-end gap-2">
|
||||
{readOnly && canEdit && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setEditPlan(true)}
|
||||
className="inline-flex items-center gap-1 rounded px-2 py-1 text-[11px] font-medium text-brand-700 transition hover:bg-brand-50"
|
||||
>
|
||||
<Pencil className="h-3 w-3" /> Sửa
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { setViewPlanId(null); setEditPlan(false) }}
|
||||
className="inline-flex items-center gap-1 rounded px-2 py-1 text-[11px] text-slate-500 transition hover:bg-slate-100 hover:text-slate-700"
|
||||
>
|
||||
<X className="h-3 w-3" /> Về form tạo
|
||||
</button>
|
||||
</div>
|
||||
{viewPlan.isLoading && <div className="text-sm text-slate-500">Đang tải…</div>}
|
||||
{!viewPlan.isLoading && !viewPlan.data && (
|
||||
<div className="text-sm text-red-600">Không tìm thấy phiếu.</div>
|
||||
)}
|
||||
{viewPlan.data && (
|
||||
<KhkkDetailContent plan={viewPlan.data} readOnly={readOnly} onChanged={() => viewPlan.refetch()} />
|
||||
<KhkkDetailContent plan={viewPlan.data} readOnly={readOnly} onChanged={() => viewPlan.refetch()} onDeleted={() => { setViewPlanId(null); setEditPlan(false) }} />
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -170,7 +170,7 @@ export function KhkkDetailPage() {
|
||||
<KhkkWorkflowPanel plan={k} onChanged={invalidate} onDeleted={() => navigate(backToList)} />
|
||||
</div>
|
||||
|
||||
<KhkkDetailContent plan={k} readOnly={readOnly} onChanged={invalidate} />
|
||||
<KhkkDetailContent plan={k} readOnly={readOnly} onChanged={invalidate} onDeleted={() => navigate("/khkk/list")} />
|
||||
|
||||
{bridgeOpen && <CreateContractFromKhkkDialog plan={k} onClose={() => setBridgeOpen(false)} />}
|
||||
</div>
|
||||
|
||||
@ -27,9 +27,8 @@
|
||||
import { useState } from 'react'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useNavigate, useSearchParams } from 'react-router-dom'
|
||||
import { FileCheck, Plus, X } from 'lucide-react'
|
||||
import { FileCheck, X } from 'lucide-react'
|
||||
import { EmptyState } from '@/components/EmptyState'
|
||||
import { Button } from '@/components/ui/Button'
|
||||
import { KhkkListPanel } from '@/components/khkk/KhkkListPanel'
|
||||
import { KhkkDetailContent } from '@/components/khkk/KhkkDetailContent'
|
||||
import { KhkkWorkflowPanel } from '@/components/khkk/KhkkWorkflowPanel'
|
||||
@ -162,12 +161,10 @@ export function KhkkListPage() {
|
||||
Tên nhóm đã có trong `headerTitle` ngay bên trái (dạng ngắn "— N2"), và dải 4 giai
|
||||
đoạn ở panel giữa đã chỉ rõ đang đứng ở GĐ2 ⇒ chip này là lần kể thứ ba. */}
|
||||
</div>
|
||||
{!deletedView && (
|
||||
<Button onClick={() => navigate(group !== null ? `/khkk/create?group=${group}` : '/khkk/create')}>
|
||||
<Plus className="mr-2 h-4 w-4" />
|
||||
Lập kế hoạch
|
||||
</Button>
|
||||
)}
|
||||
{/* [S175 - anh: "Bo het di"] Nut "+ Lap ke hoach" o header DA GO. Duong lap ke
|
||||
hoach di tu man Thao tac (bam phieu PE o cot trai = nap thang vao form tao) —
|
||||
do moi la duong dung nghiep-vu; nut o day de nguoi dung mo form TRONG khong
|
||||
gan PE nao. */}
|
||||
</header>
|
||||
|
||||
<div className="grid flex-1 grid-cols-1 overflow-hidden lg:grid-cols-[400px_1fr_360px]">
|
||||
@ -239,7 +236,7 @@ export function KhkkListPage() {
|
||||
<div className="text-sm text-red-600">Không tìm thấy phiếu.</div>
|
||||
)}
|
||||
{selectedId && plan && (
|
||||
<KhkkDetailContent plan={plan} readOnly={readOnly} onChanged={() => detail.refetch()} />
|
||||
<KhkkDetailContent plan={plan} readOnly={readOnly} onChanged={() => detail.refetch()} onDeleted={() => setId(null)} />
|
||||
)}
|
||||
</main>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user