[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
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:
68
fe-user/src/components/ui/PathLink.tsx
Normal file
68
fe-user/src/components/ui/PathLink.tsx
Normal 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>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user