[CLAUDE] FE: PE bang ngan sach muc con thut dong + gach dau dong (phan biet muc co so / khong so)
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m39s
All checks were successful
Deploy SOLUTION_ERP / build-deploy (push) Successful in 4m39s
Tra Sol + anh Kiet (Zalo, annotate anh do): muc con (khong co so) thut vao + gach dau dong '–' de phan biet voi muc cha co so (1-9). BudgetRow +indent prop (pl-5 + dash span). Ap dung: Block A '– Ngan sach Ban hanh lan dau' + '– Ngan sach V0/hieu chinh tang giam' (con cua Ngan sach full); Block B '– Gia tri ky nay' + '– So sanh voi ngan sach ky nay' + '– So voi NS' + '– So sanh voi Ngan sach full'. Muc 1-9 giu cap cha. FE-only, 2 app SHA256-identical PeDetailTabs. Build PASS x2. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -1010,7 +1010,7 @@ function VndInlineEdit({
|
|||||||
// 1 dòng bảng — label trái | value phải (right-align) | cột 3 (% hoặc ghi chú).
|
// 1 dòng bảng — label trái | value phải (right-align) | cột 3 (% hoặc ghi chú).
|
||||||
// tone: 'brand' = nền brand đậm chữ trắng (dòng tổng) · 'brand-soft' = nền brand-50.
|
// tone: 'brand' = nền brand đậm chữ trắng (dòng tổng) · 'brand-soft' = nền brand-50.
|
||||||
function BudgetRow({
|
function BudgetRow({
|
||||||
label, sub, value, third, tone, danger, mono = true,
|
label, sub, value, third, tone, danger, mono = true, indent = false,
|
||||||
}: {
|
}: {
|
||||||
label: React.ReactNode
|
label: React.ReactNode
|
||||||
sub?: React.ReactNode
|
sub?: React.ReactNode
|
||||||
@ -1019,6 +1019,8 @@ function BudgetRow({
|
|||||||
tone?: 'brand' | 'brand-soft' | 'blue-soft'
|
tone?: 'brand' | 'brand-soft' | 'blue-soft'
|
||||||
danger?: boolean
|
danger?: boolean
|
||||||
mono?: boolean
|
mono?: boolean
|
||||||
|
/** [S77 Tra Sol] mục con (không có số) → thụt dòng + gạch đầu dòng phân biệt với mục cha có số. */
|
||||||
|
indent?: boolean
|
||||||
}) {
|
}) {
|
||||||
const toneCls =
|
const toneCls =
|
||||||
tone === 'brand' ? 'bg-[#1F7DC1] text-white font-semibold'
|
tone === 'brand' ? 'bg-[#1F7DC1] text-white font-semibold'
|
||||||
@ -1027,8 +1029,10 @@ function BudgetRow({
|
|||||||
: ''
|
: ''
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex items-start gap-2 border-b border-slate-100 px-3 py-1.5 text-[13px]', toneCls)}>
|
<div className={cn('flex items-start gap-2 border-b border-slate-100 px-3 py-1.5 text-[13px]', toneCls)}>
|
||||||
<div className="min-w-0 flex-1">
|
<div className={cn('min-w-0 flex-1', indent && 'pl-5')}>
|
||||||
<div className={cn(tone === 'brand' ? 'text-white' : 'text-slate-700')}>{label}</div>
|
<div className={cn(tone === 'brand' ? 'text-white' : 'text-slate-700')}>
|
||||||
|
{indent && <span className="mr-1 text-slate-400">–</span>}{label}
|
||||||
|
</div>
|
||||||
{sub && <div className={cn('text-[10px]', tone === 'brand' ? 'text-white/70' : 'text-slate-400')}>{sub}</div>}
|
{sub && <div className={cn('text-[10px]', tone === 'brand' ? 'text-white/70' : 'text-slate-400')}>{sub}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
@ -1283,7 +1287,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
</tr>
|
</tr>
|
||||||
{/* Ban hành lần đầu */}
|
{/* Ban hành lần đầu */}
|
||||||
<tr>
|
<tr>
|
||||||
<td className="border border-slate-300 px-3 py-1.5 text-slate-700">Ngân sách Ban hành lần đầu</td>
|
<td className="border border-slate-300 px-3 py-1.5 pl-8 text-slate-700">– Ngân sách Ban hành lần đầu</td>
|
||||||
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
||||||
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
||||||
<BudgetCell
|
<BudgetCell
|
||||||
@ -1304,7 +1308,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
</tr>
|
</tr>
|
||||||
{/* V0 / hiệu chỉnh tăng giảm (cho phép ÂM) */}
|
{/* V0 / hiệu chỉnh tăng giảm (cho phép ÂM) */}
|
||||||
<tr>
|
<tr>
|
||||||
<td className="border border-slate-300 px-3 py-1.5 text-slate-700">Ngân sách V0 / hiệu chỉnh tăng giảm</td>
|
<td className="border border-slate-300 px-3 py-1.5 pl-8 text-slate-700">– Ngân sách V0 / hiệu chỉnh tăng giảm</td>
|
||||||
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
||||||
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
||||||
<BudgetCell
|
<BudgetCell
|
||||||
@ -1405,6 +1409,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="blue-soft"
|
tone="blue-soft"
|
||||||
label="Giá trị kỳ này"
|
label="Giá trị kỳ này"
|
||||||
|
indent
|
||||||
value={
|
value={
|
||||||
proposalOver ? (
|
proposalOver ? (
|
||||||
<span className="inline-block rounded bg-[#C00000] px-2 py-0.5 font-bold text-white">{fmtVnd(row4)}</span>
|
<span className="inline-block rounded bg-[#C00000] px-2 py-0.5 font-bold text-white">{fmtVnd(row4)}</span>
|
||||||
@ -1414,6 +1419,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="blue-soft"
|
tone="blue-soft"
|
||||||
label="So sánh với ngân sách kỳ này"
|
label="So sánh với ngân sách kỳ này"
|
||||||
|
indent
|
||||||
sub="= 3 − 4"
|
sub="= 3 − 4"
|
||||||
value={<span className={cn(cmpPeriod < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmpPeriod)}</span>}
|
value={<span className={cn(cmpPeriod < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmpPeriod)}</span>}
|
||||||
third={fmtPct(cmpPeriod, row3) ?? undefined}
|
third={fmtPct(cmpPeriod, row3) ?? undefined}
|
||||||
@ -1435,6 +1441,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
/>
|
/>
|
||||||
<BudgetRow
|
<BudgetRow
|
||||||
label="So với NS"
|
label="So với NS"
|
||||||
|
indent
|
||||||
sub="= 5 − 6"
|
sub="= 5 − 6"
|
||||||
value={<span className={cn(cmp56 < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmp56)}</span>}
|
value={<span className={cn(cmp56 < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmp56)}</span>}
|
||||||
third={fmtPct(cmp56, row5) ?? undefined}
|
third={fmtPct(cmp56, row5) ?? undefined}
|
||||||
@ -1486,6 +1493,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="brand-soft"
|
tone="brand-soft"
|
||||||
label="So sánh với Ngân sách full"
|
label="So sánh với Ngân sách full"
|
||||||
|
indent
|
||||||
sub="= Ngân sách full − 9"
|
sub="= Ngân sách full − 9"
|
||||||
value={<span className={cn(cmpFull < 0 && 'font-bold text-red-600')}>{fmtVndSigned(cmpFull)}</span>}
|
value={<span className={cn(cmpFull < 0 && 'font-bold text-red-600')}>{fmtVndSigned(cmpFull)}</span>}
|
||||||
third={fmtPct(cmpFull, full) ?? undefined}
|
third={fmtPct(cmpFull, full) ?? undefined}
|
||||||
|
|||||||
@ -1010,7 +1010,7 @@ function VndInlineEdit({
|
|||||||
// 1 dòng bảng — label trái | value phải (right-align) | cột 3 (% hoặc ghi chú).
|
// 1 dòng bảng — label trái | value phải (right-align) | cột 3 (% hoặc ghi chú).
|
||||||
// tone: 'brand' = nền brand đậm chữ trắng (dòng tổng) · 'brand-soft' = nền brand-50.
|
// tone: 'brand' = nền brand đậm chữ trắng (dòng tổng) · 'brand-soft' = nền brand-50.
|
||||||
function BudgetRow({
|
function BudgetRow({
|
||||||
label, sub, value, third, tone, danger, mono = true,
|
label, sub, value, third, tone, danger, mono = true, indent = false,
|
||||||
}: {
|
}: {
|
||||||
label: React.ReactNode
|
label: React.ReactNode
|
||||||
sub?: React.ReactNode
|
sub?: React.ReactNode
|
||||||
@ -1019,6 +1019,8 @@ function BudgetRow({
|
|||||||
tone?: 'brand' | 'brand-soft' | 'blue-soft'
|
tone?: 'brand' | 'brand-soft' | 'blue-soft'
|
||||||
danger?: boolean
|
danger?: boolean
|
||||||
mono?: boolean
|
mono?: boolean
|
||||||
|
/** [S77 Tra Sol] mục con (không có số) → thụt dòng + gạch đầu dòng phân biệt với mục cha có số. */
|
||||||
|
indent?: boolean
|
||||||
}) {
|
}) {
|
||||||
const toneCls =
|
const toneCls =
|
||||||
tone === 'brand' ? 'bg-[#1F7DC1] text-white font-semibold'
|
tone === 'brand' ? 'bg-[#1F7DC1] text-white font-semibold'
|
||||||
@ -1027,8 +1029,10 @@ function BudgetRow({
|
|||||||
: ''
|
: ''
|
||||||
return (
|
return (
|
||||||
<div className={cn('flex items-start gap-2 border-b border-slate-100 px-3 py-1.5 text-[13px]', toneCls)}>
|
<div className={cn('flex items-start gap-2 border-b border-slate-100 px-3 py-1.5 text-[13px]', toneCls)}>
|
||||||
<div className="min-w-0 flex-1">
|
<div className={cn('min-w-0 flex-1', indent && 'pl-5')}>
|
||||||
<div className={cn(tone === 'brand' ? 'text-white' : 'text-slate-700')}>{label}</div>
|
<div className={cn(tone === 'brand' ? 'text-white' : 'text-slate-700')}>
|
||||||
|
{indent && <span className="mr-1 text-slate-400">–</span>}{label}
|
||||||
|
</div>
|
||||||
{sub && <div className={cn('text-[10px]', tone === 'brand' ? 'text-white/70' : 'text-slate-400')}>{sub}</div>}
|
{sub && <div className={cn('text-[10px]', tone === 'brand' ? 'text-white/70' : 'text-slate-400')}>{sub}</div>}
|
||||||
</div>
|
</div>
|
||||||
<div className={cn(
|
<div className={cn(
|
||||||
@ -1283,7 +1287,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
</tr>
|
</tr>
|
||||||
{/* Ban hành lần đầu */}
|
{/* Ban hành lần đầu */}
|
||||||
<tr>
|
<tr>
|
||||||
<td className="border border-slate-300 px-3 py-1.5 text-slate-700">Ngân sách Ban hành lần đầu</td>
|
<td className="border border-slate-300 px-3 py-1.5 pl-8 text-slate-700">– Ngân sách Ban hành lần đầu</td>
|
||||||
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
||||||
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
||||||
<BudgetCell
|
<BudgetCell
|
||||||
@ -1304,7 +1308,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
</tr>
|
</tr>
|
||||||
{/* V0 / hiệu chỉnh tăng giảm (cho phép ÂM) */}
|
{/* V0 / hiệu chỉnh tăng giảm (cho phép ÂM) */}
|
||||||
<tr>
|
<tr>
|
||||||
<td className="border border-slate-300 px-3 py-1.5 text-slate-700">Ngân sách V0 / hiệu chỉnh tăng giảm</td>
|
<td className="border border-slate-300 px-3 py-1.5 pl-8 text-slate-700">– Ngân sách V0 / hiệu chỉnh tăng giảm</td>
|
||||||
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
<td className="border border-slate-300 px-2 py-1.5 text-right text-slate-300">—</td>
|
||||||
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
<td className="border border-slate-300 px-1.5 py-1.5 text-right align-top">
|
||||||
<BudgetCell
|
<BudgetCell
|
||||||
@ -1405,6 +1409,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="blue-soft"
|
tone="blue-soft"
|
||||||
label="Giá trị kỳ này"
|
label="Giá trị kỳ này"
|
||||||
|
indent
|
||||||
value={
|
value={
|
||||||
proposalOver ? (
|
proposalOver ? (
|
||||||
<span className="inline-block rounded bg-[#C00000] px-2 py-0.5 font-bold text-white">{fmtVnd(row4)}</span>
|
<span className="inline-block rounded bg-[#C00000] px-2 py-0.5 font-bold text-white">{fmtVnd(row4)}</span>
|
||||||
@ -1414,6 +1419,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="blue-soft"
|
tone="blue-soft"
|
||||||
label="So sánh với ngân sách kỳ này"
|
label="So sánh với ngân sách kỳ này"
|
||||||
|
indent
|
||||||
sub="= 3 − 4"
|
sub="= 3 − 4"
|
||||||
value={<span className={cn(cmpPeriod < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmpPeriod)}</span>}
|
value={<span className={cn(cmpPeriod < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmpPeriod)}</span>}
|
||||||
third={fmtPct(cmpPeriod, row3) ?? undefined}
|
third={fmtPct(cmpPeriod, row3) ?? undefined}
|
||||||
@ -1435,6 +1441,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
/>
|
/>
|
||||||
<BudgetRow
|
<BudgetRow
|
||||||
label="So với NS"
|
label="So với NS"
|
||||||
|
indent
|
||||||
sub="= 5 − 6"
|
sub="= 5 − 6"
|
||||||
value={<span className={cn(cmp56 < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmp56)}</span>}
|
value={<span className={cn(cmp56 < 0 && 'font-semibold text-red-600')}>{fmtVndSigned(cmp56)}</span>}
|
||||||
third={fmtPct(cmp56, row5) ?? undefined}
|
third={fmtPct(cmp56, row5) ?? undefined}
|
||||||
@ -1486,6 +1493,7 @@ function PeBudgetSummaryTable({ ev, readOnly }: { ev: PeDetailBundle; readOnly:
|
|||||||
<BudgetRow
|
<BudgetRow
|
||||||
tone="brand-soft"
|
tone="brand-soft"
|
||||||
label="So sánh với Ngân sách full"
|
label="So sánh với Ngân sách full"
|
||||||
|
indent
|
||||||
sub="= Ngân sách full − 9"
|
sub="= Ngân sách full − 9"
|
||||||
value={<span className={cn(cmpFull < 0 && 'font-bold text-red-600')}>{fmtVndSigned(cmpFull)}</span>}
|
value={<span className={cn(cmpFull < 0 && 'font-bold text-red-600')}>{fmtVndSigned(cmpFull)}</span>}
|
||||||
third={fmtPct(cmpFull, full) ?? undefined}
|
third={fmtPct(cmpFull, full) ?? undefined}
|
||||||
|
|||||||
Reference in New Issue
Block a user