[st] - fix: 집계06.공공하수처리시설 조회 조건 추가, 입력06.공공하수처리시설 매핑 계약기간 DatePicker 수정, 입력자 예외 제출 valuedation 수정
This commit is contained in:
@@ -69,6 +69,7 @@ function buildSearchFormValues(
|
||||
isDetail: false,
|
||||
isSummary: d.isSummary || "",
|
||||
clsfCd: initialClsfCd,
|
||||
capacityGbn: d.capacityGbn || "ALL",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -85,6 +86,7 @@ function buildSearchFormValues(
|
||||
isDetail: false,
|
||||
isSummary: d?.isSummary || "",
|
||||
clsfCd: initialClsfCd,
|
||||
capacityGbn: d?.capacityGbn || "ALL",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -362,6 +364,26 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{mergedProps.capacityGbn && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-label">구분</Label>
|
||||
<Select
|
||||
value={values.capacityGbn}
|
||||
onValueChange={(value) =>
|
||||
setValues({ ...values, capacityGbn: value })
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="w-[10rem]">
|
||||
<SelectValue placeholder="전체"></SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value='ALL'>전체</SelectItem>
|
||||
<SelectItem value='500톤이상'>500톤이상</SelectItem>
|
||||
<SelectItem value='500톤미만'>500톤미만</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
)}
|
||||
{mergedProps.isDetail && (
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-label cursor-pointer" htmlFor="isDetail">
|
||||
|
||||
@@ -311,15 +311,24 @@ export function VerificationResultDialog({
|
||||
}, [rows, loading]);
|
||||
|
||||
const handleExceptionSubmitClick = useCallback(async () => {
|
||||
if (checkedIndices.size === 0) {
|
||||
alert("작성된 예외 제출 항목이 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
const gridRows = getGridDataRef.current?.() ?? [];
|
||||
const payload: VerificationExceptionSubmitItem[] = [];
|
||||
checkedIndices.forEach((idx) => {
|
||||
for (const idx of checkedIndices) {
|
||||
const prcsOpnnExpln = String(gridRows[idx]?.prcsOpnnExpln ?? "").trim();
|
||||
if (!prcsOpnnExpln) return;
|
||||
if (!prcsOpnnExpln) {
|
||||
alert("예외 제출 사유를 작성해주세요.");
|
||||
return;
|
||||
}
|
||||
const vrfcSn = Number(rows[idx]?.vrfcSn);
|
||||
if (!Number.isFinite(vrfcSn)) return;
|
||||
if (!Number.isFinite(vrfcSn)) continue;
|
||||
payload.push({ vrfcSn, prcsOpnnExpln });
|
||||
});
|
||||
}
|
||||
|
||||
if (payload.length === 0) {
|
||||
alert("작성된 예외 제출 항목이 없습니다.");
|
||||
return;
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { CalendarIcon } from "lucide-react";
|
||||
import dayjs from "dayjs";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import {
|
||||
Button,
|
||||
Calendar,
|
||||
Dialog,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
@@ -12,8 +15,10 @@ import {
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
Input,
|
||||
InputDatePicker,
|
||||
Label,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@common/components";
|
||||
|
||||
export interface MainFacilityMappingSaveDialogValues {
|
||||
@@ -79,6 +84,95 @@ function validateContractRange(start: Date | undefined, end: Date | undefined):
|
||||
return null;
|
||||
}
|
||||
|
||||
const CONTRACT_DATE_END_MONTH = new Date(new Date().getFullYear() + 10, 11);
|
||||
|
||||
function isValidDate(date: Date | undefined) {
|
||||
if (!date) return false;
|
||||
return !Number.isNaN(date.getTime());
|
||||
}
|
||||
|
||||
/** 이 다이얼로그 전용 — 연도 드롭다운을 현재+10년까지 허용 */
|
||||
function ContractDatePicker({
|
||||
value,
|
||||
onChange,
|
||||
disabled,
|
||||
className,
|
||||
}: {
|
||||
value?: Date;
|
||||
onChange: (date: Date | undefined) => void;
|
||||
disabled?: boolean;
|
||||
className?: string;
|
||||
}) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [month, setMonth] = useState<Date | undefined>(value);
|
||||
const [displayValue, setDisplayValue] = useState<Date | undefined>(value);
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayValue(value);
|
||||
setMonth(value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<div className="relative flex gap-2">
|
||||
<Input
|
||||
type="date"
|
||||
value={displayValue ? dayjs(displayValue).format("YYYY-MM-DD") : ""}
|
||||
disabled={disabled}
|
||||
max={dayjs(CONTRACT_DATE_END_MONTH).format("YYYY-MM-DD")}
|
||||
className={`bg-background pr-10 ${className ?? ""}`}
|
||||
onChange={(e) => {
|
||||
const newDate = new Date(e.target.value);
|
||||
setDisplayValue(newDate);
|
||||
if (isValidDate(newDate)) {
|
||||
onChange(newDate);
|
||||
setMonth(newDate);
|
||||
}
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "ArrowDown") {
|
||||
e.preventDefault();
|
||||
setOpen(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="ghost"
|
||||
color="white"
|
||||
disabled={disabled}
|
||||
className="absolute right-2 top-1/2 size-7 -translate-y-1/2 rounded-[0.4rem] border-none p-0"
|
||||
>
|
||||
<CalendarIcon className="!size-full" />
|
||||
<span className="sr-only">Select date</span>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
className="w-auto overflow-hidden p-0"
|
||||
align="end"
|
||||
alignOffset={-8}
|
||||
sideOffset={10}
|
||||
>
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={value}
|
||||
captionLayout="dropdown"
|
||||
month={month}
|
||||
onMonthChange={setMonth}
|
||||
endMonth={CONTRACT_DATE_END_MONTH}
|
||||
onSelect={(newDate) => {
|
||||
onChange(newDate);
|
||||
setDisplayValue(newDate);
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export function MainFacilityMappingSaveDialog({
|
||||
open,
|
||||
onOpenChange,
|
||||
@@ -220,7 +314,7 @@ export function MainFacilityMappingSaveDialog({
|
||||
<div className="flex flex-col gap-3 sm:flex-row sm:items-end sm:gap-4">
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
||||
<Label className="text-label text-[1.2rem]">시작일</Label>
|
||||
<InputDatePicker
|
||||
<ContractDatePicker
|
||||
value={prxyCtrtStart}
|
||||
onChange={setPrxyCtrtStart}
|
||||
className="w-full"
|
||||
@@ -229,7 +323,7 @@ export function MainFacilityMappingSaveDialog({
|
||||
</div>
|
||||
<div className="flex min-w-0 flex-1 flex-col gap-2">
|
||||
<Label className="text-label text-[1.2rem]">종료일</Label>
|
||||
<InputDatePicker
|
||||
<ContractDatePicker
|
||||
value={prxyCtrtEnd}
|
||||
onChange={setPrxyCtrtEnd}
|
||||
className="w-full"
|
||||
|
||||
@@ -21,6 +21,7 @@ const PublicSewageFacilityTot = () => {
|
||||
setIsLoading(true);
|
||||
|
||||
const isSummaryEnabled = values.isSummary !== 'ALL';
|
||||
const isCapacityGbn = values.capacityGbn !== 'ALL'
|
||||
const summaryYearCnt = isSummaryEnabled ? Number(values.isSummary) : undefined;
|
||||
|
||||
const param = {
|
||||
@@ -29,6 +30,7 @@ const PublicSewageFacilityTot = () => {
|
||||
sewerBzmnCd: values.bsnmCd,
|
||||
statsYr: values.year,
|
||||
rowDataYn: values.isDetail,
|
||||
...(isCapacityGbn ? { capacityGbn: values.capacityGbn } : {}),
|
||||
summaryYn: isSummaryEnabled,
|
||||
...(isSummaryEnabled ? { summaryYearCnt } : {}),
|
||||
};
|
||||
@@ -50,7 +52,7 @@ const PublicSewageFacilityTot = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm isDetail={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" />
|
||||
<SearchForm isDetail={true} capacityGbn={true} isSummary={true} onSubmit={handleSearch} sidoSelectText="전체" />
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
|
||||
@@ -12,6 +12,7 @@ export type SearchFormValues = {
|
||||
isSummary?: string;
|
||||
/** 분류: 전체(ALL), 입력(INPT), 검증(VRFC) */
|
||||
clsfCd?: SearchFormClsfCd;
|
||||
capacityGbn?: string;
|
||||
};
|
||||
|
||||
export type SearchFormProps = {
|
||||
@@ -24,6 +25,7 @@ export type SearchFormProps = {
|
||||
/** 분류(입력/검증) 셀렉트 표시 */
|
||||
clsf?: boolean;
|
||||
userMenual?: boolean;
|
||||
capacityGbn?: boolean;
|
||||
isDetail?: boolean;
|
||||
isSummary?: boolean;
|
||||
onSubmit?: (values: SearchFormValues) => void;
|
||||
@@ -44,6 +46,7 @@ export const defaultSearchFormProps: Required<
|
||||
fctName: false,
|
||||
clsf: false,
|
||||
userMenual: false,
|
||||
capacityGbn: false,
|
||||
isDetail: false,
|
||||
isSummary: false,
|
||||
isReset: true,
|
||||
|
||||
+1
@@ -6,6 +6,7 @@ export interface SewagePipeMaintainTotalRequest {
|
||||
rowDataYn?: boolean;
|
||||
summaryYn?: boolean;
|
||||
summaryYearCnt?: number;
|
||||
capacityGbn?: string;
|
||||
}
|
||||
|
||||
export interface SewagePipeMaintainRepairTotalItem {
|
||||
|
||||
Reference in New Issue
Block a user