Merge commit 'da1795a519302df3f99ecf8273c15b72e5adf673' into iipbs/wr/form_fuction

This commit is contained in:
jyha00
2025-07-03 16:36:01 +09:00
8 changed files with 218 additions and 38 deletions
@@ -7,6 +7,7 @@ import {
} from "./lib/chart";
import type { CSSProperties } from "react";
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -17,6 +18,22 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
gap: "12px",
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px",
} as CSSProperties,
};
type BarChartProps = {
chartConfig: ChartConfig | undefined;
@@ -60,7 +77,7 @@ const CustomTooltip = ({
};
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
const CustomLegend = (props: any) => {
/*const CustomLegend = (props: any) => {
const { payload } = props;
return (
<div style={customStyles.legendContainer}>
@@ -72,6 +89,38 @@ const CustomLegend = (props: any) => {
))}
</div>
);
};*/
const CustomLegend = (props: any) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: any, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.color,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span>
</div>
))}
</div>
);
};
export default function DoubleBarChart({chartConfig=undefined, chartData=[], chartTitle='차트', chartClassName='w-full h-full', graphSize=40, yFieldText='', showLegend=false} : BarChartProps) {
@@ -83,7 +132,7 @@ export default function DoubleBarChart({chartConfig=undefined, chartData=[], cha
.map(key => item[key])
).flat());
};
console.log(chartData);
const barMaxValue = getMaxValue(chartData, 'barVal');
return (
<>
@@ -48,6 +48,7 @@ type LegendProps = {
};
/** 차트 기본 스타일 */
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -58,6 +59,23 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
/** 차트 기본 스타일 (라인차트와 동일하게) */
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap", // 여러 줄로 자동 줄바꿈
justifyContent: "center",
alignItems: "center",
gap: "12px", // 아이템 간 간격
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px", // 범례 영역 높이 통일
} as CSSProperties,
};
// 커스텀 툴팁
const CustomTooltip = ({ active, payload, label }: {
@@ -82,6 +100,7 @@ const CustomTooltip = ({ active, payload, label }: {
};
// 커스텀 범례
/*
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
@@ -97,12 +116,52 @@ const CustomLegend = (props: LegendProps) => {
</div>
);
};
*/
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: LegendEntry, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.fill,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>
{entry.payload?.label || entry.value}
</span>
</div>
))}
</div>
);
};
export default function DoughnutChart(props: {
chartConfig: any;
chartData: ChartDataItem[] | undefined;
chartTitle: string
}) {
const legendData = props.chartData?.map(item => ({
value: item.label,
fill: props.chartConfig?.[item.label]?.fill || 'blue',
})) ?? [];
return (
<Card className="flex flex-col">
<CardContent className="flex-1 pb-0">
@@ -130,9 +189,9 @@ export default function DoughnutChart(props: {
nameKey="label"
innerRadius={60}
/>
<CustomLegend />
</PieChart>
</ChartContainer>
<CustomLegend payload={legendData} />
</div>
</CardContent>
</Card>
@@ -18,6 +18,7 @@ type LineChartProps = {
}
/** 차트 기본 스타일 */
/*
const customStyles = {
legendContainer: {
display: "flex",
@@ -28,6 +29,23 @@ const customStyles = {
marginTop: "10px",
} as CSSProperties,
};
*/
/** 차트 기본 스타일 */
const customStyles = {
legendContainer: {
display: "flex",
flexWrap: "wrap",
justifyContent: "center",
alignItems: "center",
gap: "12px",
fontSize: "13px",
fontWeight: "normal",
marginTop: "16px",
marginBottom: "8px",
minHeight: "32px",
} as CSSProperties,
};
type LegendEntry = {
value: string;
@@ -60,7 +78,7 @@ const CustomTooltip = ({ active, payload, label }: { active?: boolean; payload?:
};
// 커스텀 범례 (글씨 크기 키우기 + 스타일 추가)
const CustomLegend = (props: LegendProps) => {
/*const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
@@ -74,6 +92,40 @@ const CustomLegend = (props: LegendProps) => {
))}
</div>
);
};*/
// 커스텀 범례 (도넛차트와 동일하게)
const CustomLegend = (props: LegendProps) => {
const { payload } = props;
if (!payload) return null;
return (
<div style={customStyles.legendContainer}>
{payload.map((entry: LegendEntry, index: number) => (
<div
key={`legend-${index}`}
className="flex items-center"
style={{
minWidth: "90px",
margin: "2px 0",
}}
>
<div
style={{
width: "14px",
height: "14px",
backgroundColor: entry.color,
borderRadius: "3px",
marginRight: "8px",
minWidth: "14px",
minHeight: "14px",
}}
></div>
<span style={{ fontSize: "13px", whiteSpace: "nowrap" }}>{entry.value}</span>
</div>
))}
</div>
);
};
type DataType = {label: string; val: string};
@@ -1,7 +1,7 @@
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader } from "@common/components";
import { cn } from "../../lib/utils";
type ModalType = {
type ModalType = {
bodyClass: string;
body: React.ReactNode;
open?: boolean;
@@ -10,43 +10,45 @@ type ModalType = {
noFooterYn?: 'N' | 'Y';
headerTitle?: string;
footerContent?: React.ReactNode;
useDirectRender?: boolean;
}
export function UiModal({
bodyClass,
body,
open,
export function UiModal({
bodyClass,
body,
open,
onOpenChange,
noHeaderYn = 'N',
noFooterYn = 'N',
headerTitle,
footerContent
footerContent,
useDirectRender = false
}: ModalType) {
return (
<>
<Dialog open={open} onOpenChange={onOpenChange}>
<Dialog open={open} onOpenChange={onOpenChange}>
<DialogContent className={bodyClass}>
{noHeaderYn === 'N' && (
<DialogHeader>
<DialogDescription>
{headerTitle}
</DialogDescription>
</DialogHeader>
)}
{(open && body) ?
<div> {body}</div>:<></>
}
{noFooterYn === 'N' && (
<DialogFooter className="sm:justify-start">
{footerContent}
</DialogFooter>
)}
</DialogContent>
</Dialog>
{noHeaderYn === 'N' && (
<DialogHeader>
<DialogDescription>
{headerTitle}
</DialogDescription>
</DialogHeader>
)}
{(open && body) ?
useDirectRender
? body
: <div>{body}</div>
: <></>
}
{noFooterYn === 'N' && (
<DialogFooter className="sm:justify-start">
{footerContent}
</DialogFooter>
)}
</DialogContent>
</Dialog>
</>
);
}
@@ -0,0 +1,20 @@
import React from 'react';
import { LoadingWithAnimation } from '@common/components/ui/loading';
interface LoadingOverlayProps {
isLoading: boolean;
}
const LoadingOverlay: React.FC<LoadingOverlayProps> = ({ isLoading }) => {
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">
<LoadingWithAnimation color="primary" />
</div>
</div>
);
};
export default LoadingOverlay;
@@ -301,7 +301,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
resetAllValues();
// 리셋 후 트리거를 false로 설정
if (setRtnPartValue) {
setRtnPartValue('0');
setRtnPartValue('A');
}
}
}, [resetTrigger]);
@@ -110,9 +110,7 @@ export function UiTable2({
? 'text-right'
: head.align === 'center'
? 'text-center'
: typeof el[head.id] === 'number'
? 'text-right'
: 'text-center'
: 'text-center'
}
${cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''}
@@ -82,7 +82,7 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
boldArray.includes(index)
?
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${
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`}
@@ -97,7 +97,7 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr
</TableCell>
:
<TableCell
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : typeof el[head.id] === 'number' ? 'text-right' : 'text-center'} ${
className={`${head.align === 'right' ? 'text-right' : head.align === 'center' ? 'text-center' : 'text-center'} ${
cellClick && idx === index ? '!font-[1000] cursor-pointer' :
cellClick ? 'cursor-pointer' : ''
}`}