Compare commits

...
6 Commits
Author SHA1 Message Date
jcchoi c2396f093b 필수입력 안내 메세지
Deploy Frontend / deploy (push) Successful in 8m31s
2026-10-07 19:43:06 +09:00
jcchoi bdf65dcfd1 설치인가 사업구분 팝업 사이즈 조정 2026-10-07 19:42:42 +09:00
jcchoi 2aefbe17ee 웹접근성 2차 수정 2026-10-07 19:42:20 +09:00
jcchoi 4482b92ccd 메뉴간 탭이동
Deploy Frontend / deploy (push) Successful in 7m33s
2026-10-06 17:41:39 +09:00
jcchoi d3c39caefb 웹 접근성 조치 2026-10-06 14:32:26 +09:00
jcchoi 24c5dce24d 대체 텍스트 적용 2026-10-06 13:18:58 +09:00
111 changed files with 459 additions and 348 deletions
@@ -76,7 +76,7 @@ function AprvrPickerDialog({ open, onOpenChange, atrzSeComCd, onSelect }: AprvrP
배치된 검토인력이 없습니다. 배치된 검토인력이 없습니다.
</p> </p>
) : ( ) : (
<Table className="w-full"> <Table caption="결재자 선택 목록으로 성명, 부서, 직위, 직급, 선택 정보 제공" className="w-full">
<colgroup> <colgroup>
<col width="25%" /> <col width="25%" />
<col width="25%" /> <col width="25%" />
@@ -162,7 +162,7 @@ function ElaprAplnPickerGrid({
</p> </p>
) : ( ) : (
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}> <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<Table className="w-full"> <Table caption="결재선 선택 목록으로 결재순서, 결재구분, 결재자 정보 제공" className="w-full">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="10%" /> <col width="10%" />
@@ -315,7 +315,7 @@ function ElaprApprovalDialog({
collisionDetection={closestCenter} collisionDetection={closestCenter}
onDragEnd={handleDragEnd} onDragEnd={handleDragEnd}
> >
<Table className="w-full"> <Table caption="결재 진행 현황 목록으로 결재순서, 결재구분, 결재자, 전결자 지정, 결재상태, 관리 정보 제공" className="w-full">
<colgroup> <colgroup>
<col width="8%" /> <col width="8%" />
<col width="8%" /> <col width="8%" />
@@ -66,6 +66,7 @@ function ElaprTmpltSelectTable({
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}, },
dataTableOptions: { dataTableOptions: {
caption: "결재서식 선택 목록",
onRowClick: (row) => { onRowClick: (row) => {
setRowSelection({ [row.elaprTmpltId]: true }); setRowSelection({ [row.elaprTmpltId]: true });
onSelectTmplt(row); onSelectTmplt(row);
@@ -73,7 +73,7 @@ function AprvrPickerDialog({
배치된 검토인력이 없습니다. 배치된 검토인력이 없습니다.
</p> </p>
) : ( ) : (
<Table className="w-full"> <Table caption="검토인력 목록으로 성명, 부서, 직위, 직급, 선택 정보 제공" className="w-full">
<colgroup> <colgroup>
<col width="25%" /> <col width="25%" />
<col width="25%" /> <col width="25%" />
@@ -185,7 +185,7 @@ function ElaprAplnGrid({ elaprTmpltId }: ElaprAplnGridProps) {
</p> </p>
) : ( ) : (
<DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}> <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
<Table className="w-full"> <Table caption="결재선 목록으로 결재순서, 결재구분, 결재자 정보 제공" className="w-full">
<colgroup> <colgroup>
<col width="5%" /> <col width="5%" />
<col width="10%" /> <col width="10%" />
@@ -90,6 +90,7 @@ function ElaprTmpltList({ selectedTmpltId, onSelectTmplt }: ElaprTmpltListProps)
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}, },
dataTableOptions: { dataTableOptions: {
caption: "결재서식 목록으로 결재서식명 정보 제공",
onRowClick: (row) => { onRowClick: (row) => {
setRowSelection({ [row.elaprTmpltId]: true }); setRowSelection({ [row.elaprTmpltId]: true });
onSelectTmplt(row); onSelectTmplt(row);
@@ -67,7 +67,12 @@ function CklstArtclList({ cklstSn }: CklstArtclListProps) {
</div> </div>
), ),
Empty: <NoData />, Empty: <NoData />,
Success: () => <DataTable table={table} />, Success: () => (
<DataTable
table={table}
caption="체크리스트 항목 목록: 항목명, 검토내용, 검토결과 정보 제공"
/>
),
}); });
const handleFormSubmit = async (values: CklstArtclFormValues) => { const handleFormSubmit = async (values: CklstArtclFormValues) => {
@@ -83,6 +83,7 @@ function CklstMngList({ selectedCklstSn, onSelectCklst }: CklstMngListProps) {
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}, },
dataTableOptions: { dataTableOptions: {
caption: "체크리스트 목록",
onRowClick: (row) => { onRowClick: (row) => {
setRowSelection({ [String(row.cklstSn)]: true }); setRowSelection({ [String(row.cklstSn)]: true });
onSelectCklst(row); onSelectCklst(row);
@@ -51,7 +51,7 @@ function CklstPreviewDialog({
{displayRows.length === 0 ? ( {displayRows.length === 0 ? (
<p className="py-6 text-center text-muted-foreground">표시할 항목이 없습니다.</p> <p className="py-6 text-center text-muted-foreground">표시할 항목이 없습니다.</p>
) : ( ) : (
<Table> <Table caption={`체크리스트 ${cklstNm} 미리보기`}>
<colgroup> <colgroup>
<col width="25%" /> <col width="25%" />
<col width="50%" /> <col width="50%" />
@@ -277,7 +277,7 @@ function CklstRvwGrid({ selectedCklst }: CklstRvwGridProps) {
등록된 항목이 없습니다. [추가]로 1단계 항목을 등록하세요. 등록된 항목이 없습니다. [추가]로 1단계 항목을 등록하세요.
</p> </p>
) : ( ) : (
<Table className="w-full"> <Table caption="체크리스트 항목 목록" className="w-full">
<colgroup> <colgroup>
<col width="16%" /> <col width="16%" />
<col width="36%" /> <col width="36%" />
@@ -103,7 +103,7 @@ function AcntgCodeTabPanel() {
</p> </p>
) : ( ) : (
<div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1"> <div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1">
<Table className="w-full"> <Table caption="회계구분 코드 목록" className="w-full">
<colgroup> <colgroup>
<col width="14%" /> <col width="14%" />
<col width="16%" /> <col width="16%" />
@@ -103,7 +103,7 @@ function CnstpCodeTabPanel() {
</p> </p>
) : ( ) : (
<div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1"> <div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1">
<Table className="w-full"> <Table caption="공종구분 코드 목록" className="w-full">
<colgroup> <colgroup>
<col width="14%" /> <col width="14%" />
<col width="16%" /> <col width="16%" />
@@ -103,7 +103,7 @@ function FnrsSharCodeTabPanel() {
</p> </p>
) : ( ) : (
<div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1"> <div className="max-h-[60rem] overflow-y-auto px-4 pb-4 pt-1">
<Table className="w-full"> <Table caption="재원분담 코드 목록" className="w-full">
<colgroup> <colgroup>
<col width="14%" /> <col width="14%" />
<col width="16%" /> <col width="16%" />
@@ -155,7 +155,7 @@
} }
.basinLabel.active { .basinLabel.active {
background: #006bf8; background: #0056b3;
color: #fff; color: #fff;
border-color: #96c3ff; border-color: #96c3ff;
box-shadow: 0 4px 12px rgba(0, 107, 248, 0.3); box-shadow: 0 4px 12px rgba(0, 107, 248, 0.3);
@@ -40,18 +40,18 @@ export function DashboardNotiList({
); );
return ( return (
<section className="card card-border m-0 bg-background"> <section className="card card-border m-0 bg-[#FAFBFC]">
<div className="card-header flex items-center justify-between gap-4"> <div className="card-header flex items-center justify-between gap-4">
<h3 className="text-2xl font-semibold"> <h3 className="text-2xl font-semibold">
알림이력 알림이력
{dataUpdatedAt > 0 ? ( {dataUpdatedAt > 0 ? (
<span className="pl-2 text-lg font-medium text-muted-foreground"> <span className="pl-2 text-lg font-medium text-[#4A4A4A]">
(업데이트 일시: {dayjs(dataUpdatedAt).format("YYYY-MM-DD HH:mm")}) (업데이트 일시: {dayjs(dataUpdatedAt).format("YYYY-MM-DD HH:mm")})
</span> </span>
) : null} ) : null}
</h3> </h3>
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<Button type="button" size="sm" color="white" onClick={() => router.push("/nti-hstry")}> <Button type="button" size="sm" color="white" className="!text-[#0056B3]" onClick={() => router.push("/nti-hstry")}>
전체보기 전체보기
</Button> </Button>
</div> </div>
@@ -60,7 +60,7 @@ export function DashboardNotiList({
<div className="flex flex-col gap-4 p-2"> <div className="flex flex-col gap-4 p-2">
<div className="flex flex-wrap gap-2 pt-2"> <div className="flex flex-wrap gap-2 pt-2">
{NOTI_STAT_CHIPS.map((chip) => ( {NOTI_STAT_CHIPS.map((chip) => (
<Badge key={chip.field} color={chip.color}> <Badge key={chip.field} color={chip.color} className={chip.className}>
{chip.label} {isPending ? "-" : (notiStats?.[chip.field] ?? 0)}건 {chip.label} {isPending ? "-" : (notiStats?.[chip.field] ?? 0)}건
</Badge> </Badge>
))} ))}
@@ -75,7 +75,7 @@ export function DashboardNotiList({
) : null} ) : null}
{isError ? ( {isError ? (
<p className="flex min-h-[12rem] items-center justify-center text-muted-foreground"> <p className="flex min-h-[12rem] items-center justify-center text-[#4A4A4A]">
알림이력을 불러오지 못했습니다. 알림이력을 불러오지 못했습니다.
</p> </p>
) : null} ) : null}
@@ -110,11 +110,11 @@ interface DashboardNotiRowProps {
function DashboardNotiRow({ row, isActionPending, onAction }: DashboardNotiRowProps) { function DashboardNotiRow({ row, isActionPending, onAction }: DashboardNotiRowProps) {
return ( return (
<div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-4 border-b px-2 py-4 last:border-b-0"> <div className="grid grid-cols-[auto_minmax(0,1fr)_auto] items-center gap-4 border-b px-2 py-4 last:border-b-0">
<span className="text-lg text-muted-foreground"> <span className="text-lg text-[#4A4A4A]">
{row.regDt ? dayjs(row.regDt).format("YYYY-MM-DD") : "-"} {row.regDt ? dayjs(row.regDt).format("YYYY-MM-DD") : "-"}
</span> </span>
<p className="min-w-0 line-clamp-2 text-xl sm:line-clamp-1">{row.notiTtl}</p> <p className="min-w-0 line-clamp-2 text-xl sm:line-clamp-1">{row.notiTtl}</p>
<Button type="button" size="sm" color="white" disabled={isActionPending} onClick={onAction}> <Button type="button" size="sm" color="white" className="!text-[#0056B3]" disabled={isActionPending} onClick={onAction}>
처리하기 처리하기
</Button> </Button>
</div> </div>
@@ -137,7 +137,7 @@ function resolveNotiUrl(row: NotiAsUserResponseDto) {
} }
const NOTI_STAT_CHIPS = [ const NOTI_STAT_CHIPS = [
{ field: "todayCount", label: "오늘", color: "green" }, { field: "todayCount", label: "오늘", color: "green", className: "!bg-[#188038]" },
{ field: "delayCount", label: "지연", color: "orange" }, { field: "delayCount", label: "지연", color: "orange", className: "!bg-[#C5221F]" },
{ field: "pendingCount", label: "완료대기", color: "gray" }, { field: "pendingCount", label: "완료대기", color: "gray", className: "!bg-[#5F6368]" },
] as const; ] as const;
@@ -39,16 +39,17 @@ export function DashboardNoticeTable() {
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}, },
dataTableOptions: { dataTableOptions: {
caption: "공지사항 목록",
variant: "line", variant: "line",
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
}); });
return ( return (
<section className="card card-border m-0 bg-background"> <section className="card card-border m-0 bg-[#FAFBFC]">
<div className="card-header flex items-center justify-between"> <div className="card-header flex items-center justify-between">
<h3 className="text-2xl font-semibold">공지사항</h3> <h3 className="text-2xl font-semibold">공지사항</h3>
<Button type="button" size="sm" color="white" onClick={handleMoreClick}> <Button type="button" size="sm" color="white" className="!text-[#0056B3]" onClick={handleMoreClick}>
더보기 더보기
</Button> </Button>
</div> </div>
@@ -11,7 +11,7 @@ export function DashboardPage() {
const { data, isPending, isError, dataUpdatedAt } = useGetMainDashboard(); const { data, isPending, isError, dataUpdatedAt } = useGetMainDashboard();
return ( return (
<div className="mt-4 flex gap-4 px-[1.8rem] pb-6"> <div className="flex min-h-full gap-4 bg-[#E9EDF2] px-[1.8rem] pb-6 pt-4 text-[#1E1E1E]">
<div className="hidden flex-[0.5] sm:block"> <div className="hidden flex-[0.5] sm:block">
<NationalAsMap basinDocPrgrsList={data?.basinDocPrgrsList} /> <NationalAsMap basinDocPrgrsList={data?.basinDocPrgrsList} />
</div> </div>
@@ -24,7 +24,7 @@ export function DocPrgrsSttsCards({ items, isPending, isError }: DocPrgrsSttsCar
if (isError) { if (isError) {
return ( return (
<div className="card card-border m-0 flex min-h-[14rem] items-center justify-center bg-background text-muted-foreground"> <div className="card card-border m-0 flex min-h-[14rem] items-center justify-center bg-[#FAFBFC] text-[#4A4A4A]">
진행상황을 불러오지 못했습니다. 진행상황을 불러오지 못했습니다.
</div> </div>
); );
@@ -39,7 +39,7 @@ export function DocPrgrsSttsCards({ items, isPending, isError }: DocPrgrsSttsCar
return ( return (
<div <div
key={slot.docSeComCd} key={slot.docSeComCd}
className="card card-border hover:bg-muted/40 m-0 block bg-background transition-colors" className="card card-border hover:bg-muted/40 m-0 block bg-[#FAFBFC] transition-colors"
> >
<div className="card-header"> <div className="card-header">
<h3 className="text-2xl font-semibold">{slot.title}</h3> <h3 className="text-2xl font-semibold">{slot.title}</h3>
@@ -90,7 +90,7 @@ function DocPrgrsSttsMetric({
> >
<Icon className="size-6" /> <Icon className="size-6" />
</span> </span>
<span className="text-xl text-muted-foreground">{label}</span> <span className="text-xl text-[#4A4A4A]">{label}</span>
<span className="text-3xl font-semibold tabular-nums">{count}</span> <span className="text-3xl font-semibold tabular-nums">{count}</span>
</div> </div>
); );
@@ -107,21 +107,21 @@ const STAT_METRICS = [
{ {
field: "reqCnt", field: "reqCnt",
label: "신청", label: "신청",
iconClassName: "bg-blue-500", iconClassName: "bg-[#4285F4]",
bgColor: "bg-blue-100", bgColor: "bg-blue-100",
Icon: FilePlus, Icon: FilePlus,
}, },
{ {
field: "prgrsCnt", field: "prgrsCnt",
label: "진행", label: "진행",
iconClassName: "bg-emerald-500", iconClassName: "bg-[#34A853]",
bgColor: "bg-emerald-100", bgColor: "bg-emerald-100",
Icon: RefreshCw, Icon: RefreshCw,
}, },
{ {
field: "cmptnCnt", field: "cmptnCnt",
label: "완료", label: "완료",
iconClassName: "bg-orange-500", iconClassName: "bg-[#EA4335]",
bgColor: "bg-orange-100", bgColor: "bg-orange-100",
Icon: CircleCheck, Icon: CircleCheck,
}, },
@@ -18,7 +18,7 @@ export function NationalAsMap({ basinDocPrgrsList }: NationalAsMapProps) {
const popupColumnSpan = Math.max(1, popupContent.items.length); const popupColumnSpan = Math.max(1, popupContent.items.length);
return ( return (
<section className="card card-border m-0 flex h-full min-h-[40rem] flex-col bg-background"> <section className="card card-border m-0 flex h-full min-h-[40rem] flex-col bg-[#FAFBFC]">
<div className="card-header"> <div className="card-header">
<h3 className="text-2xl font-semibold">전국 행정지원 지도</h3> <h3 className="text-2xl font-semibold">전국 행정지원 지도</h3>
</div> </div>
@@ -165,8 +165,11 @@ function DesignFormPage({ mode, initialData, createDefaults }: DesignFormPagePro
<FormProvider {...form}> <FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-6 space-y-4"> <form onSubmit={form.handleSubmit(onSave)} className="mt-6 space-y-4">
<SectionCollapsibleGroup> <SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2"> <div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle /> <SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
{initialData?.detDto?.designCnstnDocNo && ( {initialData?.detDto?.designCnstnDocNo && (
@@ -59,6 +59,7 @@ function DesignList({ searchParams, pagination, onPaginationChange }: DesignList
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "설계검토 목록",
viewPagination: true, viewPagination: true,
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
@@ -36,7 +36,7 @@ function BasicInfoFormSection() {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="사업 기본 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -45,7 +45,7 @@ function BasicInfoFormSection() {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" data-required> <TableHead scope="row" className="w-[20rem]" data-required>
사업명 사업명
</TableHead> </TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
@@ -73,7 +73,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업기간</TableHead> <TableHead scope="row" data-required>사업기간</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldGroup className="flex-row items-center gap-2"> <FieldGroup className="flex-row items-center gap-2">
<Controller <Controller
@@ -117,7 +117,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업내용</TableHead> <TableHead scope="row" data-required>사업내용</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="designCnstnMng.bizCn" name="designCnstnMng.bizCn"
@@ -137,9 +137,9 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>구분</TableHead> <TableHead scope="row" data-required>구분</TableHead>
<TableCell>{taskSeComCdLabel}</TableCell> <TableCell>{taskSeComCdLabel}</TableCell>
<TableHead>신청 지자체</TableHead> <TableHead scope="row">신청 지자체</TableHead>
<TableCell>{localGovLabel}</TableCell> <TableCell>{localGovLabel}</TableCell>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
@@ -11,7 +11,7 @@ interface BasicInfoSectionProps {
function BasicInfoSection({ det }: BasicInfoSectionProps) { function BasicInfoSection({ det }: BasicInfoSectionProps) {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="사업 기본 정보" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -13,7 +13,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<SectionCollapsible title="사업규모"> <SectionCollapsible title="사업규모">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="사업규모 목록: 구분, 기본계획, 예산반영, 금회설계, 증감 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[30rem]">구분</TableHead> <TableHead className="w-[30rem]">구분</TableHead>
@@ -36,7 +36,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<TableRow key={node.cnstpSeCd}> <TableRow key={node.cnstpSeCd}>
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{node.cnstpSeCdNm} {node.cnstpSeCdNm}
</TableHead> </TableHead>
<TableCell> <TableCell>
@@ -11,21 +11,21 @@ interface ContactInfoSectionProps {
function ContactInfoSection({ det }: ContactInfoSectionProps) { function ContactInfoSection({ det }: ContactInfoSectionProps) {
return ( return (
<SectionCollapsible title="담당자 정보"> <SectionCollapsible title="담당자 정보">
<Table variant="secondary"> <Table caption="사업 담당자 정보" variant="secondary">
<TableHeader> <TableHeader>
{det.aplcntNm && ( {det.aplcntNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>신청자</TableHead> <TableHead scope="row" rowSpan={2}>신청자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.aplcntNm || "-"}</TableCell> <TableCell>{det.aplcntNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.aplcntMblTelno || "-"}</TableCell> <TableCell>{det.aplcntMblTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.aplcntOgdpNm || "-"}</TableCell> <TableCell>{det.aplcntOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.aplcntEmlAddr || "-"}</TableCell> <TableCell>{det.aplcntEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -33,16 +33,16 @@ function ContactInfoSection({ det }: ContactInfoSectionProps) {
{det.dsgnrNm && ( {det.dsgnrNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>설계자</TableHead> <TableHead scope="row" rowSpan={2}>설계자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.dsgnrNm || "-"}</TableCell> <TableCell>{det.dsgnrNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.dsgnrTelno || "-"}</TableCell> <TableCell>{det.dsgnrTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.dsgnrOgdpNm || "-"}</TableCell> <TableCell>{det.dsgnrOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.dsgnrEmlAddr || "-"}</TableCell> <TableCell>{det.dsgnrEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -180,10 +180,10 @@ const TechReviewOpinionSection = forwardRef<
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<h4 className="text-xl font-semibold">검토의견 작성</h4> <h4 className="text-xl font-semibold">검토의견 작성</h4>
<Table variant="secondary"> <Table caption="검토의견 입력" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[12rem]">의견내용</TableHead> <TableHead scope="row" className="w-[12rem]">의견내용</TableHead>
<TableCell> <TableCell>
<Textarea <Textarea
value={formData.rvwRsltCn} value={formData.rvwRsltCn}
@@ -197,7 +197,7 @@ const TechReviewOpinionSection = forwardRef<
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>검토결과</TableHead> <TableHead scope="row">검토결과</TableHead>
<TableCell> <TableCell>
<FieldSet> <FieldSet>
<RadioGroup <RadioGroup
@@ -234,7 +234,7 @@ const TechReviewOpinionSection = forwardRef<
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>첨부파일</TableHead> <TableHead scope="row">첨부파일</TableHead>
<TableCell> <TableCell>
{uploadedFile ? ( {uploadedFile ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -289,7 +289,7 @@ const TechReviewOpinionSection = forwardRef<
function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="검토의견 목록: 의견자, 의견내용, 검토결과, 첨부파일, 등록일시 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="55%" /> <col width="55%" />
@@ -100,6 +100,7 @@ function EsntlAtchFileList({
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "필수 첨부파일 관리 목록",
viewPagination: true, viewPagination: true,
}, },
}); });
@@ -53,7 +53,7 @@ function ChecklistTaskPanel({
return ( return (
<> <>
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="체크리스트 검토 입력: 검토항목, 주요 검토내용, 검토결과 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" rowSpan={2}> <TableHead className="w-[20rem]" rowSpan={2}>
@@ -115,6 +115,7 @@ function FileVrfcSplmntDialog({
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
}, },
dataTableOptions: { dataTableOptions: {
caption: "파일 검증 보완요청 목록",
viewPagination: false, viewPagination: false,
}, },
}); });
@@ -42,7 +42,7 @@ function PwrkCnsltnDocPjtcoAjmtTable({
} }
return ( return (
<Table variant="secondary"> <Table caption="사업비 조정 내역: 구분, 검증결과, 검증금액 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="30%" /> <col width="30%" />
<col width="50%" /> <col width="50%" />
@@ -157,7 +157,7 @@ function CnsltnListTable({
const isSomeSelected = selectedCount > 0 && !isAllSelected; const isSomeSelected = selectedCount > 0 && !isAllSelected;
return ( return (
<Table variant="secondary"> <Table caption="자문 검토결과 목록: 구분, 검토의견 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="4%" /> <col width="4%" />
<col width="4%" /> <col width="4%" />
@@ -248,8 +248,11 @@ function FnrsFormPage({ mode, initialData, createDefaults }: FnrsFormPageProps)
<FormProvider {...form}> <FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4"> <form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup> <SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2"> <div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle /> <SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
{initialData?.detDto?.fnrsCnsltnDocNo && ( {initialData?.detDto?.fnrsCnsltnDocNo && (
@@ -59,6 +59,7 @@ function FnrsList({ searchParams, pagination, onPaginationChange }: FnrsListProp
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "재원협의 목록",
viewPagination: true, viewPagination: true,
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
@@ -49,7 +49,7 @@ function BasicInfoFormSection() {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="재원협의 기본 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -58,7 +58,7 @@ function BasicInfoFormSection() {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" data-required> <TableHead scope="row" className="w-[20rem]" data-required>
사업명 사업명
</TableHead> </TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
@@ -86,7 +86,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업기간</TableHead> <TableHead scope="row" data-required>사업기간</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldGroup className="flex-row items-center gap-2"> <FieldGroup className="flex-row items-center gap-2">
<Controller <Controller
@@ -130,7 +130,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업내용</TableHead> <TableHead scope="row" data-required>사업내용</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="fnrsCnsltnMng.bizCn" name="fnrsCnsltnMng.bizCn"
@@ -150,15 +150,15 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>구분</TableHead> <TableHead scope="row" data-required>구분</TableHead>
<TableCell>{taskSeComCdLabel}</TableCell> <TableCell>{taskSeComCdLabel}</TableCell>
<TableHead>신청 지자체</TableHead> <TableHead scope="row">신청 지자체</TableHead>
<TableCell>{localGovLabel}</TableCell> <TableCell>{localGovLabel}</TableCell>
</TableRow> </TableRow>
{taskSeComCd.includes("RE") && ( {taskSeComCd.includes("RE") && (
<> <>
<TableRow> <TableRow>
<TableHead>시설종류</TableHead> <TableHead scope="row">시설종류</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="fnrsCnsltnMng.rtlztnFcltSeComCd" name="fnrsCnsltnMng.rtlztnFcltSeComCd"
@@ -198,7 +198,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>재이용용도</TableHead> <TableHead scope="row">재이용용도</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="fnrsCnsltnMng.rtlztnUsgSeComCd" name="fnrsCnsltnMng.rtlztnUsgSeComCd"
@@ -11,7 +11,7 @@ interface BasicInfoSectionProps {
function BasicInfoSection({ det }: BasicInfoSectionProps) { function BasicInfoSection({ det }: BasicInfoSectionProps) {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="재원협의 기본 정보" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -20,31 +20,31 @@ function BasicInfoSection({ det }: BasicInfoSectionProps) {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>사업명</TableHead> <TableHead scope="row">사업명</TableHead>
<TableCell>{det.bizNm || "-"}</TableCell> <TableCell>{det.bizNm || "-"}</TableCell>
<TableHead>사업기간</TableHead> <TableHead scope="row">사업기간</TableHead>
<TableCell>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</TableCell> <TableCell>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>사업내용</TableHead> <TableHead scope="row">사업내용</TableHead>
<TableCell colSpan={3}>{det.bizCn || "-"}</TableCell> <TableCell colSpan={3}>{det.bizCn || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>환경청구분</TableHead> <TableHead scope="row">환경청구분</TableHead>
<TableCell>{det.envoSeCdNm || "-"}</TableCell> <TableCell>{det.envoSeCdNm || "-"}</TableCell>
<TableHead>구분</TableHead> <TableHead scope="row">구분</TableHead>
<TableCell>{det.taskSeCdNm || "-"}</TableCell> <TableCell>{det.taskSeCdNm || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>신청지자체</TableHead> <TableHead scope="row">신청지자체</TableHead>
<TableCell> <TableCell>
{det.sido || "-"} {det.gugun || "-"} {det.sido || "-"} {det.gugun || "-"}
</TableCell> </TableCell>
<TableHead>확정예산사업번호</TableHead> <TableHead scope="row">확정예산사업번호</TableHead>
<TableCell>{det.cfmtnBgtBizNo || "-"}</TableCell> <TableCell>{det.cfmtnBgtBizNo || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>예산신청연도</TableHead> <TableHead scope="row">예산신청연도</TableHead>
<TableCell colSpan={3}>{det.bgtAplyYr || "-"}</TableCell> <TableCell colSpan={3}>{det.bgtAplyYr || "-"}</TableCell>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
@@ -20,7 +20,7 @@ function BusinessCostSection({ bizCstList }: BusinessCostSectionProps) {
<SectionCollapsible title="총사업비"> <SectionCollapsible title="총사업비">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="총사업비 내역: 구분, 예산반영, 표준사업비, 금회설계, 증감 정보 제공" variant="secondary" className="table-fixed">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[30rem]" rowSpan={2}> <TableHead className="w-[30rem]" rowSpan={2}>
@@ -51,9 +51,9 @@ function BusinessCostSection({ bizCstList }: BusinessCostSectionProps) {
return ( return (
<TableRow key={node.acntgSeCd}> <TableRow key={node.acntgSeCd}>
{node.treeLevel <= 1 ? ( {node.treeLevel <= 1 ? (
<TableHead className="!px-[0.8rem] text-left">{node.acntgSeCdNm}</TableHead> <TableHead scope="row" className="!px-[0.8rem] text-left">{node.acntgSeCdNm}</TableHead>
) : ( ) : (
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{showSubIcon && <span className="mr-1 text-gray-400">└</span>} {showSubIcon && <span className="mr-1 text-gray-400">└</span>}
{node.acntgSeCdNm} {node.acntgSeCdNm}
</TableHead> </TableHead>
@@ -13,7 +13,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<SectionCollapsible title="사업규모"> <SectionCollapsible title="사업규모">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="사업규모 내역: 구분, 기본계획, 예산반영, 금회설계, 증감 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[30rem]">구분</TableHead> <TableHead className="w-[30rem]">구분</TableHead>
@@ -36,7 +36,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<TableRow key={node.cnstpSeCd}> <TableRow key={node.cnstpSeCd}>
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{node.cnstpSeCdNm} {node.cnstpSeCdNm}
</TableHead> </TableHead>
<TableCell> <TableCell>
@@ -11,21 +11,21 @@ interface ContactInfoSectionProps {
function ContactInfoSection({ det }: ContactInfoSectionProps) { function ContactInfoSection({ det }: ContactInfoSectionProps) {
return ( return (
<SectionCollapsible title="담당자 정보"> <SectionCollapsible title="담당자 정보">
<Table variant="secondary"> <Table caption="재원협의 담당자 정보" variant="secondary">
<TableHeader> <TableHeader>
{det.aplcntNm && ( {det.aplcntNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>신청자</TableHead> <TableHead scope="row" rowSpan={2}>신청자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.aplcntNm || "-"}</TableCell> <TableCell>{det.aplcntNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.aplcntMblTelno || "-"}</TableCell> <TableCell>{det.aplcntMblTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.aplcntOgdpNm || "-"}</TableCell> <TableCell>{det.aplcntOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.aplcntEmlAddr || "-"}</TableCell> <TableCell>{det.aplcntEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -33,16 +33,16 @@ function ContactInfoSection({ det }: ContactInfoSectionProps) {
{det.dsgnrNm && ( {det.dsgnrNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>설계자</TableHead> <TableHead scope="row" rowSpan={2}>설계자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.dsgnrNm || "-"}</TableCell> <TableCell>{det.dsgnrNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.dsgnrTelno || "-"}</TableCell> <TableCell>{det.dsgnrTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.dsgnrOgdpNm || "-"}</TableCell> <TableCell>{det.dsgnrOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.dsgnrEmlAddr || "-"}</TableCell> <TableCell>{det.dsgnrEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -21,7 +21,7 @@ function FnrsSharSection({ fnrsSharList }: FnrsSharSectionProps) {
<SectionCollapsible title="재원분담"> <SectionCollapsible title="재원분담">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="재원분담 내역: 구분, 현행, 변경요구, 증감, 비고 정보 제공" variant="secondary" className="table-fixed">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[24rem]" rowSpan={2}> <TableHead className="w-[24rem]" rowSpan={2}>
@@ -51,7 +51,7 @@ function FnrsSharSection({ fnrsSharList }: FnrsSharSectionProps) {
return ( return (
<TableRow key={node.fnrsSharSeCd}> <TableRow key={node.fnrsSharSeCd}>
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{showSubIcon && <span className="mr-1 text-gray-400">└</span>} {showSubIcon && <span className="mr-1 text-gray-400">└</span>}
{node.fnrsSharSeCdNm} {node.fnrsSharSeCdNm}
</TableHead> </TableHead>
@@ -189,7 +189,7 @@ const TechReviewOpinionSection = forwardRef<
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<h4 className="text-xl font-semibold">검토의견 작성</h4> <h4 className="text-xl font-semibold">검토의견 작성</h4>
<Table variant="secondary"> <Table caption="검토의견 입력" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[12rem]">의견내용</TableHead> <TableHead className="w-[12rem]">의견내용</TableHead>
@@ -303,7 +303,7 @@ const TechReviewOpinionSection = forwardRef<
function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="검토의견 목록: 의견자, 의견내용, 검토결과, 첨부파일, 등록일시 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="55%" /> <col width="55%" />
@@ -52,7 +52,7 @@ function ChecklistTaskPanel({
return ( return (
<> <>
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="체크리스트 검토 입력: 검토항목, 주요 검토내용, 검토결과 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" rowSpan={2}> <TableHead className="w-[20rem]" rowSpan={2}>
@@ -209,8 +209,11 @@ function InstlFormPage({ mode, initialData, createDefaults }: InstlFormPageProps
<FormProvider {...form}> <FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4"> <form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup> <SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2"> <div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle /> <SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
{initialData?.detDto.instlSncnDocNo && ( {initialData?.detDto.instlSncnDocNo && (
@@ -59,6 +59,7 @@ function InstlList({ searchParams, pagination, onPaginationChange }: InstlListPr
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "설치승인 목록",
viewPagination: true, viewPagination: true,
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
@@ -53,7 +53,7 @@ function BasicInfoFormSection() {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="설치승인 기본 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -62,7 +62,7 @@ function BasicInfoFormSection() {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" data-required> <TableHead scope="row" className="w-[20rem]" data-required>
사업명 사업명
</TableHead> </TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
@@ -90,7 +90,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업기간</TableHead> <TableHead scope="row" data-required>사업기간</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldGroup className="flex-row items-center gap-2"> <FieldGroup className="flex-row items-center gap-2">
<Controller <Controller
@@ -134,7 +134,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업내용</TableHead> <TableHead scope="row" data-required>사업내용</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="instlSncnMng.bizCn" name="instlSncnMng.bizCn"
@@ -154,13 +154,13 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>구분</TableHead> <TableHead scope="row" data-required>구분</TableHead>
<TableCell>{taskSeComCdLabel}</TableCell> <TableCell>{taskSeComCdLabel}</TableCell>
<TableHead>신청 지자체</TableHead> <TableHead scope="row">신청 지자체</TableHead>
<TableCell>{localGovLabel}</TableCell> <TableCell>{localGovLabel}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>사업구분</TableHead> <TableHead scope="row" data-required>사업구분</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="instlSncnMng.sncnSeComCd" name="instlSncnMng.sncnSeComCd"
@@ -202,7 +202,7 @@ function BasicInfoFormSection() {
{taskSeComCd.includes("RE") && ( {taskSeComCd.includes("RE") && (
<> <>
<TableRow> <TableRow>
<TableHead>시설종류</TableHead> <TableHead scope="row">시설종류</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="instlSncnMng.rtlztnFcltSeComCd" name="instlSncnMng.rtlztnFcltSeComCd"
@@ -242,7 +242,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>재이용용도</TableHead> <TableHead scope="row">재이용용도</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="instlSncnMng.rtlztnUsgSeComCd" name="instlSncnMng.rtlztnUsgSeComCd"
@@ -11,7 +11,7 @@ interface BasicInfoSectionProps {
function BasicInfoSection({ det }: BasicInfoSectionProps) { function BasicInfoSection({ det }: BasicInfoSectionProps) {
return ( return (
<SectionCollapsible title="기본 정보"> <SectionCollapsible title="기본 정보">
<Table variant="secondary"> <Table caption="설치승인 기본 정보" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -20,25 +20,25 @@ function BasicInfoSection({ det }: BasicInfoSectionProps) {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>사업명</TableHead> <TableHead scope="row">사업명</TableHead>
<TableCell>{det.bizNm || "-"}</TableCell> <TableCell>{det.bizNm || "-"}</TableCell>
<TableHead>사업기간</TableHead> <TableHead scope="row">사업기간</TableHead>
<TableCell>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</TableCell> <TableCell>{(det.bizBgngYr || "-") + " ~ " + (det.bizEndYr || "-")}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>사업내용</TableHead> <TableHead scope="row">사업내용</TableHead>
<TableCell colSpan={3}>{det.bizCn || "-"}</TableCell> <TableCell colSpan={3}>{det.bizCn || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>구분</TableHead> <TableHead scope="row">구분</TableHead>
<TableCell>{det.taskSeCdNm || "-"}</TableCell> <TableCell>{det.taskSeCdNm || "-"}</TableCell>
<TableHead>신청지자체</TableHead> <TableHead scope="row">신청지자체</TableHead>
<TableCell> <TableCell>
{det.sido || "-"} {det.gugun || "-"} {det.sido || "-"} {det.gugun || "-"}
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>사업구분</TableHead> <TableHead scope="row">사업구분</TableHead>
<TableCell colSpan={3}>{det.sncnSeCdNm || "-"}</TableCell> <TableCell colSpan={3}>{det.sncnSeCdNm || "-"}</TableCell>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
@@ -20,7 +20,7 @@ function BusinessCostSection({ bizCstList }: BusinessCostSectionProps) {
<SectionCollapsible title="총사업비"> <SectionCollapsible title="총사업비">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="총사업비 내역: 구분, 예산반영, 표준사업비, 금회설계, 증감 정보 제공" variant="secondary" className="table-fixed">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[30rem]" rowSpan={2}> <TableHead className="w-[30rem]" rowSpan={2}>
@@ -51,9 +51,9 @@ function BusinessCostSection({ bizCstList }: BusinessCostSectionProps) {
return ( return (
<TableRow key={node.acntgSeCd}> <TableRow key={node.acntgSeCd}>
{node.treeLevel <= 1 ? ( {node.treeLevel <= 1 ? (
<TableHead className="!px-[0.8rem] text-left">{node.acntgSeCdNm}</TableHead> <TableHead scope="row" className="!px-[0.8rem] text-left">{node.acntgSeCdNm}</TableHead>
) : ( ) : (
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{showSubIcon && <span className="mr-1 text-gray-400">└</span>} {showSubIcon && <span className="mr-1 text-gray-400">└</span>}
{node.acntgSeCdNm} {node.acntgSeCdNm}
</TableHead> </TableHead>
@@ -13,7 +13,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<SectionCollapsible title="사업규모"> <SectionCollapsible title="사업규모">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="사업규모 내역: 구분, 기본계획, 예산반영, 금회설계, 증감 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[30rem]">구분</TableHead> <TableHead className="w-[30rem]">구분</TableHead>
@@ -36,7 +36,7 @@ function BusinessScaleSection({ bizSclList }: BusinessScaleSectionProps) {
return ( return (
<TableRow key={node.cnstpSeCd}> <TableRow key={node.cnstpSeCd}>
<TableHead className="text-left" style={{ paddingLeft: `${pl + 8}px` }}> <TableHead scope="row" className="text-left" style={{ paddingLeft: `${pl + 8}px` }}>
{node.cnstpSeCdNm} {node.cnstpSeCdNm}
</TableHead> </TableHead>
<TableCell> <TableCell>
@@ -11,21 +11,21 @@ interface ContactInfoSectionProps {
function ContactInfoSection({ det }: ContactInfoSectionProps) { function ContactInfoSection({ det }: ContactInfoSectionProps) {
return ( return (
<SectionCollapsible title="담당자 정보"> <SectionCollapsible title="담당자 정보">
<Table variant="secondary"> <Table caption="설치승인 담당자 정보" variant="secondary">
<TableHeader> <TableHeader>
{det.aplcntNm && ( {det.aplcntNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>신청자</TableHead> <TableHead scope="row" rowSpan={2}>신청자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.aplcntNm || "-"}</TableCell> <TableCell>{det.aplcntNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.aplcntMblTelno || "-"}</TableCell> <TableCell>{det.aplcntMblTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.aplcntOgdpNm || "-"}</TableCell> <TableCell>{det.aplcntOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.aplcntEmlAddr || "-"}</TableCell> <TableCell>{det.aplcntEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -33,16 +33,16 @@ function ContactInfoSection({ det }: ContactInfoSectionProps) {
{det.dsgnrNm && ( {det.dsgnrNm && (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>설계자</TableHead> <TableHead scope="row" rowSpan={2}>설계자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{det.dsgnrNm || "-"}</TableCell> <TableCell>{det.dsgnrNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{det.dsgnrTelno || "-"}</TableCell> <TableCell>{det.dsgnrTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{det.dsgnrOgdpNm || "-"}</TableCell> <TableCell>{det.dsgnrOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{det.dsgnrEmlAddr || "-"}</TableCell> <TableCell>{det.dsgnrEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -180,10 +180,10 @@ const TechReviewOpinionSection = forwardRef<
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<h4 className="text-xl font-semibold">검토의견 작성</h4> <h4 className="text-xl font-semibold">검토의견 작성</h4>
<Table variant="secondary"> <Table caption="검토의견 입력" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[12rem]">의견내용</TableHead> <TableHead scope="row" className="w-[12rem]">의견내용</TableHead>
<TableCell> <TableCell>
<Textarea <Textarea
value={formData.rvwRsltCn} value={formData.rvwRsltCn}
@@ -197,7 +197,7 @@ const TechReviewOpinionSection = forwardRef<
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>검토결과</TableHead> <TableHead scope="row">검토결과</TableHead>
<TableCell> <TableCell>
<FieldSet> <FieldSet>
<RadioGroup <RadioGroup
@@ -234,7 +234,7 @@ const TechReviewOpinionSection = forwardRef<
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>첨부파일</TableHead> <TableHead scope="row">첨부파일</TableHead>
<TableCell> <TableCell>
{uploadedFile ? ( {uploadedFile ? (
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -301,7 +301,7 @@ const TechReviewOpinionSection = forwardRef<
function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="검토의견 목록: 의견자, 의견내용, 검토결과, 첨부파일, 등록일시 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="55%" /> <col width="55%" />
@@ -70,6 +70,7 @@ function MyPbadmsSprtList({ searchParams, pagination, onPaginationChange }: MyPb
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "나의 행정지원 목록",
viewPagination: true, viewPagination: true,
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
@@ -97,6 +97,7 @@ function NtiHstryList({ searchParams, pagination, onPaginationChange }: NtiHstry
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "알림톡 발송 이력 목록",
viewPagination: true, viewPagination: true,
}, },
}); });
@@ -33,6 +33,7 @@ function InPrgrsDocRcvrList({ selectedRcvrKeys, onRcvrSelectionChange }: InPrgrs
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
...rowSelectionOptions, ...rowSelectionOptions,
}, },
dataTableOptions: { caption: "진행중 문서 담당자 수신자 목록" },
}); });
return ( return (
@@ -34,6 +34,7 @@ function RvwMnpwRcvrList({ selectedRcvrKeys, onRcvrSelectionChange }: RvwMnpwRcv
getCoreRowModel: getCoreRowModel(), getCoreRowModel: getCoreRowModel(),
...rowSelectionOptions, ...rowSelectionOptions,
}, },
dataTableOptions: { caption: "검토인력 수신자 목록" },
}); });
return ( return (
@@ -35,7 +35,7 @@ function SndngList({
return ( return (
<div className="max-h-[40rem] overflow-auto rounded-md border"> <div className="max-h-[40rem] overflow-auto rounded-md border">
<Table variant="line" className="text-sm"> <Table caption="알림톡 발송 대상 목록: 이름, 전화번호, 변수, 버튼 정보 제공" variant="line" className="text-sm">
<TableHeader className="top-0"> <TableHeader className="top-0">
<TableRow> <TableRow>
<TableHead className="min-w-[100px]">이름</TableHead> <TableHead className="min-w-[100px]">이름</TableHead>
@@ -52,7 +52,7 @@ function ChecklistTaskPanel({
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="체크리스트 검토 입력: 검토항목, 주요 검토내용, 검토결과 정보 제공" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" rowSpan={2}> <TableHead className="w-[20rem]" rowSpan={2}>
@@ -35,7 +35,7 @@ function PreviousPlanAreaTable({ data }: PreviousPlanAreaTableProps) {
const yearCells = getPlanYearCells(data); const yearCells = getPlanYearCells(data);
return ( return (
<Table variant="secondary"> <Table caption="이전 기본계획 처리구역 현황" variant="secondary">
<colgroup> <colgroup>
<col width="16%" /> <col width="16%" />
<col width="9.3%" /> <col width="9.3%" />
@@ -86,7 +86,7 @@ function PreviousPlanAreaTable({ data }: PreviousPlanAreaTableProps) {
const cells = getMetricCells(data, row.field); const cells = getMetricCells(data, row.field);
return ( return (
<TableRow key={row.field}> <TableRow key={row.field}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{cells.map((cell, index) => ( {cells.map((cell, index) => (
<TableCell key={index} className="text-right"> <TableCell key={index} className="text-right">
{cell} {cell}
@@ -202,7 +202,7 @@ function PreviousPlanFileSection({ clsfSystmNm }: PreviousPlanFileSectionProps)
) : files.length === 0 ? ( ) : files.length === 0 ? (
<p className="py-8 text-center text-lg text-muted-foreground">파일이 없습니다.</p> <p className="py-8 text-center text-lg text-muted-foreground">파일이 없습니다.</p>
) : ( ) : (
<Table variant="secondary"> <Table caption="이전 기본계획 첨부파일 목록" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="!py-2 !text-xl">번호</TableHead> <TableHead className="!py-2 !text-xl">번호</TableHead>
@@ -13,7 +13,7 @@ function PreviousPlanSummaryTable({ data }: PreviousPlanSummaryTableProps) {
const yearCells = getPlanYearCells(data); const yearCells = getPlanYearCells(data);
return ( return (
<Table variant="secondary"> <Table caption="이전 기본계획 목표연도" variant="secondary">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="10%" /> <col width="10%" />
@@ -54,7 +54,7 @@ function PreviousPlanSummaryTable({ data }: PreviousPlanSummaryTableProps) {
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead>계획목표년도</TableHead> <TableHead scope="row">계획목표년도</TableHead>
{yearCells.map((cell, index) => ( {yearCells.map((cell, index) => (
<TableCell key={index} className="text-center"> <TableCell key={index} className="text-center">
{cell} {cell}
@@ -57,7 +57,7 @@ function BasicInfoFormSection() {
return ( return (
<SectionCollapsible title="기본계획 신청"> <SectionCollapsible title="기본계획 신청">
<Table variant="secondary"> <Table caption="기본계획 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -66,7 +66,7 @@ function BasicInfoFormSection() {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" data-required> <TableHead scope="row" className="w-[20rem]" data-required>
기본계획명 기본계획명
</TableHead> </TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
@@ -89,7 +89,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>계획년도</TableHead> <TableHead scope="row" data-required>계획년도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.planYr" name="sewerBscPlanDtl.planYr"
@@ -113,7 +113,7 @@ function BasicInfoFormSection() {
)} )}
/> />
</TableCell> </TableCell>
<TableHead data-required>기준년도</TableHead> <TableHead scope="row" data-required>기준년도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.crtrYr" name="sewerBscPlanDtl.crtrYr"
@@ -139,7 +139,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>1단계 목표연도</TableHead> <TableHead scope="row" data-required>1단계 목표연도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.frlvlGoalYr" name="sewerBscPlanDtl.frlvlGoalYr"
@@ -166,7 +166,7 @@ function BasicInfoFormSection() {
)} )}
/> />
</TableCell> </TableCell>
<TableHead data-required>2단계 목표연도</TableHead> <TableHead scope="row" data-required>2단계 목표연도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.sclvlGoalYr" name="sewerBscPlanDtl.sclvlGoalYr"
@@ -192,7 +192,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>3단계 목표연도</TableHead> <TableHead scope="row" data-required>3단계 목표연도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.thlvlGoalYr" name="sewerBscPlanDtl.thlvlGoalYr"
@@ -216,7 +216,7 @@ function BasicInfoFormSection() {
)} )}
/> />
</TableCell> </TableCell>
<TableHead data-required>4단계 목표연도</TableHead> <TableHead scope="row" data-required>4단계 목표연도</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name="sewerBscPlanDtl.folvlGoalYr" name="sewerBscPlanDtl.folvlGoalYr"
@@ -242,7 +242,7 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>계획개요</TableHead> <TableHead scope="row" data-required>계획개요</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<Controller <Controller
name="sewerBscPlanDtl.bizOtlnCn" name="sewerBscPlanDtl.bizOtlnCn"
@@ -264,9 +264,9 @@ function BasicInfoFormSection() {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>구분</TableHead> <TableHead scope="row">구분</TableHead>
<TableCell>{sewerBscPlanSeLabel}</TableCell> <TableCell>{sewerBscPlanSeLabel}</TableCell>
<TableHead>신청 지자체</TableHead> <TableHead scope="row">신청 지자체</TableHead>
<TableCell>{localGovLabel || userInfo?.laeSeNm}</TableCell> <TableCell>{localGovLabel || userInfo?.laeSeNm}</TableCell>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
@@ -18,7 +18,7 @@ function BasicInfoSection({ det, dtl }: BasicInfoSectionProps) {
return ( return (
<SectionCollapsible title="기본계획 신청"> <SectionCollapsible title="기본계획 신청">
<Table variant="secondary"> <Table caption="기본계획 정보" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -27,37 +27,37 @@ function BasicInfoSection({ det, dtl }: BasicInfoSectionProps) {
</colgroup> </colgroup>
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>기본계획명</TableHead> <TableHead scope="row">기본계획명</TableHead>
<TableCell colSpan={3}>{det.sewerBscPlanNm || "-"}</TableCell> <TableCell colSpan={3}>{det.sewerBscPlanNm || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>계획년도</TableHead> <TableHead scope="row">계획년도</TableHead>
<TableCell>{dtl?.planYr || "-"}</TableCell> <TableCell>{dtl?.planYr || "-"}</TableCell>
<TableHead>기준년도</TableHead> <TableHead scope="row">기준년도</TableHead>
<TableCell>{dtl?.crtrYr || "-"}</TableCell> <TableCell>{dtl?.crtrYr || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>1단계 목표연도</TableHead> <TableHead scope="row">1단계 목표연도</TableHead>
<TableCell>{dtl?.frlvlGoalYr || "-"}</TableCell> <TableCell>{dtl?.frlvlGoalYr || "-"}</TableCell>
<TableHead>2단계 목표연도</TableHead> <TableHead scope="row">2단계 목표연도</TableHead>
<TableCell>{dtl?.sclvlGoalYr || "-"}</TableCell> <TableCell>{dtl?.sclvlGoalYr || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>3단계 목표연도</TableHead> <TableHead scope="row">3단계 목표연도</TableHead>
<TableCell>{dtl?.thlvlGoalYr || "-"}</TableCell> <TableCell>{dtl?.thlvlGoalYr || "-"}</TableCell>
<TableHead>4단계 목표연도</TableHead> <TableHead scope="row">4단계 목표연도</TableHead>
<TableCell>{dtl?.folvlGoalYr || "-"}</TableCell> <TableCell>{dtl?.folvlGoalYr || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>계획개요</TableHead> <TableHead scope="row">계획개요</TableHead>
<TableCell colSpan={3} className="whitespace-pre-wrap"> <TableCell colSpan={3} className="whitespace-pre-wrap">
{dtl?.bizOtlnCn || "-"} {dtl?.bizOtlnCn || "-"}
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>구분</TableHead> <TableHead scope="row">구분</TableHead>
<TableCell>{sewerBscPlanSeLabel || "-"}</TableCell> <TableCell>{sewerBscPlanSeLabel || "-"}</TableCell>
<TableHead>신청 지자체</TableHead> <TableHead scope="row">신청 지자체</TableHead>
<TableCell>{localGovLabel || "-"}</TableCell> <TableCell>{localGovLabel || "-"}</TableCell>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
@@ -75,7 +75,7 @@ function BizCstMatrixFormSection() {
<SectionCollapsible title="총사업비"> <SectionCollapsible title="총사업비">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="단계별 총사업비 입력" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -102,7 +102,7 @@ function BizCstMatrixFormSection() {
return ( return (
<TableRow key={item.code}> <TableRow key={item.code}>
<TableHead className="text-left" style={{ paddingLeft }}> <TableHead scope="row" className="text-left" style={{ paddingLeft }}>
<div className="relative"> <div className="relative">
{showSubIcon && ( {showSubIcon && (
<span className="absolute -left-6 top-0 text-gray-400">└</span> <span className="absolute -left-6 top-0 text-gray-400">└</span>
@@ -62,7 +62,7 @@ function BizCstMatrixSection({ bizCstList, dtl }: BizCstMatrixSectionProps) {
<SectionCollapsible title="총사업비"> <SectionCollapsible title="총사업비">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="단계별 총사업비 내역" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -89,7 +89,7 @@ function BizCstMatrixSection({ bizCstList, dtl }: BizCstMatrixSectionProps) {
return ( return (
<TableRow key={item.code}> <TableRow key={item.code}>
<TableHead className="text-left" style={{ paddingLeft }}> <TableHead scope="row" className="text-left" style={{ paddingLeft }}>
<div className="relative"> <div className="relative">
{showSubIcon && ( {showSubIcon && (
<span className="absolute -left-6 top-0 text-gray-400">└</span> <span className="absolute -left-6 top-0 text-gray-400">└</span>
@@ -13,21 +13,21 @@ function ContactInfoSection({ dtl }: ContactInfoSectionProps) {
return ( return (
<SectionCollapsible title="담당자 정보"> <SectionCollapsible title="담당자 정보">
<Table variant="secondary"> <Table caption="기본계획 담당자 정보" variant="secondary">
<TableHeader> <TableHeader>
{dtl.aplcntNm ? ( {dtl.aplcntNm ? (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>신청자</TableHead> <TableHead scope="row" rowSpan={2}>신청자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{dtl.aplcntNm || "-"}</TableCell> <TableCell>{dtl.aplcntNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{dtl.aplcntMblTelno || "-"}</TableCell> <TableCell>{dtl.aplcntMblTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{dtl.aplcntOgdpNm || "-"}</TableCell> <TableCell>{dtl.aplcntOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{dtl.aplcntEmlAddr || "-"}</TableCell> <TableCell>{dtl.aplcntEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -35,16 +35,16 @@ function ContactInfoSection({ dtl }: ContactInfoSectionProps) {
{dtl.dsgnrNm ? ( {dtl.dsgnrNm ? (
<> <>
<TableRow> <TableRow>
<TableHead rowSpan={2}>설계자</TableHead> <TableHead scope="row" rowSpan={2}>설계자</TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell>{dtl.dsgnrNm || "-"}</TableCell> <TableCell>{dtl.dsgnrNm || "-"}</TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell>{dtl.dsgnrTelno || "-"}</TableCell> <TableCell>{dtl.dsgnrTelno || "-"}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{dtl.dsgnrOgdpNm || "-"}</TableCell> <TableCell>{dtl.dsgnrOgdpNm || "-"}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{dtl.dsgnrEmlAddr || "-"}</TableCell> <TableCell>{dtl.dsgnrEmlAddr || "-"}</TableCell>
</TableRow> </TableRow>
</> </>
@@ -85,7 +85,7 @@ function FnrsCstFormSection() {
<h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3> <h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3>
<span className="font-normal text-muted-foreground">(단위: 백만원)</span> <span className="font-normal text-muted-foreground">(단위: 백만원)</span>
</div> </div>
<Table variant="secondary" className="table-fixed"> <Table caption="총사업비 대비 재원분담 합계 비교" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -107,7 +107,7 @@ function FnrsCstFormSection() {
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead>총사업비</TableHead> <TableHead scope="row">총사업비</TableHead>
{remainingList.map((item) => ( {remainingList.map((item) => (
<TableCell key={item.planStpNo}> <TableCell key={item.planStpNo}>
<div className={cn("text-right", item.remaining !== 0 ? "text-destructive" : "")}> <div className={cn("text-right", item.remaining !== 0 ? "text-destructive" : "")}>
@@ -125,7 +125,7 @@ function FnrsCstFormSection() {
<h3 className="text-xl font-semibold">재원분담</h3> <h3 className="text-xl font-semibold">재원분담</h3>
<span className="font-normal text-muted-foreground">(단위: 백만원)</span> <span className="font-normal text-muted-foreground">(단위: 백만원)</span>
</div> </div>
<Table variant="secondary" className="table-fixed"> <Table caption="단계별 재원분담 입력" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -148,7 +148,7 @@ function FnrsCstFormSection() {
<TableBody> <TableBody>
{FNRS_CST_ROWS.map((row) => ( {FNRS_CST_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{PLAN_STEPS.map((planStpNo) => { {PLAN_STEPS.map((planStpNo) => {
const item = fnrsCstList.find((cst) => cst.planStpNo === planStpNo); const item = fnrsCstList.find((cst) => cst.planStpNo === planStpNo);
return ( return (
@@ -79,7 +79,7 @@ function FnrsCstSection({ fnrsCstList, dtl }: FnrsCstSectionProps) {
<h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3> <h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3>
<span className="font-normal text-muted-foreground">(단위: 백만원)</span> <span className="font-normal text-muted-foreground">(단위: 백만원)</span>
</div> </div>
<Table variant="secondary" className="table-fixed"> <Table caption="단계별 재원분담 내역" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -102,7 +102,7 @@ function FnrsCstSection({ fnrsCstList, dtl }: FnrsCstSectionProps) {
<TableBody> <TableBody>
{FNRS_CST_ROWS.map((row) => ( {FNRS_CST_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{stepHeaders.map((step) => { {stepHeaders.map((step) => {
const item = matrixFnrsList.find((fnrs) => fnrs.planStpNo === step.planStpNo); const item = matrixFnrsList.find((fnrs) => fnrs.planStpNo === step.planStpNo);
return ( return (
@@ -79,7 +79,7 @@ function OutlineFormSection() {
이전기본계획조회 이전기본계획조회
</Button> </Button>
</div> </div>
<Table variant="secondary"> <Table caption="사업개요 단계별 입력" variant="secondary">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -102,7 +102,7 @@ function OutlineFormSection() {
<TableBody> <TableBody>
{OTLN_ROWS.map((row) => ( {OTLN_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{[1, 2, 3, 4].map((planStpNo) => { {[1, 2, 3, 4].map((planStpNo) => {
const item = otlnList.find((otln) => otln.planStpNo === planStpNo); const item = otlnList.find((otln) => otln.planStpNo === planStpNo);
return ( return (
@@ -29,7 +29,7 @@ function OutlineSection({ otlnList, dtl }: OutlineSectionProps) {
return ( return (
<SectionCollapsible title="사업개요"> <SectionCollapsible title="사업개요">
<Table variant="secondary"> <Table caption="사업개요 단계별 현황" variant="secondary">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="22%" /> <col width="22%" />
@@ -52,7 +52,7 @@ function OutlineSection({ otlnList, dtl }: OutlineSectionProps) {
<TableBody> <TableBody>
{OTLN_ROWS.map((row) => ( {OTLN_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{stepHeaders.map((step) => { {stepHeaders.map((step) => {
const item = otlnList.find((otln) => otln.planStpNo === step.planStpNo); const item = otlnList.find((otln) => otln.planStpNo === step.planStpNo);
return ( return (
@@ -187,7 +187,7 @@ const TechReviewOpinionSection = forwardRef<
return ( return (
<div className="space-y-2"> <div className="space-y-2">
<h4 className="text-xl font-semibold">검토의견 작성</h4> <h4 className="text-xl font-semibold">검토의견 작성</h4>
<Table variant="secondary"> <Table caption="검토의견 입력" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[12rem]">의견내용</TableHead> <TableHead className="w-[12rem]">의견내용</TableHead>
@@ -308,7 +308,7 @@ const TechReviewOpinionSection = forwardRef<
function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) { function TechReviewOpinionTable({ items }: TechReviewOpinionTableProps) {
return ( return (
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="검토의견 목록: 의견자, 의견내용, 검토결과, 첨부파일, 등록일시 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="10%" /> <col width="10%" />
<col width="55%" /> <col width="55%" />
@@ -147,7 +147,7 @@ function TmplntFacilityMatrix({
const originalData = Array.isArray(data) ? (data[0] ?? null) : null; const originalData = Array.isArray(data) ? (data[0] ?? null) : null;
return ( return (
<Table variant="secondary"> <Table caption="처리시설별 단계별 계획 입력" variant="secondary">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="9.75%" /> <col width="9.75%" />
@@ -199,7 +199,7 @@ function TmplntFacilityMatrix({
<TableBody> <TableBody>
{TMPLNT_FIELD_ROWS.map((row) => ( {TMPLNT_FIELD_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{PLAN_STP_NOS.map((planStpNo) => ( {PLAN_STP_NOS.map((planStpNo) => (
<TableCell key={`original-${row.key}-${planStpNo}`} className="text-right"> <TableCell key={`original-${row.key}-${planStpNo}`} className="text-right">
{getOriginalValue(originalData, row.key, planStpNo)} {getOriginalValue(originalData, row.key, planStpNo)}
@@ -317,7 +317,7 @@ function TmplntFacilityAttachments({
return ( return (
<div className="mt-6 space-y-2"> <div className="mt-6 space-y-2">
<h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3> <h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3>
<Table variant="secondary"> <Table caption="처리구역 필수 첨부파일" variant="secondary">
<colgroup> <colgroup>
<col width="40%" /> <col width="40%" />
<col width="15%" /> <col width="15%" />
@@ -332,7 +332,7 @@ function TmplntFacilityAttachments({
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead data-required align="left"> <TableHead scope="row" data-required align="left">
{facilityName} 계획평면도 {facilityName} 계획평면도
</TableHead> </TableHead>
<TableCell className="text-center">{TMPLNT_ATCH_FORMAT_LABEL}</TableCell> <TableCell className="text-center">{TMPLNT_ATCH_FORMAT_LABEL}</TableCell>
@@ -102,7 +102,7 @@ function TmplntFacilityMatrix({
const originalData = Array.isArray(data) ? (data[0] ?? null) : null; const originalData = Array.isArray(data) ? (data[0] ?? null) : null;
return ( return (
<Table variant="secondary"> <Table caption="처리시설별 단계별 계획 현황" variant="secondary">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="9.75%" /> <col width="9.75%" />
@@ -154,7 +154,7 @@ function TmplntFacilityMatrix({
<TableBody> <TableBody>
{TMPLNT_FIELD_ROWS.map((row) => ( {TMPLNT_FIELD_ROWS.map((row) => (
<TableRow key={row.key}> <TableRow key={row.key}>
<TableHead>{row.label}</TableHead> <TableHead scope="row">{row.label}</TableHead>
{PLAN_STP_NOS.map((planStpNo) => ( {PLAN_STP_NOS.map((planStpNo) => (
<TableCell key={`original-${row.key}-${planStpNo}`} className="text-right"> <TableCell key={`original-${row.key}-${planStpNo}`} className="text-right">
{getOriginalValue(originalData, row.key, planStpNo)} {getOriginalValue(originalData, row.key, planStpNo)}
@@ -242,7 +242,7 @@ function TmplntSection({ tmplntList, det, dtl }: TmplntSectionProps) {
{(item.atchFileGroupId || item.atchFileInfo?.orgnlFileNm) && ( {(item.atchFileGroupId || item.atchFileInfo?.orgnlFileNm) && (
<div className="mt-6 space-y-2"> <div className="mt-6 space-y-2">
<h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3> <h3 className="mb-4 text-xl font-semibold">처리구역 필수 첨부파일</h3>
<Table variant="secondary"> <Table caption="처리구역 첨부파일" variant="secondary">
<colgroup> <colgroup>
<col width="35%" /> <col width="35%" />
<col width="65%" /> <col width="65%" />
@@ -117,7 +117,7 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
{isPending ? ( {isPending ? (
<Skeleton className="h-[16rem] w-full" /> <Skeleton className="h-[16rem] w-full" />
) : ( ) : (
<Table variant="secondary"> <Table caption="기본계획 신청 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
<col width="35%" /> <col width="35%" />
@@ -127,7 +127,7 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
<TableHeader> <TableHeader>
{canSidoGugunSelectable && ( {canSidoGugunSelectable && (
<TableRow> <TableRow>
<TableHead data-required>시도</TableHead> <TableHead scope="row" data-required>시도</TableHead>
<TableCell> <TableCell>
<Select <Select
value={sidoComCd || undefined} value={sidoComCd || undefined}
@@ -148,7 +148,7 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
</SelectContent> </SelectContent>
</Select> </Select>
</TableCell> </TableCell>
<TableHead>시군구</TableHead> <TableHead scope="row">시군구</TableHead>
<TableCell> <TableCell>
<Select <Select
value={sggComCd || undefined} value={sggComCd || undefined}
@@ -170,7 +170,7 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
</TableRow> </TableRow>
)} )}
<TableRow> <TableRow>
<TableHead data-required>계획구분</TableHead> <TableHead scope="row" data-required>계획구분</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldSet className="px-2"> <FieldSet className="px-2">
<RadioGroup <RadioGroup
@@ -199,7 +199,7 @@ function SewerBscPlanApplyDialog({ open, onOpenChange, onConfirm }: SewerBscPlan
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead data-required>업무구분</TableHead> <TableHead scope="row" data-required>업무구분</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldSet className="px-2"> <FieldSet className="px-2">
<RadioGroup value={taskSeComCd || undefined} onValueChange={setTaskSeComCd}> <RadioGroup value={taskSeComCd || undefined} onValueChange={setTaskSeComCd}>
@@ -246,8 +246,11 @@ function SewerBscPlanFormPage({
<FormProvider {...form}> <FormProvider {...form}>
<form onSubmit={form.handleSubmit(onSave)} className="mt-4"> <form onSubmit={form.handleSubmit(onSave)} className="mt-4">
<SectionCollapsibleGroup> <SectionCollapsibleGroup>
<div className="sticky top-[6rem] z-30 bg-container px-4 py-2"> <div className="sticky top-[6rem] z-30 flex items-center justify-between bg-container px-4 py-2">
<SectionCollapsibleToggle /> <SectionCollapsibleToggle />
<p className="text-sm text-muted-foreground">
<span className="text-red-600">*</span>은 필수입력 항목입니다.
</p>
</div> </div>
<div className="space-y-4"> <div className="space-y-4">
{initialData?.detDto?.sewerBscPlanDocNo && ( {initialData?.detDto?.sewerBscPlanDocNo && (
@@ -63,6 +63,7 @@ function SewerBscPlanList({ searchParams, pagination, onPaginationChange }: Sewe
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "하수도 기본계획 목록",
viewPagination: true, viewPagination: true,
onRowClick: handleRowClick, onRowClick: handleRowClick,
}, },
@@ -14,6 +14,7 @@ import { matchQueryStatus } from "./match-query-status";
interface DataTableOptions<T> { interface DataTableOptions<T> {
variant?: "default" | "secondary" | "line"; variant?: "default" | "secondary" | "line";
className?: HTMLAttributes<HTMLTableElement>["className"]; className?: HTMLAttributes<HTMLTableElement>["className"];
caption?: string;
viewPagination?: boolean; viewPagination?: boolean;
onRowClick?: (row: T) => void; onRowClick?: (row: T) => void;
} }
@@ -134,6 +134,7 @@ function BnsPickerDialog({ open, onClose, onSelect }: BnsPickerDialogProps) {
manualPagination: true, manualPagination: true,
}, },
dataTableOptions: { dataTableOptions: {
caption: "사업 검색 결과 목록",
viewPagination: true, viewPagination: true,
onRowClick: (row) => { onRowClick: (row) => {
setRowSelection({ [getBnsListRowKey(row)]: true }); setRowSelection({ [getBnsListRowKey(row)]: true });
@@ -330,7 +331,7 @@ function BnsPickerDialog({ open, onClose, onSelect }: BnsPickerDialogProps) {
function BnsBasicInfoTable({ detail }: { detail: BnsDetailResponseDto }) { function BnsBasicInfoTable({ detail }: { detail: BnsDetailResponseDto }) {
return ( return (
<Table variant="secondary" className="w-full"> <Table caption="사업 검색 결과 목록" variant="secondary" className="w-full">
<TableBody> <TableBody>
<DetailPairRow <DetailPairRow
leftLabel="시도" leftLabel="시도"
@@ -403,7 +404,7 @@ function BnsBasicInfoTable({ detail }: { detail: BnsDetailResponseDto }) {
function BnsOperationTable({ detail }: { detail: BnsDetailResponseDto }) { function BnsOperationTable({ detail }: { detail: BnsDetailResponseDto }) {
return ( return (
<Table variant="secondary" className="w-full"> <Table caption="선택 사업 상세 정보" variant="secondary" className="w-full">
<TableBody> <TableBody>
<DetailPairRow <DetailPairRow
leftLabel="유입하수처리장" leftLabel="유입하수처리장"
@@ -380,7 +380,7 @@ function AttachmentsFormSection({
{essentialFiles.length > 0 && ( {essentialFiles.length > 0 && (
<div className="px-2"> <div className="px-2">
<h3 className="mb-4 text-xl font-semibold">필수 첨부파일</h3> <h3 className="mb-4 text-xl font-semibold">필수 첨부파일</h3>
<Table variant="secondary" className="table-fixed"> <Table caption="필수 첨부파일 목록: 파일명, 파일 확장자, 파일 첨부 정보 제공" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="44%" /> <col width="44%" />
<col width="12%" /> <col width="12%" />
@@ -402,6 +402,7 @@ function AttachmentsFormSection({
return ( return (
<TableRow key={file.esntlAtchFileId}> <TableRow key={file.esntlAtchFileId}>
<TableHead <TableHead
scope="row"
className="group break-keep font-medium" className="group break-keep font-medium"
data-required={file.esntlAtchYn === "Y"} data-required={file.esntlAtchYn === "Y"}
align="left" align="left"
@@ -17,7 +17,7 @@ function AttachmentsViewSection({ esntlFileList, etcFileList }: AttachmentsViewS
{esntlFileList.length > 0 && ( {esntlFileList.length > 0 && (
<SectionCollapsible title="필수 첨부파일"> <SectionCollapsible title="필수 첨부파일">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="첨부파일 목록" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>필수 자료명</TableHead> <TableHead>필수 자료명</TableHead>
@@ -77,7 +77,7 @@ function AttachmentsViewSection({ esntlFileList, etcFileList }: AttachmentsViewS
{etcFileList.length > 0 && ( {etcFileList.length > 0 && (
<SectionCollapsible title="기타 첨부파일"> <SectionCollapsible title="기타 첨부파일">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="첨부파일 목록" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>파일명</TableHead> <TableHead>파일명</TableHead>
@@ -58,7 +58,7 @@ function BizCstTotalDisplayTable({ costItems, sharItems }: BizCstTotalDisplayTab
<h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3> <h3 className="text-xl font-semibold">세부별 총사업비(①) - 재원분담 총사업비(②)</h3>
<span className="font-normal text-muted-foreground">(단위: 백만원)</span> <span className="font-normal text-muted-foreground">(단위: 백만원)</span>
</div> </div>
<Table variant="secondary"> <Table caption="세부별 총사업비와 재원분담 총사업비 비교" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead>구분</TableHead> <TableHead>구분</TableHead>
@@ -68,7 +68,7 @@ function BizCstTotalDisplayTable({ costItems, sharItems }: BizCstTotalDisplayTab
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead>총사업비</TableHead> <TableHead scope="row">총사업비</TableHead>
<TableCell> <TableCell>
<div className={cn("text-right", hasExstnMismatch ? "text-destructive" : "")}> <div className={cn("text-right", hasExstnMismatch ? "text-destructive" : "")}>
{formatRemaining(remaining.exstnRemaining)} {formatRemaining(remaining.exstnRemaining)}
@@ -102,7 +102,7 @@ function BusinessCostFormSection() {
<SectionCollapsible title="세부별 총사업비"> <SectionCollapsible title="세부별 총사업비">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary" className="table-fixed"> <Table caption="세부별 총사업비 입력: 구분, 예산반영, 표준사업비, 금회설계, 증감 정보 제공" variant="secondary" className="table-fixed">
<colgroup> <colgroup>
<col width="20%" /> <col width="20%" />
<col width="20%" /> <col width="20%" />
@@ -140,7 +140,7 @@ function BusinessCostFormSection() {
return ( return (
<TableRow key={item.code}> <TableRow key={item.code}>
<TableHead className="text-left" style={{ paddingLeft }}> <TableHead scope="row" className="text-left" style={{ paddingLeft }}>
<div className="relative"> <div className="relative">
{showSubIcon && ( {showSubIcon && (
<span className="absolute -left-6 top-0 text-gray-400">└</span> <span className="absolute -left-6 top-0 text-gray-400">└</span>
@@ -102,7 +102,7 @@ function BusinessScaleFormSection() {
<SectionCollapsible title="사업규모"> <SectionCollapsible title="사업규모">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p> <p className="mb-2 text-right font-normal text-muted-foreground">(단위: 백만원)</p>
<Table variant="secondary"> <Table caption="사업규모 입력: 구분, 기본계획, 예산반영, 금회설계, 증감 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="20%" /> <col width="20%" />
<col width="20%" /> <col width="20%" />
@@ -130,7 +130,7 @@ function BusinessScaleFormSection() {
return ( return (
<TableRow key={item.code}> <TableRow key={item.code}>
<TableHead className="text-left" style={{ paddingLeft }}> <TableHead scope="row" className="text-left" style={{ paddingLeft }}>
<div className="relative"> <div className="relative">
{showSubIcon && ( {showSubIcon && (
<span className="absolute -left-6 top-0 text-gray-400">└</span> <span className="absolute -left-6 top-0 text-gray-400">└</span>
@@ -199,7 +199,7 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
{checklistTabs.map((tab) => { {checklistTabs.map((tab) => {
return ( return (
<TabsContent key={tab.code} value={tab.code} className="space-y-4"> <TabsContent key={tab.code} value={tab.code} className="space-y-4">
<Table variant="secondary"> <Table caption={`${tab.label} 체크리스트 입력: 검토항목, 주요 검토내용, 검토결과 정보 제공`} variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead rowSpan={2} className="w-[30rem]"> <TableHead rowSpan={2} className="w-[30rem]">
@@ -246,7 +246,7 @@ function ChecklistFormSection({ docSeComCd, fieldPrefix }: ChecklistFormSectionP
return ( return (
<TableRow key={item.cklstRvwSn}> <TableRow key={item.cklstRvwSn}>
<TableCell className="font-medium">{item.title}</TableCell> <TableHead scope="row" className="font-medium">{item.title}</TableHead>
<TableCell <TableCell
style={{ style={{
paddingLeft: `${Math.max(0, item.treeLevel - 1) * 16 + 8}px`, paddingLeft: `${Math.max(0, item.treeLevel - 1) * 16 + 8}px`,
@@ -23,28 +23,28 @@ function ContactInfoFormSection({ fieldPrefix }: ContactInfoFormSectionProps) {
return ( return (
<SectionCollapsible title="담당자 정보"> <SectionCollapsible title="담당자 정보">
<Table variant="secondary"> <Table caption="담당자 정보 입력" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" rowSpan={2}> <TableHead scope="row" className="w-[20rem]" rowSpan={2}>
신청자 신청자
</TableHead> </TableHead>
<TableHead className="w-[16rem]">이름</TableHead> <TableHead scope="row" className="w-[16rem]">이름</TableHead>
<TableCell>{userInfo?.userName}</TableCell> <TableCell>{userInfo?.userName}</TableCell>
<TableHead className="w-[16rem]">연락처</TableHead> <TableHead scope="row" className="w-[16rem]">연락처</TableHead>
<TableCell>{userInfo?.mphn}</TableCell> <TableCell>{userInfo?.mphn}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell>{userInfo?.ogdpSeNm}</TableCell> <TableCell>{userInfo?.ogdpSeNm}</TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell>{userInfo?.email}</TableCell> <TableCell>{userInfo?.email}</TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead rowSpan={2} data-required> <TableHead scope="row" rowSpan={2} data-required>
설계자 설계자
</TableHead> </TableHead>
<TableHead>이름</TableHead> <TableHead scope="row">이름</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name={`${fieldPrefix}.dsgnrNm`} name={`${fieldPrefix}.dsgnrNm`}
@@ -62,7 +62,7 @@ function ContactInfoFormSection({ fieldPrefix }: ContactInfoFormSectionProps) {
)} )}
/> />
</TableCell> </TableCell>
<TableHead>연락처</TableHead> <TableHead scope="row">연락처</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name={`${fieldPrefix}.dsgnrTelno`} name={`${fieldPrefix}.dsgnrTelno`}
@@ -84,7 +84,7 @@ function ContactInfoFormSection({ fieldPrefix }: ContactInfoFormSectionProps) {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>소속</TableHead> <TableHead scope="row">소속</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name={`${fieldPrefix}.dsgnrOgdpNm`} name={`${fieldPrefix}.dsgnrOgdpNm`}
@@ -102,7 +102,7 @@ function ContactInfoFormSection({ fieldPrefix }: ContactInfoFormSectionProps) {
)} )}
/> />
</TableCell> </TableCell>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell> <TableCell>
<Controller <Controller
name={`${fieldPrefix}.dsgnrEmlAddr`} name={`${fieldPrefix}.dsgnrEmlAddr`}
@@ -200,7 +200,7 @@ function FnrsSharFormSection({ initialSharTree, initialSharAtchFiles }: FnrsShar
<h3 className="text-xl font-semibold">재원분담</h3> <h3 className="text-xl font-semibold">재원분담</h3>
<span className="font-normal text-muted-foreground">(단위: 백만원)</span> <span className="font-normal text-muted-foreground">(단위: 백만원)</span>
</div> </div>
<Table variant="secondary" className="table-fixed"> <Table caption="재원분담 입력: 구분, 현행, 변경요구, 증감, 비고 정보 제공" variant="secondary" className="table-fixed">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[24rem]" rowSpan={2}> <TableHead className="w-[24rem]" rowSpan={2}>
@@ -234,7 +234,7 @@ function FnrsSharFormSection({ initialSharTree, initialSharAtchFiles }: FnrsShar
return ( return (
<TableRow key={item.code}> <TableRow key={item.code}>
<TableHead className="text-left" style={{ paddingLeft }}> <TableHead scope="row" className="text-left" style={{ paddingLeft }}>
{showSubIcon && <span className="mr-1 text-gray-400">└</span>} {showSubIcon && <span className="mr-1 text-gray-400">└</span>}
{item.label} {item.label}
</TableHead> </TableHead>
@@ -97,7 +97,7 @@ function PbadmsTaskApplyDialog({
return ( return (
<Dialog open={open} onOpenChange={onOpenChange}> <Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className="max-w-[60rem]" aria-describedby={undefined}> <DialogContent className="max-w-[66rem]" aria-describedby={undefined}>
<DialogHeader> <DialogHeader>
<DialogTitle>{title}</DialogTitle> <DialogTitle>{title}</DialogTitle>
</DialogHeader> </DialogHeader>
@@ -105,17 +105,17 @@ function PbadmsTaskApplyDialog({
{isPending ? ( {isPending ? (
<Skeleton className="h-[16rem] w-full" /> <Skeleton className="h-[16rem] w-full" />
) : ( ) : (
<Table variant="secondary"> <Table caption="행정지원 신청 정보 입력" variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="20%" />
<col width="35%" /> <col width="30%" />
<col width="15%" /> <col width="20%" />
<col width="35%" /> <col width="30%" />
</colgroup> </colgroup>
<TableHeader> <TableHeader>
{canSidoGugunSelectable && ( {canSidoGugunSelectable && (
<TableRow> <TableRow>
<TableHead data-required>시도</TableHead> <TableHead scope="row" data-required>시도</TableHead>
<TableCell> <TableCell>
<Select <Select
value={sidoComCd || undefined} value={sidoComCd || undefined}
@@ -136,7 +136,7 @@ function PbadmsTaskApplyDialog({
</SelectContent> </SelectContent>
</Select> </Select>
</TableCell> </TableCell>
<TableHead>시군구</TableHead> <TableHead scope="row">시군구</TableHead>
<TableCell> <TableCell>
<Select <Select
value={sggComCd || undefined} value={sggComCd || undefined}
@@ -158,7 +158,7 @@ function PbadmsTaskApplyDialog({
</TableRow> </TableRow>
)} )}
<TableRow> <TableRow>
<TableHead data-required>업무구분</TableHead> <TableHead scope="row" data-required>업무구분</TableHead>
<TableCell colSpan={3}> <TableCell colSpan={3}>
<FieldSet className="px-2"> <FieldSet className="px-2">
<FieldGroup data-slot="checkbox-group" className="flex-row flex-wrap"> <FieldGroup data-slot="checkbox-group" className="flex-row flex-wrap">
@@ -12,7 +12,7 @@ import {
TableHead, TableHead,
TableHeader, TableHeader,
TableRow, TableRow,
} from "@common/components"; } from "@common/components";
interface PrivacyConsentFormData { interface PrivacyConsentFormData {
privacyConsent: "Y" | "N"; privacyConsent: "Y" | "N";
@@ -23,7 +23,7 @@ function PrivacyConsentSection() {
return ( return (
<SectionCollapsible title="개인정보 수집/이용 동의"> <SectionCollapsible title="개인정보 수집/이용 동의">
<Table variant="secondary"> <Table caption="개인정보 수집·이용 동의 내용" variant="secondary">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
<TableHead className="w-[20rem]" data-required> <TableHead className="w-[20rem]" data-required>
@@ -57,7 +57,7 @@ function ProgressStatusSection({
return ( return (
<SectionCollapsible title="진행 상태"> <SectionCollapsible title="진행 상태">
<Table variant="secondary" className="table-fixed"> <Table caption="행정지원 진행상태" variant="secondary" className="table-fixed">
<TableHeader> <TableHeader>
<TableRow> <TableRow>
{columns.map((column) => ( {columns.map((column) => (
@@ -239,7 +239,7 @@ function SplmntDmndDialog({
</div> </div>
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="보완 요청 입력: 보완 항목, 보완 의견, 첨부파일 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="20%" /> <col width="20%" />
<col width="50%" /> <col width="50%" />
@@ -240,7 +240,7 @@ function SplmntDmndFormSection({ initialData, readOnly = false }: SplmntDmndForm
return ( return (
<SectionCollapsible title="보완요청"> <SectionCollapsible title="보완요청">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="보완요청 및 처리 현황: 보완항목, 요청일시, 요청내용, 완료내용, 첨부파일, 완료여부 정보 제공" variant="secondary">
<colgroup> <colgroup>
<col width="12%" /> <col width="12%" />
<col width="14%" /> <col width="14%" />
@@ -28,7 +28,7 @@ function SupplementDemandSection({ splmntDmndList }: SupplementDemandSectionProp
return ( return (
<SectionCollapsible title="보완요청 및 완료 현황"> <SectionCollapsible title="보완요청 및 완료 현황">
<div className="overflow-x-auto"> <div className="overflow-x-auto">
<Table variant="secondary"> <Table caption="보완요청 현황" variant="secondary">
<colgroup> <colgroup>
<col width="14%" /> <col width="14%" />
<col width="8%" /> <col width="8%" />
@@ -1,3 +1,7 @@
"use client"; "use client";
export { PostPage as NormalPage } from "@/widgets/post"; import { PostPage } from "@/widgets/post";
export function NormalPage({ bbsId }: { bbsId: string }) {
return <PostPage bbsId={bbsId} tableCaption="게시판 목록으로 No, 제목, 조회수, 첨부파일, 작성, 등록일 정보 제공" />;
}
@@ -3,5 +3,5 @@
import { PostPage } from "@/widgets/post"; import { PostPage } from "@/widgets/post";
export function NoticePage({ bbsId }: { bbsId: string }) { export function NoticePage({ bbsId }: { bbsId: string }) {
return <PostPage bbsId={bbsId} tableCaption="공지사항 목록" />; return <PostPage bbsId={bbsId} tableCaption="공지사항 목록으로 No, 제목, 조회수, 첨부파일, 작성, 등록일 정보 제공" />;
} }
@@ -86,7 +86,7 @@ const MenuModificationDemandDialog = memo(
</colgroup> </colgroup>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead>신청자</TableHead> <TableHead scope="row">신청자</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -107,7 +107,7 @@ const MenuModificationDemandDialog = memo(
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>이메일</TableHead> <TableHead scope="row">이메일</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -128,7 +128,7 @@ const MenuModificationDemandDialog = memo(
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>요청 내용</TableHead> <TableHead scope="row">요청 내용</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -1,4 +1,4 @@
import type { HTMLAttributes } from "react"; import type { HTMLAttributes, ReactNode } from "react";
import { import {
flexRender, flexRender,
type RowData, type RowData,
@@ -26,6 +26,7 @@ type GridViewDataTableProps<T> = {
className?: HTMLAttributes<HTMLTableElement>["className"]; className?: HTMLAttributes<HTMLTableElement>["className"];
viewPagination?: boolean; viewPagination?: boolean;
onRowClick?: (row: T) => void; onRowClick?: (row: T) => void;
footerContent?: ReactNode;
}; };
function GridViewDataTable<T>({ function GridViewDataTable<T>({
@@ -33,6 +34,7 @@ function GridViewDataTable<T>({
className, className,
viewPagination, viewPagination,
onRowClick, onRowClick,
footerContent,
}: GridViewDataTableProps<T>) { }: GridViewDataTableProps<T>) {
return ( return (
<div className="bg-secondary-background pb-10"> <div className="bg-secondary-background pb-10">
@@ -72,6 +74,9 @@ function GridViewDataTable<T>({
))} ))}
</div> </div>
</div> </div>
{footerContent && (
<div className="px-4 text-left">{footerContent}</div>
)}
{viewPagination && <Pagination table={table} />} {viewPagination && <Pagination table={table} />}
</div> </div>
); );
@@ -70,6 +70,9 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
<Form {...form}> <Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)}> <form onSubmit={form.handleSubmit(onSubmit)}>
<div className="card"> <div className="card">
<p className="mb-2 text-right text-sm text-muted-foreground">
*은 필수입력 항목입니다.
</p>
<Table variant="secondary"> <Table variant="secondary">
<colgroup> <colgroup>
<col width="15%" /> <col width="15%" />
@@ -77,7 +80,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
</colgroup> </colgroup>
<TableBody> <TableBody>
<TableRow> <TableRow>
<TableHead data-required>제목</TableHead> <TableHead scope="row" data-required>제목</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -98,7 +101,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow> <TableRow>
<TableHead>작성자</TableHead> <TableHead scope="row">작성자</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -120,7 +123,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
</TableRow> </TableRow>
{!userInfo?.userUnqId && ( {!userInfo?.userUnqId && (
<TableRow> <TableRow>
<TableHead data-required>비밀번호</TableHead> <TableHead scope="row" data-required>비밀번호</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -143,7 +146,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
</TableRow> </TableRow>
)} )}
<TableRow> <TableRow>
<TableHead>내용</TableHead> <TableHead scope="row">내용</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -166,7 +169,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
</TableRow> </TableRow>
{bbsInfo?.rfrncUseYn === "Y" && ( {bbsInfo?.rfrncUseYn === "Y" && (
<TableRow> <TableRow>
<TableHead>참조 URL</TableHead> <TableHead scope="row">참조 URL</TableHead>
<TableCell className="border"> <TableCell className="border">
<FormField <FormField
control={form.control} control={form.control}
@@ -189,7 +192,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
)} )}
{bbsInfo?.popupUseYn === "Y" && ( {bbsInfo?.popupUseYn === "Y" && (
<TableRow> <TableRow>
<TableHead>팝업여부</TableHead> <TableHead scope="row">팝업여부</TableHead>
<TableCell className="border"> <TableCell className="border">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<FormField <FormField
@@ -262,7 +265,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
)} )}
{bbsInfo?.upndFixUseYn === "Y" && ( {bbsInfo?.upndFixUseYn === "Y" && (
<TableRow> <TableRow>
<TableHead>상단고정</TableHead> <TableHead scope="row">상단고정</TableHead>
<TableCell className="border"> <TableCell className="border">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<FormField <FormField
@@ -336,7 +339,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
)} )}
{bbsInfo?.pstgPrdUseYn === "Y" && ( {bbsInfo?.pstgPrdUseYn === "Y" && (
<TableRow> <TableRow>
<TableHead>게시기간</TableHead> <TableHead scope="row">게시기간</TableHead>
<TableCell className="border"> <TableCell className="border">
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<FormField <FormField
@@ -410,7 +413,7 @@ function PostForm<T extends PostFormData | PostUpdateFormData>({
)} )}
{bbsInfo?.atflUseYn === "Y" && ( {bbsInfo?.atflUseYn === "Y" && (
<TableRow> <TableRow>
<TableHead>첨부파일</TableHead> <TableHead scope="row">첨부파일</TableHead>
<TableCell className="border"> <TableCell className="border">
{bbsInfo?.bbsTypeCd === "BBSIMAGE" ? ( {bbsInfo?.bbsTypeCd === "BBSIMAGE" ? (
<WithPreviewFileUploader <WithPreviewFileUploader
@@ -213,15 +213,6 @@ function PostPage({
등록 등록
</Button> </Button>
)} )}
{pageMenuAuthority?.delAuthrtYn === "Y" && (
<Button
color="red"
onClick={onPostDelete}
disabled={!table.getFilteredSelectedRowModel().rows.length}
>
선택삭제
</Button>
)}
<Select <Select
value={table.getState().pagination.pageSize.toString()} value={table.getState().pagination.pageSize.toString()}
onValueChange={(value) => { onValueChange={(value) => {
@@ -254,6 +245,17 @@ function PostPage({
table={table} table={table}
onRowClick={handleRowClick} onRowClick={handleRowClick}
viewPagination viewPagination
footerContent={
pageMenuAuthority?.delAuthrtYn === "Y" ? (
<Button
color="red"
onClick={onPostDelete}
disabled={!table.getFilteredSelectedRowModel().rows.length}
>
선택삭제
</Button>
) : undefined
}
/> />
) : ( ) : (
<DataTable <DataTable
@@ -261,6 +263,17 @@ function PostPage({
onRowClick={handleRowClick} onRowClick={handleRowClick}
viewPagination viewPagination
caption={tableCaption} caption={tableCaption}
footerContent={
pageMenuAuthority?.delAuthrtYn === "Y" ? (
<Button
color="red"
onClick={onPostDelete}
disabled={!table.getFilteredSelectedRowModel().rows.length}
>
선택삭제
</Button>
) : undefined
}
/> />
) )
)} )}
+2 -2
View File
@@ -74,8 +74,8 @@
} }
nav[aria-label="pagination"] li a[aria-current="page"] { nav[aria-label="pagination"] li a[aria-current="page"] {
border-color: #2094fa !important; border-color: #0a84f0 !important;
background-color: #2094fa !important; background-color: #0a84f0 !important;
color: #fafafa !important; color: #fafafa !important;
} }
@@ -10,8 +10,8 @@
width: 0.55rem; width: 0.55rem;
height: 0.55rem; height: 0.55rem;
border-radius: 9999px; border-radius: 9999px;
background: #ff6c64; background: #e53e35;
box-shadow: 0 0 0 0 rgba(255, 108, 100, 0.75); box-shadow: 0 0 0 0 rgba(229, 62, 53, 0.75);
animation: verification-result-btn-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; animation: verification-result-btn-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
pointer-events: none; pointer-events: none;
} }
+3 -3
View File
@@ -132,7 +132,7 @@
@apply !font-semibold; @apply !font-semibold;
} }
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected { .rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected {
@apply !font-semibold !text-[#ff6c64]; @apply !font-semibold !text-[#e53e35];
white-space: nowrap !important; white-space: nowrap !important;
} }
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected > * { .rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-stats-status-rejected > * {
@@ -150,8 +150,8 @@
width: 0.6125rem; width: 0.6125rem;
height: 0.6125rem; height: 0.6125rem;
border-radius: 9999px; border-radius: 9999px;
background: #ff6c64; background: #e53e35;
box-shadow: 0 0 0 0 rgba(255, 108, 100, 0.75); box-shadow: 0 0 0 0 rgba(229, 62, 53, 0.75);
animation: rg-cell-stats-status-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite; animation: rg-cell-stats-status-dot-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
} }
.rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-total { .rg-grid .rg-body .rg-table .rg-data-row .rg-data-cell.rg-cell-total {
+4 -4
View File
@@ -2411,13 +2411,13 @@ useEffect(() => {
) : statusInfo.laeSbmsnSttsCd === "2" ? ( ) : statusInfo.laeSbmsnSttsCd === "2" ? (
<span className="!text-[#2094fa]">제출</span> <span className="!text-[#2094fa]">제출</span>
) : statusInfo.laeSbmsnSttsCd === "3" ? ( ) : statusInfo.laeSbmsnSttsCd === "3" ? (
<span className="!text-[#1fd078]">승인</span> <span className="!text-[#179d5b]">승인</span>
) : statusInfo.laeSbmsnSttsCd === "4" ? ( ) : statusInfo.laeSbmsnSttsCd === "4" ? (
<span className="relative inline-flex pr-3 !text-[#ff6c64]"> <span className="relative inline-flex pr-3 !text-[#e53e35]">
반려 반려
<span className="absolute -right-0.5 -top-0.5 inline-flex size-[0.6125rem]"> <span className="absolute -right-0.5 -top-0.5 inline-flex size-[0.6125rem]">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#ff6c64] opacity-75" /> <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[#e53e35] opacity-75" />
<span className="relative inline-flex size-[0.6125rem] rounded-full bg-[#ff6c64]" /> <span className="relative inline-flex size-[0.6125rem] rounded-full bg-[#e53e35]" />
</span> </span>
</span> </span>
) : ( ) : (

Some files were not shown because too many files have changed in this diff Show More