214 lines
7.0 KiB
TypeScript
214 lines
7.0 KiB
TypeScript
/**
|
|
* 📄 InputTableBody Component
|
|
* 침수예방 입력 테이블 바디 컴포넌트
|
|
*
|
|
* - 숫자 입력 및 콤마 포맷팅 기능
|
|
* - mergeCell을 통한 셀 병합 처리
|
|
* - 편집 가능/불가능 상태 관리
|
|
* - 소계/총합계 행 스타일링 및 표시
|
|
* - 입력 값 검증 및 변경 핸들링
|
|
* - 빈 데이터 상태 처리
|
|
*/
|
|
import type { TableUpperProps } from "./headMakeFloodPre";
|
|
import { Input, TableCell, TableRow } from "@common/components/ui";
|
|
|
|
// 숫자입력시 , 삽입
|
|
const formatCommaNumber = (
|
|
value: number | string | undefined | null,
|
|
): string => {
|
|
if (value === undefined || value === null || value === "") return "";
|
|
const num = Number(value);
|
|
// 숫자로 변환할 수 없는 값이 들어올 경우 빈 문자열을 반환하여 예상치 못한 "NaN" 출력을 방지합니다.
|
|
if (isNaN(num)) {
|
|
return "";
|
|
}
|
|
return num.toLocaleString();
|
|
};
|
|
|
|
// onchange 텍스트를 숫자로 and ,제거
|
|
const handleCommaNumberChange = (
|
|
e: React.ChangeEvent<HTMLInputElement>,
|
|
onChange: (value: number | "") => void,
|
|
) => {
|
|
const raw = e.target.value.replace(/,/g, "");
|
|
if (!/^\d*$/.test(raw)) return;
|
|
onChange(raw === "" ? "" : Number(raw));
|
|
};
|
|
|
|
const handleChange = (
|
|
rowIndex: number,
|
|
field: any,
|
|
value: string,
|
|
setInputData: (data: any) => void,
|
|
) => {
|
|
if (Number(value) < 0 || !Number(value)) {
|
|
value = "0";
|
|
}
|
|
setInputData((prevData: any) =>
|
|
prevData?.map((row: any, index: number) => {
|
|
if (index === rowIndex) {
|
|
return {
|
|
...row,
|
|
[field]: Number(value.replace(/,/g, "")),
|
|
};
|
|
}
|
|
return row;
|
|
}),
|
|
);
|
|
};
|
|
|
|
export const InputTableBody = (
|
|
chgRes: any[] | [],
|
|
headList: TableUpperProps[],
|
|
setInputData: (data: any[]) => void,
|
|
isEditable: boolean = true,
|
|
) => {
|
|
// mergeCell 처리용
|
|
const getRowSpan = (data: any[], key: string, rowIndex: number) => {
|
|
if (
|
|
rowIndex > 0 &&
|
|
data[rowIndex - 1][key] &&
|
|
String(data[rowIndex][key]).trim() === ""
|
|
) {
|
|
return 0; // 이전과 같으면 셀을 그리지 않음
|
|
}
|
|
let span = 1;
|
|
for (let i = rowIndex + 1; i < data.length; i++) {
|
|
if (data[i][key] === data[rowIndex][key]) span++;
|
|
else break;
|
|
}
|
|
return span;
|
|
};
|
|
return (
|
|
<>
|
|
{chgRes.map((data, dataIndex) => {
|
|
// 소계/총합계 행 판별
|
|
const isSubTotal = data["용수명"] === "소계";
|
|
const isTotal = data["구분"] === 0;
|
|
|
|
const bgClass = isTotal
|
|
? "bg-secondary font-bold"
|
|
: isSubTotal
|
|
? "bg-muted font-semibold"
|
|
: "";
|
|
|
|
return (
|
|
<TableRow key={dataIndex + "row"}>
|
|
{headList.map((head, headIndex) => {
|
|
const isTextColumn = head.id === "__EMPTY_3";
|
|
const textAlignClass = isTextColumn
|
|
? "text-center"
|
|
: "text-right";
|
|
|
|
// // 총합계 행이면 "구분"에서 colSpan=2로 병합
|
|
// if (
|
|
// (data["구분"] === 0 || data["용수명"] === 0) &&
|
|
// head.id === "구분"
|
|
// ) {
|
|
// return (
|
|
// <TableCell
|
|
// key={head.id + headIndex}
|
|
// colSpan={2}
|
|
// className="bg-secondary text-center font-bold"
|
|
// >
|
|
// 총합계
|
|
// </TableCell>
|
|
// );
|
|
// }
|
|
// // 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음
|
|
// if (
|
|
// (data["구분"] === 0 || data["용수명"] === 0) &&
|
|
// head.id === "용수명"
|
|
// ) {
|
|
// return null;
|
|
// }
|
|
|
|
// // 총합계 행의 나머지 셀에도 색상 적용
|
|
// if (data["구분"] === 0 || data["용수명"] === 0) {
|
|
// return (
|
|
// <TableCell
|
|
// key={head.id + headIndex}
|
|
// className="bg-secondary text-right font-bold"
|
|
// >
|
|
// {Number(data[head.id])
|
|
// ? formatCommaNumber(data[head.id as keyof any])
|
|
// : (data[head.id as keyof any] ?? "")}
|
|
// </TableCell>
|
|
// );
|
|
// }
|
|
// mergeCell 처리
|
|
if (head.mergeCell === true) {
|
|
const rowSpan = getRowSpan(chgRes, head.id, dataIndex);
|
|
if (rowSpan === 0) return null;
|
|
return (
|
|
<TableCell
|
|
key={head.id + headIndex}
|
|
rowSpan={rowSpan}
|
|
className={`w-36 whitespace-nowrap text-center align-middle ${bgClass}`}
|
|
>
|
|
{Number(data[head.id])
|
|
? formatCommaNumber(data[head.id as keyof any])
|
|
: (data[head.id as keyof any] ?? "")}
|
|
</TableCell>
|
|
);
|
|
}
|
|
// 기본 셀
|
|
// return head.edit === true && data.edit !== false ? (
|
|
return isEditable && head.edit === true && data.edit !== false ? (
|
|
<TableCell
|
|
key={head.id + headIndex}
|
|
className={`w-36 ${bgClass}`}
|
|
>
|
|
<Input
|
|
// className={`${head.id !== "utztnUsgCd" ? "text-right" : "text-center"} !text-xl h-10 w-full`}
|
|
className={`${textAlignClass} h-10 w-full !text-xl`}
|
|
onChange={(e) =>
|
|
handleCommaNumberChange(e, (val) =>
|
|
handleChange(
|
|
dataIndex,
|
|
head.id,
|
|
String(val),
|
|
setInputData,
|
|
),
|
|
)
|
|
}
|
|
value={formatCommaNumber(data[head.id as keyof any]) ?? ""}
|
|
maxLength={12}
|
|
/>
|
|
</TableCell>
|
|
) : (
|
|
<TableCell
|
|
key={head.id + headIndex}
|
|
className={`w-36 ${bgClass}`}
|
|
>
|
|
<div
|
|
// className={`
|
|
// ${head.id !== "utztnUsgCd" ? "text-right" : "text-center"}
|
|
// !text-xl w-full h-10
|
|
// `}
|
|
className={`${textAlignClass} h-10 w-full !text-xl`}
|
|
>
|
|
{Number(data[head.id])
|
|
? formatCommaNumber(data[head.id as keyof any])
|
|
: (data[head.id as keyof any] ?? "")}
|
|
</div>
|
|
</TableCell>
|
|
);
|
|
})}
|
|
</TableRow>
|
|
);
|
|
})}
|
|
{chgRes.length === 0 && (
|
|
<TableRow>
|
|
<TableCell
|
|
colSpan={headList.length}
|
|
className="h-24 text-center text-muted-foreground"
|
|
>
|
|
조회된 결과가 없습니다.
|
|
</TableCell>
|
|
</TableRow>
|
|
)}
|
|
</>
|
|
);
|
|
};
|