fix, feat:

- I/I 분석 화면 CSS 수정 (간격 통일
- I/I 분석 화면 Enter 클릭 이벤트 추가
This commit is contained in:
swcho
2025-07-29 16:09:49 +09:00
parent 484d90e84f
commit 97b0a2e5bf
5 changed files with 122 additions and 59 deletions
@@ -218,7 +218,7 @@ const BaseLayout = ({
<div className="flex items-center w-full">
{showDatePicker && ( // showDatePicker 값에 따라 DatePicker 렌더링
<>
<Label className="mr-4 w-20 text-xl text-gray-600 whitespace-nowrap">상수사용기간</Label>
<Label className="ml-2 mr-4 w-20 text-xl font-medium text-gray-600 whitespace-nowrap">상수사용기간</Label>
<DateMonthPicker
field={{
value: aplcnYmFrom || (() => { // aplcnYm이 없으면 현재 연월을 기본값으로 설정
@@ -232,10 +232,10 @@ const BaseLayout = ({
setAplcnYmFrom?.(value); // string 값을 직접 전달
}
}}
selectClass="ml-5 w-[100px]"
selectClass="ml-8 w-[100px]"
startYear={1900} // 시작 연도 설정
/>
<span className="font-semibold text-xl mx-2">~</span>
<span className="font-semibold text-xl mx-4">~</span>
<DateMonthPicker
field={{
value: aplcnYmTo || (() => { // aplcnYm이 없으면 현재 연월을 기본값으로 설정
@@ -248,7 +248,7 @@ const BaseLayout = ({
setAplcnYmTo?.(value); // string 값을 직접 전달
}
}}
selectClass="w-[100px]"
selectClass="w-[100px] mr-8"
startYear={1900} // 시작 연도 설정
/>
</>
@@ -259,21 +259,40 @@ const BaseLayout = ({
setRtnEnvPartSidoValue={(val) => setCtpvCd?.(val)}
setRtnEnvPartSigunValue={setSigungu} // 선택된 시군구 값을 받을 콜백 함수 전달
>
<SelectBox label={"하수처리장"} value={selectedSwageTreatmentPlant} selectArray={treatmentFacilityOptions} className="col-span-3" selectClass="ml-5 rounded-lg bg-white truncate" onSelectValue={(val) => onSwageTreatmentPlantChange?.(val)} selectContentClass="z-[101]" />
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-4">하수처리장</Label>
<SelectBox
label={''}
value={selectedSwageTreatmentPlant}
selectArray={treatmentFacilityOptions}
className="w-[160px]"
selectClass="rounded-lg bg-white truncate"
onSelectValue={(val) => onSwageTreatmentPlantChange?.(val)}
selectContentClass="z-[101]"
/>
{/* <SelectBox label={"하수처리구역"} value={selectedSwageProcessingZone} selectArray={processingZoneOptions} className="col-span-3" selectClass="rounded-lg bg-white truncate" onSelectValue={(val) => onSwageProcessingZoneChange?.(val)} selectContentClass="z-[101]" /> */}
</GovSidoSigunguSearchForm>
{selectBox?.searchChk ? <SearchFormRight><Button size="sm" onClick={() => selectBox.onSearchClick?.()}>조회</Button></SearchFormRight> : null}
{selectBox?.searchChk && (
<div className='flex flex-1 justify-end mr-6'>
<Button size="sm" onClick={() => selectBox.onSearchClick?.()}>조회</Button>
</div>
)}
</div>
</ListDiv>
<ListDiv>
<div className="card-header">
<h3 className="text-2xl font-medium">{titleName.firstCardTitle}</h3>
<div>
{graphBtn ? <Button className="px-4 py-2 !mr-[1.2rem] bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" onClick={isChckFile}>파일 다운로드</Button> : null}
{graphBtn && (
<Button className="px-4 py-2 !mr-[1.2rem] bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700" size="sm" onClick={isChckFile}>파일 다운로드</Button>
)}
{/* 그래프 있을 시 */}
{graphBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" onClick={isDeleteFile}>삭제</Button> : null}
{graphBtn && (
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" onClick={isDeleteFile}>삭제</Button>
)}
{/* 분석 버튼 */}
{analysisBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" onClick={onAnalysis}>{analysisBtn}</Button> : null}
{analysisBtn && (
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm" onClick={onAnalysis}>{analysisBtn}</Button>
)}
</div>
</div>
<Form {...form}>
@@ -285,19 +304,23 @@ const BaseLayout = ({
</form>
</Form>
</ListDiv>
{
children?.[1] != null ? <ListDiv>
<div className="card-header flex items-center justify-between">
{children?.[1] != null && (
<ListDiv>
<div className="card-header flex items-center">
<h3 className="text-2xl font-medium">{titleName?.secondCardTitle}</h3>
<div>
{graphBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm">파일 다운로드</Button> : null}
<div className='flex flex-1 justify-end mr-8'>
{graphBtn && (
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm">파일 다운로드</Button>
)}
{/* 그래프 있을 시 */}
{graphBtn ? <Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm">삭제</Button> : null}
{graphBtn && (
<Button className="px-4 py-2 bg-blue-600 text-white rounded-sm text-sm font-medium hover:bg-blue-700 !mr-[1.2rem]" size="sm">삭제</Button>
)}
</div>
</div>
<div className="card !m-[1.2rem]">{children?.[1]}</div>
</ListDiv> : null
}
</ListDiv>
)}
</Form>
)
}
@@ -399,7 +399,7 @@ const IrSetting = () => {
setSelectedDate(value);
}
}}
selectClass="ml-5 w-[150px]"
selectClass="ml-5 w-[225px]"
startYear={1900} // 시작 연도 설정
/>
</FormSection>
@@ -430,7 +430,7 @@ const IrSetting = () => {
setInput1(newValue);
}}
className="ml-5 h-[3.2rem] text-center text-xl w-[150px]"
className="ml-5 h-[3.2rem] text-center text-xl w-[225px]"
placeholder="예: 0.75"
/>
</FormSection>
@@ -441,7 +441,15 @@ const IrSetting = () => {
<Input
value={input2}
onChange={(e) => setInput2(e.target.value)}
className="ml-5 h-[3.2rem] text-center text-xl w-[150px]" />
className="ml-5 h-[3.2rem] text-center text-xl w-[225px]"
placeholder='세부 분석정보 입력'
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleAnalysisClick();
}
}}
/>
</FormSection>
<ListDiv>
<div className="card !m-[1.2rem]">
@@ -61,8 +61,8 @@ const defaultFormValues: FormSchemaType = {
sggCd: "",
swageTmplntCd: "",
swtrmtZoneCd: "",
rtkSource: "출처",
rdiiArea: "123", // 문자열로 기본값 설정
rtkSource: "",
rdiiArea: "", // 문자열로 기본값 설정
unitFactors: [
{ response: "Short-Term", R: "0.040", T: "0.5", K: "1" }, // 문자열로 기본값 설정
{ response: "Medium-Term", R: "0.005", T: "1", K: "2" },
@@ -78,7 +78,7 @@ const defaultFormValues: FormSchemaType = {
aplcnYm: "",
rate: "0.8", // 문자열로 기본값 설정
// rainFile: undefined,
analysisInfo: "test 분석정보",
analysisInfo: "",
date: (() => { // 현재 연월을 yyyyMM 형식으로 설정
const now = new Date();
const year = now.getFullYear();
@@ -501,7 +501,7 @@ export default function RTKForm() {
form.setValue("rate", newValue, { shouldValidate: true }); // form의 rate 필드에 설정
}}
className="h-12 text-center text-xl w-[225px] ml-5"
placeholder="예: 0.75"
placeholder="0 ~ 1 사이의 값 입력"
/>
</FormSection>
<FormSection name='date' form={form} titleNm='○ 상수사용량 적용월'>
@@ -512,17 +512,24 @@ export default function RTKForm() {
form.setValue("date", value, { shouldValidate: true }); // form의 date 필드에 직접 설정
}
}}
selectClass="ml-5 w-[200px]"
selectClass="ml-5 w-[225px]"
startYear={1900} // 시작 연도 설정
/>
</FormSection>
<FormSection name='rate' form={form} titleNm='○ 분석 정보'>
<Input {...form.register("analysisInfo")} className="h-12 text-center text-xl w-[225px] ml-5" />
<Input
{...form.register("analysisInfo")}
className="h-12 text-center text-xl w-[225px] ml-5"
placeholder='세부 분석정보 입력'
onKeyDown={(e) => {
if (e.key === 'Enter') {
e.preventDefault(); // Enter 키 기본 동작 방지
handleAnalysisClick();
}
}}
/>
</FormSection>
</div>
{/* <div className="flex justify-end mt-1">
<Button size="sm" type="submit" onClick={handleAnalysisClick}>RDII분석 실행</Button>
</div> */}
</div>
]}
</BaseLayout >
+1 -1
View File
@@ -103,7 +103,7 @@ const FileUploadForm = ({
}}
customPreview={
showPreview ? (
<div className="file-uploader-preview">
<div className="file-uploader-preview text-center">
{files && files.length > 0
? fileName
: "파일을 선택하세요."}
@@ -1,5 +1,6 @@
import React, { useEffect, useState } from 'react';
import { SelectBox } from '@common/business_components/ui/select';
import { Label } from '@radix-ui/react-label';
export type comCodeState = {
code: {
@@ -24,9 +25,9 @@ export type comCodeState = {
};
type SelectDataType = {
text: string;
val: string;
sido?: string; // 시도 코드 (선택 사항)
text: string;
val: string;
sido?: string; // 시도 코드 (선택 사항)
}
type EnvPartSelectDataType = SelectDataType & {
@@ -73,9 +74,9 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
const [allSigunOptions, setAllSigunOptions] = useState<SelectDataType[]>([]);
// 조회된 조건에 맞는 환경청 시도 시군 (SelectBox에 실제 사용될 데이터)
const [filteredEnvPartData, setFilteredEnvPartData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }]);
const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }]);
const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0', sido: '0' }]);
const [filteredEnvPartData, setFilteredEnvPartData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }]);
const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState<EnvPartSelectDataType[]>([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }]);
const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState<SelectDataType[]>([{ text: "전체", val: '0', sido: '0' }]);
// 시군구 데이터
const getSggCd = async (): Promise<SelectDataType[]> => {
@@ -93,7 +94,7 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
return sggCd;
} catch (error) {
console.error('시군구 데이터를 가져오는데 실패했습니다:', error);
return [{ val: '0', text: '전체', sido: '0' }];
return [{ val: '0', text: '전체', sido: '0' }];
}
};
@@ -112,7 +113,7 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
return cityCd;
} catch (error) {
console.error('시도 데이터를 가져오는데 실패했습니다:', error);
return [{ val: '0', text: '전체', sido: '0' }];
return [{ val: '0', text: '전체', sido: '0' }];
}
};
@@ -135,7 +136,7 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
return lclgvrnmntCd;
} catch (error) {
console.error('환경청 데이터를 가져오는데 실패했습니다:', error);
return [{ val: '0', text: '전체', adstDliStrCd: '', sido: '0' }];
return [{ val: '0', text: '전체', adstDliStrCd: '', sido: '0' }];
}
};
@@ -188,8 +189,8 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
const relevantSigunSidos = Array.from(
new Set(
allSigunOptions
.filter(sigungu => cityCodesInEnvPart.includes(sigungu.val))
.map(sigungu => sigungu.sido)
.filter(sigungu => cityCodesInEnvPart.includes(sigungu.val))
.map(sigungu => sigungu.sido)
)
);
console.log('relevantSigunTexts:', relevantSigunSidos);
@@ -210,8 +211,8 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
// relevantSidos와 relevantSigunsForSidoDerivation은 초기 빈 배열 상태를 유지합니다.
setFilteredEnvPartSidoData([
{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' },
...relevantSidos.map((item: SelectDataType) => ({ text: item.text, val: item.val, adstDliStrCd: '', sido: '0' }))
{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' },
...relevantSidos.map((item: SelectDataType) => ({ text: item.text, val: item.val, adstDliStrCd: '', sido: '0' }))
]);
setFilteredEnvPartSigunDataSelected(relevantSigunsForSidoDerivation);
@@ -246,14 +247,14 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
setEnvPartSigunValue('0'); // 시군구 "전체"로 초기화
// 부모에게도 초기화된 값 전달 (text 포함)
if (setRtnEnvPartSidoValue) {
const sidoDefault = filteredEnvPartSidoData.find(item => item.val === '0') || { val: '0', text: '전체' };
// setRtnEnvPartSidoValue(sidoDefault.val); // 이전 방식: 값만 전달
// TODO: 만약 시도 값도 객체로 전달해야 한다면 아래와 같이 수정
// setRtnEnvPartSidoValue({ val: sidoDefault.val, text: sidoDefault.text });
const sidoDefault = filteredEnvPartSidoData.find(item => item.val === '0') || { val: '0', text: '전체' };
// setRtnEnvPartSidoValue(sidoDefault.val); // 이전 방식: 값만 전달
// TODO: 만약 시도 값도 객체로 전달해야 한다면 아래와 같이 수정
// setRtnEnvPartSidoValue({ val: sidoDefault.val, text: sidoDefault.text });
}
if (setRtnEnvPartSigunValue) {
const sigunDefault = filteredEnvPartSigunData.find(item => item.val === '0') || { val: '0', text: '전체' };
setRtnEnvPartSigunValue({ val: sigunDefault.val, text: sigunDefault.text });
const sigunDefault = filteredEnvPartSigunData.find(item => item.val === '0') || { val: '0', text: '전체' };
setRtnEnvPartSigunValue({ val: sigunDefault.val, text: sigunDefault.text });
}
break;
case 'envPartSido': // 환경청별 - 시도 선택
@@ -262,8 +263,8 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
initializeCityDataByEnvPartSigun(val);
setEnvPartSigunValue('0'); // 시군구 "전체"로 초기화
if (setRtnEnvPartSigunValue) {
const sigunDefault = filteredEnvPartSigunData.find(item => item.val === '0') || { val: '0', text: '전체' };
setRtnEnvPartSigunValue({ val: sigunDefault.val, text: sigunDefault.text });
const sigunDefault = filteredEnvPartSigunData.find(item => item.val === '0') || { val: '0', text: '전체' };
setRtnEnvPartSigunValue({ val: sigunDefault.val, text: sigunDefault.text });
}
break;
case 'envPartSigun': // 환경청별 - 시군구 선택
@@ -286,11 +287,11 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
setEnvPartSigunValue('0');
// 필터링된 목록들도 초기 "전체" 또는 전체 목록으로 리셋
setFilteredEnvPartSigunData([{ text: "전체", val: '0', sido: '0' }, ...allSigunOptions]);
setFilteredEnvPartSigunData([{ text: "전체", val: '0', sido: '0' }, ...allSigunOptions]);
setFilteredEnvPartData([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }, ...allEnvPartOptions]);
setFilteredEnvPartSidoData([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }, ...allSidoOptions.map(s => ({ ...s, adstDliStrCd: '' }))]);
setFilteredEnvPartSigunData([{ text: "전체", val: '0', sido: '0' }, ...allSigunOptions]);
setFilteredEnvPartData([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }, ...allEnvPartOptions]);
setFilteredEnvPartSidoData([{ text: "전체", val: '0', adstDliStrCd: '', sido: '0' }, ...allSidoOptions.map(s => ({ ...s, adstDliStrCd: '' }))]);
setFilteredEnvPartSigunData([{ text: "전체", val: '0', sido: '0' }, ...allSigunOptions]);
setFilteredEnvPartSigunDataSelected(allSigunOptions);
@@ -316,11 +317,35 @@ function GovSidoSigunguSearchForm({ isShowPart = false, children, selectSidoData
return (
isShowPart ? (
<div className="grid grid-cols-12 gap-5 w-11/12 m-4">
<div className="flex items-center my-4">
<>
<SelectBox className="col-span-2" label={'환경청'} selectArray={filteredEnvPartData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={'rounded-lg bg-white truncate'} />
<SelectBox className="col-span-2" label={'시도'} selectArray={filteredEnvPartSidoData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')} value={envPartSidoValue} selectClass={'rounded-lg bg-white truncate'} />
<SelectBox className="col-span-2" label={'시군구'} selectArray={filteredEnvPartSigunData} onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')} value={envPartSigunValue} selectClass={'rounded-lg bg-white truncate'} />
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap ml-2 mr-4">환경청</Label>
<SelectBox
className="w-[160px] mr-8"
label={''}
selectArray={filteredEnvPartData}
onSelectValue={(val) => onSelectValue(val.toString(), 'envPart')}
value={envPartValue}
selectClass={'rounded-lg bg-white truncate'}
/>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-4">시도</Label>
<SelectBox
className="w-[160px] mr-8"
label={''}
selectArray={filteredEnvPartSidoData}
onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSido')}
value={envPartSidoValue}
selectClass={'rounded-lg bg-white truncate'}
/>
<Label className="text-xl text-gray-600 font-medium whitespace-nowrap mr-4">시군구</Label>
<SelectBox
className="w-[160px] mr-8"
label={''}
selectArray={filteredEnvPartSigunData}
onSelectValue={(val) => onSelectValue(val.toString(), 'envPartSigun')}
value={envPartSigunValue}
selectClass={'rounded-lg bg-white truncate'}
/>
</>
{children}
</div>