[CLAUDE] Supplier: Mig 62 expand 30-field + seed 4 NCC + FE form 2-app
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 5m7s

Phase A of the NCC/TP Excel-import backlog (anh Kiet FDC). Supplier
entity 9 -> 27 fields to hold the 30-column supplier database.

Backend:
- Supplier +18 nullable cols; SupplierType +CaHai=6 (append-only);
  new nullable SupplierStatus enum.
- Mig 62 ExpandSupplierFields (3-file): AddColumn x18 + guarded un-cram
  Sql (clear legacy crammed Note on the 4 seeded rows, exact-match).
  No new table (89), reversible Down.
- Seed fill-nulls-if-exists: populate 30 fields for TRUONGGIANG/TANPHU/
  TGN/DONGDUONG from Excel; idempotent, never clobbers existing cols.
- DTO + Create/Update commands + validators (MaximumLength-only, no
  NotEmpty so open-auth Create minimal payload stays valid) + 2 query
  projections.

Frontend (fe-admin + fe-user, byte-identical SHA-mirror):
- types/master.ts +18 fields +SupplierStatus; SuppliersPage form 4
  section groups + Status select + 3 NAS links via new shared PathLink
  (extracted from PE HoSoLink render+Copy). All new fields optional.

Excel upload auto-map = Phase B (deferred). Tests test-after (UAT mode).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
pqhuy1987
2026-07-06 16:06:11 +07:00
parent 6d217f77ed
commit 778fc98b2f
21 changed files with 7440 additions and 23 deletions

View File

@ -0,0 +1,68 @@
import { useState } from 'react'
import { toast } from 'sonner'
import { Button } from '@/components/ui/Button'
// Đổi đường dẫn Windows → URL file:// (O:\DATA\x → file:///O:/DATA/x · \\srv\share → file://srv/share).
function toFileUrl(p: string): string {
const slashed = p.trim().replace(/\\/g, '/')
const url = slashed.startsWith('//') ? 'file:' + slashed : 'file:///' + slashed
return encodeURI(url)
}
// Link đường dẫn hồ sơ / NAS dùng chung (trích từ PeDetailTabs).
// - Link web (http/https, vd SharePoint) → bấm mở thẳng tab mới.
// - Đường dẫn ổ cứng/ổ mạng (O:\…, \\server) → render LINK file:// để BẤM-THỬ mở File
// Explorer (chạy nếu máy/trình duyệt cho phép: Edge bật policy IntranetFileLinksEnabled
// qua GPO + host trong Intranet Zone) + nút Copy dự phòng (default Chrome/Edge CHẶN
// https→file:// → bấm no-op → khi đó dùng Copy dán vào File Explorer, máy đã map ổ mạng
// là mở ngay).
export function PathLink({ path }: { path: string }) {
const [copied, setCopied] = useState(false)
const trimmed = path.trim()
if (/^https?:\/\//i.test(trimmed)) {
return (
<a
href={path}
target="_blank"
rel="noopener noreferrer"
className="break-all text-sm text-brand-600 hover:underline"
>
{path}
</a>
)
}
const copy = async () => {
try {
await navigator.clipboard.writeText(path)
setCopied(true)
setTimeout(() => setCopied(false), 1500)
} catch {
toast.error('Không copy được — vui lòng bôi đen đường dẫn rồi Ctrl+C.')
}
}
return (
<div className="flex max-w-2xl items-start gap-2">
<a
href={toFileUrl(path)}
target="_blank"
rel="noopener noreferrer"
className="min-w-0 flex-1 break-all rounded bg-slate-50 px-2 py-1 text-[13px] text-brand-700 ring-1 ring-slate-200 transition hover:bg-brand-50 hover:underline"
title="Bấm mở trong File Explorer (cần Edge + IT bật policy). Không mở được thì bấm Copy rồi dán vào File Explorer."
>
{path}
</a>
<Button
type="button"
variant="outline"
onClick={copy}
className="h-8 shrink-0 px-2.5 text-xs"
title="Copy đường dẫn rồi dán vào File Explorer (This PC)"
>
{copied ? '✓ Đã copy' : 'Copy'}
</Button>
</div>
)
}