513 lines
14 KiB
TypeScript
513 lines
14 KiB
TypeScript
/**====================================
|
|
* 보편적으로 쓰는 store 공간
|
|
====================================**/
|
|
|
|
import { fetchType, getFetch } from '@/components/ui/api';
|
|
|
|
/**
|
|
* STORE - TYPE
|
|
*/
|
|
|
|
// selectBox
|
|
export type SelectDataType = {
|
|
text: string;
|
|
val: string;
|
|
}
|
|
|
|
export interface MenuItem {
|
|
menuCd: number;
|
|
menuKornNm: string;
|
|
menuEngNm: string;
|
|
parentId: number | null;
|
|
sortSeq: number;
|
|
iconNm?: string;
|
|
children: MenuItem[] | null;
|
|
levelNo: number;
|
|
urlPath: string;
|
|
menuLnkgTypeCd: string;
|
|
menuLnkgSn: number;
|
|
menuPath: string;
|
|
qrcd: string;
|
|
useYn: string;
|
|
otptYn: string;
|
|
newWndwYn: string;
|
|
requiredUrlPath: boolean;
|
|
}
|
|
|
|
// grid header
|
|
export type TableUpperProps = {
|
|
id: string;
|
|
title: string;
|
|
upName?: string;
|
|
upSequnce?: number;
|
|
align? : string;
|
|
row? : number;
|
|
rowSpan?: number;
|
|
colSpan?: number;
|
|
}
|
|
|
|
// 시도 데이터
|
|
export type sidoDataType = {
|
|
adstDstrCd: number,
|
|
sido: string,
|
|
}
|
|
|
|
// 시군구 데이터
|
|
export type sigunDataType = {
|
|
adstDstrCd: number,
|
|
gugun: string
|
|
}
|
|
|
|
// 권역 데이터
|
|
export type regionDataType = {
|
|
rvbsnCd: string,
|
|
rvbsn: string,
|
|
}
|
|
|
|
// 단위유역 데이터
|
|
export type unitWaterShedDataType = {
|
|
rvbsnCd: string,
|
|
lgbsn: string,
|
|
}
|
|
|
|
// 중권역 데이터
|
|
export type middleRegionDataType = {
|
|
rvbsnCd: string,
|
|
mdmbsn: string,
|
|
}
|
|
|
|
// 환경청 데이터
|
|
export type envPartDataType = {
|
|
lclgvrnmntCd: string,
|
|
lclgvrnmntNm: string,
|
|
adstDliStrCd: string,
|
|
adstDstrCd: string,
|
|
}
|
|
|
|
export type envPartSelectDataType = SelectDataType & {
|
|
adstDliStrCd: string,
|
|
}
|
|
|
|
/**
|
|
* STORE - DATA
|
|
*/
|
|
|
|
// 시도 데이터
|
|
let selectSidoData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
// 시군구 데이터
|
|
let selectSigunData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
// 권역 데이터
|
|
const selectRegionData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
// 단위유역 데이터
|
|
const selectUnitWaterShedData: SelectDataType[] = [
|
|
];
|
|
|
|
// 환경청 데이터
|
|
let selectEnvPartData: envPartSelectDataType[] = [
|
|
{ text: "전체", val: '0', adstDliStrCd: '' }
|
|
];
|
|
|
|
// 환경청 내 시도 데이터
|
|
const selectEnvPartSidoData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
// 환경청 내 시군구 데이터
|
|
const selectEnvPartSigunData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
// 구분 데이터
|
|
// const selectPartData:SelectDataType[] = [
|
|
// { text: "행정별", val: '0' },
|
|
// { text: "유역별", val: '01' },
|
|
// { text: "환경청별", val: '02' },
|
|
// ];
|
|
|
|
// 상향 하향 데이터
|
|
const selectUpdownData:SelectDataType[] = [
|
|
{ text: "전체", val: '0' },
|
|
{ text: "500이하", val: '499' },
|
|
{ text: "500이상", val: '500' },
|
|
];
|
|
|
|
// 운영 상태 데이터
|
|
const selectOperationData:SelectDataType[] = [
|
|
{ text: "전체", val: '0' },
|
|
{ text: "가동중", val: '1' },
|
|
{ text: "재가동", val: '2' },
|
|
{ text: "가동중지", val: '3' },
|
|
{ text: "시설폐쇄", val: '4' },
|
|
];
|
|
|
|
// 시설 구분 데이터
|
|
const selectFacilityPartData:SelectDataType[] = [
|
|
{ text: "전체", val: '0' },
|
|
{ text: "공공하수처리시설", val: 'SW' },
|
|
{ text: "오수처리장", val: 'SS' },
|
|
{ text: "개인하수처리시설", val: 'PB' },
|
|
{ text: "분뇨처리장", val: 'NS' },
|
|
{ text: "폐수처리장", val: 'LW' },
|
|
{ text: "침출수처리장", val: 'LC' },
|
|
{ text: "기타기초시설", val: 'ET' },
|
|
];
|
|
|
|
// 년도 데이터
|
|
const getYearData = () => {
|
|
const year = new Date().getFullYear();
|
|
const year1 = year - 1;
|
|
const year2 = year - 2;
|
|
const year3 = year - 3;
|
|
const year4 = year - 4;
|
|
const year5 = year - 5;
|
|
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() },
|
|
]
|
|
}
|
|
|
|
const selectSearchYear:SelectDataType[] = getYearData();
|
|
|
|
// 유량 기간 구분
|
|
const selectFlowTerm : SelectDataType[] = [
|
|
{ text: "연간", val: '0' },
|
|
{ text: "하절기", val: '01' },
|
|
{ text: "동절기", val: '02' },
|
|
{ text: "청천시", val: '03' },
|
|
{ text: "강우시", val: '04' },
|
|
];
|
|
|
|
// 유량 기간 구분
|
|
const selectFlowPanel : SelectDataType[] = [
|
|
{ text: "전체", val: '0'},
|
|
{ text: "3mm미만", val: '1'},
|
|
{ text: "3~10mm미만", val: '2'},
|
|
{ text: "10~20mm미만", val: '3'},
|
|
{ text: "20~30mm미만", val: '4'},
|
|
{ text: "30~40mm미만", val: '5'},
|
|
{ text: "40~50mm미만", val: '6'},
|
|
{ text: "50~60mm미만", val: '7'},
|
|
{ text: "60mm이상", val: '8'},
|
|
];
|
|
|
|
// 중권역 데이터
|
|
const selectMiddleRegionData: SelectDataType[] = [
|
|
{ text: "전체", val: '0' }
|
|
];
|
|
|
|
/**
|
|
* STORE - API
|
|
*/
|
|
|
|
/** API 선택 목록의 빈 값과 중복 값을 제거하고 전체 항목을 한 번만 추가한다. */
|
|
function normalizeSelectData<T extends SelectDataType>(items: T[], allItem: T): T[] {
|
|
const uniqueItems = new Map<string, T>();
|
|
|
|
items.forEach((item) => {
|
|
const val = String(item.val ?? '').trim();
|
|
|
|
if (!val || val === '0' || uniqueItems.has(val)) return;
|
|
uniqueItems.set(val, { ...item, val });
|
|
});
|
|
|
|
return [allItem, ...uniqueItems.values()];
|
|
}
|
|
|
|
// 시도 API 호출 함수 추가
|
|
const fetchSidoData = async (): Promise<SelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/city');
|
|
const data = res.data;
|
|
selectSidoData = normalizeSelectData(
|
|
data.map((item: sidoDataType) => ({
|
|
text: item.sido || '',
|
|
val: String(item.adstDstrCd) || ''
|
|
})),
|
|
{ text: "전체", val: '0' }
|
|
);
|
|
return selectSidoData;
|
|
} catch (error) {
|
|
console.error('시도 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectSidoData;
|
|
}
|
|
};
|
|
|
|
// 시군구 API 호출 함수 추가
|
|
const fetchSigunData = async (): Promise<SelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/sgg');
|
|
const data = res.data;
|
|
selectSigunData = normalizeSelectData(
|
|
data.map((item: sigunDataType) => ({
|
|
text: item.gugun || '',
|
|
val: String(item.adstDstrCd) || ''
|
|
})),
|
|
{ text: "전체", val: '0' }
|
|
);
|
|
return selectSigunData;
|
|
} catch (error) {
|
|
console.error('시군구 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectSigunData;
|
|
}
|
|
};
|
|
|
|
// 권역 API 호출 함수 추가
|
|
const fetchRegionData = async (): Promise<SelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/sarea');
|
|
const data = res.data;
|
|
return normalizeSelectData(
|
|
data.map((item: regionDataType) => ({
|
|
text: item.rvbsn || '',
|
|
val: String(item.rvbsnCd) || ''
|
|
})),
|
|
{ text: "전체", val: '0' }
|
|
);
|
|
} catch (error) {
|
|
console.error('권역 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectRegionData;
|
|
}
|
|
};
|
|
|
|
// 중권역 API 호출 함수 추가
|
|
const fetchMiddleRegionData = async (): Promise<SelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/midArea');
|
|
const data = res.data;
|
|
return normalizeSelectData(
|
|
data.map((item: middleRegionDataType) => ({
|
|
text: item.mdmbsn || '',
|
|
val: String(item.rvbsnCd) || ''
|
|
})),
|
|
{ text: "전체", val: '0' }
|
|
);
|
|
} catch (error) {
|
|
console.error('중권역 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectMiddleRegionData;
|
|
}
|
|
};
|
|
|
|
// 단위유역 API 호출 함수 추가
|
|
const fetchUnitWaterShedData = async (): Promise<SelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/largeArea');
|
|
const data = res.data;
|
|
return normalizeSelectData(
|
|
data.map((item: unitWaterShedDataType) => ({
|
|
text: item.lgbsn || '',
|
|
val: String(item.rvbsnCd) || ''
|
|
})),
|
|
{ text: "전체", val: '0' }
|
|
);
|
|
} catch (error) {
|
|
console.error('단위유역 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectUnitWaterShedData;
|
|
}
|
|
};
|
|
|
|
// 환경청 데이터
|
|
const fetchEnvPartData = async (): Promise<envPartSelectDataType[]> => {
|
|
try {
|
|
const res = await getFetch(fetchType.FO, '/addr/govArea');
|
|
const data = res.data;
|
|
selectEnvPartData = normalizeSelectData(
|
|
data.map((item: envPartDataType) => ({
|
|
text: item.lclgvrnmntNm || '',
|
|
val: String(item.lclgvrnmntCd) || '',
|
|
adstDliStrCd: item.adstDliStrCd || ''
|
|
})),
|
|
{ text: "전체", val: '0', adstDliStrCd: '' }
|
|
);
|
|
return selectEnvPartData;
|
|
} catch (error) {
|
|
console.error('환경청 데이터를 가져오는데 실패했습니다:', error);
|
|
return selectEnvPartData;
|
|
}
|
|
};
|
|
|
|
function sortMenus(items: MenuItem[]): MenuItem[] {
|
|
return [...items]
|
|
.sort((a, b) => a.sortSeq - b.sortSeq)
|
|
.map((item) => ({
|
|
...item,
|
|
children: item.children ? sortMenus(item.children) : [],
|
|
}));
|
|
}
|
|
|
|
function isVisible(item: MenuItem): boolean {
|
|
return item.useYn !== "N" && item.otptYn !== "N";
|
|
}
|
|
|
|
function normalizeMenus(items: MenuItem[]): MenuItem[] {
|
|
return sortMenus(items)
|
|
.filter(isVisible)
|
|
.map((item) => ({
|
|
...item,
|
|
children: item.children ? normalizeMenus(item.children) : [],
|
|
}));
|
|
}
|
|
|
|
export const REUSE_SITE_ID = process.env.NEXT_PUBLIC_SITE_ID || "DM";
|
|
const anonymousMenuCache = new Map<string, MenuItem[]>();
|
|
const anonymousMenuInFlight = new Map<string, Promise<MenuItem[]>>();
|
|
|
|
export async function fetchAnonymousMenu(siteId = REUSE_SITE_ID): Promise<MenuItem[]> {
|
|
const cached = anonymousMenuCache.get(siteId);
|
|
if (cached) return cached;
|
|
|
|
const inFlight = anonymousMenuInFlight.get(siteId);
|
|
if (inFlight) return inFlight;
|
|
|
|
const request = (async () => {
|
|
const response = await fetch(`/cms-service/api/v1/menu/anonymous/user/${siteId}`, {
|
|
method: "GET",
|
|
headers: { "Content-Type": "application/json" },
|
|
cache: "no-store",
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to load menu: ${response.status}`);
|
|
}
|
|
|
|
const data = (await response.json()) as MenuItem[];
|
|
const normalized = Array.isArray(data) ? normalizeMenus(data) : [];
|
|
anonymousMenuCache.set(siteId, normalized);
|
|
return normalized;
|
|
})();
|
|
|
|
anonymousMenuInFlight.set(siteId, request);
|
|
try {
|
|
return await request;
|
|
} finally {
|
|
anonymousMenuInFlight.delete(siteId);
|
|
}
|
|
}
|
|
|
|
function isPathMatched(pathname: string, urlPath: string) {
|
|
if (!urlPath) return false;
|
|
return pathname === urlPath || pathname.startsWith(`${urlPath}/`);
|
|
}
|
|
|
|
function hasMatchedPathInTree(menu: MenuItem, pathname: string): boolean {
|
|
if (isPathMatched(pathname, menu.urlPath)) return true;
|
|
return (menu.children ?? []).some((child) => hasMatchedPathInTree(child, pathname));
|
|
}
|
|
|
|
export function findActiveTopMenu(menus: MenuItem[], pathname: string): MenuItem | null {
|
|
const level1Menus = menus.filter((menu) => menu.levelNo === 1 || menu.parentId === null);
|
|
const matched = level1Menus.filter((menu) => hasMatchedPathInTree(menu, pathname));
|
|
|
|
return matched[0] ?? level1Menus[0] ?? null;
|
|
}
|
|
|
|
export function hasAnyChild(item: MenuItem): boolean {
|
|
return Array.isArray(item.children) && item.children.length > 0;
|
|
}
|
|
|
|
export function isMenuActive(pathname: string, menu: MenuItem): boolean {
|
|
return isPathMatched(pathname, menu.urlPath);
|
|
}
|
|
/**====================================
|
|
* Store - expaort
|
|
====================================*/
|
|
export type CommonAction = {
|
|
initializeCommonData: () => Promise<void>;
|
|
getMenuAuth: (menuCd:number) => Promise<void>;
|
|
fetchAnonymousMenu: (siteId?: string) => Promise<MenuItem[]>;
|
|
}
|
|
|
|
export type CommonType = {
|
|
Common: {
|
|
isInit: boolean;
|
|
selectSidoData: SelectDataType[];
|
|
selectSigunData: SelectDataType[];
|
|
selectUpdownData: SelectDataType[];
|
|
selectOperationData: SelectDataType[];
|
|
selectFacilityPartData: SelectDataType[];
|
|
selectSearchYear: SelectDataType[];
|
|
selectUnitWaterShedData: SelectDataType[];
|
|
selectRegionData: SelectDataType[];
|
|
selectMiddleRegionData: SelectDataType[];
|
|
selectEnvPartSidoData: SelectDataType[];
|
|
selectEnvPartSigunData: SelectDataType[];
|
|
selectFlowTerm: SelectDataType[];
|
|
selectFlowPanel: SelectDataType[];
|
|
selectEnvPartData: envPartSelectDataType[];
|
|
btnClass: string;
|
|
}
|
|
}
|
|
|
|
export const CommonState:CommonType = {
|
|
Common: {
|
|
isInit: false,
|
|
selectSidoData: selectSidoData,
|
|
selectSigunData: selectSigunData,
|
|
selectUpdownData: selectUpdownData,
|
|
selectOperationData: selectOperationData,
|
|
selectFacilityPartData: selectFacilityPartData,
|
|
selectSearchYear: selectSearchYear,
|
|
selectRegionData: selectRegionData,
|
|
selectUnitWaterShedData: selectUnitWaterShedData,
|
|
selectMiddleRegionData: selectMiddleRegionData,
|
|
selectEnvPartSidoData : selectEnvPartSidoData,
|
|
selectEnvPartSigunData : selectEnvPartSigunData,
|
|
selectFlowTerm: selectFlowTerm,
|
|
selectFlowPanel: selectFlowPanel,
|
|
selectEnvPartData : selectEnvPartData,
|
|
btnClass: "p-4 m-2 text-white rounded-sm text-lg font-medium"
|
|
}
|
|
}
|
|
|
|
export const CommonReducer:(set:any)=>CommonAction=(set: any) => {
|
|
return {
|
|
getMenuAuth : async (menuCd : number) =>{
|
|
const response = await getFetch(
|
|
"local",
|
|
`/cms-service/api/v1/menu-authrts/pageinfo/${menuCd}`
|
|
);
|
|
set((state: CommonType) => {
|
|
return {
|
|
...state,
|
|
auth: {
|
|
mngAuthrtYn: response[0].mngAuthrtYn,
|
|
inqAuthrtYn: response[0].mngAuthrtYn,
|
|
regAuthrtYn: response[0].mngAuthrtYn,
|
|
mdfcnAuthrtYn: response[0].mngAuthrtYn,
|
|
delAuthrtYn: response[0].mngAuthrtYn,
|
|
},
|
|
};
|
|
});
|
|
},
|
|
// 시도 변경 이벤트
|
|
initializeCommonData: async () => {
|
|
const promiseSet = await Promise.all([fetchSidoData(), fetchSigunData(), fetchRegionData(), fetchUnitWaterShedData(), fetchMiddleRegionData(), fetchEnvPartData()]);
|
|
const [sidoData, sggData, regionData, unitData, midData, envData] = promiseSet;
|
|
set((state: CommonType) => ({
|
|
Common: {
|
|
...state.Common,
|
|
selectSidoData: sidoData,
|
|
selectSigunData: sggData,
|
|
selectRegionData: regionData,
|
|
selectMiddleRegionData: midData,
|
|
selectUnitWaterShedData: unitData,
|
|
selectEnvPartData: envData
|
|
}
|
|
})
|
|
)},
|
|
fetchAnonymousMenu: async (siteId = REUSE_SITE_ID) => fetchAnonymousMenu(siteId),
|
|
}
|
|
}
|
|
export type CommonStore = CommonType & CommonAction;
|