Merge commit 'cce216ad9bac561a711d8f40a98b130fbf672d48' into iipbs/wr/dev
iipbs_wr / build (push) Waiting to run
iipbs_wr / build (push) Waiting to run
This commit is contained in:
@@ -74,17 +74,25 @@ const CustomLegend = (props: any) => {
|
||||
);
|
||||
};
|
||||
|
||||
// chartData의 모든 값 중 최대값 구하기
|
||||
const getGlobalMax = (data: Record<string, number>[]) => {
|
||||
if (!data || data.length === 0) return 0;
|
||||
return Math.max(
|
||||
...data.flatMap(item =>
|
||||
Object.entries(item)
|
||||
.filter(([key]) => key !== 'label')
|
||||
.map(([, value]) => value as 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 getMaxValue = (data: any[], keyPrefix: string) => {
|
||||
return Math.max(...data.map(item =>
|
||||
Object.keys(item)
|
||||
.filter(key => key.includes(keyPrefix))
|
||||
.map(key => item[key])
|
||||
).flat());
|
||||
};
|
||||
|
||||
const barMaxValue = getMaxValue(chartData, 'barVal');
|
||||
const globalMax = getGlobalMax(chartData);
|
||||
const tickCount = 5;
|
||||
// interval을 globalMax / tickCount로 계산
|
||||
const interval = globalMax / tickCount;
|
||||
const ticks = Array.from({ length: tickCount + 1 }, (_, i) => Math.round(interval * i));
|
||||
return (
|
||||
<>
|
||||
{chartTitle && chartTitle !== "" && chartTitle !== "undefined" ? (
|
||||
@@ -93,8 +101,8 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle='
|
||||
</div>): null}
|
||||
<div className="flex justify-center">
|
||||
<ChartContainer config={chartConfig ?? {}} className={chartClassName + " !w-[90%]"}>
|
||||
<BarChart accessibilityLayer data={chartData}>
|
||||
<CartesianGrid vertical={false} />
|
||||
<BarChart accessibilityLayer data={chartData} className="!h-[88%]">
|
||||
<CartesianGrid vertical={false} className="!h-[85%]" />
|
||||
<XAxis
|
||||
dataKey="label"
|
||||
tickLine={true}
|
||||
@@ -106,12 +114,12 @@ export default function Chart({chartConfig=undefined, chartData=[], chartTitle='
|
||||
<YAxis
|
||||
tickLine={true}
|
||||
tickMargin={10}
|
||||
tickCount={6}
|
||||
axisLine={true}
|
||||
fontSize={12}
|
||||
fontWeight={500}
|
||||
domain={[0, Math.ceil(barMaxValue * 1)]}
|
||||
label={yFieldText ? { value: yFieldText, className:"text-[13px] font-bold", position: 'insideLeft', angle: -90, offset: 20 } : undefined}
|
||||
domain={[0, globalMax]}
|
||||
ticks={ticks}
|
||||
label={yFieldText ? { value: yFieldText, className:"text-[15px] font-bold", position: 'insideLeft', angle: -90, offset: -30 } : undefined}
|
||||
/>
|
||||
<ChartTooltip cursor={false} content={<CustomTooltip active={undefined} payload={undefined} label={undefined} />}/>
|
||||
{chartData && chartData.length > 0 && (
|
||||
|
||||
@@ -6,62 +6,100 @@ import { format } from "date-fns";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import type { DayPickerSingleProps } from "react-day-picker";
|
||||
|
||||
import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from "@common/components/ui";
|
||||
import {
|
||||
Button,
|
||||
Calendar,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@common/components/ui";
|
||||
import { cn } from "../../lib/utils";
|
||||
import { FormControl } from "../form";
|
||||
import { ko } from "date-fns/locale";
|
||||
import { useState } from "react";
|
||||
|
||||
type DatePickerProps = DayPickerSingleProps & { field: { value: Date; onChange: (date: Date | undefined) => void }, selectClass: string | undefined, readOnly?: boolean };
|
||||
type DatePickerProps = DayPickerSingleProps & {
|
||||
field: { value: Date; onChange: (date: Date | undefined) => void };
|
||||
selectClass: string | undefined;
|
||||
readOnly?: boolean;
|
||||
};
|
||||
|
||||
export function DatePicker({
|
||||
field,
|
||||
selectClass,
|
||||
readOnly = false,
|
||||
...props
|
||||
}: DatePickerProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
export function DatePicker({ field, selectClass, readOnly = false, ...props }: DatePickerProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleSelect = (date: Date | undefined) => {
|
||||
if (!readOnly) {
|
||||
// readOnly가 아닐 때만 변경 허용
|
||||
field.onChange(date); // React Hook Form 업데이트
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelect = (date: Date | undefined) => {
|
||||
if (!readOnly) { // readOnly가 아닐 때만 변경 허용
|
||||
field.onChange(date); // React Hook Form 업데이트
|
||||
setOpen(false);
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Popover
|
||||
open={open && !readOnly}
|
||||
onOpenChange={readOnly ? undefined : setOpen}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
color="white"
|
||||
variant={"outline"}
|
||||
className={
|
||||
!selectClass
|
||||
? cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field?.value && "text-muted-foreground",
|
||||
|
||||
return (
|
||||
<Popover open={open && !readOnly} onOpenChange={readOnly ? undefined : setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<FormControl>
|
||||
<Button
|
||||
color="white"
|
||||
variant={"outline"}
|
||||
disabled={readOnly} // readOnly일 때 버튼 비활성화
|
||||
className={!selectClass ? cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field?.value && "text-muted-foreground",
|
||||
readOnly && "opacity-60 cursor-not-allowed" // readOnly 스타일 추가
|
||||
) : cn(selectClass, readOnly && "opacity-60 cursor-not-allowed")}
|
||||
>
|
||||
{field?.value ? (
|
||||
format(
|
||||
field.value instanceof Date && !isNaN(field.value.getTime())
|
||||
? field.value
|
||||
: new Date()
|
||||
//감리 지적사항으로 삭제 예정 리드온리는 리드온리 로만 보일수 있도록 수정
|
||||
// disabled={readOnly} // readOnly일 때 버튼 비활성화
|
||||
//readOnly && "opacity-60 cursor-not-allowed" 감리 지적사항으로
|
||||
)
|
||||
: cn(
|
||||
selectClass,
|
||||
// , readOnly && "opacity-60 cursor-not-allowed"
|
||||
)
|
||||
}
|
||||
>
|
||||
{field?.value ? (
|
||||
format(
|
||||
field.value instanceof Date && !isNaN(field.value.getTime())
|
||||
? field.value
|
||||
: new Date(),
|
||||
|
||||
, "PPP", { locale: ko })
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="h-4" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field?.value}
|
||||
onSelect={handleSelect}
|
||||
initialFocus
|
||||
locale={ko}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
"PPP",
|
||||
{ locale: ko },
|
||||
)
|
||||
) : (
|
||||
<span>날짜를 선택해주세요 </span>
|
||||
)}
|
||||
<CalendarIcon className="h-4" />
|
||||
</Button>
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
className="w-full"
|
||||
|
||||
//-- 데이트 피커가 드롭박스 형태로 년월을 선택할수 있도록 하는 Props 로 활성화 되면 드롭박스로 선택
|
||||
|
||||
// captionLayout="dropdown-buttons"
|
||||
// fromYear={2000}
|
||||
// toYear={new Date().getFullYear()}
|
||||
toDate={new Date()} // 금일까지만 표시됨 (금일 이후는 안보임)
|
||||
showOutsideDays={false} // 금월 까지만 표출되도록
|
||||
mode="single"
|
||||
selected={field?.value}
|
||||
onSelect={handleSelect}
|
||||
initialFocus
|
||||
locale={ko}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import "../date_picker/date-picker.css";
|
||||
|
||||
import { format } from "date-fns";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import type { DayPickerSingleProps } from "react-day-picker";
|
||||
|
||||
import { cn } from "../../lib/utils";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { Calendar } from "@common/components/ui";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "@common/components/ui";
|
||||
|
||||
type DatePickerRangeProps = {
|
||||
placeholder?: string;
|
||||
disabled?: boolean | ((date: Date) => boolean);
|
||||
} & DayPickerSingleProps;
|
||||
|
||||
export function DatePickerRange({
|
||||
className,
|
||||
placeholder = "날짜 선택",
|
||||
disabled,
|
||||
...props
|
||||
}: DatePickerRangeProps) {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
className={cn("date-picker-trigger", className)}
|
||||
disabled={typeof disabled === "boolean" ? disabled : false}
|
||||
>
|
||||
<CalendarIcon className="!size-[1.6rem]" />
|
||||
{props.selected ? (
|
||||
format(props.selected, "yyyy-MM-dd")
|
||||
) : (
|
||||
<span>{placeholder}</span>
|
||||
)}
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0">
|
||||
<Calendar initialFocus classNames={{ cell: "rounded-md" }} {...props}
|
||||
disabled={typeof disabled === "function" ? disabled : undefined}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
@@ -21,4 +21,5 @@ export * from "./table_div";
|
||||
export * from "./title";
|
||||
export * from "./sdmInsertForm";
|
||||
export * from "./popover_ui";
|
||||
export * from "./date_month_picker";
|
||||
export * from "./date_month_picker";
|
||||
export * from "./date_picker_range"
|
||||
@@ -301,7 +301,7 @@ function SearchFormLeft({ isShowPart = false, children, selectSidoData = [], sel
|
||||
resetAllValues();
|
||||
// 리셋 후 트리거를 false로 설정
|
||||
if (setRtnPartValue) {
|
||||
setRtnPartValue('0');
|
||||
setRtnPartValue('A');
|
||||
}
|
||||
}
|
||||
}, [resetTrigger]);
|
||||
|
||||
@@ -1,57 +1,103 @@
|
||||
// selectBox
|
||||
|
||||
import { Label } from "@common/components";
|
||||
import React from "react";
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./lib/selectBox";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "./lib/selectBox";
|
||||
|
||||
/** 차트 기본 스타일 */
|
||||
interface SelectBox1 {
|
||||
text:string,
|
||||
val:string|number,
|
||||
hidden?: boolean
|
||||
text: string;
|
||||
val: string | number;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
const SelectBox = React.forwardRef<
|
||||
HTMLDivElement,
|
||||
React.HTMLAttributes<HTMLDivElement> & {
|
||||
label:string,
|
||||
selectClass:string|undefined,
|
||||
className:string,
|
||||
selectArray:SelectBox1[],
|
||||
onSelectValue:(val:string|number)=>void,
|
||||
value?: string|number,
|
||||
readOnly?: boolean // readOnly 속성 추가
|
||||
label: string;
|
||||
selectClass: string | undefined;
|
||||
className: string;
|
||||
selectArray: SelectBox1[];
|
||||
onSelectValue: (val: string | number) => void;
|
||||
value?: string | number;
|
||||
readOnly?: boolean; // readOnly 속성 추가
|
||||
}
|
||||
>(({ label, className, selectClass, selectArray, onSelectValue, value, readOnly = false }, ref)=>{
|
||||
// hidden이 true인 첫 번째 항목을 placeholder로 사용
|
||||
const hiddenItem = selectArray.find(item => item.hidden);
|
||||
const placeHolder = hiddenItem?.text ?? "선택";
|
||||
|
||||
// hidden이 true인 항목만 드롭다운에서 제외
|
||||
const visibleItems = selectArray.filter(item => !item.hidden);
|
||||
>(
|
||||
(
|
||||
{
|
||||
label,
|
||||
className,
|
||||
selectClass,
|
||||
selectArray,
|
||||
onSelectValue,
|
||||
value,
|
||||
readOnly = false,
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
// hidden이 true인 첫 번째 항목을 placeholder로 사용
|
||||
const hiddenItem = selectArray.find((item) => item.hidden);
|
||||
const placeHolder = hiddenItem?.text ?? "선택";
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
// hidden이 true인 항목만 드롭다운에서 제외
|
||||
const visibleItems = selectArray.filter((item) => !item.hidden);
|
||||
|
||||
// 현재 값이 hidden 항목이거나 빈 값인 경우 undefined로 설정하여 placeholder가 표시되도록 함
|
||||
const currentValue = value !== undefined &&
|
||||
hiddenItem &&
|
||||
(String(value) === String(hiddenItem.val) || value === "" || value === "0" || value === 0)
|
||||
? undefined
|
||||
: (value !== undefined ? String(value) : undefined);
|
||||
// 현재 값이 hidden 항목이거나 빈 값인 경우 undefined로 설정하여 placeholder가 표시되도록 함
|
||||
const currentValue =
|
||||
value !== undefined &&
|
||||
hiddenItem &&
|
||||
(String(value) === String(hiddenItem.val) ||
|
||||
value === "" ||
|
||||
value === "0" ||
|
||||
value === 0)
|
||||
? undefined
|
||||
: value !== undefined
|
||||
? String(value)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<div className={className+" flex items-center"} ref={ref}>
|
||||
{label && <Label className="whitespace-nowrap w-20 text-xl text-gray-600">{label}</Label>}
|
||||
<Select onValueChange={onSelectValue} value={currentValue} disabled={readOnly}>
|
||||
<SelectTrigger className={selectClass?selectClass:"flex-1 p-2 border rounded"}>
|
||||
<SelectValue placeholder={placeHolder} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{visibleItems.map((selectArray) => (
|
||||
<SelectItem key={selectArray.val} value={String(selectArray.val)}>{selectArray.text}</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div className={className + " flex items-center"} ref={ref}>
|
||||
{label && (
|
||||
<Label className="w-20 whitespace-nowrap text-xl text-gray-600">
|
||||
{label}
|
||||
</Label>
|
||||
)}
|
||||
<Select
|
||||
open={isOpen}
|
||||
onOpenChange={(open) => {
|
||||
if (readOnly === true) {
|
||||
// readOnly 일경우 Select 선택안하게 하기
|
||||
setIsOpen(false);
|
||||
} else {
|
||||
setIsOpen(open);
|
||||
}
|
||||
}}
|
||||
onValueChange={onSelectValue}
|
||||
value={currentValue}
|
||||
// disabled={readOnly} //물재이용 감리 지적사항으로 일단 주석처리
|
||||
>
|
||||
<SelectTrigger
|
||||
className={selectClass ? selectClass : "flex-1 rounded border p-2"}
|
||||
>
|
||||
<SelectValue placeholder={placeHolder} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{visibleItems.map((selectArray) => (
|
||||
<SelectItem key={selectArray.val} value={String(selectArray.val)}>
|
||||
{selectArray.text}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export { SelectBox };
|
||||
|
||||
Reference in New Issue
Block a user