Merge branch 'iipbs/sn/ii' into iipbs/sn/dev

This commit is contained in:
swcho
2025-07-22 21:08:17 +09:00
20 changed files with 849 additions and 805 deletions
@@ -87,7 +87,7 @@ const getGlobalMax = (data: Record<string, number>[]) => {
};
export default function Chart({chartConfig=undefined, chartData=[], chartTitle='차트', chartClassName='w-full h-full', graphSize=40, yFieldText='', showLegend=false} : BarChartProps) {
const colors = ["#FF6B6B", "#4ECDC4", "#45B7D1", "#FED16A", "#FFEEAD", "#D4A5A5"];
const colors = ["#FF6B6B", "#4ECDC4", "#44ad57", "#FED16A", "#FFEEAD", "#D4A5A5"];
const globalMax = getGlobalMax(chartData);
const tickCount = 5;
// interval을 globalMax / tickCount로 계산
@@ -50,15 +50,40 @@ const customStyles = {
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px", // 범례 영역 높이 통일
minHeight: "60px", // 범례 영역 높이 통일
} as CSSProperties,
};
const renderCustomizedLabel = ({
cx,
cy,
midAngle,
outerRadius,
payload,
}: any) => {
const RADIAN = Math.PI / 180;
const radius = outerRadius + 25;
const x = cx + radius * Math.cos(-midAngle * RADIAN);
const y = cy + radius * Math.sin(-midAngle * RADIAN);
return (
<text
x={x}
y={y}
fill="#333"
fontSize={11}
textAnchor={x > cx ? "start" : "end"}
dominantBaseline="central"
>
{`${payload.label}: ${payload.val.toLocaleString()}`}
</text>
);
};
// 커스텀 툴팁
const CustomTooltip = ({ active, payload, label }: {
active?: boolean;
payload?: TooltipPayloadItem[];
label?: string
const CustomTooltip = ({ active, payload, label }: {
active?: boolean;
payload?: TooltipPayloadItem[];
label?: string
}) => {
if (active && payload && payload.length) {
return (
@@ -79,7 +104,6 @@ const CustomTooltip = ({ active, payload, label }: {
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: LegendEntry, index: number) => (
@@ -111,9 +135,9 @@ const CustomLegend = (props: LegendProps) => {
);
};
export default function DoughnutChart(props: {
chartConfig: ChartConfig;
chartData: ChartDataItem[] | undefined;
export default function DoughnutChart(props: {
chartConfig: ChartConfig;
chartData: ChartDataItem[] | undefined;
chartTitle: string
}) {
const legendData = props.chartData?.map(item => ({
@@ -125,19 +149,20 @@ export default function DoughnutChart(props: {
fill: props.chartConfig?.[item.label]?.color || 'blue'
}
})) ?? [];
return (
<Card className="flex flex-col">
<CardContent className="flex-1 pb-0">
{props.chartTitle && props.chartTitle !== "" && props.chartTitle !== "undefined" ? (
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop:"13px", marginBottom: "10px" }}>
<div style={{ textAlign: "left", fontSize: "13px", fontWeight: "bold", marginTop: "13px", marginBottom: "10px" }}>
{props.chartTitle}
</div>
) : null}
<div className="h-[calc(100%-42px)] justify-center">
<ChartContainer
config={props.chartConfig}
className="mx-auto aspect-square max-h-[300px]"
// className="mx-auto aspect-square max-h-[300px]"
className="min-h-[300px] w-full"
>
<PieChart>
<ChartTooltip
@@ -152,10 +177,14 @@ export default function DoughnutChart(props: {
dataKey="val"
nameKey="label"
innerRadius={60}
/>
label={(props) => {
return renderCustomizedLabel(props);
}}
>
</Pie>
</PieChart>
</ChartContainer>
<CustomLegend payload={legendData} />
<CustomLegend payload={legendData} />
</div>
</CardContent>
</Card>
@@ -32,10 +32,27 @@ export function DatePicker({
}: DatePickerProps) {
const [open, setOpen] = useState(false);
// const handleSelect = (date: Date | undefined) => {
// console.log("날짜", date)
// if (!readOnly) {
// // readOnly가 아닐 때만 변경 허용
// field.onChange(date); // React Hook Form 업데이트
// setOpen(false);
// }
// };
//저장시 9시간 전으로 돌아가는 문제
const handleSelect = (date: Date | undefined) => {
if (!readOnly) {
// readOnly가 아닐 때만 변경 허용
field.onChange(date); // React Hook Form 업데이트
if (date) {
const utcMidnight = new Date(
//utc 삽입
Date.UTC(date.getFullYear(), date.getMonth(), date.getDate())
);
field.onChange(utcMidnight);
} else {
field.onChange(undefined);
}
setOpen(false);
}
};
@@ -53,17 +70,17 @@ export function DatePicker({
className={
!selectClass
? cn(
"w-[240px] pl-3 text-left font-normal",
!field?.value && "text-muted-foreground",
"w-[240px] pl-3 text-left font-normal",
!field?.value && "text-muted-foreground",
//감리 지적사항으로 삭제 예정 리드온리는 리드온리 로만 보일수 있도록 수정
// disabled={readOnly} // readOnly일 때 버튼 비활성화
//readOnly && "opacity-60 cursor-not-allowed" 감리 지적사항으로
)
//감리 지적사항으로 삭제 예정 리드온리는 리드온리 로만 보일수 있도록 수정
// disabled={readOnly} // readOnly일 때 버튼 비활성화
//readOnly && "opacity-60 cursor-not-allowed" 감리 지적사항으로
)
: cn(
selectClass,
// , readOnly && "opacity-60 cursor-not-allowed"
)
selectClass,
// , readOnly && "opacity-60 cursor-not-allowed"
)
}
>
{field?.value ? (
@@ -87,16 +104,15 @@ export function DatePicker({
className="w-full"
//-- 데이트 피커가 드롭박스 형태로 년월을 선택할수 있도록 하는 Props 로 활성화 되면 드롭박스로 선택
// captionLayout="dropdown-buttons"
// fromYear={2000}
// toYear={new Date().getFullYear()}
toDate={new Date()} // 금일까지만 표시됨 (금일 이후는 안보임)
// captionLayout="dropdown-buttons"
// fromYear={2000}
// toYear={new Date().getFullYear()}
showOutsideDays={false} // 금월 까지만 표출되도록
mode="single"
selected={field?.value}
onSelect={handleSelect}
initialFocus
disabled={{ after: new Date() }} // 금일까지만 표시됨 (금일 이후는 안보임) 20250721 캘린더가 변경됨!!
locale={ko}
/>
</PopoverContent>
@@ -1,20 +1,26 @@
import { LoadingWithAnimation } from '@common/components/ui/loading';
import React from 'react';
import { LoadingWithAnimation } from "@common/components/ui/loading";
import React from "react";
interface LoadingOverlayProps {
isLoading: boolean;
customZindex?: string;
}
const LoadingOverlay: React.FC<LoadingOverlayProps> = ({ isLoading }) => {
const LoadingOverlay: React.FC<LoadingOverlayProps> = ({
isLoading,
customZindex,
}) => {
if (!isLoading) return null;
return (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-50">
<div className="relative w-16 h-16">
<div
className={`fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 ${customZindex || "z-50"}`}
>
<div className="relative h-16 w-16">
<LoadingWithAnimation color="primary" />
</div>
</div>
);
};
export default LoadingOverlay;
export default LoadingOverlay;
@@ -21,6 +21,9 @@ type SearchBaseType = {
btnClass:string;
ref:React.RefObject<ReturnType>;
isAdmin:boolean;
rightClassName?: string;
leftClassName?: string;
leftSelectClassName?: string;
}
export type ReturnType = {
partValue: string;
@@ -49,7 +52,10 @@ function SearchBaseForm ({
excelClick,
initClick,
ref,
isAdmin=false
isAdmin=false,
rightClassName,
leftClassName,
leftSelectClassName
}: SearchBaseType) {
const [partValue, setPartValue] = useState<string>("A");
const [sidoValue, setSidoValue] = useState<string>("0");
@@ -133,10 +139,12 @@ function SearchBaseForm ({
setRtnSigunText={setSigunText}
resetTrigger={resetTrigger}
isAdmin={isAdmin}
leftClassName={leftClassName}
leftSelectClassName={leftSelectClassName}
>
{leftChildren}
</SearchFormLeft>
<SearchFormRight>
<SearchFormRight className={rightClassName}>
<Button className={btnClass} color="green" onClick={excelDownload}>
{excelName?excelName:"엑셀다운로드"}
</Button>
@@ -44,6 +44,8 @@ type SearchFormLeftProps = {
setRtnSigunText?: (value: string) => void;
resetTrigger?: boolean;
isAdmin?: boolean;
leftClassName?: string;
leftSelectClassName?: string;
}
export type EnvPartSelectDataType = SelectDataType & {
@@ -56,7 +58,7 @@ const selectPartData:SelectDataType[] = [
{ text: "환경청별", val: 'G' },
];
function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSidoText, setRtnSigunValue, setRtnSigunText, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false, isAdmin = false }: SearchFormLeftProps) {
function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSidoText, setRtnSigunValue, setRtnSigunText, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false, isAdmin = false, leftClassName, leftSelectClassName }: SearchFormLeftProps) {
/******************선택된 데이터******************/
const [partValue, setPartValue] = useState<string>('A');
//행정별 시도 시군구
@@ -308,24 +310,24 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
return (
isShowPart ? (
<div className="grid grid-cols-12 gap-5 w-11/12 m-4">
<SelectBox className="col-span-3" label={'구분'} selectArray={isAdmin ? selectPartData.slice(0, 1) : selectPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'part')} value={partValue} selectClass={undefined}/>
<div className={leftClassName?leftClassName:`grid grid-cols-12 gap-5 w-11/12 m-4`}>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'구분'} selectArray={isAdmin ? selectPartData.slice(0, 1) : selectPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'part')} value={partValue} selectClass={undefined}/>
{partValue === 'R' ? (
<>
<SelectBox className="col-span-3" label={'유역'} selectArray={selectRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'region')} value={regionValue} selectClass={undefined}/>
<SelectBox className="col-span-3" label={'단위유역'} selectArray={filteredUnitWaterShedData} onSelectValue={(val) => onSelectValue(val.toString(), 'unitWaterShed')} value={unitWaterShedValue} selectClass={undefined}/>
<SelectBox className="col-span-3" label={'중권역'} selectArray={filteredMiddleRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'middleRegion')} value={middleRegionValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'유역'} selectArray={selectRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'region')} value={regionValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'단위유역'} selectArray={filteredUnitWaterShedData} onSelectValue={(val) => onSelectValue(val.toString(), 'unitWaterShed')} value={unitWaterShedValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'중권역'} selectArray={filteredMiddleRegionData} onSelectValue={(val) => onSelectValue(val.toString(), 'middleRegion')} value={middleRegionValue} selectClass={undefined}/>
</>
) : partValue === 'G' ? (
<>
<SelectBox className="col-span-3" label={'환경청'} selectArray={filteredEnvPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={undefined}/>
<SelectBox className="col-span-3" label={'시도'} selectArray={filteredEnvPartSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')} value={sidoValue} selectClass={undefined}/>
<SelectBox className="col-span-3" label={'시군구'} selectArray={filteredEnvPartSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')} value={sigunValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'환경청'} selectArray={filteredEnvPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시도'} selectArray={filteredEnvPartSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')} value={sidoValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시군구'} selectArray={filteredEnvPartSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')} value={sigunValue} selectClass={undefined}/>
</>
) : (
<>
<SelectBox className="col-span-3" label={'시도'} selectArray={selectSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'sido')} value={sidoValue} selectClass={undefined}/>
<SelectBox className="col-span-3" label={'시군구'} selectArray={filteredSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시도'} selectArray={selectSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'sido')} value={sidoValue} selectClass={undefined}/>
<SelectBox className={leftSelectClassName?leftSelectClassName:`col-span-3`} label={'시군구'} selectArray={filteredSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={undefined}/>
</>
)}
{children}
@@ -1,38 +0,0 @@
import { Tabs, TabsList, TabsTrigger } from '@common/components/ui';
import React from 'react';
interface TabItem {
value: string;
label: string;
onClick?: () => void;
}
interface UITabProps extends React.HTMLAttributes<HTMLDivElement> {
defaultValue?: string;
tabList: TabItem[];
children: React.ReactNode;
}
const UITab2 = React.forwardRef<
HTMLDivElement,
UITabProps
>(({defaultValue, tabList, children}, ref)=>{
return (
<Tabs defaultValue={defaultValue || tabList[0]?.value} className={"w-full"}>
<TabsList className="flex">
{tabList.map((tab) => (
<TabsTrigger
key={tab.value}
value={tab.value}
onClick={tab.onClick}
className="py-2 px-4 text-sm font-medium border-b-2 focus:outline-none data-[state=active]:border-blue-500 data-[state=active]:text-blue-600 data-[state=inactive]:border-transparent data-[state=inactive]:text-gray-500 hover:text-gray-700 hover:border-gray-300"
>
{tab.label}
</TabsTrigger>
))}
</TabsList>
{children}
</Tabs>
)
})
export { UITab2 };
@@ -1,155 +0,0 @@
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@common/components";
import { useEffect, useState } from "react";
import UiPageNations from "./uiPageNations";
type UiTableProps = {
headName: React.ReactNode | undefined;
tableData: { [key: string]: string | number | boolean | object }[];
headlist: UiHeadProps[];
pageSize: number;
total: number;
children: React.ReactNode | undefined;
cellClick: ((index: number | undefined, headId: string) => void) | undefined;
onPageChange: (page: number) => void;
className?: string;
resetPageNo?: boolean;
cur?: number;
height?: string; // ✅ 추가된 prop
};
type UiHeadProps = {
id: string;
title: string;
align?: string;
};
export function UiTable2({
tableData,
headlist,
pageSize,
total,
children,
headName,
cellClick,
onPageChange,
className = '',
resetPageNo = false,
cur,
height = '45vh', // ✅ 기본값 설정
}: UiTableProps) {
const [idx, setIdx] = useState<number>(-1);
const [curState, setCurState] = useState<number>(cur ?? 1);
useEffect(() => {
setCurState(cur ?? 1);
}, [cur]);
useEffect(() => {
if (resetPageNo) {
setCurState(1);
onPageChange(1);
}
}, [onPageChange, resetPageNo]);
const handlePageChange = (page: number) => {
setCurState(page);
onPageChange(page);
};
const handleCellClick = (index: number, headId: string) => {
if (cellClick) {
cellClick(index, headId);
setIdx(index);
}
};
const startIdx = (curState - 1) * pageSize;
return (
<>
{headName && (
<div className="card-header">
<div className="flex w-full items-center justify-between">
<h3 className="text-2xl font-medium text-label">{headName}</h3>
</div>
</div>
)}
<div className={`card !m-[1.2rem] !p-0 relative ${className}`}>
{/* ✅ 외부에서 조절 가능한 높이 적용 */}
<div className="overflow-auto" style={{ height }}>
<Table variant="secondary" className="w-full">
<TableHeader className="bg-white">
{children ? (
<>{children}</>
) : (
<TableRow>
{headlist.map((head) => (
<TableHead
key={head.id}
className="min-w-[120px] max-w-[180px] w-[150px]
text-center whitespace-nowrap overflow-hidden
text-ellipsis bg-white"
>
{head.title}
</TableHead>
))}
</TableRow>
)}
</TableHeader>
<TableBody className="text-center">
{tableData.length > 0 ? (
tableData.map((el, index) => (
<TableRow key={index + "row"}>
{headlist.map((head) => (
<TableCell
key={head.id + index}
className={`
${head.align === 'right'
? 'text-right'
: head.align === 'center'
? 'text-center'
: 'text-center'
}
${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''}
`}
onClick={() => handleCellClick(startIdx + index, head.id)}
>
{typeof el[head.id] === 'number'
? String(el[head.id]).replace(/\B(?=(\d{3})+(?!\d))/g, ",")
: String(el[head.id] ?? '')}
</TableCell>
))}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={headlist.length} className="p-0">
{/* ✅ 높이 보장 + 가운데 정렬용 div */}
<div className="flex justify-center items-center text-gray-500" style={{ height: `calc(${height} - 70px)` }}>
<span className="text-xl">🔍 검색 결과가 없습니다.</span>
</div>
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
</div>
{/* 페이지네이션 하단 고정 */}
{(
<div className="sticky left-0 right-0 bottom-0 bg-white z-20 mt-5">
<UiPageNations
total={total}
cur={curState}
pageSize={pageSize}
onPageChange={handlePageChange}
/>
</div>
)}
</div>
</>
);
}
@@ -1,11 +1,21 @@
"use client"
"use client";
import { Checkbox, Table, TableBody, TableCell, TableHeader, TableRow } from "@common/components";
import {
Checkbox,
Table,
TableBody,
TableCell,
TableHeader,
TableRow,
} from "@common/components";
import { useEffect, useState, useRef } from "react";
import { HeadMakeColSpan } from "./HeadMakeColSpan";
import UiPageNations from "./uiPageNations";
import { Check } from "lucide-react";
export type ChkClass = {
chk: boolean;
readonly: boolean;
};
type UiTableProps = {
headName: React.ReactNode | undefined;
tableData: { [key: string]: any }[];
@@ -20,22 +30,35 @@ type UiTableProps = {
boldArray?: number[];
resetSelection?: boolean;
index?: number;
}
};
type UiHeadProps = {
id: string;
title: string;
align?: string;
visible?: boolean;
}
};
export function UiTable({ tableData, headlist, pageSize, total, headName, children, cellClick, onPageChange, className = '', resetPageNo = false, boldArray = [], resetSelection = false, index = -1 }: UiTableProps) {
export function UiTable({
tableData,
headlist,
pageSize,
total,
headName,
children,
cellClick,
onPageChange,
className = "",
resetPageNo = false,
boldArray = [],
resetSelection = false,
index = -1,
}: UiTableProps) {
const [cur, setCur] = useState<number>(1);
const [idx, setIdx] = useState<number>(index);
const [headerHeight, setHeaderHeight] = useState<number>(0);
const headerRef = useRef<HTMLTableSectionElement>(null);
useEffect(() => {
if (resetPageNo) {
setCur(1);
@@ -51,14 +74,14 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
useEffect(() => {
if (headerRef.current) {
setHeaderHeight(headerRef.current.offsetHeight-5);
setHeaderHeight(headerRef.current.offsetHeight - 5);
}
}, [tableData, headlist]);
const handlePageChange = (page: number) => {
setCur(page);
onPageChange(page);
}
};
const handleCellClick = (index: number, headId: string) => {
if (cellClick) {
@@ -67,81 +90,158 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
}
};
return (
<>
{headName ? <div className="card-header">
<h3 className="text-2xl font-medium text-label">{headName}</h3>
</div> : <></>}
<div className={`card !m-[1.2rem] !p-0r ${className}`}>
{headName ? (
<div className="card-header">
<h3 className="text-2xl font-medium text-label">{headName}</h3>
</div>
) : (
<></>
)}
<div className={`card !p-0r !m-[1.2rem] ${className}`}>
<Table variant="secondary">
<TableHeader ref={headerRef} className="font-bold">
{children ? children : <HeadMakeColSpan upHeadList={headlist} />}
</TableHeader>
<TableBody className='text-center'>
{tableData.length > 0 ? tableData?.map((el: Record<string, unknown>, index) => (
<TableRow key={`row-${index}`}>
{headlist
.filter((item) => item.visible != false)
.map((head) => (
head.id && head.id.length > 1 && (
boldArray.includes(index)
?
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''
} !font-bold sticky bg-secondary z-40`}
style={{ top: `${headerHeight + (index * 39)}px` }}
onClick={() => handleCellClick(index, head.id)}
key={`cell-${head.id}-${index}`}
>
{typeof el[head.id] !== 'number' ? String(el[head.id] ?? '') : String(el[head.id]).includes('.')
? String(el[head.id]).split('.').map((part, index) =>
index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
).join('.')
: String(el[head.id] ?? '').replace(/\B(?=(\d{3})+(?!\d))/g, ",")}
</TableCell>
:
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''
<TableBody className="text-center">
{tableData.length > 0 ? (
tableData?.map((el: Record<string, unknown>, index) => (
<TableRow key={`row-${index}`}>
{headlist
.filter((item) => item.visible != false)
.map(
(head) =>
head.id &&
head.id.length > 1 &&
(boldArray.includes(index) ? (
<TableCell
className={`${head.align === "right" ? "text-right" : head.align === "center" ? "text-center" : "text-center"} ${
cellClick && idx === index
? "cursor-pointer !font-[1000]"
: cellClick
? "cursor-pointer"
: ""
} sticky z-40 bg-secondary !font-bold`}
style={{ top: `${headerHeight + index * 39}px` }}
onClick={() => handleCellClick(index, head.id)}
key={`cell-${head.id}-${index}`}
>
{typeof el[head.id] !== "number"
? String(el[head.id] ?? "")
: String(el[head.id]).includes(".")
? String(el[head.id])
.split(".")
.map((part, index) =>
index === 0
? part.replace(
/\B(?=(\d{3})+(?!\d))/g,
",",
)
: part,
)
.join(".")
: String(el[head.id] ?? "").replace(
/\B(?=(\d{3})+(?!\d))/g,
",",
)}
</TableCell>
) : (
<TableCell
className={`${head.align === "right" ? "text-right" : head.align === "center" ? "text-center" : "text-center"} ${
cellClick && idx === index
? "cursor-pointer !font-[1000]"
: cellClick
? "cursor-pointer"
: ""
} mt-[${boldArray.length * 40}px]`}
onClick={() => handleCellClick(index, head.id)}
key={`cell-${head.id}-${index}`}
>
{typeof el[head.id] === 'boolean'
? <Checkbox
checked={el[head.id] === true}
onCheckedChange={(checked) => {
el[head.id] = checked;
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
:
typeof el[head.id] !== 'number' ?
String(el[head.id] ?? '') :
String(el[head.id]).includes('.')
? String(el[head.id]).split('.').map((part, index) =>
index === 0 ? part.replace(/\B(?=(\d{3})+(?!\d))/g, ",") : part
).join('.')
:
String(el[head.id] ?? '').replace(/\B(?=(\d{3})+(?!\d))/g, ",")}
</TableCell>
)
))}
</TableRow>
)) : (
onClick={() => handleCellClick(index, head.id)}
key={`cell-${head.id}-${index}`}
>
{
//체크박스 유형애서 readOnly가 필요한 경우를 위해서 ChkClass 를 사용해서 readOnly 처리함.
typeof el[head.id] === "object" &&
el[head.id] !== null &&
"chk" in (el[head.id] as object) &&
"readonly" in (el[head.id] as object) ? (
<Checkbox
checked={
(el[head.id] as ChkClass)?.chk === true
}
onCheckedChange={(checked) => {
{
console.log(el[head.id]);
}
if (
(el[head.id] as ChkClass).readonly == true
)
return;
(el[head.id] as ChkClass).chk =
Boolean(checked);
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
) : typeof el[head.id] === "boolean" ? (
<Checkbox
checked={el[head.id] === true}
onCheckedChange={(checked) => {
el[head.id] = checked;
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
) : typeof el[head.id] !== "number" ? (
String(el[head.id] ?? "")
) : String(el[head.id]).includes(".") ? (
String(el[head.id])
.split(".")
.map((part, index) =>
index === 0
? part.replace(
/\B(?=(\d{3})+(?!\d))/g,
",",
)
: part,
)
.join(".")
) : (
String(el[head.id] ?? "").replace(
/\B(?=(\d{3})+(?!\d))/g,
",",
)
)
}
</TableCell>
)),
)}
</TableRow>
))
) : (
<TableRow>
<TableCell colSpan={headlist.filter((item) => item.visible != false).length} className="h-24 text-center text-gray-500">
<TableCell
colSpan={
headlist.filter((item) => item.visible != false).length
}
className="h-24 text-center text-gray-500"
>
조회된 결과가 없습니다.
</TableCell>
</TableRow>
)}
</TableBody>
</Table>
{total <= 0 ? <></> : <UiPageNations total={total} cur={cur} pageSize={pageSize} onPageChange={handlePageChange} />}
{total <= 0 ? (
<></>
) : (
<UiPageNations
total={total}
cur={cur}
pageSize={pageSize}
onPageChange={handlePageChange}
/>
)}
</div>
</>
);
}
}