This commit is contained in:
2026-02-04 19:42:57 +09:00
38 changed files with 1954 additions and 516 deletions
+1
View File
@@ -25,3 +25,4 @@ apps/fo/.next/**/*
pnpm-lock.yaml
settings.json
.npmrc
.cursor
+831
View File
@@ -0,0 +1,831 @@
# 표준단어정의서
AI 이해용으로 정리된 표준단어명, 영문약어명, 영문명 목록입니다.
| 표준단어명 | 표준단어 영문약어명 | 표준단어 영문명 |
|-----------|-------------------|----------------|
| BOD | BOD | Biochemical Oxygen Demand |
| C/N비 | CNR | Carbon-Nitrogen Ratio |
| COD | COD | Chemical Oxygen Demand |
| F/M비 | FMR | Food-Microorganism Ratio |
| GISD | GISDATA | Geographic Information System Data |
| HTML | HTML | Hypertext Markup Language |
| ID | ID | Id |
| IP | IP | Internet Protocol |
| KEY | KEY | Key |
| ND | ND | Not Detected |
| NON | NON | Non |
| NTU | NTU | Nephelometry Turbidity Unit |
| OPT | OPT | Opt |
| PAC | PAC | Polyaluminium Chloride |
| PH | PH | Hydrogen Exponent |
| PKI | PKI | Public Key Infrastructure |
| POOL | POOL | Pool |
| SS | SS | Suspended Solids (Ss) |
| TCE | TCE | Trichloroethane |
| TM | TM | Transverse Mercator |
| T-N | TN | Total Nitrogen |
| TOC | TOC | Total Organic Carbon |
| T-P | TP | Total Phosphorus |
| URL | URL | Uniform Resource Locator |
| 가구 | HSHD | Household |
| 가능 | PSBL | Possible |
| 가동 | OPR | Operation |
| 가산 | ADTN | Addition |
| 가성소다 | NAOH | Caustic Soda(Nach) |
| 가축분뇨 | ANMA | Animal Manure |
| 값 | VAL | Value |
| 강도 | IN | Intensity |
| 강우 | RAIN | Rain |
| 개방 | OPN | Opening |
| 개별 | INDIV | Individual |
| 개보수비 | RPAFEE | Repair Fee |
| 개설 | ESTBL | Establishment |
| 개시 | STRT | Start |
| 개정 | RVSN | Revision |
| 개조 | REMDEL | Remodeling |
| 개체 | INDVD | Individual |
| 개체군 | POPU | Population |
| 개폐 | RORGN | Reorganization |
| 갱신 | UPDT | Update |
| 건물 | BLDG | Building |
| 건설 | CONC | Construction |
| 건수 | NOCS | The Number Of Cases |
| 건조 | DRY | Dry |
| 검사 | INSP | Inspection |
| 검사서 | EXRPT | Examination Report |
| 검정 | RCGN | Recognition |
| 검증 | VRFC | Verification |
| 검출 | DETECT | Detection |
| 검토 | RVW | Review |
| 격자 | LATTC | Lattice |
| 결과 | RSLT | Result |
| 결의 | DCIS | Decision |
| 결정 | DCSN | Decision |
| 경계 | BNDRY | Boundary |
| 경과 | PROC | Process |
| 경도 | LOT | Longitude |
| 경보 | ALARM | Alarm |
| 경사판 | ICNTPT | Inclination plate |
| 계 | SUM | Summation |
| 계량기 | MRNR | Measuring Instrument |
| 계량기분리 | METRSPRT | Meter Separation |
| 계면 | SGLV | Sludge Level |
| 계산식 | FMUL | Formula |
| 계약 | CTRT | Contract |
| 계약기간 | CNTRPD | Contract Period |
| 계절 | SEASON | Season |
| 계획 | PLAN | Plan |
| 고도처리 | AWTR | Advanced Water Treatment |
| 고시 | ANCMNT | Announcement |
| 고액분리 | SLSPRT | Solid-Liquid Separation |
| 고형물체류시간 | SRT | Solid Retention Time |
| 공간데이터 | SPCEDATA | Space Data |
| 공공 | PUBLIC | Public |
| 공급 | SPLY | Supply |
| 공기 | AIR | Air |
| 공기여과 | ARFT | Air Filter |
| 공문 | ODOC | Official Documnet |
| 공법 | MSRC | Method Of Construction |
| 공사 | CSTRN | Construction |
| 공사비 | CONSTEXPN | Construction Expenses |
| 공업지역 | MNFTR_ARA | Manufacturing Area |
| 공용면적 | CMAR | Common Area |
| 공통 | CMMN | Commonness |
| 관 | PP | Pipe |
| 관계 | REL | Relation |
| 관련 | RLTN | Relation |
| 관로 | PPLINE | Pipe Line |
| 관리 | MNG | Management |
| 관리기관 | MGC | Management Agency |
| 관리자 | MNGR | Manager |
| 관찰 | WTCH | Watch |
| 관측 | OBSR | Observation |
| 관측소 | OBSRVT | Observatory |
| 교반기 | AGITOR | Agirator |
| 교정 | CRRC | Correction |
| 구간 | SCTN | Section |
| 구동 | DRIVE | Drive |
| 구분 | SE | Section |
| 구성 | CMPSG | Composing |
| 구역 | ZONE | Zone |
| 구조 | STRCT | Structure |
| 권역 | DSTR | District |
| 권한 | AUTH | Authority |
| 규격 | STNDRD | Standard |
| 규모 | SCAL | Scale |
| 규제 | REGL | Regulation |
| 균등 | EQLTY | Equality |
| 금액 | AMT | Amount |
| 급수 | WSP | Water Supply |
| 기간 | WHL | While |
| 기관 | INST | Institution |
| 기록 | RECD | Recording |
| 기록부 | REGI | Register |
| 기밀 | SCRET | Secret |
| 기법 | TECQU | Techniques |
| 기본 | BSIC | Basics |
| 기본정보 | BASINF | Bassinfo |
| 기본키 | PK | Primary Key |
| 기상 | WETHER | Weather |
| 기안 | DRFTG | Drafting |
| 기재 | WRIT | Write |
| 기점 | CDPNT | Cardinal Point |
| 기존 | LGCY | Legacy |
| 기준 | CRTR | Criteria |
| 기타 | ETC | Etc |
| 기한 | TERM | Term |
| 기후 | CLMT | Climate |
| 긴급 | EMRG | Emergency |
| 날개벽 | WW | Wing Wall |
| 날씨 | WETHR | Weather |
| 날짜 | DATE | DATE |
| 남조류 | BLAL | Blue-Green Algae |
| 납 | PB | Plumbum |
| 내려받기 | DWLD | Download |
| 내부반송 | ITNRCC | Internal Recycl |
| 내용 | CN | Content |
| 내용연수 | SVLF | Service Life |
| 냄새 | SMELL | Smell |
| 년 | YY | Year |
| 년간 | FAYR | For A Year |
| 노즐 | NZL | Nozzle |
| 노출 | EXPSR | Exposure |
| 농도 | DNSTY | Density |
| 농축 | TKN | Thickened |
| 누적 | ACML | Accumulate |
| 누출 | LKG | Leakage |
| 눈 | SNW | Snow |
| 단가 | UNPRC | Unit Price |
| 단기 | SRTPD | Short Period |
| 단순 | SIMPL | Simplicity |
| 단위 | UNIT | Unit |
| 대구역 | LZONE | Large Zone |
| 대분류 | LCLAS | Large Classification |
| 대장 | REGSTR | Register |
| 대장균 | COLI | Coliform, Fecal Coliform |
| 대장균군 | COLIB | Coliform Bacteria |
| 대지면적 | SIAR | Site Area |
| 대체 | RPLC | Replace |
| 덮개 | COVR | Cover |
| 데이타 | DAT | Data |
| 도구 | UNT | Unit |
| 도래 | ADVNT | Advent |
| 도로 | ROAD | Road |
| 도로명 | RN | Road Name |
| 도시 | CTY | City |
| 도엽 | MAPDMC | Map Demarcation |
| 도표 | CHART | Chart |
| 독성 | TOXCTY | Toxicity |
| 동의 | AGRE | Agreement |
| 동절기 | WSESN | The Winter Season |
| 등급 | GRD | Grade |
| 등기 | RG | Registered |
| 등록 | REG | Registration |
| 디바이스 | DVICE | Device |
| 디코딩 | DCD | Decoding |
| 레이어 | LYR | Layer |
| 로그인 | LGN | Login |
| 로우 | ROW | Row |
| 마감 | DDLN | Deadline |
| 마이크로필터 | MCRFT | Micro Filter |
| 막 | MBRN | Membrane |
| 만족도 | STFDG | Satisfaction Degree |
| 맑음 | CLAR | Clear |
| 매각 | SAL | Sale |
| 맨홀 | MH | Manhole |
| 맵 | MAP | Map |
| 메인 | MAIN | Main |
| 메일 | EMAIL | Email |
| 메탄올 | MTN | Methanol(CH3OH) |
| 명 | NM | Name |
| 모니터링 | MTRG | Monitoring |
| 모델 | MODL | Model |
| 모델링 | MODLNG | Modeling |
| 모래 | SAND | Sand |
| 목 | MOK | Mok |
| 무산소 | ANX | Anoxic |
| 무산소조 | ANX_TANK | Anoxic Tank |
| 무인센서 | MNLSENSR | Manless Sensor |
| 문서 | DCMT | Document |
| 물 | WTR | Water |
| 미급수 | NONWTRSPL | Non Water Supply |
| 미생물 | BLGC | Biological |
| 미세먼지 | PM | Particulate Matter |
| 미세목 | MCRB | Micro Bar |
| 민간위탁 | ETSVN | Entrustment To Civilian |
| 민감 | SST | Sensitive |
| 민원 | CVLCPT | Civil Complaint |
| 바이러스 | VIRS | Virus |
| 반기 | HT | Half Term |
| 반류수 | SIDSWT | Side Stream Water |
| 반송 | SNDBK | Send Back |
| 반송수 | RCCWT | Recycled Water |
| 반송슬러지 | RTNSLG | Return Sludge |
| 반영 | RFLT | Reflection |
| 반응조 | RETNK | Reactant Tank |
| 반출 | EXPRT | Export |
| 반토 | ALUM | Alumina |
| 반환 | GVBK | Giving Back |
| 받이 | INL | Inlet |
| 발생 | OCRN | Occurrence |
| 발전 | PWGNRT | Power Generation |
| 발주기관 | ORNT | Order Institution |
| 방류 | DCWTR | Discharge Water Stock Etc |
| 방류구 | DSCHG | Discharge |
| 방류수 | EFLEC | Effluence |
| 방문 | VST | Visit |
| 방문자 | VSTR | Visitor |
| 방법 | MTHD | Method |
| 방사 | RLSE | Release |
| 배관 | PLINE | Pipeline |
| 배분 | DSTRB | Distirbution |
| 배설물 | EXCRTN | Excretion |
| 배수 | DRNG | Drainage |
| 배수구역 | DRANGZN | Drainage Zone |
| 배출 | EXHST | Exhaust |
| 배출가스 | EMGA | Emission Gases |
| 배출구 | VENT | Vent |
| 배출시설 | DHGP | Discharge Equipment |
| 배출시험 | EXHTST | Exhaust Test |
| 배출자 | DCHGR | Discharge Person |
| 밸브 | VALVE | Valve |
| 번호 | NO | Number |
| 법 | LAW | Law |
| 법적 | LGL | Legal |
| 법정 | STTY | Statutory |
| 법정동 | STDG | Statutory Dong(Administrative District) |
| 법정리 | STLI | Statutory Li(Administrative District) |
| 변경 | CHG | Change |
| 변동 | FLCTN | Fluctuation |
| 변속기 | TRMIS | Transmission |
| 보고 | RPT | Report |
| 보고서 | RPOT | Report |
| 보관 | STORG | Storage |
| 보수 | MEND | Mend |
| 보유 | HOLD | Hold |
| 보정 | RVSION | Revision |
| 보조 | ASSISC | Assistance |
| 보조금 | SBSIDY | Subsidy |
| 복개 | COVE | Cover |
| 복토 | CWTH | Covering With Soil |
| 본류 | MI_RV | Main River |
| 본번 | MNO | Main Number |
| 부검 | ATPSY | Autopsy |
| 부과 | LEVY | Levy |
| 부과금 | LVYAMT | Levy Amount |
| 부기 | BUKIP | Bookkeeping |
| 부담금 | ALOTM | Allotment |
| 부번 | SNO | Sub Number |
| 부산물 | BYPRD | By-Product |
| 부서 | DEPT | Department |
| 부숙화 | DECPZ | Decomposed ~Ize |
| 부적합 | IMPPRTY | Impropriety |
| 부착 | ASN | Adhesion |
| 부품 | CMPNT | Components |
| 부하량 | LOADQTY | Load Quantity |
| 분과 | DIVSN | Division |
| 분뇨 | ENSO | Excreta, Night Soil |
| 분류 | CL | Classification |
| 분류군 | TAXON | Taxon |
| 분리막 | SPRTMBR | Separation Membrane |
| 분배 | DTRBT | Distribution |
| 분배조 | DTRBT_TANK | Distribution Tank |
| 분야 | RLM | Realm |
| 분원성 | FECL | Fecal |
| 분원성대장균군 | FCOLI | Fecal Coliform |
| 분원성연쇄상구균 | FCSTRCCI | Fecal Streptococci |
| 분할 | PRTIN | Partition |
| 비밀번호 | PSWD | Password |
| 비상 | EMGNY | Emergency |
| 비정상 | ABNRM | Abnormality |
| 사양 | SPECS | Specification |
| 사업비 | WCT | Working Cost |
| 사업장 | BPLC | Business Place |
| 사여과지 | SAND_ FILTR | Sand Filter |
| 사용 | USE | Use |
| 사용가능 | USABLE | Usable |
| 사용권 | RIOUS | Right Of Using |
| 사용량 | USG | USAGE |
| 사용자 | USER | User |
| 사위 | FDG | Four Directions Girth |
| 사유 | RESN | Reason |
| 사이클 | CYCLE | Cycle |
| 사이트 | SITE | Site |
| 사진 | PHOT | Photograph |
| 사항 | MATTR | Matter |
| 사후 | AFTFAT | After Fact |
| 삭제 | DEL | Deletion |
| 산기관 | DFS | Diffuser |
| 산업 | INDUST | Industrial |
| 산화환원전위 | ORP | Oxidation Reduction Potential |
| 살모넬라 | SLMN | Salmonella |
| 삼원촉매장치 | TWCTLC | Three Way Catalytic Converter |
| 상세 | DTL | Details |
| 상세주소 | DADDR | Detailed Address |
| 상수 | WT | Water |
| 상업지역 | CMCL_ARA | Commercial Area |
| 상태 | STUS | Status |
| 상품 | GDS | Goods |
| 상향류 | UFW | Upflow |
| 상호 | CONM | Company Name |
| 색도 | CRMTY | Chromaticity |
| 생략 | OMS | Omission |
| 생물 | LVB | Living Being |
| 생물반응조 | BIRAT | Bioreactor |
| 생물서식처 | ORGNHBT | Organism Habitat |
| 생물종 | BISP | Biological Species |
| 생성 | CRT | Creation |
| 생슬러지 | RSLG | Raw Sludge |
| 생태 | ECLGY | Ecology |
| 생태독성 | ECTOX | ecotoxicity |
| 서류 | PAPE | Papers |
| 서명 | SIGN | Signing |
| 서버 | SRVR | Server |
| 서비스 | SRVC | Service |
| 설계 | DESGN | Design |
| 설계용량 | DESGN_CPCT | Design Capacity |
| 설립 | FNDN | Foundation |
| 설정 | STNG | Setting |
| 설치 | INSTL | Installation |
| 성격 | CHTR | Character |
| 성공 | SCS | Success |
| 성능 | PRFMNC | Performance |
| 성능검사 | EFTST | Efficiency Test |
| 성적서 | SCRRP | Score Report |
| 세균 | BCLS | Bacillus |
| 세목 | FB | Fine bar |
| 세부 | DETAIL | Detail |
| 세정 | WS | Washing |
| 세정제 | CNML | Cleaning Material |
| 소 | SML | Small |
| 소독 | DSNF | Disinfection |
| 소독제 | DSINF | Disinfectant |
| 소분류 | SCLAS | Small Classification |
| 소수점 | DCPT | Decimal Point |
| 소요 | REQ | Required |
| 소유 | OWN | Own |
| 소유역 | SBASIN | Sub Basin |
| 소재지 | PLAC | Place Of Location |
| 소포 | ATFM | Antifoaming |
| 소포수 | FBW | Foam Breaking Water |
| 소포제 | ANAG | Antifoaming Agent |
| 송부 | SENDNG | Sending |
| 송신 | SNDM | Send Message |
| 송풍기 | BLW | Blower |
| 수 | CNT | Count |
| 수거 | TKAWY | Take Away |
| 수계 | WWBH | Watershed, Water Basin, Hydrosphere |
| 수동 | HOPR | Hand Operation |
| 수리학적 체류시간 | HRT | Hydraulic Retention Time |
| 수문 | Gate | Gate |
| 수산화나트륨 | SOHY | Sodium Hydroxide |
| 수소이온 | HION | Hydrogen Ion |
| 수신 | RCPTN | Reception |
| 수용가 | RCPTR | Receptor |
| 수위 | WAL | Water Level |
| 수정 | MDFCN | Modification |
| 수정자 | MDFR | Modifier |
| 수제 | SPRDIKE | Superdike |
| 수조 | Tank | Tank |
| 수질 | QTWT | Quality Of Water |
| 수질개선 | WTRQLIMP | Water Quality Improvement |
| 수질기준 | WQST | Water Quality Standards |
| 수질배출정보 | WTDI | Water Discharge Information |
| 수집 | CLCT | Collection |
| 순환 | CCL | Cycling |
| 쉬겔라 | SHIGLA | Shigella |
| 스컴 | SCM | Scum |
| 스크린 | SCR | Screen |
| 슬러지 | SLG | Sludge |
| 슬러지 밀도지수 | SDI | sludge density index |
| 슬러지 용량 지표 | SVI | Sludge Volume Index |
| 습지 | WTLN | Wetland |
| 승인 | APRV | Approval |
| 승인권 | APPRVRGT | Right Of Approval |
| 시각 | TIME | Time |
| 시간 | HR | Hour |
| 시군구 | SGG | Si/Gun/Gu |
| 시나리오 | SCEN | Scenario |
| 시도 | CTPV | Cities And Provinces |
| 시료 | SMPL | Sample |
| 시설 | FCLT | Facility |
| 시설면적 | FCAR | Facility Area |
| 시설물 | FCLTS | Facilities |
| 시스템 | SYS | System |
| 시안 | CYN | Cyaan |
| 시운전 | TSTRN | Test Run |
| 시작 | BGNG | Beginning |
| 시점 | PTM | Point Time |
| 시행 | ENFC | Enforcement |
| 시험 | TEST | Test |
| 신고 | DCLR | Declaration |
| 신고자 | DCL | Declarer |
| 신규 | NEW | New |
| 신기술 | NTCH | New Technology |
| 신뢰 | CNFDNC | Confidence |
| 신뢰성 | CRDIBLTY | Credibility |
| 실시 | OPRT | Operation |
| 실적 | ACRS | Actual Result |
| 실행 | EXCN | Execution |
| 심사 | SRNG | Screening |
| 심의 | DLBR | Deliberation |
| 아황산환원혐기성포자형성균 | SFSRA | Spore Forming Sulfite Reducing Anaerobes |
| 안정화 | STBLZT | Stabilization |
| 암롤박스(컨테이너) | ARTCT | Arm roll type container |
| 암모니아성질소 | NHN | Ammonia Nitrogen |
| 압력 | PRESSR | Pressure |
| 압송 | PUMPNG | Pumping |
| 압축 | CMPRS | Compress |
| 액비 | LQFERTLZ | Liquid Fertilizer |
| 액상 | LIQD | Liquid |
| 약 | GENTLE | Gentle |
| 약품 | CMC | Chemical |
| 약품비 | MEDFEE | Medicine Fee |
| 약품사용 | USMD | Use Medicines |
| 업로드 | UPLD | Upload |
| 업무 | DTY | Duty |
| 없음 | NOT | Nothing |
| 에너지 | ENR | Energy |
| 에틸벤젠 | ETBNZN | Ethylbenzene |
| 여과 | FILTR | Filteration |
| 여과수 | FTWT | Filtered Water |
| 여과재 | FTMTRL | Filter Material |
| 여과형 | FILTRFOM | Filter Form |
| 여부 | YN | Yes or No |
| 여시니아균 | YERSNA | Yersinia |
| 역률 | PWRER_FCT | Power Factor |
| 역세척 | BWS | Back Wash |
| 연결 | CONN | Connection |
| 연계 | LINK | Link |
| 연도 | YR | Year |
| 연락 | CNTC | Contact |
| 연령 | AGE | Age |
| 연료화 | FUELZ | Fuelize |
| 연월 | YM | Year and Month |
| 염소 | CLRN | Chlorine |
| 염소소독 | CHDI | Chlorine Disinfection |
| 염소이온 | CLION | Chlorine Ion |
| 염화제이철 | IRCLD | Iron(III) Chloride |
| 예보 | FRCST | Forecast |
| 예비 | PRPT | Preparation |
| 예산 | BGT | Budget |
| 예상 | EXPCT | Expectation |
| 예약 | RSVT | Reservation |
| 예외 | EXCPT | Exception |
| 예정 | PRNG | Prearrangement |
| 예찰 | PRDICT | Prediction |
| 오류 | ERR | Error |
| 오수받이 | HUS_INL | House Inlet |
| 오염물질 | CNTMN | Contaminant |
| 오염원 | POLUSRC | Pollution Source |
| 오존 | OZN | Ozone |
| 오프로드 | OFFRD | Off Road |
| 옥살산 | OXACID | Oxalic Acid |
| 와류 | VORTEX | Vortex |
| 와류형 | VORTXFOM | Vortex From |
| 완결 | COMPLT | Completion |
| 완료 | CMPTN | Completion |
| 완전 | PRFECT | Perfection |
| 요건 | REQSIT | Requisite |
| 요막액 | ALLNTFLD | Allantoic Fluid |
| 요청 | DMND | Demand |
| 용량 | CPCT | Capacity |
| 용역 | SERVC | Service |
| 용존산소 | DO | Dissolved Oxygen |
| 용해 | DSLV | Dissolving |
| 우량 | EXLT | Excellent |
| 우수 | ST | Storm |
| 우수받이 | STRT_INL | Street Inlet |
| 우수토구 | STM_OVFL_MUT | Storm Overflow Mouth |
| 우회 | BP | BY PASS |
| 운반 | CNVY | Conveyance |
| 운영 | OPER | Operation |
| 운영비 | OPEXP | Operation Expense |
| 운행 | OPRAT | Operation |
| 원격 | RMRT | Rmrt |
| 원격감시체계 | TMS | Tele Monitoring System |
| 원료 | MTRAL | Material |
| 원수 | ORGWT | Origin'S Water |
| 원인자 | ORGPR | The Origin Person |
| 월 | MM | Month |
| 위도 | LAT | Latitude |
| 위반 | CNTR | Contravene |
| 위촉 | ENTRST | Entrusting |
| 위치 | LOC | Location |
| 위탁 | CNSG | Consign |
| 위탁자 | CONSGNR | Consignor |
| 유기인 | ORGP | Organic Phosphorus |
| 유량 | FLUX | Flux |
| 유량조정조 | EQLZT__TANK | Equalization Tank |
| 유입 | INFlOW | Inflow |
| 유입수 | INFWTR | Influent Water |
| 유주 | SWARMG | Swarming |
| 유지 | MNTNC | Maintenance |
| 유지용수공급 | MWRS | Maintenance Water Requirement Supply |
| 유체 | FLUID | Fluid |
| 유출 | EFFLUX | Efflux |
| 유충 | LAVL | Larval |
| 유형 | TY | Type |
| 유효 | VLD | Validity |
| 음용 | DKPS | For Drinking Purpose |
| 읍면동 | EMD | Eup/Myun/Dong |
| 응답 | RSPNS | Response |
| 응집제 | COAG | Cohesive Agents |
| 이관 | TRNSF | Transfer |
| 이동 | MVMN | Movement |
| 이력 | HST | History |
| 이메일 | EML | Email |
| 이상 | ABOVE | Above |
| 이송 | TRSF | Transfer |
| 이의 | OBJC | Objection |
| 이차 | SCDR | Secondary |
| 이차침전지 | SCDR_SDMT_TANK | Secondary Sedimaentation |
| 이행 | MIG | Migratation |
| 인건비 | PEXP | Personnel Expenses{Expenditure] |
| 인계 | HNDVR | Handover |
| 인계서 | HDOVDC | Handover Document |
| 인구 | POPL | Population |
| 인산 | PHACID | Phosphoric Acid |
| 인산염인 | POP | phosphate |
| 인양기 | LFT | Lifter |
| 인원수 | NOPE | The Number of Persons |
| 인증 | CERT | Certification |
| 인처리 | PPRCS | Phosphorus Process |
| 인허가 | APVL | Approval |
| 일 | DY | Day |
| 일련번호 | SN | Serial Number |
| 일반 | GNRL | General |
| 일별 | DALY | Daily |
| 일시 | DT | Date and Time |
| 일자 | YMD | YEAR Month Day |
| 일지 | DIARY | Diary |
| 일차 | PRM | Primary |
| 일차침전지 | PST_SDMT_TANK | Primary Sedimentation Tank |
| 일평균 | DYRG | Day Average |
| 임시 | TMPR | Temporary |
| 임의 | RNDM | Random |
| 입고 | WRHS | Warehousing |
| 입력 | INPT | Input |
| 잉여 | SPS | Surplus |
| 잉여슬러지 | EC_SLG | Excess Sludge |
| 자 | MAN | Man |
| 자갈 | GRAVEL | Gravel |
| 자료 | DATA | Data |
| 자리 | DIGIT | Digit |
| 자립화 | SLFRLI | Self Reliance |
| 자연형 | NATRLFOM | Natural Form |
| 자외선 | URLI | Ultraviolet Rays, Light |
| 자재 | MTRIL | Material |
| 자체 | ITSL | Itself |
| 작성 | WRT | Writing |
| 작업 | JOB | Job |
| 잠금 | LOCK | Lock |
| 장기 | LNGTR | Long Term |
| 장소 | PLCE | Place |
| 장착 | MNTNG | Mounting |
| 재 | RE | Re |
| 재이용 | REUSE | Reuse |
| 재이용수 | | Reuse Water |
| 재활용 | RUSE | Reuse |
| 저감 | REDUC | Reduction |
| 저류조 | DTT_TANK | Detention Tank |
| 저온 | LOWTMP | Low Temperature |
| 저장 | STRG | Storage |
| 저장소 | STORGE | Storage |
| 적발 | DSCL | Disclose |
| 적산 | ADD | Addition |
| 적용 | APLCN | Application |
| 적합 | STBLT | Suitability |
| 전기 | ELCTY | Electricity |
| 전기료 | ELFEE | Electricity Fee |
| 전력 | PWRER | Power |
| 전문 | SPCY | Specially |
| 전산 | CMPUTT | Computation |
| 전송 | TRSM | Transmission |
| 전압 | VLTGE | Voltage |
| 전용 | EXUSE | Exclusive Use |
| 전원 | SELCT | Source Of Electricity |
| 전처리 | PRETR | Pretreatment |
| 점검 | CHCK | Check |
| 접속 | CNTN | Connection |
| 정밀 | PRCIS | Precision |
| 정보 | INFO | Information |
| 정산 | CLCLN | Calculation |
| 정상 | NRMLT | Normality |
| 정수장 | WPPW | Water Purification Plant, Waterworks |
| 정제 | REFINE | Refining |
| 정지 | STP | Stop |
| 제거 | RMV | Removal |
| 제수변 | SL_VALVE | Sluice Valve |
| 제작 | MNFCT | Manufacture |
| 제조사 | MKR | Maker |
| 제출 | SBMSN | Submission |
| 제한 | LIMT | Limitation |
| 조류 | ALG | Algae |
| 조목 | CSB | Coarse Bar |
| 조사 | EXMN | Examination |
| 조성 | MAKE | Make |
| 조정 | EQLT | Equalization |
| 조치 | ACTN | Action |
| 조회 | INQ | Inquiry |
| 존재 | EXST | Existence |
| 종결 | TRMN | Termination |
| 종균제 | MICBA | Microbial Agent |
| 종료 | END | End |
| 종류 | KND | Kind |
| 종목 | IEM | Item |
| 종별 | ASORT | Assortment |
| 종사자 | ENFSN | Enfilade Person |
| 종점 | TMNL | Terminal |
| 좌표 | COOR | Coordinate |
| 주간 | WIK | Week |
| 주변 | CFR | Circumference |
| 주소 | ADDR | Address |
| 주입 | IJTN | Injection |
| 주파수 | FQNC | Frequency |
| 준공 | CMCN | Completion Of Construction |
| 중권역 | MDSTRC | Medium District |
| 중복 | DPCN | Duplication |
| 중분류 | MLSFC | Middle Classification |
| 중온 | MESPH | Mesophilic |
| 중첩 | RETRTN | Reiteration |
| 중화설비 | NUTEQP | Neutralization Equipment |
| 중화제 | CNTAG | Counteragent |
| 증가 | INCRS | Increase |
| 지도점검표사본 | CITBMR | Copy of Instruction Checklist |
| 지방자치단체 | LGOV | Local Governments |
| 지번 | LOTNO | Lot Number |
| 지상 | GRND | Ground |
| 지역 | ARA | Area |
| 지질 | NTRFS | Nature Of Soil |
| 지질도 | GEOMAP | Geological Map |
| 지하 | UDGD | Underground |
| 지하수 | GROU | Groundwater |
| 지형 | TPGRPH | Topography |
| 진공 | VCM | Vacuum |
| 진단 | DGNSS | Diagnosis |
| 진동 | VIBRAT | Vibration |
| 진행 | PRGRE | Progress |
| 질산 | NIACID | Nitric Acid. |
| 질산성질소 | NO3N | Nitrate Nitrogen |
| 집계 | TOT | Total |
| 집계구 | SUMDST | Summation District |
| 집행 | IMPL | Implementation |
| 찌꺼기 | LEES | Lees |
| 차아염소산 | NAOCL | Hypochlorous Acid |
| 차집 | ITCT | Intercepting |
| 착공 | BGNCST | Begin Construction |
| 채수 | SAMWT | Sampling Of Water |
| 채수기 | WTRSMPLR | Water Sampler |
| 채수병 | WTRBOTL | Water Bottle |
| 처리 | PRCS | Process |
| 처리비 | PSSFEE | Process Fee |
| 처리수 | TRT_WT | Treated Water |
| 처리수조 | TRT_WT_TANK | Treated Water Tank |
| 처리시설 | TRTMTFCLT | Treatment Facility |
| 처리자 | PRCR | Processor |
| 처분 | DSPS | Disposition |
| 철염 | FESLT | Ferric Salt |
| 첨부 | ATCH | Attachment |
| 첨부파일 | ATFI | Attachment File |
| 초과 | EXCS | Excess |
| 초기화 | INITL | Initialization |
| 촉매 | CTLY | Catalyst |
| 총계 | TSM | Summation |
| 총대장균군 | TCOLFGRP | Total Coliform Group |
| 총량 | TQT | Total Quantity |
| 총면적 | GFA | Gross Floor Area |
| 총사업비 | TPCO | Total Project Cost |
| 총인구 | TPOPLTN | Total Population |
| 총인처리시설 | TPFCT | Total Phosphorus facility |
| 최근 | RCNT | Recent |
| 최대값 | MAXV | Maximum Value |
| 최소값 | MINV | Minimum Value |
| 최적 | BMTB | Being The Most Suitable |
| 최종 | LAST | Last |
| 최초 | FRST | First |
| 추출 | EXTR | Extraction |
| 추출정보 | EXTRINFO | Extraction Information |
| 축 | AXS | Axis |
| 출력 | OTPT | Output |
| 출발 | LVE | Leave |
| 충전기 | CHRGR | Charger |
| 취득 | ACQS | Acquisition |
| 취소 | RTRCN | Retraction |
| 측정 | MSUR | Measurement |
| 측정기 | MSRR | Measurement Instrument |
| 측정소 | MSRSTN | Measurement Station |
| 침사지 | GTCB | Grit Chamber |
| 침전 | SDMT | Sediment |
| 침전지 | SDMT_TANK | sedimentation tank |
| 컨베이어 | CVY | Conveyor |
| 컬럼 | COL | Column |
| 코드 | CD | Code |
| 크기 | SZ | Size |
| 크실렌 | XYLEN | Xylene |
| 탄화 | CARB | Carbonization |
| 탈거 | CRYOFF | Carry Off |
| 탈리액 | SPNT | Supernatant |
| 탈수 | DWTR | Dewatering |
| 탈수기 | DEHYM | Dehydration Machine |
| 탈질 | DNTFCT | Denitrificatio |
| 탈취 | DODRZ | Deodorization |
| 탈취기 | DEODRZ | Deodorizer |
| 탈취제 | DEODR | Deodorant |
| 탈황제 | DSLFA | Desulfurizing Agent |
| 터널형 | YUNLTP | Tunnel Type |
| 테이블 | TBL | Table |
| 토구 | OTFL | Outfall |
| 토지 | LAD | Land |
| 토지면적 | LDAR | Land Area |
| 통계 | STATS | Statistics |
| 통보 | NTFCTN | Notification |
| 통신 | COMM | Communication |
| 통지 | AVTSMT | Avertissement |
| 통합 | UNTY | Unity |
| 특성 | CHRT | Character |
| 특수 | SPECL | Special |
| 특정유해물질 | SHCH | Specified Hazardous Chemicals |
| 파일 | FILE | File |
| 판정 | JGMT | Judgement |
| 펌프 | PUMP | Pump |
| 펌프장 | PUMP_STT | Pump Station |
| 페놀 | PHNL | Phenol |
| 평가 | EVL | Evaluation |
| 폐기 | DSCD | Discard |
| 폐기물 | WSTE | Waste |
| 폐쇄 | CLSG | Closing |
| 폐수 | WAWA | Waste Water |
| 폐수처리 | WSWT | Wastewater Treatment |
| 폐열 | WASTHET | Waste Heat |
| 포기 | ARTN | Aeration |
| 포트 | PORT | Port |
| 폭기조 | ARTN_TANK | Aeration Tank |
| 폴리머 | PLYMR | Polymer |
| 폴리철 | FRRCSU | Ferric Sulfate |
| 표고 | AL | Altitude |
| 표기 | MARK | Mark |
| 표시 | INDCT | Indication |
| 표준 | STD | Standard |
| 표출 | EPRSS | Expression |
| 플래그 | FLAG | Flag |
| 필드 | FILD | Field |
| 필수 | ESNTL | Essential |
| 필증 | CERFIN | Certificate Of Finishing |
| 필터 | FLTER | Filter |
| 하수 | SWGE | Sewage |
| 하수도 | DRNGSYS | Drainage System |
| 하수미처리 | SEWGUNTTM | Un Sewage Treatment |
| 하수처리 | SEWGTRTM | Sewage Treatment |
| 하수처리수 | STWTR | Sewage Treatment Water |
| 하위 | LOWR | Lower |
| 하향류 | DWFW | Downflow |
| 할인 | DSCNT | Discount |
| 함수율 | MISTR_CTNT | Moisture content |
| 합계 | SMM | Summation |
| 해당 | RLVT | Relevant |
| 해석 | INTRPRTT | Interpretation |
| 해양투기 | OCDU | Ocean Dumping |
| 행망 | ADMNW | Administration Network |
| 행정 | ADMN | Administration |
| 행정구역 | ADMI | Administrative District |
| 행정동 | DONG | Dong (Administrative District) |
| 허가 | PRMSN | Permission |
| 허용 | PERM | Permission |
| 현상 | PHNMN | Phenomenon |
| 혐기 | AARB | Anaerobic |
| 혐기조 | AARB_TANK | Anaerobic tank |
| 협잡물 | CCMT | Concomitant |
| 형태 | SHAP | Shape |
| 호기 | ARB | Aerobic |
| 호기조 | ARB_TANK | Aerobic Tank |
| 호소수 | LMSHWT | Lake And Marsh Water |
| 호수 | LKE | Lake |
| 호안 | RVTMNT | Revetment |
| 호이스트 | HIST | Hoist |
| 혼합 | CMPN | Compound |
| 혼합액현탁고형물 | MLSS | Mixed liquor suspended solids |
| 혼화지 | MXG_TNAK | Mixing tank |
| 홈페이지 | HMPG | Homepage |
| 홍수 | FLOOD | Flood |
| 확인 | IDNTY | Identify |
| 확인서 | CNFRMN | Confirmation |
| 확인자 | IDFR | Identifier |
| 확장자 | EXTN | Extension |
| 확정 | CFMTN | Confirmation |
| 환경 | ENVR | Environment |
| 환경기초시설 | ENINF | Environmental Infrastructure |
| 환원 | RSTORE | Restoration |
| 활성탄 | AC | Activated Carbon |
| 활성화 | PRMT | Promote/Facilitate |
| 활용 | PRUS | Practical Use |
| 황산 | ECCBT | Encyclopaedia Britannica (H2So4) |
| 회사 | CO | Company |
| 회수 | RTRVL | Retrieval |
| 회신 | RPLY | Reply |
| 효율 | EFC | Efficiency |
| 효율성 | EFFCTV | Effectiveness |
| 휴대 | MBL | Mobile |
| 흡수정 | EXTTW | Extraction Well |
| 흡착 | ADST | Adsorption |
@@ -1,53 +1,22 @@
// import { client } from "@/shared/api";
// import { ENDPOINT } from "@/shared/config";
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import {
type BoardStatisticsParams,
type BoardStatistics,
type BoardStatisticsService,
} from "../model/board-statistics-interface";
// 임시 모의 데이터
const mockBoardStatisticsData: BoardStatistics = {
totalPosts: 2456,
totalComments: 156,
averageRating: 4.2,
totalViews: 45678,
dayList: [
{ date: "1월", posts: 10, comments: 5, views: 800 },
{ date: "2월", posts: 15, comments: 8, views: 1200 },
{ date: "3월", posts: 12, comments: 10, views: 1000 },
{ date: "4월", posts: 18, comments: 15, views: 1500 },
{ date: "5월", posts: 22, comments: 20, views: 1800 },
{ date: "6월", posts: 20, comments: 18, views: 1600 },
{ date: "7월", posts: 25, comments: 22, views: 2000 },
],
boardList: [
{ boardType: "notice", boardName: "공지사항", count: 45 },
{ boardType: "faq", boardName: "FAQ", count: 120 },
{ boardType: "qna", boardName: "Q&A", count: 180 },
{ boardType: "free", boardName: "자유게시판", count: 95 },
],
statusList: [
{ status: "completed", statusName: "답변완료", count: 75 },
{ status: "waiting", statusName: "답변대기", count: 25 },
],
};
class BoardStatisticsApiService implements BoardStatisticsService {
async getBoardStatistics(
params: BoardStatisticsParams,
): Promise<BoardStatistics> {
console.log("params: ", params);
try {
// 실제 API 연동 시 아래 코드 사용
// const response = await client.get<BoardStatistics>(
// `${ENDPOINT.CMS_SERVICE.BOARD_STATISTICS}`,
// { params },
// );
// return response.data;
// 임시 모의 데이터 반환
return Promise.resolve(mockBoardStatisticsData);
const response = await client.get<BoardStatistics>(
`${ENDPOINT.BOARD_SERVICE.STATISTICS}`,
{ params },
);
return response.data;
} catch (error) {
console.error("게시판 통계 데이터 조회 실패:", error);
throw error;
@@ -12,32 +12,36 @@ export interface BoardStatisticsParams extends PageableParams {
}
export interface BoardStatistics {
totalPosts: number;
totalComments: number;
averageRating: number;
totalViews: number;
dayList: DayStatistics[];
boardList: BoardTypeStatistics[];
statusList: StatusStatistics[];
bbsTotalDto: BbsTotalDto; // 게시판 전체 통계
pstAnsList: PstAnswerStatistics[]; // 게시물 답변 상태별 통계 목록
bbsDailyList: BbsDailyStatistics[]; // 게시판 일별 통계 목록
bbsPstCntList: BbsPostCountStatistics[]; // 게시판별 게시물 건수 통계 목록
}
interface DayStatistics {
date: string;
posts: number;
comments: number;
views: number;
interface BbsTotalDto {
pstInqCnt: number; // 게시물 조회 건수
pstEvlAvg: number; // 게시물 평가 평균
pstTotCnt: number; // 게시물 총 건수
pstAnsWaitCnt: number; // 게시물 답변 대기 건수
}
interface BoardTypeStatistics {
boardType: string;
boardName: string;
count: number;
interface PstAnswerStatistics {
answerNm: string; // 답변 명
answerYn: string; // 답변 여부 (Y/N)
ansCnt: number; // 답변 건수
}
interface StatusStatistics {
status: string;
statusName: string;
count: number;
interface BbsDailyStatistics {
dayYmd: string; // 일자 (YYYY-MM-DD)
pstInqCnt: number; // 게시물 조회 건수
pstCmntCnt: number; // 게시물 댓글 건수
pstNewCnt: number; // 게시물 신규 건수
}
interface BbsPostCountStatistics {
bbsId: number; // 게시판 ID
bbsNm: string; // 게시판 명
pstCnt: number; // 게시물 건수
}
export interface BoardStatisticsService {
@@ -11,20 +11,20 @@ export const chartData = {
} => {
return {
data: {
labels: data.dayList.map((item) => item.date),
labels: data.bbsDailyList.map((item) => item.dayYmd),
datasets: [
{
type: "line",
label: "신규게시물",
data: data.dayList.map((item) => item.posts),
data: data.bbsDailyList.map((item) => item.pstNewCnt),
borderColor: getCssVariableValue("--chart-1"),
backgroundColor: "rgba(59, 130, 246, 0.1)",
tension: 0.4,
},
{
type: "line",
label: "답변대기",
data: data.dayList.map((item) => item.comments),
label: "댓글수",
data: data.bbsDailyList.map((item) => item.pstCmntCnt),
borderColor: getCssVariableValue("--chart-2"),
backgroundColor: "rgba(236, 72, 153, 0.1)",
tension: 0.4,
@@ -32,11 +32,10 @@ export const chartData = {
{
type: "line",
label: "조회수",
data: data.dayList.map((item) => item.views),
data: data.bbsDailyList.map((item) => item.pstInqCnt),
borderColor: getCssVariableValue("--chart-3"),
backgroundColor: "rgba(168, 85, 247, 0.1)",
tension: 0.4,
hidden: true,
},
],
},
@@ -67,13 +66,13 @@ export const chartData = {
} => {
return {
data: {
labels: data.boardList.map((item) => item.boardName),
labels: data.bbsPstCntList.map((item) => item.bbsNm),
datasets: [
{
type: "bar",
label: "게시판별 분포",
data: data.boardList.map((item) => item.count),
backgroundColor: data.boardList.map((_, index) =>
data: data.bbsPstCntList.map((item) => item.pstCnt),
backgroundColor: data.bbsPstCntList.map((_, index) =>
getCssVariableValue(`--chart-${(index % 5) + 1}`),
),
},
@@ -106,12 +105,12 @@ export const chartData = {
} => {
return {
data: {
labels: data.statusList.map((item) => item.statusName),
labels: data.pstAnsList.map((item) => item.answerNm),
datasets: [
{
type: "doughnut",
data: data.statusList.map((item) => item.count),
backgroundColor: data.statusList.map((_, index) =>
data: data.pstAnsList.map((item) => item.ansCnt),
backgroundColor: data.pstAnsList.map((_, index) =>
getCssVariableValue(`--chart-${(index % 5) + 1}`),
),
},
@@ -26,7 +26,7 @@ import {
SelectValue,
} from "@common/components";
import { SiteSelect } from "@/entities/site";
// import { ENDPOINT } from "@/shared/config";
import { ENDPOINT } from "@/shared/config";
import { NoData } from "@/shared/ui/no-data";
import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker";
import { BoardStatisticsApi } from "../api/board-statistics-service";
@@ -66,7 +66,7 @@ function BoardStatisticsPage() {
});
const { data: boardStatisticsData } = useQuery({
queryKey: ["board-statistics", searchParams],
queryKey: [ENDPOINT.BOARD_SERVICE.STATISTICS, searchParams],
queryFn: () =>
BoardStatisticsApi.getBoardStatistics({
...searchParams,
@@ -176,7 +176,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">총 게시물</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalPosts.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstTotCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -210,7 +211,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">답변대기</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalComments.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstAnsWaitCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -244,7 +246,7 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">평균평점</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.averageRating.toFixed(1) || 0}
{boardStatisticsData?.bbsTotalDto?.pstEvlAvg?.toFixed(1) || 0}
</div>
<div className="h-16 w-24">
<Line
@@ -278,7 +280,8 @@ function BoardStatisticsPage() {
<h3 className="text-lg font-medium text-gray-500">총 조회수</h3>
<div className="flex items-center justify-between">
<div className="mt-2 text-4xl font-bold">
{boardStatisticsData?.totalViews.toLocaleString() || 0}
{boardStatisticsData?.bbsTotalDto?.pstInqCnt?.toLocaleString() ||
0}
</div>
<div className="h-16 w-24">
<Line
@@ -315,7 +318,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">일별 게시물 현황</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.dayList?.length ? (
{boardStatisticsData?.bbsDailyList?.length ? (
<Line {...chartData.day(boardStatisticsData)} />
) : (
<NoData />
@@ -329,7 +332,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">답변상태</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.statusList?.length ? (
{boardStatisticsData?.pstAnsList?.length ? (
<Doughnut {...chartData.status(boardStatisticsData)} />
) : (
<NoData />
@@ -342,7 +345,7 @@ function BoardStatisticsPage() {
<h3 className="text-2xl font-medium">게시판별 분포</h3>
</div>
<div className="h-96 p-4">
{boardStatisticsData?.boardList?.length ? (
{boardStatisticsData?.bbsPstCntList?.length ? (
<Bar {...chartData.board(boardStatisticsData)} />
) : (
<NoData />
@@ -1,6 +1,13 @@
import { client } from "@/shared/api";
import { ENDPOINT } from "@/shared/config";
import type { Dashboard, DashboardService } from "../model/dashboard-interface";
import type {
Dashboard,
DashboardService,
NoticeUser,
Schedule,
ScheduleQueryParams,
} from "../model/dashboard-interface";
import type { PageableList } from "@/shared/model";
export class DashboardApiService implements DashboardService {
public async getDashboard(): Promise<Dashboard> {
@@ -9,6 +16,25 @@ export class DashboardApiService implements DashboardService {
);
return response.data;
}
public async getNoticeUserList(
recvUnqId: string,
): Promise<PageableList<NoticeUser>> {
const response = await client.get<PageableList<NoticeUser>>(
`${ENDPOINT.CMS_SERVICE.NOTICE_USER}/${recvUnqId}/list`,
);
return response.data;
}
public async getScheduleList(
params?: ScheduleQueryParams,
): Promise<Schedule[]> {
const response = await client.get<Schedule[]>(
ENDPOINT.CMS_SERVICE.SCHEDULES,
{ params },
);
return response.data;
}
}
export const DashboardApi = new DashboardApiService();
@@ -1,3 +1,5 @@
import type { PageableList } from "@/shared/model";
export interface SiteStatisticsContent {
siteId: string;
siteNm: string;
@@ -27,6 +29,42 @@ export interface Dashboard {
menuAccessList: MenuStatisticsContent[];
}
export interface NoticeUser {
notiId: number;
recvUnqId: string;
senderUnqId: string;
notiType: string;
notiTtl: string;
notReadYn: string;
regDt: string;
}
export interface Schedule {
schdlBgngDt: string;
schdlEndDt: string;
actualDate: string;
schdlSn: number;
siteId: string;
schdlTtl: string;
schdlSeCd: string;
schdlCn: string;
reptYn: string;
commSchdlYn: string;
atflCd: string | null;
}
export interface ScheduleQueryParams {
siteId?: string;
schdlTtl?: string;
schdlSeCd?: string;
schdlBgngYmd?: string;
schdlEndYmd?: string;
reptYn?: string;
commSchdlYn?: string;
}
export interface DashboardService {
getDashboard(): Promise<Dashboard>;
getNoticeUserList(recvUnqId: string): Promise<PageableList<NoticeUser>>;
getScheduleList(params?: ScheduleQueryParams): Promise<Schedule[]>;
}
@@ -1,5 +1,6 @@
"use client";
import dayjs from "dayjs";
import { useRouter } from "next/navigation";
import { useQuery } from "@tanstack/react-query";
import { getCoreRowModel } from "@tanstack/react-table";
@@ -17,8 +18,8 @@ import {
} from "chart.js";
import { Bar, Line } from "react-chartjs-2";
import { PostApi, type RecentPost } from "@/entities/post";
import { ENDPOINT } from "@/shared/config";
import { useDataTable } from "@/shared/lib";
import { AUTH_USER_ID, ENDPOINT, SITE_ID } from "@/shared/config";
import { getCookie, useDataTable } from "@/shared/lib";
import { DashboardApi } from "../api/dashboard-service";
import { chartData } from "../model/chart-data";
import {
@@ -39,12 +40,44 @@ ChartJS.register(
);
function DashboardPage() {
const userId = getCookie(AUTH_USER_ID) ?? "";
const router = useRouter();
const { data } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.DASHBOARD],
queryFn: () => DashboardApi.getDashboard(),
});
const { data: noticeUserList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER],
queryFn: () => DashboardApi.getNoticeUserList(userId),
enabled: !!userId,
select: (data) => {
// 오늘 ~ 한 달 전 사이의 일정
const today = dayjs().endOf("day");
const monthAgo = dayjs().subtract(1, "month").startOf("day");
return data.content?.filter((item) => {
const regDt = dayjs(item.regDt);
return (
(regDt.isSame(monthAgo) || regDt.isAfter(monthAgo)) &&
(regDt.isSame(today) || regDt.isBefore(today))
);
});
},
});
const { data: scheduleList } = useQuery({
queryKey: [ENDPOINT.CMS_SERVICE.SCHEDULES],
queryFn: () =>
DashboardApi.getScheduleList({
siteId: SITE_ID,
schdlBgngYmd: dayjs().format("YYYY-MM-DD"),
schdlEndYmd: dayjs().add(1, "month").format("YYYY-MM-DD"),
commSchdlYn: "Y",
}),
});
const noticePostQuery = useQuery({
queryKey: [ENDPOINT.BOARD_SERVICE.POSTS],
queryFn: () =>
@@ -323,22 +356,15 @@ function DashboardPage() {
</div>
<div className="p-4">
<div className="space-y-4 text-foreground">
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">신규 사용자 가입</span>
<span>{(1).toLocaleString()}분 전</span>
</div>
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">메뉴 수정 요청</span>
<span>{(5).toLocaleString()}분 전</span>
</div>
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">게시물 신고</span>
<span>{(10).toLocaleString()}분 전</span>
</div>
<div className="flex items-center justify-between">
<span className="font-medium">컨텐츠 승인 요청</span>
<span>{(15).toLocaleString()}분 전</span>
</div>
{noticeUserList?.map((item) => (
<div
key={item.notiId}
className="flex items-center justify-between border-b border-border pb-4"
>
<span className="font-medium">{item.notiTtl}</span>
<span>{dayjs(item.regDt).fromNow()}</span>
</div>
))}
</div>
</div>
</div>
@@ -349,24 +375,44 @@ function DashboardPage() {
</div>
<div className="p-4">
<div className="space-y-4 text-foreground">
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">
{(3).toLocaleString()}월 정기 시스템 점검
</span>
<span>내일</span>
</div>
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">서버 업데이트 예정</span>
<span>{(3).toLocaleString()}일 후</span>
</div>
<div className="flex items-center justify-between border-b border-border pb-4">
<span className="font-medium">백업 스케줄</span>
<span>{(5).toLocaleString()}일 후</span>
</div>
<div className="flex items-center justify-between">
<span className="font-medium">정기 보안 점검</span>
<span>{(7).toLocaleString()}일 후</span>
</div>
{scheduleList && scheduleList.length > 0 ? (
scheduleList.map((schedule, index) => {
const today = dayjs();
const scheduleDate = dayjs(schedule.actualDate);
const daysUntil = scheduleDate.diff(today, "day");
let timeText = "";
if (daysUntil === 0) {
timeText = "오늘";
} else if (daysUntil === 1) {
timeText = "내일";
} else if (daysUntil > 1) {
timeText = `${daysUntil}일 후`;
} else {
timeText = scheduleDate.format("YYYY-MM-DD");
}
return (
<div
key={schedule.schdlSn}
className={`flex items-center justify-between ${
index < scheduleList.length - 1
? "border-b border-border pb-4"
: ""
}`}
>
<span className="font-medium">
{schedule.schdlTtl}
</span>
<span>{timeText}</span>
</div>
);
})
) : (
<div className="text-center text-muted-foreground">
예정된 일정이 없습니다.
</div>
)}
</div>
</div>
</div>
+2
View File
@@ -56,6 +56,7 @@ export const ENDPOINT = {
APILOG: "/cms-service/api/v1/api-logs",
SITE_AUTHORITY: "/cms-service/api/v1/site-authrt",
CONNECTION_LOG: "/cms-service/api/v1/cntnlog",
NOTICE_USER: "/cms-service/api/v1/noti/user",
},
BOARD_SERVICE: {
BBS: "/board-service/api/v1/bbs",
@@ -63,6 +64,7 @@ export const ENDPOINT = {
POSTS: "/board-service/api/v1/posts",
POSTS_COMMENTS: "/board-service/api/v1/posts-cmnts",
POST_EVALUATION: "/board-service/api/v1/pstEvl",
STATISTICS: "/board-service/api/v1/stat/bbs",
},
};
+1 -1
View File
@@ -8,7 +8,7 @@ NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
NEXT_PUBLIC_SUB_DOMAIN = http://localhost:13000
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = http://localhost:3001/auth/login
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11083/operation-service
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service/
NEXT_PUBLIC_WR_SERVER_API_URL = http://con.mind-one.co.kr:11083/reuse-service
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
NEXT_PUBLIC_GEOSERVER_URL = https://hasudo.geo.rsonesoft.com/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://con.mind-one.co.kr:11306/geoserver
+2 -3
View File
@@ -8,13 +8,12 @@ NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
#NEXT_PUBLIC_PROXY_HOST = https://devlarva.hasuon.or.kr
#NEXT_PUBLIC_CM_LOGIN_PAGE_URL = https://devqueen.hasuon.or.kr/auth/login
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/operation-service/api/v1
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
NEXT_PUBLIC_GEOSERVER_URL = http://172.29.143.87:8080/geoserver
NEXT_PUBLIC_LX_GEOSERVER_URL = http://172.29.143.87:8080/geoserver_swl
NEXT_PUBLIC_WR_SERVER_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/reuse-service/api/v1
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
NEXT_PUBLIC_DC_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/dc-service
NEXT_PUBLIC_SEWERAGE_API_URL = http://apigateway.iipbs-was.svc.cluster.local:8000/sewerage-service
NEXT_PUBLIC_NGII_URL = http://172.29.143.87/poiact
NEXT_PUBLIC_NGII_PARAM = BDE2BEF39DAFEC293AB6730150F222AC&service=WMTS&request=GetTile&version=1.0.0&format=image/png&layer=korean_map&style=korean&tilematrixset=korean&tilematrix={z}&tilecol={y}&tilerow={x}
@@ -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);
}
@@ -60,6 +60,10 @@ export default function DashBoard() {
const [sidoValue, setSidoValue] = useState<string>('0');
const [sigunValue, setSigunValue] = useState<string>('0');
const { isInit, selectSearchYear, btnClass, selectSidoData, selectSigunData, } = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const { planFcltyList } = PlanFclty;
const { operationalStatusList } = OperationStatus;
const { excelList } = RainManage;
@@ -75,7 +79,7 @@ export default function DashBoard() {
/******************선택된 데이터******************/
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || '0'); // 연도
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear); // 연도
// 시설명
const [fcltyList, setFcltyList] = useState<FacilityType>({
bscFctCd: '11000SW001R',
@@ -283,7 +287,7 @@ export default function DashBoard() {
trtFrfNm: '표준활성슬러지법, MLE, A2O',
efflWqltStndrdNm: '500톤 이상(Ⅲ지역)'
});
setSearchYear(selectSearchYear[0]?.val || '0');
setSearchYear(defaultSearchYear);
searchFcltyList.bscFctNm = '난지';
setSidoValue('0');
@@ -5,11 +5,11 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import PrecipitationModal from "./modal/page";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
@@ -22,6 +22,11 @@ export default function FacilityPrecipitation() {
,initializeCommonData
,searchFacilityPrecipitationList
} = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }};
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -37,6 +42,11 @@ export default function FacilityPrecipitation() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
labelArray,
} = FacilityPrecipitationSearch;
@@ -45,7 +55,6 @@ export default function FacilityPrecipitation() {
upHeadList1,
upHeadList2,
upHeadList3,
excelList,
facilityPrecipitation,
facilityPrecipitationCount,
isLoading,
@@ -90,8 +99,9 @@ export default function FacilityPrecipitation() {
// 시설상태
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear);
// 엑셀다운로드 트리거
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
/**
* 페이지 함수
*/
@@ -102,7 +112,7 @@ export default function FacilityPrecipitation() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYear(selectSearchYear[0]?.val || "0");
setSearchYear(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -111,7 +121,7 @@ export default function FacilityPrecipitation() {
input.value = "";
}
}
searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0");
searchFacilityPrecipitationList(1, 10, defaultSearchYear);
}
// 모달 닫기
@@ -134,20 +144,9 @@ export default function FacilityPrecipitation() {
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchFacilityPrecipitationList(1, 10, selectSearchYear[0]?.val || "0");
searchFacilityPrecipitationList(1, 10, defaultSearchYear);
}
}, [isInit, initializeCommonData, searchFacilityPrecipitationList, selectSearchYear]);
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '시설별 강수현황',
sheetNameArray: ['시설별 강수현황'],
headerRange: 'A1:N1'
});
}
}, [excelList]);
}, [isInit, initializeCommonData, searchFacilityPrecipitationList, defaultSearchYear]);
useEffect(() => {
if (facilityPrecipitation.length > 0) {
@@ -159,7 +158,7 @@ export default function FacilityPrecipitation() {
* 콜백함수
*/
// 조회
const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -177,9 +176,9 @@ export default function FacilityPrecipitation() {
break;
}
if (partStr.length > 1 || operationValue!== '0' || fcltCpct !== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchFacilityPrecipitationList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchFacilityPrecipitationList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
} else {
searchFacilityPrecipitationList(pageNo, pageCnt, searchYear);
await searchFacilityPrecipitationList(pageNo, pageCnt, searchYear);
}
}, [operationValue, fcltyName, searchFacilityPrecipitationList, searchYear, fcltCpct]);
@@ -190,9 +189,42 @@ export default function FacilityPrecipitation() {
}, [upHeadList1, upHeadList2, upHeadList3]);
// 엑셀다운로드
const excelDownload = useCallback((searchReturn: ReturnType) => {
searchFacilityPrecipitation(searchReturn, 1, 10000);
}, [searchFacilityPrecipitation]);
const excelDownload = useCallback(async (searchReturn: ReturnType) => {
if (isExcelDownClick) return;
// if (ref.current.partValue === 'A') { // 행정별
// if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
// alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'R') { // 유역별
// if (!ref.current.regionValue || ref.current.regionValue === '0') {
// alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'G') { // 환경청별
// if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
// alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// }
setIsExcelDownClick(true);
try {
await searchFacilityPrecipitation(searchReturn, 1, 10000);
const latestExcelList = store.getState().FacilityPrecipitation.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: '시설별 강수현황',
sheetNameArray: ['시설별 강수현황'],
headerRange: 'A1:N1'
});
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFacilityPrecipitation, store]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -227,6 +259,7 @@ export default function FacilityPrecipitation() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref} isAdmin={false}/>
<ListDiv>
@@ -254,4 +287,4 @@ export default function FacilityPrecipitation() {
)}
</MainDiv>
);
}
}
@@ -447,7 +447,9 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
</div>
<div className="card-header border-t mt-1">
<h3 className="text-2xl font-medium text-label">수질 TMS</h3>
<h3 className="text-2xl font-medium text-label text-right">({msrmtDate ? msrmtDate.substring(0, 4) + '-' + msrmtDate.substring(4, 6) + '-' + msrmtDate.substring(6, 8) : yesterDayStr})</h3>
<h3 className="text-2xl font-medium text-label text-right">
({msrmtDate ? msrmtDate.substring(0, 4) + '-' + msrmtDate.substring(4, 6) + '-' + msrmtDate.substring(6, 8) : yesterDayStr})
</h3>
</div>
<div className="overflow-y-auto h-[250px]">
<UiTable
@@ -6,13 +6,13 @@
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import type { FacilityWaterQltyProps } from "@/app/store/facilityWaterQlty";
import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import WaterQualityModal from "./modal/page";
export default function ProcessFacilitySearch() {
@@ -21,6 +21,11 @@ export default function ProcessFacilitySearch() {
, initializeCommonData
, searchFacilityWaterQltyList
} = useFoStore((state) => state) || { FacilityWaterQltyList: { facilityWaterQltyList: [], facilityWaterQltyCount: 0 } };
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -36,6 +41,11 @@ export default function ProcessFacilitySearch() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
mainLabelArray,
upHeadList1,
@@ -43,13 +53,13 @@ export default function ProcessFacilitySearch() {
upHeadList3,
facilityWaterQltyList,
facilityWaterQltyCount,
excelList,
isLoading,
} = FacilityWaterQltyMain;
const mainList: FacilityWaterQltyProps[] = facilityWaterQltyList || [];
const [initTrigger, setInitTrigger] = useState<boolean>(false);
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
// 엑셀다운로드 트리거
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
// 그리드 관련
const [resetPage, setResetPage] = useState<boolean>(false);
const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null);
@@ -57,7 +67,7 @@ export default function ProcessFacilitySearch() {
const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1);
const [fcltyName, setFcltyName] = useState<string>("");
const [operationValue, setOperationValue] = useState<string>("0");
const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear);
const [fcltCpct, setFcltCpct] = useState<string>("0");
// 모달 상태 추가
@@ -66,7 +76,7 @@ export default function ProcessFacilitySearch() {
const [fcltyCd, setFcltyCd] = useState<string>("");
const [modalYear, setModalYear] = useState<string>("");
const searchFcltyQltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => {
const searchFcltyQltyList = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => {
let nameCd, partStr;
switch (partValue) {
case 'R':
@@ -84,9 +94,9 @@ export default function ProcessFacilitySearch() {
break;
}
if (partStr === 'G') {
searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue);
await searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue);
} else {
searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchFacilityWaterQltyList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchFacilityWaterQltyList, searchYearValue, fcltCpct]);
@@ -96,7 +106,7 @@ export default function ProcessFacilitySearch() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYearValue(selectSearchYear[0]?.val || "0");
setSearchYearValue(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -146,33 +156,52 @@ export default function ProcessFacilitySearch() {
}
}, [isInit, initializeCommonData, searchFacilityWaterQltyList, searchFcltyQltyList, initTrigger]);
useEffect(() => {
if (!excelTrigger) return;
if (excelList && excelList.length > 0) {
downloadExcelFormat(
{
data: excelList as unknown as JSON[],
fileName: '시설별 수질현황',
sheetNameArray: ['시설별 수질현황'],
headerRange: 'A1:T1',
decimalArray1: [10, 11, 12, 15, 16, 17],
decimalArray3: [13, 14, 18, 19]
}
);
}
}, [excelList, excelTrigger]);
const chkVal = useCallback((returntype: ReturnType) => {
// setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]")
setUpheadList(returntype.partValue == 'R' ? upHeadList2 : returntype.partValue == 'G' ? upHeadList3 : upHeadList1);
setResetPage(true);
}, [upHeadList1, upHeadList2, upHeadList3]);
const excelDownload = useCallback(() => {
setExcelTrigger(true);
searchFcltyQltyList(ref.current, 1, 10000);
}, [searchFcltyQltyList]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
if (ref.current.partValue === 'A') { // 행정별
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'R') { // 유역별
if (!ref.current.regionValue || ref.current.regionValue === '0') {
alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'G') { // 환경청별
if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
return;
}
}
setIsExcelDownClick(true);
try {
await searchFcltyQltyList(ref.current, 1, 10000);
const latestExcelList = store.getState().FacilityWaterQltyMain.excelList || [];
if (latestExcelList.length > 0) {
downloadExcelFormat(
{
data: latestExcelList as unknown as JSON[],
fileName: '시설별 수질현황',
sheetNameArray: ['시설별 수질현황'],
headerRange: 'A1:T1',
decimalArray1: [10, 11, 12, 15, 16, 17],
decimalArray3: [13, 14, 18, 19]
}
);
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFcltyQltyList, store]);
const handlePageChange = useCallback((page: number) => {
setResetPage(false);
@@ -201,6 +230,7 @@ export default function ProcessFacilitySearch() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref} isAdmin={false} initSidoValue={"11"} />
<ListDiv>
@@ -224,4 +254,4 @@ export default function ProcessFacilitySearch() {
)}
</MainDiv>
);
}
}
@@ -34,6 +34,7 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
const { btnClass } = Common;
const [copyYearList, setCopyYearList] = useState<FlowRateModalInterface[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [activeTab, setActiveTab] = useState<string>("tab_term_year");
const prevExcelListRef = useRef<modalExcelType[] | null>(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 <div>로딩 중...</div>;
}
const excelDownload = () => {
const excelDownList: modalExcelType[] = [];
if (copyYearList.length > 0) {
@@ -206,14 +203,45 @@ 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],
// );
const rainRowClassName = useCallback(
(row: FlowRateModalInterface, rowIndex: number) => {
if (activeTab !== "tab_term_rain") 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-slate-50" : "";
},
[activeTab],
);
if (isLoading) {
return <div>로딩 중...</div>;
}
return (
<>
<UITab tabList={tabList} defaultValue="tab_term_year">
<UITab tabList={tabList} defaultValue="tab_term_year" onValueChange={setActiveTab}>
<Button className={btnClass} style={{ float: 'right' }} color="green" onClick={excelDownload}>
{"엑셀다운로드"}
</Button>
@@ -337,7 +365,8 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
/>
<div className="h-[370px] overflow-y-auto overflow-x-hidden">
<UiTable headName="유량현황" tableData={copyYearList} headlist={upHeadListFlowRateModalYear} pageSize={0} total={0}
cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]} />
cellClick={undefined} onPageChange={() => { }} className="h-[370px]" boldArray={[0, 1, 2]}
rowClassName={rainRowClassName} />
</div>
<div className="mt-20">
<UnderComment commentArray={["미처리하수 추정량 산식 =[(강우시 일별유입유량*강우시 일별유입BOD)-(청천시 연평균유입유량*청천시 연평균유입BOD)]/강우시 일별유입BOD)", "강우량 3mm 이상만 날과 강우영향일(강우일+2일)의 날"]} />
@@ -346,4 +375,4 @@ export default function FlowRateModal(props: { fcltyName: string; facilityCd: st
</UITab>
</>
);
}
}
@@ -5,13 +5,13 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import type { ExcelType } from "@/app/store/flowRate";
// import type { ExcelType } from "@/app/store/flowRate";
import { ContentsDiv, downloadExcelFormat, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import FlowRateModal from "./modal/page";
export default function ProcessFacilitySearch() {
@@ -21,6 +21,11 @@ export default function ProcessFacilitySearch() {
,initializeCommonData
,searchFlowRateList
} = useFoStore((state) => state);
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const searchInputRef = useRef<HTMLDivElement & HTMLInputElement>(null);
@@ -38,6 +43,11 @@ export default function ProcessFacilitySearch() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
flowRateSearchLabelArray
} = FlowRateSearch;
@@ -49,7 +59,6 @@ export default function ProcessFacilitySearch() {
upHeadList3,
flowRateList,
flowRateCount,
excelList,
isLoading,
} = FlowRateList;
@@ -57,20 +66,20 @@ export default function ProcessFacilitySearch() {
const [fcltCpct, setFcltCpct] = useState<string>("0");
const [fcltyName, setFcltyName] = useState<string>("");
const [operationValue, setOperationValue] = useState<string>("0");
const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear);
// const [widthSize, setWidthSize] = useState<string>("w-[120%]");
const [upheadList, setUpheadList] = useState<TableUpperProps[]>(upHeadList1);
const [resetPage, setResetPage] = useState<boolean>(false);
const prevExcelListRef = useRef<ExcelType[] | null>(null);
// const prevExcelListRef = useRef<ExcelType[] | null>(null);
// 모달 상태 추가
const [selectedRow, setSelectedRow] = useState<number | null>(null);
const [fcltyNm, setFcltyNm] = useState<string>("");
const [fcltyCd, setFcltyCd] = useState<string>("");
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
const searchFlowRate = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
const searchFlowRate = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr;
switch (partValue) {
@@ -89,9 +98,9 @@ export default function ProcessFacilitySearch() {
break;
}
if(partStr==='G'){
searchFlowRateList(pageNo, pageCnt, searchYearValue);
await searchFlowRateList(pageNo, pageCnt, searchYearValue);
}else{
searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchFlowRateList(pageNo, pageCnt, searchYearValue, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [searchFlowRateList, searchYearValue, fcltCpct, operationValue, fcltyName]);
@@ -99,7 +108,7 @@ export default function ProcessFacilitySearch() {
// setWidthSize("w-[120%]");
setUpheadList(upHeadList1)
// 상태값 설정
setSearchYearValue(selectSearchYear[0]?.val || "0");
setSearchYearValue(defaultSearchYear);
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
// SearchInputSelect 초기화
@@ -146,17 +155,6 @@ export default function ProcessFacilitySearch() {
}
}, [isInit, initializeCommonData, searchFlowRateList, selectSearchYear, searchFlowRate, initTrigger]);
useEffect(() => {
if(!excelTrigger) return;
if (excelList && excelList.length > 0) {
downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1', decimalArray0: [9,10,11,12,13,14] });
} else if (prevExcelListRef.current && prevExcelListRef.current.length > 0) {
alert('다운받을 데이터가 없습니다.');
}
prevExcelListRef.current = excelList;
}, [excelList, excelTrigger]);
const ref = useRef<ReturnType>({
partValue: '',
sidoValue: '11',
@@ -175,10 +173,37 @@ export default function ProcessFacilitySearch() {
setResetPage(true);
}, [upHeadList1, upHeadList2, upHeadList3]);
const excelDownload = useCallback(() => {
searchFlowRate(ref.current, 1, 10000);
setExcelTrigger(true);
}, [searchFlowRate]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
if (ref.current.partValue === 'A') { // 행정별
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'R') { // 유역별
if (!ref.current.regionValue || ref.current.regionValue === '0') {
alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'G') { // 환경청별
if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
return;
}
}
setIsExcelDownClick(true);
try {
await searchFlowRate(ref.current, 1, 10000);
const latestExcelList = store.getState().FlowRateList.excelList || [];
if (latestExcelList.length > 0) {
downloadExcelFormat({ data: JSON.parse(JSON.stringify(latestExcelList)), fileName: '시설별 유량현황', sheetNameArray: ['시설별 유량현황'], headerRange: 'A1:O1', decimalArray0: [9,10,11,12,13,14] });
} else {
alert('조회된 결과가 없습니다.');
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFlowRate, store]);
const total = flowRateCount;
return (
@@ -203,6 +228,7 @@ export default function ProcessFacilitySearch() {
queryClick={chkVal}
excelClick={excelDownload}
initClick={resetVal}
excelDisabled={isExcelDownClick}
ref={ref} isAdmin={false} initSidoValue={'11'}/>
<ListDiv>
<LoadingOverlay isLoading={isLoading} />
@@ -5,11 +5,11 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
@@ -26,6 +26,11 @@ export default function PlanSewage() {
, initializeCommonData
, searchPlanSewageList
} = useFoStore((state) => state) || { processAreaList: { processAreaList: [] } };
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -41,6 +46,11 @@ export default function PlanSewage() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
labelArray,
} = PlanSewageSearch;
@@ -51,7 +61,6 @@ export default function PlanSewage() {
upHeadList3,
planSewageList,
planSewageCount,
excelList,
isLoading,
} = PlanSewage;
@@ -85,11 +94,12 @@ export default function PlanSewage() {
// 시설상태
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
// 엑셀다운로드 트리거
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
const [excelTrigger, setExcelTrigger] = useState<boolean>(false);
/**
* 페이지 함수
*/
@@ -100,7 +110,7 @@ export default function PlanSewage() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYear(selectSearchYear[0]?.val || "0");
setSearchYear(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -113,24 +123,11 @@ export default function PlanSewage() {
searchPlanSewage(ref.current, 1, 10);
}
useEffect(() => {
if (!excelTrigger) return;
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '계획하수량 산정지표 현황',
sheetNameArray: ['계획하수량 산정지표 현황'],
headerRange: 'A1:M1'
});
}
}, [excelList, excelTrigger]);
/**
* 콜백함수
*/
// 조회
const searchPlanSewage = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => {
const searchPlanSewage = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt: number = 20) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -150,10 +147,10 @@ export default function PlanSewage() {
if (partStr === 'G') {
partValue = partValue === 'G' ? 'A' : partValue;
searchPlanSewageList(pageNo, pageCnt, searchYear, partValue);
await searchPlanSewageList(pageNo, pageCnt, searchYear, partValue);
}
else {
searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchPlanSewageList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchPlanSewageList, searchYear, fcltCpct]);
@@ -168,7 +165,7 @@ export default function PlanSewage() {
setInitTrigger(true);
}
}
}, [isInit, initializeCommonData, searchPlanSewageList, selectSearchYear, initTrigger, searchPlanSewage]);
}, [isInit, initializeCommonData, initTrigger, searchPlanSewage]);
const chkVal = useCallback((returntype: ReturnType) => {
// setWidthSize(returntype.partValue=='A' ?"w-[120%]":"w-[130%]")
@@ -177,10 +174,42 @@ export default function PlanSewage() {
}, [upHeadList1, upHeadList2, upHeadList3]);
// 엑셀다운로드
const excelDownload = useCallback((searchReturn: ReturnType) => {
searchPlanSewage(searchReturn, 1, 10000);
setExcelTrigger(true);
}, [searchPlanSewage]);
const excelDownload = useCallback(async (searchReturn: ReturnType) => {
if (isExcelDownClick) return;
if (ref.current.partValue === 'A') { // 행정별
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'R') { // 유역별
if (!ref.current.regionValue || ref.current.regionValue === '0') {
alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'G') { // 환경청별
if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
return;
}
}
setIsExcelDownClick(true);
try {
await searchPlanSewage(searchReturn, 1, 10000);
const latestExcelList = store.getState().PlanSewage.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: '계획하수량 산정지표 현황',
sheetNameArray: ['계획하수량 산정지표 현황'],
headerRange: 'A1:M1'
});
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchPlanSewage, store]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -211,6 +240,7 @@ export default function PlanSewage() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref} isAdmin={false} initSidoValue={"11"} />
<ListDiv>
@@ -224,4 +254,4 @@ export default function PlanSewage() {
</ListDiv>
</MainDiv>
);
}
}
@@ -5,11 +5,11 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import { useShallow } from 'zustand/react/shallow';
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import ProcessFacilityInfoModal from "./modal/page";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
@@ -29,6 +29,11 @@ export default function ProcessArea() {
searchProcessAreaList: state.searchProcessAreaList,
}))
);
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -42,6 +47,11 @@ export default function ProcessArea() {
btnClass,
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
processFacilityLabelArray,
} = ProcessAreaSearch;
@@ -50,7 +60,6 @@ export default function ProcessArea() {
upHeadList1,
processAreaList,
processAreaCount,
excelList,
isLoading,
} = ProcessArea;
@@ -64,7 +73,9 @@ export default function ProcessArea() {
const [fcltyCd, setFcltyCd] = useState<string>("");
const [resetPage, setResetPage] = useState<boolean>(false);
const [searchYearValue, setSearchYearValue] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYearValue, setSearchYearValue] = useState<string>(defaultSearchYear);
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
const ref = useRef<ReturnType>({
partValue: '',
@@ -78,8 +89,8 @@ export default function ProcessArea() {
sigunText: '',
});
const searchProcessArea = useCallback(({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => {
searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue);
const searchProcessArea = useCallback(async ({ sidoText, sigunText }: ReturnType, pageNo: number, pageCnt: number = 20) => {
await searchProcessAreaList(pageNo, pageCnt, sidoText, sigunText, searchYearValue);
}, [searchProcessAreaList, searchYearValue]);
// 조회
@@ -95,8 +106,8 @@ export default function ProcessArea() {
input.value = "";
}
}
setSearchYearValue(selectSearchYear[0]?.val || "0");
searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val || "0");
setSearchYearValue(defaultSearchYear);
searchProcessAreaList(1, 10, '', '', defaultSearchYear);
}
// 셀 클릭 시 모달 표시
@@ -116,24 +127,47 @@ export default function ProcessArea() {
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchProcessAreaList(1, 10, '', '', selectSearchYear[0]?.val || "0");
searchProcessAreaList(1, 10, '', '', defaultSearchYear);
}
}, [isInit, initializeCommonData, searchProcessAreaList]);
}, [isInit, initializeCommonData, searchProcessAreaList, defaultSearchYear]);
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '처리구역정보',
sheetNameArray: ['처리구역정보'],
headerRange: 'A1:W1'
});
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
// if (ref.current.partValue === 'A') { // 행정별
// if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
// alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'R') { // 유역별
// if (!ref.current.regionValue || ref.current.regionValue === '0') {
// alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'G') { // 환경청별
// if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
// alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// }
setIsExcelDownClick(true);
try {
await searchProcessArea(ref.current, 1, 10000);
const latestExcelList = store.getState().ProcessArea.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: '처리구역정보',
sheetNameArray: ['처리구역정보'],
headerRange: 'A1:W1'
});
} else {
alert('조회된 결과가 없습니다.');
}
} finally {
setIsExcelDownClick(false);
}
}, [excelList]);
const excelDownload = useCallback(() => {
searchProcessArea(ref.current, 1, 10000);
}, [searchProcessArea]);
}, [isExcelDownClick, searchProcessArea, store]);
const handlePageChange = useCallback((pageNo: number) => {
setResetPage(false);
@@ -159,6 +193,7 @@ export default function ProcessArea() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref}
isAdmin={true}
@@ -183,4 +218,4 @@ export default function ProcessArea() {
)}
</MainDiv>
);
}
}
@@ -6,11 +6,11 @@
"use client"
import UnderComment from "@/app/components/common/UnderComment";
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import ProcessFacilityInfoModal from "./modal/page";
export default function ProcessFacilitySearch() {
@@ -25,6 +25,11 @@ export default function ProcessFacilitySearch() {
//시설데이터 수질정보 조회
,searchProcessFacilityWaterQlty
} = useFoStore((state) => state) || { ProcessFacilityList: { processFacilityList: [], processFacilityCount: 0 }};
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -69,7 +74,6 @@ export default function ProcessFacilitySearch() {
upHeadList1,
upHeadList2,
upHeadList3,
excelList,
isLoading,
} = ProcessFacilityList;
@@ -89,6 +93,7 @@ export default function ProcessFacilitySearch() {
const [partValue, setPartValue] = useState<string>("A");
// const [widthSize, setWidthSize] = useState<string>("w-[120%]");
const [upHeadList, setUpheadList] = useState(upHeadList1);
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
/**
* 모달 상태 변수
@@ -149,13 +154,7 @@ export default function ProcessFacilitySearch() {
}
}, [partValue, upHeadList1, upHeadList2, upHeadList3]);
useEffect(() => {
if (excelList && excelList.length > 0) {
downloadExcel({ data: excelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' });
}
}, [excelList]);
const searchFcltyList = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => {
const searchFcltyList = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=10) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -172,7 +171,7 @@ export default function ProcessFacilitySearch() {
partStr = envPartValue !== '0' ? envPartValue:partValue;
break;
}
searchProcessFacility(pageNo, pageCnt, partStr, nameCd || '0', fcltCpct, operationValue, facilityPartValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchProcessFacility(pageNo, pageCnt, partStr, nameCd || '0', fcltCpct, operationValue, facilityPartValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
if(isSearch) {
setIsSearch(false);
}
@@ -235,9 +234,38 @@ export default function ProcessFacilitySearch() {
}
}
const excelDownload = useCallback(() => {
searchFcltyList(ref.current, 1, 10000);
}, [searchFcltyList]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
// if (ref.current.partValue === 'A') { // 행정별
// if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
// alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'R') { // 유역별
// if (!ref.current.regionValue || ref.current.regionValue === '0') {
// alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'G') { // 환경청별
// if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
// alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// }
setIsExcelDownClick(true);
try {
await searchFcltyList(ref.current, 1, 10000);
const latestExcelList = store.getState().ProcessFacilityList.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({ data: latestExcelList as unknown as JSON[], fileName: '처리시설 시설정보', sheetNameArray: ['처리시설 시설정보'], headerRange: 'A1:P1' });
} else {
alert('조회된 결과가 없습니다.');
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFcltyList, store]);
// 모달 닫기
const closeModal = () => {
@@ -266,6 +294,7 @@ export default function ProcessFacilitySearch() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref} isAdmin={false} />
<ListDiv>
@@ -299,4 +328,4 @@ export default function ProcessFacilitySearch() {
)}
</MainDiv>
);
}
}
+58 -27
View File
@@ -5,11 +5,11 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import UnderComment from "@/app/components/common/UnderComment";
@@ -26,6 +26,11 @@ export default function Rdi() {
,RdiSearch
,searchRdiList
} = useFoStore((state) => state) || { processAreaList: { processAreaList: [] }};
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -41,6 +46,11 @@ export default function Rdi() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
labelArray,
} = RdiSearch;
@@ -51,7 +61,6 @@ export default function Rdi() {
upHeadList3,
rdiList,
rdiCount,
excelList,
isLoading,
} = Rdi;
@@ -83,9 +92,10 @@ export default function Rdi() {
// 시설상태
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear);
// 엑셀 다운로드 트리거
const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false);
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
const [initTrigger, setInitTrigger] = useState<boolean>(false);
/**
@@ -99,7 +109,7 @@ export default function Rdi() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYear(selectSearchYear[0]?.val || "0");
setSearchYear(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -112,23 +122,11 @@ export default function Rdi() {
searchRdi(ref.current, 1, 10);
}
useEffect(() => {
if(!isInitExcelDownload) return ;
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: 'RDII추정',
sheetNameArray: ['RDII추정'],
headerRange: 'A1:R1'
});
}
}, [excelList, isInitExcelDownload]);
/**
* 콜백함수
*/
// 조회
const searchRdi = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
const searchRdi = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -147,10 +145,9 @@ export default function Rdi() {
}
if(partStr === 'G'){
searchRdiList(pageNo, pageCnt, searchYear);
await searchRdiList(pageNo, pageCnt, searchYear);
}else{
searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchRdiList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
}
}, [operationValue, fcltyName, searchRdiList, searchYear, fcltCpct]);
@@ -174,10 +171,43 @@ export default function Rdi() {
}, [upHeadList1, upHeadList2, upHeadList3]);
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchRdi(ref.current, 1, 5000);
setIsInitExcelDownload(true);
}, [searchRdi]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
// if (ref.current.partValue === 'A') { // 행정별
// if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
// alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'R') { // 유역별
// if (!ref.current.regionValue || ref.current.regionValue === '0') {
// alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// } else if (ref.current.partValue === 'G') { // 환경청별
// if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
// alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
// return;
// }
// }
setIsExcelDownClick(true);
try {
await searchRdi(ref.current, 1, 5000);
const latestExcelList = store.getState().Rdi.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: 'RDII추정',
sheetNameArray: ['RDII추정'],
headerRange: 'A1:R1'
});
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchRdi, store]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -209,6 +239,7 @@ export default function Rdi() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref} isAdmin={false} initSidoValue={"11"}/>
<ListDiv>
@@ -224,4 +255,4 @@ export default function Rdi() {
</ContentsDiv>
</MainDiv>
);
}
}
@@ -6,13 +6,13 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import { type TableUpperProps } from "@/app/store/common";
import type { SewageOccurProps } from "@/app/store/sewageOccur";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import SewageOccurModal from "./modal/page";
export default function PlanSewage() {
@@ -29,6 +29,11 @@ export default function PlanSewage() {
searchSewageOccurList: () => {},
calculateModalDataForAllFacilities: async () => []
};
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -44,6 +49,11 @@ export default function PlanSewage() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
labelArray,
} = SewageOccurSearch;
@@ -54,7 +64,6 @@ export default function PlanSewage() {
upHeadList3,
sewageOccurList,
sewageOccurCount,
excelList,
isLoading,
} = SewageOccur;
@@ -93,10 +102,9 @@ export default function PlanSewage() {
// 시설상태
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
// 엑셀다운로드 트리거
const [isInitExcelDownload, setIsInitExcelDownload] = useState<boolean>(false);
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear);
// 엑셀 조회 중 상태
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
/**
* 페이지 함수
*/
@@ -107,7 +115,7 @@ export default function PlanSewage() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYear(selectSearchYear[0]?.val || "0");
setSearchYear(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -116,7 +124,7 @@ export default function PlanSewage() {
input.value = "";
}
}
searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0");
searchSewageOccurList(1, 10, defaultSearchYear);
}
// 모달 닫기
@@ -139,32 +147,15 @@ export default function PlanSewage() {
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchSewageOccurList(1, 10, selectSearchYear[0]?.val || "0");
searchSewageOccurList(1, 10, defaultSearchYear);
}
}, [isInit, initializeCommonData, searchSewageOccurList, selectSearchYear]);
useEffect(() => {
if(!isInitExcelDownload) return ;
const timer = setTimeout(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '오수발생량 추정',
sheetNameArray: ['오수발생량 추정'],
headerRange: 'A1:O1'
});
}
}, 500); // 약간의 지연을 두고 다운로드 실행
return () => clearTimeout(timer);
}, [excelList, isInit, isInitExcelDownload]);
}, [isInit, initializeCommonData, searchSewageOccurList, defaultSearchYear]);
/**
* 콜백함수
*/
// 조회
const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -182,9 +173,10 @@ export default function PlanSewage() {
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchSewageOccurList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue
, fcltyName.trim() !== ""? fcltyName : undefined);
} else {
searchSewageOccurList(pageNo, pageCnt, searchYear);
await searchSewageOccurList(pageNo, pageCnt, searchYear);
}
}, [fcltCpct, operationValue, fcltyName, searchSewageOccurList, searchYear]);
@@ -195,10 +187,42 @@ export default function PlanSewage() {
}, [upHeadList1, upHeadList2, upHeadList3]);
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchFacilityPrecipitation(ref.current, 1, 5000);
setIsInitExcelDownload(true);
}, [searchFacilityPrecipitation]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
if (ref.current.partValue === 'A') { //
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'R') { // 유역별
if (!ref.current.regionValue || ref.current.regionValue === '0') {
alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'G') { // 환경청별
if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
return;
}
}
setIsExcelDownClick(true);
try {
await searchFacilityPrecipitation(ref.current, 1, 5000);
const latestExcelList = store.getState().SewageOccur.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: '오수발생량 추정',
sheetNameArray: ['오수발생량 추정'],
headerRange: 'A1:O1'
});
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFacilityPrecipitation]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -230,6 +254,7 @@ export default function PlanSewage() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref}
isAdmin={false}
@@ -7,11 +7,11 @@
*/
"use client"
import { useFoStore } from "@/app/store";
import { StoreContext, useFoStore } from "@/app/store";
import type { TableUpperProps } from "@/app/store/common";
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
import ListDiv from "@common/business_components/ui/list_div";
import { useCallback, useEffect, useRef, useState } from "react";
import { useCallback, useContext, useEffect, useRef, useState } from "react";
import UnderWaterInputModal from "./modal/page";
import type { UnderWaterProps } from "@/app/store/underWaterInput/types";
import LoadingOverlay from "@common/business_components/ui/loadingBar";
@@ -35,6 +35,11 @@ export default function UnderWaterInput() {
initializeCommonData: () => {},
searchUnderWaterList: () => {}
};
const store = useContext(StoreContext);
if (!store) {
throw new Error("StoreContext is not available. Ensure StoreProvider is mounted.");
}
const {
isInit,
@@ -50,6 +55,11 @@ export default function UnderWaterInput() {
btnClass
} = Common;
const defaultSearchYear =
selectSearchYear.find((item) => item.selected)?.val ||
selectSearchYear[0]?.val ||
"0";
const {
labelArray,
} = UnderWaterSearch;
@@ -60,7 +70,6 @@ export default function UnderWaterInput() {
upHeadList3,
underWaterList,
underWaterCount,
excelList,
isLoading,
} = UnderWater;
@@ -98,9 +107,9 @@ export default function UnderWaterInput() {
// 시설상태
const [operationValue, setOperationValue] = useState<string>("0");
// 조회기간
const [searchYear, setSearchYear] = useState<string>(selectSearchYear[0]?.val || "0");
const [searchYear, setSearchYear] = useState<string>(defaultSearchYear);
// 엑셀다운로드 트리거
const [isMount, setIsMount] = useState<boolean>(false);
const [isExcelDownClick, setIsExcelDownClick] = useState<boolean>(false);
/**
* 페이지 함수
@@ -112,7 +121,7 @@ export default function UnderWaterInput() {
// 상태값 설정
setFcltCpct(selectUpdownData[0]?.val || "0");
setOperationValue(selectOperationData[0]?.val || "0");
setSearchYear(selectSearchYear[0]?.val || "0");
setSearchYear(defaultSearchYear);
// SearchInputSelect 초기화
setFcltyName("");
if (searchInputRef.current) {
@@ -121,7 +130,7 @@ export default function UnderWaterInput() {
input.value = "";
}
}
searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0");
searchUnderWaterList(1, 10, defaultSearchYear);
}
// 모달 닫기
@@ -144,31 +153,15 @@ export default function UnderWaterInput() {
useEffect(() => {
if (!isInit) {
initializeCommonData();
searchUnderWaterList(1, 10, selectSearchYear[0]?.val || "0");
searchUnderWaterList(1, 10, defaultSearchYear);
}
}, [isInit, initializeCommonData, searchUnderWaterList, selectSearchYear]);
useEffect(() => {
if(!isMount) return ;
const timer = setTimeout(() => {
if (excelList && excelList.length > 0) {
downloadExcel({
data: excelList as unknown as JSON[],
fileName: '지하수유입량 추정',
sheetNameArray: ['지하수유입량 추정'],
headerRange: 'A1:O1'
});
}
}, 1000); // 약간의 지연을 두고 다운로드 실행
return () => clearTimeout(timer);
}, [excelList, isMount]);
}, [isInit, initializeCommonData, searchUnderWaterList, defaultSearchYear]);
/**
* 콜백함수
*/
// 조회
const searchFacilityPrecipitation = useCallback(({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
const searchFacilityPrecipitation = useCallback(async ({ partValue, regionValue, unitWaterShedValue, middleRegionValue, envPartValue, sidoValue, sigunValue }: ReturnType, pageNo: number, pageCnt:number=20) => {
let nameCd, partStr
switch (partValue) {
case 'R':
@@ -186,9 +179,10 @@ export default function UnderWaterInput() {
break;
}
if (partStr.length > 1 || fcltCpct !== '0' || operationValue!== '0' ||nameCd ||(fcltyName.trim() !== "" && fcltyName.trim() !== null)) {
searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue, fcltyName.trim() !== "" || fcltyName.trim() !== null ? fcltyName : undefined);
await searchUnderWaterList(pageNo, pageCnt, searchYear, partStr, nameCd || '0', fcltCpct, operationValue
, fcltyName.trim() !== ""? fcltyName : undefined);
} else {
searchUnderWaterList(pageNo, pageCnt, searchYear);
await searchUnderWaterList(pageNo, pageCnt, searchYear);
}
}, [fcltCpct, operationValue, fcltyName, searchUnderWaterList, searchYear]);
@@ -199,10 +193,42 @@ export default function UnderWaterInput() {
}, [upHeadList1, upHeadList2, upHeadList3]);
// 엑셀다운로드
const excelDownload = useCallback(() => {
searchFacilityPrecipitation(ref.current, 1, 5000);
setIsMount(true);
}, [searchFacilityPrecipitation]);
const excelDownload = useCallback(async () => {
if (isExcelDownClick) return;
if (ref.current.partValue === 'A') { //
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'R') { // 유역별
if (!ref.current.regionValue || ref.current.regionValue === '0') {
alert('엑셀 다운로드는 유역 조건을 선택한 후 이용 가능합니다.');
return;
}
} else if (ref.current.partValue === 'G') { // 환경청별
if (!ref.current.envPartValue || ref.current.envPartValue === '0') {
alert('엑셀 다운로드는 환경청 조건을 선택한 후 이용 가능합니다.');
return;
}
}
setIsExcelDownClick(true);
try {
await searchFacilityPrecipitation(ref.current, 1, 5000);
const latestExcelList = store.getState().UnderWater.excelList || [];
if (latestExcelList.length > 0) {
downloadExcel({
data: latestExcelList as unknown as JSON[],
fileName: '지하수유입량 추정',
sheetNameArray: ['지하수유입량 추정'],
headerRange: 'A1:O1'
});
} else {
alert("조회된 결과가 없습니다.");
}
} finally {
setIsExcelDownClick(false);
}
}, [isExcelDownClick, searchFacilityPrecipitation, store]);
// 페이지 변경
const handlePageChange = useCallback((page: number) => {
@@ -234,6 +260,7 @@ export default function UnderWaterInput() {
btnClass={btnClass}
queryClick={chkVal}
excelClick={excelDownload}
excelDisabled={isExcelDownClick}
initClick={resetVal}
ref={ref}
isAdmin={false}
@@ -260,4 +287,4 @@ export default function UnderWaterInput() {
)}
</MainDiv>
);
}
}
+15 -15
View File
@@ -12,6 +12,8 @@ import { getFetch, getFetchAreaList } from "@/app/components/api";
export type SelectDataType = {
text: string;
val: string;
selected?: boolean;
hidden?: boolean;
}
// grid header
export type TableUpperProps = {
@@ -161,22 +163,20 @@ const getYearData = () => {
const today = new Date();
const year = today.getFullYear();
const month = today.getMonth() + 1;
// 상반기(6월까지)는 2년 전, 하반기는 1년 전부터 시작
const startYear = month <= 6 ? (year - 2) : (year - 1);
const defaultIdx = month <= 6 ? 2 : 1;
const startYear = year;
const year1 = startYear;
const year2 = startYear - 1;
const year3 = startYear - 2;
const year4 = startYear - 3;
const year5 = startYear - 4;
return [
{ text: year1 + "년", val: year1.toString() },
{ text: year2 + "년", val: year2.toString() },
{ text: year3 + "년", val: year3.toString() },
{ text: year4 + "년", val: year4.toString() },
{ text: year5 + "년", val: year5.toString() },
]
// 최근 10개년도 제공 (기본값: 첫 번째 항목 선택)
return Array.from({ length: 10 }, (_, index) => {
const targetYear = startYear - index;
return {
text: `${targetYear}년`,
val: targetYear.toString(),
selected: index === defaultIdx,
};
});
}
const selectSearchYear: SelectDataType[] = getYearData();
@@ -486,4 +486,4 @@ export const CommonReducer = (
}
}
export type CommonStore = CommonType & CommonAction;
export type CommonStore = CommonType & CommonAction;
+54 -21
View File
@@ -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 },
@@ -282,15 +284,19 @@ const upHeadListModalChongIn: TableUpperProps[] = [
====================================*/
// 메인페이지
// 시설정보 수질 리스트 데이터 호출
const fetchFacilityWaterQltyList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string | undefined, nameCd?: string | undefined, fcltCpct?: string | undefined, operationValue?: string | undefined, fcltyNm?: string | undefined): Promise<{ data: FacilityWaterQltyProps[], count: number }> => {
const fetchFacilityWaterQltyList = async (
pageNo: number, pageSize: number, searchYear: string, partCd?: string | undefined
, nameCd?: string | undefined, fcltCpct?: string | undefined
, operationValue?: string | undefined, fcltyNm?: string | undefined
): Promise<{ data: FacilityWaterQltyProps[], count: number, status: number }> => {
try {
const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/fclt/qlty/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
return { data: res.data, count: res.count, status: res.status };
} catch (error) {
console.error('시설정보 수질현황 데이터를 가져오는데 실패했습니다:', error);
return { data: [], count: 0 };
return { data: [], count: 0, status: 300 };
}
}
@@ -457,8 +463,33 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
isLoading: true,
},
}));
const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
const rtnData = res.data.map(item => {
// const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
//---------
const waterQltyList: any[] = [];
let recordCount = 0;
if (pageSize < 5000) {
const res = await fetchFacilityWaterQltyList(pageNo, pageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
waterQltyList.push(...res.data);
recordCount = res.count;
} else {
for (let idx = 0; idx < pageSize; idx += 100) {
const tmpPageNo = Math.floor(idx / 100) + 1;
const tmpPageSize = Math.min(100, pageSize - idx);
const result = await fetchFacilityWaterQltyList(tmpPageNo, tmpPageSize, searchYear, part, nameCd, fcltCpct, operationValue, fcltyNm);
if (result?.status === 200 && Array.isArray(result?.data)) {
waterQltyList.push(...result.data);
}
recordCount = result?.count || 0;
if (result?.count < tmpPageNo * tmpPageSize) {
break; // 더 이상 데이터가 없으면 중지
}
}
}
//-------
// const rtnData = res.data.map(item => {
const rtnData = waterQltyList.map(item => {
dataFormSetting(item)
if (item.inflAssctBfrWqltTn) {
item.inflAssctBfrWqltTn = Number(Math.round(Number(item.inflAssctBfrWqltTn) * 1000) / 1000).toFixed(3);
@@ -500,11 +531,12 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
});
const excelDownList: ExcelType[] = [];
if (pageSize > 5000) {
res.data.forEach(item => {
// res.data.forEach(item => {
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({
@@ -513,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),
@@ -531,11 +563,12 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
});
});
} else {
res.data.forEach((item: FacilityWaterQltyProps) => {
// res.data.forEach((item: FacilityWaterQltyProps) => {
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;
});
@@ -545,7 +578,7 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
FacilityWaterQltyMain: pageSize < 5000 ? {
...state.FacilityWaterQltyMain,
facilityWaterQltyList: rtnData,
facilityWaterQltyCount: res.count,
facilityWaterQltyCount: recordCount,
isLoading: false,
} : {
...state.FacilityWaterQltyMain,
+40 -7
View File
@@ -175,11 +175,11 @@ const fetchFlowRateList = async (pageNo: number, pageSize: number, searchYear: s
const tailStr = partCd ? '/' + partCd + '/' + nameCd + '/' + fcltCpct + '/' + operationValue + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/fclt/flow/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
return { data: res.data, count: res.count, status: res.status}
} catch (error) {
console.error('시설정보 유량현황 데이터를 가져오는데 실패했습니다:', error);
console.log(error);
return { data: [], count: 0 };
return { data: [], count: 0, status: 300 };
}
}
@@ -279,8 +279,41 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
isLoading: true,
},
}));
const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
const data = res.data;
// const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
//---------
const flowRateList: any[] = [];
const results: any[] = [];
if (pageSize < 5000) {
const res = await fetchFlowRateList(pageNo, pageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
flowRateList.push(...res.data);
results.push(res);
} else {
for (let idx = 0; idx < pageSize; idx += 100) {
const tmpPageNo = Math.floor(idx / 100) + 1;
const tmpPageSize = Math.min(100, pageSize - idx);
const result = await fetchFlowRateList( tmpPageNo, tmpPageSize, searchYear, partCd, nameCd, fcltCpct, operationValue, fcltyNm);
results.push(result);
if (result?.count < tmpPageNo * tmpPageSize) {
break; // 더 이상 데이터가 없으면 중지
}
}
// console.log(results);
// 결과를 합치기
for (const res of results) {
if (res?.status === 200 && Array.isArray(res?.data)) {
flowRateList.push(...res.data);
}
}
}
//---------
const recordCount = results[0]?.count || 0;
//-------
// const data = res.data;
const data = flowRateList;
const excelDownList: ExcelType[] = [];
const rtnData = data.map((item: flowRateListProps) => {
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
@@ -316,7 +349,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
FlowRateList: pageSize < 5000 ? {
...state.FlowRateList,
flowRateList: rtnData,
flowRateCount: res.count,
flowRateCount: recordCount,
isLoading: false,
} : {
...state.FlowRateList,
@@ -355,7 +388,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
const yearSunnyAmnt = sunnyDay > 0 ? sunnyInflAmnt / sunnyDay : 0; // 청천시 연평균유입유량
const yearSunnyBod = sunnyDay > 0 ? sunnyBod / sunnyDay : 0; // 청천시 연평균유입BOD
console.log(inflData);
//console.log(inflData);
const rtnData = inflData.map((item: FlowRateModalProps) => {
const targetWqItem = wqltData?.find(wqitem => wqitem.msrDt === item.msrDt.replaceAll('-', ''));
const dayBod = targetWqItem ? Number(targetWqItem.inflAssctBfrWqltBod) : 0;
@@ -371,7 +404,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
: item.msrDt,
};
});
console.log(rtnData);
//console.log(rtnData);
set((state: FlowRateSearchType) => ({
...state,
FlowRateModal: {
+41 -8
View File
@@ -4,6 +4,7 @@ import { getFetch, postFetch } from "@/app/components/api";
import { type ApiResponse } from "../underWaterInput";
// import CalcRainEffect from "@/app/components/common/CalcRainEffect";
import { roundUp } from "../common";
// import { fetchSweageOccurListFlow, fetchWtrUsgYmList } from "../sewageOccur";
export type { TableUpperProps };
/**
* 처리시설 연간 운영현황 > 계획하수량 산정지표 현황
@@ -101,14 +102,15 @@ const planSewageList: PlanSewageProps[] = [
* @param oprtngSttsCd : 운영 상태 코드
* @param facilityName : 시설명
*/
const fetchPlanSewageList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const fetchPlanSewageList = async (pageNo: number, pageSize: number, searchYear: string, partCd?: string, nameCd?: string
, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
const tailStr = partCd ? '/' + partCd + '/' + (nameCd || '0') + '/' + (fcltCpct || '0') + '/' + (operationValue || '0') + '/0' + (fcltyNm && fcltyNm !== '' ? '/' + fcltyNm : '') : '';
const url = '/prcsFclt/info/plan/' + pageNo + '/' + pageSize + '/' + searchYear + tailStr;
const res = await getFetch('fo', url);
return { data: res.data, count: res.count }
}
// 분류식화율 구하기 위한 api 호출
// 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100
const fetchPlanZoneList = async (searchYear: string, fcltCdList: string[]) => {
try {
const res = await postFetch('fo', '/prcsFclt/info/planZone/' + searchYear, fcltCdList);
@@ -251,19 +253,50 @@ export const planSewageReducer: (set: (fn: (state: PlanSewageType) => PlanSewage
const excelDownList: ExcelType[] = [];
// const data = res.data
const planZoneRes: any = await fetchPlanZoneList(searchYear, fcltCdList);
const planZoneList = planZoneRes?.data;
// 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100
// const planZoneRes: any = await fetchPlanZoneList(searchYear, fcltCdList);
// const detailRes: any = await fetchFlow(searchYear, fcltCdList);
//---------
const planZoneList: any[] = [];
const flowDetailList: Record<string, any[]> = {};
// const results: any[] = [];
const flowDetailResults: any[] = [];
for (let idx = 0; idx < fcltCdList.length; idx += 100) {
const slicedItems = fcltCdList.slice(idx, idx + 100);
const result = await fetchPlanZoneList(searchYear, slicedItems); // 분류식화율 구하기 위한 api 호출 : 분류식화율 = 분류식지역 면적(㎢) / 처리​구역 면적합계(㎢) × 100
const flowResult = await fetchFlow(searchYear, slicedItems);
if (result?.status === 200 && Array.isArray(result?.data)) {
planZoneList.push(...result.data);
}
flowDetailResults.push(flowResult);
}
//console.log(results);
// 결과를 합치기
for (const res of flowDetailResults) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
if (!flowDetailList[keyStr]) flowDetailList[keyStr] = [];
flowDetailList[keyStr].push(...(value as any[]));
}
}
}
//-------
// const planZoneList = planZoneRes?.data;
planZoneList?.forEach(item => {
const planSewageItem = planSewageList.find(item2 => item2.bscFctCd == item.bscFctCd);
if (planSewageItem) {
planSewageItem.sprtProcZoneAr = item.sprtProcZoneAr;
planSewageItem.procZoneSm = item.procZoneSm;
planSewageItem.sprtProcZoneAr = item.sprtProcZoneAr; // 처리구역면적_분류식
planSewageItem.procZoneSm = item.procZoneSm; //처리구역면적합계
}
});
const detailRes: any = await fetchFlow(searchYear, fcltCdList);
//const detailRes: any = await fetchFlow(searchYear, fcltCdList);
for (const item of planSewageList) {
const detailList = detailRes?.data[item.bscFctCd];
// const detailList = detailRes?.data[item.bscFctCd];
const detailList = flowDetailList[item.bscFctCd];
let avgInflAmnt = 0;
let sumInflAmntSunny = 0;
+3 -1
View File
@@ -418,7 +418,9 @@ const gridListFcltyWaterQltyInfo: fcltyWaterQltyInfoProps[] = [
*/
export const fetchFacilityListInit = async (pageNo: number, pageSize: number, partValue?: string, nameCd?: string, fcltCpct?: string, oprtngSttsCd?: string, facilityPartValue?: string, facilityName?: string): Promise<{ data: facilityListProps[], count: number }> => {
try {
const tailStr = partValue ? '/' + (partValue === 'G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd + '/' + facilityPartValue + (facilityName && facilityName !== '' ? '/' + facilityName : '') : '';
const tailStr = partValue ? '/' + (partValue === 'G' ? 'A' : partValue) + '/' + nameCd + '/' + fcltCpct + '/' + oprtngSttsCd
+ (facilityPartValue && facilityPartValue !== ''? '/' + facilityPartValue : '')
+ (facilityName && facilityName !== ''? '/' + facilityName : '') : '';
const url = '/prcsFclt/info/' + pageNo + '/' + pageSize + tailStr;
const res = await getFetch('fo', url);
res.data.forEach((item: Record<string, unknown>) => {
+25 -7
View File
@@ -322,15 +322,33 @@ export const rdiReducer:(set:SetStateFunction)=>RdiActions=(set: SetStateFunctio
fcltCdList.push(item.bscFctCd);
});
const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList);
console.log(rdiiDetailListRes);
// const rdiiDetailListRes : any = await fetchFacilityRdiiDetailList(searchYear, fcltCdList);
//---------
const rainDetailList: Record<string, any[]> = {};
const results: any[] = [];
for (let idx = 0; idx < fcltCdList.length; idx += 100) {
const slicedItems = fcltCdList.slice(idx, idx + 100);
const result = await fetchFacilityRdiiDetailList(searchYear, slicedItems);
results.push(result);
}
//console.log(results);
// 결과를 합치기
for (const res of results) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
if (!rainDetailList[keyStr]) rainDetailList[keyStr] = [];
rainDetailList[keyStr].push(...(value as any[]));
}
}
}
//-------
// console.log(rdiiDetailListRes);
for (const item of rtnData) {
//const fcltyCd = item.bscFctCd;
//const res: any = await fetchFacilityWaterQltyListHist(searchYear, fcltyCd);
//const rdiiDetailList = res.data.wqltObjs;
const rdiiDetailList = rdiiDetailListRes?.data[item.bscFctCd];
//console.log(rdiiDetailListRes);
// const rdiiDetailList = rdiiDetailListRes?.data[item.bscFctCd];
const rdiiDetailList = rainDetailList[item.bscFctCd];
let rtnWinterInflBod = 0;
let rtnSummerBodInfl = 0;
+44 -8
View File
@@ -4,6 +4,7 @@ import { roundNumber } from "@/app/components/common/DataForm";
import { OSU_PERCENT } from "../common";
import type { TableUpperProps } from "../dashboard";
import { fetchFacilityListInit } from "../processFacility";
// import { fetchFacilityRainDetailList } from "../facilityPrecipitation";
export type { TableUpperProps };
/**
@@ -328,17 +329,52 @@ export const sewageOccurReducer: (set: any) => SewageOccurActions = (set: any) =
});
});
const soccurDetailRes: any = await fetchSweageOccurListFlow(searchYear, fcltCdList);
const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList);
// const wtrUsgMap : Record<string, number> = {};
// wtrUsgRes.data.forEach(fclt => {
// wtrUsgMap[fclt.bscFctCd] = fclt.wtrUsg;
// });
// const soccurDetailRes: any = await fetchSweageOccurListFlow(searchYear, fcltCdList);
// const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList);
//---------
const rainDetailList: Record<string, any[]> = {};
const wtrDetailList: Record<string, any[]> = {};
const results: any[] = [];
const wtrResults: any[] = [];
for (let idx = 0; idx < fcltCdList.length; idx += 100) {
const slicedItems = fcltCdList.slice(idx, idx + 100);
const result = await fetchSweageOccurListFlow(searchYear, slicedItems);
const wtrResult = await fetchWtrUsgYmList(searchYear, slicedItems);
results.push(result);
wtrResults.push(wtrResult);
}
//console.log(results);
// 결과를 합치기
for (const res of results) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
//rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])];
if (!rainDetailList[keyStr]) rainDetailList[keyStr] = [];
rainDetailList[keyStr].push(...(value as any[]));
}
}
}
for (const res of wtrResults) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
// wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])];
if (!wtrDetailList[keyStr]) wtrDetailList[keyStr] = [];
wtrDetailList[keyStr].push(...(value as any[]));
}
}
}
//-------
let maxEstimationSewage = 0, minEstimationSewage = 999999999;
for (const item of sewageOccurPropsList) {
const detailList = soccurDetailRes?.data[item.bscFctCd];
const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd];
//const detailList = soccurDetailRes?.data[item.bscFctCd];
// const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd];
const detailList = rainDetailList[item.bscFctCd];
const wtrUsgYmList = wtrDetailList[item.bscFctCd];
item.swageChangePercent = 90;
let sumChungcunDay = 0; // 청천일수
+50 -6
View File
@@ -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) {
@@ -368,13 +376,49 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater
});
});
const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList);
const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList);
// const soccurDetailRes: any = await fetchDetailListFlow(searchYear, fcltCdList);
// const wtrUsgYmRes: any = await fetchWtrUsgYmList(searchYear, fcltCdList);
//---------
const rainDetailList: Record<string, any[]> = {};
const wtrDetailList: Record<string, any[]> = {};
const results: any[] = [];
const wtrResults: any[] = [];
for (let idx = 0; idx < fcltCdList.length; idx += 100) {
const slicedItems = fcltCdList.slice(idx, idx + 100);
const result = await fetchDetailListFlow(searchYear, slicedItems);
const wtrResult = await fetchWtrUsgYmList(searchYear, slicedItems);
results.push(result);
wtrResults.push(wtrResult);
}
//console.log(results);
// 결과를 합치기
for (const res of results) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
//rainDetailList[keyStr] = [...(rainDetailList[keyStr] || []), ...(value as any[])];
if (!rainDetailList[keyStr]) rainDetailList[keyStr] = [];
rainDetailList[keyStr].push(...(value as any[]));
}
}
}
for (const res of wtrResults) {
if (res.status === 200 && res.data) {
for (const [key, value] of Object.entries(res.data)) {
const keyStr = String(key);
// wtrDetailList[keyStr] = [...(wtrDetailList[keyStr] || []), ...(value as any[])];
if (!wtrDetailList[keyStr]) wtrDetailList[keyStr] = [];
wtrDetailList[keyStr].push(...(value as any[]));
}
}
}
//-------
for (const item of underWaterPropsList) {
const detailList = soccurDetailRes?.data[item.bscFctCd];
const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd];
// const detailList = soccurDetailRes?.data[item.bscFctCd];
// const wtrUsgYmList = wtrUsgYmRes?.data[item.bscFctCd];
const detailList = rainDetailList[item.bscFctCd];
const wtrUsgYmList = wtrDetailList[item.bscFctCd];
let chungcunSumFlow = 0; // 청천유입량
let sumChungcunDay = 0; // 청천일수
@@ -688,4 +732,4 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater
}))
}
}
}
}
@@ -1,3 +1,4 @@
"use client";
import { createContext, useState } from "react";
interface PromptContext {
@@ -26,6 +26,7 @@ type SearchBaseType = {
leftSelectClassName?: string;
buttonOrder?: ("query" | "init" | "excel")[];
initSidoValue?: string | '';
excelDisabled?: boolean;
}
export type ReturnType = {
partValue: string;
@@ -60,6 +61,7 @@ function SearchBaseForm ({
leftSelectClassName,
buttonOrder,
initSidoValue='',
excelDisabled=false,
}: SearchBaseType) {
const [partValue, setPartValue] = useState<string>("A");
const [sidoValue, setSidoValue] = useState<string>(initSidoValue?initSidoValue:"0");
@@ -87,7 +89,7 @@ function SearchBaseForm ({
);
case "excel":
return (
<Button className={btnClass} color="green" onClick={excelDownload} key="excel">
<Button className={btnClass} color="green" onClick={excelDownload} key="excel" disabled={excelDisabled}>
{excelName ? excelName : "엑셀다운로드"}
</Button>
);
@@ -191,4 +193,4 @@ function SearchBaseForm ({
}
export { SearchBaseForm };
@@ -1,7 +1,8 @@
// selectBox
import { Label } from "@common/components";
import React, { useEffect, useState } from "react";
// import React, { useEffect, useState } from "react";
import React, { useState } from "react";
import {
Select,
SelectContent,
@@ -15,6 +16,7 @@ interface SelectBox1 {
text: string;
val: string | number;
hidden?: boolean;
selected?: boolean;
}
const SelectBox = React.forwardRef<
@@ -51,18 +53,22 @@ const SelectBox = React.forwardRef<
const [isOpen, setIsOpen] = useState(false);
// hidden이 true인 항목만 드롭다운에서 제외
const visibleItems = selectArray.filter((item) => !item.hidden);
const selectedItem = visibleItems.find((item) => item.selected);
const resolvedValue =
value === undefined && selectedItem ? selectedItem.val : value;
// 현재 값이 hidden 항목이거나 빈 값인 경우 undefined로 설정하여 placeholder가 표시되도록 함
const currentValue =
value !== undefined &&
resolvedValue !== undefined &&
hiddenItem &&
(String(value) === String(hiddenItem.val) ||
value === "" ||
value === "0" ||
value === 0)
(String(resolvedValue) === String(hiddenItem.val) ||
resolvedValue === "" ||
resolvedValue === "0" ||
resolvedValue === 0)
? undefined
: value !== undefined
? String(value)
: resolvedValue !== undefined
? String(resolvedValue)
: undefined;
return (
@@ -16,14 +16,16 @@ export type ChkClass = {
chk: boolean;
readonly: boolean;
};
type UiTableProps = {
type UiTableProps<T extends object> = {
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;
rowClassName?: (row: T, rowIndex: number) => string;
className?: string;
resetPageNo?: boolean;
children?: React.ReactNode | undefined;
@@ -46,7 +48,7 @@ type UiHeadProps = {
colSpan?: number;
};
export function UiTable({
export function UiTable<T extends object = Record<string, unknown>>({
tableData,
headlist,
pageSize,
@@ -55,6 +57,8 @@ export function UiTable({
children,
cellClick,
onPageChange,
cellClassName,
rowClassName,
className = "",
resetPageNo = false,
boldArray = [],
@@ -63,7 +67,7 @@ export function UiTable({
curPage = 1,
headButton = undefined,
widthFixed = false
}: UiTableProps) {
}: UiTableProps<T>) {
const [cur, setCur] = useState<number>(curPage);
const [idx, setIdx] = useState<number>(index);
const [headerHeight, setHeaderHeight] = useState<number>(0);
@@ -148,8 +152,8 @@ export function UiTable({
</TableHeader>
<TableBody className="text-center">
{tableData.length > 0 ? (
tableData?.map((el: Record<string, unknown>, index) => (
<TableRow key={`row-${index}`}>
tableData?.map((el: T, index) => (
<TableRow key={`row-${index}`} className={rowClassName ? rowClassName(el, index) : ""}>
{headlist
.filter((item) => item.visible != false)
.map(
@@ -163,29 +167,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<string, unknown>)[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,
",",
);
})()}
</TableCell>
) : (
<TableCell
@@ -194,47 +201,49 @@ export function UiTable({
: cellClick
? "cursor-pointer"
: ""
} mt-[${boldArray.length * 40}px] whitespace-pre-line`}
} ${cellClassName ? cellClassName(el, head.id, index) : ""} mt-[${boldArray.length * 40}px] whitespace-pre-line`}
onClick={() => 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<string, unknown>)[head.id];
return typeof cellValue === "object" &&
cellValue !== null &&
"chk" in (cellValue as object) &&
"readonly" in (cellValue as object) ? (
<Checkbox
checked={
(el[head.id] as ChkClass)?.chk === true
(cellValue as ChkClass)?.chk === true
}
onCheckedChange={(checked) => {
{
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);
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
) : typeof el[head.id] === "boolean" ? (
) : typeof cellValue === "boolean" ? (
<Checkbox
checked={el[head.id] === true}
checked={cellValue === true}
onCheckedChange={(checked) => {
el[head.id] = checked;
(el as Record<string, unknown>)[head.id] = checked;
}}
>
<Check className="h-6 w-6 text-primary" />
</Checkbox>
) : 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 +255,12 @@ export function UiTable({
)
.join(".")
) : (
String(el[head.id] ?? "").replace(
String(cellValue ?? "").replace(
/\B(?=(\d{3})+(?!\d))/g,
",",
)
)
);
})()
}
</TableCell>
)),
@@ -34,6 +34,7 @@ export function NoticePopover() {
queryKey: [ENDPOINT.CMS_SERVICE.NOTICE_USER],
queryFn: () => getNoticeUserList(userId!),
enabled: !!userId,
select: (data) => data.content.filter((item) => item.notReadYn === "N"),
});
const { data: unreadNoticeCount } = useQuery({
@@ -53,11 +54,11 @@ export function NoticePopover() {
};
const handleSelectAll = () => {
if (noticeUserList?.content) {
if (selectedNoticeIds.length === noticeUserList.content.length) {
if (noticeUserList) {
if (selectedNoticeIds.length === noticeUserList.length) {
setSelectedNoticeIds([]);
} else {
const allIds = noticeUserList.content.map((item) => item.notiId);
const allIds = noticeUserList.map((item) => item.notiId);
setSelectedNoticeIds(allIds);
}
}
@@ -79,9 +80,9 @@ export function NoticePopover() {
}
};
const isAllSelected = noticeUserList?.content
? selectedNoticeIds.length === noticeUserList.content.length &&
noticeUserList.content.length > 0
const isAllSelected = noticeUserList
? selectedNoticeIds.length === noticeUserList.length &&
noticeUserList.length > 0
: false;
useEffect(() => {
@@ -107,7 +108,7 @@ export function NoticePopover() {
</Label>
</div>
<ul>
{noticeUserList?.content?.map((item) => (
{noticeUserList?.map((item) => (
<li
key={item.notiId}
className={cn(