From 164fc1388e73a26a670c183f9ef097b16d79c5f6 Mon Sep 17 00:00:00 2001 From: ljpark Date: Fri, 30 Jan 2026 16:22:51 +0900 Subject: [PATCH] =?UTF-8?q?fo:=20=EA=B0=95=EC=9A=B0=EC=8B=9C=20=EA=B0=95?= =?UTF-8?q?=EC=9A=B0=EC=9D=BC=EC=9D=98=20=EA=B0=95=EC=9A=B0=EB=9F=89?= =?UTF-8?q?=EC=97=90=20=EC=9D=8C=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/components/common/CalcRainEffect.tsx | 12 +-- .../(with-layout)/flowRate/modal/page.tsx | 32 +++++-- apps/fo/app/store/facilityWaterQlty/index.tsx | 28 +++--- apps/fo/app/store/underWaterInput/index.tsx | 10 +- .../src/ui/table/index.tsx | 92 ++++++++++--------- 5 files changed, 104 insertions(+), 70 deletions(-) diff --git a/apps/fo/app/components/common/CalcRainEffect.tsx b/apps/fo/app/components/common/CalcRainEffect.tsx index 3ea198016..898bea0ba 100644 --- a/apps/fo/app/components/common/CalcRainEffect.tsx +++ b/apps/fo/app/components/common/CalcRainEffect.tsx @@ -30,18 +30,18 @@ export default function CalcRainEffect(data: any, weather = 'ALL') { rtnDataSunny.push(item); } else if (rainEffectStd >= 0) { // 강우일 + 강우영향일 item.rainEffectDay = 1; - if (idx > 1) { - // 전날 비가 왔고 오늘 강우량 3미만인 경우 전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전날 강우량으로 설정 - if (data[idx - 1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx - 1]?.infoRnDay.toString().trim()) >= 3) { - data[idx]!.toBeInfoRnDay = data[idx - 1]!.infoRnDay; - } - } if (idx > 2) { // 전전날 비가 왔고 오늘 강우량 3미만인 경우 전전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전전날 강우량으로 설정 if (data[idx - 2]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx - 2]?.infoRnDay.toString().trim()) >= 3) { data[idx]!.toBeInfoRnDay = data[idx - 2]!.infoRnDay; } } + if (idx > 1) { + // 전날 비가 왔고 오늘 강우량 3미만인 경우 전날 강우량이 3이상이면 오늘 toBeInfoRnDay을 전날 강우량으로 설정 + if (data[idx - 1]?.infoRnDay && Number(data[idx]?.infoRnDay) < 3 && Number(data[idx - 1]?.infoRnDay.toString().trim()) >= 3) { + data[idx]!.toBeInfoRnDay = data[idx - 1]!.infoRnDay; + } + } rtnDataRain.push(item); } diff --git a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx index 4e0fffeb5..c92fb4325 100644 --- a/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx +++ b/apps/fo/app/pages/(with-layout)/flowRate/modal/page.tsx @@ -34,6 +34,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st const { btnClass } = Common; const [copyYearList, setCopyYearList] = useState([]); const [isLoading, setIsLoading] = useState(true); + const [activeTab, setActiveTab] = useState("tab_term_year"); const prevExcelListRef = useRef(null); const { modalFlowRateListYear, upHeadListFlowRateModalYear, } = FlowRateModal; @@ -183,10 +184,6 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st fetchData(); }, [props.facilityCd, props.searchYear, searchFlowRateModalList]); - if (isLoading) { - return
로딩 중...
; - } - const excelDownload = () => { const excelDownList: modalExcelType[] = []; if (copyYearList.length > 0) { @@ -206,14 +203,32 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st if (excelDownList && excelDownList.length > 0) { downloadExcel({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.searchYear + '년 ' + props.fcltyName + ' 유량현황', sheetNameArray: [props.fcltyName + ' 유량현황'], headerRange: 'A1:H1' }); } else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) { - alert('다운받을 데이터가 없습니다.'); + alert('조회된 결과가 없습니다.'); } prevExcelListRef.current = excelDownList; } + const rainCellClassName = useCallback( + (row: FlowRateModalInterface, headId: string, rowIndex: number) => { + if (activeTab !== "tab_term_rain") return ""; + if (headId !== "infoRnDay") return ""; + if (rowIndex < 3) return ""; + + const raw = row.infoRnDay; + const value = typeof raw === "string" ? Number(raw.replace(/,/g, "").trim()) : Number(raw); + if (!Number.isFinite(value)) return ""; + return value > 3 ? "bg-red-50 font-semibold" : ""; + }, + [activeTab], + ); + + if (isLoading) { + return
로딩 중...
; + } + return ( <> - + @@ -337,7 +352,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st />
{ }} className="h-[370px]" boldArray={[0, 1, 2]} /> + cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} + cellClassName={rainCellClassName} />
@@ -346,4 +362,4 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st ); -} \ No newline at end of file +} diff --git a/apps/fo/app/store/facilityWaterQlty/index.tsx b/apps/fo/app/store/facilityWaterQlty/index.tsx index 1a3508597..676c0624c 100644 --- a/apps/fo/app/store/facilityWaterQlty/index.tsx +++ b/apps/fo/app/store/facilityWaterQlty/index.tsx @@ -28,9 +28,11 @@ export interface FacilityRdiiDetailProps { export interface FacilityWaterQltyProps { bscFctCd: string, bscFctNm: string, - msrDt: string - sidoNm: string, - sggNm: string, + msrDt: string, + sido: string, + gugun: string, + // sidoNm: string, + // sggNm: string, addr: string, fctCpc: number, inflAssctBfrWqltBod: string | '', @@ -147,8 +149,8 @@ const mainLabelArray: string[] = ['구분', '시도', '시군구', '용량별', // 시설수질리스트 헤더(행정별) const upHeadList1: TableUpperProps[] = [ { id: "C", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, - { id: "sidoNm", title: "시도", row: 1, widthPercent: 5 }, - { id: "sggNm", title: "시군구", row: 1, widthPercent: 5 }, + { id: "sido", title: "시도", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", rowSpan: 2, row: 0, widthPercent: 10 }, { id: "addr", title: "주소", rowSpan: 2, row: 0 }, { id: "fctCpc", title: "시설용량(m³/일)", align: "right", rowSpan: 2, row: 0, widthPercent: 10 }, @@ -197,8 +199,8 @@ const upHeadList3: TableUpperProps[] = [ { id: "mdmbsn", title: "중권역", row: 1, widthPercent: 5 }, { id: "rgnNm", title: "환경청", row: 0, rowSpan: 2, widthPercent: 7 }, { id: "D", title: "행정명", colSpan: 2, row: 0, widthPercent: 10 }, - { id: "sidoNm", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, - { id: "sggNm", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "sido", title: "시도", upName: "upChangeRe2", row: 1, widthPercent: 5 }, + { id: "gugun", title: "시군구", upName: "upChangeRe2", row: 1, widthPercent: 5 }, { id: "bscFctNm", title: "시설명", row: 0, rowSpan: 2, widthPercent: 8 }, { id: "addr", title: "주소", row: 0, rowSpan: 2 }, { id: "fctCpc", title: "시설용량(m³/L)", align: "right", row: 0, rowSpan: 2, widthPercent: 5 }, @@ -533,8 +535,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions waterQltyList.forEach(item => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + // item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; + // item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; excelDownList.push({ @@ -543,8 +545,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions 단위유역: item.lgbsn, 중권역: item.mdmbsn, 환경청: item.rgnNm, - 시도: item.sidoNm, - 시군구: item.sggNm, + 시도: item.sido, + 시군구: item.gugun, 시설이름: item.bscFctNm, 주소: item.addr, "시설용량(m³/일)": CommaToNumber(item.fctCpc), @@ -565,8 +567,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions waterQltyList.forEach((item: FacilityWaterQltyProps) => { dataFormSetting(item) item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, '')); - item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || ''; - item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; + // item.sidoNm = item.; + // item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || ''; item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc; item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc; }); diff --git a/apps/fo/app/store/underWaterInput/index.tsx b/apps/fo/app/store/underWaterInput/index.tsx index d4d4c39e2..806b12e2b 100644 --- a/apps/fo/app/store/underWaterInput/index.tsx +++ b/apps/fo/app/store/underWaterInput/index.tsx @@ -317,6 +317,14 @@ export type UnderWaterStore = UnderWaterType & UnderWaterActions; export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => UnderWaterActions = (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => { return { searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => { + set((state: UnderWaterType) => ({ + ...state, + UnderWater: { + ...state.UnderWater, + isLoading: true, + }, + })); + const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm); if (pageSize < 5000) { @@ -724,4 +732,4 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater })) } } -} \ No newline at end of file +} diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index 1a0fc57c0..94c86d2d8 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -16,14 +16,15 @@ export type ChkClass = { chk: boolean; readonly: boolean; }; -type UiTableProps = { +type UiTableProps = { headName: React.ReactNode | undefined; - tableData: { [key: string]: any }[]; + tableData: T[]; headlist: UiHeadProps[]; pageSize: number; total: number; cellClick: ((index: number | undefined, headId: string) => void) | undefined; onPageChange: (page: number) => void; + cellClassName?: (row: T, headId: string, rowIndex: number) => string; className?: string; resetPageNo?: boolean; children?: React.ReactNode | undefined; @@ -46,7 +47,7 @@ type UiHeadProps = { colSpan?: number; }; -export function UiTable({ +export function UiTable>({ tableData, headlist, pageSize, @@ -55,6 +56,7 @@ export function UiTable({ children, cellClick, onPageChange, + cellClassName, className = "", resetPageNo = false, boldArray = [], @@ -63,7 +65,7 @@ export function UiTable({ curPage = 1, headButton = undefined, widthFixed = false -}: UiTableProps) { +}: UiTableProps) { const [cur, setCur] = useState(curPage); const [idx, setIdx] = useState(index); const [headerHeight, setHeaderHeight] = useState(0); @@ -148,7 +150,7 @@ export function UiTable({ {tableData.length > 0 ? ( - tableData?.map((el: Record, index) => ( + tableData?.map((el: T, index) => ( {headlist .filter((item) => item.visible != false) @@ -163,29 +165,32 @@ export function UiTable({ : cellClick ? "cursor-pointer" : "" - } sticky top-20 z-40 bg-secondary !font-bold whitespace-pre-line`} + } ${cellClassName ? cellClassName(el, head.id, index) : ""} sticky top-20 z-40 bg-secondary !font-bold whitespace-pre-line`} style={{ top: `${headerHeight + index * 32 - 4}px` }} onClick={() => handleCellClick(index, head.id)} key={`cell-${head.id}-${index}`} > - {typeof el[head.id] !== "number" - ? String(el[head.id] ?? "") - : String(el[head.id]).includes(".") - ? String(el[head.id]) - .split(".") - .map((part, index) => - index === 0 - ? part.replace( - /\B(?=(\d{3})+(?!\d))/g, - ",", - ) - : part, - ) - .join(".") - : String(el[head.id] ?? "").replace( - /\B(?=(\d{3})+(?!\d))/g, - ",", - )} + {(() => { + const cellValue = (el as Record)[head.id]; + return typeof cellValue !== "number" + ? String(cellValue ?? "") + : String(cellValue).includes(".") + ? String(cellValue) + .split(".") + .map((part, index) => + index === 0 + ? part.replace( + /\B(?=(\d{3})+(?!\d))/g, + ",", + ) + : part, + ) + .join(".") + : String(cellValue ?? "").replace( + /\B(?=(\d{3})+(?!\d))/g, + ",", + ); + })()} ) : ( handleCellClick(index, head.id)} key={`cell-${head.id}-${index}`} > { //체크박스 유형애서 readOnly가 필요한 경우를 위해서 ChkClass 를 사용해서 readOnly 처리함. - typeof el[head.id] === "object" && - el[head.id] !== null && - "chk" in (el[head.id] as object) && - "readonly" in (el[head.id] as object) ? ( + (() => { + const cellValue = (el as Record)[head.id]; + return typeof cellValue === "object" && + cellValue !== null && + "chk" in (cellValue as object) && + "readonly" in (cellValue as object) ? ( { { - console.log(el[head.id]); + console.log(cellValue); } if ( - (el[head.id] as ChkClass).readonly == true + (cellValue as ChkClass).readonly == true ) return; - (el[head.id] as ChkClass).chk = + (cellValue as ChkClass).chk = Boolean(checked); }} > - ) : typeof el[head.id] === "boolean" ? ( + ) : typeof cellValue === "boolean" ? ( { - el[head.id] = checked; + (el as Record)[head.id] = checked; }} > - ) : typeof el[head.id] !== "number" ? ( - String(el[head.id] ?? "") - ) : String(el[head.id]).includes(".") ? ( - String(el[head.id]) + ) : typeof cellValue !== "number" ? ( + String(cellValue ?? "") + ) : String(cellValue).includes(".") ? ( + String(cellValue) .split(".") .map((part, index) => index === 0 @@ -246,11 +253,12 @@ export function UiTable({ ) .join(".") ) : ( - String(el[head.id] ?? "").replace( + String(cellValue ?? "").replace( /\B(?=(\d{3})+(?!\d))/g, ",", ) - ) + ); + })() } )),