Merge branch 'feature/review-skeleton-sein' of https://www.onasys.co.kr:3000/ONAANDALL/frontend into iipbs/st/dev
This commit is contained in:
+2
-1
@@ -38,4 +38,5 @@ yarn-error.log*
|
||||
next-env.d.ts
|
||||
|
||||
.env*
|
||||
!.env.example
|
||||
!.env.example
|
||||
*.md
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
{
|
||||
"plugins": ["prettier-plugin-tailwindcss"]
|
||||
"plugins": ["prettier-plugin-tailwindcss"],
|
||||
"tabWidth": 4
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useCallback } from "react";
|
||||
import { useEffect, useCallback, useMemo } from "react";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { useQueryClient, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import type { MenuItem } from "@/entities/menu";
|
||||
import { useMenuStore, useAlertStore } from "@/shared/lib";
|
||||
import { useTabStore, getTabStoreState } from "@/store/tab-store";
|
||||
import { useTabStore as gridTabStore } from "@rsone/components";
|
||||
import { getConfig } from "@common/config";
|
||||
import { getCookie } from "@/shared/lib";
|
||||
import { getMenuList } from "../../../../packages/common/components/src/api";
|
||||
@@ -29,10 +30,17 @@ export default function WithBaseLayout({
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const setCurrentMenuInfo = useMenuStore((state) => state.setCurrentMenuInfo);
|
||||
const currentMenuInfo = useMenuStore((state) => state.currentMenuInfo);
|
||||
|
||||
const addTab = useTabStore((state) => state.addTab);
|
||||
const setActiveTab = useTabStore((state) => state.setActiveTab);
|
||||
const setMenuList = useTabStore((state) => state.setMenuList);
|
||||
const activeTabId = useTabStore((state) => state.activeTabId);
|
||||
const menuList = useTabStore((state) => state.menuList);
|
||||
const tabs = useTabStore((state) => state.tabs);
|
||||
const addTabForGrid = gridTabStore((state) => state.addTab);
|
||||
const setActiveTabForGrid = gridTabStore((state) => state.setActiveTab);
|
||||
const setMenuListForGrid = gridTabStore((state) => state.setMenuList);
|
||||
const alert = useAlertStore((state) => state.setMessage);
|
||||
|
||||
const { data: menuListData } = useQuery({
|
||||
@@ -44,8 +52,9 @@ export default function WithBaseLayout({
|
||||
useEffect(() => {
|
||||
if (menuListData) {
|
||||
setMenuList(menuListData);
|
||||
setMenuListForGrid(menuListData);
|
||||
}
|
||||
}, [menuListData, setMenuList]);
|
||||
}, [menuListData, setMenuList, setMenuListForGrid]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!pathname) return;
|
||||
@@ -55,23 +64,73 @@ export default function WithBaseLayout({
|
||||
const tab = currentTabs.find((t) => t.path === pathname);
|
||||
if (tab) {
|
||||
setActiveTab(tab.id);
|
||||
setActiveTabForGrid(tab.id);
|
||||
}
|
||||
}, [pathname, setActiveTab]);
|
||||
}, [pathname, setActiveTab, setActiveTabForGrid]);
|
||||
|
||||
// 활성 탭의 메뉴를 찾아서 urlPath를 가져옴. 탭이 전부 닫히면 ''를 넘겨 LNB에서 메뉴 강조 제거
|
||||
const currentPath = useMemo(() => {
|
||||
if (tabs.length === 0) return "";
|
||||
|
||||
if (activeTabId && menuList) {
|
||||
// menuList에서 활성 탭의 메뉴 찾기
|
||||
const findMenuByEngNm = (items: MenuItem[]): MenuItem | null => {
|
||||
for (const item of items) {
|
||||
if (item.menuEngNm === activeTabId) {
|
||||
return item;
|
||||
}
|
||||
if (item.children) {
|
||||
const found = findMenuByEngNm(item.children);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
const activeMenu = findMenuByEngNm(menuList);
|
||||
|
||||
if (activeMenu?.urlPath) {
|
||||
return activeMenu.urlPath;
|
||||
}
|
||||
}
|
||||
|
||||
// 탭에서 직접 찾기
|
||||
if (activeTabId) {
|
||||
const currentTabs = getTabStoreState().tabs;
|
||||
const activeTab = currentTabs.find((t) => t.id === activeTabId);
|
||||
if (activeTab?.menuItem?.urlPath) {
|
||||
return activeTab.menuItem.urlPath;
|
||||
}
|
||||
}
|
||||
|
||||
// currentMenuInfo에서 가져오기
|
||||
if (currentMenuInfo?.urlPath) {
|
||||
return currentMenuInfo.urlPath;
|
||||
}
|
||||
|
||||
// 기본값으로 pathname 사용
|
||||
return pathname ?? "";
|
||||
}, [tabs.length, activeTabId, menuList, currentMenuInfo, pathname]);
|
||||
|
||||
const handleMenuClick = useCallback((item: MenuItem) => {
|
||||
setCurrentMenuInfo(item);
|
||||
const addTabResult: boolean = addTab(item);
|
||||
|
||||
// packages/rsone의 스토어에도 동기화
|
||||
if (addTabResult) {
|
||||
addTabForGrid(item);
|
||||
}
|
||||
|
||||
if (!addTabResult) {
|
||||
alert(`최대 추가 할 수 있는 화면 수를 초과 하였습니다.
|
||||
기존 화면을 닫은 후 이용해주세요.`);
|
||||
}
|
||||
}, [setCurrentMenuInfo, addTab]);
|
||||
}, [setCurrentMenuInfo, addTab, addTabForGrid, alert]);
|
||||
|
||||
return (
|
||||
<BaseLayout
|
||||
queryClient={queryClient}
|
||||
currentPath={pathname ?? ""}
|
||||
currentPath={currentPath}
|
||||
handleMenuClick={handleMenuClick}
|
||||
>
|
||||
<StatisticsPageLayout>{children}</StatisticsPageLayout>
|
||||
|
||||
@@ -32,7 +32,7 @@ export function middleware(req: NextRequest) {
|
||||
`[Request]\n Original Pathname: ${pathname}`,
|
||||
];
|
||||
|
||||
if (pathname.startsWith("/st-service")) {
|
||||
if (pathname.startsWith("/st-management-service") || pathname.startsWith("/st-input-service")) {
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
const token = req.cookies.get(CLAIM_NAME)?.value;
|
||||
const userId = req.cookies.get(AUTH_USER_ID)?.value;
|
||||
@@ -138,5 +138,5 @@ export function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
export const config = {
|
||||
matcher: ["/server/:path*", "/attach-service/:path*", "/api/link/:path*", "/st-service/:path*", "/"],
|
||||
matcher: ["/server/:path*", "/attach-service/:path*", "/api/link/:path*", "/st-management-service/:path*", "/st-input-service/:path*", "/"],
|
||||
};
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"@common/assets": "workspace:*",
|
||||
"@common/components": "workspace:*",
|
||||
"@common/config": "workspace:*",
|
||||
"@faker-js/faker": "^9.9.0",
|
||||
"@fontsource-variable/noto-sans-kr": "^5.2.5",
|
||||
"@frontend-opensource/use-react-hooks": "^1.1.4",
|
||||
"@fullcalendar/core": "^6.1.17",
|
||||
@@ -25,6 +26,7 @@
|
||||
"@radix-ui/react-label": "^2.1.2",
|
||||
"@radix-ui/react-slot": "^1.1.2",
|
||||
"@radix-ui/react-tooltip": "^1.1.8",
|
||||
"@rsone/components": "workspace:*",
|
||||
"@tanstack/react-query": "^5.67.1",
|
||||
"@tanstack/react-query-devtools": "^5.75.5",
|
||||
"@tanstack/react-table": "^8.21.2",
|
||||
|
||||
@@ -13,6 +13,7 @@ import { PromptDialog } from "@/shared/ui/prompt-dialog";
|
||||
import { ConfirmDialog } from "@/shared/ui/confirm-dialog";
|
||||
import { SelectPromptDialog } from "@/shared/ui/select-prompt-dialog";
|
||||
import { PromptProvider, StoreProvider } from "@/shared/providers";
|
||||
import { AlertDialog as RsoneAlertDialog } from "@rsone/components";
|
||||
|
||||
const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
const queryClient = new QueryClient();
|
||||
@@ -31,6 +32,7 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => {
|
||||
</DndProvider>
|
||||
</MenuWrapper>
|
||||
<AlertDialog />
|
||||
<RsoneAlertDialog />
|
||||
<PromptDialog />
|
||||
<ConfirmDialog />
|
||||
<SelectPromptDialog />
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface AddArticleButtonProps {
|
||||
addArticleFunc: () => void;
|
||||
}
|
||||
|
||||
const AddArticleButton = ({ addArticleFunc }: AddArticleButtonProps) => {
|
||||
return (
|
||||
<Button className="h-[3.2rem] w-[96px]" onClick={addArticleFunc}>
|
||||
<i className="ri-add-fill" />
|
||||
<span>항목 추가</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default AddArticleButton;
|
||||
@@ -6,9 +6,9 @@ interface ApproveButtonProps {
|
||||
|
||||
const ApproveButton = ({ approveFunc }: ApproveButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="px-6" onClick={approveFunc}>
|
||||
<i className="diveicon di-check-circle translate-y-[1px]" />
|
||||
<span className="translate-y-[-1px]">승인</span>
|
||||
<Button className="h-[3.2rem] w-[96px]" onClick={approveFunc}>
|
||||
<i className="diveicon di-check-circle" />
|
||||
<span>승인</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface DeleteArticleButtonProps {
|
||||
deleteArticleFunc: () => void;
|
||||
}
|
||||
|
||||
const DeleteArticleButton = ({ deleteArticleFunc }: DeleteArticleButtonProps) => {
|
||||
return (
|
||||
<Button className="h-[3.2rem] w-[96px]" color="red" onClick={deleteArticleFunc}>
|
||||
<i className="ri-subtract-fill"></i>
|
||||
<span>항목 제거</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeleteArticleButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface InstallationStatusButtonProps {
|
||||
installationStatusFunc: () => void;
|
||||
}
|
||||
|
||||
const InstallationStatusButton = ({ installationStatusFunc }: InstallationStatusButtonProps) => {
|
||||
return (
|
||||
<Button className="h-[3.2rem] w-[176px]" color="lightGray" onClick={installationStatusFunc}>
|
||||
<i className="diveicon di-server-line"></i>
|
||||
<span>시설별 설치 현황관리</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default InstallationStatusButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface LastYearDataButtonProps {
|
||||
getLastYearDataFunc: () => void;
|
||||
}
|
||||
|
||||
const LastYearDataButton = ({ getLastYearDataFunc }: LastYearDataButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="h-[3.2rem] w-[176px]" onClick={getLastYearDataFunc}>
|
||||
<i className="diveicon di-search" />
|
||||
<span>지난연도 데이터 가져오기</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default LastYearDataButton;
|
||||
@@ -0,0 +1,28 @@
|
||||
import { Checkbox, buttonVariants, cn } from "@common/components";
|
||||
import type React from "react";
|
||||
|
||||
interface NotApplicableCheckButtonProp {
|
||||
isCheck: boolean;
|
||||
setIsCheck: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
}
|
||||
|
||||
const NotApplicableCheckButton = ({ isCheck, setIsCheck }: NotApplicableCheckButtonProp) => {
|
||||
|
||||
const handleCheckChange = (value: boolean) => {
|
||||
setIsCheck(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={cn(buttonVariants({ variant: "default", size: "default" }), "w-[124px] bg-[#ebebeb] border border-[#999] text-[rgb(146 146 146)] text-opacity-100")}>
|
||||
<label htmlFor="notApplicable">해당사항 없음</label>
|
||||
<Checkbox
|
||||
id="notApplicable"
|
||||
className="!border-[#999] data-[state=checked]:!bg-[#999]"
|
||||
checked={isCheck}
|
||||
onCheckedChange={handleCheckChange}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotApplicableCheckButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface OperateDataButtonProps {
|
||||
getOperateDataFunc: () => void;
|
||||
}
|
||||
|
||||
const OperateDataButton = ({ getOperateDataFunc }: OperateDataButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="h-[3.2rem] w-[176px]" onClick={getOperateDataFunc}>
|
||||
<i className="diveicon di-arrow-left-right" />
|
||||
<span>운영 데이터 가져오기</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default OperateDataButton;
|
||||
@@ -6,9 +6,9 @@ interface RejectButtonProps {
|
||||
|
||||
const RejectButton = ({ rejectFunc }: RejectButtonProps) => {
|
||||
return (
|
||||
<Button color="red" className="px-6" onClick={rejectFunc}>
|
||||
<i className="diveicon di-exclamation-circle translate-y-[1px]" />
|
||||
<span className="translate-y-[-1px]">보완 요청</span>
|
||||
<Button color="red" className="h-[3.2rem] w-[96px]" onClick={rejectFunc}>
|
||||
<i className="diveicon di-exclamation-circle" />
|
||||
<span>보완 요청</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface ReturnButtonProps {
|
||||
returnFunc: () => void;
|
||||
}
|
||||
|
||||
const ReturnButton = ({ returnFunc }: ReturnButtonProps) => {
|
||||
return (
|
||||
<Button color="red" className="h-[3.2rem] w-[96px]" onClick={returnFunc}>
|
||||
<i className="diveicon di-arrow-reset" />
|
||||
<span>반려</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReturnButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface ReviewOpinionButtonProps {
|
||||
reviewOpinionFunc: () => void;
|
||||
}
|
||||
|
||||
const ReviewOpinionButton = ({ reviewOpinionFunc }: ReviewOpinionButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="h-[3.2rem] w-[124px]" onClick={reviewOpinionFunc}>
|
||||
<i className="diveicon di-pencil" />
|
||||
<span>검토의견 작성</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default ReviewOpinionButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface SaveButtonProps {
|
||||
saveFunc: () => void;
|
||||
}
|
||||
|
||||
const SaveButton = ({ saveFunc }: SaveButtonProps) => {
|
||||
return (
|
||||
<Button color="green" className="h-[3.2rem] w-[96px]" onClick={saveFunc}>
|
||||
<i className="diveicon di-download" />
|
||||
<span>저장</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SaveButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface SubmitExceptionButtonProps {
|
||||
SubmitExceptionFunc: () => void;
|
||||
}
|
||||
|
||||
const SubmitExceptionButton = ({ SubmitExceptionFunc }: SubmitExceptionButtonProps) => {
|
||||
return (
|
||||
<Button color="red" className="h-[3.2rem] w-[96px]" onClick={SubmitExceptionFunc}>
|
||||
<i className="diveicon di-box-arrow-upload" />
|
||||
<span>예외제출</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubmitExceptionButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface SubmitButtonProps {
|
||||
submitFunc: () => void;
|
||||
}
|
||||
|
||||
const SubmitButton = ({ submitFunc }: SubmitButtonProps) => {
|
||||
return (
|
||||
<Button className="h-[3.2rem] w-[96px]" onClick={submitFunc}>
|
||||
<i className="diveicon di-upload" />
|
||||
<span>제출</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default SubmitButton;
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Button } from "@common/components";
|
||||
|
||||
interface UpdateOperateDataButtonProps {
|
||||
updateOperateDataButtonFunc: () => void;
|
||||
}
|
||||
|
||||
const UpdateOperateDataButton = ({ updateOperateDataButtonFunc }: UpdateOperateDataButtonProps) => {
|
||||
return (
|
||||
<Button color="emerald" className="h-[3.2rem] w-[176px]" onClick={updateOperateDataButtonFunc}>
|
||||
<i className="diveicon di-arrow-up-down" />
|
||||
<span>운영 데이터 업데이트</span>
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export default UpdateOperateDataButton;
|
||||
@@ -1,105 +0,0 @@
|
||||
/* RealGrid2 폰트 설정 - 루트 폰트와 일치 */
|
||||
.rg-root,
|
||||
.rg-grid,
|
||||
.rg-body,
|
||||
.rg-cell,
|
||||
.rg-header,
|
||||
.rg-head,
|
||||
.rg-rowbarcontainer {
|
||||
font-family: "Noto Sans KR", sans-serif !important;
|
||||
font-size: 12px !important;
|
||||
font-weight: 500;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
/* RealGrid2 컨테이너 스타일 */
|
||||
.rg-root {
|
||||
border-radius: 0.5rem !important;
|
||||
overflow: hidden !important;
|
||||
border: 1px solid #dbe2e6 !important;
|
||||
}
|
||||
|
||||
.rg-grid {
|
||||
border-radius: 0.5rem !important;
|
||||
/* box-shadow: 0 0 10px -1px rgba(0, 0, 0, 0.06); */
|
||||
}
|
||||
|
||||
/* 헤더 스타일 */
|
||||
.rg-header,
|
||||
.rg-head,
|
||||
.rg-foot,
|
||||
.rg-footer,
|
||||
.rg-fixed-footer {
|
||||
background-color: #f5f7fa !important;
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
/* 헤더 셀 스타일 */
|
||||
.rg-header .rg-cell,
|
||||
.rg-head .rg-cell {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
|
||||
/* 헤더 필터링 영역 위치 조정 - 오른쪽 여백 추가 */
|
||||
.rg-header-filtering {
|
||||
left: auto !important;
|
||||
right: 8px !important;
|
||||
}
|
||||
|
||||
/* 그룹 헤더 스타일 */
|
||||
.rg-header-group,
|
||||
.rg-header-group-cell {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
|
||||
/* 첫 번째 헤더 셀 - 왼쪽 상단 모서리 */
|
||||
.rg-header .rg-cell:first-child,
|
||||
.rg-head .rg-cell:first-child {
|
||||
border-top-left-radius: 8px !important;
|
||||
}
|
||||
|
||||
/* 마지막 헤더 셀 - 오른쪽 상단 모서리 */
|
||||
.rg-header .rg-cell:last-child,
|
||||
.rg-head .rg-cell:last-child {
|
||||
border-top-right-radius: 8px !important;
|
||||
}
|
||||
|
||||
/* border color 통일 */
|
||||
.rg-header .rg-table tr td,
|
||||
.rg-head .rg-table tr td:not(:first-child),
|
||||
.rg-body .rg-table tr td,
|
||||
.rg-rowbarcontainer .rg-table tr td:not(:first-child) {
|
||||
border-left: 1px solid #dbe2e6 !important;
|
||||
border-bottom: 1px solid #dbe2e6 !important;
|
||||
border-right: none !important;
|
||||
}
|
||||
.rg-rowindicator-head,
|
||||
.rg-rowbarcontainer .rg-table tr td:first-child {
|
||||
border-right: none !important;
|
||||
border-bottom: 1px solid #dbe2e6 !important;
|
||||
border-left: none !important;
|
||||
}
|
||||
.rg-footer .rg-table tr td,
|
||||
.rg-fixed-footer .rg-table tr td,
|
||||
.rg-foot .rg-table tr td {
|
||||
border-right: 1px solid #dbe2e6 !important;
|
||||
border-top: 1px solid #dbe2e6 !important;
|
||||
}
|
||||
|
||||
.rg-rowbarcontainer .rg-table tr td {
|
||||
background-color: #f5f7fa !important;
|
||||
}
|
||||
|
||||
/* 푸터 마지막 요소 - 오른쪽 border 제거 */
|
||||
.rg-footer .rg-table tr td:last-child {
|
||||
border-right: none !important;
|
||||
}
|
||||
|
||||
/* 고정 컬럼 바 */
|
||||
.rg-fixed-column-bar {
|
||||
background-color: #ccc !important;
|
||||
border-right: 1px solid #ccc !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,295 @@
|
||||
import { useRef, useEffect } from "react"
|
||||
import { ValueType } from "realgrid"
|
||||
|
||||
import RealGrid, { GridFitStyle } from "realgrid"
|
||||
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
||||
import type { DataGridProps, RealGridColumnInfo, GridViewWithSetColumns, FooterItemWithCallback } from "../type/DataGrid.type"
|
||||
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks"
|
||||
|
||||
// RealGrid 타입 확장
|
||||
declare module "realgrid" {
|
||||
interface GridView {
|
||||
setOptions(options: {
|
||||
footer?: { visible?: boolean };
|
||||
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
||||
checkBar?: { visible?: boolean };
|
||||
}): void;
|
||||
}
|
||||
}
|
||||
|
||||
RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || '');
|
||||
|
||||
/** setDataComparer(field, comparer) - setFields 없이 숫자 정렬용. comparer(field, row1, row2) => -1|0|1 */
|
||||
interface RealGridDataProviderComparer {
|
||||
setDataComparer?(field: string | number, comparer: (field: string | number, row1: number, row2: number) => number): void;
|
||||
getValue?(row: number, field: string | number): unknown;
|
||||
}
|
||||
|
||||
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
||||
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
||||
return columns.map((col) => {
|
||||
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
||||
fieldName: col.fieldName,
|
||||
dataType: col.valueType === ValueType.NUMBER ? "number" : "text",
|
||||
};
|
||||
if (col.computed) {
|
||||
const hasFields = "fields" in col.computed && col.computed.fields.length > 0;
|
||||
const hasNumeratorDenominator = "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && col.computed.denominatorFields.length > 0;
|
||||
if (hasFields || hasNumeratorDenominator) {
|
||||
field.valueCallback = getComputedValueCallback(col.computed) as (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number;
|
||||
}
|
||||
}
|
||||
return field;
|
||||
});
|
||||
}
|
||||
|
||||
/** setDataComparer용 숫자 비교기. setFields 없이 숫자 정렬. */
|
||||
function createNumberComparer(dp: RealGridDataProviderComparer): (field: string | number, row1: number, row2: number) => number {
|
||||
return (field, row1, row2) => {
|
||||
const get = dp.getValue?.bind(dp);
|
||||
if (!get) return 0;
|
||||
const val1 = get(row1, field);
|
||||
const val2 = get(row2, field);
|
||||
if (val1 == null && val2 == null) return 0;
|
||||
if (val1 == null) return 1;
|
||||
if (val2 == null) return -1;
|
||||
const num1 = typeof val1 === "number" ? val1 : parseFloat(String(val1));
|
||||
const num2 = typeof val2 === "number" ? val2 : parseFloat(String(val2));
|
||||
if (isNaN(num1) && isNaN(num2)) return 0;
|
||||
if (isNaN(num1)) return 1;
|
||||
if (isNaN(num2)) return -1;
|
||||
return num1 > num2 ? 1 : num1 < num2 ? -1 : 0;
|
||||
};
|
||||
}
|
||||
|
||||
const CompactDataGrid = ({ columnInfo, fixedColumns, showHeaderCheckbox = false, rowData, setRowData }: DataGridProps) => {
|
||||
const { columns, columnLayout } = columnInfo;
|
||||
const gridRef = useRef<RealGridReact>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (!gridRef.current?.gridView || !gridRef.current?.dataProvider) return;
|
||||
|
||||
const gridView = gridRef.current.gridView;
|
||||
const dataProvider = gridRef.current.dataProvider;
|
||||
|
||||
// setDataComparer로 숫자 정렬 (setFields 미사용 → 데이터 유실·필드 중복 오류 없음)
|
||||
const dp = dataProvider as RealGridDataProviderComparer;
|
||||
if (typeof dp.setDataComparer === "function" && typeof dp.getValue === "function") {
|
||||
const numberComparer = createNumberComparer(dp);
|
||||
const seen = new Set<string>();
|
||||
columns.forEach((col) => {
|
||||
if (col.valueType === ValueType.NUMBER && col.fieldName && !seen.has(col.fieldName)) {
|
||||
seen.add(col.fieldName);
|
||||
try {
|
||||
dp.setDataComparer!(col.fieldName, numberComparer);
|
||||
} catch (e) {
|
||||
console.warn("setDataComparer:", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
gridView.setDisplayOptions({
|
||||
fitStyle: GridFitStyle.EVEN
|
||||
});
|
||||
|
||||
gridView.header.height = 60;
|
||||
|
||||
// 헤더 체크박스 표시 여부 설정
|
||||
gridView.setOptions({
|
||||
checkBar: { visible: showHeaderCheckbox },
|
||||
rowIndicator: { visible: false },
|
||||
});
|
||||
|
||||
// footer가 있는 컬럼이 있으면 footer 높이 설정
|
||||
const hasFooter = columns.some(col => col.footer);
|
||||
if (hasFooter) {
|
||||
// footer가 배열이거나 multiRow가 true인 footer가 있으면 멀티푸터 설정 (여러 행)
|
||||
const hasArrayFooter = columns.some(col => col.footer && Array.isArray(col.footer));
|
||||
const hasMultiRowFooter = columns.some(col => {
|
||||
const footer = col.footer;
|
||||
return footer && !Array.isArray(footer) && 'multiRow' in footer && footer.multiRow === true;
|
||||
});
|
||||
if (hasArrayFooter || hasMultiRowFooter) {
|
||||
// footer 배열의 길이를 확인하여 행 수 결정
|
||||
const arrayFooterLengths = columns
|
||||
.filter(col => col.footer && Array.isArray(col.footer))
|
||||
.map(col => (col.footer as unknown[]).length);
|
||||
const maxFooterLength = arrayFooterLengths.length > 0
|
||||
? Math.max(...arrayFooterLengths)
|
||||
: 2; // 기본값 2
|
||||
const footerHeights = Array.from({ length: maxFooterLength }, () => ({ height: 40 }));
|
||||
gridView.setFooters?.(footerHeights);
|
||||
} else {
|
||||
gridView.footer.height = 40;
|
||||
}
|
||||
}
|
||||
|
||||
// 고정 컬럼 설정
|
||||
if (fixedColumns !== undefined && fixedColumns > 0) {
|
||||
gridView.setFixedOptions({
|
||||
colCount: fixedColumns,
|
||||
});
|
||||
}
|
||||
|
||||
gridView.setOptions({
|
||||
summaryMode: "aggregate"
|
||||
});
|
||||
|
||||
// footerUserSpans가 있는 경우 setColumnLayout으로 설정
|
||||
const checkFooterUserSpans = (layout: unknown[]): boolean => {
|
||||
return layout.some(item => {
|
||||
if (typeof item === 'string') return false;
|
||||
if (item && typeof item === 'object' && 'footerUserSpans' in item) return true;
|
||||
if (item && typeof item === 'object' && 'items' in item && Array.isArray(item.items)) {
|
||||
return checkFooterUserSpans(item.items);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
if (checkFooterUserSpans(columnLayout)) {
|
||||
// setColumnLayout은 그리드가 완전히 렌더링된 후 호출해야 함
|
||||
setTimeout(() => {
|
||||
if (gridRef.current?.gridView && columnLayout) {
|
||||
gridRef.current.gridView.setColumnLayout?.(columnLayout);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// footer 설정 (배열 또는 단일 객체 모두 처리)
|
||||
// setFooters 호출 후 footer 배열 설정
|
||||
setTimeout(() => {
|
||||
const currentGridView = gridRef.current?.gridView;
|
||||
if (!currentGridView || !currentGridView.columnByName) {
|
||||
console.warn('GridView not available for footer setup');
|
||||
return;
|
||||
}
|
||||
|
||||
// footer가 배열인 컬럼이 있으면 setColumns를 다시 호출하여 footer 설정
|
||||
const hasArrayFooter = columns.some(col => col.footer && Array.isArray(col.footer));
|
||||
if (hasArrayFooter) {
|
||||
// 모든 컬럼 정보를 다시 가져와서 footer 배열을 포함하여 setColumns 호출
|
||||
const columnsWithFooter: RealGridColumnInfo[] = columns.map(col => {
|
||||
const colInfo: RealGridColumnInfo = {
|
||||
name: col.name,
|
||||
fieldName: col.fieldName,
|
||||
header: col.header,
|
||||
editable: col.editable,
|
||||
valueType: col.valueType,
|
||||
dataFormat: col.dataFormat,
|
||||
...(col.styleName != null && { styleName: col.styleName }),
|
||||
...(col.mergeCells && { mergeRule: { criteria: 'value' as const } }),
|
||||
};
|
||||
|
||||
if (col.footer) {
|
||||
if (Array.isArray(col.footer)) {
|
||||
colInfo.footer = col.footer;
|
||||
} else {
|
||||
colInfo.footer = {
|
||||
text: col.footer.text,
|
||||
expression: col.footer.expression,
|
||||
numberFormat: col.footer.numberFormat,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return colInfo;
|
||||
});
|
||||
|
||||
try {
|
||||
(currentGridView as GridViewWithSetColumns).setColumns?.(columnsWithFooter);
|
||||
|
||||
// setColumns 호출 후 footer 배열의 valueCallback을 다시 설정
|
||||
setTimeout(() => {
|
||||
columns.forEach(col => {
|
||||
if (!col.footer || !Array.isArray(col.footer)) return;
|
||||
|
||||
try {
|
||||
const column = currentGridView.columnByName(col.name);
|
||||
if (!column) return;
|
||||
|
||||
// footer 배열의 각 요소에 valueCallback 설정
|
||||
col.footer.forEach((footerItem, index) => {
|
||||
if (footerItem.valueCallback && column.footer) {
|
||||
// footer가 배열인 경우
|
||||
if (Array.isArray(column.footer) && column.footer[index]) {
|
||||
(column.footer[index] as FooterItemWithCallback).valueCallback = footerItem.valueCallback;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(`Error setting footer array valueCallback for column ${col.name}:`, e);
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
} catch (e) {
|
||||
console.warn('Failed to set columns with footer array:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// footer가 단일 객체이고 valueCallback이 있는 경우
|
||||
columns.forEach(col => {
|
||||
if (!col.footer || Array.isArray(col.footer)) return;
|
||||
|
||||
try {
|
||||
const column = currentGridView.columnByName(col.name);
|
||||
if (!column || !column.footer) return;
|
||||
|
||||
if (col.footer.valueCallback) {
|
||||
(column.footer as { valueCallback?: typeof col.footer.valueCallback }).valueCallback = col.footer.valueCallback;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Error setting footer valueCallback for column ${col.name}:`, e);
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
|
||||
}, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem] w-1/2">
|
||||
<div className="h-[65vh]">
|
||||
<RealGridReact
|
||||
ref={gridRef}
|
||||
autoGenerateField={true}
|
||||
layout={columnLayout}
|
||||
rows={rowData}
|
||||
onInitialized={(grid) => {
|
||||
const dp = gridRef.current?.dataProvider as { setFields?: (fields: unknown[]) => void } | undefined;
|
||||
if (dp?.setFields) {
|
||||
dp.setFields(buildFieldsFromColumns(columns));
|
||||
}
|
||||
}}
|
||||
>
|
||||
{columns.map((column) => (
|
||||
<RGDataColumn
|
||||
key={column.name}
|
||||
name={column.name}
|
||||
fieldName={column.fieldName}
|
||||
valueType={column.valueType ? column.valueType : ValueType.TEXT}
|
||||
{...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.000' })}
|
||||
header={column.header}
|
||||
editable={column.editable}
|
||||
{...(column.styleName != null
|
||||
? { styleName: column.styleName }
|
||||
: column.editable === false
|
||||
? { styleName: 'rg-cell-readonly' as const }
|
||||
: {})}
|
||||
{...(column.visible === false && { visible: false })}
|
||||
footer={column.footer && !Array.isArray(column.footer) ? {
|
||||
text: column.footer.text,
|
||||
expression: column.footer.expression,
|
||||
numberFormat: column.footer.numberFormat,
|
||||
} : undefined}
|
||||
mergeRule={column.mergeCells ? { criteria: 'value' } : undefined}
|
||||
sortable={!column.sortdisable}
|
||||
/>
|
||||
))}
|
||||
</RealGridReact>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CompactDataGrid;
|
||||
@@ -1,14 +1,28 @@
|
||||
import { useRef, useEffect, useState } from "react"
|
||||
import { useRef, useEffect } from "react";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
import RealGrid, { GridFitStyle, type DisplayOptions } from "realgrid";
|
||||
import { RealGridReact, RGDataColumn } from "realgrid-react";
|
||||
import type { DataGridProps, RealGridColumnInfo, GridViewWithSetColumns, FooterItemWithCallback, ColumnLayoutItem } from "../type/DataGrid.type";
|
||||
import { getComputedValueCallback } from "@/components/util/grid/computedFieldCallbacks";
|
||||
import JSZip from "jszip";
|
||||
import * as XLSX from "xlsx";
|
||||
|
||||
import RealGrid, { GridFitStyle, type DisplayOptions } from "realgrid"
|
||||
import { RealGridReact, RGDataColumn } from "realgrid-react"
|
||||
import type { DataGridProps } from "../type/DataGrid.type"
|
||||
import JSZip from "jszip"
|
||||
import * as XLSX from "xlsx"
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
|
||||
import { Button } from "@common/components";
|
||||
import { useTabStore } from "@/store/tab-store"
|
||||
import { useTabStore } from "@/store/tab-store";
|
||||
|
||||
// RealGrid 타입 확장
|
||||
declare module "realgrid" {
|
||||
interface GridView {
|
||||
setOptions(options: {
|
||||
footer?: { visible?: boolean };
|
||||
summaryMode?: 'aggregate' | 'statistical' | 'none';
|
||||
checkBar?: { visible?: boolean };
|
||||
}): void;
|
||||
}
|
||||
}
|
||||
|
||||
// Window 인터페이스 확장
|
||||
declare global {
|
||||
@@ -24,16 +38,267 @@ if (typeof window !== "undefined") {
|
||||
|
||||
RealGrid.setLicenseKey(process.env.NEXT_PUBLIC_ST_REALGRID_KEY || '');
|
||||
|
||||
const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fixedColumns }: DataGridProps) => {
|
||||
/** setDataComparer(field, comparer) - setFields 없이 숫자 정렬용. comparer(field, row1, row2) => -1|0|1 */
|
||||
interface RealGridDataProviderComparer {
|
||||
setDataComparer?(field: string | number, comparer: (field: string | number, row1: number, row2: number) => number): void;
|
||||
getValue?(row: number, field: string | number): unknown;
|
||||
}
|
||||
|
||||
/** setDataComparer용 숫자 비교기. setFields 없이 숫자 정렬. */
|
||||
function createNumberComparer(dp: RealGridDataProviderComparer): (field: string | number, row1: number, row2: number) => number {
|
||||
return (field, row1, row2) => {
|
||||
const get = dp.getValue?.bind(dp);
|
||||
if (!get) return 0;
|
||||
const val1 = get(row1, field);
|
||||
const val2 = get(row2, field);
|
||||
if (val1 == null && val2 == null) return 0;
|
||||
if (val1 == null) return 1;
|
||||
if (val2 == null) return -1;
|
||||
const num1 = typeof val1 === "number" ? val1 : parseFloat(String(val1));
|
||||
const num2 = typeof val2 === "number" ? val2 : parseFloat(String(val2));
|
||||
if (isNaN(num1) && isNaN(num2)) return 0;
|
||||
if (isNaN(num1)) return 1;
|
||||
if (isNaN(num2)) return -1;
|
||||
return num1 > num2 ? 1 : num1 < num2 ? -1 : 0;
|
||||
};
|
||||
}
|
||||
|
||||
/** 정렬 필드 값을 숫자로 파싱 (쉼표 제거) */
|
||||
function toNum(v: unknown): number {
|
||||
if (v == null) return NaN;
|
||||
if (typeof v === "number") return isNaN(v) ? NaN : v;
|
||||
return parseFloat(String(v).replace(/,/g, "")) || NaN;
|
||||
}
|
||||
|
||||
/** 헤더에 정렬 화살표 표시 (CSS 방식) */
|
||||
function updateHeaderSortIndicator(
|
||||
gridView: {
|
||||
columnByIndex?: (i: number) => { fieldName?: string; name?: string } | undefined;
|
||||
columnByName?: (name: string) => { fieldName?: string; name?: string } | undefined;
|
||||
getColumn?: (i: number) => { fieldName?: string; name?: string } | undefined;
|
||||
},
|
||||
columns: { fieldName?: string; name: string }[],
|
||||
sortDir: Record<string, "asc" | "desc" | "none">
|
||||
) {
|
||||
try {
|
||||
columns.forEach((col) => {
|
||||
if (!col.fieldName && !col.name) return;
|
||||
|
||||
// 컬럼 찾기
|
||||
let gridCol: { fieldName?: string; name?: string } | undefined;
|
||||
for (let i = 0; i < 100; i++) {
|
||||
const c = gridView.columnByIndex?.(i) ?? gridView.getColumn?.(i);
|
||||
if (!c) break;
|
||||
if (c.fieldName === (col.fieldName || col.name) || c.name === (col.fieldName || col.name)) {
|
||||
gridCol = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!gridCol) {
|
||||
gridCol = gridView.columnByName?.(col.name);
|
||||
}
|
||||
|
||||
if (!gridCol) return;
|
||||
|
||||
const fieldName = gridCol.fieldName || gridCol.name || col.fieldName || col.name;
|
||||
const direction = sortDir[fieldName] || sortDir[col.name] || "none";
|
||||
|
||||
// DOM에서 헤더 요소 찾기
|
||||
const gridEl1 = document.querySelector('[data-grid-id]') as HTMLElement | null;
|
||||
const gridEl2 = document.querySelector('.rg-grid') as HTMLElement | null;
|
||||
const gridEl = gridEl1 || gridEl2;
|
||||
if (!gridEl) return;
|
||||
|
||||
// 헤더 셀 찾기 (fieldName 또는 name으로)
|
||||
const headerCells = gridEl.querySelectorAll('.rg-header-cell, [class*="header"]');
|
||||
let targetCell: HTMLElement | null = null;
|
||||
|
||||
headerCells.forEach((cell) => {
|
||||
const el = cell as HTMLElement;
|
||||
const text = el.textContent?.trim();
|
||||
const colName = col.name;
|
||||
const colFieldName = col.fieldName;
|
||||
if (text && (text.includes(colName) || (colFieldName && text.includes(colFieldName)))) {
|
||||
targetCell = el;
|
||||
}
|
||||
});
|
||||
|
||||
if (!targetCell) return;
|
||||
|
||||
const headerCell = targetCell as HTMLElement;
|
||||
|
||||
// 기존 화살표 제거
|
||||
const existingIndicator = headerCell.querySelector(".rg-sort-indicator") as HTMLElement | null;
|
||||
if (existingIndicator) {
|
||||
existingIndicator.remove();
|
||||
}
|
||||
|
||||
// 화살표 추가
|
||||
if (direction === "asc" || direction === "desc") {
|
||||
const indicator = document.createElement("span");
|
||||
indicator.className = "rg-sort-indicator";
|
||||
indicator.textContent = direction === "asc" ? "▲" : "▼";
|
||||
indicator.style.marginLeft = "4px";
|
||||
indicator.style.fontSize = "10px";
|
||||
indicator.style.color = "#666";
|
||||
indicator.style.display = "inline-block";
|
||||
indicator.style.verticalAlign = "middle";
|
||||
headerCell.appendChild(indicator);
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn("updateHeaderSortIndicator error:", e);
|
||||
}
|
||||
}
|
||||
|
||||
/** onSorting: mergeCells: true인 컬럼이 있으면 그룹 내 순서 유지 정렬, 없으면 RealGrid 기본 정렬 */
|
||||
function createOnSortingHandler(
|
||||
columns: { fieldName?: string; name: string; mergeCells?: boolean; sortdisable?: boolean; valueType?: ValueType }[],
|
||||
setRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>,
|
||||
sortDirRef: { current: Record<string, "asc" | "desc" | "none"> },
|
||||
originalRowsRef: { current: Record<string, Record<string, string | number>[]> }
|
||||
) {
|
||||
const fieldNames = [...new Set(columns.map((c) => c.fieldName).filter((x): x is string => typeof x === "string"))];
|
||||
// mergeCells: true인 컬럼 찾기 (시군구 등) - 그룹 필드로 사용
|
||||
// 시군구를 우선으로 찾고, 없으면 첫 번째 mergeCells 컬럼 사용
|
||||
const mergeCellCols = columns.filter((c) => c.mergeCells === true && c.fieldName);
|
||||
const mergeCellCol = mergeCellCols.find((c) => c.fieldName === 'gugun') || mergeCellCols[0];
|
||||
const groupField = mergeCellCol?.fieldName || null;
|
||||
const orderByField = 'rgnNm'; // 고정값 또는 설정 가능하게 할 수 있음
|
||||
const hasMergeCells = mergeCellCols.length > 0;
|
||||
|
||||
return function onSorting(g: unknown, fields: unknown[], _directions: unknown[]) {
|
||||
const grid = g as { getColumn?: (i: number) => { fieldName?: string; name?: string } | undefined; getDataSource?: () => { getRowCount(): number; getValue(r: number, f: string): unknown } };
|
||||
const idx = fields?.[0];
|
||||
if (idx === undefined) return true;
|
||||
let sortField: string | null = null;
|
||||
if (typeof idx === "string") sortField = idx;
|
||||
else {
|
||||
const colObj = grid?.getColumn?.(typeof idx === "number" ? idx : 0);
|
||||
sortField = (colObj?.fieldName ?? colObj?.name) ?? null;
|
||||
}
|
||||
if (!sortField) return true;
|
||||
const col = columns.find((c) => (c.fieldName === sortField || c.name === sortField));
|
||||
if (!col || col.sortdisable) return true;
|
||||
|
||||
// mergeCells: true인 컬럼이 없으면 RealGrid 기본 정렬 사용
|
||||
if (!hasMergeCells || !groupField) return true;
|
||||
|
||||
const ds = grid.getDataSource?.();
|
||||
if (!ds) return true;
|
||||
const cnt = ds.getRowCount();
|
||||
const rows: Record<string, string | number>[] = [];
|
||||
for (let i = 0; i < cnt; i++) {
|
||||
const r: Record<string, string | number> = {};
|
||||
for (const f of fieldNames) r[f] = ds.getValue(i, f) as string | number;
|
||||
rows.push(r);
|
||||
}
|
||||
const prev = sortDirRef.current[sortField] ?? "none";
|
||||
const setRows = (ds as { setRows?: (r: unknown[]) => void }).setRows?.bind(ds);
|
||||
|
||||
if (prev === "desc") {
|
||||
const orig = originalRowsRef.current[sortField];
|
||||
if (orig && setRows) {
|
||||
setRows(orig);
|
||||
setRowData(orig);
|
||||
}
|
||||
sortDirRef.current[sortField] = "none";
|
||||
return false;
|
||||
}
|
||||
if (prev === "none") {
|
||||
originalRowsRef.current[sortField] = rows.map((r) => ({ ...r }));
|
||||
}
|
||||
const sortAsc = prev !== "asc";
|
||||
sortDirRef.current[sortField] = sortAsc ? "asc" : "desc";
|
||||
const sorted = sortRowsGroupPreserving(rows, sortField, sortAsc, { groupField, orderByField }, col.valueType);
|
||||
setRows?.(sorted);
|
||||
setRowData(sorted);
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
/** sortPreserveGroupOrder: 그룹 간에는 sortField로 정렬, 그룹 내에서는 원본 순서 유지. */
|
||||
function sortRowsGroupPreserving(
|
||||
rows: Record<string, string | number>[],
|
||||
sortField: string,
|
||||
sortAsc: boolean,
|
||||
opt: { groupField: string; orderByField?: string },
|
||||
valueType?: ValueType
|
||||
): Record<string, string | number>[] {
|
||||
const groups = new Map<string, Record<string, string | number>[]>();
|
||||
for (const r of rows) {
|
||||
const k = String(r[opt.groupField] ?? "");
|
||||
if (!groups.has(k)) groups.set(k, []);
|
||||
groups.get(k)!.push(r);
|
||||
}
|
||||
|
||||
// valueType에 따라 비교 함수 선택
|
||||
const compareValue = (val: unknown): number | string => {
|
||||
if (valueType === ValueType.NUMBER) {
|
||||
return toNum(val);
|
||||
}
|
||||
// 텍스트나 기타 타입은 문자열로 비교
|
||||
return String(val ?? "");
|
||||
};
|
||||
|
||||
const rep = (arr: Record<string, string | number>[]): number | string => {
|
||||
const values = arr.map((r) => compareValue(r[sortField]));
|
||||
if (valueType === ValueType.NUMBER) {
|
||||
const nums = values.filter((v): v is number => typeof v === "number" && !isNaN(v));
|
||||
if (nums.length === 0) return sortAsc ? Infinity : -Infinity;
|
||||
return sortAsc ? Math.min(...nums) : Math.max(...nums);
|
||||
} else {
|
||||
// 문자열 정렬
|
||||
const strs = values.filter((v): v is string => typeof v === "string");
|
||||
if (strs.length === 0) return sortAsc ? "\uffff" : "";
|
||||
strs.sort();
|
||||
return sortAsc ? (strs[0] as string) : (strs[strs.length - 1] as string);
|
||||
}
|
||||
};
|
||||
|
||||
const entries = [...groups.entries()].sort((a, b) => {
|
||||
const valA = rep(a[1]);
|
||||
const valB = rep(b[1]);
|
||||
if (typeof valA === "number" && typeof valB === "number") {
|
||||
return (sortAsc ? 1 : -1) * (valA - valB);
|
||||
}
|
||||
// 문자열 비교
|
||||
const strA = String(valA);
|
||||
const strB = String(valB);
|
||||
return (sortAsc ? 1 : -1) * strA.localeCompare(strB);
|
||||
});
|
||||
|
||||
return entries.flatMap(([, arr]) => arr);
|
||||
}
|
||||
|
||||
/** columnInfo → RealGrid DataField 배열 (computed → valueCallback 포함, setFields용) */
|
||||
function buildFieldsFromColumns(columns: { fieldName: string; valueType?: ValueType; computed?: import("../type/DataGrid.type").ComputedFieldConfig }[]) {
|
||||
return columns.map((col) => {
|
||||
const field: { fieldName: string; dataType: string; valueCallback?: (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number } = {
|
||||
fieldName: col.fieldName,
|
||||
dataType: col.valueType === ValueType.NUMBER ? "number" : "text",
|
||||
};
|
||||
if (col.computed) {
|
||||
const hasFields = "fields" in col.computed && col.computed.fields.length > 0;
|
||||
const hasNumeratorDenominator = "numeratorFields" in col.computed && col.computed.numeratorFields.length > 0 && col.computed.denominatorFields.length > 0;
|
||||
if (hasFields || hasNumeratorDenominator) {
|
||||
field.valueCallback = getComputedValueCallback(col.computed) as (prod: unknown, dataRow: number, fieldName: string, fieldNames: string[], values: unknown[]) => number;
|
||||
}
|
||||
}
|
||||
return field;
|
||||
});
|
||||
}
|
||||
|
||||
const DataGrid = ({ columnInfo, rowStartNum, isExcelImport = true, isExcelExport = true, fixedColumns, showHeaderCheckbox = false, rowData, setRowData }: DataGridProps) => {
|
||||
const { columns, columnLayout } = columnInfo;
|
||||
const gridRef = useRef<RealGridReact>(null);
|
||||
const fileInputRef = useRef<HTMLInputElement>(null);
|
||||
const sortDirRef = useRef<Record<string, "asc" | "desc" | "none">>({});
|
||||
const originalRowsRef = useRef<Record<string, Record<string, string | number>[]>>({});
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const activeTabId = useTabStore((state) => state.activeTabId);
|
||||
const menuList = useTabStore((state) => state.menuList);
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string>[]>([]);
|
||||
|
||||
const exportExcel = () => {
|
||||
if (rowData.length === 0) {
|
||||
alert('데이터가 없습니다.');
|
||||
@@ -50,12 +315,94 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
.find((s) => s.menuEngNm === activeTabId)
|
||||
?.menuKornNm || 'export';
|
||||
|
||||
// 엑셀 import 시 매칭을 위해 헤더에 fieldName 포함 (예: "합계 (swgeProcZoneInnerSm)")
|
||||
const originalHeaders: Map<string, string> = new Map();
|
||||
columns.forEach((col) => {
|
||||
if (col.fieldName && gridView.columnByName) {
|
||||
const gridCol = gridView.columnByName(col.name);
|
||||
if (gridCol && gridCol.header) {
|
||||
const originalText = gridCol.header.text || '';
|
||||
originalHeaders.set(col.name, originalText);
|
||||
const headerWithFieldName = `${originalText} (${col.fieldName})`;
|
||||
gridCol.header.text = headerWithFieldName;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// exportGrid 호출 전에 columnLayout 정규화 (col 속성 추가)
|
||||
const normalizeLayoutForExport = (layout: ColumnLayoutItem[]): ColumnLayoutItem[] => {
|
||||
return layout.map(item => {
|
||||
if (typeof item === 'string') {
|
||||
return item;
|
||||
}
|
||||
if (item && typeof item === 'object') {
|
||||
// { column: string, footerUserSpans?: ... } 형태인 경우
|
||||
if ('column' in item && typeof item.column === 'string') {
|
||||
const colItem = item as { column: string; footerUserSpans?: unknown[] };
|
||||
// col 속성 추가 (RealGrid가 exportGrid에서 필요로 함)
|
||||
return {
|
||||
...colItem,
|
||||
col: gridView.columnByName?.(colItem.column) || null,
|
||||
} as ColumnLayoutItem;
|
||||
}
|
||||
// { name: string, items: ... } 형태인 경우
|
||||
if ('items' in item && Array.isArray(item.items)) {
|
||||
return {
|
||||
...item,
|
||||
items: normalizeLayoutForExport(item.items as ColumnLayoutItem[]),
|
||||
};
|
||||
}
|
||||
}
|
||||
return item;
|
||||
});
|
||||
};
|
||||
|
||||
const originalLayout = columnLayout;
|
||||
let normalizedLayout: ColumnLayoutItem[] | undefined;
|
||||
let layoutRestored = false;
|
||||
|
||||
// footerUserSpans가 있는 경우에만 정규화
|
||||
const checkFooterUserSpans = (layout: ColumnLayoutItem[]): boolean => {
|
||||
return layout.some(item => {
|
||||
if (typeof item === 'string') return false;
|
||||
if (item && typeof item === 'object' && 'footerUserSpans' in item) return true;
|
||||
if (item && typeof item === 'object' && 'items' in item && Array.isArray(item.items)) {
|
||||
return checkFooterUserSpans(item.items as ColumnLayoutItem[]);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
if (checkFooterUserSpans(columnLayout)) {
|
||||
normalizedLayout = normalizeLayoutForExport(columnLayout);
|
||||
// 정규화된 layout을 임시로 설정
|
||||
gridView.setColumnLayout?.(normalizedLayout);
|
||||
}
|
||||
|
||||
gridView.exportGrid({
|
||||
type: 'excel',
|
||||
target: 'local',
|
||||
fileName: `${menuName}.xlsx`,
|
||||
footer: 'hidden',
|
||||
done: () => {
|
||||
// 헤더 원복
|
||||
columns.forEach((col) => {
|
||||
if (col.fieldName && gridView.columnByName) {
|
||||
const gridCol = gridView.columnByName(col.name);
|
||||
if (gridCol && gridCol.header && originalHeaders.has(col.name)) {
|
||||
gridCol.header.text = originalHeaders.get(col.name) || '';
|
||||
}
|
||||
}
|
||||
});
|
||||
// columnLayout 원복 (footerUserSpans 유지)
|
||||
if (normalizedLayout && !layoutRestored) {
|
||||
layoutRestored = true;
|
||||
setTimeout(() => {
|
||||
if (gridRef.current?.gridView && originalLayout) {
|
||||
gridRef.current.gridView.setColumnLayout?.(originalLayout);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
alert('내보내기가 완료되었습니다.');
|
||||
},
|
||||
});
|
||||
@@ -125,25 +472,64 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
const maxHeaderRowIndex = headerRowIndexes.length > 0 ? Math.max(...headerRowIndexes) : headerStartRow;
|
||||
const dataStartRow = maxHeaderRowIndex + 1;
|
||||
|
||||
// 엑셀 컬럼 인덱스 → 그리드 fieldName 매핑
|
||||
const headerToFieldNameMap = new Map<string, string>();
|
||||
headers.forEach((headerText, colIndex) => {
|
||||
let fieldName: string | null = null;
|
||||
|
||||
// 헤더에 fieldName이 포함된 경우 (예: "합계 (swgeProcZoneInnerSm)")
|
||||
const fieldNameMatch = headerText.match(/\(([a-zA-Z_][a-zA-Z0-9_]*)\)$/);
|
||||
if (fieldNameMatch && fieldNameMatch[1]) {
|
||||
const extractedFieldName = fieldNameMatch[1];
|
||||
if (columns.find(c => c.fieldName === extractedFieldName)) {
|
||||
fieldName = extractedFieldName;
|
||||
}
|
||||
}
|
||||
|
||||
// 매칭 실패 시 원본 헤더 텍스트 사용
|
||||
if (!fieldName) {
|
||||
console.warn(`엑셀 컬럼 ${colIndex + 1} (헤더: "${headerText}") 매칭 실패 → 헤더 텍스트를 fieldName으로 사용`);
|
||||
fieldName = headerText;
|
||||
}
|
||||
|
||||
headerToFieldNameMap.set(headerText, fieldName);
|
||||
});
|
||||
|
||||
// 데이터 행 읽기
|
||||
const dataRows: Record<string, string>[] = [];
|
||||
const dataRows: Record<string, string | number>[] = [];
|
||||
for (let row = dataStartRow; row <= range.e.r; row++) {
|
||||
const rowData: Record<string, string> = {};
|
||||
const rowData: Record<string, string | number> = {};
|
||||
let hasData = false;
|
||||
|
||||
for (let colIndex = 0; colIndex < headers.length; colIndex++) {
|
||||
const col = range.s.c + colIndex;
|
||||
const cell = worksheet[XLSX.utils.encode_cell({ r: row, c: col })];
|
||||
const headerName = headers[colIndex] || `Column${colIndex + 1}`;
|
||||
const cellValue = cell && cell.v !== undefined && cell.v !== null
|
||||
? String(cell.v)
|
||||
: '';
|
||||
// 헤더 텍스트를 fieldName으로 변환
|
||||
const fieldName = headerToFieldNameMap.get(headerName) || headerName;
|
||||
|
||||
if (cellValue !== '') {
|
||||
let cellValue: string | number = '';
|
||||
if (cell && cell.v !== undefined && cell.v !== null) {
|
||||
// 엑셀 셀 타입이 숫자이거나 값이 숫자인 경우 숫자로 변환
|
||||
if (cell.t === 'n' || (typeof cell.v === 'number' && !isNaN(cell.v))) {
|
||||
cellValue = cell.v as number;
|
||||
} else {
|
||||
const stringValue = String(cell.v);
|
||||
// 문자열이지만 숫자로 변환 가능한 경우 숫자로 변환
|
||||
const numericValue = Number(stringValue.replace(/,/g, ''));
|
||||
if (!isNaN(numericValue) && stringValue.trim() !== '') {
|
||||
cellValue = numericValue;
|
||||
} else {
|
||||
cellValue = stringValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cellValue !== '' && cellValue !== null && cellValue !== undefined) {
|
||||
hasData = true;
|
||||
}
|
||||
|
||||
rowData[headerName] = cellValue;
|
||||
rowData[fieldName] = cellValue;
|
||||
}
|
||||
|
||||
// 데이터가 하나라도 있는 행만 추가
|
||||
@@ -151,7 +537,6 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
dataRows.push(rowData);
|
||||
}
|
||||
}
|
||||
|
||||
setRowData(dataRows);
|
||||
} catch (error) {
|
||||
console.error('엑셀 파일 파싱 오류:', error);
|
||||
@@ -181,14 +566,66 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (!gridRef.current?.gridView) return;
|
||||
if (!gridRef.current?.gridView || !gridRef.current?.dataProvider) return;
|
||||
|
||||
const gridView = gridRef.current.gridView;
|
||||
const dataProvider = gridRef.current.dataProvider;
|
||||
|
||||
// mergeCells: true인 컬럼이 있으면 onSorting에서 클라이언트 정렬로 처리
|
||||
const hasMergeCells = columns.some((col) => col.mergeCells === true);
|
||||
|
||||
// setDataComparer로 숫자 정렬 (mergeCells가 있으면 onSorting에서 클라이언트 정렬로 처리)
|
||||
const dp = dataProvider as RealGridDataProviderComparer;
|
||||
if (typeof dp.setDataComparer === "function" && typeof dp.getValue === "function") {
|
||||
const numberComparer = createNumberComparer(dp);
|
||||
const seen = new Set<string>();
|
||||
columns.forEach((col) => {
|
||||
if (hasMergeCells) return; // mergeCells가 있으면 모든 컬럼을 클라이언트 정렬로 처리
|
||||
if (col.valueType === ValueType.NUMBER && col.fieldName && !seen.has(col.fieldName)) {
|
||||
seen.add(col.fieldName);
|
||||
try {
|
||||
dp.setDataComparer!(col.fieldName, numberComparer);
|
||||
} catch (e) {
|
||||
console.warn("setDataComparer:", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// mergeCells: true인 컬럼이 있으면 onSorting에서 그룹 내 순서 유지 정렬 적용
|
||||
(gridView as { onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean }).onSorting = createOnSortingHandler(columns, setRowData, sortDirRef, originalRowsRef);
|
||||
|
||||
(gridView.displayOptions as DisplayOptions).fitStyle = GridFitStyle.EVEN;
|
||||
gridView.header.height = 60;
|
||||
if (rows.length > 0) {
|
||||
setRowData(rows);
|
||||
|
||||
// 헤더 체크박스 표시 여부 설정
|
||||
gridView.setOptions({
|
||||
checkBar: { visible: showHeaderCheckbox },
|
||||
rowIndicator: { visible: false },
|
||||
});
|
||||
|
||||
// footer가 있는 컬럼이 있으면 footer 높이 설정
|
||||
const hasFooter = columns.some(col => col.footer);
|
||||
if (hasFooter) {
|
||||
// footer가 배열이거나 multiRow가 true인 footer가 있으면 멀티푸터 설정 (여러 행)
|
||||
const hasArrayFooter = columns.some(col => col.footer && Array.isArray(col.footer));
|
||||
const hasMultiRowFooter = columns.some(col => {
|
||||
const footer = col.footer;
|
||||
return footer && !Array.isArray(footer) && 'multiRow' in footer && footer.multiRow === true;
|
||||
});
|
||||
if (hasArrayFooter || hasMultiRowFooter) {
|
||||
// footer 배열의 길이를 확인하여 행 수 결정
|
||||
const arrayFooterLengths = columns
|
||||
.filter(col => col.footer && Array.isArray(col.footer))
|
||||
.map(col => (col.footer as unknown[]).length);
|
||||
const maxFooterLength = arrayFooterLengths.length > 0
|
||||
? Math.max(...arrayFooterLengths)
|
||||
: 2; // 기본값 2
|
||||
const footerHeights = Array.from({ length: maxFooterLength }, () => ({ height: 40 }));
|
||||
gridView.setFooters?.(footerHeights);
|
||||
} else {
|
||||
gridView.footer.height = 40;
|
||||
}
|
||||
}
|
||||
|
||||
// 고정 컬럼 설정
|
||||
@@ -197,7 +634,122 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
colCount: fixedColumns,
|
||||
});
|
||||
}
|
||||
}, [rows, columns, columnLayout, fixedColumns]);
|
||||
|
||||
gridView.setOptions({
|
||||
summaryMode: "aggregate"
|
||||
});
|
||||
|
||||
// footerUserSpans가 있는 경우 setColumnLayout으로 설정
|
||||
const checkFooterUserSpans = (layout: unknown[]): boolean => {
|
||||
return layout.some(item => {
|
||||
if (typeof item === 'string') return false;
|
||||
if (item && typeof item === 'object' && 'footerUserSpans' in item) return true;
|
||||
if (item && typeof item === 'object' && 'items' in item && Array.isArray(item.items)) {
|
||||
return checkFooterUserSpans(item.items);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
};
|
||||
|
||||
if (checkFooterUserSpans(columnLayout)) {
|
||||
// setColumnLayout은 그리드가 완전히 렌더링된 후 호출해야 함
|
||||
setTimeout(() => {
|
||||
if (gridRef.current?.gridView && columnLayout) {
|
||||
gridRef.current.gridView.setColumnLayout?.(columnLayout);
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// footer 설정 (배열 또는 단일 객체 모두 처리)
|
||||
// setFooters 호출 후 footer 배열 설정
|
||||
setTimeout(() => {
|
||||
const currentGridView = gridRef.current?.gridView;
|
||||
if (!currentGridView || !currentGridView.columnByName) {
|
||||
console.warn('GridView not available for footer setup');
|
||||
return;
|
||||
}
|
||||
|
||||
// footer가 배열인 컬럼이 있으면 setColumns를 다시 호출하여 footer 설정
|
||||
const hasArrayFooter = columns.some(col => col.footer && Array.isArray(col.footer));
|
||||
if (hasArrayFooter) {
|
||||
// 모든 컬럼 정보를 다시 가져와서 footer 배열을 포함하여 setColumns 호출
|
||||
const columnsWithFooter: RealGridColumnInfo[] = columns.map(col => {
|
||||
const colInfo: RealGridColumnInfo = {
|
||||
name: col.name,
|
||||
fieldName: col.fieldName,
|
||||
header: col.header,
|
||||
editable: col.editable,
|
||||
valueType: col.valueType,
|
||||
dataFormat: col.dataFormat,
|
||||
...(col.styleName != null && { styleName: col.styleName }),
|
||||
...(col.mergeCells && { mergeRule: { criteria: 'value' as const } }),
|
||||
};
|
||||
|
||||
if (col.footer) {
|
||||
if (Array.isArray(col.footer)) {
|
||||
colInfo.footer = col.footer;
|
||||
} else {
|
||||
colInfo.footer = {
|
||||
text: col.footer.text,
|
||||
expression: col.footer.expression,
|
||||
numberFormat: col.footer.numberFormat,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return colInfo;
|
||||
});
|
||||
|
||||
try {
|
||||
(currentGridView as GridViewWithSetColumns).setColumns?.(columnsWithFooter);
|
||||
|
||||
// setColumns 호출 후 footer 배열의 valueCallback을 다시 설정
|
||||
setTimeout(() => {
|
||||
columns.forEach(col => {
|
||||
if (!col.footer || !Array.isArray(col.footer)) return;
|
||||
|
||||
try {
|
||||
const column = currentGridView.columnByName(col.name);
|
||||
if (!column) return;
|
||||
|
||||
// footer 배열의 각 요소에 valueCallback 설정
|
||||
col.footer.forEach((footerItem, index) => {
|
||||
if (footerItem.valueCallback && column.footer) {
|
||||
// footer가 배열인 경우
|
||||
if (Array.isArray(column.footer) && column.footer[index]) {
|
||||
(column.footer[index] as FooterItemWithCallback).valueCallback = footerItem.valueCallback;
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (e) {
|
||||
console.warn(`Error setting footer array valueCallback for column ${col.name}:`, e);
|
||||
}
|
||||
});
|
||||
}, 50);
|
||||
} catch (e) {
|
||||
console.warn('Failed to set columns with footer array:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// footer가 단일 객체이고 valueCallback이 있는 경우
|
||||
columns.forEach(col => {
|
||||
if (!col.footer || Array.isArray(col.footer)) return;
|
||||
|
||||
try {
|
||||
const column = currentGridView.columnByName(col.name);
|
||||
if (!column || !column.footer) return;
|
||||
|
||||
if (col.footer.valueCallback) {
|
||||
(column.footer as { valueCallback?: typeof col.footer.valueCallback }).valueCallback = col.footer.valueCallback;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn(`Error setting footer valueCallback for column ${col.name}:`, e);
|
||||
}
|
||||
});
|
||||
}, 200);
|
||||
|
||||
}, [columns, columnLayout, fixedColumns, rowData, showHeaderCheckbox]);
|
||||
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-[0.6rem] mx-[0.6rem]">
|
||||
@@ -208,32 +760,60 @@ const DataGrid = ({ columnInfo, rows = [], rowStartNum, isExcelImport = true, fi
|
||||
style={{ display: 'none' }}
|
||||
onChange={handleFileChange}
|
||||
/>
|
||||
<div className="flex justify-end items-center gap-[0.6rem]">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] px-[1.2rem]">
|
||||
{isExcelImport &&
|
||||
<Button className="h-[3.2rem] px-6 bg-gradient-green hover:bg-gradient-green-hover" type="button" onClick={importExcel}>
|
||||
<i className="diveicon di-file-excel translate-y-[1px]" />
|
||||
<span className="translate-y-[-1px]">가져오기</span>
|
||||
<Button className="h-[3.2rem] px-6 bg-gradient-green hover:bg-gradient-green-hover w-[96px]" type="button" onClick={importExcel}>
|
||||
<i className="diveicon di-file-excel" />
|
||||
<span>가져오기</span>
|
||||
</Button>
|
||||
}
|
||||
{isExcelExport &&
|
||||
<Button className="h-[3.2rem] px-6 bg-gradient-green hover:bg-gradient-green-hover w-[96px]" type="button" onClick={exportExcel}>
|
||||
<i className="diveicon di-file-excel" />
|
||||
<span>내보내기</span>
|
||||
</Button>
|
||||
}
|
||||
<Button className="h-[3.2rem] px-6 bg-gradient-green hover:bg-gradient-green-hover" type="button" onClick={exportExcel}>
|
||||
<i className="diveicon di-file-excel translate-y-[1px]" />
|
||||
<span className="translate-y-[-1px]">내보내기</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="h-[65vh]">
|
||||
<RealGridReact
|
||||
ref={gridRef}
|
||||
autoGenerateField={true}
|
||||
layout={columnLayout}
|
||||
rows={rowData}
|
||||
>
|
||||
<RealGridReact
|
||||
ref={gridRef}
|
||||
autoGenerateField={true}
|
||||
layout={columnLayout}
|
||||
rows={rowData}
|
||||
onInitialized={(grid) => {
|
||||
(grid as { onSorting?: (g: unknown, f: unknown[], d: unknown[]) => boolean }).onSorting = createOnSortingHandler(columns, setRowData, sortDirRef, originalRowsRef);
|
||||
const dp = gridRef.current?.dataProvider as { setFields?: (fields: unknown[]) => void; setRows?: (rows: Record<string, string | number>[]) => void } | undefined;
|
||||
if (dp?.setFields) {
|
||||
dp.setFields(buildFieldsFromColumns(columns));
|
||||
}
|
||||
// setFields 호출 직후 행 데이터 적용 (realgrid-react의 setRows 타이밍 이슈 방지)
|
||||
if (dp?.setRows && rowData?.length) {
|
||||
dp.setRows(rowData);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{columns.map((column) => (
|
||||
<RGDataColumn
|
||||
key={column.name}
|
||||
name={column.name}
|
||||
fieldName={column.fieldName}
|
||||
valueType={column.valueType ? column.valueType : ValueType.TEXT}
|
||||
{...(column.valueType === ValueType.NUMBER && { numberFormat: column.dataFormat ? column.dataFormat : '#,##0.000' })}
|
||||
header={column.header}
|
||||
// autoFilter={true}
|
||||
editable={column.editable}
|
||||
{...(column.styleName != null
|
||||
? { styleName: column.styleName }
|
||||
: column.editable === false
|
||||
? { styleName: 'rg-cell-readonly' as const }
|
||||
: {})}
|
||||
{...(column.visible === false && { visible: false })}
|
||||
footer={column.footer && !Array.isArray(column.footer) ? {
|
||||
text: column.footer.text,
|
||||
expression: column.footer.expression,
|
||||
numberFormat: column.footer.numberFormat,
|
||||
} : undefined}
|
||||
mergeRule={column.mergeCells ? { criteria: 'value' } : undefined}
|
||||
sortable={!column.sortdisable}
|
||||
/>
|
||||
))}
|
||||
</RealGridReact>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useState, useEffect } from "react";
|
||||
import useSWR from 'swr';
|
||||
|
||||
import {
|
||||
@@ -18,9 +18,9 @@ from "@common/components";
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { type SearchFormProps, type SearchFormValues, defaultSearchFormProps } from "../type/SearchForm.type";
|
||||
import { statisticsAPi } from "@/entities/statistics/api/statistics-service";
|
||||
import type { ApiResponse, Sido, Sgg } from "@/entities/statistics/model/statistics-interface";
|
||||
import type { ApiResponse, SearchCondition, Sgg } from "@/entities/statistics/model/statistics-interface";
|
||||
|
||||
const getSidoListFetcher = async (): Promise<ApiResponse<Sido[]>> => {
|
||||
const getSidoListFetcher = async (): Promise<ApiResponse<SearchCondition>> => {
|
||||
return statisticsAPi.getSidoList();
|
||||
};
|
||||
|
||||
@@ -31,15 +31,11 @@ const getSggListFetcher = async (key: [string, string]): Promise<ApiResponse<Sgg
|
||||
const SearchForm = (props: SearchFormProps = {}) => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const mergedProps = { ...defaultSearchFormProps, ...props };
|
||||
const [values, setValues] = useState<SearchFormValues>({
|
||||
sido: props.defaultValues?.sido || "",
|
||||
sgg: props.defaultValues?.sgg || "",
|
||||
year: props.defaultValues?.year || "",
|
||||
order: props.defaultValues?.order || "",
|
||||
fctName: props.defaultValues?.fctName || "",
|
||||
});
|
||||
|
||||
const { data: sidoList } = useSWR<ApiResponse<Sido[]>>(
|
||||
const currentYear = new Date().getFullYear();
|
||||
const defaultYear = currentYear - 1;
|
||||
|
||||
const { data: sidoList } = useSWR<ApiResponse<SearchCondition>>(
|
||||
"sido-list",
|
||||
getSidoListFetcher,
|
||||
{
|
||||
@@ -61,6 +57,15 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
}
|
||||
);
|
||||
|
||||
const [values, setValues] = useState<SearchFormValues>({
|
||||
sido: props.defaultValues?.sido || '',
|
||||
gugun: props.defaultValues?.gugun || '',
|
||||
year: props.defaultValues?.year || defaultYear.toString(),
|
||||
order: props.defaultValues?.order || '',
|
||||
fctName: props.defaultValues?.fctName || '',
|
||||
bsnmCd: props.defaultValues?.bsnmCd || '',
|
||||
});
|
||||
|
||||
const { data: sggList } = useSWR<ApiResponse<Sgg[]>>(
|
||||
values.sido && values.sido !== "ALL" ? ["sgg-list", values.sido] : null,
|
||||
getSggListFetcher,
|
||||
@@ -83,6 +88,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
|
||||
e.preventDefault();
|
||||
props.onSubmit?.(values);
|
||||
@@ -90,17 +96,44 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
|
||||
const handleReset = () => {
|
||||
const resetValues: SearchFormValues = {
|
||||
sido: "",
|
||||
sgg: "",
|
||||
year: "",
|
||||
order: "",
|
||||
fctName: "",
|
||||
sido: '',
|
||||
gugun: '',
|
||||
year: String(defaultYear),
|
||||
order: '',
|
||||
fctName: '',
|
||||
bsnmCd: '',
|
||||
};
|
||||
setValues(resetValues);
|
||||
props.onReset?.();
|
||||
props.onSubmit?.(resetValues);
|
||||
};
|
||||
|
||||
const handleSidoChange = (value: string) => {
|
||||
const selectedBsnm = sidoList?.data.sidoList.find((v) => v.sido === value)?.bsnmCd || '';
|
||||
|
||||
setValues((prev) => ({
|
||||
...prev,
|
||||
sido: value,
|
||||
gugun: '',
|
||||
bsnmCd: selectedBsnm,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSggChange = (value: string) => {
|
||||
const selectedBsnm = value === 'ALL'
|
||||
? (sidoList?.data.sidoList.find((v) => v.sido === values.sido)?.bsnmCd || '')
|
||||
: (sggList?.data?.find((v) => v.gugun === value)?.bsnmCd || '');
|
||||
|
||||
setValues((prev) => ({
|
||||
...prev,
|
||||
gugun: value,
|
||||
bsnmCd: selectedBsnm,
|
||||
}));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
props.onValuesChange?.(values);
|
||||
}, [values]);
|
||||
|
||||
return (
|
||||
<div className="card card-border">
|
||||
<form onSubmit={handleSubmit}>
|
||||
@@ -110,13 +143,13 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
<Label className="text-label">
|
||||
시도
|
||||
</Label>
|
||||
<Select value={values.sido} onValueChange={(value) => setValues((prev) => ({ ...prev, sido: value, sgg: 'ALL' }))}>
|
||||
<Select value={values.sido} onValueChange={handleSidoChange}>
|
||||
<SelectTrigger className="w-[12rem]">
|
||||
<SelectValue placeholder="전체"></SelectValue>
|
||||
<SelectValue placeholder="선택"></SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="ALL">전체</SelectItem>
|
||||
{sidoList?.data?.map((sido) => (
|
||||
<SelectItem value="ALL">선택</SelectItem>
|
||||
{sidoList?.data?.sidoList?.map((sido) => (
|
||||
<SelectItem key={sido.adstDstrCd} value={sido.sido}>
|
||||
{sido.sido}
|
||||
</SelectItem>
|
||||
@@ -125,12 +158,12 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
</Select>
|
||||
</div>
|
||||
}
|
||||
{mergedProps.sgg &&
|
||||
{mergedProps.gugun &&
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-label">
|
||||
시군구
|
||||
</Label>
|
||||
<Select value={values.sgg} onValueChange={(value) => setValues({ ...values, sgg: value })}>
|
||||
<Select value={values.gugun} onValueChange={handleSggChange}>
|
||||
<SelectTrigger className="w-[12rem]">
|
||||
<SelectValue placeholder="전체"></SelectValue>
|
||||
</SelectTrigger>
|
||||
@@ -152,10 +185,14 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
</Label>
|
||||
<Select value={values.year} onValueChange={(value) => setValues({ ...values, year: value })}>
|
||||
<SelectTrigger className="w-[10rem]">
|
||||
<SelectValue placeholder="전체"></SelectValue>
|
||||
<SelectValue placeholder="선택"></SelectValue>
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="ALL">전체</SelectItem>
|
||||
{sidoList?.data?.yearList.map((year) => (
|
||||
<SelectItem key={year} value={String(year)}>
|
||||
{year}년
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -176,10 +213,10 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
</div>
|
||||
}
|
||||
<div className="flex items-center gap-2 ml-auto">
|
||||
<Button color="green" className="h-[3.2rem]" type="button" onClick={handleReset}>
|
||||
<Button color="green" className="h-[3.2rem] w-[96px]" type="button" onClick={handleReset}>
|
||||
초기화
|
||||
</Button>
|
||||
<Button className="h-[3.2rem]" type="submit">
|
||||
<Button className="h-[3.2rem] w-[96px]" type="submit">
|
||||
조회
|
||||
</Button>
|
||||
</div>
|
||||
@@ -202,7 +239,7 @@ const SearchForm = (props: SearchFormProps = {}) => {
|
||||
}
|
||||
{mergedProps.userMenual &&
|
||||
<div className="flex items-center gap-2 ml-auto">
|
||||
<Button className="h-[3.2rem]" type="button">
|
||||
<Button className="h-[3.2rem] w-[124px]" type="button">
|
||||
<i className="diveicon di-person-fill" />
|
||||
사용자 메뉴얼
|
||||
</Button>
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import CompactDataGrid from "./CompactDataGrid";
|
||||
import type { SplitDataGridProps } from "../type/DataGrid.type";
|
||||
|
||||
const SplitDataGrid = ({
|
||||
leftColumnInfo,
|
||||
rightColumnInfo,
|
||||
leftFixedColumns,
|
||||
rightFixedColumns,
|
||||
showHeaderCheckbox = false,
|
||||
leftRowData,
|
||||
rightRowData,
|
||||
setLeftRowData,
|
||||
setRightRowData,
|
||||
}: SplitDataGridProps) => {
|
||||
return (
|
||||
<div className="flex gap-[0.6rem] mx-[0.6rem]">
|
||||
<CompactDataGrid
|
||||
columnInfo={leftColumnInfo}
|
||||
fixedColumns={leftFixedColumns}
|
||||
showHeaderCheckbox={showHeaderCheckbox}
|
||||
rowData={leftRowData}
|
||||
setRowData={setLeftRowData}
|
||||
/>
|
||||
<CompactDataGrid
|
||||
columnInfo={rightColumnInfo}
|
||||
fixedColumns={rightFixedColumns}
|
||||
showHeaderCheckbox={showHeaderCheckbox}
|
||||
rowData={rightRowData}
|
||||
setRowData={setRightRowData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SplitDataGrid;
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,80 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { ExcretaTreatFactInpColumn } from "@/components/util/column/input/ExcretaTreatFactInpColumn"
|
||||
|
||||
// 하수도 통계 관리 > 07. 분뇨처리시설
|
||||
const ExcretaTreatmentFacilityInp = () => {
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid
|
||||
columnInfo={ExcretaTreatFactInpColumn}
|
||||
rowStartNum={2}
|
||||
fixedColumns={2}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExcretaTreatmentFacilityInp;
|
||||
@@ -0,0 +1,62 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
|
||||
import { SewageTreatFactStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SewageTreatFactStatusInpColumn"
|
||||
import { SepticTankStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/SepticTankStatusInpColumn"
|
||||
import { PrivateSewageDesigStatusInpColumn } from "@/components/util/column/input/privateSewageFacility/PrivateSewageDesigStatusInpColumn"
|
||||
|
||||
// 하수도 통계 관리 > 08. 개인하수처리시설
|
||||
const PrivateSewageFacilityInp = () => {
|
||||
|
||||
// tab list
|
||||
const PrivateSewageFacilityInpTabList = [
|
||||
SewageTreatFactStatusInpColumn,
|
||||
SepticTankStatusInpColumn,
|
||||
PrivateSewageDesigStatusInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const lastYearDataFunc = () => {
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={lastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={PrivateSewageFacilityInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivateSewageFacilityInp;
|
||||
@@ -0,0 +1,73 @@
|
||||
import { useState } from 'react';
|
||||
|
||||
import SearchForm from '@/components/module/SearchForm';
|
||||
import { DataGrid } from '@rsone/components';
|
||||
import SubmitButton from '@/components/button/SumitButton';
|
||||
import SaveButton from '@/components/button/SaveButton';
|
||||
import SubmitExceptionButton from '@/components/button/SubmitExceptionButton';
|
||||
import OperateDataButton from '@/components/button/OperateDataButton';
|
||||
import UpdateOperateDataButton from "@/components/button/UpdateOperateDataButton"
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { PublicSewageFactInpColumn } from '@/components/util/column/input/PublicSewageFactInpColumn';
|
||||
|
||||
// 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
const PublicSewageFacilityInp = () => {
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
console.log('submitException');
|
||||
// 예외제출 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const getOperateDataFunc = () => {
|
||||
console.log('get operate data');
|
||||
// 운영 데이터 가져오기
|
||||
};
|
||||
|
||||
const updateOperateDataButtonFunc = () => {
|
||||
console.log('updatedOperateData');
|
||||
// 운영 데이터 업데이트 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
||||
<OperateDataButton getOperateDataFunc={getOperateDataFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid
|
||||
columnInfo={ PublicSewageFactInpColumn }
|
||||
rowStartNum={3}
|
||||
fixedColumns={2}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicSewageFacilityInp;
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { DataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { PumpingStationInpColumn } from "@/components/util/column/input/PumpingStationInpColumn"
|
||||
|
||||
// 하수도 통계 관리 > 05. 펌프장
|
||||
const PumpingStationInp = () => {
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid
|
||||
columnInfo={ PumpingStationInpColumn }
|
||||
rowStartNum={3}
|
||||
fixedColumns={3}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PumpingStationInp;
|
||||
@@ -0,0 +1,81 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
|
||||
import { PublicInstitutionSewerIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionSewerIndustryInpColumn"
|
||||
import { PublicInstitutionExcretaIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PublicInstitutionExcretaIndustryInpColumn"
|
||||
import { ExcretaRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/ExcretaRelatedIndustryInpColumn";
|
||||
import { PrivateSewageTreatRelatedIndustryInpColumn } from "@/components/util/column/input/sewageExcretaRelated/PrivateSewageTreatRelatedIndustryInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업
|
||||
const SewageExcretaRelatedInp = () => {
|
||||
|
||||
// tab list
|
||||
const SewageExcretaRelatedInpTabList = [
|
||||
PublicInstitutionSewerIndustryInpColumn,
|
||||
PublicInstitutionExcretaIndustryInpColumn,
|
||||
ExcretaRelatedIndustryInpColumn,
|
||||
PrivateSewageTreatRelatedIndustryInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const lastYearDataFunc = () => {
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={lastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewageExcretaRelatedInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaRelatedInp;
|
||||
@@ -0,0 +1,84 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { SlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SlurgeProcessingFacStatusInpColumn";
|
||||
import { DigestorOperatingStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/DigestorOperatingStatusInpColumn";
|
||||
import { SewageSlurgeProcessingFacStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/SewageSlurgeProcessingFacStatusInpColumn";
|
||||
import { ExcretaSlurgeProcessingStatusInpColumn } from "@/components/util/column/input/sewageExcretaSlurge/ExcretaSlurgeProcessingStatusInpColumn";
|
||||
|
||||
|
||||
// 하수도 통계 관리 > 11. 하수 및 분뇨찌꺼기(슬러지)처리
|
||||
const SewageExcretaSlurgeInp = () => {
|
||||
|
||||
// tab list
|
||||
const SewageExcretaSlurgeInpTabList = [
|
||||
SlurgeProcessingFacStatusInpColumn,
|
||||
DigestorOperatingStatusInpColumn,
|
||||
SewageSlurgeProcessingFacStatusInpColumn,
|
||||
ExcretaSlurgeProcessingStatusInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const lastYearDataFunc = () => {
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={lastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewageExcretaSlurgeInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaSlurgeInp;
|
||||
@@ -0,0 +1,72 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
|
||||
import { RegionalFactStatusInpColumn } from "@/components/util/column/input/sewagePipe/RegionalFactStatusInpColumn";
|
||||
import { FactInstallStatusInpColumn } from "@/components/util/column/input/sewagePipe/FactInstallStatusInpColumn";
|
||||
import { PipeTypeStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeTypeStatusInpColumn";
|
||||
import { PipeDiameterStatusInpColumn } from "@/components/util/column/input/sewagePipe/PipeDiameterStatusInpColumn";
|
||||
import { ManholeStatusInpColumn } from "@/components/util/column/input/sewagePipe/ManholeStatusInpColumn";
|
||||
import { ConnectionStatusInpColumn } from "@/components/util/column/input/sewagePipe/ConnectionStatusInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 02. 하수관로
|
||||
const SewagePipeInp = () => {
|
||||
|
||||
// tab List
|
||||
const SewagePipeInpTapList = [
|
||||
RegionalFactStatusInpColumn,
|
||||
FactInstallStatusInpColumn,
|
||||
PipeTypeStatusInpColumn,
|
||||
PipeDiameterStatusInpColumn,
|
||||
ManholeStatusInpColumn,
|
||||
ConnectionStatusInpColumn,
|
||||
];
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewagePipeInpTapList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeInp;
|
||||
@@ -0,0 +1,64 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
|
||||
import { RepairStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/RepairStatusInpColumn";
|
||||
import { PipeDredgingStatusInpColumn } from "@/components/util/column/input/sewagePipeMaintain/PipeDredgingStatusInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 03. 하수관로 유지관리
|
||||
const SewagePipeMaintainInp = () => {
|
||||
|
||||
// tab List
|
||||
const SewagePipeMaintainInpTabList = [
|
||||
RepairStatusInpColumn,
|
||||
PipeDredgingStatusInpColumn
|
||||
];
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewagePipeMaintainInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeMaintainInp;
|
||||
@@ -0,0 +1,85 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { SewageReservoirInpColumn } from "@/components/util/column/input/sewageReservoirPump/SewageReservoirInpColumn";
|
||||
import { RainfallPumpStationInpColumn } from "@/components/util/column/input/sewageReservoirPump/RainfallPumpStationInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 04. 하수저류 시설 및 빗물 펌프장
|
||||
const SewageReservoirPumpInp = () => {
|
||||
|
||||
// tab List
|
||||
const SewageReservoirPumpInpTabList = [
|
||||
SewageReservoirInpColumn,
|
||||
RainfallPumpStationInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('save');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewageReservoirPumpInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageReservoirPumpInp;
|
||||
@@ -0,0 +1,64 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
|
||||
import { SewerageFinanceSettleInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageFinanceSettleInpColumn"
|
||||
import { SewerageChargeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageChargeInpColumn"
|
||||
import { SewerageUsageFeeInpColumn } from "@/components/util/column/input/sewerageFinance/SewerageUsageFeeInpColumn"
|
||||
import { CauserBurdenInpColumn } from "@/components/util/column/input/sewerageFinance/CauserBurdenInpColumn"
|
||||
|
||||
// 하수도 통계 관리 > 09. 하수도재정
|
||||
const SewerageFinanceInp = () => {
|
||||
|
||||
// tab list
|
||||
const SewerageFinanceInpTabList = [
|
||||
SewerageFinanceSettleInpColumn,
|
||||
SewerageChargeInpColumn,
|
||||
SewerageUsageFeeInpColumn,
|
||||
CauserBurdenInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const lastYearDataFunc = () => {
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={lastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewerageFinanceInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageFinanceInp;
|
||||
@@ -0,0 +1,167 @@
|
||||
import { useState, useMemo } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
// import { DataGrid } from "@rsone/components";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsInputAPi } from "@/entities/statistics/api/statistics-input-service";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import type {
|
||||
SewerageSupplyRateItem,
|
||||
SewerageSupplyRateRequestParams,
|
||||
} from "@/entities/statistics/model/statistics-input-interface";
|
||||
import { SeweragePenetrationRateInpColumn } from "@/components/util/column/input/SeweragePenetrationRateInpColumn";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
function getSewerageSupplyRateParams(
|
||||
values: SearchFormValues,
|
||||
overrides?: { yr?: string; demoYr?: string; mode?: string }
|
||||
): SewerageSupplyRateRequestParams {
|
||||
return {
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: overrides?.yr ?? values.year,
|
||||
demoYr: overrides?.demoYr ?? values.year,
|
||||
...(overrides?.mode && { mode: overrides.mode }),
|
||||
};
|
||||
}
|
||||
|
||||
// 하수도 통계 관리 > 01. 하수도 보급률
|
||||
const SeweragePenetrationRateInp = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
const [searchValues, setSearchValues] = useState<SearchFormValues | null>(null);
|
||||
const [isEnterable, setIsEnterable] = useState<boolean>(true);
|
||||
const [lastSearchedYear, setLastSearchedYear] = useState<string | null>(null);
|
||||
|
||||
|
||||
// 최상위 관리자일땐 모든 상황에서 edit 가능하게 수정 필요.
|
||||
const columnInfo = useMemo(() => {
|
||||
const { columns, columnLayout } = SeweragePenetrationRateInpColumn;
|
||||
return {
|
||||
columnLayout,
|
||||
columns: isEnterable
|
||||
? columns
|
||||
: columns.map((col) => ({ ...col, editable: false as const })),
|
||||
};
|
||||
}, [isEnterable]);
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
setLastSearchedYear(null);
|
||||
};
|
||||
|
||||
const fetchSewerageSupplyRate = async (params: SewerageSupplyRateRequestParams) => {
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsInputAPi.getSewerageSupplyRateList(params);
|
||||
if (response.status === 'success' && response.data) {
|
||||
const convertedData: SewerageSupplyRateItem[] = response.data.sewerageSupplyRateList.map((d) => ({
|
||||
...d,
|
||||
speclCntrplnAr: d.speclCntrplnAr === '' || d.speclCntrplnAr === null ? '해당없음' : d.speclCntrplnAr,
|
||||
}));
|
||||
|
||||
setRowData(toGridRows(convertedData));
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
setRowData([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (values.sido === '' || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await statisticsInputAPi.checkInputPeriod(values.year || '');
|
||||
|
||||
if (response.status === 'success') {
|
||||
setIsEnterable(response.data);
|
||||
setLastSearchedYear(values.year || null);
|
||||
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values));
|
||||
} else {
|
||||
alert(response.message);
|
||||
}
|
||||
} catch {
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
}
|
||||
};
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = async (values: SearchFormValues) => {
|
||||
if (values.sido === '' || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
// 실제 조회된 연도가 없으면 실행 불가
|
||||
if (!lastSearchedYear) {
|
||||
alert('먼저 데이터를 조회해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
await fetchSewerageSupplyRate(getSewerageSupplyRateParams(values, { mode: 'PRE' }));
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} onValuesChange={setSearchValues} />
|
||||
{rowData.length > 0 &&
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] mx-[0.6rem]">
|
||||
{isEnterable && <SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />}
|
||||
{isEnterable && <LastYearDataButton getLastYearDataFunc={() => getLastYearDataFunc(searchValues ?? {})} />}
|
||||
{isEnterable && <SubmitButton submitFunc={submitFunc} />}
|
||||
{
|
||||
// 최고 관리자일땐 저장 가능하게
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
{isLoading && <div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>}
|
||||
<DataGrid
|
||||
key={isEnterable ? 'enterable' : 'readonly'}
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={(rowData.length > 0) && isEnterable}
|
||||
rowStartNum={3}
|
||||
fixedColumns={1}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeweragePenetrationRateInp;
|
||||
@@ -0,0 +1,67 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { ComplaintInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ComplaintInpColumn";
|
||||
import { ResidentFriendlyFactInpColumn } from "@/components/util/column/input/sewerageServiceLevel/ResidentFriendlyFactInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 13. 하수도 서비스 수준
|
||||
const SewerageServiceLevelInp = () => {
|
||||
|
||||
// tab List
|
||||
const SewerageServiceLevelInpTabList = [
|
||||
ComplaintInpColumn,
|
||||
ResidentFriendlyFactInpColumn
|
||||
];
|
||||
|
||||
const submitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={submitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={SewerageServiceLevelInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageServiceLevelInp;
|
||||
@@ -0,0 +1,44 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import RejectButton from "@/components/button/RejectButton";
|
||||
|
||||
import { StatsInputStatusInpColumn } from "@/components/util/column/input/StatsInputStatusInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 00. 통계 입력 현황
|
||||
const StatsInputStatusInp = () => {
|
||||
|
||||
const rejectFunc = () => {
|
||||
// 보완 요청 로직
|
||||
};
|
||||
|
||||
const approveFunc = () => {
|
||||
// 승인 요청 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<RejectButton rejectFunc={rejectFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid
|
||||
columnInfo={ StatsInputStatusInpColumn }
|
||||
rowStartNum={2}
|
||||
fixedColumns={3}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
isExcelImport={false}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatsInputStatusInp;
|
||||
@@ -0,0 +1,92 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { TabDataGrid } from '@rsone/components';
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import UpdateOperateDataButton from "@/components/button/UpdateOperateDataButton"
|
||||
import AddArticleButton from "@/components/button/AddArticleButton";
|
||||
import DeleteArticleButton from "@/components/button/DeleteArticleButton";
|
||||
import NotApplicableCheckButton from "@/components/button/NotApplicableCheckButton";
|
||||
|
||||
import { PublicSewageTreatWaterReuseInpColumn } from "@/components/util/column/input/waterReuse/PublicSewageTreatWaterReuseInpColumn";
|
||||
import { RecycledWaterStatusInpColumn } from "@/components/util/column/input/waterReuse/RecycledWaterStatusInpColumn";
|
||||
import { RainFallUtilFactStatusInpColumn } from "@/components/util/column/input/waterReuse/RainFallUtilFactStatusInpColumn";
|
||||
import { TreatWaterReuseDesignConstStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseDesignConstStatusInpColumn";
|
||||
import { TreatWaterReuseBusinessApprStatusInpColumn } from "@/components/util/column/input/waterReuse/TreatWaterReuseBusinessApprStatusInpColumn";
|
||||
|
||||
// 하수도 통계 관리 > 10. 물 재이용
|
||||
const WaterReuseInp = () => {
|
||||
|
||||
// tab list
|
||||
const WaterReuseInpTabList = [
|
||||
PublicSewageTreatWaterReuseInpColumn,
|
||||
RecycledWaterStatusInpColumn,
|
||||
RainFallUtilFactStatusInpColumn,
|
||||
TreatWaterReuseDesignConstStatusInpColumn,
|
||||
TreatWaterReuseBusinessApprStatusInpColumn
|
||||
];
|
||||
const SubmitExceptionFunc = () => {
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
// 전연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const submitFunc = () => {
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const updateOperateDataButtonFunc = () => {
|
||||
// 운영 데이터 업데이트 로직 - tab1. 공공하수처리수 재이용
|
||||
};
|
||||
|
||||
const addArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 추가 로직
|
||||
};
|
||||
|
||||
const deleteArticleFunc = () => {
|
||||
console.log('save');
|
||||
// 항목 제외 로직
|
||||
};
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
const [isNotApplicable, setIsNotApplicable] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<NotApplicableCheckButton isCheck={isNotApplicable} setIsCheck={setIsNotApplicable} />
|
||||
<UpdateOperateDataButton updateOperateDataButtonFunc={updateOperateDataButtonFunc} />
|
||||
<AddArticleButton addArticleFunc={addArticleFunc} />
|
||||
<DeleteArticleButton deleteArticleFunc={deleteArticleFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid
|
||||
columnInfo={WaterReuseInpTabList}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaterReuseInp;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const ExcretaTreatmentFacilityMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExcretaTreatmentFacilityMng;
|
||||
@@ -0,0 +1,41 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
|
||||
const NotEnteredStatus = () => {
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
const columns: ColumnConfig[] = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '1', fieldName: '1', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '2-1', fieldName: '2-1', header: { text: '2-1' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '2-2', fieldName: '2-2', header: { text: '2-2' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '2-3', fieldName: '2-3', header: { text: '2-3' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '2-4', fieldName: '2-4', header: { text: '2-4' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '3-1', fieldName: '3-1', header: { text: '3-1' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '3-2', fieldName: '3-2', header: { text: '3-2' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sido',
|
||||
'sgg',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '미입력 하수도 통계 세부항목(번호)' },
|
||||
items: ['1', '2-1', '2-2', '2-3', '2-4', '3-1', '3-2'],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowData={rowData} setRowData={setRowData} isExcelImport={false} fixedColumns={2} rowStartNum={2} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NotEnteredStatus;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const PrivateSewageFacilityMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivateSewageFacilityMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const PublicSewageFacilityMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicSewageFacilityMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const PumpingStationMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PumpingStationMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageExcretaRelatedMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaRelatedMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageExcretaSlurgeMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaSlurgeMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewagePipeMaintainMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeMaintainMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageReservoirPumpMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageReservoirPumpMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewerageFinanceMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageFinanceMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "../../module/SearchForm";
|
||||
|
||||
const SewerageServiceLevelMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageServiceLevelMng;
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
|
||||
const StatisticsInputManagement = () => {
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
const columns: ColumnConfig[] = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '구분', fieldName: '구분', header: { text: '구분' }, editable: false, sortdisable: true },
|
||||
{ name: '광역자치단체', fieldName: '광역자치단체', header: { text: '광역자치단체' }, editable: false, sortdisable: true },
|
||||
{ name: '공단', fieldName: '공단', header: { text: '공단' }, editable: false, sortdisable: true },
|
||||
{ name: '처리내역', fieldName: '처리내역', header: { text: '처리내역' }, editable: false, sortdisable: true },
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sido',
|
||||
'sgg',
|
||||
'구분',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '검토내역' },
|
||||
items: ['광역자치단체', '공단', '처리내역'],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm sgg={false} sido={false} />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowData={rowData} setRowData={setRowData} isExcelImport={false} isExcelExport={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsInputManagement;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const StatisticsPopulationManagement = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm sgg={false} sido={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsPopulationManagement;
|
||||
@@ -0,0 +1,39 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import type { ColumnConfig } from "@/components/type/DataGrid.type";
|
||||
|
||||
const StatisticsReviewHistory = () => {
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
const columns: ColumnConfig[] = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, mergeCells: true, editable: false, sortdisable: true },
|
||||
{ name: '구분', fieldName: '구분', header: { text: '구분' }, editable: false, sortdisable: true },
|
||||
{ name: '광역자치단체', fieldName: '광역자치단체', header: { text: '광역자치단체' }, editable: false, sortdisable: true },
|
||||
{ name: '공단', fieldName: '공단', header: { text: '공단' }, editable: false, sortdisable: true },
|
||||
{ name: '처리내역', fieldName: '처리내역', header: { text: '처리내역' }, editable: false, sortdisable: true },
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sido',
|
||||
'sgg',
|
||||
'구분',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '검토내역' },
|
||||
items: ['광역자치단체', '공단', '처리내역'],
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<DataGrid columnInfo={{ columns, columnLayout }} rowStartNum={2} fixedColumns={3} rowData={rowData} setRowData={setRowData} isExcelImport={false} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatisticsReviewHistory;
|
||||
@@ -1,55 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import RejectButton from "@/components/button/RejectButton";
|
||||
|
||||
const StatsInputSatusMng = () => {
|
||||
const columns = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' } },
|
||||
{ name: 'sgg', fieldName: '구군', header: { text: '구군' } },
|
||||
{ name: 'menu_nm', fieldName: '구분', header: { text: '구분' } },
|
||||
{ name: 'locg_status_nm', fieldName: '진행상황', header: { text: '진행상황' } },
|
||||
{ name: 'locg_status', fieldName: '작성률', header: { text: '작성률' } },
|
||||
{ name: 'locg_charger', fieldName: '작성자', header: { text: '작성자' } },
|
||||
{ name: 'locg_cttpc', fieldName: '작성자 연락처', header: { text: '작성자 연락처' } },
|
||||
{ name: 'locg_dept', fieldName: '작성자 부서', header: { text: '작성자 부서' } },
|
||||
{ name: 'locg_job', fieldName: '작성자 직제', header: { text: '작성자 직제' } },
|
||||
{ name: 'locg_cnfirm_nm', fieldName: '승인자', header: { text: '승인자' } },
|
||||
{ name: 'locg_cnfirm_dept', fieldName: '승인자 부서', header: { text: '승인자 부서' } },
|
||||
{ name: 'locg_cnfirm_job', fieldName: '승인자 직제', header: { text: '승인자 직제' } },
|
||||
{ name: 'return_opinion_sm', fieldName: '반려 사유', header: { text: '반려 사유' } },
|
||||
];
|
||||
|
||||
const columnLayout = [
|
||||
'sido',
|
||||
'sgg',
|
||||
'menu_nm',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수도사업자' },
|
||||
items: columns.filter((c) => ['sido', 'sgg', 'menu_nm'].includes(c.name) === false).map((m) => m.name),
|
||||
},
|
||||
];
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('appoved');
|
||||
};
|
||||
|
||||
const rejectFunc = () => {
|
||||
console.log('reject');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<RejectButton rejectFunc={rejectFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={2} isExcelImport={true} fixedColumns={3} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatsInputSatusMng;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "../../module/SearchForm";
|
||||
|
||||
const WaterReuseMng = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaterReuseMng;
|
||||
@@ -0,0 +1,38 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { ExcretaTreatmentFacilityInfoList } from "@/components/util/column/review/ExcretaTreatmentFacilityRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 07.분뇨처리 시설
|
||||
const ExcretaTreatmentFacilityRvw = () => {
|
||||
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => console.log('approveFunc');
|
||||
const saveFunc = () => console.log('submit');
|
||||
const reviewOpinionFunc = () => console.log('reviewOpinionFunc');
|
||||
const returnFunc = () => console.log('returnFunc');
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={ExcretaTreatmentFacilityInfoList} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExcretaTreatmentFacilityRvw;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { PrivateSewageFacilityInfoListRvw } from "@/components/util/column/review/PrivateSewageFacilityColumn";
|
||||
|
||||
// 하수도 통계 관리 08.개인하수처리시설
|
||||
const PrivateSewageFacilityRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={PrivateSewageFacilityInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivateSewageFacilityRvw;
|
||||
@@ -0,0 +1,48 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { PublicSewageFacilityInfoList } from "@/components/util/column/review/PublicSewageFacilityRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 06.공공하수처리시설
|
||||
const PublicSewageFacilityRvw = () => {
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid columnInfo={PublicSewageFacilityInfoList} isExcelImport={false} rowStartNum={3} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicSewageFacilityRvw;
|
||||
@@ -1,12 +1,37 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { useState } from "react";
|
||||
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { PumpingStationInfoList } from "@/components/util/column/review/PumpingStationRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 05.펌프장
|
||||
const PumpingStationRvw = () => {
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
const approveFunc = () => { console.log('approveFunc'); };
|
||||
const saveFunc = () => { console.log('submit'); };
|
||||
const reviewOpinionFunc = () => { console.log('reviewOpinionFunc'); };
|
||||
const returnFunc = () => { console.log('returnFunc'); };
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} fctName={true} />
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<DataGrid columnInfo={PumpingStationInfoList} isExcelImport={false} rowStartNum={3} fixedColumns={3} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default PumpingStationRvw;
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewageExcretaRelatedInfoListRvw } from "@/components/util/column/review/SewageExcretaRelatedRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 12. 하수 및 분뇨 관련 산업
|
||||
const SewageExcretaRelatedRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewageExcretaRelatedInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default SewageExcretaRelatedRvw;
|
||||
@@ -0,0 +1,52 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewageExcretaSludgeInfoListRvw } from "@/components/util/column/review/SewageExcretaSlurgeRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 11. 하수 및 분뇨 찌꺼기(슬러지) 처리
|
||||
const SewageExcretaSlurgeRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewageExcretaSludgeInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaSlurgeRvw;
|
||||
@@ -1,11 +1,52 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewagePipeMaintainColumnInfoList } from "@/components/util/column/review/SewagePipeMaintainRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 03. 하수관로 유지 관리
|
||||
const SewagePipeMaintainRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewagePipeMaintainColumnInfoList} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SewagePipeMaintainRvw;
|
||||
@@ -1,11 +1,100 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import TabDataGrid from "@/components/module/TabDataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||
import { SewagePipeColumnInfoListRvw } from "@/components/util/column/review/SewagePipeRvwColumn";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
// 하수도 통계 검토 02.하수관로
|
||||
const SewagePipeRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, any[]>>(new Map());
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
return SewagePipeColumnInfoListRvw.map((tab: any) => ({
|
||||
...tab,
|
||||
columns: tab.columns.map((col: any) => ({
|
||||
...col,
|
||||
editable: false as const,
|
||||
styleName: col.styleName ?? ("rg-cell-readonly" as const),
|
||||
})),
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const handleReset = () => setRowDataMap(new Map());
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (!values.sido || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
const response = await statisticsManagementApi.getSewagePipeReviewList({
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: values.year,
|
||||
});
|
||||
|
||||
if (response.status === 'success' && response.data) {
|
||||
const rawList = response.data;
|
||||
const newRowDataMap = new Map<string, any[]>();
|
||||
|
||||
newRowDataMap.set('a', toGridRows(rawList));
|
||||
|
||||
setRowDataMap(newRowDataMap);
|
||||
} else {
|
||||
handleReset();
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("조회 에러:", error);
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
handleReset();
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={() => {}} />
|
||||
<ApproveButton approveFunc={() => {}} />
|
||||
<ReturnButton returnFunc={() => {}} />
|
||||
<SaveButton saveFunc={() => {}} />
|
||||
</div>
|
||||
</div>
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<TabDataGrid
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={false}
|
||||
rowDataMap={rowDataMap}
|
||||
setRowDataMap={setRowDataMap}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SewagePipeRvw;
|
||||
@@ -1,11 +1,52 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewageReservoirPumpInfoListRvw } from "@/components/util/column/review/SewageReservoirPumpRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 04. 하수저류 시설 및 빗물 펌프장
|
||||
const SewageReservoirPumpRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewageReservoirPumpInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SewageReservoirPumpRvw;
|
||||
export default SewageReservoirPumpRvw;
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewerageFinanceInfoListRvw } from "@/components/util/column/review/SewerageFinanceRvwColumn";
|
||||
|
||||
|
||||
// 하수도 통계 관리 09. 하수도 재정
|
||||
const SewerageFinanceRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewerageFinanceInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default SewerageFinanceRvw;
|
||||
@@ -1,11 +1,115 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { SeweragePenetrationRateInfoList } from "@/components/util/column/review/SeweragePenetrationRateRvwColumn";
|
||||
import type { SewerageSupplyRateReviewItem } from "@/entities/statistics/model/statistics-sewerage-penetration-review-interface";
|
||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||
import type { SearchFormValues } from "@/components/type/SearchForm.type";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
// 하수도 통계 검토 01.하수도 보급률
|
||||
const SeweragePenetrationRateRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowData, setRowData] = useState<any[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
const { columns, columnLayout, fixedColumns, rowStartNum } = SeweragePenetrationRateInfoList;
|
||||
return {
|
||||
columnLayout,
|
||||
fixedColumns,
|
||||
rowStartNum,
|
||||
columns: columns.map((col) => ({
|
||||
...col,
|
||||
editable: false as const,
|
||||
styleName: col.styleName ?? ("rg-cell-readonly" as const),
|
||||
})),
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
};
|
||||
|
||||
const handleSearch = async (values: SearchFormValues) => {
|
||||
if (values.sido === '' || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await statisticsManagementApi.getSewerageSupplyRateReviewList({
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
bsnmCd: values.bsnmCd,
|
||||
yr: values.year,
|
||||
});
|
||||
|
||||
if (response.status === 'success' && response.data) {
|
||||
const rawList = response.data.sewerageSupplyRateList;
|
||||
const convertedData: SewerageSupplyRateReviewItem[] = rawList.map((item) => ({
|
||||
...item,
|
||||
speclCntrplnAr: !item.speclCntrplnAr ? '해당없음' : item.speclCntrplnAr,
|
||||
}));
|
||||
|
||||
setRowData(toGridRows(convertedData));
|
||||
} else {
|
||||
setRowData([]);
|
||||
alert(response.message || "데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("조회 중 에러 발생:", error);
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const approveFunc = () => console.log('approveFunc');
|
||||
const saveFunc = () => console.log('submit');
|
||||
const reviewOpinionFunc = () => console.log('reviewOpinionFunc');
|
||||
const returnFunc = () => console.log('returnFunc');
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DataGrid
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={false}
|
||||
fixedColumns={columnInfo.fixedColumns}
|
||||
rowStartNum={columnInfo.rowStartNum}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
export default SeweragePenetrationRateRvw;
|
||||
@@ -0,0 +1,53 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { SewerageServiceLevelInfoListRvw } from "@/components/util/column/review/SewerageServiceLevelRvwColumn";
|
||||
|
||||
// 하수도 통계 관리 13. 하수도 서비스 수준
|
||||
const SewerageServiceLevelRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={SewerageServiceLevelInfoListRvw} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
export default SewerageServiceLevelRvw;
|
||||
@@ -1,11 +0,0 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const StatsInputSatusRvw = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default StatsInputSatusRvw;
|
||||
@@ -0,0 +1,113 @@
|
||||
import { useState, useMemo } from "react";
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
import { LoadingWithAnimation } from "@common/components";
|
||||
|
||||
import { useAlertStore } from "@/shared/lib";
|
||||
import { StatsInputStatusInfoList } from "@/components/util/column/review/StatsInputStatusRvwColumn";
|
||||
import { statisticsManagementApi } from "@/entities/statistics/api/statistics-management-service";
|
||||
import type { StatsInputStatusReviewItem } from "@/entities/statistics/model/statistics-input-review-interface";
|
||||
import { toGridRows } from "@/components/util/grid/gridFunction";
|
||||
|
||||
// 하수도 통계 검토 00. 통계 입력 현황
|
||||
const StatsInputStatusRvw = () => {
|
||||
const { setMessage: alert } = useAlertStore((state) => state);
|
||||
const [rowData, setRowData] = useState<any[]>([]);
|
||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||
|
||||
const columnInfo = useMemo(() => {
|
||||
const { columns, columnLayout } = StatsInputStatusInfoList;
|
||||
return {
|
||||
columnLayout,
|
||||
columns: columns.map((col) => ({
|
||||
...col,
|
||||
editable: false as const,
|
||||
})),
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleReset = () => {
|
||||
setRowData([]);
|
||||
};
|
||||
|
||||
const handleSearch = async (values: any) => {
|
||||
if (!values.sido || values.sido === 'ALL') {
|
||||
alert('시도를 선택해주세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsLoading(true);
|
||||
|
||||
const response = await statisticsManagementApi.getStatsInputStatusList({
|
||||
sido: values.sido,
|
||||
gugun: values.gugun === 'ALL' ? '' : values.gugun,
|
||||
yr: values.year || values.yr,
|
||||
bsnmCd: values.bsnmCd
|
||||
});
|
||||
|
||||
if (response.status === 'success' && response.data) {
|
||||
const rawList = response.data.sewerageSupplyRateList || response.data;
|
||||
|
||||
const convertedData: StatsInputStatusReviewItem[] = rawList.map((item: any) => ({
|
||||
...item,
|
||||
status: item.status || '미확인',
|
||||
}));
|
||||
|
||||
setRowData(toGridRows(convertedData));
|
||||
} else {
|
||||
setRowData([]);
|
||||
alert(response.message || "조회된 데이터가 없습니다.");
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("입력현황 조회 중 에러 발생:", error);
|
||||
alert('데이터 조회 중 오류가 발생했습니다.');
|
||||
setRowData([]);
|
||||
} finally {
|
||||
setIsLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const approveFunc = () => console.log('approveFunc');
|
||||
const saveFunc = () => console.log('submit');
|
||||
const reviewOpinionFunc = () => console.log('reviewOpinionFunc');
|
||||
const returnFunc = () => console.log('returnFunc');
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<SearchForm onSubmit={handleSearch} onReset={handleReset} />
|
||||
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading && (
|
||||
<div className="absolute inset-0 z-50 [data-theme='black']:bg-transparent bg-white/50 rounded-lg p-10 flex justify-center items-center">
|
||||
<div className="relative size-[5rem]">
|
||||
<LoadingWithAnimation color="primary" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<DataGrid
|
||||
columnInfo={columnInfo}
|
||||
isExcelImport={false}
|
||||
rowStartNum={2}
|
||||
fixedColumns={2}
|
||||
rowData={rowData}
|
||||
setRowData={setRowData}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default StatsInputStatusRvw;
|
||||
@@ -0,0 +1,51 @@
|
||||
import { useState } from "react";
|
||||
|
||||
import { TabDataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import ApproveButton from "@/components/button/ApproveButton";
|
||||
import ReviewOpinionButton from "@/components/button/ReviewOpinionButton";
|
||||
import ReturnButton from "@/components/button/ReturnButton";
|
||||
|
||||
import { WaterReuseInfoList } from "@/components/util/column/review/WaterReuseRvwColumn";
|
||||
|
||||
const WaterReuseRvw = () => {
|
||||
const [rowDataMap, setRowDataMap] = useState<Map<string, Record<string, string | number>[]>>(new Map());
|
||||
|
||||
const approveFunc = () => {
|
||||
console.log('approveFunc');
|
||||
// 승인 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const reviewOpinionFunc = () => {
|
||||
console.log('reviewOpinionFunc');
|
||||
// 검토의견 작성
|
||||
};
|
||||
|
||||
const returnFunc = () => {
|
||||
console.log('returnFunc');
|
||||
// 반려
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm fctName={true} />
|
||||
<div className="card !py-0">
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<ReviewOpinionButton reviewOpinionFunc={reviewOpinionFunc} />
|
||||
<ApproveButton approveFunc={approveFunc} />
|
||||
<ReturnButton returnFunc={returnFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
</div>
|
||||
</div>
|
||||
<TabDataGrid columnInfo={WaterReuseInfoList} isExcelImport={false} rowDataMap={rowDataMap} setRowDataMap={setRowDataMap} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaterReuseRvw;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const ExcretaTreatmentFacilityTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ExcretaTreatmentFacilityTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const PrivateSewageFacilityTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PrivateSewageFacilityTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const PublicSewageFacilityTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default PublicSewageFacilityTot;
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewagePipeMng = () => {
|
||||
const PumpingStationTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeMng;
|
||||
export default PumpingStationTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageExcretaRelatedTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaRelatedTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageExcretaSlurgeTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageExcretaSlurgeTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewagePipeMaintainTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeMaintainTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewagePipeTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewagePipeTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewageReservoirPumpTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewageReservoirPumpTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
|
||||
const SewerageFinanceTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageFinanceTot;
|
||||
+38
-5
@@ -1,10 +1,15 @@
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import DataGrid from "@/components/module/DataGrid";
|
||||
import SubmitButton from "@/components/button/SumitButton";
|
||||
import SaveButton from "@/components/button/SaveButton";
|
||||
import LastYearDataButton from "@/components/button/LastYearDataButton";
|
||||
import SubmitExceptionButton from "@/components/button/SubmitExceptionButton";
|
||||
import { useState } from "react";
|
||||
|
||||
const SeweragePenetrationRate = () => {
|
||||
const SeweragePenetrationRateTot = () => {
|
||||
const columns = [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' } },
|
||||
{ name: 'sgg', fieldName: '구군', header: { text: '구군' } },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' } },
|
||||
{ name: 'rvbsn', fieldName: '수계', header: { text: '수계' } },
|
||||
{ name: 'bstrm', fieldName: '지류', header: { text: '지류' } },
|
||||
{ name: 'mdbsn', fieldName: '세부단위유역', header: { text: '세부단위유역' } },
|
||||
@@ -98,12 +103,40 @@ const SeweragePenetrationRate = () => {
|
||||
'rmk',
|
||||
];
|
||||
|
||||
const submitFunc = () => {
|
||||
console.log('submit');
|
||||
// 제출 로직
|
||||
};
|
||||
|
||||
const saveFunc = () => {
|
||||
console.log('submit');
|
||||
// 저장 로직
|
||||
};
|
||||
|
||||
const getLastYearDataFunc = () => {
|
||||
console.log('get last year data');
|
||||
// 지난연도 데이터 가져오기 로직
|
||||
};
|
||||
|
||||
const SubmitExceptionFunc = () => {
|
||||
console.log('submit exception');
|
||||
// 예외 제출 로직
|
||||
};
|
||||
|
||||
const [rowData, setRowData] = useState<Record<string, string | number>[]>([]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SearchForm userMenual={true} />
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={2} isExcelImport={true} fixedColumns={1} />
|
||||
<SearchForm />
|
||||
<div className="flex justify-end items-center gap-[0.6rem] m-[0.6rem]">
|
||||
<SubmitButton submitFunc={submitFunc} />
|
||||
<SaveButton saveFunc={saveFunc} />
|
||||
<LastYearDataButton getLastYearDataFunc={getLastYearDataFunc} />
|
||||
<SubmitExceptionButton SubmitExceptionFunc={SubmitExceptionFunc} />
|
||||
</div>
|
||||
<DataGrid columnInfo={{columns, columnLayout}} rowStartNum={2} isExcelImport={true} fixedColumns={1} rowData={rowData} setRowData={setRowData} />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SeweragePenetrationRate;
|
||||
export default SeweragePenetrationRateTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "../../module/SearchForm";
|
||||
|
||||
const SewerageServiceLevelTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default SewerageServiceLevelTot;
|
||||
@@ -0,0 +1,11 @@
|
||||
import SearchForm from "../../module/SearchForm";
|
||||
|
||||
const WaterReuseTot = () => {
|
||||
return (
|
||||
<>
|
||||
<SearchForm />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default WaterReuseTot;
|
||||
@@ -0,0 +1,482 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { DataGrid } from "@rsone/components";
|
||||
import SearchForm from "@/components/module/SearchForm";
|
||||
import {
|
||||
Button,
|
||||
Input,
|
||||
Label,
|
||||
Select,
|
||||
SelectTrigger,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectValue,
|
||||
Checkbox,
|
||||
} from "@common/components";
|
||||
import { verificationHistoryColumnInfo } from "@/entities/statistics/model/verification-history-column";
|
||||
import { verificationHistoryMockData } from "@/entities/statistics/model/verification-history-mock";
|
||||
|
||||
interface VerificationFormValues {
|
||||
mu: string;
|
||||
percentile: string;
|
||||
a: string;
|
||||
c: string;
|
||||
verificationYear: string;
|
||||
checkboxOptions: {
|
||||
sidoDistribution: boolean;
|
||||
countyDistribution: boolean;
|
||||
countyDistributionUserManagement: boolean;
|
||||
lowerDistribution: boolean;
|
||||
sidoServiceAvailability: boolean;
|
||||
individualService: boolean;
|
||||
legalServiceUsage: boolean;
|
||||
excessUse: boolean;
|
||||
lowerOrgStatistics: boolean;
|
||||
studentStatistics: boolean;
|
||||
developmentStatistics: boolean;
|
||||
lowerManagementEnterprise: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const ManagementVerificationRule = () => {
|
||||
const [verificationHistoryRowData, setVerificationHistoryRowData] =
|
||||
useState<Record<string, string | number>[]>(
|
||||
verificationHistoryMockData,
|
||||
);
|
||||
|
||||
const [formValues, setFormValues] = useState<VerificationFormValues>({
|
||||
mu: "0",
|
||||
percentile: "0",
|
||||
a: "0",
|
||||
c: "0",
|
||||
verificationYear: "2025",
|
||||
checkboxOptions: {
|
||||
sidoDistribution: false,
|
||||
countyDistribution: false,
|
||||
countyDistributionUserManagement: false,
|
||||
lowerDistribution: false,
|
||||
sidoServiceAvailability: false,
|
||||
individualService: false,
|
||||
legalServiceUsage: false,
|
||||
excessUse: false,
|
||||
lowerOrgStatistics: false,
|
||||
studentStatistics: false,
|
||||
developmentStatistics: false,
|
||||
lowerManagementEnterprise: false,
|
||||
},
|
||||
});
|
||||
|
||||
const handleCheckboxChange = (
|
||||
key: keyof VerificationFormValues["checkboxOptions"],
|
||||
) => {
|
||||
setFormValues((prev) => ({
|
||||
...prev,
|
||||
checkboxOptions: {
|
||||
...prev.checkboxOptions,
|
||||
[key]: !prev.checkboxOptions[key],
|
||||
},
|
||||
}));
|
||||
};
|
||||
|
||||
const handleInputChange = (
|
||||
key: keyof Omit<VerificationFormValues, "checkboxOptions">,
|
||||
value: string,
|
||||
) => {
|
||||
setFormValues((prev) => ({
|
||||
...prev,
|
||||
[key]: value,
|
||||
}));
|
||||
};
|
||||
|
||||
const handleSubmit = () => {
|
||||
console.log("검증 실행:", formValues);
|
||||
};
|
||||
|
||||
const handleReset = () => {
|
||||
console.log("초기화");
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="card card-border mt-4">
|
||||
<div className="p-2">
|
||||
{/* 통계 검증 섹션 */}
|
||||
<div className="mb-6">
|
||||
<h3 className="px-2 text-[1.5rem] font-semibold">
|
||||
통계 검증
|
||||
</h3>
|
||||
|
||||
<div className="flex gap-2">
|
||||
{/* 왼쪽: 검증 변수 */}
|
||||
<div className="card card-border flex-[0.5] rounded p-4">
|
||||
<h4 className="mb-3 rounded bg-gray-100 p-2 text-[1.4rem] font-medium">
|
||||
검증 변수
|
||||
</h4>
|
||||
|
||||
<div className="space-y-3">
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">μ</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formValues.mu}
|
||||
onChange={(e) =>
|
||||
handleInputChange(
|
||||
"mu",
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
Percentile
|
||||
</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formValues.percentile}
|
||||
onChange={(e) =>
|
||||
handleInputChange(
|
||||
"percentile",
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">A</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formValues.a}
|
||||
onChange={(e) =>
|
||||
handleInputChange(
|
||||
"a",
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">C</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={formValues.c}
|
||||
onChange={(e) =>
|
||||
handleInputChange(
|
||||
"c",
|
||||
e.target.value,
|
||||
)
|
||||
}
|
||||
className="flex-1"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Label className="w-32 text-label">
|
||||
검증 년도
|
||||
</Label>
|
||||
<Select
|
||||
value={formValues.verificationYear}
|
||||
onValueChange={(value) =>
|
||||
handleInputChange(
|
||||
"verificationYear",
|
||||
value,
|
||||
)
|
||||
}
|
||||
>
|
||||
<SelectTrigger className="flex-1">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="2025">
|
||||
2025년
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 오른쪽: 검증 대상 */}
|
||||
<div className="card card-border flex-1 rounded p-4">
|
||||
<h4 className="mb-3 rounded bg-gray-100 p-2 text-[1.4rem] font-medium">
|
||||
검증 대상
|
||||
</h4>
|
||||
|
||||
<div className="space-y-4 p-2">
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.sidoDistribution
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"sidoDistribution",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수도 보급률
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.countyDistribution
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"countyDistribution",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수관로
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.countyDistributionUserManagement
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"countyDistributionUserManagement",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수관로 유지관리
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.lowerDistribution
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"lowerDistribution",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수저류시설 및 빗물펌프장
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.sidoServiceAvailability
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"sidoServiceAvailability",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
펌프장
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.individualService
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"individualService",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
공공하수처리시설
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.sidoServiceAvailability
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"sidoServiceAvailability",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
분뇨처리시설
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.individualService
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"individualService",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
개인하수처리시설
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.lowerOrgStatistics
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"lowerOrgStatistics",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수도재정
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.studentStatistics
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"studentStatistics",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
물 재이용
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.lowerOrgStatistics
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"lowerOrgStatistics",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수 및 분뇨찌꺼기(슬러지) 처리
|
||||
</Label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.studentStatistics
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"studentStatistics",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수 및 분뇨관련산업
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-4 gap-4">
|
||||
<div className="flex items-center gap-2">
|
||||
<Checkbox
|
||||
checked={
|
||||
formValues.checkboxOptions
|
||||
.lowerManagementEnterprise
|
||||
}
|
||||
onCheckedChange={() =>
|
||||
handleCheckboxChange(
|
||||
"lowerManagementEnterprise",
|
||||
)
|
||||
}
|
||||
/>
|
||||
<Label className="cursor-pointer text-label">
|
||||
하수도 서비스 수준
|
||||
</Label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 버튼 */}
|
||||
<div className="mt-6 flex justify-center gap-4 pt-4">
|
||||
<Button
|
||||
color="green"
|
||||
className="h-[3.6rem] w-[120px]"
|
||||
onClick={handleSubmit}
|
||||
>
|
||||
검증 실행
|
||||
</Button>
|
||||
<Button
|
||||
color="gray"
|
||||
className="h-[3.6rem] w-[120px]"
|
||||
onClick={handleReset}
|
||||
>
|
||||
초기화
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* 검증 이력 섹션 */}
|
||||
<div className="mt-8 border-t pt-6">
|
||||
<h3 className="mb-4 px-2 text-[1.5rem] font-semibold">
|
||||
검증 이력
|
||||
</h3>
|
||||
<DataGrid
|
||||
columnInfo={verificationHistoryColumnInfo}
|
||||
rowData={verificationHistoryRowData}
|
||||
setRowData={setVerificationHistoryRowData}
|
||||
isExcelImport={false}
|
||||
isExcelExport={false}
|
||||
showHeaderCheckbox={false}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManagementVerificationRule;
|
||||
@@ -1,7 +1,115 @@
|
||||
import React from "react";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// RealGrid 타입 정의
|
||||
/** setColumns에 전달하는 컬럼 정보 (footer 배열/단일 객체 포함) */
|
||||
export type RealGridColumnInfo = {
|
||||
name: string;
|
||||
fieldName: string;
|
||||
header: { text: string };
|
||||
editable?: boolean;
|
||||
valueType?: import("realgrid").ValueType;
|
||||
dataFormat?: string;
|
||||
styleName?: string;
|
||||
mergeRule?: { criteria: 'value' };
|
||||
footer?: {
|
||||
text?: string;
|
||||
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
|
||||
numberFormat?: string;
|
||||
valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string;
|
||||
} | Array<{
|
||||
text?: string;
|
||||
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
|
||||
numberFormat?: string;
|
||||
valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string;
|
||||
}>;
|
||||
};
|
||||
|
||||
/** setColumns 메서드가 있는 GridView */
|
||||
export type GridViewWithSetColumns = GridView & { setColumns?: (columns: RealGridColumnInfo[]) => void };
|
||||
|
||||
/** footer 배열 요소에 valueCallback 할당용 */
|
||||
export type FooterItemWithCallback = { valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string };
|
||||
|
||||
export type GridView = {
|
||||
getSummary(field: string, summary: 'sum' | 'avg' | 'count' | 'max' | 'min'): number | undefined;
|
||||
getDataSource(): {
|
||||
getRowCount(): number;
|
||||
getValue(rowIndex: number, field: string): number | string;
|
||||
getDataRowId(dataRow: number): number | string;
|
||||
};
|
||||
getDataRow(itemIndex: number): number;
|
||||
};
|
||||
|
||||
export type MergeCallback = (grid: GridView, column: DataColumn, itemIndex: number, value: number | string | null | undefined) => number | null;
|
||||
|
||||
export type DataColumn = {
|
||||
name: string;
|
||||
fieldName: string;
|
||||
};
|
||||
|
||||
export type ColumnFooter = {
|
||||
text?: string;
|
||||
expression?: string;
|
||||
numberFormat?: string;
|
||||
};
|
||||
|
||||
/** 정렬 시 같은 그룹 내에서는 orderByField 순서 유지, 그룹 간에는 정렬 필드로 비교. */
|
||||
export type SortPreserveGroupOrder = {
|
||||
groupField: string;
|
||||
orderByField?: string;
|
||||
};
|
||||
|
||||
/** RealGrid valueCallback 시그니처 (계산 필드용) */
|
||||
export type DataFieldValueCallback = (
|
||||
prod: unknown,
|
||||
dataRow: number,
|
||||
fieldName: string,
|
||||
fieldNames: string[],
|
||||
values: unknown[]
|
||||
) => number | string | undefined;
|
||||
|
||||
/** 계산 필드 설정 (computedFieldCallbacks.ts 참고) */
|
||||
export type ComputedFieldConfig =
|
||||
| { fields: string[]; type: "sum" | "avg" }
|
||||
| { numeratorFields: string[]; denominatorFields: string[]; type: "pblswrgPopltnSuprtRate" }
|
||||
| { numeratorFields: string[]; denominatorFields: string[]; type: "adtrtPopltnSuprtRate" }
|
||||
| { numeratorFields: string[]; denominatorFields: string[]; thirdFields: string[], type: "swrgInstlrtRate" };
|
||||
|
||||
export type ColumnConfig = {
|
||||
name: string;
|
||||
fieldName: string;
|
||||
header: { text: string };
|
||||
/** 계산 필드: fields 합계/평균 등. valueCallback으로 dataProvider.setFields 시 전달 */
|
||||
computed?: ComputedFieldConfig;
|
||||
editable?: boolean; // 셀 편집 가능 여부
|
||||
/** 그리드에서 컬럼 숨김 (수식용 필드 등) */
|
||||
visible?: boolean;
|
||||
/** 셀에 적용할 CSS 클래스명 (예: 'rg-cell-readonly', 'rg-cell-total') */
|
||||
styleName?: string;
|
||||
mergeCells?: boolean;
|
||||
sortdisable?: boolean;
|
||||
sortPreserveGroupOrder?: SortPreserveGroupOrder;
|
||||
valueType?: ValueType;
|
||||
dataFormat?: string;
|
||||
footer?: {
|
||||
text?: string;
|
||||
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
|
||||
numberFormat?: string;
|
||||
valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string;
|
||||
multiRow?: boolean; // 여러 행 footer 사용 여부
|
||||
} | Array<{
|
||||
text?: string;
|
||||
expression?: 'sum' | 'avg' | 'count' | 'max' | 'min';
|
||||
numberFormat?: string;
|
||||
valueCallback?: (grid: GridView, column: DataColumn, footerIndex: number, columnFooter: ColumnFooter, value: number | string | undefined) => number | string;
|
||||
}>, // RealGrid에서 footer를 배열로 설정할 수 있음
|
||||
};
|
||||
|
||||
export type FooterUserSpan = {
|
||||
rowspan?: number; // 병합할 행 수
|
||||
colspan?: number; // 병합할 컬럼 수
|
||||
text?: string; // 표시할 텍스트
|
||||
};
|
||||
|
||||
export type ColumnLayoutItem = string | {
|
||||
@@ -9,6 +117,10 @@ export type ColumnLayoutItem = string | {
|
||||
hideChildHeaders?: boolean;
|
||||
header: { text: string };
|
||||
items: (string | ColumnLayoutItem)[];
|
||||
footerUserSpans?: FooterUserSpan[]; // footer 병합 설정
|
||||
} | {
|
||||
column: string; // 컬럼 이름 (footerUserSpans 사용 시)
|
||||
footerUserSpans?: FooterUserSpan[]; // footer 병합 설정
|
||||
};
|
||||
|
||||
export type ColumnInfo = {
|
||||
@@ -16,11 +128,50 @@ export type ColumnInfo = {
|
||||
columnLayout: ColumnLayoutItem[];
|
||||
};
|
||||
|
||||
export type ColumnInfoList = {
|
||||
tabKey: string; // 탭을 식별하는 고유 키 (필수), server(api)에 전송할 변수 값
|
||||
columns?: ColumnConfig[]; // 일반 그리드용 (isSplitGrid가 false일 때)
|
||||
columnLayout?: ColumnLayoutItem[]; // 일반 그리드용 (isSplitGrid가 false일 때)
|
||||
rowStartNum?: number;
|
||||
fixedColumns?: number;
|
||||
tabLabel?: string; // 탭에 표시될 레이블
|
||||
isSplitGrid?: boolean; // 5:5 분리형 그리드 유무
|
||||
left?: ColumnInfoList; // SplitDataGrid용 왼쪽 그리드 정보
|
||||
right?: ColumnInfoList; // SplitDataGrid용 오른쪽 그리드 정보
|
||||
}
|
||||
|
||||
export type DataGridProps = {
|
||||
columnInfo: ColumnInfo;
|
||||
rows?: Record<string, string>[];
|
||||
rowStartNum?: number; // 헤더 행 개수 (1부터 시작, 예: 2면 1행과 2행까지 헤더로 간주)
|
||||
isExcelImport?: boolean; // 엑셀 가져오기 유무무
|
||||
onRowsChange?: (rows: Record<string, string>[]) => void;
|
||||
isExcelImport?: boolean; // 엑셀 가져오기 유무
|
||||
isExcelExport?: boolean;
|
||||
onRowsChange?: (rows: Record<string, string | number>[]) => void;
|
||||
fixedColumns?: number; // 고정할 컬럼 개수 (좌측부터)
|
||||
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
|
||||
rowData: Record<string, string | number>[];
|
||||
setRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
|
||||
};
|
||||
|
||||
export type TabDataGridProps = {
|
||||
columnInfo: ColumnInfoList[];
|
||||
rows?: Record<string, string | number>[];
|
||||
isExcelImport?: boolean; // 엑셀 가져오기 유무
|
||||
isExcelExport?: boolean;
|
||||
onRowsChange?: (rows: Record<string, string | number>[]) => void;
|
||||
showHeaderCheckbox?: boolean; // 헤더 체크박스 표시 여부 (기본값: true)
|
||||
rowDataMap: Map<string, Record<string, string | number>[]>;
|
||||
setRowDataMap: React.Dispatch<React.SetStateAction<Map<string, Record<string, string | number>[]>>>;
|
||||
isSplitGrid?: boolean; // 5:5 분리형 그리드 유무
|
||||
};
|
||||
|
||||
export type SplitDataGridProps = {
|
||||
leftColumnInfo: ColumnInfo;
|
||||
rightColumnInfo: ColumnInfo;
|
||||
leftFixedColumns?: number;
|
||||
rightFixedColumns?: number;
|
||||
showHeaderCheckbox?: boolean;
|
||||
leftRowData: Record<string, string | number>[];
|
||||
rightRowData: Record<string, string | number>[];
|
||||
setLeftRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
|
||||
setRightRowData: React.Dispatch<React.SetStateAction<Record<string, string | number>[]>>;
|
||||
};
|
||||
@@ -1,26 +1,28 @@
|
||||
export type SearchFormValues = {
|
||||
sido?: string;
|
||||
sgg?: string;
|
||||
gugun?: string;
|
||||
year?: string;
|
||||
order?: string;
|
||||
fctName?: string;
|
||||
bsnmCd?: string;
|
||||
};
|
||||
|
||||
export type SearchFormProps = {
|
||||
sido?: boolean;
|
||||
sgg?: boolean;
|
||||
gugun?: boolean;
|
||||
year?: boolean;
|
||||
order?: boolean;
|
||||
fctName?: boolean;
|
||||
userMenual?: boolean;
|
||||
onSubmit?: (values: SearchFormValues) => void;
|
||||
onReset?: () => void;
|
||||
onValuesChange?: (values: SearchFormValues) => void;
|
||||
defaultValues?: SearchFormValues;
|
||||
};
|
||||
|
||||
export const defaultSearchFormProps: Required<Omit<SearchFormProps, 'onSubmit' | 'onReset' | 'defaultValues'>> = {
|
||||
export const defaultSearchFormProps: Required<Omit<SearchFormProps, 'onSubmit' | 'onReset' | 'onValuesChange' | 'defaultValues'>> = {
|
||||
sido: true,
|
||||
sgg: true,
|
||||
gugun: true,
|
||||
year: true,
|
||||
order: false,
|
||||
fctName: false,
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
/**
|
||||
* 하수도 통계 관리 > 07. 분뇨처리시설
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const ExcretaTreatFactInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'gugun', fieldName: '시군구', header: { text: '시군구' }, footer: { text: '합계' } },
|
||||
|
||||
// 기본 정보
|
||||
{ name: 'ecscs_nm', fieldName: '시설명', header: { text: '시설명' } },
|
||||
{ name: 'locplcs', fieldName: '소재지', header: { text: '소재지' } },
|
||||
{ name: 'telno', fieldName: '전화번호', header: { text: '전화번호' } },
|
||||
|
||||
// 날짜 정보
|
||||
{ name: 'comp_dt', fieldName: '준공일 yyyy-mm-dd', header: { text: '준공일 yyyy-mm-dd' } },
|
||||
{ name: 'rn_dt', fieldName: '가동개시일 yyyy-mm-dd', header: { text: '가동개시일 yyyy-mm-dd' } },
|
||||
|
||||
// 사업비/용량 정보
|
||||
{ name: 'wct', fieldName: '사업비(백만원)', header: { text: '사업비(백만원)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ecscs_cpcty', fieldName: '시설용량(m³/일)', header: { text: '시설용량(m³/일)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'process_cpcty', fieldName: '처리량(m³/일)', header: { text: '처리량(m³/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'opr_daycnt', fieldName: '가동일수(일/년)', header: { text: '가동일수(일/년)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 처리 공법 및 연계
|
||||
{ name: 'trt_msrc', fieldName: '처리공법', header: { text: '처리공법' } },
|
||||
{ name: 'cntc_prcplt', fieldName: '연계처리장명', header: { text: '연계처리장명' } },
|
||||
{ name: 'assct_trt_cpc', fieldName: '연계처리량(m³/일)', header: { text: '연계처리량(m³/일)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 유입수질
|
||||
{ name: 'infl_wqlt_bod', fieldName: 'BOD', header: { text: 'BOD' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'infl_wqlt_toc', fieldName: 'TOC', header: { text: 'TOC' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'infl_wqlt_ss', fieldName: 'SS', header: { text: 'SS' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'infl_wqlt_tn', fieldName: 'T-N', header: { text: 'T-N' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'infl_wqlt_tp', fieldName: 'T-P', header: { text: 'T-P' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'infl_wqlt_clfgrpcnt', fieldName: '대장균군수', header: { text: '대장균군수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 방류수질
|
||||
{ name: 'effl_wqlt_bod', fieldName: 'BOD', header: { text: 'BOD' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'effl_wqlt_toc', fieldName: 'TOC', header: { text: 'TOC' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'effl_wqlt_ss', fieldName: 'SS', header: { text: 'SS' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'effl_wqlt_tn', fieldName: 'T-N', header: { text: 'T-N' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'effl_wqlt_tp', fieldName: 'T-P', header: { text: 'T-P' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'effl_wqlt_clfgrpcnt', fieldName: '대장균군수', header: { text: '대장균군수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 방류수역
|
||||
{ name: 'rvbsn', fieldName: '수계', header: { text: '수계' } },
|
||||
{ name: 'bstrm', fieldName: '지류', header: { text: '지류' } },
|
||||
{ name: 'lgbsn', fieldName: '중권역', header: { text: '중권역' } },
|
||||
{ name: 'mdmbsn', fieldName: '소권역', header: { text: '소권역' } },
|
||||
|
||||
// 운영 정보
|
||||
{ name: 'oper_mth', fieldName: '운영주체(자체/공기업/민간위탁)', header: { text: '운영주체(자체/공기업/민간위탁)' } },
|
||||
{ name: 'cntc_prcplt_cpc', fieldName: '직원총수(명)', header: { text: '직원총수(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'safe_acdnt_co', fieldName: '안전사고건수(건/인/년)', header: { text: '안전사고건수(건/인/년)' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'rmk', fieldName: '비고', header: { text: '비고' } },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'adminGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: ['sido', 'gugun'],
|
||||
},
|
||||
'ecscs_nm',
|
||||
'locplcs',
|
||||
'telno',
|
||||
'comp_dt',
|
||||
'rn_dt',
|
||||
'wct',
|
||||
'ecscs_cpcty',
|
||||
'process_cpcty',
|
||||
'opr_daycnt',
|
||||
'trt_msrc',
|
||||
'cntc_prcplt',
|
||||
'assct_trt_cpc',
|
||||
{
|
||||
name: 'influenceGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '유입수질(mg/L, 개/mL)' },
|
||||
items: ['infl_wqlt_bod', 'infl_wqlt_toc', 'infl_wqlt_ss', 'infl_wqlt_tn', 'infl_wqlt_tp', 'infl_wqlt_clfgrpcnt'],
|
||||
},
|
||||
{
|
||||
name: 'effluentGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '방류수질(mg/L, 개/mL)' },
|
||||
items: ['effl_wqlt_bod', 'effl_wqlt_toc', 'effl_wqlt_ss', 'effl_wqlt_tn', 'effl_wqlt_tp', 'effl_wqlt_clfgrpcnt'],
|
||||
},
|
||||
{
|
||||
name: 'dischargeGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '방류수역' },
|
||||
items: ['rvbsn', 'bstrm', 'lgbsn', 'mdmbsn'],
|
||||
},
|
||||
'oper_mth',
|
||||
'cntc_prcplt_cpc',
|
||||
'safe_acdnt_co',
|
||||
'rmk',
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,211 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
/**
|
||||
* 하수도 통계 관리 > 06. 공공하수처리시설
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const PublicSewageFactInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'sidoCd', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'gugun', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 시설명
|
||||
{ name: 'bscFctNm', fieldName: '시설명(500m³/일 이상/미만)', header: { text: '시설명(500m³/일 이상/미만)' }, editable: false },
|
||||
|
||||
// 소재지
|
||||
{ name: 'addr', fieldName: '소재지', header: { text: '소재지' }, editable: false },
|
||||
|
||||
// 시설용량
|
||||
{ name: 'fctCpc', fieldName: '시설용량(500m³/일 이상/미만)', header: { text: '시설용량(500m³/일 이상/미만)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// (m³/일)
|
||||
{ name: 'fctCpc1', fieldName: '물리적', header: { text: '물리적' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'fctCpc2', fieldName: '생물학적', header: { text: '생물학적' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'fctCpc3', fieldName: '고도', header: { text: '고도' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 유입하수량
|
||||
{ name: 'totInflAmntAve', fieldName: '유입하수량(500m³/일 이상/미만)', header: { text: '유입하수량(500m³/일 이상/미만)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// (m³/일)
|
||||
{ name: 'pInflAmntAve', fieldName: '물리적', header: { text: '물리적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'oInflAmntAve', fieldName: '생물학적', header: { text: '생물학적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'aInflAmntAve', fieldName: '고도', header: { text: '고도' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 방류량
|
||||
{ name: 'totTputAve', fieldName: '방류량(500m³/일 이상/미만)', header: { text: '방류량(500m³/일 이상/미만)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 방류량 - (m³/일)
|
||||
{ name: 'pTputAve', fieldName: '물리적', header: { text: '물리적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'oTputAve', fieldName: '생물학적', header: { text: '생물학적' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'aTputAve', fieldName: '고도', header: { text: '고도' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 수질
|
||||
{ name: 'inflAssctBfrWqltBod', fieldName: '유입BOD', header: { text: '유입BOD' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'efflWqltBod', fieldName: '방류BOD', header: { text: '방류BOD' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'inflAssctBfrWqltToc', fieldName: '유입TOC', header: { text: '유입TOC' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'efflWqltToc', fieldName: '방류TOC', header: { text: '방류TOC' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'inflAssctBfrWqltSs', fieldName: '유입SS', header: { text: '유입SS' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'efflWqltSs', fieldName: '방류SS', header: { text: '방류SS' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'inflAssctBfrWqltTn', fieldName: '유입T-N', header: { text: '유입T-N' }, editable: false, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'efflWqltTn', fieldName: '방류T-N', header: { text: '방류T-N' }, editable: false, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflAssctBfrWqltTp', fieldName: '유입T-P', header: { text: '유입T-P' }, editable: false, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'efflWqltTp', fieldName: '방류T-P', header: { text: '방류T-P' }, editable: false, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
{ name: 'inflAssctBfrWqltClfgrpcnt', fieldName: '유입총대장균군수', header: { text: '유입총대장균군수' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'efflWqltClfgrpcnt', fieldName: '방류총대장균군수', header: { text: '방류총대장균군수' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 처리특성
|
||||
{ name: 'tmEfficiency', fieldName: '처리효율(%)', header: { text: '처리효율(%)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'pcLoad', fieldName: '처리부하량(kgBOD/D)', header: { text: '처리부하량(kgBOD/D)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'trtFrfHanNm', fieldName: '처리방법', header: { text: '처리방법' }, editable: false },
|
||||
|
||||
// 연계처리량
|
||||
{ name: 'excretionsTot', fieldName: '분뇨', header: { text: '분뇨' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'stkrsngWstwtrTot', fieldName: '축산', header: { text: '축산' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'lchtTot', fieldName: '침출수', header: { text: '침출수' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'etcTot', fieldName: '기타', header: { text: '기타' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 시설정보
|
||||
{ name: 'tel', fieldName: '전화번호', header: { text: '전화번호' }, editable: false },
|
||||
{ name: 'rnDt', fieldName: '준공일', header: { text: '준공일' }, editable: false },
|
||||
{ name: 'compDt', fieldName: '가동개시일', header: { text: '가동개시일' }, editable: false },
|
||||
{ name: 'tot', fieldName: '사업비', header: { text: '사업비' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 방류수 소독방법
|
||||
{ name: 'dsfctNm', fieldName: '방류수 소독방법', header: { text: '방류수 소독방법' }, editable: false },
|
||||
|
||||
// 방류수역
|
||||
{ name: 'wbsnNm', fieldName: '수계', header: { text: '수계' }, editable: false },
|
||||
{ name: 'rvNm', fieldName: '지류', header: { text: '지류' }, editable: false },
|
||||
{ name: 'mdmbsn', fieldName: '세부단위구역', header: { text: '세부단위구역' }, editable: false },
|
||||
{ name: 'efflWqltStndrdNm', fieldName: '지역구분', header: { text: '지역구분' }, editable: false },
|
||||
|
||||
// 방류수역 > 중권역
|
||||
{ name: 'lgbsn', fieldName: '명칭', header: { text: '명칭' }, editable: false },
|
||||
{ name: 'lgbsnBod', fieldName: '목표수질(BOD)', header: { text: '목표수질(BOD)' }, editable: false },
|
||||
|
||||
// 에너지 자립률
|
||||
{ name: 'toeRt', fieldName: '에너지자립률(%)', header: { text: '에너지자립률(%)' }, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 에너지 자체 생산량
|
||||
{ name: 'useQnty', fieldName: '에너지자체생산량(TOE)', header: { text: '에너지자체생산량(TOE)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 연간 총 에너지 사용량
|
||||
{ name: 'toeSum', fieldName: '계(TOE)', header: { text: '계(TOE)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'elcpwAmnt', fieldName: '총 전력사용량(kWh)', header: { text: '총 전력사용량(kWh)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'toeQnty', fieldName: '자체 에너지사용량(TOE)', header: { text: '자체 에너지사용량(TOE)' }, editable: false, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 하수처리량당 CO2배출량
|
||||
{ name: 'co2Emissions', fieldName: '하수처리량당 CO2배출량(kgCO2/m³)', header: { text: '하수처리량당 CO2배출량(kgCO2/m³)' }, editable: false, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 운영주체
|
||||
{ name: 'oprClsNm', fieldName: '운영주체(자체/공기업/민간대행)', header: { text: '운영주체(자체/공기업/민간대행)' }, editable: false },
|
||||
|
||||
// 위탁현황
|
||||
{ name: 'trstOprEtpNm', fieldName: '위탁업체명', header: { text: '위탁업체명' } },
|
||||
{ name: 'yrstpTrstCst', fieldName: '위탁비용(백만원/년)', header: { text: '위탁비용(백만원/년)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'trstOprDt', fieldName: '위탁계약기간(yyyy-mm-dd~yyyy-mm-dd)', header: { text: '위탁계약기간(yyyy-mm-dd~yyyy-mm-dd)' } },
|
||||
|
||||
// 기타
|
||||
{ name: 'cntrTrtFctNm', fieldName: '중심처리시설', header: { text: '중심처리시설' } },
|
||||
{ name: 'totWtrQrm', fieldName: '직원총수(명)', header: { text: '직원총수(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'safeAcdntCo', fieldName: '안전사고건수', header: { text: '안전사고건수' }, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rmk', fieldName: '비고', header: { text: '비고' } },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'administrative',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: ['sidoCd', 'gugun'],
|
||||
},
|
||||
'bscFctNm',
|
||||
'addr',
|
||||
'fctCpc',
|
||||
{
|
||||
name: 'facilityCapacityDetail',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(m³/일)' },
|
||||
items: ['fctCpc1', 'fctCpc2', 'fctCpc3'],
|
||||
},
|
||||
'totInflAmntAve',
|
||||
{
|
||||
name: 'influentWaterDetail',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(m³/일)' },
|
||||
items: ['pInflAmntAve', 'oInflAmntAve', 'aInflAmntAve'],
|
||||
},
|
||||
'totTputAve',
|
||||
{
|
||||
name: 'effluentWaterDetail',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '(m³/일)' },
|
||||
items: ['pTputAve', 'oTputAve', 'aTputAve'],
|
||||
},
|
||||
'inflAssctBfrWqltBod',
|
||||
'efflWqltBod',
|
||||
'inflAssctBfrWqltToc',
|
||||
'efflWqltToc',
|
||||
'inflAssctBfrWqltSs',
|
||||
'efflWqltSs',
|
||||
'inflAssctBfrWqltTn',
|
||||
'efflWqltTn',
|
||||
'inflAssctBfrWqltTp',
|
||||
'efflWqltTp',
|
||||
'inflAssctBfrWqltClfgrpcnt',
|
||||
'efflWqltClfgrpcnt',
|
||||
'tmEfficiency',
|
||||
'pcLoad',
|
||||
'trtFrfHanNm',
|
||||
{
|
||||
name: 'linkedTreatment',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '연계처리량(m³/일) (500m³/일 이상/미만)' },
|
||||
items: ['excretionsTot', 'stkrsngWstwtrTot', 'lchtTot', 'etcTot'],
|
||||
},
|
||||
'tel',
|
||||
'rnDt',
|
||||
'compDt',
|
||||
'tot',
|
||||
'dsfctNm',
|
||||
{
|
||||
name: 'dischargeArea',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '방류수역' },
|
||||
items: [
|
||||
'wbsnNm',
|
||||
'rvNm',
|
||||
'mdmbsn',
|
||||
'efflWqltStndrdNm',
|
||||
{
|
||||
name: 'mediumWatershed',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '중권역' },
|
||||
items: ['lgbsn', 'lgbsnBod'],
|
||||
},
|
||||
],
|
||||
},
|
||||
'toeRt',
|
||||
'useQnty',
|
||||
{
|
||||
name: 'energy',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '연간 총 에너지 사용량(TOE)' },
|
||||
items: ['toeSum', 'elcpwAmnt', 'toeQnty'],
|
||||
},
|
||||
'co2Emissions',
|
||||
'oprClsNm',
|
||||
{
|
||||
name: 'consignmentStatus',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '위탁현황' },
|
||||
items: ['trstOprEtpNm', 'yrstpTrstCst', 'trstOprDt'],
|
||||
},
|
||||
'cntrTrtFctNm',
|
||||
'totWtrQrm',
|
||||
'safeAcdntCo',
|
||||
'rmk',
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,143 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
/**
|
||||
* 하수도 통계 관리 > 05. 펌프장
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const PumpingStationInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' }, footer: { text: '합계' } },
|
||||
|
||||
// 기본 정보
|
||||
{ name: 'treatmentFacilityName', fieldName: '처리장명', header: { text: '처리장명' } },
|
||||
{ name: 'facilityName', fieldName: '시설명', header: { text: '시설명' } },
|
||||
{ name: 'classification', fieldName: '구분(합류식 분류식)', header: { text: '구분(합류식 분류식)' } },
|
||||
{ name: 'location', fieldName: '위치', header: { text: '위치' } },
|
||||
{ name: 'operationDate', fieldName: '가동 년월일 yyyy-mm-dd', header: { text: '가동 년월일 yyyy-mm-dd' } },
|
||||
{ name: 'planDrainageArea', fieldName: '계획배수면적(㎢)', header: { text: '계획배수면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 계획시간 대 최대배수량
|
||||
{ name: 'fairWeatherFlow', fieldName: '청천시(A)', header: { text: '청천시(A)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'rainyWeatherFlow', fieldName: '우천시(B)', header: { text: '우천시(B)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'rainwaterFlow', fieldName: '우수량(B-A)', header: { text: '우수량(B-A)' }, footer: footerDecimal1, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 배수능력 > 총 양수량 (오수)
|
||||
{ name: 'sewageTotalPumpCapacity', fieldName: '총양수량(m³/min)', header: { text: '총양수량(m³/min)' }, footer: footerDecimal1, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 배수능력 > 오수펌프(1)
|
||||
{ name: 'sewagePump1Diameter', fieldName: '오수펌프(1) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump1Capacity', fieldName: '오수펌프(1) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'sewagePump1Count', fieldName: '오수펌프(1) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump1Reserve', fieldName: '오수펌프(1) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 배수능력 > 오수펌프(2)
|
||||
{ name: 'sewagePump2Diameter', fieldName: '오수펌프(2) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump2Capacity', fieldName: '오수펌프(2) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'sewagePump2Count', fieldName: '오수펌프(2) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump2Reserve', fieldName: '오수펌프(2) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 배수능력 > 오수펌프(3)
|
||||
{ name: 'sewagePump3Diameter', fieldName: '오수펌프(3) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump3Capacity', fieldName: '오수펌프(3) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'sewagePump3Count', fieldName: '오수펌프(3) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'sewagePump3Reserve', fieldName: '오수펌프(3) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 배수능력 > 총 양수량 (우수)
|
||||
{ name: 'rainwaterTotalPumpCapacity', fieldName: '총양수량(m³/min)', header: { text: '총양수량(m³/min)' }, footer: footerDecimal1, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 배수능력 > 우수펌프(1)
|
||||
{ name: 'rainwaterPump1Diameter', fieldName: '우수펌프(1) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump1Capacity', fieldName: '우수펌프(1) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'rainwaterPump1Count', fieldName: '우수펌프(1) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump1Reserve', fieldName: '우수펌프(1) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 배수능력 > 우수펌프(2)
|
||||
{ name: 'rainwaterPump2Diameter', fieldName: '우수펌프(2) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump2Capacity', fieldName: '우수펌프(2) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'rainwaterPump2Count', fieldName: '우수펌프(2) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump2Reserve', fieldName: '우수펌프(2) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 배수능력 > 우수펌프(3)
|
||||
{ name: 'rainwaterPump3Diameter', fieldName: '우수펌프(3) 구경(mm)', header: { text: '구경(mm)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump3Capacity', fieldName: '우수펌프(3) 대당 양수량(m³/min·대)', header: { text: '대당 양수량(m³/min·대)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'rainwaterPump3Count', fieldName: '우수펌프(3) 펌프대수', header: { text: '펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'rainwaterPump3Reserve', fieldName: '우수펌프(3) 예비펌프대수', header: { text: '예비펌프대수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 연간전력 사용량
|
||||
{ name: 'annualPowerUsage', fieldName: '연간전력사용량(kWh/년)', header: { text: '연간전력사용량(kWh/년)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'remarks', fieldName: '비고', header: { text: '비고' } },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'administrativeArea',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: ['sido', 'sgg'],
|
||||
},
|
||||
'treatmentFacilityName',
|
||||
'facilityName',
|
||||
'classification',
|
||||
'location',
|
||||
'operationDate',
|
||||
'planDrainageArea',
|
||||
{
|
||||
name: 'planFlowGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '계획시간대최대배수량(m³/hr)' },
|
||||
items: ['fairWeatherFlow', 'rainyWeatherFlow', 'rainwaterFlow'],
|
||||
},
|
||||
{
|
||||
name: 'drainageCapability',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '배수능력' },
|
||||
items: [
|
||||
'sewageTotalPumpCapacity',
|
||||
{
|
||||
name: 'sewagePump1Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '오수펌프(1)' },
|
||||
items: ['sewagePump1Diameter', 'sewagePump1Capacity', 'sewagePump1Count', 'sewagePump1Reserve'],
|
||||
},
|
||||
{
|
||||
name: 'sewagePump2Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '오수펌프(2)' },
|
||||
items: ['sewagePump2Diameter', 'sewagePump2Capacity', 'sewagePump2Count', 'sewagePump2Reserve'],
|
||||
},
|
||||
{
|
||||
name: 'sewagePump3Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '오수펌프(3)' },
|
||||
items: ['sewagePump3Diameter', 'sewagePump3Capacity', 'sewagePump3Count', 'sewagePump3Reserve'],
|
||||
},
|
||||
'rainwaterTotalPumpCapacity',
|
||||
{
|
||||
name: 'rainwaterPump1Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '우수펌프(1)' },
|
||||
items: ['rainwaterPump1Diameter', 'rainwaterPump1Capacity', 'rainwaterPump1Count', 'rainwaterPump1Reserve'],
|
||||
},
|
||||
{
|
||||
name: 'rainwaterPump2Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '우수펌프(2)' },
|
||||
items: ['rainwaterPump2Diameter', 'rainwaterPump2Capacity', 'rainwaterPump2Count', 'rainwaterPump2Reserve'],
|
||||
},
|
||||
{
|
||||
name: 'rainwaterPump3Group',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '우수펌프(3)' },
|
||||
items: ['rainwaterPump3Diameter', 'rainwaterPump3Capacity', 'rainwaterPump3Count', 'rainwaterPump3Reserve'],
|
||||
},
|
||||
],
|
||||
},
|
||||
'annualPowerUsage',
|
||||
'remarks',
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,244 @@
|
||||
import { footerInt, footerDecimal1, footerDecimal3, footerAvgDecimal } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
/**
|
||||
* 하수도 통계 관리 > 01. 하수도 보급률
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const SeweragePenetrationRateInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'sido', fieldName: 'sido', header: { text: '시도' }, footer: { text: '합계' }, editable: false },
|
||||
{ name: 'gugun', fieldName: 'gugun', header: { text: '시군구' }, editable: false },
|
||||
{ name: 'adstDong', fieldName: 'adstDong', header: { text: '행정구역명' }, editable: false },
|
||||
|
||||
// 수계 및 권역
|
||||
{ name: 'rvbsn', fieldName: 'rvbsn', header: { text: '수계' }, editable: false },
|
||||
{ name: 'bstrm', fieldName: 'bstrm', header: { text: '지류' } },
|
||||
|
||||
// 수계영향권별분류
|
||||
{ name: 'mdbsn', fieldName: 'mdbsn', header: { text: '세부단위유역' }, editable: false },
|
||||
{ name: 'lgbsn', fieldName: 'lgbsn', header: { text: '중권역' }, editable: false },
|
||||
{ name: 'mdmbsn', fieldName: 'mdmbsn', header: { text: '소권역' }, editable: false },
|
||||
|
||||
// 특별대책지역
|
||||
{ name: 'speclCntrplnAr', fieldName: 'speclCntrplnAr', header: { text: '특별대책지역' } },
|
||||
|
||||
// 행정참고자료인구
|
||||
{ name: 'totalPopl', fieldName: 'totalPopl', header: { text: '총인구' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'poplSm', fieldName: 'poplSm', header: { text: '내국인' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'frgnrPoplSm', fieldName: 'frgnrPoplSm', header: { text: '외국인' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 행정참고자료면적
|
||||
{ name: 'area', fieldName: 'area', header: { text: '행정참고자료면적(㎢)' }, footer: footerDecimal3, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 총인구
|
||||
{ name: 'popltnSm', fieldName: 'popltnSm', header: { text: '총인구(명)' }, footer: footerInt, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 총면적
|
||||
{
|
||||
name: 'arSm',
|
||||
fieldName: 'arSm',
|
||||
header: { text: '총면적(㎢)' },
|
||||
footer: footerDecimal3,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.000',
|
||||
computed: { fields: ['swgeProcZoneInnerAr', 'swgeProcZoneOuterAr'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 하수처리구역 내 > 합계
|
||||
{
|
||||
name: 'swgeProcZoneInnerSm',
|
||||
fieldName: 'swgeProcZoneInnerSm',
|
||||
header: { text: '합계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 하수처리구역 내 > 공공하수처리인구
|
||||
{
|
||||
name: 'pblswrgPopltnSm',
|
||||
fieldName: 'pblswrgPopltnSm',
|
||||
header: { text: '소계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'pblswrgPrmTrt', fieldName: 'pblswrgPrmTrt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'pblswrgScdTrt', fieldName: 'pblswrgScdTrt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'pblswrgTertTrt', fieldName: 'pblswrgTertTrt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 폐수처리인구
|
||||
{
|
||||
name: 'wstrPopltnSm',
|
||||
fieldName: 'wstrPopltnSm',
|
||||
header: { text: '소계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'wstrPrmTrt', fieldName: 'wstrPrmTrt', header: { text: '물리적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wstrScdTrt', fieldName: 'wstrScdTrt', header: { text: '생물학적처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'wstrTertTrt', fieldName: 'wstrTertTrt', header: { text: '고도처리' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 미접속인구
|
||||
{ name: 'notConectPopltn', fieldName: 'notConectPopltn', header: { text: '미접속인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 면적
|
||||
{ name: 'swgeProcZoneInnerAr', fieldName: 'swgeProcZoneInnerAr', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 하수처리구역 외
|
||||
{
|
||||
name: 'swgeProcZoneOuterSm',
|
||||
fieldName: 'swgeProcZoneOuterSm',
|
||||
header: { text: '합계' },
|
||||
footer: footerInt,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0',
|
||||
computed: { fields: ['townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'], type: 'sum' as const },
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
{ name: 'townUnprocPopltn', fieldName: 'townUnprocPopltn', header: { text: '미처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'townSwttPopltn', fieldName: 'townSwttPopltn', header: { text: '오수처리인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'townWrrtnPopltn', fieldName: 'townWrrtnPopltn', header: { text: '정화조인구' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'swgeProcZoneOuterAr', fieldName: 'swgeProcZoneOuterAr', header: { text: '면적(㎢)' }, footer: footerDecimal3, valueType: ValueType.NUMBER, dataFormat: '#,##0.000' },
|
||||
|
||||
// 공공하수처리구역 인구보급률 (하수처리구역 내 인구 / 전체 인구 * 100)
|
||||
{
|
||||
name: 'pblswrgPopltnSuprt',
|
||||
fieldName: 'pblswrgPopltnSuprt',
|
||||
header: { text: '공공하수처리구역인구보급률(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'],
|
||||
type: 'pblswrgPopltnSuprtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 고도처리 인구보급률 (고도처리 인구 / 전체 인구 * 100)
|
||||
{
|
||||
name: 'adtrtPopltnSuprt',
|
||||
fieldName: 'adtrtPopltnSuprt',
|
||||
header: { text: '고도처리인구보급률(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgTertTrt', 'wstrTertTrt'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'townUnprocPopltn', 'townSwttPopltn', 'townWrrtnPopltn'],
|
||||
type: 'adtrtPopltnSuprtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 하수도 설치율
|
||||
{
|
||||
name: 'swrgInstlrt',
|
||||
fieldName: 'swrgInstlrt',
|
||||
header: { text: '하수도설치율(%)' },
|
||||
footer: footerAvgDecimal,
|
||||
editable: false,
|
||||
valueType: ValueType.NUMBER,
|
||||
dataFormat: '#,##0.0',
|
||||
computed: {
|
||||
numeratorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn', 'swgeProcZoneOuterSm'],
|
||||
denominatorFields: ['pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt', 'notConectPopltn'],
|
||||
thirdFields: ['piplSupprt'],
|
||||
type: 'swrgInstlrtRate' as const
|
||||
},
|
||||
styleName: 'rg-cell-total',
|
||||
},
|
||||
|
||||
// 비고
|
||||
{ name: 'rmk', fieldName: 'rmk', header: { text: '비고' } },
|
||||
|
||||
{ name: 'piplSupprt', fieldName: 'piplSupprt', header: { text: '하수관로보급률(%)' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정구역' },
|
||||
items: [
|
||||
{ column: 'sido', footerUserSpans: [{ colspan: 3 }] },
|
||||
'gugun',
|
||||
'adstDong',
|
||||
],
|
||||
},
|
||||
'rvbsn',
|
||||
'bstrm',
|
||||
{
|
||||
name: 'groupB',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '수계영향권별분류' },
|
||||
items: ['mdbsn', 'lgbsn', 'mdmbsn'],
|
||||
},
|
||||
'speclCntrplnAr',
|
||||
{
|
||||
name: 'groupC',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '행정참고자료인구' },
|
||||
items: ['totalPopl', 'poplSm', 'frgnrPoplSm'],
|
||||
},
|
||||
'area',
|
||||
'popltnSm',
|
||||
'arSm',
|
||||
{
|
||||
name: 'groupD',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수처리구역내' },
|
||||
items: [
|
||||
'swgeProcZoneInnerSm',
|
||||
{
|
||||
name: 'pblswrgGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '공공하수처리인구(명)' },
|
||||
items: ['pblswrgPopltnSm', 'pblswrgPrmTrt', 'pblswrgScdTrt', 'pblswrgTertTrt'],
|
||||
},
|
||||
{
|
||||
name: 'wstrGroup',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '폐수처리인구(명)' },
|
||||
items: ['wstrPopltnSm', 'wstrPrmTrt', 'wstrScdTrt', 'wstrTertTrt'],
|
||||
},
|
||||
'notConectPopltn',
|
||||
'swgeProcZoneInnerAr'
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'groupE',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수처리구역외' },
|
||||
items: [
|
||||
'swgeProcZoneOuterSm',
|
||||
'townUnprocPopltn',
|
||||
'townSwttPopltn',
|
||||
'townWrrtnPopltn',
|
||||
'swgeProcZoneOuterAr'
|
||||
],
|
||||
},
|
||||
'pblswrgPopltnSuprt',
|
||||
'adtrtPopltnSuprt',
|
||||
'swrgInstlrt',
|
||||
'rmk',
|
||||
'piplSupprt',
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,46 @@
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
/**
|
||||
* 하수도 통계 관리 > 00. 통계 입력 현황
|
||||
* 단일 Tab
|
||||
*/
|
||||
export const StatsInputStatusInpColumn = {
|
||||
columns: [
|
||||
{ name: 'sido', fieldName: '시도', header: { text: '시도' } },
|
||||
{ name: 'sgg', fieldName: '시군구', header: { text: '시군구' } },
|
||||
{ name: 'menu_nm', fieldName: '구분', header: { text: '구분' } },
|
||||
{ name: 'locg_status_nm', fieldName: '진행상황', header: { text: '진행상황' } },
|
||||
{ name: 'locg_status', fieldName: '작성률', header: { text: '작성률' }, valueType: ValueType.NUMBER },
|
||||
{ name: 'locg_charger', fieldName: '작성자', header: { text: '작성자' } },
|
||||
{ name: 'locg_cttpc', fieldName: '작성자연락처', header: { text: '작성자연락처' } },
|
||||
{ name: 'locg_dept', fieldName: '부서', header: { text: '부서' } },
|
||||
{ name: 'locg_job', fieldName: '직제', header: { text: '직제' } },
|
||||
{ name: 'locg_cnfirm_nm', fieldName: '승인자', header: { text: '승인자' } },
|
||||
{ name: 'locg_cnfirm_dept', fieldName: '부서', header: { text: '부서' } },
|
||||
{ name: 'locg_cnfirm_job', fieldName: '직제', header: { text: '직제' } },
|
||||
{ name: 'return_opinion_sm', fieldName: '반려사유', header: { text: '반려사유' } },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
'sido',
|
||||
'sgg',
|
||||
'menu_nm',
|
||||
{
|
||||
name: 'groupA',
|
||||
hideChildHeaders: false,
|
||||
header: { text: '하수도사업자' },
|
||||
items: [
|
||||
'locg_status_nm',
|
||||
'locg_status',
|
||||
'locg_charger',
|
||||
'locg_cttpc',
|
||||
'locg_dept',
|
||||
'locg_job',
|
||||
'locg_cnfirm_nm',
|
||||
'locg_cnfirm_dept',
|
||||
'locg_cnfirm_job',
|
||||
'return_opinion_sm'
|
||||
],
|
||||
},
|
||||
]
|
||||
};
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
import { footerInt, footerDecimal1 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 08.개인하수처리시설 > tab 3. 개인하수도 관리지역 지정공고현황
|
||||
export const PrivateSewageDesigStatusInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 개인하수도관리지역공고현황
|
||||
{ name: 'MGMT_AR', fieldName: '공고지역(개소)', header: { text: '공고지역(개소)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'APPN_SCOPE', fieldName: '지정범위(㎢)', header: { text: '지정범위(㎢)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 개인하수도관리지역공고현황 > 정화조
|
||||
{ name: 'STTY_CNT', fieldName: '개소수', header: { text: '개소수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_CPC', fieldName: '처리용량(인/일)', header: { text: '처리용량(인/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 개인하수도관리지역공고현황 > 오수시설
|
||||
{ name: 'WRRTN_CNT', fieldName: '개소수', header: { text: '개소수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'WRRTN_CPC', fieldName: '처리용량(m³/일)', header: { text: '처리용량(m³/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// 검증 필드 (hidden)
|
||||
{ name: 'CHK_MGMT_AR', fieldName: 'CHK_MGMT_AR', header: { text: '' } },
|
||||
{ name: 'CHK_APPN_SCOPE', fieldName: 'CHK_APPN_SCOPE', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_CNT', fieldName: 'CHK_STTY_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_CPC', fieldName: 'CHK_STTY_CPC', header: { text: '' } },
|
||||
{ name: 'CHK_WRRTN_CNT', fieldName: 'CHK_WRRTN_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_WRRTN_CPC', fieldName: 'CHK_WRRTN_CPC', header: { text: '' } },
|
||||
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' } },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' } },
|
||||
],
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
{
|
||||
name: 'group_notice',
|
||||
header: { text: '개인하수도관리지역공고현황 (하수도법제34조의2)' },
|
||||
items: [
|
||||
'MGMT_AR',
|
||||
'APPN_SCOPE',
|
||||
{
|
||||
name: 'group_septic',
|
||||
header: { text: '정화조' },
|
||||
items: [
|
||||
'STTY_CNT',
|
||||
'STTY_CPC'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'group_sewage',
|
||||
header: { text: '오수시설' },
|
||||
items: [
|
||||
'WRRTN_CNT',
|
||||
'WRRTN_CPC'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'RMK'
|
||||
],
|
||||
rowStartNum: 3,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'privateSewageDesigStatusInp',
|
||||
tabLabel: '개인하수도 관리지역 지정공고 현황'
|
||||
};
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 08.개인하수처리시설 > tab 2. 정화조 현황
|
||||
export const SepticTankStatusInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 총 시설 수
|
||||
{ name: 'TOT_FCLTY_CNT', fieldName: '총 시설 수 (A+D)', header: { text: '총 시설 수 (A+D)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 총계
|
||||
{ name: 'SPZI_SM', fieldName: '총계 A=(B+C)/2', header: { text: '총계 A=(B+C)/2' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 처리방식별
|
||||
{ name: 'SPZI_MTHD_SM', fieldName: '계(B)', header: { text: '계(B)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 처리방식별 > 부패탱크
|
||||
{ name: 'SPZI_ROT_NPFL_CNT', fieldName: '자연유하', header: { text: '자연유하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_ROT_ENFCT_PUMP_1', fieldName: '강제펌핑식', header: { text: '강제펌핑식' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 처리방식별
|
||||
{ name: 'SPZI_WTROT_NPFL_CNT', fieldName: '살수여상', header: { text: '살수여상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_TFM', fieldName: '폭기방법', header: { text: '폭기방법' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_ARTM', fieldName: '접촉폭기', header: { text: '접촉폭기' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_CTARM', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 내 > 처리용량별
|
||||
{ name: 'SPZI_PROC_CPC_SM', fieldName: '계(C)', header: { text: '계(C)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_1', fieldName: '10인조이하', header: { text: '10인조이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_2', fieldName: '11~20', header: { text: '11~20' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_3', fieldName: '21~30', header: { text: '21~30' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_4', fieldName: '31~50', header: { text: '31~50' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_5', fieldName: '51~199', header: { text: '51~199' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_6', fieldName: '200~499', header: { text: '200~499' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_7', fieldName: '500~999', header: { text: '500~999' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZI_PROC_CPC_8', fieldName: '1,000 이상', header: { text: '1,000 이상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 외 > 총계
|
||||
{ name: 'SPZO_SM', fieldName: '총계 D=(E+F)/2', header: { text: '총계 D=(E+F)/2' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 외 > 처리방식별
|
||||
{ name: 'SPZO_MTHD_SM', fieldName: '계(E)', header: { text: '계(E)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 외 > 처리방식별 > 부패탱크
|
||||
{ name: 'SPZO_ROT_NPFL_CNT', fieldName: '자연유하', header: { text: '자연유하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_ROT_ENFCT_PUMP_1', fieldName: '강제펌핑식', header: { text: '강제펌핑식' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 외 > 처리방식별
|
||||
{ name: 'SPZO_WTROT_NPFL_CNT', fieldName: '살수여상', header: { text: '살수여상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_TFM', fieldName: '폭기방법', header: { text: '폭기방법' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_ARTM', fieldName: '접촉폭기', header: { text: '접촉폭기' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_CTARM', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 하수처리구역 외 > 처리용량별
|
||||
{ name: 'SPZO_PROC_CPC_SM', fieldName: '계(F)', header: { text: '계(F)' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_1', fieldName: '10인조이하', header: { text: '10인조이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_2', fieldName: '11~20', header: { text: '11~20' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_3', fieldName: '21~30', header: { text: '21~30' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_4', fieldName: '31~50', header: { text: '31~50' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_5', fieldName: '51~199', header: { text: '51~199' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_6', fieldName: '200~499', header: { text: '200~499' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_7', fieldName: '500~999', header: { text: '500~999' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'SPZO_PROC_CPC_8', fieldName: '1,000 이상', header: { text: '1,000 이상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// hidden
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' } },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' } },
|
||||
|
||||
// 검증 필드 (검증 여부 표시용 - 빨간색 표시)
|
||||
{ name: 'CHK_TOT_FCLTY_CNT', fieldName: 'CHK_TOT_FCLTY_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_SM', fieldName: 'CHK_SPZI_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_MTHD_SM', fieldName: 'CHK_SPZI_MTHD_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ROT_NPFL_CNT', fieldName: 'CHK_SPZI_ROT_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ROT_ENFCT_PUMP_1', fieldName: 'CHK_SPZI_ROT_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ROT_ENFCT_PUMP_2', fieldName: 'CHK_SPZI_ROT_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ROT_ENFCT_PUMP_3', fieldName: 'CHK_SPZI_ROT_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ROT_TANK_SM', fieldName: 'CHK_SPZI_ROT_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_IMHF_NPFL_CNT', fieldName: 'CHK_SPZI_IMHF_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_IMHF_ENFCT_PUMP_1', fieldName: 'CHK_SPZI_IMHF_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_IMHF_ENFCT_PUMP_2', fieldName: 'CHK_SPZI_IMHF_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_IMHF_ENFCT_PUMP_3', fieldName: 'CHK_SPZI_IMHF_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_IMHF_TANK_SM', fieldName: 'CHK_SPZI_IMHF_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_WTROT_NPFL_CNT', fieldName: 'CHK_SPZI_WTROT_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_WTROT_ENFCT_PUMP_1', fieldName: 'CHK_SPZI_WTROT_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_WTROT_ENFCT_PUMP_2', fieldName: 'CHK_SPZI_WTROT_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_WTROT_ENFCT_PUMP_3', fieldName: 'CHK_SPZI_WTROT_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_WTROT_TANK_SM', fieldName: 'CHK_SPZI_WTROT_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_TFM', fieldName: 'CHK_SPZI_TFM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ARTM', fieldName: 'CHK_SPZI_ARTM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_CTARM', fieldName: 'CHK_SPZI_CTARM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_NPFL', fieldName: 'CHK_SPZI_NPFL', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_ENFCT_PUMP', fieldName: 'CHK_SPZI_ENFCT_PUMP', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_SM', fieldName: 'CHK_SPZI_PROC_CPC_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_1', fieldName: 'CHK_SPZI_PROC_CPC_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_2', fieldName: 'CHK_SPZI_PROC_CPC_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_3', fieldName: 'CHK_SPZI_PROC_CPC_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_4', fieldName: 'CHK_SPZI_PROC_CPC_4', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_5', fieldName: 'CHK_SPZI_PROC_CPC_5', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_6', fieldName: 'CHK_SPZI_PROC_CPC_6', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_7', fieldName: 'CHK_SPZI_PROC_CPC_7', header: { text: '' } },
|
||||
{ name: 'CHK_SPZI_PROC_CPC_8', fieldName: 'CHK_SPZI_PROC_CPC_8', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_SM', fieldName: 'CHK_SPZO_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_MTHD_SM', fieldName: 'CHK_SPZO_MTHD_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ROT_NPFL_CNT', fieldName: 'CHK_SPZO_ROT_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ROT_ENFCT_PUMP_1', fieldName: 'CHK_SPZO_ROT_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ROT_ENFCT_PUMP_2', fieldName: 'CHK_SPZO_ROT_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ROT_ENFCT_PUMP_3', fieldName: 'CHK_SPZO_ROT_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ROT_TANK_SM', fieldName: 'CHK_SPZO_ROT_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_IMHF_NPFL_CNT', fieldName: 'CHK_SPZO_IMHF_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_IMHF_ENFCT_PUMP_1', fieldName: 'CHK_SPZO_IMHF_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_IMHF_ENFCT_PUMP_2', fieldName: 'CHK_SPZO_IMHF_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_IMHF_ENFCT_PUMP_3', fieldName: 'CHK_SPZO_IMHF_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_IMHF_TANK_SM', fieldName: 'CHK_SPZO_IMHF_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_WTROT_NPFL_CNT', fieldName: 'CHK_SPZO_WTROT_NPFL_CNT', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_WTROT_ENFCT_PUMP_1', fieldName: 'CHK_SPZO_WTROT_ENFCT_PUMP_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_WTROT_ENFCT_PUMP_2', fieldName: 'CHK_SPZO_WTROT_ENFCT_PUMP_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_WTROT_ENFCT_PUMP_3', fieldName: 'CHK_SPZO_WTROT_ENFCT_PUMP_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_WTROT_TANK_SM', fieldName: 'CHK_SPZO_WTROT_TANK_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_TFM', fieldName: 'CHK_SPZO_TFM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ARTM', fieldName: 'CHK_SPZO_ARTM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_CTARM', fieldName: 'CHK_SPZO_CTARM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_NPFL', fieldName: 'CHK_SPZO_NPFL', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_ENFCT_PUMP', fieldName: 'CHK_SPZO_ENFCT_PUMP', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_SM', fieldName: 'CHK_SPZO_PROC_CPC_SM', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_1', fieldName: 'CHK_SPZO_PROC_CPC_1', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_2', fieldName: 'CHK_SPZO_PROC_CPC_2', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_3', fieldName: 'CHK_SPZO_PROC_CPC_3', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_4', fieldName: 'CHK_SPZO_PROC_CPC_4', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_5', fieldName: 'CHK_SPZO_PROC_CPC_5', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_6', fieldName: 'CHK_SPZO_PROC_CPC_6', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_7', fieldName: 'CHK_SPZO_PROC_CPC_7', header: { text: '' } },
|
||||
{ name: 'CHK_SPZO_PROC_CPC_8', fieldName: 'CHK_SPZO_PROC_CPC_8', header: { text: '' } },
|
||||
],
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
'TOT_FCLTY_CNT',
|
||||
{
|
||||
name: 'group_spzi',
|
||||
header: { text: '하수처리구역 내' },
|
||||
items: [
|
||||
'SPZI_SM',
|
||||
{
|
||||
name: 'group_spzi_mthd',
|
||||
header: { text: '처리방식별' },
|
||||
items: [
|
||||
'SPZI_MTHD_SM',
|
||||
{
|
||||
name: 'group_spzi_rot',
|
||||
header: { text: '부패탱크' },
|
||||
items: [
|
||||
'SPZI_ROT_NPFL_CNT',
|
||||
'SPZI_ROT_ENFCT_PUMP_1'
|
||||
]
|
||||
},
|
||||
'SPZI_WTROT_NPFL_CNT',
|
||||
'SPZI_TFM',
|
||||
'SPZI_ARTM',
|
||||
'SPZI_CTARM'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'group_spzi_proc',
|
||||
header: { text: '처리용량별' },
|
||||
items: [
|
||||
'SPZI_PROC_CPC_SM',
|
||||
'SPZI_PROC_CPC_1',
|
||||
'SPZI_PROC_CPC_2',
|
||||
'SPZI_PROC_CPC_3',
|
||||
'SPZI_PROC_CPC_4',
|
||||
'SPZI_PROC_CPC_5',
|
||||
'SPZI_PROC_CPC_6',
|
||||
'SPZI_PROC_CPC_7',
|
||||
'SPZI_PROC_CPC_8'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'group_spzo',
|
||||
header: { text: '하수처리구역 외' },
|
||||
items: [
|
||||
'SPZO_SM',
|
||||
{
|
||||
name: 'group_spzo_mthd',
|
||||
header: { text: '처리방식별' },
|
||||
items: [
|
||||
'SPZO_MTHD_SM',
|
||||
{
|
||||
name: 'group_spzo_rot',
|
||||
header: { text: '부패탱크' },
|
||||
items: [
|
||||
'SPZO_ROT_NPFL_CNT',
|
||||
'SPZO_ROT_ENFCT_PUMP_1'
|
||||
]
|
||||
},
|
||||
'SPZO_WTROT_NPFL_CNT',
|
||||
'SPZO_TFM',
|
||||
'SPZO_ARTM',
|
||||
'SPZO_CTARM'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'group_spzo_proc',
|
||||
header: { text: '처리용량별' },
|
||||
items: [
|
||||
'SPZO_PROC_CPC_SM',
|
||||
'SPZO_PROC_CPC_1',
|
||||
'SPZO_PROC_CPC_2',
|
||||
'SPZO_PROC_CPC_3',
|
||||
'SPZO_PROC_CPC_4',
|
||||
'SPZO_PROC_CPC_5',
|
||||
'SPZO_PROC_CPC_6',
|
||||
'SPZO_PROC_CPC_7',
|
||||
'SPZO_PROC_CPC_8'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'RMK'
|
||||
],
|
||||
rowStartNum: 4,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'septicTankStatusInp',
|
||||
tabLabel: '정화조 현황'
|
||||
};
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 08.개인하수처리시설 > tab 1. 처리용량별 오수처리시설현황
|
||||
export const SewageTreatFactStatusInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 총계
|
||||
{ name: 'STTY_SM', fieldName: '총계', header: { text: '총계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 오수처리시설 > 하수처리구역 내(m³/일)
|
||||
{ name: 'STTY_ZONE_INNER_SM', fieldName: '계', header: { text: '계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_2', fieldName: '2이하', header: { text: '2이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_3', fieldName: '3~10', header: { text: '3~10' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_11', fieldName: '11~20', header: { text: '11~20' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_21', fieldName: '21~50', header: { text: '21~50' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_51', fieldName: '51~100', header: { text: '51~100' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_101', fieldName: '101~500', header: { text: '101~500' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_INNER_501', fieldName: '501이상', header: { text: '501이상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 오수처리시설 > 하수처리구역 외(m³/일)
|
||||
{ name: 'STTY_ZONE_OUTER_SM', fieldName: '계', header: { text: '계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_2', fieldName: '2이하', header: { text: '2이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_3', fieldName: '3~10', header: { text: '3~10' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_11', fieldName: '11~20', header: { text: '11~20' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_21', fieldName: '21~50', header: { text: '21~50' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_51', fieldName: '51~100', header: { text: '51~100' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_101', fieldName: '101~500', header: { text: '101~500' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'STTY_ZONE_OUTER_501', fieldName: '501이상', header: { text: '501이상' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// hidden
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' } },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' } },
|
||||
|
||||
// 검증 필드 (검증 여부 표시용, 빨간색 표시)
|
||||
{ name: 'CHK_STTY_SM', fieldName: 'CHK_STTY_SM', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_SM', fieldName: 'CHK_STTY_ZONE_INNER_SM', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_2', fieldName: 'CHK_STTY_ZONE_INNER_2', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_3', fieldName: 'CHK_STTY_ZONE_INNER_3', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_11', fieldName: 'CHK_STTY_ZONE_INNER_11', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_21', fieldName: 'CHK_STTY_ZONE_INNER_21', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_51', fieldName: 'CHK_STTY_ZONE_INNER_51', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_101', fieldName: 'CHK_STTY_ZONE_INNER_101', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_INNER_501', fieldName: 'CHK_STTY_ZONE_INNER_501', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_SM', fieldName: 'CHK_STTY_ZONE_OUTER_SM', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_2', fieldName: 'CHK_STTY_ZONE_OUTER_2', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_3', fieldName: 'CHK_STTY_ZONE_OUTER_3', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_11', fieldName: 'CHK_STTY_ZONE_OUTER_11', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_21', fieldName: 'CHK_STTY_ZONE_OUTER_21', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_51', fieldName: 'CHK_STTY_ZONE_OUTER_51', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_101', fieldName: 'CHK_STTY_ZONE_OUTER_101', header: { text: '' } },
|
||||
{ name: 'CHK_STTY_ZONE_OUTER_501', fieldName: 'CHK_STTY_ZONE_OUTER_501', header: { text: '' } },
|
||||
],
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
'STTY_SM',
|
||||
{
|
||||
name: 'group_stty',
|
||||
header: { text: '오수처리시설' },
|
||||
items: [
|
||||
{
|
||||
name: 'group_inner',
|
||||
header: { text: '하수처리구역 내(m³/일)' },
|
||||
items: [
|
||||
'STTY_ZONE_INNER_SM',
|
||||
'STTY_ZONE_INNER_2',
|
||||
'STTY_ZONE_INNER_3',
|
||||
'STTY_ZONE_INNER_11',
|
||||
'STTY_ZONE_INNER_21',
|
||||
'STTY_ZONE_INNER_51',
|
||||
'STTY_ZONE_INNER_101',
|
||||
'STTY_ZONE_INNER_501'
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'group_outer',
|
||||
header: { text: '하수처리구역 외(m³/일)' },
|
||||
items: [
|
||||
'STTY_ZONE_OUTER_SM',
|
||||
'STTY_ZONE_OUTER_2',
|
||||
'STTY_ZONE_OUTER_3',
|
||||
'STTY_ZONE_OUTER_11',
|
||||
'STTY_ZONE_OUTER_21',
|
||||
'STTY_ZONE_OUTER_51',
|
||||
'STTY_ZONE_OUTER_101',
|
||||
'STTY_ZONE_OUTER_501'
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
'RMK'
|
||||
],
|
||||
rowStartNum: 3,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'sewageTreatFactStatusInp',
|
||||
tabLabel: '처리용량별 오수처리시설 현황'
|
||||
};
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업 > tab 3. 분뇨수집·운반업
|
||||
export const ExcretaRelatedIndustryInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 행정코드 (hidden)
|
||||
{ name: 'ADST_DSTR_CD', fieldName: '행정구역코드', header: { text: '행정구역코드' }, visible: false },
|
||||
{ name: 'ADST_CD', fieldName: '행정코드', header: { text: '행정코드' }, visible: false },
|
||||
{ name: 'ADST_DONG', fieldName: '행정동', header: { text: '행정동' }, visible: false },
|
||||
{ name: 'RGN_NM', fieldName: '지역명', header: { text: '지역명' }, visible: false },
|
||||
|
||||
// 업체수(개소)
|
||||
{ name: 'ECSCS_SM', fieldName: '업체수(개소)', header: { text: '업체수(개소)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 종사인원(명)
|
||||
{ name: 'ECSCS_BSMN', fieldName: '종사인원(명)', header: { text: '종사인원(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 시설(차량) 확보현황(대수)
|
||||
{ name: 'VHCLE_SM', fieldName: '계', header: { text: '계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'THREE_BELOW', fieldName: '3톤이하', header: { text: '3톤이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'FOUR_BELOW', fieldName: '4.5톤이하', header: { text: '4.5톤이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'EIGHT_BELOW', fieldName: '8톤이하', header: { text: '8톤이하' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ETC', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 수집·운반 실적(m³/년)
|
||||
{ name: 'COLCT_TRSP_ACMSLT', fieldName: '수집·운반 실적(m³/년)', header: { text: '수집·운반 실적(m³/년)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// Hidden: 의견 필드
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' }, visible: false },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' }, visible: false },
|
||||
|
||||
// Hidden: Check fields : 데이터 변경 여부를 판단하는 필드로, UI에서 숨김 처리
|
||||
{ name: 'CHK_ECSCS_SM', fieldName: 'CHK_ECSCS_SM', header: { text: 'CHK_ECSCS_SM' }, visible: false },
|
||||
{ name: 'CHK_ECSCS_BSMN', fieldName: 'CHK_ECSCS_BSMN', header: { text: 'CHK_ECSCS_BSMN' }, visible: false },
|
||||
{ name: 'CHK_VHCLE_SM', fieldName: 'CHK_VHCLE_SM', header: { text: 'CHK_VHCLE_SM' }, visible: false },
|
||||
{ name: 'CHK_THREE_BELOW', fieldName: 'CHK_THREE_BELOW', header: { text: 'CHK_THREE_BELOW' }, visible: false },
|
||||
{ name: 'CHK_FOUR_BELOW', fieldName: 'CHK_FOUR_BELOW', header: { text: 'CHK_FOUR_BELOW' }, visible: false },
|
||||
{ name: 'CHK_EIGHT_BELOW', fieldName: 'CHK_EIGHT_BELOW', header: { text: 'CHK_EIGHT_BELOW' }, visible: false },
|
||||
{ name: 'CHK_ETC', fieldName: 'CHK_ETC', header: { text: 'CHK_ETC' }, visible: false },
|
||||
{ name: 'CHK_COLCT_TRSP_ACMSLT', fieldName: 'CHK_COLCT_TRSP_ACMSLT', header: { text: 'CHK_COLCT_TRSP_ACMSLT' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
'ECSCS_SM',
|
||||
'ECSCS_BSMN',
|
||||
{
|
||||
name: 'group_vehicle_status',
|
||||
header: { text: '시설(차량) 확보현황(대수)' },
|
||||
items: [
|
||||
'VHCLE_SM',
|
||||
'THREE_BELOW',
|
||||
'FOUR_BELOW',
|
||||
'EIGHT_BELOW',
|
||||
'ETC'
|
||||
]
|
||||
},
|
||||
'COLCT_TRSP_ACMSLT',
|
||||
'RMK'
|
||||
],
|
||||
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'excretaRelatedIndustryInp',
|
||||
tabLabel: '분뇨수집·운반업'
|
||||
};
|
||||
+86
@@ -0,0 +1,86 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업 > tab 4. 개인하수처리관련업
|
||||
export const PrivateSewageTreatRelatedIndustryInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 행정코드 (hidden)
|
||||
{ name: 'ADST_DONG', fieldName: '행정동', header: { text: '행정동' }, visible: false },
|
||||
{ name: 'RGN_NM', fieldName: '지역명', header: { text: '지역명' }, visible: false },
|
||||
{ name: 'ADST_CD', fieldName: '행정코드', header: { text: '행정코드' }, visible: false },
|
||||
|
||||
// 개인하수처리시설 설계·시공업
|
||||
{ name: 'CNSTRCT_ENTRPS', fieldName: '업소수', header: { text: '업소수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'CNSTRCT_BSMN', fieldName: '종사인원(명)', header: { text: '종사인원(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 개인하수처리시설 제조업
|
||||
{ name: 'MNFCTUR_ENTRPS', fieldName: '업소수', header: { text: '업소수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'MNFCTUR_BSMN', fieldName: '종사인원(명)', header: { text: '종사인원(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 개인하수처리시설 관리업
|
||||
{ name: 'MGMT_ENTRPS', fieldName: '업소수', header: { text: '업소수' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'MGMT_BSMN', fieldName: '종사인원(명)', header: { text: '종사인원(명)' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// Hidden: 의견 필드
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' }, visible: false },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' }, visible: false },
|
||||
|
||||
// Hidden: 추가 필드 (화면에 미노출이, DB 저장)
|
||||
{ name: 'CNSTRCT_FCT_CNT', fieldName: '설계시공시설개수', header: { text: '설계시공시설개수' }, visible: false },
|
||||
{ name: 'CNSTRCT_FCT_CPCTY', fieldName: '설계시공시설용량', header: { text: '설계시공시설용량' }, visible: false },
|
||||
{ name: 'MNFCTUR_STTY_CNT', fieldName: '제조정원', header: { text: '제조정원' }, visible: false },
|
||||
{ name: 'MNFCTUR_WRRTN_CNT', fieldName: '제조권원', header: { text: '제조권원' }, visible: false },
|
||||
{ name: 'MGMT_STTY_CNT', fieldName: '관리정원', header: { text: '관리정원' }, visible: false },
|
||||
{ name: 'MGMT_WRRTN_CNT', fieldName: '관리권원', header: { text: '관리권원' }, visible: false },
|
||||
|
||||
// Hidden: Check fields : 데이터 변경 여부를 판단하는 필드로, UI에서 숨김 처리
|
||||
{ name: 'CHK_CNSTRCT_ENTRPS', fieldName: 'CHK_CNSTRCT_ENTRPS', header: { text: 'CHK_CNSTRCT_ENTRPS' }, visible: false },
|
||||
{ name: 'CHK_CNSTRCT_BSMN', fieldName: 'CHK_CNSTRCT_BSMN', header: { text: 'CHK_CNSTRCT_BSMN' }, visible: false },
|
||||
{ name: 'CHK_CNSTRCT_FCT_CNT', fieldName: 'CHK_CNSTRCT_FCT_CNT', header: { text: 'CHK_CNSTRCT_FCT_CNT' }, visible: false },
|
||||
{ name: 'CHK_CNSTRCT_FCT_CPCTY', fieldName: 'CHK_CNSTRCT_FCT_CPCTY', header: { text: 'CHK_CNSTRCT_FCT_CPCTY' }, visible: false },
|
||||
{ name: 'CHK_MNFCTUR_ENTRPS', fieldName: 'CHK_MNFCTUR_ENTRPS', header: { text: 'CHK_MNFCTUR_ENTRPS' }, visible: false },
|
||||
{ name: 'CHK_MNFCTUR_BSMN', fieldName: 'CHK_MNFCTUR_BSMN', header: { text: 'CHK_MNFCTUR_BSMN' }, visible: false },
|
||||
{ name: 'CHK_MNFCTUR_STTY_CNT', fieldName: 'CHK_MNFCTUR_STTY_CNT', header: { text: 'CHK_MNFCTUR_STTY_CNT' }, visible: false },
|
||||
{ name: 'CHK_MNFCTUR_WRRTN_CNT', fieldName: 'CHK_MNFCTUR_WRRTN_CNT', header: { text: 'CHK_MNFCTUR_WRRTN_CNT' }, visible: false },
|
||||
{ name: 'CHK_MGMT_ENTRPS', fieldName: 'CHK_MGMT_ENTRPS', header: { text: 'CHK_MGMT_ENTRPS' }, visible: false },
|
||||
{ name: 'CHK_MGMT_BSMN', fieldName: 'CHK_MGMT_BSMN', header: { text: 'CHK_MGMT_BSMN' }, visible: false },
|
||||
{ name: 'CHK_MGMT_STTY_CNT', fieldName: 'CHK_MGMT_STTY_CNT', header: { text: 'CHK_MGMT_STTY_CNT' }, visible: false },
|
||||
{ name: 'CHK_MGMT_WRRTN_CNT', fieldName: 'CHK_MGMT_WRRTN_CNT', header: { text: 'CHK_MGMT_WRRTN_CNT' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
{
|
||||
name: 'group_design_construct',
|
||||
header: { text: '개인하수처리시설 설계·시공업' },
|
||||
items: ['CNSTRCT_ENTRPS', 'CNSTRCT_BSMN']
|
||||
},
|
||||
{
|
||||
name: 'group_manufacture',
|
||||
header: { text: '개인하수처리시설 제조업' },
|
||||
items: ['MNFCTUR_ENTRPS', 'MNFCTUR_BSMN']
|
||||
},
|
||||
{
|
||||
name: 'group_management',
|
||||
header: { text: '개인하수처리시설 관리업' },
|
||||
items: ['MGMT_ENTRPS', 'MGMT_BSMN']
|
||||
},
|
||||
'RMK'
|
||||
],
|
||||
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'privateSewageTreatRelatedIndustryInp',
|
||||
tabLabel: '개인하수처리관련업'
|
||||
};
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업 > tab 2. 공공기관 분뇨분야
|
||||
export const PublicInstitutionExcretaIndustryInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 행정코드 (hidden)
|
||||
{ name: 'ADST_CD', fieldName: '행정코드', header: { text: '행정코드' }, visible: false },
|
||||
|
||||
// 직제
|
||||
{ name: 'OCGNZ', fieldName: '직 제', header: { text: '직 제' } },
|
||||
|
||||
// 직원총수
|
||||
{ name: 'TOT_WTR_QRM', fieldName: '직원총수', header: { text: '직원총수' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 행정직
|
||||
{ name: 'ADMINIST_JSSFC', fieldName: '행정직', header: { text: '행정직' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 기술직
|
||||
{ name: 'TCHNLGY_JSSFC_SM', fieldName: '계', header: { text: '계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ENGRK_JSSFC', fieldName: '토목', header: { text: '토목' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'MCHN_JSSFC', fieldName: '기계', header: { text: '기계' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ELCTY_JSSFC', fieldName: '전기', header: { text: '전기' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'CHMSTRY_JSSFC', fieldName: '화공', header: { text: '화공' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ENVRN_JSSFC', fieldName: '환경', header: { text: '환경' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'TCHNLGY_ETC', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 기능직 (hidden)
|
||||
{ name: 'TCNSRV', fieldName: '기능직', header: { text: '기능직' }, visible: false },
|
||||
|
||||
// 기타
|
||||
{ name: 'ETC', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// Hidden: 의견 필드
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' }, visible: false },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' }, visible: false },
|
||||
|
||||
// Hidden: Check fields : 데이터 변경 여부를 판단하는 필드로, UI에서 숨김 처리
|
||||
{ name: 'CHK_OCGNZ', fieldName: 'CHK_OCGNZ', header: { text: 'CHK_OCGNZ' }, visible: false },
|
||||
{ name: 'CHK_TOT_WTR_QRM', fieldName: 'CHK_TOT_WTR_QRM', header: { text: 'CHK_TOT_WTR_QRM' }, visible: false },
|
||||
{ name: 'CHK_ADMINIST_JSSFC', fieldName: 'CHK_ADMINIST_JSSFC', header: { text: 'CHK_ADMINIST_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_TCHNLGY_JSSFC_SM', fieldName: 'CHK_TCHNLGY_JSSFC_SM', header: { text: 'CHK_TCHNLGY_JSSFC_SM' }, visible: false },
|
||||
{ name: 'CHK_ENGRK_JSSFC', fieldName: 'CHK_ENGRK_JSSFC', header: { text: 'CHK_ENGRK_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_MCHN_JSSFC', fieldName: 'CHK_MCHN_JSSFC', header: { text: 'CHK_MCHN_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_ELCTY_JSSFC', fieldName: 'CHK_ELCTY_JSSFC', header: { text: 'CHK_ELCTY_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_CHMSTRY_JSSFC', fieldName: 'CHK_CHMSTRY_JSSFC', header: { text: 'CHK_CHMSTRY_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_ENVRN_JSSFC', fieldName: 'CHK_ENVRN_JSSFC', header: { text: 'CHK_ENVRN_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_TCHNLGY_ETC', fieldName: 'CHK_TCHNLGY_ETC', header: { text: 'CHK_TCHNLGY_ETC' }, visible: false },
|
||||
{ name: 'CHK_TCNSRV', fieldName: 'CHK_TCNSRV', header: { text: 'CHK_TCNSRV' }, visible: false },
|
||||
{ name: 'CHK_ETC', fieldName: 'CHK_ETC', header: { text: 'CHK_ETC' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
'OCGNZ',
|
||||
'TOT_WTR_QRM',
|
||||
'ADMINIST_JSSFC',
|
||||
{
|
||||
name: 'group_technology',
|
||||
header: { text: '기술직' },
|
||||
items: [
|
||||
'TCHNLGY_JSSFC_SM',
|
||||
'ENGRK_JSSFC',
|
||||
'MCHN_JSSFC',
|
||||
'ELCTY_JSSFC',
|
||||
'CHMSTRY_JSSFC',
|
||||
'ENVRN_JSSFC',
|
||||
'TCHNLGY_ETC'
|
||||
]
|
||||
},
|
||||
'ETC',
|
||||
'RMK'
|
||||
],
|
||||
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 0,
|
||||
tabKey: 'publicInstitutionExcretaIndustryInp',
|
||||
tabLabel: '공공기관 분뇨분야'
|
||||
};
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
import { footerInt } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 12. 하수 및 분뇨관련산업 > tab 1. 공공기관 하수분야
|
||||
export const PublicInstitutionSewerIndustryInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'GUGUN', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 행정코드 (hidden)
|
||||
{ name: 'ADST_CD', fieldName: '행정코드', header: { text: '행정코드' }, visible: false },
|
||||
|
||||
// 직제
|
||||
{ name: 'OCGNZ', fieldName: '직 제', header: { text: '직 제' } },
|
||||
|
||||
// 직원총수
|
||||
{ name: 'TOT_WTR_QRM', fieldName: '직원총수', header: { text: '직원총수' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 행정직
|
||||
{ name: 'ADMINIST_JSSFC', fieldName: '행정직', header: { text: '행정직' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 기술직
|
||||
{ name: 'TCHNLGY_JSSFC_SM', fieldName: '계', header: { text: '계' }, editable: false, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ENGRK_JSSFC', fieldName: '토목', header: { text: '토목' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'MCHN_JSSFC', fieldName: '기계', header: { text: '기계' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ELCTY_JSSFC', fieldName: '전기', header: { text: '전기' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'CHMSTRY_JSSFC', fieldName: '화공', header: { text: '화공' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'ENVRN_JSSFC', fieldName: '환경', header: { text: '환경' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
{ name: 'TCHNLGY_ETC', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 기능직 (hidden)
|
||||
{ name: 'TCNSRV', fieldName: '기능직', header: { text: '기능직' }, visible: false },
|
||||
|
||||
// 기타
|
||||
{ name: 'ETC', fieldName: '기타', header: { text: '기타' }, footer: footerInt, valueType: ValueType.NUMBER, dataFormat: '#,##0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// Hidden: 의견 필드
|
||||
{ name: 'WRTER_OPINION', fieldName: '사용자의견', header: { text: '사용자의견' }, visible: false },
|
||||
{ name: 'CHCKER_OPINION', fieldName: '검토자의견', header: { text: '검토자의견' }, visible: false },
|
||||
|
||||
// Hidden: Check fields : 데이터 변경 여부를 판단하는 필드로, UI에서 숨김 처리
|
||||
{ name: 'CHK_OCGNZ', fieldName: 'CHK_OCGNZ', header: { text: 'CHK_OCGNZ' }, visible: false },
|
||||
{ name: 'CHK_TOT_WTR_QRM', fieldName: 'CHK_TOT_WTR_QRM', header: { text: 'CHK_TOT_WTR_QRM' }, visible: false },
|
||||
{ name: 'CHK_ADMINIST_JSSFC', fieldName: 'CHK_ADMINIST_JSSFC', header: { text: 'CHK_ADMINIST_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_TCHNLGY_JSSFC_SM', fieldName: 'CHK_TCHNLGY_JSSFC_SM', header: { text: 'CHK_TCHNLGY_JSSFC_SM' }, visible: false },
|
||||
{ name: 'CHK_ENGRK_JSSFC', fieldName: 'CHK_ENGRK_JSSFC', header: { text: 'CHK_ENGRK_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_MCHN_JSSFC', fieldName: 'CHK_MCHN_JSSFC', header: { text: 'CHK_MCHN_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_ELCTY_JSSFC', fieldName: 'CHK_ELCTY_JSSFC', header: { text: 'CHK_ELCTY_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_CHMSTRY_JSSFC', fieldName: 'CHK_CHMSTRY_JSSFC', header: { text: 'CHK_CHMSTRY_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_ENVRN_JSSFC', fieldName: 'CHK_ENVRN_JSSFC', header: { text: 'CHK_ENVRN_JSSFC' }, visible: false },
|
||||
{ name: 'CHK_TCHNLGY_ETC', fieldName: 'CHK_TCHNLGY_ETC', header: { text: 'CHK_TCHNLGY_ETC' }, visible: false },
|
||||
{ name: 'CHK_TCNSRV', fieldName: 'CHK_TCNSRV', header: { text: 'CHK_TCNSRV' }, visible: false },
|
||||
{ name: 'CHK_ETC', fieldName: 'CHK_ETC', header: { text: 'CHK_ETC' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO', 'GUGUN']
|
||||
},
|
||||
'OCGNZ',
|
||||
'TOT_WTR_QRM',
|
||||
'ADMINIST_JSSFC',
|
||||
{
|
||||
name: 'group_technology',
|
||||
header: { text: '기술직' },
|
||||
items: [
|
||||
'TCHNLGY_JSSFC_SM',
|
||||
'ENGRK_JSSFC',
|
||||
'MCHN_JSSFC',
|
||||
'ELCTY_JSSFC',
|
||||
'CHMSTRY_JSSFC',
|
||||
'ENVRN_JSSFC',
|
||||
'TCHNLGY_ETC'
|
||||
]
|
||||
},
|
||||
'ETC',
|
||||
'RMK'
|
||||
],
|
||||
|
||||
rowStartNum: 2,
|
||||
fixedColumns: 1,
|
||||
tabKey: 'publicInstitutionSewerIndustryInp',
|
||||
tabLabel: '공공기관 하수분야'
|
||||
};
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
import { footerDecimal1 } from "@/components/util/grid/footerSummary";
|
||||
import { ValueType } from "realgrid";
|
||||
|
||||
// 하수도 통계 관리 > 11. 하수 및 분뇨찌꺼기(슬러지)처리 > tab 2. 소화조 운영현황
|
||||
export const DigestorOperatingStatusInpColumn = {
|
||||
columns: [
|
||||
// 행정구역
|
||||
{ name: 'SIDO_CD', fieldName: '시도', header: { text: '시도' }, editable: false },
|
||||
{ name: 'ADST_CD', fieldName: '시군구', header: { text: '시군구' }, editable: false, footer: { text: '합계' } },
|
||||
|
||||
// 하수처리장명
|
||||
{ name: 'BSC_FCT_NM', fieldName: '하수처리장명', header: { text: '하수처리장명' }, editable: false },
|
||||
|
||||
// 소화조 운영현황
|
||||
{ name: 'DGSTR_FNNC', fieldName: '소화조 유/무(Y/N)선택', header: { text: '소화조 유/무(Y/N)선택' } },
|
||||
{ name: 'DGSTR_CPC', fieldName: '설계용량(m³)', header: { text: '설계용량(m³)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_OPR_CPC', fieldName: '실제운전용량(m³)', header: { text: '실제운전용량(m³)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_IN', fieldName: '투입량(m³/일)', header: { text: '투입량(m³/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_TS', fieldName: '투입 TS 농도(%)', header: { text: '투입 TS 농도(%)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_YRSTP_RN_DYN', fieldName: '가동일수(연간)', header: { text: '가동일수(연간)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_OCCUR_GAS', fieldName: '발생가스량(m³/일)', header: { text: '발생가스량(m³/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 소화조 운영현황 > 소화가스 이용현황(m³/일)
|
||||
{ name: 'DGSTR_SM', fieldName: '계', header: { text: '계' }, footer: footerDecimal1, editable: false, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_SLE', fieldName: '판매', header: { text: '판매' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_ELTGNR', fieldName: '발전', header: { text: '발전' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_ONSLF', fieldName: '자체활용', header: { text: '자체활용' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
{ name: 'DGSTR_ETC', fieldName: '기타(CNG등)', header: { text: '기타(CNG등)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 소화조 운영현황 > 잉여가스량
|
||||
{ name: 'DGSTR_GAS', fieldName: '잉여가스량(m³/일)', header: { text: '잉여가스량(m³/일)' }, footer: footerDecimal1, valueType: ValueType.NUMBER, dataFormat: '#,##0.0' },
|
||||
|
||||
// 비고
|
||||
{ name: 'DGSTR_RMK', fieldName: '비고', header: { text: '비고' } },
|
||||
|
||||
// Hidden: Check fields for change detection
|
||||
{ name: 'CHK_DGSTR_FNNC', fieldName: 'CHK_DGSTR_FNNC', header: { text: 'CHK_DGSTR_FNNC' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_IN', fieldName: 'CHK_DGSTR_IN', header: { text: 'CHK_DGSTR_IN' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_TS', fieldName: 'CHK_DGSTR_TS', header: { text: 'CHK_DGSTR_TS' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_YRSTP_RN_DYN', fieldName: 'CHK_DGSTR_YRSTP_RN_DYN', header: { text: 'CHK_DGSTR_YRSTP_RN_DYN' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_OCCUR_GAS', fieldName: 'CHK_DGSTR_OCCUR_GAS', header: { text: 'CHK_DGSTR_OCCUR_GAS' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_CPC', fieldName: 'CHK_DGSTR_CPC', header: { text: 'CHK_DGSTR_CPC' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_OPR_CPC', fieldName: 'CHK_DGSTR_OPR_CPC', header: { text: 'CHK_DGSTR_OPR_CPC' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_SM', fieldName: 'CHK_DGSTR_SM', header: { text: 'CHK_DGSTR_SM' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_SLE', fieldName: 'CHK_DGSTR_SLE', header: { text: 'CHK_DGSTR_SLE' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_ELTGNR', fieldName: 'CHK_DGSTR_ELTGNR', header: { text: 'CHK_DGSTR_ELTGNR' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_ONSLF', fieldName: 'CHK_DGSTR_ONSLF', header: { text: 'CHK_DGSTR_ONSLF' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_ETC', fieldName: 'CHK_DGSTR_ETC', header: { text: 'CHK_DGSTR_ETC' }, visible: false },
|
||||
{ name: 'CHK_DGSTR_GAS', fieldName: 'CHK_DGSTR_GAS', header: { text: 'CHK_DGSTR_GAS' }, visible: false },
|
||||
],
|
||||
|
||||
columnLayout: [
|
||||
{
|
||||
name: 'group_admin',
|
||||
header: { text: '행정구역' },
|
||||
items: ['SIDO_CD', 'ADST_CD']
|
||||
},
|
||||
'BSC_FCT_NM',
|
||||
{
|
||||
name: 'group_digestor_operating',
|
||||
header: { text: '소화조 운영현황' },
|
||||
items: [
|
||||
'DGSTR_FNNC',
|
||||
'DGSTR_CPC',
|
||||
'DGSTR_OPR_CPC',
|
||||
'DGSTR_IN',
|
||||
'DGSTR_TS',
|
||||
'DGSTR_YRSTP_RN_DYN',
|
||||
'DGSTR_OCCUR_GAS',
|
||||
{
|
||||
name: 'group_gas_usage',
|
||||
header: { text: '소화가스 이용현황(m³/일)' },
|
||||
items: [
|
||||
'DGSTR_SM',
|
||||
'DGSTR_SLE',
|
||||
'DGSTR_ELTGNR',
|
||||
'DGSTR_ONSLF',
|
||||
'DGSTR_ETC'
|
||||
]
|
||||
},
|
||||
'DGSTR_GAS'
|
||||
]
|
||||
},
|
||||
'DGSTR_RMK'
|
||||
],
|
||||
|
||||
rowStartNum: 3,
|
||||
fixedColumns: 0,
|
||||
tabKey: 'digestorOperatingStatusInp',
|
||||
tabLabel: '소화조 운영현황'
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user