[CLAUDE] FE-PE: Link hồ sơ auto-detect — http(s) -> hyperlink bấm-mở / đường dẫn ổ mạng -> chữ + nút Copy (x2 app SHA256)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m22s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m22s
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@ -1433,14 +1433,21 @@ function HoSoLinkRow({ ev, readOnly = false }: { ev: PeDetailBundle; readOnly?:
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : ev.hoSoLink ? (
|
) : ev.hoSoLink ? (
|
||||||
<a
|
/^https?:\/\//i.test(ev.hoSoLink.trim()) ? (
|
||||||
href={ev.hoSoLink}
|
// Link web (http/https — vd SharePoint) → bấm mở thẳng tab mới.
|
||||||
target="_blank"
|
<a
|
||||||
rel="noopener noreferrer"
|
href={ev.hoSoLink}
|
||||||
className="break-all text-sm text-brand-600 hover:underline"
|
target="_blank"
|
||||||
>
|
rel="noopener noreferrer"
|
||||||
{ev.hoSoLink}
|
className="break-all text-sm text-brand-600 hover:underline"
|
||||||
</a>
|
>
|
||||||
|
{ev.hoSoLink}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
// Đường dẫn ổ cứng/ổ mạng (O:\…, \\server) → trình duyệt CHẶN mở file://
|
||||||
|
// từ https nên bấm sẽ hụt → hiện chữ + nút Copy để dán vào File Explorer.
|
||||||
|
<PathWithCopy path={ev.hoSoLink} />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<span className="text-sm text-slate-400">—</span>
|
<span className="text-sm text-slate-400">—</span>
|
||||||
)}
|
)}
|
||||||
@ -1449,6 +1456,38 @@ function HoSoLinkRow({ ev, readOnly = false }: { ev: PeDetailBundle; readOnly?:
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// e.bis — Đường dẫn ổ cứng/ổ mạng (không phải http) → chữ + nút Copy. Trình duyệt
|
||||||
|
// CHẶN mở file:// từ trang https nên KHÔNG render <a> bấm-mở (bấm sẽ hụt); thay
|
||||||
|
// bằng Copy → người dùng dán vào File Explorer (máy có map ổ mạng là mở ngay).
|
||||||
|
function PathWithCopy({ path }: { path: string }) {
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
|
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">
|
||||||
|
<code className="min-w-0 flex-1 break-all rounded bg-slate-50 px-2 py-1 text-[13px] text-brand-800 ring-1 ring-slate-200">
|
||||||
|
{path}
|
||||||
|
</code>
|
||||||
|
<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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Form row: label cố định 176px (w-44) bên trái + value bên phải (giống spec).
|
// Form row: label cố định 176px (w-44) bên trái + value bên phải (giống spec).
|
||||||
function FormRow({ label, value }: { label: string; value: React.ReactNode }) {
|
function FormRow({ label, value }: { label: string; value: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1433,14 +1433,21 @@ function HoSoLinkRow({ ev, readOnly = false }: { ev: PeDetailBundle; readOnly?:
|
|||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
) : ev.hoSoLink ? (
|
) : ev.hoSoLink ? (
|
||||||
<a
|
/^https?:\/\//i.test(ev.hoSoLink.trim()) ? (
|
||||||
href={ev.hoSoLink}
|
// Link web (http/https — vd SharePoint) → bấm mở thẳng tab mới.
|
||||||
target="_blank"
|
<a
|
||||||
rel="noopener noreferrer"
|
href={ev.hoSoLink}
|
||||||
className="break-all text-sm text-brand-600 hover:underline"
|
target="_blank"
|
||||||
>
|
rel="noopener noreferrer"
|
||||||
{ev.hoSoLink}
|
className="break-all text-sm text-brand-600 hover:underline"
|
||||||
</a>
|
>
|
||||||
|
{ev.hoSoLink}
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
// Đường dẫn ổ cứng/ổ mạng (O:\…, \\server) → trình duyệt CHẶN mở file://
|
||||||
|
// từ https nên bấm sẽ hụt → hiện chữ + nút Copy để dán vào File Explorer.
|
||||||
|
<PathWithCopy path={ev.hoSoLink} />
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<span className="text-sm text-slate-400">—</span>
|
<span className="text-sm text-slate-400">—</span>
|
||||||
)}
|
)}
|
||||||
@ -1449,6 +1456,38 @@ function HoSoLinkRow({ ev, readOnly = false }: { ev: PeDetailBundle; readOnly?:
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// e.bis — Đường dẫn ổ cứng/ổ mạng (không phải http) → chữ + nút Copy. Trình duyệt
|
||||||
|
// CHẶN mở file:// từ trang https nên KHÔNG render <a> bấm-mở (bấm sẽ hụt); thay
|
||||||
|
// bằng Copy → người dùng dán vào File Explorer (máy có map ổ mạng là mở ngay).
|
||||||
|
function PathWithCopy({ path }: { path: string }) {
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
|
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">
|
||||||
|
<code className="min-w-0 flex-1 break-all rounded bg-slate-50 px-2 py-1 text-[13px] text-brand-800 ring-1 ring-slate-200">
|
||||||
|
{path}
|
||||||
|
</code>
|
||||||
|
<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>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// Form row: label cố định 176px (w-44) bên trái + value bên phải (giống spec).
|
// Form row: label cố định 176px (w-44) bên trái + value bên phải (giống spec).
|
||||||
function FormRow({ label, value }: { label: string; value: React.ReactNode }) {
|
function FormRow({ label, value }: { label: string; value: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
Reference in New Issue
Block a user