Merge remote-tracking branch 'origin/main' into iipbs/dm/dev
This commit is contained in:
@@ -25,3 +25,4 @@ apps/fo/.next/**/*
|
||||
pnpm-lock.yaml
|
||||
settings.json
|
||||
.npmrc
|
||||
.cursor
|
||||
@@ -15,4 +15,3 @@ export async function POST() {
|
||||
cookieStore.delete(CLAIM_NAME);
|
||||
return NextResponse.json({ message: "Logged out" }, { status: 200 });
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AUTH_USER_ID, CLAIM_NAME } from "@/shared/config";
|
||||
import { ACCESS_TOKEN, AUTH_USER_ID, CLAIM_NAME, REFRESH_TOKEN } from "@/shared/config";
|
||||
import { getCookie, setCookie, removeCookie } from "@/shared/lib";
|
||||
|
||||
export class TokenManager {
|
||||
@@ -76,6 +76,8 @@ export class TokenManager {
|
||||
|
||||
this.removeToken(CLAIM_NAME);
|
||||
this.removeToken(AUTH_USER_ID);
|
||||
this.removeToken(REFRESH_TOKEN);
|
||||
this.removeToken(ACCESS_TOKEN);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { getCoreRowModel } from "@tanstack/react-table";
|
||||
import { PostApi, type MyPost } from "@/entities/post";
|
||||
import { PostApi, type MyPost, type NoticePost } from "@/entities/post";
|
||||
import { ENDPOINT } from "@/shared/config";
|
||||
import { useDataTable } from "@/shared/lib";
|
||||
import {
|
||||
@@ -23,15 +23,21 @@ const MyPostList: React.FC = () => {
|
||||
}),
|
||||
});
|
||||
|
||||
const handleMyPostRowClick = (row: MyPost) => {
|
||||
router.push(`/cms/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`);
|
||||
};
|
||||
|
||||
const { tableComponent: myPostTableComponent } = useDataTable({
|
||||
query: myPostQuery,
|
||||
tableOptions: {
|
||||
columns: myPostTableColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
columns: myPostTableColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
},
|
||||
dataTableOptions: {
|
||||
variant: "line",
|
||||
variant: "line",
|
||||
onRowClick: handleMyPostRowClick
|
||||
},
|
||||
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -26,7 +26,7 @@ const NoticeList: React.FC = () => {
|
||||
});
|
||||
|
||||
const handleNoticePostRowClick = (row: NoticePost) => {
|
||||
router.push(`/bbs/bbsnotice/${row.bbsId}/${row.pstNo}`);
|
||||
router.push(`/cms/${row.bbsTypeCd.toLowerCase()}/${row.bbsId}/${row.pstNo}`);
|
||||
};
|
||||
|
||||
const handleMoreClick = () => {
|
||||
@@ -40,12 +40,12 @@ const NoticeList: React.FC = () => {
|
||||
const { tableComponent: noticePostTableComponent } = useDataTable({
|
||||
query: noticePostQuery,
|
||||
tableOptions: {
|
||||
columns: noticePostTableColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
columns: noticePostTableColumns,
|
||||
getCoreRowModel: getCoreRowModel(),
|
||||
},
|
||||
dataTableOptions: {
|
||||
variant: "line",
|
||||
onRowClick: handleNoticePostRowClick,
|
||||
variant: "line",
|
||||
onRowClick: handleNoticePostRowClick,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
keepPreviousData,
|
||||
useQuery,
|
||||
@@ -75,7 +75,7 @@ function AddAdminDialog() {
|
||||
});
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, pagination, "normal-user"],
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, "findPageUser", pagination],
|
||||
queryFn: () =>
|
||||
UserApi.findPageUser({
|
||||
...userSearchQuery,
|
||||
@@ -181,6 +181,21 @@ function AddAdminDialog() {
|
||||
query.refetch();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
setRowSelection({});
|
||||
setSelectedGroupId("");
|
||||
setUserSearchQuery({
|
||||
keywordType: "userName",
|
||||
keyword: "",
|
||||
});
|
||||
setPagination({ pageIndex: 0, pageSize: 10 });
|
||||
queryClient.removeQueries({
|
||||
queryKey: [ENDPOINT.USER_SERVICE.USERS, "findPageUser"],
|
||||
});
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
import { memo } from "react";
|
||||
import { memo, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
@@ -140,6 +140,10 @@ const LwpoCodeManagementDialog = memo(
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) form.reset();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange} {...props}>
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { memo } from "react";
|
||||
import { memo, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -96,6 +96,10 @@ const UpCodeManagementDialog = memo(
|
||||
if (await confirm(confirmMessage)) callback(data);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) form.reset();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange} {...props}>
|
||||
<DialogTrigger asChild>{children}</DialogTrigger>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -48,25 +48,14 @@ function MenuAuthorityDialog({ groupId }: MenuAuthorityDialogProps) {
|
||||
keywordType: "",
|
||||
siteId: "",
|
||||
});
|
||||
|
||||
const handleReset = () => {
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
setKeywordType("");
|
||||
setSiteId("");
|
||||
setSearchParams({
|
||||
keyword: "",
|
||||
keywordType: "",
|
||||
siteId: "",
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: [ENDPOINT.CMS_SERVICE.MENU_AUTHRTS, groupId, searchParams],
|
||||
queryFn: () => MenuAuthorityApi.getGroupMenuAuthorityList({
|
||||
groupId,
|
||||
...searchParams
|
||||
}),
|
||||
queryFn: () =>
|
||||
MenuAuthorityApi.getGroupMenuAuthorityList({
|
||||
groupId,
|
||||
...searchParams,
|
||||
}),
|
||||
enabled: open && !!groupId,
|
||||
});
|
||||
|
||||
@@ -117,6 +106,21 @@ function MenuAuthorityDialog({ groupId }: MenuAuthorityDialogProps) {
|
||||
});
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
if (inputRef.current) inputRef.current.value = "";
|
||||
setSiteId("");
|
||||
setKeywordType("");
|
||||
setSearchParams({
|
||||
keyword: "",
|
||||
keywordType: "",
|
||||
siteId: "",
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) handleReset();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, memo } from "react";
|
||||
import { useState, memo, useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
@@ -90,6 +90,10 @@ const ManagementAuthorityDialog = memo(
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) form.reset();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger asChild>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useRef } from "react";
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { getCoreRowModel, type ColumnDef } from "@tanstack/react-table";
|
||||
import {
|
||||
@@ -113,6 +113,10 @@ function MappingRoleDialog({
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) handleReset();
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={onOpenChange} {...props}>
|
||||
<DialogTrigger asChild>
|
||||
|
||||
@@ -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",
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ export default function ProcessFacilitySearch({searchYear = '', fcltyList = []}:
|
||||
(head.id === 'flowRate' && index === 0)?<TableCell rowSpan={5} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'flowRate' && index === 5)?<TableCell rowSpan={6} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'flowRate' && index === 11)?<TableCell rowSpan={2} className="text-center" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{Number.isNaN(el[head.id]) ? "" : el[head.id]}</TableCell>:
|
||||
(head.id === 'groundWaterAvg'||head.id === 'groundWaterSummer'||head.id === 'groundWaterWinter')&&(index === 7)?<TableCell rowSpan={6} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'rdi'&&index === 0)?<TableCell rowSpan={7} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
(head.id === 'rdi'&&index === 7)?<TableCell rowSpan={6} className="text-right" style={{ whiteSpace: 'pre-line' }} key={head.id+index}>{el[head.id]}</TableCell>:
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"use client"
|
||||
import { useFoStore } from "@/app/store";
|
||||
import {
|
||||
ContentsDiv, downloadExcel, downloadMultipleExcel, filePickedBlobArray, MainDiv
|
||||
ContentsDiv, downloadExcelFormat, downloadMultipleExcel, filePickedBlobArrayFormat, MainDiv
|
||||
, SelectBox, UITab, type SelectDataType
|
||||
} from "@common/business_components";
|
||||
import { Button, TabsContent } from "@common/components/ui";
|
||||
@@ -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',
|
||||
@@ -138,13 +142,11 @@ export default function DashBoard() {
|
||||
}
|
||||
}
|
||||
|
||||
const excelDownload = () => {
|
||||
const excelDownload = async () => {
|
||||
if (!fcltyList.bscFctCd) return;
|
||||
|
||||
switch (activeTab) {
|
||||
case 'facilityInfo': // 시설정보 및 운영현황
|
||||
searchOperationStatus(false, searchYear, fcltyList.bscFctCd).then(() => { setTimeout(() => { makeExcelData(); }, 200); });
|
||||
|
||||
const makeExcelData = async () => {
|
||||
fetch(`/mainDashBoard.xlsx`, {}).then(async (response) => {
|
||||
if (!response.ok) {
|
||||
@@ -194,20 +196,27 @@ export default function DashBoard() {
|
||||
headerNum: 3,
|
||||
headerRange: 'A1:G2',
|
||||
sheetName: '운영실태',
|
||||
startCol: 'A'
|
||||
startCol: 'A',
|
||||
decimalRange0: 'B3:G2,B9:B11',
|
||||
decimalRange1: 'B5:G5',
|
||||
},
|
||||
{
|
||||
data: excelData2,
|
||||
headerNum: 4,
|
||||
headerRange: 'A1:Q3',
|
||||
sheetName: '운영실태',
|
||||
startCol: 'C'
|
||||
startCol: 'C',
|
||||
decimalRange0: 'C4:O8',
|
||||
decimalRange1: 'C9:L10,M11:O11',
|
||||
decimalRange3: 'C11:L16',
|
||||
}
|
||||
];
|
||||
// 버퍼에 있는 엑셀데이터 전달 후 json으로 변환
|
||||
await filePickedBlobArray(blobRet, '시설정보및운영현황', sheetParameter);
|
||||
await filePickedBlobArrayFormat(blobRet, '시설정보및운영현황', sheetParameter);
|
||||
});
|
||||
};
|
||||
await searchOperationStatus(false, searchYear, fcltyList.bscFctCd);
|
||||
await makeExcelData();
|
||||
break;
|
||||
|
||||
case 'mainGraph': // 주요그래프
|
||||
@@ -258,7 +267,15 @@ export default function DashBoard() {
|
||||
case 'rainManage': // 강우일 운영현황
|
||||
searchRainManage(searchYear, fcltyList.bscFctCd, true);
|
||||
if (excelList && excelList.length > 0) {
|
||||
downloadExcel({ data: excelList as unknown as JSON[], fileName: '강우일 운영현황', sheetNameArray: ['강우일 운영현황'], headerRange: 'A1:T1' });
|
||||
downloadExcelFormat({
|
||||
data: excelList as unknown as JSON[],
|
||||
fileName: '강우일 운영현황',
|
||||
sheetNameArray: ['강우일 운영현황'],
|
||||
headerRange: 'A1:T1',
|
||||
decimalArray0: [2,3],
|
||||
decimalArray1: [1,4,5,6,7,10,11,12,15,16,17],
|
||||
decimalArray3: [8,9,13,14,18,19],
|
||||
});
|
||||
}
|
||||
break;
|
||||
// Add other cases for different tabs as needed
|
||||
@@ -283,7 +300,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 { 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 { 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,43 @@ 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) {
|
||||
downloadExcelFormat({
|
||||
data: latestExcelList as unknown as JSON[],
|
||||
fileName: '시설별 강수현황',
|
||||
sheetNameArray: ['시설별 강수현황'],
|
||||
headerRange: 'A1:N1',
|
||||
decimalArray0: [9, 11, 12, 13],
|
||||
});
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchFacilityPrecipitation, store]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -227,6 +260,7 @@ export default function FacilityPrecipitation() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false}/>
|
||||
<ListDiv>
|
||||
@@ -254,4 +288,4 @@ export default function FacilityPrecipitation() {
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -394,7 +394,7 @@ export default function WaterQualityModal({ fcltyName = '', facilityCd = '', sea
|
||||
"유입BOD(mg/L)": CommaToNumber(item.tpInflWqltBod),
|
||||
"유입TP(mg/L)": CommaToNumber(item.tpInflWqltTp),
|
||||
"유출BOD(mg/L)": CommaToNumber(item.efflWqltBod),
|
||||
"유출TP(mg/L)": CommaToNumber(item.efflWqltTn),
|
||||
"유출TP(mg/L)": CommaToNumber(item.efflWqltTp),
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -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,51 @@ 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',
|
||||
decimalArray0: [9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
|
||||
}
|
||||
);
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchFcltyQltyList, store]);
|
||||
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
setResetPage(false);
|
||||
@@ -201,6 +229,7 @@ export default function ProcessFacilitySearch() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false} initSidoValue={"11"} />
|
||||
<ListDiv>
|
||||
@@ -224,4 +253,4 @@ export default function ProcessFacilitySearch() {
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ import FacilityTermModalHeader from "@/app/components/common/FacilityTermModalHe
|
||||
import { useFoStore } from "@/app/store";
|
||||
import type { FlowRateModalInterface, modalExcelType } from "@/app/store/flowRate";
|
||||
import { dataFormSetting } from "@/app/store/flowRate";
|
||||
import { downloadExcel, UITab, UiTable } from "@common/business_components/ui";
|
||||
import { downloadExcelFormat, UITab, UiTable } from "@common/business_components/ui";
|
||||
import { Button, TabsContent } from "@common/components/ui";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import type { ReturnType } from "../../../../components/common/FacilityTermModalHeader";
|
||||
@@ -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) {
|
||||
@@ -204,16 +201,54 @@ 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' });
|
||||
downloadExcelFormat({
|
||||
data: JSON.parse(JSON.stringify(excelDownList)),
|
||||
fileName: props.searchYear + '년 ' + props.fcltyName + ' 유량현황',
|
||||
sheetNameArray: [props.fcltyName + ' 유량현황'],
|
||||
headerRange: 'A1:H1',
|
||||
decimalArray0: [1, 2, 3, 4, 5, 6],
|
||||
decimalArray1: [0],
|
||||
});
|
||||
} 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 +372,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 +382,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 { downloadExcelFormat, 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,66 @@ 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) {
|
||||
const toNumber = (value: unknown) => {
|
||||
if (value === null || value === undefined || value === '') return '';
|
||||
const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, ""));
|
||||
return Number.isFinite(parsed) ? parsed : '';
|
||||
};
|
||||
|
||||
const numericKeys = [
|
||||
"시설용량(m³/일)",
|
||||
"여유용량(m³/일)",
|
||||
"변동부하율(%)",
|
||||
"분류식화율(%)",
|
||||
];
|
||||
|
||||
const excelData = latestExcelList.map((row) => {
|
||||
const nextRow = { ...row } as Record<string, unknown>;
|
||||
numericKeys.forEach((key) => {
|
||||
if (key in nextRow) {
|
||||
nextRow[key] = toNumber(nextRow[key]);
|
||||
}
|
||||
});
|
||||
return nextRow;
|
||||
});
|
||||
|
||||
downloadExcelFormat({
|
||||
data: excelData as unknown as JSON[],
|
||||
fileName: '계획하수량 산정지표 현황',
|
||||
sheetNameArray: ['계획하수량 산정지표 현황'],
|
||||
headerRange: 'A1:M1',
|
||||
decimalArray0: [9, 10, 11, 12]
|
||||
});
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchPlanSewage, store]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -211,6 +264,7 @@ export default function PlanSewage() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false} initSidoValue={"11"} />
|
||||
<ListDiv>
|
||||
@@ -224,4 +278,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 { ContentsDiv, downloadExcelFormat, 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,49 @@ 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) {
|
||||
downloadExcelFormat({
|
||||
data: latestExcelList as unknown as JSON[],
|
||||
fileName: '처리구역정보',
|
||||
sheetNameArray: ['처리구역정보'],
|
||||
headerRange: 'A1:W1',
|
||||
decimalArray0: [3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15],
|
||||
decimalArray2: [16, 17, 18, 19, 20, 21],
|
||||
});
|
||||
} 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 +195,7 @@ export default function ProcessArea() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref}
|
||||
isAdmin={true}
|
||||
@@ -183,4 +220,4 @@ export default function ProcessArea() {
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
"use client"
|
||||
import { useCallback, useRef } from "react";
|
||||
import { useFoStore } from "@/app/store";
|
||||
import type { TableUpperProps } from "@/app/store/dashboard";
|
||||
import { downloadExcelFormat, filePickedBlobArray, UITab, UiTable } from "@common/business_components/ui";
|
||||
@@ -121,6 +122,21 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
const upHeadListPlanInfoChange = headMakeList(upHeadListPlanInfo, 2);
|
||||
const upHeadListFcltyHistInfoChange = headMakeList(upHeadListFcltyHistInfo, 3);
|
||||
const upHeadListFcltyWaterQltyInfoChange = headMakeList(upHeadListFcltyWaterQltyInfo, 4);
|
||||
const historyTopScrollRef = useRef<HTMLDivElement>(null);
|
||||
const historyBottomScrollRef = useRef<HTMLDivElement>(null);
|
||||
const syncLockRef = useRef(false);
|
||||
|
||||
const syncScroll = useCallback((source: HTMLDivElement | null, target: HTMLDivElement | null) => {
|
||||
if (!source || !target || syncLockRef.current) return;
|
||||
syncLockRef.current = true;
|
||||
const nextTop = source.scrollTop;
|
||||
if (target.scrollTop !== nextTop) {
|
||||
target.scrollTop = nextTop;
|
||||
}
|
||||
requestAnimationFrame(() => {
|
||||
syncLockRef.current = false;
|
||||
});
|
||||
}, []);
|
||||
|
||||
const excelDownloadPlan = () => {
|
||||
const excelDownList: any[] = [];
|
||||
@@ -137,11 +153,19 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
"시운전완료일": item.trlrnCmplDt,
|
||||
"가동개시일": item.rnDt,
|
||||
"시설용량(m³/일)": item.fctCpc&&item.fctCpc.toString().trim()!=''?Number(item.fctCpc.toString().replaceAll(',','')):'',
|
||||
"공법구분": item.trtSrsHanNm,
|
||||
"공법계열": item.trtMocHanNm,
|
||||
"방법": item.trtFrfHanNm,
|
||||
});
|
||||
});
|
||||
}
|
||||
if (excelDownList && excelDownList.length > 0) {
|
||||
downloadExcelFormat({ data: JSON.parse(JSON.stringify(excelDownList)), fileName: props.fcltyName + ' 시설이력관리', sheetNameArray: [props.fcltyName + ' 시설이력관리'], headerRange: 'A1:I1' });
|
||||
downloadExcelFormat({
|
||||
data: JSON.parse(JSON.stringify(excelDownList)),
|
||||
fileName: props.fcltyName + ' 시설이력관리',
|
||||
sheetNameArray: [props.fcltyName + ' 시설이력관리'],
|
||||
decimalArray0: [8],
|
||||
headerRange: 'A1:L1' });
|
||||
} else if (gridListFcltyHistInfo.length == 0) {
|
||||
alert('다운받을 데이터가 없습니다.');
|
||||
}
|
||||
@@ -182,7 +206,7 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
const sheetParameter = [
|
||||
{
|
||||
data: excelData,
|
||||
headerNum: 2,
|
||||
headerNum: 3,
|
||||
headerRange: 'A1:S2',
|
||||
sheetName: '시설 수질정보',
|
||||
startCol: 'A'
|
||||
@@ -218,7 +242,7 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
<h3 className="text-2xl font-medium text-label">시설 기본정보</h3>
|
||||
</div>
|
||||
<div className="card !m-[1.2rem] max-h-[40rem] overflow-auto !p-0r">
|
||||
<Table>
|
||||
<Table variant="secondary">
|
||||
<thead>
|
||||
<TableRow className="">
|
||||
<TableHead className="w-1/6">{'시설명'}</TableHead>
|
||||
@@ -262,7 +286,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
|
||||
<TabsContent value="history_info">
|
||||
<ListDiv>
|
||||
<div className="h-[250px] w-full overflow-y-auto overflow-x-hidden">
|
||||
<div
|
||||
className="h-[250px] w-full overflow-y-auto overflow-x-hidden"
|
||||
ref={historyTopScrollRef}
|
||||
onScroll={() => syncScroll(historyTopScrollRef.current, historyBottomScrollRef.current)}
|
||||
>
|
||||
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadPlan}>
|
||||
{"엑셀다운로드"}
|
||||
</Button>
|
||||
@@ -274,7 +302,11 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
</div>
|
||||
</ListDiv>
|
||||
<ListDiv>
|
||||
<div className="h-[250px] w-full overflow-y-auto overflow-x-hidden">
|
||||
<div
|
||||
className="h-[250px] w-full overflow-y-auto overflow-x-hidden"
|
||||
ref={historyBottomScrollRef}
|
||||
onScroll={() => syncScroll(historyBottomScrollRef.current, historyTopScrollRef.current)}
|
||||
>
|
||||
<Button className={btnClass} style={{float: 'right'}} color="green" onClick={excelDownloadQlty}>
|
||||
{"엑셀다운로드"}
|
||||
</Button>
|
||||
@@ -292,4 +324,4 @@ export default function ProcessFacilityInfoModal(props: ModalType) {
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
|
||||
"use client"
|
||||
import UnderComment from "@/app/components/common/UnderComment";
|
||||
import { useFoStore } from "@/app/store";
|
||||
import { ContentsDiv, downloadExcel, MainDiv, SearchBaseForm, SearchInput, SelectBox, Title, UiModal, UiTable, type ReturnType } from "@common/business_components";
|
||||
import { StoreContext, useFoStore } from "@/app/store";
|
||||
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 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,44 @@ 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) {
|
||||
downloadExcelFormat({
|
||||
data: latestExcelList as unknown as JSON[],
|
||||
fileName: '처리시설 시설정보',
|
||||
sheetNameArray: ['처리시설 시설정보'],
|
||||
headerRange: 'A1:P1',
|
||||
decimalArray0: [9, 10, 11],
|
||||
});
|
||||
} else {
|
||||
alert('조회된 결과가 없습니다.');
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchFcltyList, store]);
|
||||
|
||||
// 모달 닫기
|
||||
const closeModal = () => {
|
||||
@@ -266,6 +300,7 @@ export default function ProcessFacilitySearch() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false} />
|
||||
<ListDiv>
|
||||
@@ -292,11 +327,11 @@ export default function ProcessFacilitySearch() {
|
||||
{selectedRow !== null && (
|
||||
<UiModal
|
||||
body={<ProcessFacilityInfoModal fcltyName={modalFcltyNm} facilityCd={modalFcltyCd} sido={modalSido} gugun={modalGugun} daddr={modalAddr} fctCpc={modalFctCpc} trtFrfNm={modalTrtFrfNm} rnDt={modalRnDt} cmplDt={modalCmplDt} trstOprEtpNm={modalTrstOprEtpNm} bscFctClsNm={modalBscFctClsNm} mnstr={modalMnstr} efflWtrrgn={modalEfflWtrrgn} lgbsn={modalLgbsn} efflWqltStndrdNm={modalEfflWqltStndrdNm} rgnNm={modalRgnNm} rvbsn={modalRvbsn}></ProcessFacilityInfoModal>}
|
||||
bodyClass="sm:max-w-[70vw] h-[100dvh] max-h-[800px]"
|
||||
bodyClass="sm:max-w-[100vw] w-[1300px] h-[100dvh] max-h-[800px]"
|
||||
open={selectedRow !== null}
|
||||
onOpenChange={(open) => !open && closeModal()}
|
||||
/>
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 { ContentsDiv, downloadExcelFormat, 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,71 @@ 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) {
|
||||
const toNumber = (value: unknown) => {
|
||||
if (value === null || value === undefined || value === '') return '';
|
||||
const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, ""));
|
||||
return Number.isFinite(parsed) ? parsed : '';
|
||||
};
|
||||
|
||||
const numericKeys = [
|
||||
"시설용량(m³/일)",
|
||||
"청천시유입하수량(m³/일)",
|
||||
"하절기강우일최저유입BOD(mg/L)",
|
||||
"하절기최저유입BOD유입유량(m³/일)",
|
||||
"동절기청천시유입BOD(mg/L)",
|
||||
"RDII추정",
|
||||
"RDII추정시일강수량(mm)",
|
||||
"강우시총추정유입량(m³/일)",
|
||||
];
|
||||
|
||||
const excelData = latestExcelList.map((row) => {
|
||||
const nextRow = { ...row } as Record<string, unknown>;
|
||||
numericKeys.forEach((key) => {
|
||||
if (key in nextRow) {
|
||||
nextRow[key] = toNumber(nextRow[key]);
|
||||
}
|
||||
});
|
||||
return nextRow;
|
||||
});
|
||||
|
||||
downloadExcelFormat({
|
||||
data: excelData as unknown as JSON[],
|
||||
fileName: 'RDII추정',
|
||||
sheetNameArray: ['RDII추정'],
|
||||
headerRange: 'A1:R1',
|
||||
decimalArray0: [9, 10, 11, 12, 13, 14, 15, 16],
|
||||
});
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchRdi, store]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -209,6 +267,7 @@ export default function Rdi() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref} isAdmin={false} initSidoValue={"11"}/>
|
||||
<ListDiv>
|
||||
@@ -224,4 +283,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 { 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 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,7 +187,8 @@ export default function PlanSewage() {
|
||||
}, [upHeadList1, upHeadList2, upHeadList3]);
|
||||
|
||||
// 엑셀다운로드
|
||||
const excelDownload = useCallback(() => {
|
||||
const excelDownload = useCallback(async () => {
|
||||
if (isExcelDownClick) return;
|
||||
if (ref.current.partValue === 'A') { //
|
||||
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
|
||||
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
|
||||
@@ -212,9 +205,50 @@ export default function PlanSewage() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
searchFacilityPrecipitation(ref.current, 1, 5000);
|
||||
setIsInitExcelDownload(true);
|
||||
}, [searchFacilityPrecipitation]);
|
||||
setIsExcelDownClick(true);
|
||||
try {
|
||||
await searchFacilityPrecipitation(ref.current, 1, 5000);
|
||||
const latestExcelList = store.getState().SewageOccur.excelList || [];
|
||||
if (latestExcelList.length > 0) {
|
||||
const toNumber = (value: unknown) => {
|
||||
if (value === null || value === undefined || value === '') return '';
|
||||
const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, ""));
|
||||
return Number.isFinite(parsed) ? parsed : '';
|
||||
};
|
||||
|
||||
const numericKeys = [
|
||||
"시설용량(m³/일)",
|
||||
"물사용량(m³/일)",
|
||||
"오수전환율(%)",
|
||||
"오수발생량추정(m³/일)",
|
||||
"연간하수유입량(m³/일)",
|
||||
"청천시하수유입량(m³/일)",
|
||||
];
|
||||
|
||||
const excelData = latestExcelList.map((row) => {
|
||||
const nextRow = { ...row } as Record<string, unknown>;
|
||||
numericKeys.forEach((key) => {
|
||||
if (key in nextRow) {
|
||||
nextRow[key] = toNumber(nextRow[key]);
|
||||
}
|
||||
});
|
||||
return nextRow;
|
||||
});
|
||||
|
||||
downloadExcelFormat({
|
||||
data: excelData as unknown as JSON[],
|
||||
fileName: '오수발생량 추정',
|
||||
sheetNameArray: ['오수발생량 추정'],
|
||||
headerRange: 'A1:O1',
|
||||
decimalArray0: [9, 10, 11, 12, 13, 14]
|
||||
});
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchFacilityPrecipitation]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -246,6 +280,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 { 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 { 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,7 +193,8 @@ export default function UnderWaterInput() {
|
||||
}, [upHeadList1, upHeadList2, upHeadList3]);
|
||||
|
||||
// 엑셀다운로드
|
||||
const excelDownload = useCallback(() => {
|
||||
const excelDownload = useCallback(async () => {
|
||||
if (isExcelDownClick) return;
|
||||
if (ref.current.partValue === 'A') { //
|
||||
if (!ref.current.sidoValue || ref.current.sidoValue === '0') {
|
||||
alert('엑셀 다운로드는 시도 조건을 선택한 후 이용 가능합니다.');
|
||||
@@ -216,9 +211,49 @@ export default function UnderWaterInput() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
searchFacilityPrecipitation(ref.current, 1, 5000);
|
||||
setIsMount(true);
|
||||
}, [searchFacilityPrecipitation]);
|
||||
setIsExcelDownClick(true);
|
||||
try {
|
||||
await searchFacilityPrecipitation(ref.current, 1, 5000);
|
||||
const latestExcelList = store.getState().UnderWater.excelList || [];
|
||||
if (latestExcelList.length > 0) {
|
||||
const toNumber = (value: unknown) => {
|
||||
if (value === null || value === undefined || value === '') return '';
|
||||
const parsed = typeof value === "number" ? value : Number(String(value).replace(/,/g, ""));
|
||||
return Number.isFinite(parsed) ? parsed : '';
|
||||
};
|
||||
|
||||
const numericKeys = [
|
||||
"시설용량(m³/일)",
|
||||
"평균유입하수량(m³/일)",
|
||||
"연간지하수유입량(m³/일)",
|
||||
"하절기지하수유입량(m³/일)",
|
||||
"동절기지하수유입량(m³/일)",
|
||||
];
|
||||
|
||||
const excelData = latestExcelList.map((row) => {
|
||||
const nextRow = { ...row } as Record<string, unknown>;
|
||||
numericKeys.forEach((key) => {
|
||||
if (key in nextRow) {
|
||||
nextRow[key] = toNumber(nextRow[key]);
|
||||
}
|
||||
});
|
||||
return nextRow;
|
||||
});
|
||||
|
||||
downloadExcelFormat({
|
||||
data: excelData as unknown as JSON[],
|
||||
fileName: '지하수유입량 추정',
|
||||
sheetNameArray: ['지하수유입량 추정'],
|
||||
headerRange: 'A1:O1',
|
||||
decimalArray0: [9, 10, 11, 12, 13]
|
||||
});
|
||||
} else {
|
||||
alert("조회된 결과가 없습니다.");
|
||||
}
|
||||
} finally {
|
||||
setIsExcelDownClick(false);
|
||||
}
|
||||
}, [isExcelDownClick, searchFacilityPrecipitation, store]);
|
||||
|
||||
// 페이지 변경
|
||||
const handlePageChange = useCallback((page: number) => {
|
||||
@@ -250,6 +285,7 @@ export default function UnderWaterInput() {
|
||||
btnClass={btnClass}
|
||||
queryClick={chkVal}
|
||||
excelClick={excelDownload}
|
||||
excelDisabled={isExcelDownClick}
|
||||
initClick={resetVal}
|
||||
ref={ref}
|
||||
isAdmin={false}
|
||||
@@ -276,4 +312,4 @@ export default function UnderWaterInput() {
|
||||
)}
|
||||
</MainDiv>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -1712,7 +1712,7 @@ export const dashBoardReducer = (
|
||||
// RDII 추정 = 하절기(6~8월) 중 최저 유입 BOD일때 유입유량 x ((동절기 청천시 유입BOD - 하절기(6~8월) 중 최저 유입BOD) / (동절기 청천시 유입BOD))
|
||||
// const resp = await fetchMainGraph(searchYear, fcltyCd);
|
||||
const resp = mainGraphData;
|
||||
if (resp && resp.data && resp.data.wqltObjs) {
|
||||
if (resp && resp.data && resp.data.wqltObjs && resp.data.wqltObjs.length > 0) {
|
||||
const wqltData = resp.data.wqltObjs;
|
||||
const wqltDataTot = CalcRainEffect(clone(wqltData));
|
||||
const wqltDataSunny = CalcRainEffect(clone(wqltData), 'SUNNY');
|
||||
@@ -1800,10 +1800,11 @@ export const dashBoardReducer = (
|
||||
|
||||
const rtnData = await calcWaterQltyData(operationalStatusList, searchYear, fcltyCd, mainGraphData); // 수질 데이터 청천시, 강우시 재계산
|
||||
|
||||
let tpFctYn = 'N';
|
||||
if (mainGraphData.data.wqltObjs && mainGraphData.data.wqltObjs.length > 0)
|
||||
tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn;
|
||||
// 총인설비가 없을 경우 제외
|
||||
console.log('총인시설 여부 : ', mainGraphData.data.wqltObjs?.[0].tpFctYn);
|
||||
|
||||
const tpFctYn = mainGraphData.data.wqltObjs?.[0].tpFctYn;
|
||||
console.log('총인시설 여부 : ', tpFctYn);
|
||||
|
||||
// console.log('rtnData : ', rtnData);
|
||||
if (tpFctYn !== 'Y') {
|
||||
|
||||
@@ -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 },
|
||||
@@ -466,16 +468,22 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
|
||||
//---------
|
||||
const waterQltyList: any[] = [];
|
||||
let recordCount = 0;
|
||||
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; // 더 이상 데이터가 없으면 중지
|
||||
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; // 더 이상 데이터가 없으면 중지
|
||||
}
|
||||
}
|
||||
}
|
||||
//-------
|
||||
@@ -527,8 +535,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
|
||||
waterQltyList.forEach(item => {
|
||||
dataFormSetting(item)
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
// item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
// item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc;
|
||||
item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc;
|
||||
excelDownList.push({
|
||||
@@ -537,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),
|
||||
@@ -559,8 +567,8 @@ export const facilityWaterQltyReducer = (set: SetFunc): FacilityWaterQltyActions
|
||||
waterQltyList.forEach((item: FacilityWaterQltyProps) => {
|
||||
dataFormSetting(item)
|
||||
item.fctCpc = parseFloat(item.fctCpc.toString().replace(/,/g, ''));
|
||||
item.sidoNm = item.lclgvrnmntNm.split(' ')[0]?.toString() || '';
|
||||
item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
// item.sidoNm = item.;
|
||||
// item.sggNm = item.lclgvrnmntNm.split(' ')[1]?.toString() || '';
|
||||
item.inflAssctBfrWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.inflAssctBfrWqltToc + ")" : item.inflAssctBfrWqltToc;
|
||||
item.efflWqltToc = Number(searchYear) < COD_YEAR ? "(" + item.efflWqltToc + ")" : item.efflWqltToc;
|
||||
});
|
||||
|
||||
@@ -285,23 +285,30 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
|
||||
//---------
|
||||
const flowRateList: any[] = [];
|
||||
const results: any[] = [];
|
||||
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);
|
||||
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;
|
||||
//-------
|
||||
|
||||
@@ -381,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;
|
||||
@@ -397,7 +404,7 @@ export const flowRateSearchReducer: (set: (fn: (state: FlowRateSearchType) => Fl
|
||||
: item.msrDt,
|
||||
};
|
||||
});
|
||||
console.log(rtnData);
|
||||
//console.log(rtnData);
|
||||
set((state: FlowRateSearchType) => ({
|
||||
...state,
|
||||
FlowRateModal: {
|
||||
|
||||
@@ -113,7 +113,10 @@ export type fcltyHistInfoProps = {
|
||||
sitArea: number,
|
||||
trtDstrArea: number,
|
||||
swrTrtPopl: number,
|
||||
fctCpc: number | ''
|
||||
fctCpc: number | '',
|
||||
trtSrsHanNm?: string, // 공법구분
|
||||
trtMocHanNm?: string, // 공법계열
|
||||
trtFrfHanNm?: string, // 방법
|
||||
}
|
||||
|
||||
// 시설 수질정보
|
||||
@@ -328,6 +331,9 @@ const upHeadListFcltyHistInfo: TableUpperProps[] = [
|
||||
{ id: "trlrnCmplDt", title: "시운전완료일" },
|
||||
{ id: "rnDt", title: "가동개시일" },
|
||||
{ id: "fctCpc", title: "시설용량(m³/일)", align: 'right' },
|
||||
{ id: "trtSrsHanNm", title: "공법구분" },
|
||||
{ id: "trtMocHanNm", title: "공법계열" },
|
||||
{ id: "trtFrfHanNm", title: "방법" },
|
||||
];
|
||||
|
||||
// 시설 이력관리 (리스트)
|
||||
@@ -344,7 +350,10 @@ const gridListFcltyHistInfo: fcltyHistInfoProps[] = [
|
||||
sitArea: 0,
|
||||
trtDstrArea: 0,
|
||||
swrTrtPopl: 0,
|
||||
fctCpc: 860000
|
||||
fctCpc: 860000,
|
||||
trtFrfHanNm: "",
|
||||
trtMocHanNm: "",
|
||||
trtSrsHanNm: "",
|
||||
}
|
||||
];
|
||||
|
||||
@@ -418,7 +427,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>) => {
|
||||
@@ -900,4 +911,4 @@ export const processFacilityReducer: (set: SetStateFunction) => ProcessFacilityA
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -317,6 +317,14 @@ export type UnderWaterStore = UnderWaterType & UnderWaterActions;
|
||||
export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => UnderWaterActions = (set: (fn: (state: UnderWaterType) => UnderWaterType) => void) => {
|
||||
return {
|
||||
searchUnderWaterList: async (pageNo: number, pageSize: number, searchYear: string, part?: string, nameCd?: string, fcltCpct?: string, operationValue?: string, fcltyNm?: string) => {
|
||||
set((state: UnderWaterType) => ({
|
||||
...state,
|
||||
UnderWater: {
|
||||
...state.UnderWater,
|
||||
isLoading: true,
|
||||
},
|
||||
}));
|
||||
|
||||
const facilityInitData = await fetchFacilityListInit(pageNo, pageSize, part, nameCd, fcltCpct, operationValue, fcltyNm);
|
||||
|
||||
if (pageSize < 5000) {
|
||||
@@ -724,4 +732,4 @@ export const underWaterReducer: (set: (fn: (state: UnderWaterType) => UnderWater
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"use client";
|
||||
import { createContext, useState } from "react";
|
||||
|
||||
interface PromptContext {
|
||||
|
||||
@@ -27,7 +27,8 @@ export const MsSwagePplCol = [
|
||||
// { id: 'ftre_smbol_cd', title: '지형지물부호코드' },
|
||||
// { id: 'lyrTypeNm', title: '레이어타입명' },
|
||||
]
|
||||
export const MsSwagePplCol2 = [
|
||||
// 하수관로 searchModal 기본정보tab
|
||||
export const MsSwagePplCol2 = [
|
||||
{ id: 'rowNumber', title: '일련\n번호' },
|
||||
{ id: 'fcltMngNo', title: '시설\n관리번호' },
|
||||
{ id: 'instMngNo', title: '기관\n관리번호' },
|
||||
@@ -44,13 +45,13 @@ export const MsSwagePplCol2 = [
|
||||
{ id: 'tmptMhlMngNo', title: '시점맨홀\n관리번호' },
|
||||
{ id: 'scendDpth', title: '종점깊이\n(m)' },
|
||||
{ id: 'scendMhlMngNo', title: '종점맨홀\n관리번호' },
|
||||
// { id: 'vrtcLen', title: '세로길이\n(m)' },
|
||||
// { id: 'wdthLen', title: '가로길이\n(m)' },
|
||||
// { id: 'fcltyShpCd', title: '시설물형태코드' },
|
||||
{ id: 'vrtcLen', title: '세로길이\n(m)' },
|
||||
{ id: 'wdthLen', title: '가로길이\n(m)' },
|
||||
{ id: 'fcltyShpCd', title: '시설물형태코드' },
|
||||
// { id: 'fid', title: 'FID' },
|
||||
// { id: 'ftreSmbolCd', title: '지형지물부호코드' },
|
||||
// { id: 'mngInstCd', title: '관리기관코드' },
|
||||
// { id: 'mqltCd', title: '재질코드' },
|
||||
{ id: 'mqltCd', title: '재질코드' },
|
||||
// { id: 'pbadmsEmdCd', title: '행정읍면동코드' },
|
||||
// { id: 'usgCd', title: '용도코드' },
|
||||
// { id: 'lyrTypeNm', title: '레이어타입명' },
|
||||
@@ -69,6 +70,10 @@ export const MsSwagePplExcelCol = {
|
||||
'tmptMhlMngNo': '시점맨홀 관리번호',
|
||||
'scendDpth': '종점 깊이(m)',
|
||||
'scendMhlMngNo': '종점맨홀 관리번호',
|
||||
'vrtcLen': '세로길이(m)',
|
||||
'wdthLen': '가로길이(m)',
|
||||
'fcltyShpCd': '시설물형태코드',
|
||||
'mqltCd': '재질코드',
|
||||
};
|
||||
// 하수관로 용도 코드표
|
||||
export const MS_SWAGE_PPL_USE_CODES = [
|
||||
@@ -275,7 +280,80 @@ export const MS_SWAGE_PPL_CODES = [
|
||||
{ val: "MOP977", text: "전주용입상관" },
|
||||
{ val: "MOP978", text: "MD관" },
|
||||
];
|
||||
// 하수관로 'fcltyShpCd' '시설물형태코드'
|
||||
export const MS_SWAGE_PPL_SHAPE = [
|
||||
{ val: "FOR000 ", text: "미분류" },
|
||||
{ val: "FOR001 ", text: "원형" },
|
||||
{ val: "FOR002 ", text: "원추형" },
|
||||
{ val: "FOR003 ", text: "원통형" },
|
||||
{ val: "FOR004 ", text: "구형" },
|
||||
{ val: "FOR005 ", text: "타원형" },
|
||||
{ val: "FOR006 ", text: "난원" },
|
||||
{ val: "FOR007 ", text: "반원형" },
|
||||
|
||||
{ val: "FOR010 ", text: "피라미드형" },
|
||||
{ val: "FOR011 ", text: "사면체형" },
|
||||
{ val: "FOR012 ", text: "기둥,축" },
|
||||
{ val: "FOR013 ", text: "돛대,활대처럼 둥글고 긴 원재" },
|
||||
{ val: "FOR014 ", text: "아치형" },
|
||||
{ val: "FOR015 ", text: "다중아치형" },
|
||||
{ val: "FOR016 ", text: "돔형" },
|
||||
{ val: "FOR017 ", text: "고형체형" },
|
||||
|
||||
{ val: "FOR020 ", text: "사각형" },
|
||||
{ val: "FOR021 ", text: "평방형" },
|
||||
{ val: "FOR022 ", text: "다이아몬드형" },
|
||||
{ val: "FOR023 ", text: "사다리꼴" },
|
||||
{ val: "FOR024 ", text: "각형" },
|
||||
{ val: "FOR025 ", text: "마제형관" },
|
||||
{ val: "FOR026 ", text: "태형" },
|
||||
|
||||
{ val: "FOR030 ", text: "A형" },
|
||||
{ val: "FOR031 ", text: "H형" },
|
||||
{ val: "FOR032 ", text: "I형" },
|
||||
{ val: "FOR033 ", text: "Y형" },
|
||||
{ val: "FOR034 ", text: "T형" },
|
||||
|
||||
{ val: "FOR050 ", text: "불규칙한 형태" },
|
||||
|
||||
{ val: "FOR900 ", text: "계란형" },
|
||||
{ val: "FOR901 ", text: "구(사각)형" },
|
||||
{ val: "FOR902 ", text: "높이조절철개형" },
|
||||
{ val: "FOR903 ", text: "박스형(RCB)" },
|
||||
{ val: "FOR904 ", text: "반월개거" },
|
||||
{ val: "FOR905 ", text: "반월개거(측구)" },
|
||||
{ val: "FOR906 ", text: "벽돌조" },
|
||||
{ val: "FOR907 ", text: "사각철판" },
|
||||
{ val: "FOR908 ", text: "석축개거" },
|
||||
{ val: "FOR909 ", text: "석축개거(측구)" },
|
||||
{ val: "FOR910 ", text: "승수로" },
|
||||
{ val: "FOR911 ", text: "옹벽개거" },
|
||||
{ val: "FOR912 ", text: "옹벽개거(측구)" },
|
||||
{ val: "FOR913 ", text: "이단" },
|
||||
{ val: "FOR914 ", text: "이중침전형" },
|
||||
{ val: "FOR915 ", text: "자연개거" },
|
||||
{ val: "FOR916 ", text: "자연개거(측구)" },
|
||||
{ val: "FOR917 ", text: "조립식" },
|
||||
{ val: "FOR918 ", text: "지상관" },
|
||||
{ val: "FOR919 ", text: "지상단구" },
|
||||
{ val: "FOR920 ", text: "지상쌍구" },
|
||||
{ val: "FOR921 ", text: "지하단구" },
|
||||
{ val: "FOR922 ", text: "지하쌍구" },
|
||||
{ val: "FOR923 ", text: "직사각형" },
|
||||
{ val: "FOR924 ", text: "타설식" },
|
||||
{ val: "FOR925 ", text: "토류형" },
|
||||
{ val: "FOR926 ", text: "흄관원형" },
|
||||
{ val: "FOR927 ", text: "L형측구" },
|
||||
{ val: "FOR928 ", text: "LO형측구" },
|
||||
{ val: "FOR929 ", text: "LU형측구" },
|
||||
{ val: "FOR930 ", text: "PVC이중벽관" },
|
||||
{ val: "FOR931 ", text: "RCB 맨홀" },
|
||||
{ val: "FOR932 ", text: "U형" },
|
||||
{ val: "FOR933 ", text: "U형측구(미복개)" },
|
||||
{ val: "FOR934 ", text: "U형측구(복개)" },
|
||||
|
||||
{ val: "FOR999 ", text: "기타" }
|
||||
];
|
||||
// 하수처리시설
|
||||
export const SwtrmtFcltCol = [
|
||||
{ id: 'swtrmt_fclt_nm', title: '하수처리시설명' },
|
||||
|
||||
@@ -125,32 +125,30 @@ const SearchModal: React.FC = () => {
|
||||
{/* 📋 결과 리스트 */}
|
||||
{/* 기본정보 탭 */}
|
||||
{activeTab === 'basic' && (
|
||||
<div className="h-[79dvh] w-full rounded-lg border mt-4">
|
||||
{/* <div className="flex-1 px-2 pb-2"> */}
|
||||
<div className="h-[79dvh] w-full rounded-lg border mt-4 overflow-x-scroll">
|
||||
<LoadingOverlay isLoading={isLoading} />
|
||||
<UiTable
|
||||
headName={(() => {
|
||||
const label = BASIC_TYPES.find((type) => type.val === basicType)?.text
|
||||
return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>);
|
||||
})()
|
||||
}
|
||||
tableData={tableData}
|
||||
headlist={dynamicHeadlist}
|
||||
pageSize={10}
|
||||
total={tableCount}
|
||||
cellClick={handleBasicCellClick}
|
||||
onPageChange={setCurPage}
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
curPage={curPage}
|
||||
headButton={
|
||||
<div className='flex'>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{/* </div> */}
|
||||
<UiTable className='w-[120%]'
|
||||
headName={(() => {
|
||||
const label = BASIC_TYPES.find((type) => type.val === basicType)?.text
|
||||
return (<>{label} 조회 결과 ({tableCount.toLocaleString('ko-KR')})건</>);
|
||||
})()
|
||||
}
|
||||
tableData={tableData}
|
||||
headlist={dynamicHeadlist}
|
||||
pageSize={10}
|
||||
total={tableCount}
|
||||
cellClick={handleBasicCellClick}
|
||||
onPageChange={setCurPage}
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
curPage={curPage}
|
||||
headButton={
|
||||
<div className='flex'>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium primary" size="sm" onClick={viewMultipleFeature}>지도에서 보기</Button>
|
||||
<Button className="px-4 py-2 !mr-[1.2rem] text-white rounded-sm text-lg font-medium green" size="sm" onClick={basicExcelDownload}>파일 다운로드</Button>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{/* 유지관리 정보 탭 */}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*/
|
||||
import { downloadExcelWithKoreanHeaders } from '@common/business_components/ui';
|
||||
import {
|
||||
MS_SWAGE_PPL_USE_CODES, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES,
|
||||
MS_SWAGE_PPL_USE_CODES, MS_SWAGE_PPL_CODES, MS_SWAGE_PPL_SHAPE, MS_SWAGE_MHL_CODES, MS_SWAGE_MHL_USE_CODES,
|
||||
MsSwagePplExcelCol, SwtrmtFcltExcelCol, SwtrmtPrcsZoneExcelCol, MsSwageMhlExcelCol, ExclnSewagePumpExcelCol, stofcbrExcelCol
|
||||
} from '../components/common/table';
|
||||
import { getData } from "@/components/lib/api";
|
||||
@@ -46,6 +46,7 @@ export default function useBasicTab() {
|
||||
} = useSearchModalStore();
|
||||
const { ctpv, sgg } = useStore();
|
||||
|
||||
|
||||
const fetchBasicFilteredData = async () => {
|
||||
let cqlFilters: string[] = [];
|
||||
const queryParams = new URLSearchParams({
|
||||
@@ -79,8 +80,15 @@ export default function useBasicTab() {
|
||||
if (!sggCd && code) sggCd = code.slice(0, 5);
|
||||
}
|
||||
|
||||
const matchedMhlCode = MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim());
|
||||
const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd);
|
||||
const matchedMqltCode = basicType === 'tb_ms_swage_ppl'
|
||||
? MS_SWAGE_PPL_CODES.find(code => code.val === item?.mqltCd?.trim()) // 하수관로 재질
|
||||
: basicType === 'tb_ms_swage_mhl'
|
||||
? MS_SWAGE_MHL_CODES.find(code => code.val === item?.mqltCd?.trim()) // 맨홀 재질
|
||||
: undefined;
|
||||
const matchedMhlUsgCode = MS_SWAGE_MHL_USE_CODES.find(code => code.val === item?.usgCd); // 맨홀 용도
|
||||
const matchedPplShpCode = MS_SWAGE_PPL_SHAPE.find(code => code.val === item?.fcltyShpCd); // 하수관로 시설물형태코드
|
||||
|
||||
|
||||
const ctpvNm = ctpv.find(code => code.val.trim() === ctpvCd)?.text || item?.ctpvNm;
|
||||
const sggNm = sgg.find(code => code.val.trim() === sggCd)?.text || item?.sggNm;
|
||||
const usgCdObj = MS_SWAGE_PPL_USE_CODES.find(code => code.val === item?.usgCd?.trim());
|
||||
@@ -90,15 +98,17 @@ export default function useBasicTab() {
|
||||
...formattedItem,
|
||||
rowNumber: (curPage - 1) * 10 + index + 1, // 1부터 시작하는 일련번호 추가
|
||||
scsYn: item.scsYn === null || item.scsYn === undefined ? 'N' : item?.scsYn, // scsYn이 null이면 'N'으로 변경
|
||||
mqltCd: matchedMhlCode ? matchedMhlCode.text : item?.mqltCd,
|
||||
mqltCd: matchedMqltCode ? matchedMqltCode.text : item?.mqltCd,
|
||||
usgCd: matchedMhlUsgCode ? matchedMhlUsgCode.text : (usgCdObj ? usgCdObj.text : item?.usgCd),
|
||||
ctpvNm: ctpvNm ?? '-',
|
||||
sggNm: sggNm ?? '-',
|
||||
swtrmt_zone_nm: item.swtrmtZoneNm || item.swtrmt_zone_nm || '-',
|
||||
fcltyShpCd: matchedPplShpCode? matchedPplShpCode.text : item?.fcltyShpCd,
|
||||
};
|
||||
});
|
||||
|
||||
setTableData(dataWithRowNumber);
|
||||
// console.log(tableData);
|
||||
setTableCount(res.count || []);
|
||||
};
|
||||
|
||||
@@ -150,7 +160,7 @@ export default function useBasicTab() {
|
||||
// 하수관로
|
||||
cqlFilters = swagePplCqlFilters()
|
||||
headerMapping = MsSwagePplExcelCol;
|
||||
headerRange = "A1:M1";
|
||||
headerRange = "A1:Q1";
|
||||
break;
|
||||
}
|
||||
case 'tb_il_swage_prcs_fclt': {
|
||||
@@ -196,6 +206,8 @@ export default function useBasicTab() {
|
||||
|
||||
const mhlUsgCdMap = new Map(MS_SWAGE_MHL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
||||
const pplUsgCdMap = new Map(MS_SWAGE_PPL_USE_CODES.map(code => [code.val?.trim(), code.text]));
|
||||
const pplMqltCdMap = new Map(MS_SWAGE_PPL_CODES.map(code => [code.val?.trim(), code.text]));
|
||||
const pplShpCdMap = new Map(MS_SWAGE_PPL_SHAPE.map(code => [code.val?.trim(), code.text])); // 관로 시설물형태코드
|
||||
const ctpvMap = new Map(ctpv.map(code => [code.val?.trim(), code.text]));
|
||||
const sggMap = new Map(sgg.map(code => [code.val?.trim(), code.text]));
|
||||
|
||||
@@ -232,6 +244,10 @@ export default function useBasicTab() {
|
||||
tmptMhlMngNo: formattedItem.tmptMhlMngNo ?? item.tmptMhlMngNo ?? '-',
|
||||
scendDpth: formattedItem.scendDpth ?? item.scendDpth ?? '-',
|
||||
scendMhlMngNo: formattedItem.scendMhlMngNo ?? item.scendMhlMngNo ?? '-',
|
||||
vrtcLen: formattedItem.vrtcLen ?? item.vrtcLen ?? '-',
|
||||
wdthLen: formattedItem.wdthLen ?? item.wdthLen ?? '-',
|
||||
fcltyShpCd: pplShpCdMap.get(item?.fcltyShpCd?.trim()) || item.fcltyShpCd || formattedItem.fcltyShpCd || '-',
|
||||
mqltCd: pplMqltCdMap.get(item?.mqltCd?.trim()) || item.mqltCd || formattedItem.mqltCd || '-',
|
||||
};
|
||||
}
|
||||
case 'tb_il_swage_prcs_fclt': {
|
||||
@@ -329,4 +345,4 @@ export default function useBasicTab() {
|
||||
|
||||
|
||||
return { fetchBasicFilteredData, handleBasicCellClick, basicExcelDownload };
|
||||
};
|
||||
};
|
||||
|
||||
@@ -94,7 +94,7 @@ export default function Page() {
|
||||
|
||||
const cellClick = () => {
|
||||
if (searchYear)
|
||||
if (selFcltDiv === "RNB") {
|
||||
if (selFcltDiv === "RNB") { // 빗물
|
||||
if (fcltNm) {
|
||||
rainChkNmSearch(
|
||||
rainPageNation,
|
||||
@@ -107,7 +107,7 @@ export default function Page() {
|
||||
} else {
|
||||
rainChkInit(rainPageNation, rainPageSize, searchYear, laeSeCd);
|
||||
}
|
||||
} else {
|
||||
} else { // 중수도
|
||||
if (fcltNm) {
|
||||
rswtChkNmSearch(
|
||||
rainPageNation,
|
||||
|
||||
@@ -190,12 +190,10 @@ export const chRowspanTable = (
|
||||
value={formatCommaNumber(value) || ""}
|
||||
disabled={!selectedIds.includes(row.chkgdnSn)}
|
||||
maxLength={numSize}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
head.type === "number" &&
|
||||
e.target.value.length > numSize
|
||||
) {
|
||||
e.target.value = e.target.value.slice(0, numSize);
|
||||
onInput={(e: React.FormEvent<HTMLInputElement>) => {
|
||||
const el = e.currentTarget;
|
||||
if (head.type === "number" && el.value.length > numSize) {
|
||||
el.value = el.value.slice(0, numSize);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
@@ -225,12 +223,10 @@ export const chRowspanTable = (
|
||||
value={value || ""}
|
||||
disabled={!selectedIds.includes(row.chkgdnSn)}
|
||||
maxLength={numSize}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (
|
||||
head.type === "number" &&
|
||||
e.target.value.length > numSize
|
||||
) {
|
||||
e.target.value = e.target.value.slice(0, numSize);
|
||||
onInput={(e: React.FormEvent<HTMLInputElement>) => {
|
||||
const el = e.currentTarget;
|
||||
if (head.type === "number" && el.value.length > numSize) {
|
||||
el.value = el.value.slice(0, numSize);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
chRowspanTable,
|
||||
rswtChkTableData,
|
||||
} from "@/components/lib/func/TableData";
|
||||
import { codeToText } from "@/components/lib/func/commom";
|
||||
import UiPageNations from "@common/business_components/ui/table/uiPageNations";
|
||||
import { Table, TableBody, TableHeader } from "@common/components/ui";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
@@ -99,9 +100,16 @@ export default function RswtChkgdTable({
|
||||
const tableTotalData = rswtChkTableData(rswtChkData);
|
||||
const makeRswtChkData = tableTotalData.map((item: any) => {
|
||||
const bud = tableData([item.building], { code });
|
||||
// 운영관리형태 코드 → 한글 텍스트로 치환 (빗물 화면과 동일한 표시)
|
||||
const operMngCdText =
|
||||
codeToText(item.operMngCd?.trim(), "rainRswtMng") ??
|
||||
codeToText(item.reuseBuilding?.operMngCd?.trim(), "rainRswtMng") ??
|
||||
item.operMngCd;
|
||||
|
||||
return {
|
||||
...item,
|
||||
...bud[0],
|
||||
operMngCd: operMngCdText,
|
||||
rowspan: item.rswtrDetails?.length,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -11,6 +11,10 @@ type ExcelDownloadProps = {
|
||||
decimalArray1? : number[];
|
||||
decimalArray2? : number[];
|
||||
decimalArray3? : number[];
|
||||
decimalRange0?: string;
|
||||
decimalRange1?: string;
|
||||
decimalRange2?: string;
|
||||
decimalRange3?: string;
|
||||
}
|
||||
|
||||
export const downloadExcel = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3'}: ExcelDownloadProps) => {
|
||||
@@ -29,7 +33,20 @@ export const downloadExcelHeaders = ({ data, fileName = new Date().getTime().toS
|
||||
excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName);
|
||||
};
|
||||
|
||||
export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toString() + '.xlsx', sheetNameArray = ["Sheet1"], headerRange='A1:V3', decimalArray0=[], decimalArray1=[], decimalArray2=[], decimalArray3=[]}: ExcelDownloadProps) => {
|
||||
export const downloadExcelFormat = ({
|
||||
data,
|
||||
fileName = new Date().getTime().toString() + '.xlsx',
|
||||
sheetNameArray = ["Sheet1"],
|
||||
headerRange = 'A1:V3',
|
||||
decimalArray0 = [],
|
||||
decimalArray1 = [],
|
||||
decimalArray2 = [],
|
||||
decimalArray3 = [],
|
||||
decimalRange0,
|
||||
decimalRange1,
|
||||
decimalRange2,
|
||||
decimalRange3,
|
||||
}: ExcelDownloadProps) => {
|
||||
const worksheet = XLSX.utils.json_to_sheet(Array.isArray(data) ? data : [data]);
|
||||
const workbook = XLSX.utils.book_new();
|
||||
XLSX.utils.book_append_sheet(workbook, worksheet, sheetNameArray[0]);
|
||||
@@ -61,10 +78,35 @@ export const downloadExcelFormat = ({ data, fileName = new Date().getTime().toSt
|
||||
}
|
||||
}
|
||||
};
|
||||
const applyRangeFormat = (rangeStr: string | undefined, decimal: number) => {
|
||||
if (!rangeStr) return;
|
||||
const rangeInfo = XLSX.utils.decode_range(rangeStr);
|
||||
for (let row = rangeInfo.s.r; row <= rangeInfo.e.r; row++) {
|
||||
for (let col = rangeInfo.s.c; col <= rangeInfo.e.c; col++) {
|
||||
const cellAddr = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = worksheet[cellAddr];
|
||||
if (cell && typeof cell.v === "number") {
|
||||
if (decimal === 1) {
|
||||
cell.z = "#,##0.0";
|
||||
} else if (decimal === 2) {
|
||||
cell.z = "#,##0.00";
|
||||
} else if (decimal === 3) {
|
||||
cell.z = "#,##0.000";
|
||||
} else {
|
||||
cell.z = "#,##0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
chaneValue(decimalArray0, 0);
|
||||
chaneValue(decimalArray1, 1);
|
||||
chaneValue(decimalArray2, 2);
|
||||
chaneValue(decimalArray3, 3);
|
||||
applyRangeFormat(decimalRange0, 0);
|
||||
applyRangeFormat(decimalRange1, 1);
|
||||
applyRangeFormat(decimalRange2, 2);
|
||||
applyRangeFormat(decimalRange3, 3);
|
||||
excelStyle(XLSX.write(workbook, { bookType: "xlsx", type: "buffer" }), headerRange, fileName);
|
||||
};
|
||||
|
||||
@@ -74,6 +116,10 @@ export type SheetParameter = {
|
||||
headerRange: string;
|
||||
sheetName: string;
|
||||
startCol?: string;
|
||||
decimalRange0?: string;
|
||||
decimalRange1?: string;
|
||||
decimalRange2?: string;
|
||||
decimalRange3?: string;
|
||||
};
|
||||
|
||||
export const downloadMultipleExcel = (fileName = new Date().getTime().toString() + '.xlsx', sheetArray: SheetParameter[]): Promise<JSON | undefined> => {
|
||||
@@ -201,9 +247,29 @@ export const filePickedBlob=(oFile: ArrayBuffer, data:[][],fileNm:string, header
|
||||
});
|
||||
}
|
||||
|
||||
export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArray: SheetParameter[]): Promise<JSON | undefined> => {
|
||||
return new Promise<JSON | undefined>(async () => {
|
||||
const wb = XLSX.read(oFile, { type: 'binary' });
|
||||
// export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArray: SheetParameter[]): Promise<JSON | undefined> => {
|
||||
// return new Promise<JSON | undefined>(async () => {
|
||||
// const wb = XLSX.read(oFile, { type: 'binary' });
|
||||
// wb.SheetNames.forEach(function (sheetName, index) {
|
||||
// if (sheetArray[index]) {
|
||||
// const sheet = wb.Sheets[sheetName];
|
||||
// if (sheet) {
|
||||
// const startCol = sheetArray[index].startCol ? sheetArray[index].startCol : 'A';
|
||||
// XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, { origin: startCol + sheetArray[index].headerNum });
|
||||
// } else {
|
||||
// console.error(`Sheet "${sheetName}" is undefined.`);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm)
|
||||
// });
|
||||
// }
|
||||
export const filePickedBlobArray = async (
|
||||
oFile: ArrayBuffer,
|
||||
fileNm: string,
|
||||
sheetArray: SheetParameter[]
|
||||
): Promise<JSON | undefined> => {
|
||||
const wb = XLSX.read(oFile, { type: 'binary' });
|
||||
wb.SheetNames.forEach(function (sheetName, index) {
|
||||
if (sheetArray[index]) {
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
@@ -215,9 +281,68 @@ export const filePickedBlobArray = (oFile: ArrayBuffer, fileNm: string, sheetArr
|
||||
}
|
||||
}
|
||||
});
|
||||
await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm)
|
||||
await excelArrayStyle(XLSX.write(wb, { bookType: "xlsx", type: "buffer" }), sheetArray, fileNm);
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const filePickedBlobArrayFormat = async (
|
||||
oFile: ArrayBuffer,
|
||||
fileNm: string,
|
||||
sheetArray: SheetParameter[]
|
||||
): Promise<JSON | undefined> => {
|
||||
const wb = XLSX.read(oFile, { type: "binary" });
|
||||
|
||||
wb.SheetNames.forEach((sheetName, index) => {
|
||||
if (sheetArray[index]) {
|
||||
const sheet = wb.Sheets[sheetName];
|
||||
if (sheet) {
|
||||
const startCol = sheetArray[index].startCol ?? "A";
|
||||
|
||||
XLSX.utils.sheet_add_aoa(sheet, sheetArray[index].data, {
|
||||
origin: startCol + sheetArray[index].headerNum,
|
||||
});
|
||||
const applyRangeFormat = (rangeStr: string | undefined, decimal: number) => {
|
||||
if (!rangeStr) return;
|
||||
const parts = rangeStr.split(",").map((part) => part.trim()).filter(Boolean);
|
||||
for (const part of parts) {
|
||||
const rangeInfo = XLSX.utils.decode_range(part);
|
||||
for (let row = rangeInfo.s.r; row <= rangeInfo.e.r; row++) {
|
||||
for (let col = rangeInfo.s.c; col <= rangeInfo.e.c; col++) {
|
||||
const cellAddr = XLSX.utils.encode_cell({ r: row, c: col });
|
||||
const cell = sheet[cellAddr];
|
||||
if (cell && typeof cell.v === "number") {
|
||||
if (decimal === 1) {
|
||||
cell.z = "#,##0.0";
|
||||
} else if (decimal === 2) {
|
||||
cell.z = "#,##0.00";
|
||||
} else if (decimal === 3) {
|
||||
cell.z = "#,##0.000";
|
||||
} else {
|
||||
cell.z = "#,##0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
applyRangeFormat(sheetArray[index].decimalRange0, 0);
|
||||
applyRangeFormat(sheetArray[index].decimalRange1, 1);
|
||||
applyRangeFormat(sheetArray[index].decimalRange2, 2);
|
||||
applyRangeFormat(sheetArray[index].decimalRange3, 3);
|
||||
} else {
|
||||
console.error(`Sheet "${sheetName}" is undefined.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
await excelArrayStyle(
|
||||
XLSX.write(wb, { bookType: "xlsx", type: "buffer" }),
|
||||
sheetArray,
|
||||
fileNm
|
||||
);
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
type ExcelDownloadWithHeaderProps = {
|
||||
data: JSON | JSON[];
|
||||
@@ -251,4 +376,4 @@ export const downloadExcelWithKoreanHeaders = async ({
|
||||
|
||||
// 3. 헤더만 한글로 교체하는 커스텀 스타일 함수 호출
|
||||
await excelStyleWithKoreanHeaders(buffer, headerRange, fileName, headerMapping, dataArray[0]);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -172,7 +172,7 @@ GisApp.core.prototype = {
|
||||
wmtsSource.setTileUrlFunction((tileCoord) => {
|
||||
const [z, x, y] = tileCoord;
|
||||
const matrix = matrixIds[z];
|
||||
console.log(GisApp.NGII_WMTS_URL.replace("{z}", matrix).replace("{x}", x).replace("{y}", y));
|
||||
// console.log(GisApp.NGII_WMTS_URL.replace("{z}", matrix).replace("{x}", x).replace("{y}", y));
|
||||
return GisApp.NGII_WMTS_URL
|
||||
.replace("{z}", matrix)
|
||||
.replace("{x}", x)
|
||||
|
||||
@@ -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>
|
||||
)),
|
||||
|
||||
@@ -1,27 +1,42 @@
|
||||
@tailwind components;
|
||||
|
||||
@layer components {
|
||||
|
||||
/* 상단 메뉴 호버 시 하단 라인 - 기본 테마 */
|
||||
.header-nav-link {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.header-nav-link::after {
|
||||
content: '';
|
||||
/* .header-nav-link::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
bottom: -4px;
|
||||
left: 0;
|
||||
width: 0;
|
||||
height: 2px;
|
||||
background-color: #063A74;
|
||||
background-color: #063a74;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.header-nav-link:hover::after {
|
||||
.header-nav-link:hover::before {
|
||||
width: 100%;
|
||||
} */
|
||||
|
||||
/* 네비게이션 아이템 사이 구분선 */
|
||||
.header-nav-link::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: -0.75rem;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
width: 1px !important;
|
||||
height: 1.5rem !important;
|
||||
background-color: var(--border);
|
||||
}
|
||||
|
||||
|
||||
.header-nav-link:first-child::after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
[data-theme="blue"] {
|
||||
header {
|
||||
background: #00afe5;
|
||||
@@ -35,7 +50,7 @@
|
||||
color: #fff;
|
||||
}
|
||||
header button[role="button"].primary {
|
||||
background-color: #008E8D !important;
|
||||
background-color: #008e8d !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
nav a,
|
||||
@@ -45,7 +60,7 @@
|
||||
.header-nav-link:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
.header-nav-link::after {
|
||||
.header-nav-link::before {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
@@ -63,7 +78,7 @@
|
||||
color: #fff;
|
||||
}
|
||||
header button[role="button"].primary {
|
||||
background-color: #008E8D !important;
|
||||
background-color: #008e8d !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
nav a,
|
||||
@@ -73,9 +88,8 @@
|
||||
.header-nav-link:hover {
|
||||
color: #fff !important;
|
||||
}
|
||||
.header-nav-link::after {
|
||||
.header-nav-link::before {
|
||||
background-color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import { SidebarTrigger } from "../sidebar";
|
||||
import { Popover, PopoverContent, PopoverTrigger } from "../popover";
|
||||
import { SearchForm } from "./search-form";
|
||||
import { NoticePopover } from "./notice-popover";
|
||||
import { ScrollArea, ScrollBar } from "../scroll-area";
|
||||
|
||||
const appConfig = getConfig();
|
||||
const userId = getCookie(appConfig.AUTH_USER_ID ?? "");
|
||||
@@ -64,66 +65,99 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
queryFn: () => getSiteList(),
|
||||
enabled: isLoggedIn && !viewOnly,
|
||||
});
|
||||
|
||||
const logout = async () => {
|
||||
try {
|
||||
// 1. 백엔드 API 로그아웃 호출
|
||||
const response = await fetch("/api/auth/logout", {
|
||||
method: "POST",
|
||||
credentials: "include", // ⭐ 쿠키 포함 중요!
|
||||
});
|
||||
if (!response.ok) throw new Error("Failed to logout");
|
||||
|
||||
const actualHost = window.location.hostname;
|
||||
|
||||
// 서브도메인 쿠키 삭제를 위한 루트 도메인 추출
|
||||
const getRootDomain = (hostname: string): string => {
|
||||
// localhost나 IP 주소인 경우
|
||||
if (hostname === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
// hasuon.or.kr 도메인인 경우
|
||||
if (hostname.includes("hasuon.or.kr")) {
|
||||
return ".hasuon.or.kr";
|
||||
}
|
||||
|
||||
// 일반적인 도메인의 경우 루트 도메인 추출 (예: sub.example.com → .example.com)
|
||||
const parts = hostname.split(".");
|
||||
if (parts.length >= 2) {
|
||||
// 마지막 두 부분을 사용 (예: example.com)
|
||||
return `.${parts.slice(-2).join(".")}`;
|
||||
}
|
||||
|
||||
return hostname;
|
||||
};
|
||||
|
||||
const domain = getRootDomain(actualHost);
|
||||
const cookieOptions = domain.startsWith(".") || domain === "localhost"
|
||||
? { domain }
|
||||
: {};
|
||||
|
||||
// 쿠키 삭제 (서브도메인 포함)
|
||||
if (appConfig.AUTH_USER_ID) {
|
||||
removeCookie(appConfig.AUTH_USER_ID, cookieOptions);
|
||||
if (!response.ok) {
|
||||
console.error("Logout API failed");
|
||||
// API 실패해도 계속 진행
|
||||
}
|
||||
if (appConfig.REFRESH_TOKEN) {
|
||||
removeCookie(appConfig.REFRESH_TOKEN, cookieOptions);
|
||||
}
|
||||
if (appConfig.ACCESS_TOKEN) {
|
||||
removeCookie(appConfig.ACCESS_TOKEN, cookieOptions);
|
||||
}
|
||||
if (appConfig.CLAIM_NAME) {
|
||||
removeCookie(appConfig.CLAIM_NAME, cookieOptions);
|
||||
}
|
||||
|
||||
removeCookie("site-id-key", cookieOptions);
|
||||
removeCookie("site-theme-key", cookieOptions);
|
||||
|
||||
window.location.href = "/auth/login";
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
console.error("Logout error:", error);
|
||||
// 에러가 나도 계속 진행
|
||||
} finally {
|
||||
// 2. 클라이언트 쿠키 삭제 (백업)
|
||||
clearClientCookies();
|
||||
|
||||
// 3. 로컬/세션 스토리지 정리
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.clear();
|
||||
sessionStorage.clear();
|
||||
}
|
||||
|
||||
// 4. 로그인 페이지로 리다이렉트
|
||||
window.location.href = "/auth/login";
|
||||
}
|
||||
};
|
||||
|
||||
// 쿠키 삭제 헬퍼 함수
|
||||
const clearClientCookies = () => {
|
||||
const actualHost = window.location.hostname;
|
||||
|
||||
// 루트 도메인 추출
|
||||
const getRootDomain = (hostname: string): string => {
|
||||
if (hostname === "localhost" || /^\d+\.\d+\.\d+\.\d+$/.test(hostname)) {
|
||||
return hostname;
|
||||
}
|
||||
|
||||
if (hostname.includes("hasuon.or.kr")) {
|
||||
return ".hasuon.or.kr";
|
||||
}
|
||||
|
||||
const parts = hostname.split(".");
|
||||
if (parts.length >= 2) {
|
||||
return `.${parts.slice(-2).join(".")}`;
|
||||
}
|
||||
|
||||
return hostname;
|
||||
};
|
||||
|
||||
const domain = getRootDomain(actualHost);
|
||||
|
||||
// 삭제할 쿠키 목록
|
||||
const cookiesToDelete = [
|
||||
appConfig.AUTH_USER_ID,
|
||||
appConfig.REFRESH_TOKEN,
|
||||
appConfig.ACCESS_TOKEN,
|
||||
appConfig.CLAIM_NAME,
|
||||
"site-id-key",
|
||||
"site-theme-key",
|
||||
].filter(Boolean); // undefined 제거
|
||||
|
||||
// 여러 방법으로 쿠키 삭제 시도
|
||||
cookiesToDelete.forEach((cookieName) => {
|
||||
if (!cookieName) return;
|
||||
|
||||
// 방법 1: removeCookie 함수 사용
|
||||
if (domain === "localhost") {
|
||||
removeCookie(cookieName, {});
|
||||
} else {
|
||||
removeCookie(cookieName, { domain });
|
||||
}
|
||||
|
||||
// 방법 2: 직접 document.cookie 설정 (도메인 포함)
|
||||
if (domain !== "localhost") {
|
||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}`;
|
||||
}
|
||||
|
||||
// 방법 3: 도메인 없이 삭제 (현재 도메인만)
|
||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;`;
|
||||
|
||||
// 방법 4: Secure 속성 포함 삭제
|
||||
if (window.location.protocol === "https:") {
|
||||
if (domain !== "localhost") {
|
||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; domain=${domain}; secure`;
|
||||
}
|
||||
document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; secure`;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const openPopup = useCallback(async (popup: Popup) => {
|
||||
try {
|
||||
const cookieName = `cs-popup-hide-for-day-${popup.popupSn}`;
|
||||
@@ -176,8 +210,8 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<header className="sticky top-0 z-30 box-border flex flex-col sm:flex-row h-[6rem] w-full items-center justify-between border-b border-solid border-border bg-background">
|
||||
<div className="flex items-center px-2 sm:px-4 md:px-6 w-full sm:w-auto justify-between sm:justify-start">
|
||||
<header className="sticky top-0 z-30 box-border flex h-[6rem] w-full flex-col items-center justify-between border-b border-solid border-border bg-background sm:flex-row">
|
||||
<div className="flex w-full items-center justify-between px-2 sm:w-auto sm:justify-start sm:px-4 md:px-6">
|
||||
<div className="flex items-center gap-2 sm:gap-4">
|
||||
<SidebarTrigger className="size-12 !bg-transparent p-2 hover:!bg-accent [&>svg]:!size-full [&>svg]:text-foreground" />
|
||||
<h1 className="flex flex-col items-center gap-2">
|
||||
@@ -199,7 +233,10 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
<span
|
||||
className="text-[1.2rem] font-semibold text-foreground"
|
||||
style={{
|
||||
letterSpacing: logoWidth > 0 ? `${(logoWidth - 120) / (siteInfo?.siteNm?.length || 1)}px` : '0.05em'
|
||||
letterSpacing:
|
||||
logoWidth > 0
|
||||
? `${(logoWidth - 120) / (siteInfo?.siteNm?.length || 1)}px`
|
||||
: "0.05em",
|
||||
}}
|
||||
>
|
||||
{siteInfo?.siteNm}
|
||||
@@ -214,7 +251,9 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
|
||||
className="m-0 flex h-[3rem] items-center !bg-background px-3 py-0 text-label"
|
||||
>
|
||||
<i className={`diveicon ${isMobileMenuOpen ? 'di-menu-close-fill' : 'di-menu-open-fill'} static text-4xl`} />
|
||||
<i
|
||||
className={`diveicon ${isMobileMenuOpen ? "di-menu-close-fill" : "di-menu-open-fill"} static text-4xl`}
|
||||
/>
|
||||
</Button>
|
||||
)}
|
||||
{mounted && isLoggedIn && (
|
||||
@@ -222,7 +261,9 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
<PopoverTrigger asChild>
|
||||
<Button className="group m-0 flex h-[3rem] items-center !bg-background px-2 py-0 text-label">
|
||||
<i className="diveicon di-account-circle static translate-y-0.5 pr-2 text-3xl" />
|
||||
<span className="text-xs hidden xs:inline">{userInfo?.userName}</span>
|
||||
<span className="xs:inline hidden text-xs">
|
||||
{userInfo?.userName}
|
||||
</span>
|
||||
<i className="diveicon di-chevron-down static p-0 transition-transform group-data-[state=open]:rotate-180" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
@@ -245,57 +286,60 @@ export function Header({ viewOnly }: { viewOnly?: boolean }) {
|
||||
</div>
|
||||
{/* 모바일에서 네비게이션 (토글 시 표시) */}
|
||||
{isMobileMenuOpen && (
|
||||
<div className="w-full sm:hidden border-t border-border bg-background py-2">
|
||||
{mounted && userSiteList?.content && userSiteList.content.length > 0 && (
|
||||
<nav className="flex flex-col items-center gap-2 px-4">
|
||||
<div className="w-full border-t border-border bg-background py-2 sm:hidden">
|
||||
{mounted &&
|
||||
userSiteList?.content &&
|
||||
userSiteList.content.length > 0 && (
|
||||
<nav className="flex flex-col items-center gap-2 px-4">
|
||||
{userSiteList.content.map((site) => (
|
||||
<a
|
||||
key={site.siteId}
|
||||
href={site.dmnAddr}
|
||||
className="w-full py-2 text-center text-xl font-medium text-foreground transition-colors hover:text-primary"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
{site.siteNm}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* 데스크톱에서 중간 네비게이션 */}
|
||||
<ScrollArea className="hidden max-w-[calc(100vw-60rem)] flex-1 items-center justify-center px-2 py-4 sm:flex">
|
||||
{mounted &&
|
||||
userSiteList?.content &&
|
||||
userSiteList.content.length > 0 && (
|
||||
<nav className="flex w-full flex-nowrap items-center justify-start gap-3 overflow-x-auto whitespace-nowrap md:gap-6">
|
||||
{userSiteList.content.map((site) => (
|
||||
<a
|
||||
key={site.siteId}
|
||||
href={site.dmnAddr}
|
||||
className="text-xl font-medium text-foreground hover:text-primary transition-colors w-full text-center py-2"
|
||||
className="header-nav-link whitespace-nowrap text-sm font-medium text-foreground transition-colors hover:text-primary md:text-lg lg:text-2xl"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
onClick={() => setIsMobileMenuOpen(false)}
|
||||
>
|
||||
{site.siteNm}
|
||||
</a>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{/* 데스크톱에서 중간 네비게이션 */}
|
||||
<div className="hidden sm:flex items-center flex-1 justify-center px-2">
|
||||
{mounted && userSiteList?.content && userSiteList.content.length > 0 && (
|
||||
<nav className="flex items-center gap-3 md:gap-6 flex-wrap justify-center">
|
||||
{userSiteList.content.map((site, index) => (
|
||||
<div key={site.siteId} className="flex items-center">
|
||||
<a
|
||||
href={site.dmnAddr}
|
||||
className="text-sm md:text-lg lg:text-2xl font-medium text-foreground hover:text-primary transition-colors header-nav-link"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
{site.siteNm}
|
||||
</a>
|
||||
{index < userSiteList.content.length - 1 && (
|
||||
<div className="w-px h-4 md:h-6 bg-border ml-3 md:ml-6"></div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
)}
|
||||
</div>
|
||||
<ScrollBar orientation="horizontal" />
|
||||
</ScrollArea>
|
||||
{/* 데스크톱에서 오른쪽 요소들 */}
|
||||
<div className="hidden sm:flex items-center gap-2 px-2 md:px-4">
|
||||
<div className="hidden items-center gap-2 px-2 sm:flex md:px-4">
|
||||
<SearchForm />
|
||||
{mounted ? (
|
||||
isLoggedIn && (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button className="group m-0 flex h-[3rem] items-center !bg-background px-2 md:px-4 py-0 text-label">
|
||||
<i className="diveicon di-account-circle static translate-y-0.5 pr-1 md:pr-2 text-2xl md:text-3xl" />
|
||||
<span className="text-sm md:text-base hidden md:inline">{userInfo?.userName}</span>
|
||||
<Button className="group m-0 flex h-[3rem] items-center !bg-background px-2 py-0 text-label md:px-4">
|
||||
<i className="diveicon di-account-circle static translate-y-0.5 pr-1 text-2xl md:pr-2 md:text-3xl" />
|
||||
<span className="hidden text-sm md:inline md:text-base">
|
||||
{userInfo?.userName}
|
||||
</span>
|
||||
<i className="diveicon di-chevron-down static p-0 transition-transform group-data-[state=open]:rotate-180" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user