Merge commit 'c22e07bc16afbc2888806b4e0d36606b8ea0d35f' into iipbs/wr/dev
This commit is contained in:
@@ -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로 계산
|
||||
|
||||
@@ -53,12 +53,37 @@ const customStyles = {
|
||||
minHeight: "32px", // 범례 영역 높이 통일
|
||||
} 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,10 +104,10 @@ export function DatePicker({
|
||||
className="w-full"
|
||||
|
||||
//-- 데이트 피커가 드롭박스 형태로 년월을 선택할수 있도록 하는 Props 로 활성화 되면 드롭박스로 선택
|
||||
|
||||
// captionLayout="dropdown-buttons"
|
||||
// fromYear={2000}
|
||||
// toYear={new Date().getFullYear()}
|
||||
|
||||
// captionLayout="dropdown-buttons"
|
||||
// fromYear={2000}
|
||||
// toYear={new Date().getFullYear()}
|
||||
toDate={new Date()} // 금일까지만 표시됨 (금일 이후는 안보임)
|
||||
showOutsideDays={false} // 금월 까지만 표출되도록
|
||||
mode="single"
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -49,12 +49,6 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
|
||||
}
|
||||
}, [resetSelection]);
|
||||
|
||||
// 테이블 데이터가 변경될 때마다 선택된 행 초기화하는 useEffect 추가
|
||||
useEffect(() => {
|
||||
// 새로운 데이터가 로드되면 선택 상태 초기화
|
||||
setIdx(-1);
|
||||
}, [tableData]);
|
||||
|
||||
useEffect(() => {
|
||||
if (headerRef.current) {
|
||||
setHeaderHeight(headerRef.current.offsetHeight-5);
|
||||
|
||||
Reference in New Issue
Block a user