diff --git a/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx b/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx index fb1bf5fa1..0a01a8d4c 100644 --- a/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx +++ b/apps/as/src/pages/instl-sncn/ui/instl-view-page.tsx @@ -1,5 +1,7 @@ "use client"; +import { useState } from "react"; + import { useUserStore } from "@/shared/lib"; import { useInstlSncnDetail } from "@/entities/instl-sncn"; import { Skeleton } from "@common/components"; diff --git a/apps/cs/src/pages/admin/ui/admin-page.tsx b/apps/cs/src/pages/admin/ui/admin-page.tsx index 6a621b865..4874f6525 100644 --- a/apps/cs/src/pages/admin/ui/admin-page.tsx +++ b/apps/cs/src/pages/admin/ui/admin-page.tsx @@ -1,17 +1,29 @@ "use client"; import { useState } from "react"; + import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { getCoreRowModel, type PaginationState, + type Row, type RowSelectionState, type Table, - type Row, } from "@tanstack/react-table"; + +import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useDataTable } from "@/shared/lib"; +import { GroupApi } from "@/entities/group"; +import { GroupUsersApi } from "@/entities/group-user"; +import { + type AdminUserListResponse, + UserApi, + type UserSearchParams, +} from "@/entities/user"; import { Button, + Checkbox, Input, Label, Select, @@ -19,18 +31,10 @@ import { SelectItem, SelectTrigger, SelectValue, - Checkbox, } from "@common/components"; -import { GroupApi } from "@/entities/group"; -import { - UserApi, - type UserSearchParams, - type AdminUserListResponse, -} from "@/entities/user"; -import { GroupUsersApi } from "@/entities/group-user"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable, useAlertStore } from "@/shared/lib"; + import { columns } from "../model/table-columns"; + import { AddAdminDialog } from "./add-admin-dialog"; function AdminPage() { diff --git a/apps/cs/src/pages/banner/ui/banner-page.tsx b/apps/cs/src/pages/banner/ui/banner-page.tsx index e09f5ab58..4e1e4733c 100644 --- a/apps/cs/src/pages/banner/ui/banner-page.tsx +++ b/apps/cs/src/pages/banner/ui/banner-page.tsx @@ -1,20 +1,25 @@ "use client"; -import { useEffect, useState, useRef } from "react"; +import { useEffect, useRef, useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; +import { Button, Input, Label } from "@common/components"; + import { BannerApi } from "../api/banner-service"; +import { type Banner } from "../model/banner-interface"; import { createColumns } from "../model/banner-table-columns"; -import { type Banner, type BannerParams } from "../model/banner-interface"; + import { PreviewBannerDialog } from "./preview-banner-dialog"; type PostingTarget = { @@ -22,50 +27,52 @@ type PostingTarget = { pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + bnrTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function BannerPage() { const router = useRouter(); const imageRefs = useRef>(new Map()); - + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); - const [bnrTtl, setBnrTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - bnrTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const [bnrTtl, setBnrTtl] = useState(params.bnrTtl); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.BANNERS, params], queryFn: () => BannerApi.getBannerList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + bnrTtl: params.bnrTtl, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - bnrTtl, - }); + setParams({ bnrTtl, page: 0 }); }; const handleReset = () => { setBnrTtl(""); - setSearchParams({ - ...searchParams, - bnrTtl: "", - }); + resetParams(); }; const handleRowClick = (row: Banner) => { @@ -92,7 +99,7 @@ function BannerPage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/bbs/ui/bbs-page.tsx b/apps/cs/src/pages/bbs/ui/bbs-page.tsx index abb1ec9db..27d0fb879 100644 --- a/apps/cs/src/pages/bbs/ui/bbs-page.tsx +++ b/apps/cs/src/pages/bbs/ui/bbs-page.tsx @@ -2,12 +2,19 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; + +import { ENDPOINT } from "@/shared/config"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Board, BoardApi } from "@/entities/board"; +import { CodeSelect } from "@/entities/code"; import { Button, Input, @@ -18,60 +25,57 @@ import { SelectTrigger, SelectValue, } from "@common/components"; -import { CodeSelect } from "@/entities/code"; -import { BoardApi, type BoardParams } from "@/entities/board"; -import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; -import { type Board } from "@/entities/board"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + bbsTypeCd: "", + bbsNm: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function BbsPage() { const router = useRouter(); - + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [rowSelection, setRowSelection] = useState({}); - const [bbsTypeCd, setBbsTypeCd] = useState(""); - const [bbsNm, setBbsNm] = useState(""); - const [searchParams, setSearchParams] = useState({ - bbsTypeCd: "", - bbsNm: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const [bbsTypeCd, setBbsTypeCd] = useState(params.bbsTypeCd); + const [bbsNm, setBbsNm] = useState(params.bbsNm); const query = useQuery({ - queryKey: [ENDPOINT.BOARD_SERVICE.BBS, searchParams, pagination], + queryKey: [ENDPOINT.BOARD_SERVICE.BBS, params], queryFn: () => BoardApi.getBoardList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + bbsTypeCd: params.bbsTypeCd, + bbsNm: params.bbsNm, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - bbsTypeCd, - bbsNm, - }); + setParams({ bbsTypeCd, bbsNm, page: 0 }); }; const handleReset = () => { setBbsTypeCd(""); setBbsNm(""); - setSearchParams({ - ...searchParams, - bbsTypeCd: "", - bbsNm: "", - }); + resetParams(); }; const handleRowClick = (row: Board) => { @@ -89,7 +93,7 @@ function BbsPage() { manualPagination: true, enableMultiRowSelection: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { diff --git a/apps/cs/src/pages/code/model/upcode-table-columns.tsx b/apps/cs/src/pages/code/model/upcode-table-columns.tsx index c35ea4d70..5c9108543 100644 --- a/apps/cs/src/pages/code/model/upcode-table-columns.tsx +++ b/apps/cs/src/pages/code/model/upcode-table-columns.tsx @@ -1,8 +1,11 @@ -import dayjs from "dayjs"; import { useState } from "react"; + import type { ColumnDef } from "@tanstack/react-table"; -import { Button } from "@common/components"; +import dayjs from "dayjs"; + import type { UpCode } from "@/entities/code"; +import { Button } from "@common/components"; + import { UpCodeManagementDialog } from "../ui/upcode-dialog"; export const columns: ColumnDef[] = [ @@ -24,7 +27,7 @@ export const columns: ColumnDef[] = [ header: "상위코드명", }, { - accessorKey: "cdSe", + accessorKey: "cdSeNm", header: "코드구분", }, { diff --git a/apps/cs/src/pages/contents/ui/contents-page.tsx b/apps/cs/src/pages/contents/ui/contents-page.tsx index 105aecdba..bda7c9ed6 100644 --- a/apps/cs/src/pages/contents/ui/contents-page.tsx +++ b/apps/cs/src/pages/contents/ui/contents-page.tsx @@ -2,60 +2,64 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; import { - ContentsApi, - type Contents, - type ContentsParams, -} from "@/entities/content"; + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Contents, ContentsApi } from "@/entities/content"; +import { Button, Input, Label } from "@common/components"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + contsTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function ContentsPage() { const router = useRouter(); - - const [contsTtl, setContsTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - contsTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [contsTtl, setContsTtl] = useState(params.contsTtl); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, params], queryFn: () => ContentsApi.getContentsList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + contsTtl: params.contsTtl, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - contsTtl, - }); + setParams({ contsTtl, page: 0 }); }; const handleReset = () => { setContsTtl(""); - setSearchParams({ - ...searchParams, - contsTtl: "", - }); + resetParams(); }; const handleRowClick = (row: Contents) => { @@ -69,7 +73,7 @@ function ContentsPage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx index d787a6ab7..466148ed4 100644 --- a/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx +++ b/apps/cs/src/pages/dashboard/ui/dashboard-page.tsx @@ -354,7 +354,7 @@ function DashboardPage() {

실시간 알림

-
+
{noticeUserList?.map((item) => (

일정 알림

-
+
{scheduleList && scheduleList.length > 0 ? ( scheduleList.map((schedule, index) => { diff --git a/apps/cs/src/pages/file/ui/file-page.tsx b/apps/cs/src/pages/file/ui/file-page.tsx index f4ff3f97a..8669d6717 100644 --- a/apps/cs/src/pages/file/ui/file-page.tsx +++ b/apps/cs/src/pages/file/ui/file-page.tsx @@ -1,13 +1,16 @@ "use client"; import { useState } from "react"; + +import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { useConfirm } from "@frontend-opensource/use-react-hooks"; -import { Button, Input, Label } from "@common/components"; -import { AttachmentApi, type AttachmentParams } from "@/entities/attachment"; -import { useAlertStore, useDataTable, useMutationWrapper } from "@/shared/lib"; + import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useDataTable, useMutationWrapper } from "@/shared/lib"; +import { AttachmentApi, type AttachmentParams } from "@/entities/attachment"; +import { Button, Input, Label } from "@common/components"; + import { createColumns } from "../model/table-columns"; function FilePage() { diff --git a/apps/cs/src/pages/groups/ui/add-user-dialog.tsx b/apps/cs/src/pages/groups/ui/add-user-dialog.tsx index f2a1b68a2..1b94048fc 100644 --- a/apps/cs/src/pages/groups/ui/add-user-dialog.tsx +++ b/apps/cs/src/pages/groups/ui/add-user-dialog.tsx @@ -23,6 +23,11 @@ import { Input, Checkbox, Label, + Select, + SelectValue, + SelectContent, + SelectItem, + SelectTrigger, } from "@common/components"; import { UserApi, @@ -42,9 +47,11 @@ function AddUserDialog({ groupId }: AdditionalUserDialogProps) { const alert = useAlertStore((state) => state.setMessage); const [open, setOpen] = useState(false); - const [userName, setUserName] = useState(""); + const [keywordType, setKeywordType] = useState("all"); + const [keyword, setKeyword] = useState(""); const [searchParam, setSearchParam] = useState({ - userName: "", + keywordType: "all", + keyword: "", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -156,7 +163,7 @@ function AddUserDialog({ groupId }: AdditionalUserDialogProps) { ...pagination, pageIndex: 0, }); - setSearchParam({ userName }); + setSearchParam({ keywordType, keyword }); }; const resetSearch = () => { @@ -164,8 +171,8 @@ function AddUserDialog({ groupId }: AdditionalUserDialogProps) { pageIndex: 0, pageSize: 10, }); - setUserName(""); - setSearchParam({ userName: "" }); + setKeyword(""); + setSearchParam({ keywordType: "all", keyword: "" }); setUserRowSelection({}); }; @@ -184,15 +191,26 @@ function AddUserDialog({ groupId }: AdditionalUserDialogProps) {
- + setUserName(e.target.value)} - placeholder="사용자 이름으로 검색" + value={keyword} + onChange={(e) => setKeyword(e.target.value)} + className="!text-[1.3rem]" + placeholder="검색어를 입력하세요" />
diff --git a/apps/cs/src/pages/role/ui/role-page.tsx b/apps/cs/src/pages/role/ui/role-page.tsx index b370ed338..a6c7ec2d1 100644 --- a/apps/cs/src/pages/role/ui/role-page.tsx +++ b/apps/cs/src/pages/role/ui/role-page.tsx @@ -2,39 +2,68 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { RoleApi, type Role, type RoleParams } from "@/entities/role"; + +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useAlertStore, useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Role, RoleApi } from "@/entities/role"; +import { Button, Input, Label } from "@common/components"; + import { createColumns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + keywordType: "roleName", + keyword: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function RolePage() { const router = useRouter(); - const alert = useAlertStore((state) => state.setMessage); - - const [keyword, setKeyword] = useState(""); - const [searchParams, setSearchParams] = useState({ - keywordType: "roleName", - keyword: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.ROLES, searchParams, pagination], + queryKey: [ENDPOINT.USER_SERVICE.ROLES, params], queryFn: () => RoleApi.getRoles({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keywordType: params.keywordType, + keyword: params.keyword, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setParams({ keyword, page: 0 }); + }; + + const handleReset = () => { + setKeyword(""); + resetParams(); + }; + const handleRowClick = (row: Role) => { router.push(`/role/register/${row.roleId}`); }; @@ -48,7 +77,7 @@ function RolePage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, }, dataTableOptions: { onRowClick: handleRowClick, @@ -56,26 +85,6 @@ function RolePage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { - e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - }); - }; - - const handleReset = () => { - setKeyword(""); - setSearchParams({ - ...searchParams, - keyword: "", - }); - }; - return (
diff --git a/apps/cs/src/pages/site/ui/site-page.tsx b/apps/cs/src/pages/site/ui/site-page.tsx index fbdd9d36c..20a38e998 100644 --- a/apps/cs/src/pages/site/ui/site-page.tsx +++ b/apps/cs/src/pages/site/ui/site-page.tsx @@ -1,54 +1,65 @@ "use client"; -import "@common/assets/styles/grid.css"; - import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { SiteApi, type Site, type SiteParams } from "@/entities/site"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { type Site, SiteApi } from "@/entities/site"; +import { Button, Input, Label } from "@common/components"; + import { columns } from "../model/table-columns"; +const DEFAULT_PARAMS = { + siteNm: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function SitePage() { const router = useRouter(); - const [siteNm, setSiteNm] = useState(""); - const [searchParams, setSearchParams] = useState({ - siteNm: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [siteNm, setSiteNm] = useState(params.siteNm); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SITES, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SITES, params], queryFn: () => SiteApi.getSiteList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + siteNm: params.siteNm, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setSearchParams({ - ...searchParams, - siteNm, - }); + setParams({ siteNm, page: 0 }); }; const handleReset = () => { setSiteNm(""); - setSearchParams({ - ...searchParams, - siteNm: "", - }); + resetParams(); }; const handleRowClick = (row: Site) => { @@ -62,7 +73,7 @@ function SitePage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/survey/ui/survey-page.tsx b/apps/cs/src/pages/survey/ui/survey-page.tsx index 27f080343..f3e0481d5 100644 --- a/apps/cs/src/pages/survey/ui/survey-page.tsx +++ b/apps/cs/src/pages/survey/ui/survey-page.tsx @@ -2,19 +2,23 @@ import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; import { getCoreRowModel, + type OnChangeFn, type PaginationState, type RowSelectionState, } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; -import { AuthorityButton } from "@/entities/menu-authority"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { AuthorityButton } from "@/entities/menu-authority"; +import { POSTING_TYPE, PostingDialog } from "@/entities/posting"; +import { Button, Input, Label } from "@common/components"; + import { SurveyApi } from "../api/survey-service"; -import type { Survey, SurveyParams } from "../model/survey-interface"; +import type { Survey } from "../model/survey-interface"; import { columns } from "../model/survey-table-columns"; type PostingTarget = { @@ -22,32 +26,53 @@ type PostingTarget = { pstgTrgtNo: number; }; +const DEFAULT_PARAMS = { + srvyTtl: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + function SurveyPage() { const router = useRouter(); - - const [srvyTtl, setSrvyTtl] = useState(""); - const [searchParams, setSearchParams] = useState({ - srvyTtl: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [srvyTtl, setSrvyTtl] = useState(params.srvyTtl); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, params], queryFn: () => SurveyApi.getSurveyList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + srvyTtl: params.srvyTtl, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setParams({ srvyTtl, page: 0 }); + }; + + const handleReset = () => { + setSrvyTtl(""); + resetParams(); + }; + const handleRowClick = (row: Survey) => { router.push(`/survey/${row.srvySn}`); }; @@ -62,7 +87,7 @@ function SurveyPage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, onRowSelectionChange: setRowSelection, }, dataTableOptions: { @@ -71,26 +96,6 @@ function SurveyPage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { - e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - srvyTtl, - }); - }; - - const handleReset = () => { - setSrvyTtl(""); - setSearchParams({ - ...searchParams, - srvyTtl: "", - }); - }; - useEffect(() => { const postingTargets = table .getFilteredSelectedRowModel() diff --git a/apps/cs/src/pages/template/ui/template-page.tsx b/apps/cs/src/pages/template/ui/template-page.tsx index d4ceb3bca..5db3f1572 100644 --- a/apps/cs/src/pages/template/ui/template-page.tsx +++ b/apps/cs/src/pages/template/ui/template-page.tsx @@ -2,58 +2,70 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { CodeSelect } from "@/entities/code"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { CodeSelect } from "@/entities/code"; +import { Button, Input, Label } from "@common/components"; + import { TemplateApi } from "../api/template-service"; +import type { Template } from "../model/template-interface"; import { columns } from "../model/template-table-columns"; -import type { Template, TemplateParams } from "../model/template-interface"; + +const DEFAULT_PARAMS = { + keyword: "", + tmpltSeCd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; function TemplatePage() { const router = useRouter(); - const [keyword, setKeyword] = useState(""); - const [tmpltSeCd, setTmpltSeCd] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - tmpltSeCd: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); + const [tmpltSeCd, setTmpltSeCd] = useState(params.tmpltSeCd); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, params], queryFn: () => TemplateApi.getTemplateList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + tmpltSeCd: params.tmpltSeCd, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setSearchParams({ - ...searchParams, - keyword, - tmpltSeCd, - }); + setParams({ keyword, tmpltSeCd, page: 0 }); }; const handleReset = () => { setKeyword(""); setTmpltSeCd(""); - setSearchParams({ - ...searchParams, - keyword: "", - tmpltSeCd: "", - }); + resetParams(); }; const handleRowClick = (row: Template) => { @@ -67,7 +79,7 @@ function TemplatePage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/terms/ui/terms-page.tsx b/apps/cs/src/pages/terms/ui/terms-page.tsx index ea00276df..73b6b0d16 100644 --- a/apps/cs/src/pages/terms/ui/terms-page.tsx +++ b/apps/cs/src/pages/terms/ui/terms-page.tsx @@ -2,63 +2,70 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; + import { keepPreviousData, useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button, Input, Label } from "@common/components"; -import { CodeSelect } from "@/entities/code"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; + import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; +import { CodeSelect } from "@/entities/code"; +import { Button, Input, Label } from "@common/components"; + import { TermsApi } from "../api/terms-service"; +import type { Terms } from "../model/terms-interface"; import { columns } from "../model/terms-table-columns"; -import type { TermsParams, Terms } from "../model/terms-interface"; + +const DEFAULT_PARAMS = { + keyword: "", + trmsSeCd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; function TermsPage() { const router = useRouter(); - - const [keyword, setKeyword] = useState(""); - const [trmsSeCd, setTrmsSeCd] = useState(""); - const [searchParams, setSearchParams] = useState({ - keyword: "", - trmsSeCd: "", - sort: "regDt,desc", - }); - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); + const [keyword, setKeyword] = useState(params.keyword); + const [trmsSeCd, setTrmsSeCd] = useState(params.trmsSeCd); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TERMS, searchParams, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TERMS, params], queryFn: () => TermsApi.getTermsList({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keyword: params.keyword, + trmsSeCd: params.trmsSeCd, + sort: params.sort, + page: params.page, + size: params.size, }), placeholderData: keepPreviousData, }); - const handleSubmit = (e: React.SubmitEvent) => { + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, - keyword, - trmsSeCd, - }); + setParams({ keyword, trmsSeCd, page: 0 }); }; const handleReset = () => { setKeyword(""); setTrmsSeCd(""); - setSearchParams({ - ...searchParams, - keyword: "", - trmsSeCd: "", - }); + resetParams(); }; const handleRowClick = (row: Terms) => { @@ -72,7 +79,7 @@ function TermsPage() { state: { pagination, }, - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, getCoreRowModel: getCoreRowModel(), manualPagination: true, }, diff --git a/apps/cs/src/pages/users/ui/users-page.tsx b/apps/cs/src/pages/users/ui/users-page.tsx index 17b44707c..cabf8eb42 100644 --- a/apps/cs/src/pages/users/ui/users-page.tsx +++ b/apps/cs/src/pages/users/ui/users-page.tsx @@ -3,19 +3,19 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; -import { useQuery } from "@tanstack/react-query"; -import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; +import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + getCoreRowModel, + type OnChangeFn, + type PaginationState, +} from "@tanstack/react-table"; import dayjs from "dayjs"; import { ENDPOINT } from "@/shared/config"; -import { useDataTable } from "@/shared/lib"; +import { useDataTable, useSearchParamsState } from "@/shared/lib"; import { InputDateRangePicker } from "@/shared/ui/input-date-range-picker"; import { CodeApi } from "@/entities/code"; -import { - UserApi, - type UserListResponse, - type UserSearchParams, -} from "@/entities/user"; +import { UserApi, type UserListResponse } from "@/entities/user"; import { Button, Checkbox, @@ -35,34 +35,39 @@ type DateRange = { to?: Date | null; }; +const DEFAULT_PARAMS = { + keywordType: "all", + keyword: "", + userStateCode: "", + aprvYn: "", + grpId: "", + frDateYmd: "", + toDateYmd: "", + sort: "regDt,desc", + page: 0, + size: 10, +}; + +function parseDateRange(frDateYmd: string, toDateYmd: string): DateRange { + return { + from: frDateYmd ? dayjs(frDateYmd, "YYYYMMDD").toDate() : undefined, + to: toDateYmd ? dayjs(toDateYmd, "YYYYMMDD").toDate() : undefined, + }; +} + function UsersPage() { const router = useRouter(); - - const [pagination, setPagination] = useState({ - pageIndex: 0, - pageSize: 10, - }); + const { params, setParams, resetParams } = + useSearchParamsState(DEFAULT_PARAMS); const [presetDateRange, setPresetDateRange] = useState(""); - const [dateRange, setDateRange] = useState({ - from: undefined, - to: undefined, - }); - const [keywordType, setKeywordType] = useState("all"); - const [keyword, setKeyword] = useState(""); - const [userStateCode, setUserStateCode] = useState(""); - const [aprvYn, setAprvYn] = useState(""); - const [grpId, setGrpId] = useState(""); - - const [searchParams, setSearchParams] = useState({ - keywordType: "all", - keyword: "", - userStateCode: "", - aprvYn: "", - grpId: "", - frDateYmd: "", - toDateYmd: "", - sort: "regDt,desc", - }); + const [dateRange, setDateRange] = useState(() => + parseDateRange(params.frDateYmd, params.toDateYmd), + ); + const [keywordType, setKeywordType] = useState(params.keywordType); + const [keyword, setKeyword] = useState(params.keyword); + const [userStateCode, setUserStateCode] = useState(params.userStateCode); + const [aprvYn, setAprvYn] = useState(params.aprvYn); + const [grpId, setGrpId] = useState(params.grpId); const { data: userSttsStats } = useQuery({ queryKey: [ENDPOINT.USER_SERVICE.USERS, "userStatusStatistics"], @@ -70,13 +75,21 @@ function UsersPage() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.USERS, searchParams, pagination], + queryKey: [ENDPOINT.USER_SERVICE.USERS, params], queryFn: () => UserApi.findPageUser({ - ...searchParams, - page: pagination.pageIndex, - size: pagination.pageSize, + keywordType: params.keywordType, + keyword: params.keyword, + userStateCode: params.userStateCode, + aprvYn: params.aprvYn, + grpId: params.grpId, + frDateYmd: params.frDateYmd, + toDateYmd: params.toDateYmd, + sort: params.sort, + page: params.page, + size: params.size, }), + placeholderData: keepPreviousData, }); const { data: userStateCodes } = useQuery({ @@ -84,6 +97,16 @@ function UsersPage() { queryFn: () => CodeApi.getCode("USERSTTS"), }); + const pagination: PaginationState = { + pageIndex: params.page, + pageSize: params.size, + }; + + const handlePaginationChange: OnChangeFn = (updater) => { + const next = typeof updater === "function" ? updater(pagination) : updater; + setParams({ page: next.pageIndex, size: next.pageSize }); + }; + const handleRowClick = (row: UserListResponse) => { router.push(`/users/${row.userUnqId}`); }; @@ -97,7 +120,7 @@ function UsersPage() { }, manualPagination: true, getCoreRowModel: getCoreRowModel(), - onPaginationChange: setPagination, + onPaginationChange: handlePaginationChange, }, dataTableOptions: { onRowClick: handleRowClick, @@ -105,14 +128,9 @@ function UsersPage() { }, }); - const handleSubmit = (e: React.SubmitEvent) => { + const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - setPagination({ - ...pagination, - pageIndex: 0, - }); - setSearchParams({ - ...searchParams, + setParams({ keywordType, keyword, userStateCode, @@ -122,6 +140,7 @@ function UsersPage() { ? dayjs(dateRange.from).format("YYYYMMDD") : "", toDateYmd: dateRange?.to ? dayjs(dateRange.to).format("YYYYMMDD") : "", + page: 0, }); }; @@ -131,20 +150,12 @@ function UsersPage() { setUserStateCode(""); setAprvYn(""); setGrpId(""); + setPresetDateRange(""); setDateRange({ from: undefined, to: undefined, }); - setSearchParams({ - ...searchParams, - keywordType: "all", - keyword: "", - userStateCode: "", - aprvYn: "", - grpId: "", - frDateYmd: "", - toDateYmd: "", - }); + resetParams(); }; const handlePresetDateRange = (value: string) => { @@ -351,12 +362,9 @@ function UsersPage() {

회원 목록

{ field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly className={readOnlyInputClass} /> @@ -416,15 +480,14 @@ export default function CoMatRvw() { control={form.control} name="wntUntprc" render={({ field }) => ( - + { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly className={readOnlyInputClass} /> @@ -440,7 +503,7 @@ export default function CoMatRvw() { control={form.control} name="grssClfg" render={({ field }) => ( - +
@@ -480,7 +546,7 @@ export default function CoMatRvw() { type="text" className={`w-full pr-16 border py-2 text-right rounded-md ${readOnlyInputClass}`} placeholder="" - value={field.value ?? ""} + value={formatNumberWithComma(field.value)} readOnly /> @@ -504,7 +570,7 @@ export default function CoMatRvw() { placeholder="" className={`w-full pr-16 border py-2 text-right rounded-md ${readOnlyInputClass}`} type="text" - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly /> @@ -532,7 +598,7 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(Number(e.target.value)); }} - value={field.value ?? ""} + value={formatNumberWithComma(field.value)} readOnly /> @@ -574,7 +640,7 @@ export default function CoMatRvw() { className={`w-full pr-16 border py-2 text-right rounded-md ${readOnlyInputClass}`} type="text" step="0.1" - value={field.value ?? ""} + value={formatNumberWithComma(field.value)} readOnly /> @@ -601,7 +667,7 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly /> @@ -628,7 +694,7 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly /> @@ -655,7 +721,7 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly />
@@ -679,7 +745,7 @@ export default function CoMatRvw() { onChange={(e) => { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly /> @@ -701,12 +767,12 @@ export default function CoMatRvw() {
{ field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={formatNumberWithComma(field.value)} readOnly /> diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx index cc892b6d1..84f6ad87e 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/htdflReg/page.tsx @@ -154,6 +154,7 @@ export default function Home() { onPageChange={setPageNation} index={htdfTableIndex} resetPageNo={resetPageNo} + widthFixed={true} > diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx index 75d718411..349e8be98 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -31,7 +31,6 @@ import { btnClass } from "@/app/store/common/code"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components"; import { useCallback, useEffect, useRef, useState } from "react"; import ListDiv from "@common/business_components/ui/list_div"; -import { tableData } from "@/components/lib/func/common"; import type { customPbnst, fcBizType, @@ -56,7 +55,6 @@ import { useAlertStore } from "@/src/shared/lib"; export default function PublicReuseFaciltyInsert() { const { auth, - code, pbnst, pubHasuInit, pbnstInsert, @@ -112,11 +110,11 @@ export default function PublicReuseFaciltyInsert() { useInitRef.current = true; }, []); - useEffect(() => { - if (useInitRef.current == true && laeSeCd !== undefined) { - pubHasuInit("1", laeSeCd); //page: string, sggOrCity: string - } - }, [useInitRef.current, laeSeCd]); + // useEffect(() => { + // if (useInitRef.current == true && laeSeCd !== undefined) { + // pubHasuInit(1, laeSeCd); + // } + // }, [useInitRef.current, laeSeCd]); const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { const data = writeRgtrAndMdfr(valuse.items); @@ -128,6 +126,13 @@ export default function PublicReuseFaciltyInsert() { const pbnst = data.map((fclt) => { return { pbnstRuseFcltId: fclt.pbnstRuseFcltId, + swtrmtFcltId: fclt.swtrmtFcltId, + swageTrtmfctId: fclt.swageTrtmfctId, + swageBscFctNm: fclt.swageBscFctNm, + swageRgnCd: fclt.swageRgnCd, + swageAdstDstrCd: fclt.swageAdstDstrCd, + swageRvbsnCd: fclt.swageRvbsnCd, + swageFctCpc: fclt.swageFctCpc, fcltCpct: fclt.fcltCpct, ruseCpct: fclt.ruseCpct, splyExtraCpct: fclt.splyExtraCpct, @@ -156,7 +161,7 @@ export default function PublicReuseFaciltyInsert() { message += "하수재이용 시설 사업 "; } alert(message + "오류 입니다 "); - pubHasuInit("1", laeSeCd); + pubHasuInit(1, laeSeCd); } }; if (await confirm(t("isUpdatetMsg"))) { @@ -233,10 +238,12 @@ export default function PublicReuseFaciltyInsert() { }, [items]); useEffect(() => { - if (code.sggCd.length && pbnstHasuRes.length > 0) { - setbdstTable(tableData(pbnstHasuRes, { code })); + if (pbnstHasuRes.length > 0) { + setbdstTable(pbnstHasuRes); + } else { + setbdstTable([]); } - }, [code, pbnstHasuRes]); + }, [pbnstHasuRes]); const cellClick = (val: number | undefined) => { if (val === undefined) return; @@ -288,7 +295,8 @@ export default function PublicReuseFaciltyInsert() { }, [pbnstRes, append, selectRow]); useEffect(() => { - pubHasuInit(String(pageNation), laeSeCd); // 해당 지자체의 하수처리시설 조회 + if (laeSeCd === undefined) return; + pubHasuInit(pageNation, laeSeCd); // 해당 지자체의 하수처리시설 조회 isResetPage(false); setSelectRow(undefined); setSelectedRowIndex(-1); @@ -316,9 +324,9 @@ export default function PublicReuseFaciltyInsert() { // size={"sm"} onClick={() => { if (searchTxt && searchTxt?.length > 0) { - pubHasuSearch(String(pageNation), laeSeCd, searchTxt); + pubHasuSearch(pageNation, laeSeCd, searchTxt); } else { - pubHasuInit(String(pageNation), laeSeCd); + pubHasuInit(pageNation, laeSeCd); } isResetPage(true); }} @@ -368,6 +376,7 @@ export default function PublicReuseFaciltyInsert() { resetSelection={resetSelection} index={selectedRowIndex} curPage={pageNation} + widthFixed={true} /> @@ -454,6 +463,12 @@ export default function PublicReuseFaciltyInsert() { void (async () => { const message = await pbnstInsert(data); alert(message); + + if (searchTxt && searchTxt.trim().length > 0) { + await pubHasuSearch(pageNation, laeSeCd, searchTxt); + } else { + await pubHasuInit(pageNation, laeSeCd); + } })(); setIsRuseReg({ isModal: false }); } diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx index f61697e7e..3f64e42c6 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx @@ -5,7 +5,13 @@ export function createDefaultPbnstItem(row: pubHasuType, index: number) { return JSON.parse(JSON.stringify({ pbnstRuseFcltId: pk, - swtrmtFcltId: "", + swtrmtFcltId: row.bscFctCd ||"", + swageTrtmfctId: row.bscFctCd || "", + swageBscFctNm: row.bscFctNm || "", + swageRgnCd: row.rgnCd || "", + swageAdstDstrCd: row.adstDstrCd || "", + swageRvbsnCd: row.rvbsnCd || "", + swageFctCpc: Number(row.fctCpc) || 0, ruseUtztnFcltNm: "", fcltCpct: 0, ruseCpct: 0, @@ -44,4 +50,4 @@ export function createDefaultPbnstItem(row: pubHasuType, index: number) { cycl, // 필요한 값 있으면 여기에 추가 } as fcBizType; - } \ No newline at end of file + } diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx index 45fb636c6..cdbee61c3 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -167,6 +167,7 @@ export default function Home() { onPageChange={setPageNation} index={rainTableIndex} resetPageNo={resetPageNo} + widthFixed={true} > diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx index a4fa9b97b..b8e7e7727 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -171,6 +171,7 @@ export default function Home() { onPageChange={setPageNation} index={rswtTableIndex} resetPageNo={resetPageNo} + widthFixed={true} > diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx index a481f66a1..d9ca92126 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx @@ -39,18 +39,15 @@ export default function PbnstSttn() { auth, code, pbnstSttn, - pbnstSttnSearch, - pbnSttnInit, + pbnstSttnList, getPbnStnDetail, - getFlcts, // 하수재이용시설(tb_wr_pbnst_ruse_fclt) 조회 resetPbnstDetail, getLaeSeCdCheck, } = useWrStore((state) => state); - const { pbnstSttnRes, fclts, pbnstSttnResCount } = pbnstSttn; + const { pbnstSttnRes, pbnstSttnResCount } = pbnstSttn; const { laeSeCd } = auth; // 지자체구분코드 - const [isReset, setIsReset] = useState(false); const ref = useRef({} as ReturnType); const [searchYear, setSearchYear] = useState( String(new Date().getFullYear()) @@ -66,7 +63,7 @@ export default function PbnstSttn() { const [pbnRuseNm, setPbnRuseNm] = useState(""); const { t } = useTranslation("base"); const alert = useAlertStore((state) => state.setMessage); - const isAllAreaUser = laeSeCd === "0"; // 모든 지자체 권한이 있는 경우 + const isAllAreaUser = laeSeCd?.length != 5; // 모든 지자체 권한이 있는 경우 const fixedSidoValue = !isAllAreaUser && laeSeCd?.length ? laeSeCd.slice(0, 2) : ""; const fixedSigunValue = @@ -110,16 +107,16 @@ export default function PbnstSttn() { const excelClick = useCallback(() => { isDownloadTriggered.current = true; const fixedSearchValue = getFixedSearchValue(ref.current); - pbnstSttnSearch( + pbnstSttnList( true, String(1), "100000", fixedSearchValue, pbnRuseNm, searchYear, - fclts + [] ); - }, [pbnstSttnSearch, fclts, pbnRuseNm, searchYear, getFixedSearchValue]); + }, [pbnstSttnList, pbnRuseNm, searchYear, getFixedSearchValue]); const cellCLick = useCallback( (index: number | undefined) => { @@ -137,16 +134,29 @@ export default function PbnstSttn() { }, []); useEffect(() => { - if (!pbnstSttn.isInit) { - getFlcts(); // 하수재이용시설 조회 + if ( + useInitRef.current === true && + laeSeCd !== undefined && + !pbnstSttn.isTableLoaded + ) { + pbnstSttnList( + false, + "1", + String(DEFAULT_LIST_SIZE), + getFixedSearchValue(ref.current), + pbnRuseNm, + searchYear, + [] + ); } - }, [pbnstSttn.isInit]); - - useEffect(() => { - if (useInitRef.current === true && laeSeCd !== undefined && fclts.length > 0) { - pbnSttnInit("1", String(DEFAULT_LIST_SIZE), getFixedSearchValue(ref.current), searchYear, fclts); - } - }, [fclts, laeSeCd, searchYear, pbnSttnInit, getFixedSearchValue]); + }, [ + laeSeCd, + pbnstSttn.isTableLoaded, + pbnRuseNm, + searchYear, + pbnstSttnList, + getFixedSearchValue, + ]); useEffect(() => { if (pbnstSttnRes && pbnstSttnRes.length > 0) { @@ -200,11 +210,9 @@ export default function PbnstSttn() { : code.cityCd } selectSigunData={ - !isAllAreaUser && laeSeCd?.length === 5 + laeSeCd?.length === 5 ? code.sggCd.filter((item) => item.val === laeSeCd) - : !isAllAreaUser && laeSeCd?.length === 2 - ? code.sggCd.filter((item) => item.val.slice(0, 2) === laeSeCd) - : code.sggCd + : code.sggCd } selectRegionData={code.rvbsnCd} selectUnitWaterShedData={code.lgbsnCd} @@ -251,16 +259,15 @@ export default function PbnstSttn() { } queryClick={() => { const fixedSearchValue = getFixedSearchValue(ref.current); - pbnstSttnSearch( + pbnstSttnList( false, "1", String(DEFAULT_LIST_SIZE), fixedSearchValue, pbnRuseNm, searchYear, - fclts + [] ); - setIsReset(true); }} excelClick={excelClick} initClick={function (): void { @@ -290,18 +297,16 @@ export default function PbnstSttn() { }} onPageChange={(page: number) => { const fixedSearchValue = getFixedSearchValue(ref.current); - pbnstSttnSearch( + pbnstSttnList( false, String(page), String(DEFAULT_LIST_SIZE), fixedSearchValue, pbnRuseNm, searchYear, - fclts + [] ); - setIsReset(false); }} - resetPageNo={isReset} widthFixed={true} > diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx index c1e9fb141..3d87dbbbf 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -60,6 +60,11 @@ export default function RainSttn() { }>({ data: undefined, isOpen: false }); const [fcltNm, setFcltNm] = useState(""); + const [appliedSearch, setAppliedSearch] = useState({ + conValue: "0", + fcltNm: "", + }); + const [searchTrigger, setSearchTrigger] = useState(0); const { t } = useTranslation("base"); const alert = useAlertStore((state) => state.setMessage); const skipNextSearchRef = useRef(true); @@ -142,16 +147,27 @@ export default function RainSttn() { return; } + const initialConValue = + laeSeCd === undefined || laeSeCd === "0" + ? "0" + : laeSeCd.length === 5 + ? laeSeCd + : laeSeCd.slice(0, 2); + skipNextSearchRef.current = true; + setAppliedSearch({ + conValue: initialConValue, + fcltNm: "", + }); rainSttnInit( false, 1, rainSttnSize, - getFixedConValue(), - fcltNm, + initialConValue, + "", code as unknown as Record ); - }, [rainSttn.isInit, rainSttnInit, fcltNm, code, getFixedConValue, isLaeSeCdReady]); + }, [rainSttn.isInit, rainSttnInit, code, isLaeSeCdReady, laeSeCd]); useEffect(() => { if (!isLaeSeCdReady) { @@ -163,16 +179,28 @@ export default function RainSttn() { return; } + if (searchTrigger === 0) { + return; + } + rainSttnSearch( false, pageNation, rainSttnSize, - String(getFixedConValue()), - fcltNm, + appliedSearch.conValue, + appliedSearch.fcltNm, code as unknown as Record ); isResetPage(false); - }, [pageNation, rainSttnSearch, fcltNm, code, getFixedConValue, isLaeSeCdReady]); + }, [ + pageNation, + searchTrigger, + rainSttnSearch, + code, + appliedSearch.conValue, + appliedSearch.fcltNm, + isLaeSeCdReady, + ]); useEffect(() => { if (!isLaeSeCdReady) { @@ -212,19 +240,31 @@ export default function RainSttn() { true, 1, rainSttnResCount, - String(getFixedConValue()), - fcltNm, + appliedSearch.conValue, + appliedSearch.fcltNm, code as unknown as Record ); }, [ rainSttnSearch, - fcltNm, rainSttnResCount, code, - getFixedConValue, + appliedSearch.conValue, + appliedSearch.fcltNm, isLaeSeCdReady, ]); + const handleSearch = useCallback(() => { + const nextSearch = { + conValue: String(getFixedConValue()), + fcltNm, + }; + + setAppliedSearch(nextSearch); + isResetPage(true); + setPageNation(1); + setSearchTrigger((prev) => prev + 1); + }, [fcltNm, getFixedConValue]); + useEffect(() => { const data = tableData(rainSttnRes, { code }); const chData = data @@ -318,17 +358,7 @@ export default function RainSttn() {
diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index da953bb43..4e76336c5 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -55,6 +55,11 @@ export default function RswtSttn() { const [objSearch, setObjSearch] = useState({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }) const [fcltNm, setFcltNm] = useState(""); + const [appliedSearch, setAppliedSearch] = useState({ + conValue: "0", + fcltNm: "", + }); + const [searchTrigger, setSearchTrigger] = useState(0); const { t } = useTranslation('base'); const alert = useAlertStore((state) => state.setMessage); const isAllAreaUser = laeSeCd === "0"; @@ -137,16 +142,27 @@ export default function RswtSttn() { return; } + const initialConValue = + laeSeCd === undefined || laeSeCd === "0" + ? "0" + : laeSeCd.length === 5 + ? laeSeCd + : laeSeCd.slice(0, 2); + skipNextSearchRef.current = true; + setAppliedSearch({ + conValue: initialConValue, + fcltNm: "", + }); rswtSttnInit( false, 1, rswtSttnSize, - getFixedConValue(), - fcltNm, + initialConValue, + "", code as unknown as Record ); - }, [rswtSttn.isInit, rswtSttnInit, fcltNm, code, getFixedConValue, isLaeSeCdReady]); + }, [rswtSttn.isInit, rswtSttnInit, code, isLaeSeCdReady, laeSeCd]); useEffect(() => { const data = tableData(rswtSttnRes, { code }); @@ -208,8 +224,8 @@ export default function RswtSttn() { } isDownloadTriggered.current = true; - rswtSttnSearch(true, 1, rswtSttnResCount, String(getFixedConValue()), fcltNm, code as unknown as Record); - }, [rswtSttnSearch, fcltNm, rswtSttnResCount, code, getFixedConValue, isLaeSeCdReady]); + rswtSttnSearch(true, 1, rswtSttnResCount, appliedSearch.conValue, appliedSearch.fcltNm, code as unknown as Record); + }, [rswtSttnSearch, rswtSttnResCount, code, appliedSearch.conValue, appliedSearch.fcltNm, isLaeSeCdReady]); useEffect(() => { if (!isLaeSeCdReady) { @@ -221,9 +237,29 @@ export default function RswtSttn() { return; } - rswtSttnSearch(false, pageNation, rswtSttnSize, String(getFixedConValue()), fcltNm, code as unknown as Record); + if (searchTrigger === 0) { + return; + } + + rswtSttnSearch(false, pageNation, rswtSttnSize, appliedSearch.conValue, appliedSearch.fcltNm, code as unknown as Record); isResetPage(false) - }, [pageNation, rswtSttnSearch, fcltNm, code, getFixedConValue, isLaeSeCdReady]); + }, [pageNation, searchTrigger, rswtSttnSearch, code, appliedSearch.conValue, appliedSearch.fcltNm, isLaeSeCdReady]); + + const handleSearch = useCallback(() => { + if (!isLaeSeCdReady) { + return; + } + + const nextSearch = { + conValue: String(getFixedConValue()), + fcltNm, + }; + + setAppliedSearch(nextSearch); + isResetPage(true); + setPageNation(1); + setSearchTrigger((prev) => prev + 1); + }, [fcltNm, getFixedConValue, isLaeSeCdReady]); return ( <> @@ -279,13 +315,7 @@ export default function RswtSttn() {
diff --git a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index ee2e776ba..ac3c72bc1 100644 --- a/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/(with-layout)/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -1,5 +1,8 @@ "use client"; +/** + * 재이용실적 현황 > 지도점검 현황 + */ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import { rainPageSize } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; diff --git a/apps/wr/app/api/common-codes/route.ts b/apps/wr/app/api/common-codes/route.ts new file mode 100644 index 000000000..ae0c175cd --- /dev/null +++ b/apps/wr/app/api/common-codes/route.ts @@ -0,0 +1,219 @@ +export const dynamic = "force-dynamic"; +import { SITE_ID } from "@/src/shared/config"; +import { NextResponse } from "next/server"; + +export const revalidate = 86400; //60 * 60 * 24; + +type SelectDataType = { + text: string; + val: string; +}; + +type EnvPartSelectDataType = SelectDataType & { + adstDliStrCd: string; +}; + +const codeMapping = { + WR001: "bdstUsgCd", + WR002: "rswtBdstType", + WR003: "rainFcltCd", + WR004: "bdstGrntchClass", + WR005: "rswtPrscCdMthdCd", + WR006: "orgwtKndCd", + WR007: "ruseMngMtd", + WR008: "rusePrcsMthdCd", + WR009: "erctUswtrPrcsMeth", + WR010: "ruseFcltSpot", + WR011: "pplQulity", + WR012: "pplLenght", + WR013: "bdstFilterYn", + WR014: "rainRswtMng", + WR015: "rainFcltFlowRate", + WR016: "dmdUszCd", + WR017: "sewageInFcltUse", + WR018: "sewageOutFclttUse", + WR019: "htdPowerMthdCd", + WR020: "htdUtztnUsgCd", +} as const; + +const defaultHeaders = { + accept: "application/json", + "X-Site-Id": SITE_ID, +}; + +function getServerBaseUrl() { + const port = process.env.PORT ?? process.env.NEXT_PUBLIC_PORT ?? "3000"; + const proxyHost = process.env.NEXT_PUBLIC_PROXY_HOST; + + if (process.env.NODE_ENV === "production" && process.env.HOSTNAME) { + return `http://${process.env.HOSTNAME}:${port}`; + } + + return proxyHost || `http://localhost:${port}`; +} + +async function fetchJson(url: string, cookieHeader?: string) { + const response = await fetch(url, { + method: "GET", + headers: { + ...defaultHeaders, + ...(cookieHeader ? { cookie: cookieHeader } : {}), + }, + next: { revalidate }, + }); + + if (!response.ok) { + const responseText = await response.text(); + throw new Error( + `Failed to fetch ${url}: ${response.status} ${response.statusText}${ + responseText ? ` - ${responseText}` : "" + }` + ); + } + + return response.json(); +} + +async function fetchOperationData(path: string, cookieHeader?: string) { + const json = await fetchJson( + `${getServerBaseUrl()}/operation-service${path}`, + cookieHeader + ); + return json.data; +} + +async function fetchCmsData(path: string, cookieHeader?: string) { + return fetchJson(`${getServerBaseUrl()}${path}`, cookieHeader); +} + +async function fetchCommonCodesByKeys(keys: string[], cookieHeader?: string) { + const targets = [...new Set(keys)].filter( + (cd) => Boolean(codeMapping[cd as keyof typeof codeMapping]) + ); + + const entries = await Promise.all( + targets.map(async (cd) => { + const mapping = codeMapping[cd as keyof typeof codeMapping]; + const lwCd = await fetchCmsData( + `/cms-service/api/v1/lwpo-cds/up-cd/${cd}`, + cookieHeader + ); + const list = Array.isArray(lwCd) ? lwCd : (lwCd.content ?? []); + + return [ + mapping, + list.map((it: any) => ({ + text: it.lwpoCdNm, + val: it.lwpoCd, + })), + ] as const; + }) + ); + + return Object.fromEntries(entries) as Record; +} + +export async function GET(request: Request) { + try { + const cookieHeader = request.headers.get("cookie") ?? ""; + const [sgg, city, rvbsn, mdmbsn, lgbsn, lclgvrnmnt, upCd] = + await Promise.all([ + fetchOperationData("/addr/sgg", cookieHeader), + fetchOperationData("/addr/city", cookieHeader), + fetchOperationData("/addr/sarea", cookieHeader), + fetchOperationData("/addr/midArea", cookieHeader), + fetchOperationData("/addr/largeArea", cookieHeader), + fetchOperationData("/addr/govArea", cookieHeader), + fetchCmsData( + "/cms-service/api/v1/up-codes?keyword=&upCd=&cdSe=&useYn=Y&siteId=WR&page=0&size=100&sort=string", + cookieHeader + ), + ]); + + const upWrCode: string[] = (upCd.content ?? []) + .filter((item: any) => item.upCd.slice(0, 2) === "WR") + .map((cd: any) => cd.upCd); + + const lwCds = await fetchCommonCodesByKeys(upWrCode, cookieHeader); + + const payload = { + sggCd: [ + ...((sgg ?? []).map((item: any) => ({ + text: item.gugun || "", + val: String(item.adstDstrCd) || "", + })) as SelectDataType[]), + ], + cityCd: [ + { val: "0", text: "전체" }, + ...((city ?? []).map((item: any) => ({ + val: item.adstDstrCd, + text: item.sido, + })) as SelectDataType[]), + ], + rvbsnCd: [ + { val: "0", text: "전체" }, + ...((rvbsn ?? []).map((item: any) => ({ + val: item.rvbsnCd, + text: item.rvbsn, + })) as SelectDataType[]), + ], + mdmbsnCd: [ + { val: "0", text: "전체" }, + ...((mdmbsn ?? []).map((item: any) => ({ + val: item.rvbsnCd, + text: item.mdmbsn, + })) as SelectDataType[]), + ], + lgbsnCd: [ + { val: "0", text: "전체" }, + ...((lgbsn ?? []).map((item: any) => ({ + val: item.rvbsnCd, + text: item.lgbsn, + })) as SelectDataType[]), + ], + lclgvrnmntCd: [ + { val: "0", text: "전체", adstDliStrCd: "" }, + ...((lclgvrnmnt ?? []).map((item: any) => ({ + val: item.lclgvrnmntCd, + text: item.lclgvrnmntNm, + adstDliStrCd: item.adstDliStrCd || "", + })) as EnvPartSelectDataType[]), + ], + rainFcltCd: lwCds["rainFcltCd"] ?? [], + bdstUsgCd: lwCds["bdstUsgCd"] ?? [], + orgwtKndCd: lwCds["orgwtKndCd"] ?? [], + pplQulity: lwCds["pplQulity"] ?? [], + pplLenght: lwCds["pplLenght"] ?? [], + dmdUszCd: lwCds["dmdUszCd"] ?? [], + sewageOutFclttUse: lwCds["sewageOutFclttUse"] ?? [], + rainRswtMng: lwCds["rainRswtMng"] ?? [], + rainFcltFlowRate: lwCds["rainFcltFlowRate"] ?? [], + ruseMngMtd: lwCds["ruseMngMtd"] ?? [], + rusePrcsMthdCd: lwCds["rusePrcsMthdCd"] ?? [], + erctUswtrPrcsMeth: lwCds["erctUswtrPrcsMeth"] ?? [], + bdstGrntchClass: lwCds["bdstGrntchClass"] ?? [], + htdPowerMthdCd: lwCds["htdPowerMthdCd"] ?? [], + htdUtztnUsgCd: lwCds["htdUtztnUsgCd"] ?? [], + rswtBdstType: lwCds["rswtBdstType"] ?? [], + bdstTotalUsgType: (lwCds["bdstUsgCd"] ?? []).concat(lwCds["rswtBdstType"] ?? []), + }; + + return NextResponse.json(payload, { + headers: { + "Cache-Control": "s-maxage=86400, stale-while-revalidate=3600", + }, + }); + } catch (error) { + console.error("Failed to load common codes:", error); + const message = + error instanceof Error ? error.message : "Failed to load common codes"; + + return NextResponse.json( + { + message: "Failed to load common codes", + detail:message , + }, + { status: 500 } + ); + } +} diff --git a/apps/wr/app/api/proxy/[...url]/route.ts b/apps/wr/app/api/proxy/[...url]/route.ts index e847e8ad2..d779aec83 100644 --- a/apps/wr/app/api/proxy/[...url]/route.ts +++ b/apps/wr/app/api/proxy/[...url]/route.ts @@ -75,7 +75,7 @@ async function handler( if (refreshToken) { response.cookies.set(REFRESH_TOKEN, refreshToken, { httpOnly: true, - sameSite: "strict", // 다른 사이트에서 들어오는 모든 요청에 대해 쿠키를 보내지 않는 가장 강력한 설정 + sameSite: "lax", // 다른 사이트에서 들어오는 모든 요청에 대해 쿠키를 보내지 않는 가장 강력한 설정 domain: getCookieDomain(), path: "/", }); diff --git a/apps/wr/app/store/common/auth/index.tsx b/apps/wr/app/store/common/auth/index.tsx index feca57c80..fe99a02ae 100644 --- a/apps/wr/app/store/common/auth/index.tsx +++ b/apps/wr/app/store/common/auth/index.tsx @@ -32,7 +32,7 @@ export const authStateExport: authState = { export type authActions = { getMenuAuthrts: (menuCd: number) => void; - getLaeSeCdCheck: () => Promise; + getLaeSeCdCheck: () => Promise; // 로그인 사용자 지역코드 laeSeCd를 조회 후 상태 update getMyUUID: () => Promise; }; export const authActionsExport: (set: any, get: any) => authActions = ( @@ -52,10 +52,10 @@ export const authActionsExport: (set: any, get: any) => authActions = ( auth: { ...state.auth, mngAuthrtYn: response[0].mngAuthrtYn, - inqAuthrtYn: response[0].mngAuthrtYn, - regAuthrtYn: response[0].mngAuthrtYn, - mdfcnAuthrtYn: response[0].mngAuthrtYn, - delAuthrtYn: response[0].mngAuthrtYn, + inqAuthrtYn: response[0].inqAuthrtYn, + regAuthrtYn: response[0].regAuthrtYn, + mdfcnAuthrtYn: response[0].mdfcnAuthrtYn, + delAuthrtYn: response[0].delAuthrtYn, }, }; }); diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index adcff57f2..5e6600960 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -21,12 +21,12 @@ const codeMApping = { WR002: "rswtBdstType", WR003: "rainFcltCd", WR004: "bdstGrntchClass", - WR005: "rswtPrscCdMthdCd", // 아직 디 못바꿈 - WR006: "orgwtKndCd", //작업 완ㅛ - WR007: "ruseMngMtd", // 작업완료 - WR008: "rusePrcsMthdCd", //w작업완료 - WR009: "erctUswtrPrcsMeth", //w작업완료 - WR010: "ruseFcltSpot", // inout은 yn 만 사용해야 함으로 해당 코드는 사용안함. + WR005: "rswtPrscCdMthdCd", + WR006: "orgwtKndCd", + WR007: "ruseMngMtd", + WR008: "rusePrcsMthdCd", + WR009: "erctUswtrPrcsMeth", + WR010: "ruseFcltSpot", WR011: "pplQulity", WR012: "pplLenght", WR013: "bdstFilterYn", // 사용 불가 yn만 사용해야함으로 해당코드 사용 안함 @@ -312,6 +312,7 @@ export type comCodeActions = { returnCodeText: (val: string, codeName: string) => string; returnTextCode: (text: string, codeName: string) => string; getCommonCodesByKeys: (keys: string[]) => Promise; + initCommonCodes: () => Promise; }; export const codeActionExport: (set: any, get:any) => comCodeActions = (set: any, get:any) => { @@ -368,5 +369,102 @@ export const codeActionExport: (set: any, get:any) => comCodeActions = (set: any const found = codeList.find((item) => item.text === text); return found ? found.val : text; }, + initCommonCodes: async () => { + if (get().code.isInit) return; + const response = await fetch("/api/common-codes", { + method: "GET", + headers: { + accept: "application/json", + }, + }); + + if (!response.ok) { + let errorMessage = `공통 코드 조회 실패: ${response.status}`; + + try { + const errorBody = await response.json(); + if (errorBody?.detail) { + errorMessage += ` - ${errorBody.detail}`; + } else if (errorBody?.message) { + errorMessage += ` - ${errorBody.message}`; + } + } catch { + const errorText = await response.text(); + if (errorText) { + errorMessage += ` - ${errorText}`; + } + } + + console.error("initCommonCodes failed:", errorMessage); + throw new Error(errorMessage); + } + + const data = await response.json(); + + lwCds["rainFcltCd"] = data.rainFcltCd ?? lwCds["rainFcltCd"] ?? []; + lwCds["bdstUsgCd"] = data.bdstUsgCd ?? lwCds["bdstUsgCd"] ?? []; + lwCds["orgwtKndCd"] = data.orgwtKndCd ?? lwCds["orgwtKndCd"] ?? []; + lwCds["pplQulity"] = data.pplQulity ?? lwCds["pplQulity"] ?? []; + lwCds["pplLenght"] = data.pplLenght ?? lwCds["pplLenght"] ?? []; + lwCds["dmdUszCd"] = data.dmdUszCd ?? lwCds["dmdUszCd"] ?? []; + lwCds["sewageOutFclttUse"] = + data.sewageOutFclttUse ?? lwCds["sewageOutFclttUse"] ?? []; + lwCds["rainRswtMng"] = data.rainRswtMng ?? lwCds["rainRswtMng"] ?? []; + lwCds["rainFcltFlowRate"] = + data.rainFcltFlowRate ?? lwCds["rainFcltFlowRate"] ?? []; + lwCds["ruseMngMtd"] = data.ruseMngMtd ?? lwCds["ruseMngMtd"] ?? []; + lwCds["rusePrcsMthdCd"] = + data.rusePrcsMthdCd ?? lwCds["rusePrcsMthdCd"] ?? []; + lwCds["erctUswtrPrcsMeth"] = + data.erctUswtrPrcsMeth ?? lwCds["erctUswtrPrcsMeth"] ?? []; + lwCds["bdstGrntchClass"] = + data.bdstGrntchClass ?? lwCds["bdstGrntchClass"] ?? []; + lwCds["htdPowerMthdCd"] = + data.htdPowerMthdCd ?? lwCds["htdPowerMthdCd"] ?? []; + lwCds["htdUtztnUsgCd"] = + data.htdUtztnUsgCd ?? lwCds["htdUtztnUsgCd"] ?? []; + lwCds["rswtBdstType"] = + data.rswtBdstType ?? lwCds["rswtBdstType"] ?? []; + lwCds["bdstTotalUsgType"] = + data.bdstTotalUsgType ?? lwCds["bdstTotalUsgType"] ?? []; + + set((state) => ({ + code: { + ...state.code, + sggCd: data.sggCd ?? state.code.sggCd, + cityCd: data.cityCd ?? state.code.cityCd, + rvbsnCd: data.rvbsnCd ?? state.code.rvbsnCd, + mdmbsnCd: data.mdmbsnCd ?? state.code.mdmbsnCd, + lgbsnCd: data.lgbsnCd ?? state.code.lgbsnCd, + lclgvrnmntCd: data.lclgvrnmntCd ?? state.code.lclgvrnmntCd, + rainFcltCd: data.rainFcltCd ?? state.code.rainFcltCd, + bdstUsgCd: data.bdstUsgCd ?? state.code.bdstUsgCd, + orgwtKndCd: data.orgwtKndCd ?? state.code.orgwtKndCd, + pplQulity: data.pplQulity ?? state.code.pplQulity, + pplLenght: data.pplLenght ?? state.code.pplLenght, + dmdUszCd: data.dmdUszCd ?? state.code.dmdUszCd, + sewageOutFclttUse: + data.sewageOutFclttUse ?? state.code.sewageOutFclttUse, + rainRswtMng: data.rainRswtMng ?? state.code.rainRswtMng, + rainFcltFlowRate: + data.rainFcltFlowRate ?? state.code.rainFcltFlowRate, + ruseMngMtd: data.ruseMngMtd ?? state.code.ruseMngMtd, + rusePrcsMthdCd: + data.rusePrcsMthdCd ?? state.code.rusePrcsMthdCd, + erctUswtrPrcsMeth: + data.erctUswtrPrcsMeth ?? state.code.erctUswtrPrcsMeth, + bdstGrntchClass: + data.bdstGrntchClass ?? state.code.bdstGrntchClass, + htdPowerMthdCd: + data.htdPowerMthdCd ?? state.code.htdPowerMthdCd, + htdUtztnUsgCd: + data.htdUtztnUsgCd ?? state.code.htdUtztnUsgCd, + rswtBdstType: data.rswtBdstType ?? state.code.rswtBdstType, + bdstTotalUsgType: + data.bdstTotalUsgType ?? state.code.bdstTotalUsgType, + isInit: true, + }, + })); + }, }; }; diff --git a/apps/wr/app/store/map/pbnstMap/index.tsx b/apps/wr/app/store/map/pbnstMap/index.tsx index 18f9abfe2..80eb2697a 100644 --- a/apps/wr/app/store/map/pbnstMap/index.tsx +++ b/apps/wr/app/store/map/pbnstMap/index.tsx @@ -9,13 +9,15 @@ import { excelHasuMapParsing } from "./excel"; export const pbnMapTableSize = 20; const hasuListFetch = async ( + get: any, + set: any, page: number, pageTotal: number, reurnValue: ReturnType, searchNm?: string ) => { let url = `/prcsFclt/ruseInfo/${page}/${pageTotal}/`; - const checkWrRegListRes = await checkWrRegList(); + const checkWrRegListRes = await checkWrRegList(get, set); if (reurnValue.partValue === "A") { url += `${reurnValue.partValue}/${ @@ -92,7 +94,7 @@ export const pbnMapStateExport: pbnMapState = { }, }; -export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => { +export const pbnMapActionsExport: (set: any, get: any) => pbnMapActions = (set: any, get: any) => { return { pbnMapInit: async ( page: number, @@ -100,7 +102,7 @@ export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => { reurnValue: ReturnType ) => { try { - const pubMapRes = await hasuListFetch(page, pageTotal, reurnValue); + const pubMapRes = await hasuListFetch(get, set, page, pageTotal, reurnValue); set((state: pbnMapState) => { return { ...state, @@ -144,7 +146,7 @@ export const pbnMapActionsExport: (set: any) => pbnMapActions = (set: any) => { txt: string, ) => { try { - const hasuMapRes = await hasuListFetch(page, pageTotal, reurnValue, txt); + const hasuMapRes = await hasuListFetch(get, set, page, pageTotal, reurnValue, txt); if (isExcel) { const hasuMapExcelList = excelHasuMapParsing( hasuMapRes diff --git a/apps/wr/app/store/matDmd/coMatRvw/index.tsx b/apps/wr/app/store/matDmd/coMatRvw/index.tsx index b347a1df8..afeb36fc1 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/index.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/index.tsx @@ -1,4 +1,5 @@ import { fetchType, getFetchWithCount, putFectch } from "@/components/lib/api"; +import { DEFAULT_LIST_SIZE } from "@/src/shared/config"; import type { CommonTableProps } from "../../common/type/header"; import { constCostHeadListExport, @@ -12,6 +13,7 @@ const coRvwHeadList = coRvwHeadListExport; const coRvwNodeList = coRvwNodeListExport; const rateFeeHeadList = rateFeeHeadListExport; const constCostHeadList = constCostHeadListExport; + export type coRvwState = { coRvw: { isInit: boolean; @@ -118,7 +120,7 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { const coMatRvwRes = await coMatInit( 1, - 10, + DEFAULT_LIST_SIZE, new Date().getFullYear().toString(), new Date().getFullYear().toString() ); diff --git a/apps/wr/app/store/matDmd/coMatRvw/type.tsx b/apps/wr/app/store/matDmd/coMatRvw/type.tsx index d195953cd..a505777ff 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/type.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/type.tsx @@ -75,8 +75,8 @@ export const DmdCoReqSchema = z.object({ dmndTmng: z.coerce.date().nullish(), // 요구시기 dmndQty: z.number().nullish(), // 요구수량(m³/일) blgcOxygDmndQnt: z.number().nullish(), // 생물학적 산소요구량(BOD)(mg/L) - wntUntprc: z.number().nullish(), // 희망단가(원/m3) - grssClfg: z.number().nullish(), // 총대장균군수(개/mg) + wntUntprc: z.number().nullish(), // 희망단가(원/m³) + grssClfg: z.number().nullish(), // 총대장균군수(개/100㎖) combResdch: z.number().nullish(), // 결합잔류염소(mg/L) trbt: z.number().nullish(), // 탁도(NTU) smll: z.string().nullish(), // 냄새 diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx index 538135d0a..c70b821af 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -124,7 +124,7 @@ export const rainMainHeadNmExport: chHeadType[] = [ export const rainRuseHeadNmExport: chHeadType[] = [ { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, - { headNm: "ruseWater", text: "연간대체수 이용량(m³)", length: 13 }, + { headNm: "ruseWater", text: "연간빗물이용량(m³)", length: 13 }, { headNm: "detailQulity", text: "분기", length: 11 }, ]; @@ -133,7 +133,7 @@ export const rainSplHeadNmExport: chHeadType[] = [ { headNm: "useQuilty", text: "이용수질(필요시)", length: 3 }, { headNm: "feeHist", text: "과태료 부과내역", length: 3 }, { headNm: "detailQulity", text: "분기", length: 11 }, - { headNm: "splWater", text: "연간빗물 이용량(m³)", length: 13 }, + { headNm: "splWater", text: "연간대체수이용량(m³)", length: 13 }, ]; export const rainChkgdnHeadListExport: TableUpperProps[] = [ @@ -152,7 +152,7 @@ export const rainChkgdnHeadListExport: TableUpperProps[] = [ { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)", widthPercent: 7 }, { id: "ph", title: "수소이온농도(pH)", upName: "useQuilty", upSequnce: 1, type: "number", edit: true, widthPercent: 5 }, { id: "trbt", title: "탁도(NTU)", upName: "useQuilty", upSequnce: 2, type: "number", edit: true, widthPercent: 4 }, - { id: "grssClfg", title: "총대장균군수(개/mg)", upName: "useQuilty", upSequnce: 3, type: "number", edit: true, widthPercent: 5 }, + { id: "grssClfg", title: "총대장균군수(개/100㎖)", upName: "useQuilty", upSequnce: 3, type: "number", edit: true, widthPercent: 5 }, { id: "vltnDt", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1, type: "text", edit: true, widthPercent: 5 }, { id: "vltnMttr", title: "위반사항", upName: "feeHist", upSequnce: 2, type: "text", edit: true, widthPercent: 6 }, { id: "levyAmt", title: "부과금액(천원)", upName: "feeHist", upSequnce: 3, type: "text", edit: true, widthPercent: 5 }, diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx index 9a8b65ced..7cba87e82 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx @@ -149,7 +149,7 @@ export const rswtChkHeadListExport: TableUpperProps[] = [ { id: "utztnUsgCdText", title: "이용용도", widthPercent: 7 }, { id: "splyUswtrUtztnQnt", title: "연간대체수이용량(m³)" ,type: "number", widthPercent: 5 }, { id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)",type: "number", widthPercent: 5 }, - { id: "grssClfgUswtr", title: "총대장균군수(개/mg)", upName: "useQuilty", upSequnce: 1 ,type: "number", widthPercent: 6 }, + { id: "grssClfgUswtr", title: "총대장균군수(개/100㎖)", upName: "useQuilty", upSequnce: 1 ,type: "number", widthPercent: 6 }, { id: "combResdch", title: "결합잔류염소(mh/L)", upName: "useQuilty", upSequnce: 2 ,type: "number", widthPercent: 6 }, { id: "trbt", title: "탁도(NTU)", upName: "useQuilty", upSequnce: 3 ,type: "number", widthPercent: 4 }, { id: "bod", title: "BOD\n(mg/L)", upName: "useQuilty", upSequnce: 4 ,type: "number", widthPercent: 4 }, diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx index c45a772e7..48909e20e 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/headList.tsx @@ -15,7 +15,7 @@ export const rainChkgdnHeadSttnExport: TableUpperProps[] = [ { id: "totalRuseFcltUtztnQnt", title: "연간빗물이용량(m³)", widthPercent: 7 }, { id: "ph", title: "수소이온농도(pH)", upName: "useQuilty", upSequnce: 1, type: "number", widthPercent: 5 }, { id: "trbt", title: "탁도(NTU)", upName: "useQuilty", upSequnce: 2, type: "number", widthPercent: 4 }, - { id: "grssClfg", title: "총대장균군수(개/mg)", upName: "useQuilty", upSequnce: 3, type: "number", widthPercent: 5 }, + { id: "grssClfg", title: "총대장균군수(개/100㎖)", upName: "useQuilty", upSequnce: 3, type: "number", widthPercent: 5 }, { id: "vltnDt", title: "부과일(위반일)", upName: "feeHist", upSequnce: 1, type: "text", widthPercent: 5 }, { id: "vltnMttr", title: "위반사항", upName: "feeHist", upSequnce: 2, type: "text", widthPercent: 6 }, diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx index 21a78b07d..6a0a925d2 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/headList.tsx @@ -14,7 +14,7 @@ export const rswtChkSttnHeadListExport: TableUpperProps[] = [ { id: "splyUswtrUtztnQnt", title: "연간보급수이용량(m³)", type: "number", widthPercent: 5 }, { id: "ruseFcltUtztnQnt", title: "연간중수도이용량(m³)", type: "number", widthPercent: 5 }, - { id: "grssClfgUswtr", title: "총대장균군수(개/mg)", upName: "useQuilty", upSequnce: 1, type: "number", widthPercent: 6 }, + { id: "grssClfgUswtr", title: "총대장균군수(개/100㎖)", upName: "useQuilty", upSequnce: 1, type: "number", widthPercent: 6 }, { id: "combResdch", title: "결합잔류염소(mh/L)", upName: "useQuilty", upSequnce: 2, type: "number", widthPercent: 6 }, { id: "trbt", title: "탁도(NTU)", upName: "useQuilty", upSequnce: 3, type: "number", widthPercent: 4 }, { id: "bod", title: "BOD (mg/L)", upName: "useQuilty", upSequnce: 4, type: "number", widthPercent: 4 }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx index 4d0c228be..78b4f22cf 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx @@ -1,10 +1,10 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; export const htdTableHeadList: TableUpperProps[] = [ - { id: "cityText", title: "시도" }, - { id: "sggText", title: "시군구" }, - { id: "bdstNm", title: "시설명" }, - { id: "daddr", title: "위치" }, - { id: "frstArchPrmsnDt", title: "준공년도" }, - { id: "archArea", title: "건축면적(㎡)" }, + { id: "cityText", title: "시도", widthPercent: 12 }, + { id: "sggText", title: "시군구", widthPercent: 10 }, + { id: "bdstNm", title: "시설명", widthPercent: 20 }, + { id: "daddr", title: "위치", widthPercent: 30 }, + { id: "frstArchPrmsnDt", title: "준공년도", widthPercent: 13 }, + { id: "archArea", title: "건축면적(㎡)", widthPercent: 15 }, ]; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx index 5d77c64ca..e1e4adf44 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx @@ -3,14 +3,14 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; export const pubFacHeadListExport: TableUpperProps[] = [ - { id: "sido", title: "시도" }, - { id: "gugun", title: "시군구" }, - { id: "bscFctNm", title: "시설명" }, - { id: "addr", title: "위치" }, - { id: "efflWqltStndrdNm", title: "지역구분" }, - { id: "fctCpc", title: "시설용량(m³/일)" }, - { id: "ruse", title: "재이용여부" }, - { id: "rswtrYn", title: "등록여부" }, + { id: "sido", title: "시도", widthPercent: 8 }, + { id: "gugun", title: "시군구", widthPercent: 8 }, + { id: "bscFctNm", title: "시설명", widthPercent: 18 }, + { id: "addr", title: "위치", widthPercent: 24 }, + { id: "efflWqltStndrdNm", title: "지역구분", widthPercent: 15 }, + { id: "fctCpc", title: "시설용량(m³/일)", widthPercent: 12 }, + { id: "ruse", title: "재이용\n여부", widthPercent: 8 }, + { id: "rswtrYn", title: "등록\n여부", widthPercent: 6 }, ]; export const pbnstMngUpHeadListExport: TableUpperProps[] = [ @@ -151,7 +151,7 @@ export const businessSttnInfo: formDetailType[] = [ export const ruseWaterQulityList: formDetailType[] = [ { id: "bod", lable: "BOD(mg/L)", type: "text", maxLenght:numSize }, - { id: "grssClfg", lable: "총대장균군수(개/mg)", type: "text" , maxLenght:numSize}, + { id: "grssClfg", lable: "총대장균군수(개/100㎖)", type: "text" , maxLenght:numSize}, { id: "combResdch", lable: "결합잔류염소(mh/L)", type: "text" , maxLenght:numSize}, { id: "trbt", lable: "탁도(NTU)", type: "text" , maxLenght:numSize}, { id: "smll", lable: "냄새", type: "text", maxLenght:numSize }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index 6340f1082..0b395d1b3 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -5,6 +5,7 @@ import { getFetch, postFectch, putFectch, + getFetchWithCount } from "@/components/lib/api"; import { DEFAULT_LIST_SIZE, SITE_ID } from "@/src/shared/config"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; @@ -61,10 +62,11 @@ export type pubFacState = { dmdComList: any[]; apiMessage: string; pbnstHasuResCount: number; + fclts: any[] | null; }; }; type pubFacActions = { - pubHasuInit: (page: string, sggOrCity: string) => void; + pubHasuInit: (page: number, sggOrCity: string) => void; pbnstRegClick: (pubHasuRes: pubHasuType) => void; //pbnstReg: (txt: string | undefined) => void; pbnstInsert(pbnstRes: customPbnst): Promise; @@ -73,7 +75,7 @@ type pubFacActions = { fileDownLoadName: (atflCd: string, fileName: string) => void; pbnstRuseFcltUpdate: (ruseRes: customPbnst[]) => void; pbnstRuseBizUpdate: (ruseRes: fcBizType[]) => void; - pubHasuSearch: (page: string, sggOrCity: string, searchTxt: string) => void; + pubHasuSearch: (page: number, sggOrCity: string, searchTxt: string) => void; getFcOrgwts: (fcltPkList: string[], size: number) => void; }; export type pubFacType = pubFacState & pubFacActions; @@ -98,38 +100,59 @@ export const pubFacStateExport: pubFacState = { dmdComList: [], apiMessage: "", pbnstHasuResCount: 1, + fclts: null, }, }; // 재사용시설에 대한 정보 조회 -export const checkWrRegList = async () => { +export const checkWrRegList = async (get: any, set: any) => { + const { pbnst } = get(); + + if (Array.isArray(pbnst.fclts)) { + return pbnst.fclts; + } + const wrRegList = await getFetch("wr", `/reuseFc/pubFc`); - return wrRegList; + const fclts = Array.isArray(wrRegList) ? wrRegList : []; + + set((state: pubFacState) => ({ + ...state, + pbnst: { + ...state.pbnst, + fclts, + }, + })); + + return fclts; }; // 하수처리시설 정보 조회 const hasuListFetch = async ( - page: string, + get: any, + set: any, + page: number = 1, sggOrCity: string, // 해당 지자체의 하수처리시설 조회 searchTxt?: string ) => { - const checkWrRegListRes = await checkWrRegList(); // 재사용시설에 대한 정보 조회 + const wrData = await checkWrRegList(get, set); // 재사용시설에 대한 정보 조회 + const wrBscFctCdSet = new Set( + wrData + .map((wrItem: any) => (typeof wrItem === "string" ? wrItem.trim() : "")) + ); - let url = `/prcsFclt/ruseInfo/${page ? page : 1}/${DEFAULT_LIST_SIZE}/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`; - - const data = checkWrRegListRes.filter((item: string) => item !== ""); - if (searchTxt) { - url = url + `/${searchTxt}`; + let url = `/prcsFclt/ruseInfo/reg/${page}/${DEFAULT_LIST_SIZE}/A/${sggOrCity ? sggOrCity : "0"}/0/1/SW`; + if (searchTxt?.trim()) { + url += `?swtrmtFcltNm=${encodeURIComponent(searchTxt.trim())}`; } - const rainRes = await postFectch(url, data, fetchType.COMMON); // fo + const fcltRes = await getFetchWithCount(fetchType.COMMON, url); // fo - const hasuList = rainRes.data.map((item: any) => { + const hasuList = fcltRes.data.map((item: any) => { return { ...item, fctCpc: Number(item.fctCpc) || 0, - ruse: item.ruse === false ? "N" : "Y", + ruse: item?.bscFctCd && wrBscFctCdSet.has(item.bscFctCd) ? "Y" : "N", }; }); - return { data: hasuList, count: rainRes.count }; + return { data: hasuList, count: fcltRes.count }; }; const initFetch = async (ruseFcltPk: string | undefined) => { @@ -172,12 +195,12 @@ export const writeRgtrAndMdfr = (data: customPbnst[]) => { return data; }; -export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { +export const pubFacActionsExport: (set: any, get: any) => pubFacActions = (set: any, get: any) => { return { // 하수처리시설을 조회한다(운영실태) - pubHasuInit: async (page: string, sggOrCity: string) => { + pubHasuInit: async (page: number, sggOrCity: string) => { try { - const pbnstHasuRes = await hasuListFetch(page, sggOrCity); // /prcsFclt/ruseInfo + const pbnstHasuRes = await hasuListFetch(get, set, page, sggOrCity); // /prcsFclt/ruseInfo return set((state: pubFacState) => ({ ...state, pbnst: { @@ -192,12 +215,12 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { }, // 하수처리시설을 조회한다(운영실태) (처리시설명 포함) pubHasuSearch: async ( - page: string, + page: number, sggOrCity: string, searchTxt: string ) => { try { - const pbnstHasuRes = await hasuListFetch(page, sggOrCity, searchTxt); + const pbnstHasuRes = await hasuListFetch(get, set, page, sggOrCity, searchTxt); return set((state: pubFacState) => ({ ...state, pbnst: { @@ -238,11 +261,14 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { const newPbnstRes = await initFetch( pbnstRes.pbnstRuseFcltId.slice(0, 11) ); + const wrRegList = await getFetch("wr", `/reuseFc/pubFc`); + const fclts = Array.isArray(wrRegList) ? wrRegList : []; set((state: pubFacState) => ({ ...state, pbnst: { ...state.pbnst, pbnstRes: newPbnstRes, + fclts, }, })); return successMessage; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index eafbc4477..c39d3d72b 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -62,10 +62,18 @@ export type PbnstDemandComType = { export const pubHasuZod = z.object({ choose: z.boolean().default(false), bscFctCd: z.string(), + rvbsnCd: z.string().default(""), // 권역코드 + rvbsn: z.string().default(""), + lgbsn: z.string().default(""), + mdmbsn: z.string().default(""), + rgnNm: z.string().default(""), + rgnCd: z.string().default(""), // 지역코드 + adstDstrCd: z.string().default(""), // 행정구역코드 sido: z.string().default(""), // 시도 gugun: z.string().default(""), // 구군 bscFctNm: z.string().default(""), // 시설명 efflWqltStndrdNm: z.string().default(""), // 지역구분 + tel: z.string().default(""), fctCpc: z.number().default(0), // 시설용량 addr: z.string().nullish(), // 위치 }); @@ -258,6 +266,15 @@ const PrfSchema = z.object({ export const pbnstRegZod = z.object({ pbnstRuseFcltId: z.string().default(""), swtrmtFcltId: z.string().default(""), + swageTrtmfctId: z.string().default(""), + swageBscFctNm: z.string().default(""), + swageRgnCd: z.string().default(""), + swageAdstDstrCd: z.string().default(""), + swageRvbsnCd: z.string().default(""), + swageFctCpc: z.preprocess( + (v) => (v !== null && v !== undefined ? Number(v) : v), + z.number().default(0) + ), ruseUtztnFcltNm: //z.string().default(''), z.preprocess( (v) => (v !== null && v !== undefined ? String(v).trim() : ""), // null/undefined → "", 공백 제거 diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index ce6da6334..29c8e529d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -69,15 +69,15 @@ export type chgBuilding = { export type customRainBdst = z.infer; export const upHeadList: TableUpperProps[] = [ - { id: "cityText", title: "시도" }, - { id: "sggText", title: "시군구" }, - { id: "bdstNm", title: "시설명" }, - { id: "daddr", title: "위치" }, - { id: "bdsgUsgText", title: "건축물용도" }, - { id: "frstArchPrmsnDt", title: "최초건축허가일" }, - { id: "archArea", title: "건축면적(㎡)" }, - { id: "lawTrgtYn", title: "법적의무대상여부" }, - { id: "bdstChgYn", title: "건축물변경여부" }, + { id: "cityText", title: "시도", widthPercent: 10 }, + { id: "sggText", title: "시군구", widthPercent: 8 }, + { id: "bdstNm", title: "시설명", widthPercent: 15 }, + { id: "daddr", title: "위치", widthPercent: 22 }, + { id: "bdsgUsgText", title: "건축물용도", widthPercent: 12 }, + { id: "frstArchPrmsnDt", title: "최초\n건축허가일", widthPercent: 9 }, + { id: "archArea", title: "건축면적(㎡)", widthPercent: 9 }, + { id: "lawTrgtYn", title: "법적의무대상여부", widthPercent: 8 }, + { id: "bdstChgYn", title: "건축물변경여부", widthPercent: 7 }, ]; const rainRes: customRainBdst[] = []; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx index 816d6ab52..82915f4c7 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -1,5 +1,5 @@ import { deleteFectch, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding } from "../rainReg"; +import { type chgBuilding } from "../rainReg"; import { DEFAULT_LIST_SIZE } from "@/src/shared/config"; import type { TableUpperProps } from "@/app/store/common/type/header"; @@ -57,6 +57,19 @@ export type customRswtBdst = z.infer; const rswtRes: customRswtBdst[] = []; +export const rswtUpHeadList: TableUpperProps[] = [ + { id: "cityText", title: "시도", widthPercent: 8 }, + { id: "sggText", title: "시군구", widthPercent: 7 }, + { id: "bdstNm", title: "건축물명", widthPercent: 14 }, + { id: "daddr", title: "위치", widthPercent: 20 }, + { id: "bdstUsgText", title: "건축물용도", widthPercent: 11 }, + { id: "frstArchPrmsnDt", title: "최초\n건축허가일", widthPercent: 9 }, + { id: "archArea", title: "건축면적(㎡)", widthPercent: 8 }, + { id: "lawTrgtYn", title: "법적의무대상여부", widthPercent: 8 }, + { id: "chBuildingYn", title: "증축/개축/재축여부", widthPercent: 8 }, + { id: "instlCmptnDt", title: "설치완료일시", widthPercent: 7 }, +]; + export type rswtFacState = { rswt: { upHeadList: TableUpperProps[]; @@ -83,7 +96,7 @@ export type rswtFacType = rswtFacState & rswtFacSActions; export const rswtFacStateExport: rswtFacState = { rswt: { - upHeadList: upHeadList, + upHeadList: rswtUpHeadList, rswtRes: rswtRes, rswtResCount: 1, }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx index 71c4c01d7..cca75609f 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx @@ -102,7 +102,7 @@ export const rusePplHeadListExport: TableUpperProps[] = [ export const ruseGuranteeHeadListExport: TableUpperProps[] = [ { id: "cycl", title: "차수", visible: true }, { id: "bod", title: "BOD(mg/L)", visible: true }, - { id: "grssClfg", title: "총대장균군수(개/mg)", visible: true }, + { id: "grssClfg", title: "총대장균군수(개/100㎖)", visible: true }, { id: "combResdch", title: "결합잔류염소(mh/L)", visible: true }, { id: "trbt", title: "탁도(NTU)", visible: true }, { id: "smll", title: "냄새", visible: true }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx index 35a3fb3d7..5b2a72acf 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx @@ -3,7 +3,7 @@ import type { TableUpperProps, } from "@/app/store/common/type/header"; import type { FcPrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; -import { fetchType, getFetch, postFectch } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount, postFectch } from "@/components/lib/api"; import type { ReturnType } from "@common/business_components/ui"; import moment from "moment"; import { type z } from "zod"; @@ -47,12 +47,22 @@ export type pbnstSttnState = { pbnstSttnResCount: number; excelList: []; fclts: string[]; - isInit: boolean; + isFcltsLoaded: boolean; // wr 하수재이용시설 목록 조회 여부 + isTableLoaded: boolean; // 현황 테이블 초기 조회 여부 }; }; type pbnstSttnActions = { pbnstChSttnHead: (headList: z.infer) => void; + pbnstSttnList: ( + isExcel: boolean, + page: string, + total: string, + reurnValue: ReturnType, + searchNm: string | undefined, + year: string, + fclts: string[] + ) => void; pbnstSttnSearch: ( isExcel: boolean, page: string, @@ -100,7 +110,8 @@ export const pbnstSttnStateExport: pbnstSttnState = { pbnstSearchData: [], excelList: [], fclts: [], - isInit: false, + isFcltsLoaded: false, + isTableLoaded: false, }, }; @@ -244,6 +255,119 @@ export const hasuListFetch = async ( return { data: data, count: getRuseList.count }; }; +export const pbnstListFetch = async ( + page: string, + total: string, + reurnValue: ReturnType, + searchNm: string | undefined, + year: string +) => { + let nameCd = "0"; + let partStr = "A"; + + switch (reurnValue.partValue) { + case "R": + if (reurnValue.regionValue !== "0") { + if (reurnValue.unitWaterShedValue === "0") nameCd = reurnValue.regionValue; + else if (reurnValue.middleRegionValue === "0") nameCd = reurnValue.unitWaterShedValue; + else nameCd = reurnValue.middleRegionValue; + } + partStr = reurnValue.partValue; + break; + default: + if (reurnValue.sidoValue && reurnValue.sidoValue !== "0") nameCd = reurnValue.sidoValue; + if (reurnValue.sigunValue && reurnValue.sigunValue !== "0") nameCd = reurnValue.sigunValue; + partStr = reurnValue.envPartValue !== "0" ? reurnValue.envPartValue : "A"; + break; + } + + let url = `/reuseFc/pbnstList/${year}/${page}/${total}/${partStr}/${nameCd}/0/1/SW`; + if (searchNm && searchNm.length > 0) { + url += `?swtrmtFcltNm=${searchNm}`; + } + + const response = await getFetchWithCount(fetchType.WR, url); + const wrList: WaterReuseFacility[] = Array.isArray(response.data) + ? response.data + : []; + + const swtrmtFcltIds = [ + ...new Set( + wrList + .map((item: WaterReuseFacility) => { + if (item.swtrmtFcltId && item.swtrmtFcltId.length > 0) { + return item.swtrmtFcltId; + } + + if (item.pbnstRuseFcltId && item.pbnstRuseFcltId.length >= 11) { + return item.pbnstRuseFcltId.substring(0, 11); + } + + return ""; + }) + .filter(Boolean) + ), + ]; + + let pbnListData: pubHasuType[] = []; + + if (swtrmtFcltIds.length > 0) { + let foUrl = `/prcsFclt/ruseInfo/1/${swtrmtFcltIds.length + 1}`; + if (searchNm && searchNm.length > 0) { + foUrl += `/${searchNm}`; + } + + const pbnList = await postFectch( + foUrl, + swtrmtFcltIds, + fetchType.COMMON + ); + + pbnListData = Array.isArray(pbnList?.data) ? pbnList.data : []; + } + + const data: WaterReuseFacility[] = wrList.map((item: WaterReuseFacility) => { + const swtrmtFcltId = + item.swtrmtFcltId && item.swtrmtFcltId.length > 0 + ? item.swtrmtFcltId + : item.pbnstRuseFcltId?.substring(0, 11) ?? ""; + + const findData = pbnListData.find( + (fclt: pubHasuType) => fclt.bscFctCd === swtrmtFcltId + ); + + return { + ...item, + swtrmtFcltId, + rvbsn: findData?.rvbsn || item.rvbsn || "-", + lgbsn: findData?.lgbsn || item.lgbsn || "-", + mdmbsn: findData?.mdmbsn || item.mdmbsn || "-", + rgnNm: findData?.rgnNm || item.rgnNm || "-", + sido: findData?.sido || item.sido || "-", + gugun: findData?.gugun || item.gugun || "-", + bscFctNm: findData?.bscFctNm || item.bscFctNm || "-", + efflWqltStndrdNm: + findData?.efflWqltStndrdNm || item.efflWqltStndrdNm || "-", + tel: findData?.tel || item.tel || "-", + fctCpc: Number(findData?.fctCpc ?? item.fctCpc) || 0, + ruseUtztnFcltNm: item.ruseUtztnFcltNm || "-", + fcltCpct: Number(item.fcltCpct) || 0, + splyExtraCpct: Number(item.splyExtraCpct) || 0, + ruseCpct: Number(item.ruseCpct) || 0, + usageTotal: Number(item.usageTotal) || 0, + inUsage: Number(item.inUsage) || 0, + outUsage: Number(item.outUsage) || 0, + operMthd: item.operMthd || "-", + rprtvBzenty: item.rprtvBzenty || "-", + bgngDt: item.bgngDt || "", + endDt: item.endDt || "", + prfList: item.prfList ?? [], + }; + }); + + return { data, count: response.count }; +}; + export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( set: any ) => { @@ -251,12 +375,56 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( //등록된 하수재이용시설을 조회한다. getFlcts: async () => { const fclts = await getFetch(fetchType.WR, "/reuseFc/pubFc"); - return set((state: pbnstSttnState) => ({ - pbnstSttn: { - ...state.pbnstSttn, - fclts: fclts, - }, - })); + return set((state: pbnstSttnState) => ({ + pbnstSttn: { + ...state.pbnstSttn, + isFcltsLoaded: true, + fclts: fclts, + }, + })); + }, + pbnstSttnList: async ( + isExcel: boolean, + page: string, + total: string, + reurnValue: ReturnType, + searchNm: string | undefined, + year: string, + // _fclts: string[] + ) => { + try { + const pbnstSttnRes = await pbnstListFetch( + page, + total, + reurnValue, + searchNm, + year + ); + + if (isExcel) { + const pbnstExcel = excelPbnstSttnParsing(pbnstSttnRes.data); + set((state: pbnstSttnState) => ({ + ...state, + pbnstSttn: { + ...state.pbnstSttn, + excelList: pbnstExcel, + }, + })); + } else { + set((state: pbnstSttnState) => ({ + ...state, + pbnstSttn: { + ...state.pbnstSttn, + pbnstSttnRes: pbnstSttnRes.data, + pbnstSttnResCount: pbnstSttnRes.count, + pbnstDetail: {} as customPbnst, + isTableLoaded: true, + }, + })); + } + } catch (error) { + console.log("error", error); + } }, //테이블 헤드를 조정한다. pbnstChSttnHead: async ( @@ -313,7 +481,7 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( ...state.pbnstSttn, pbnstSttnRes: pbnstSttnRes.data, pbnstSttnResCount: pbnstSttnRes.count, - // isInit: false, + isTableLoaded: true, }, }; }); @@ -347,8 +515,8 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( ...state.pbnstSttn, pbnstSttnRes: pbnstSttnRes.data, pbnstSttnResCount: pbnstSttnRes.count, - isInit: false, pbnstDetail: {} as customPbnst, + isTableLoaded: true, }, }; }); diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx index 7d0f8a068..ee202d4f6 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx @@ -1,10 +1,11 @@ import type { PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; export type WaterReuseFacility = { + swtrmtFcltId?: string; bscFctNm: string; // 기본시설명 (예: "난지") efflWqltStndrdNm: string; // 방류수 수질 기준명 (예: "500톤 이상(Ⅲ지역)") fcltCpct: number; // 시설 용량 (숫자형, 예: 1) - fctCpc: string; // 시설 처리 능력 (예: "2360000") + fctCpc: number; // 시설 처리 능력 (예: 2360000) gugun: string; // 구군 정보 (예: " ") inUsage: number; // 유입량 (예: 1387) lgbsn: string; // 대수계 (예: "한강본류") diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx index b278a9a22..67de7f687 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx @@ -149,6 +149,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( rainSttn: { ...state.rainSttn, excelList: rainExcel, + rainSttnResCount: rainSttnRes.count, }, }; }); @@ -159,6 +160,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( rainSttn: { ...state.rainSttn, rainSttnRes: rainSttnRes.data, + rainSttnResCount: rainSttnRes.count, isInit: false, }, }; diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index fbb3434d9..268be198b 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -2,13 +2,6 @@ import { createStore } from "zustand/vanilla"; import { codeActionExport, comCodeStateExport, - getCityCd, - getCommonUpCd, - getEnvPartCd, - getMiddleRegionCd, - getRegionCd, - getSggCd, - getUnitWaterShedCd, type comCodeState, type comCodeType, } from "./common/code"; @@ -336,17 +329,17 @@ export const StoreZus = ( } ) => { return createStore()((set ,get) => { - getSggCd(set); - getCityCd(set); - getRegionCd(set); - getMiddleRegionCd(set); - getUnitWaterShedCd(set); - getEnvPartCd(set); - getCommonUpCd(set) + // getSggCd(set); + // getCityCd(set); + // getRegionCd(set); + // getMiddleRegionCd(set); + // getUnitWaterShedCd(set); + // getEnvPartCd(set); + // getCommonUpCd(set); return { ...initState, ...comFcltSearchAction(set), - ...pubFacActionsExport(set), + ...pubFacActionsExport(set, get), ...rainFacActionsExport(set), ...rswtFacActionsExport(set), ...matDmdActionsExport(set), @@ -373,7 +366,7 @@ export const StoreZus = ( ...rswtStatActionsExport(set), ...authActionsExport(set,get), ...commonMapActionsExport(set), - ...pbnMapActionsExport(set), + ...pbnMapActionsExport(set, get), ...rainMapActionsExport(set), ...rswtMapActionsExport(set), ...htdfMapActionsExport(set), diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index b2411eea4..03c000dd6 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -29,8 +29,8 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => { totalRuseFcltUtztnQnt: 0, }; - acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; - acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; + acc[key].totalSplyUswtrUtztnQnt += cur.splyUswtrUtztnQnt; // 연간대체수이용량(m³) + acc[key].totalRuseFcltUtztnQnt += cur.ruseFcltUtztnQnt; // 연간빗물이용량(m³) return acc; }, {}); diff --git a/apps/wr/components/lib/func/common.tsx b/apps/wr/components/lib/func/common.tsx index 1d9d4a43e..7afeda993 100644 --- a/apps/wr/components/lib/func/common.tsx +++ b/apps/wr/components/lib/func/common.tsx @@ -66,9 +66,9 @@ export const tableData = (data: any, code: comCodeState) => { ...item, sggText: sggText ?? "없음", cityText: cityText ?? "없음", - bdsgUsgText: bdsgUsgText, - lawTrgtYn: lawTrgtYn, - grntchBdstCertGrdText: grntchBdstCertGrdText, + bdsgUsgText: bdsgUsgText, // 건물용도명 + lawTrgtYn: lawTrgtYn, // 법정대상 여부 + grntchBdstCertGrdText: grntchBdstCertGrdText, // 녹색건축인증등급명 }; } else { returnData = { diff --git a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx index 09ed01987..2b567979c 100644 --- a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx +++ b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx @@ -28,6 +28,19 @@ import PopoverUi from "@common/business_components/ui/popover_ui"; import { Button, Checkbox, Input, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import { useForm, type UseFormReturn } from "react-hook-form"; + +const formatNumberWithComma = (value: string | number | null | undefined) => { + if (value === null || value === undefined || value === "") return ""; + + const normalized = + typeof value === "string" ? Number(value.replace(/,/g, "")) : Number(value); + + if (Number.isNaN(normalized)) { + return String(value); + } + + return normalized.toLocaleString("ko-KR"); +}; /** * ConCostForm * 호출: (with-layout)/matMng/coMat/coMatRvw @@ -456,12 +469,16 @@ export default function ConCostForm({ { field.onChange(Number(e.target.value)); }} - value={field.value ?? 0} + value={ + isSim + ? field.value ?? 0 + : formatNumberWithComma(field.value) + } readOnly={!isSim} className={!isSim ? readOnlyInputClass : ""} /> @@ -524,14 +541,13 @@ export default function ConCostForm({ { console.log("dmndQty ", e); //field.onChange(Number(e.target.value) * 365 ); }} // value={Number(field.value) * 365 || 0} - value={Number(field.value) || 0} + value={formatNumberWithComma(Number(field.value) || 0)} readOnly className={readOnlyInputClass} /> diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/buseWaterQulity/buseWaterQulity.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/buseWaterQulity/buseWaterQulity.tsx index dd43658d1..545fe62d1 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/buseWaterQulity/buseWaterQulity.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/buseWaterQulity/buseWaterQulity.tsx @@ -151,7 +151,7 @@ export function BuseWaterQulity({ name={`items.${indexMng}.fcBizs.${indexBiz}.grssClfg`} key={`items.${indexMng}.fcBizs.${indexBiz}.grssClfg-key`} render={({ field }) => ( - +
{ if ( - headId === "totalSplyUswtrUtztnQnt" || - headId === "totalRuseFcltUtztnQnt" + headId === "totalSplyUswtrUtztnQnt" || // 연간대체수이용량(m³) + headId === "totalRuseFcltUtztnQnt" // 연간빗물이용량(m³) ) { handleClick(makeTableData[index]) diff --git a/apps/wr/next-env.d.ts b/apps/wr/next-env.d.ts index 1b3be0840..830fb594c 100644 --- a/apps/wr/next-env.d.ts +++ b/apps/wr/next-env.d.ts @@ -1,5 +1,6 @@ /// /// +/// // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/wr/public/images/help.png b/apps/wr/public/images/help.png index e872802e4..977ef9d38 100644 Binary files a/apps/wr/public/images/help.png and b/apps/wr/public/images/help.png differ diff --git a/apps/wr/src/app/providers/app-provider.tsx b/apps/wr/src/app/providers/app-provider.tsx index 63df8349d..f54dfea52 100644 --- a/apps/wr/src/app/providers/app-provider.tsx +++ b/apps/wr/src/app/providers/app-provider.tsx @@ -1,5 +1,6 @@ "use client"; +import { useEffect } from "react"; import { DndProvider } from "react-dnd"; import { MultiBackend, getBackendOptions } from "@minoru/react-dnd-treeview"; import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; @@ -16,7 +17,11 @@ import i18next from "i18next"; import { I18nextProvider } from "react-i18next"; import { Toaster } from "react-hot-toast"; import koBase from "@/public/locales/ko/message.json"; -import { StoreProvider as WrStoreProvider } from "@/app/store"; +import { + StoreProvider as WrStoreProvider, + useWrStore, +} from "@/app/store"; +import { usePathname } from "next/navigation"; //import { LoginApi } from "@/src/entities/auth"; //import { useEffect } from "react"; import { setCookie } from "@/src/shared/lib/cookie"; @@ -34,6 +39,22 @@ i18n.init({ }, }); +function CommonCodeInitializer() { + const isInit = useWrStore((state) => state.code.isInit); + const initCommonCodes = useWrStore((state) => state.initCommonCodes); + const pathname = usePathname(); + const isLoginPage = + pathname === "/auth/login" || pathname?.startsWith("/auth/login/"); + + useEffect(() => { + if (isLoginPage) return; + if (isInit) return; + initCommonCodes(); + }, [isInit, initCommonCodes, isLoginPage]); + + return null; +} + const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => { const queryClient = new QueryClient(); return ( @@ -49,6 +70,7 @@ const AppProvider = ({ children }: Readonly<{ children: React.ReactNode }>) => { > + {children} diff --git a/apps/wr/src/app/styles/components.css b/apps/wr/src/app/styles/components.css index 4dc30bafd..fd651fe6c 100644 --- a/apps/wr/src/app/styles/components.css +++ b/apps/wr/src/app/styles/components.css @@ -21,6 +21,62 @@ .card-header { @apply border-b-[#3f4042]; } + + .gis-layer-panel { + background: #111214; + border-right-color: #2f3136; + box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.03); + } + + .gis-layer-panel-title { + color: #f3f4f6; + } + + .gis-layer-panel hr { + border-color: #2f3136; + } + + .gis-layer-row { + color: #e5e7eb; + } + + .gis-layer-row:hover { + background: rgba(255, 255, 255, 0.08); + } + + .gis-layer-row span, + .gis-layer-row label { + color: #e5e7eb !important; + } + + .gis-layer-row input[type="checkbox"] { + accent-color: #c026d3; + } + + .gis-layer-action-button { + background: #1a1c20; + border-color: #3b82f6; + color: #cfe3ff; + } + + .gis-layer-action-button:hover { + background: #23262b; + } + + .gis-layer-setting { + background: #111214; + border-top: 1px solid #2f3136; + } + + .gis-layer-toggle { + background: #111214; + border-color: #2f3136; + color: #f3f4f6; + } + + .gis-layer-toggle:hover { + background: #1a1c20; + } } input[type="file"] { diff --git a/apps/wr/src/entities/auth/api/login-service.ts b/apps/wr/src/entities/auth/api/login-service.ts index 1ad5f2cd0..94be8b53f 100644 --- a/apps/wr/src/entities/auth/api/login-service.ts +++ b/apps/wr/src/entities/auth/api/login-service.ts @@ -1,7 +1,7 @@ import type { LoginService, ILogin } from "../model/login-interface"; import { tokenManager } from "../lib/token-manager"; -import { ACCESS_TOKEN, AUTH_USER_ID, SITE_ID, CLAIM_NAME, ENDPOINT } from "../../../shared/config"; +import {PROXY_HOST, ACCESS_TOKEN, AUTH_USER_ID,SITE_ID, CLAIM_NAME, ENDPOINT, JWT_EXPIRATION_TIME } from "../../../shared/config"; export class LoginApiService implements LoginService { private static instance: LoginApiService; @@ -18,33 +18,31 @@ export class LoginApiService implements LoginService { public async login(payload: ILogin): Promise { try { tokenManager.clearAuthToken(); - const response = await fetch(`/api/proxy${ENDPOINT.USER_SERVICE.LOGIN}`, { + const response = await fetch( PROXY_HOST+ ENDPOINT.USER_SERVICE.LOGIN, { method: "POST", headers: { "Content-Type": "application/json", + "X-Site-Id": SITE_ID, }, body: JSON.stringify({ userId: payload.userId, password: payload.password, }), }); - - const data = await response.json(); - - if (!response.ok) { - throw new Error(data?.message ?? "Login failed"); - } - - const accessToken = data[ACCESS_TOKEN]; - const tokenId = data[AUTH_USER_ID]; + // const data = response.headers.get(ACCESS_TOKEN); + const accessToken = response.headers.get(ACCESS_TOKEN); + const tokenId = response.headers.get(AUTH_USER_ID); if (!accessToken || !tokenId) { throw new Error("Missing required authentication tokens"); } - tokenManager.setToken(CLAIM_NAME, accessToken); - tokenManager.setToken(AUTH_USER_ID, tokenId); - tokenManager.setToken("site-id-key", SITE_ID); - tokenManager.setupRefreshTimer(() => this.silentRefresh()); + tokenManager.setToken(CLAIM_NAME, accessToken) + tokenManager.setToken(AUTH_USER_ID, tokenId) + tokenManager.setToken("site-id-key", SITE_ID) + tokenManager.setupRefreshTimer( + () => this.silentRefresh(), + JWT_EXPIRATION_TIME, + ); } catch (error) { throw new Error(`Login failed: ${error}`); @@ -56,19 +54,17 @@ export class LoginApiService implements LoginService { console.log(' silentRefresh ') try { - const response = await fetch( - `/api/proxy${ENDPOINT.USER_SERVICE.SILENT_REFRESH}`, + const response = await fetch(PROXY_HOST+ + `${ENDPOINT.USER_SERVICE.SILENT_REFRESH}`, { method: "PUT", + headers: { + "X-Site-Id": SITE_ID, + }, }, ); const data = await response.json(); - - if (!response.ok) { - throw new Error(data?.message ?? "Silent refresh failed"); - } - const accessToken = data[ACCESS_TOKEN]; const tokenId = data[AUTH_USER_ID]; @@ -78,7 +74,6 @@ export class LoginApiService implements LoginService { tokenManager.setToken(CLAIM_NAME, accessToken); tokenManager.setToken(AUTH_USER_ID, tokenId); - tokenManager.setupRefreshTimer(() => this.silentRefresh()); } catch (error) { tokenManager.clearAuthToken(); throw new Error(`Silent refresh failed: ${error}`); diff --git a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx index 91073c42c..796cd44a9 100644 --- a/apps/wr/src/entities/auth/lib/auth-wrapper.tsx +++ b/apps/wr/src/entities/auth/lib/auth-wrapper.tsx @@ -2,12 +2,10 @@ import { useEffect } from "react"; import { usePathname } from "next/navigation"; -import { LoginApi } from "../api/login-service"; -import { tokenManager } from "./token-manager"; import { client } from "../../../shared/api"; import type { IUserInfo } from "../../../shared/store"; import { useUserStore } from "../../../shared/lib"; -import { ENDPOINT, AUTH_USER_ID, CLAIM_NAME } from "../../../shared/config"; +import { ENDPOINT, AUTH_USER_ID } from "../../../shared/config"; import { isAtLoginRedirectUrl } from "@common/network"; import { getCookie } from "../../../shared/lib"; @@ -19,37 +17,22 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { const { userInfo, setUserInfo } = useUserStore((state) => state); async function authCheck() { - // 현재 페이지가 로그인 페이지이면 authCheck(쿠키점검) 안함. if (isAtLoginRedirectUrl(LOGIN_PAGE_URL)) { return; } const userId = getCookie(AUTH_USER_ID); - if (!userId) { // token_id 가 없으면 로그인 페이지로 이동 + if (!userId) { throw new Error("Missing required authentication tokens"); } - if (userInfo) return; - const response = await client.get( `${ENDPOINT.USER_SERVICE.USERS}/info/me`, ); - setUserInfo(response.data); + if (!userInfo) setUserInfo(response.data); } useEffect(() => { - const token = getCookie(CLAIM_NAME); - const userId = getCookie(AUTH_USER_ID); - - if (!token || !userId) { - return; - } - - tokenManager.setupRefreshTimer(() => LoginApi.silentRefresh()); - }, []); - - useEffect(() => { - const isJwtTestPage = pathname?.startsWith("/jwttest"); (async () => { try { await authCheck(); @@ -57,7 +40,7 @@ const AuthWrapper = ({ children }: { children: React.ReactNode }) => { console.error(error); setUserInfo(null); - if (isAtLoginRedirectUrl(LOGIN_PAGE_URL) || isJwtTestPage) return; + if (isAtLoginRedirectUrl(LOGIN_PAGE_URL)) return; // const hostname = window.location.hostname; diff --git a/apps/wr/src/entities/auth/lib/token-manager.ts b/apps/wr/src/entities/auth/lib/token-manager.ts index af6ecb1c3..919386622 100644 --- a/apps/wr/src/entities/auth/lib/token-manager.ts +++ b/apps/wr/src/entities/auth/lib/token-manager.ts @@ -1,4 +1,4 @@ -import { AUTH_USER_ID, CLAIM_NAME, REFRESH_TOKEN } from "@/src/shared/config"; +import { AUTH_USER_ID, CLAIM_NAME } from "@/src/shared/config"; import { getCookie, removeCookie, setCookie } from "@/src/shared/lib/cookie"; type JwtPayload = { @@ -11,7 +11,6 @@ type JwtPayload = { export class TokenManager { private static instance: TokenManager; private refreshTimer: NodeJS.Timeout | null = null; - private static readonly REFRESH_BUFFER_MS = 60000; // 60초 private constructor() {} @@ -80,37 +79,20 @@ export class TokenManager { removeCookie(key); } - private handleRefreshFailure(error: unknown, message: string): void { - console.error(message, error); - this.clearAuthToken(); - } - - public setupRefreshTimer(callback: () => Promise): void { + public setupRefreshTimer( + callback: () => Promise, + expirationTime: number, + ): void { if (this.refreshTimer) { clearTimeout(this.refreshTimer); - this.refreshTimer = null; } - const remainingMs = this.getRemainingMsFromToken(CLAIM_NAME); - if (remainingMs === null) { - return; - } - - if (remainingMs <= 0) { - this.clearAuthToken(); - return; - } - - const refreshDelay = Math.max( - remainingMs - TokenManager.REFRESH_BUFFER_MS, - 0, - ); - this.refreshTimer = setTimeout(() => { callback().catch((error) => { - this.handleRefreshFailure(error, "Silent refresh failed:"); + console.error("Silent refresh failed:", error); + this.clearAuthToken(); }); - }, refreshDelay); + }, expirationTime - 60000); } public clearAuthToken(): void { @@ -120,7 +102,6 @@ export class TokenManager { } this.removeToken(CLAIM_NAME); - this.removeToken(REFRESH_TOKEN); this.removeToken(AUTH_USER_ID); } } diff --git a/packages/common/business_components/src/ui/map/GisTree.js b/packages/common/business_components/src/ui/map/GisTree.js index 75f523cd4..5f9510bb5 100644 --- a/packages/common/business_components/src/ui/map/GisTree.js +++ b/packages/common/business_components/src/ui/map/GisTree.js @@ -518,7 +518,7 @@ export default React.memo(function GisTree({ <> {/* 사이드 패널 */}
-

시설물

+

시설물


{/* DnD Tree */} @@ -550,7 +550,7 @@ export default React.memo(function GisTree({ return (
handleLayerImgClick( node.data.lyrTyNm, @@ -627,13 +627,13 @@ export default React.memo(function GisTree({
{LayerSettingView && ( -
+
)} @@ -641,7 +641,7 @@ export default React.memo(function GisTree({ {!visible && ( diff --git a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx index a663feabf..e13965768 100644 --- a/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx +++ b/packages/common/business_components/src/ui/map/searchBar/searchBar.tsx @@ -4,7 +4,7 @@ import { Button } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; import SearchInputText from "./SearchInputText"; import GisApp from "../lib/gis.core"; -import { moveMapToCenter, sidoCenter, sigunguCenter } from "./utils"; +import { getSigunguCenter, moveMapToCenter, sidoCenter } from "./utils"; const FACILITY_TYPE_URL_MAP: Record = { tb_il_swage_prcs_fclt: @@ -112,9 +112,9 @@ export const SearchBar = ({ .map((item: any) => ({ val: item.lwpoCd, text: item.lwpoCdNm, - center: sigunguCenter[item.lwpoCd?.trim()], - })) - .sort((a: any, b: any) => a.text.localeCompare(b.text, 'ko')); + center: getSigunguCenter(item.lwpoCd), + })); + //.sort((a: any, b: any) => a.text.localeCompare(b.text, 'ko')); setSidoData([{ text: "시도", val: "0" }, ...sidoList]); setSigunData(sigunList); }; @@ -168,7 +168,10 @@ export const SearchBar = ({ const selectedSido = sidoData.find((item) => item.val === sidoValue); if (!selectedSido?.center) return; + // console.log("시도 : " +sidoValue); + // console.log("시군구 : " + sigunValue); if (sigunValue !== "0") { + console.log(sigunData.filter((item) => item.val == sigunValue)); const selectedSigun = filteredSigunData.find((item) => item.val === sigunValue) ?? sigunData.find((item) => item.val === sigunValue); diff --git a/packages/common/business_components/src/ui/map/searchBar/utils.ts b/packages/common/business_components/src/ui/map/searchBar/utils.ts index 57528d6b9..5c9aef350 100644 --- a/packages/common/business_components/src/ui/map/searchBar/utils.ts +++ b/packages/common/business_components/src/ui/map/searchBar/utils.ts @@ -2,6 +2,11 @@ import type { RefObject } from "react"; import { transform } from "ol/proj"; import GisApp from "../lib/gis.core"; +/** + * + * @param geometry + * @returns + */ export const getGeometryCenter = (geometry: any): [number, number] | null => { if (!geometry?.coordinates) return null; @@ -42,22 +47,34 @@ export const getGeometryCenter = (geometry: any): [number, number] | null => { return [(minX + maxX) / 2, (minY + maxY) / 2]; }; +/** + * 이미 5179좌표계이면 변환하지 않음. + * @param centerCoord + * @returns + */ export const getMapCenterCoordinate = (centerCoord: [number, number]): [number, number] => { const [x, y] = centerCoord; - const looksLikeLonLat = Math.abs(x) <= 180 && Math.abs(y) <= 90; - const looksLikeLatLonSwapped = Math.abs(x) <= 90 && Math.abs(y) <= 180; + const looksLikeLonLat = Math.abs(x) <= 180 && Math.abs(y) <= 90; // 경위도 + const looksLikeLatLonSwapped = Math.abs(x) <= 90 && Math.abs(y) <= 180; // 위경도 - if (looksLikeLonLat) { - return transform(centerCoord, GisApp.FROM_PROJ, GisApp.TO_PROJ) as [number, number]; + if (looksLikeLonLat) { + return transform(centerCoord, GisApp.FROM_PROJ, GisApp.TO_PROJ) as [number, number]; // 4326 -> 5179 } if (looksLikeLatLonSwapped) { - return transform([y, x], GisApp.FROM_PROJ, GisApp.TO_PROJ) as [number, number]; + return transform([y, x], GisApp.FROM_PROJ, GisApp.TO_PROJ) as [number, number]; // 4326 -> 5179 } return centerCoord; }; +/** + * + * @param gisMaps + * @param centerCoord + * @param zoom + * @returns + */ export const moveMapToCenter = ( gisMaps: RefObject, centerCoord?: [number, number], @@ -69,7 +86,7 @@ export const moveMapToCenter = ( if (!map?.getView) return; const view = map.getView(); - const center = getMapCenterCoordinate(centerCoord); + const center = getMapCenterCoordinate(centerCoord); // 4326 -> 5179 if (!Number.isFinite(center[0]) || !Number.isFinite(center[1])) return; const projection = view.getProjection?.(); @@ -89,7 +106,28 @@ export const moveMapToCenter = ( }); }; +/** + * 시군구 코드에 해당하는 중심 좌표를 반환한다. + * 먼저 전체 코드로 정확히 조회하고, 값이 없으면 앞 4자리가 같은 다른 시군구 코드의 좌표를 대체로 사용한다. + * + * @param lwpoCd 행정구역 코드. 예: "41110" + * @returns 시군구 중심 좌표. 조회 결과가 없으면 undefined + */ +export const getSigunguCenter = (lwpoCd?: string | null): [number, number] | undefined => { + const code = lwpoCd?.trim(); + if (!code) return undefined; + const exactCenter = sigunguCenter[code]; + if (exactCenter) return exactCenter; + + const prefix = code.slice(0, 4); + if (prefix.length < 4) return undefined; + + const fallbackCode = Object.keys(sigunguCenter).find((key) => key.startsWith(prefix)); + return fallbackCode ? sigunguCenter[fallbackCode] : undefined; +}; + +// EPSG:5179 기준 export const sidoCenter: Record = { "11": [953551.4119216551, 1951826.357686395], // 서울특별시 "26": [1139616.39795744, 1683535.70569214], // 부산광역시 @@ -98,23 +136,25 @@ export const sidoCenter: Record = { "29": [939294.465052485, 1684630.0528689548], // 광주광역시 "30": [991301.069516585, 1816039.953510165], // 대전광역시 "31": [1155621.6870651902, 1727062.69578941], // 울산광역시 - "36": [979381.304388835, 1841430.83666584], // 세종특별자치시 + // "36": [979381.304388835, 1841430.83666584], // 세종특별자치시 "41": [965621.8990488851, 1954345.5683645], // 경기도 - "51": [1065114.938094025, 1980661.8453088552], // 강원특별자치도 + "42": [1065114.938094025, 1980661.8453088552], // 강원특별자치도 "43": [1041183.7558293699, 1848671.9260201901], // 충청북도 "44": [918689.7963483699, 1836216.9375309348], // 충청남도 - "52": [949568.330647045, 1748060.215177075], // 전북특별자치도 + "45": [949568.330647045, 1748060.215177075], // 전북특별자치도 "46": [906934.38266853, 1637218.959990745], // 전라남도 "47": [1207219.543276005, 1843195.136606685], // 경상북도 "48": [1081504.77257488, 1690185.644486565], // 경상남도 - "50": [912295.3285630699, 1508716.724020285], // 제주특별자치도 + "49": [909678.884, 1485988.314], // [912295.3285630699, 1508716.724020285], // 제주특별자치도 + "50": [979381.304388835, 1841430.83666584], // 세종특별자치시 }; +// EPSG:5179 기준, 구코드 기준임. 즉, 하수도정보시스템 기준, tb_ms_sgg는 신코드 기준임. export const sigunguCenter: Record = { "41820": [994886.197272545, 1979052.53325589], // 가평군 "11680": [961673.31210415, 1944170.63969123], // 강남구 "11740": [968769.7482373801, 1950018.61637764], // 강동구 - "51150": [1117008.10469879, 1968660.393087245], // 강릉시 + "42150": [1117008.10469879, 1968660.393087245], // 강릉시 "11305": [957184.89551525, 1960948.17897649], // 강북구 "11500": [940169.1006571399, 1952038.261591505], // 강서구 "26440": [1125722.34144724, 1680630.4026719849], // 강서구 @@ -128,11 +168,11 @@ export const sigunguCenter: Record = { "28245": [932663.7165225251, 1951314.751646345], // 계양구 "47830": [1074241.6005863552, 1748726.26930297], // 고령군 "48820": [1073144.623548525, 1668111.92215727], // 고성군 - "51820": [1079906.976889925, 2044841.96337935], // 고성군 + "42820": [1079906.976889925, 2044841.96337935], // 고성군 "41281": [945034.57886003, 1962467.607140625], // 고양시 덕양구 "41285": [937759.4023643399, 1964877.5403761598], // 고양시 일산동구 "41287": [931767.42700348, 1964473.38259711], // 고양시 일산서구 - "52790": [918393.62804468, 1716132.826828825], // 고창군 + "45790": [918393.62804468, 1716132.826828825], // 고창군 "46770": [982955.40283695, 1619845.06015117], // 고흥군 "46720": [976956.4637679299, 1689787.68075054], // 곡성군 "44150": [962642.898486655, 1831283.240475945], // 공주시 @@ -148,14 +188,14 @@ export const sigunguCenter: Record = { "11530": [943255.85156361, 1944224.7496726601], // 구로구 "41310": [967836.346287095, 1955821.725581055], // 구리시 "47190": [1076297.5737083051, 1801900.2253747801], // 구미시 - "52130": [904674.42544751, 1767715.183037305], // 군산시 + "45130": [904674.42544751, 1767715.183037305], // 군산시 "27720": [1103849.611897755, 1797204.1944948], // 군위군 "41410": [948411.5776788951, 1927135.757437655], // 군포시 "44710": [998110.87580872, 1792026.97835628], // 금산군 "26410": [1144696.85330015, 1697028.92074261], // 금정구 "11545": [946955.492372005, 1940271.753176735], // 금천구 "26710": [1155182.296211175, 1700204.308554315], // 기장군 - "52210": [935224.890489175, 1755205.56953502], // 김제시 + "45210": [935224.890489175, 1755205.56953502], // 김제시 "47150": [1052988.6733146599, 1783129.650228145], // 김천시 "41570": [925936.0119416551, 1965389.1203246699], // 김포시 "48250": [1123054.361467805, 1698359.11561172], // 김해시 @@ -166,7 +206,7 @@ export const sigunguCenter: Record = { "31140": [1164388.02782853, 1725008.616189565], // 남구 "28200": [931330.60305263, 1937119.742216935], // 남동구 "41360": [976250.43203106, 1960416.01281481], // 남양주시 - "52190": [993534.846345315, 1715101.9621615452], // 남원시 + "45190": [993534.846345315, 1715101.9621615452], // 남원시 "48840": [1042145.28987352, 1636788.3540021451], // 남해군 "11350": [962686.53614943, 1961831.238915105], // 노원구 "44230": [969310.08745166, 1800569.86826501], // 논산시 @@ -187,20 +227,20 @@ export const sigunguCenter: Record = { "41250": [963148.54470934, 1991284.1699954001], // 동두천시 "26260": [1143854.4548997101, 1691107.4825817398], // 동래구 "11590": [950875.3949149849, 1944274.8505625948], // 동작구 - "51170": [1137915.778823135, 1947378.462972425], // 동해시 + "42170": [1137915.778823135, 1947378.462972425], // 동해시 "11440": [947783.55349907, 1951598.7669664049], // 마포구 "46110": [897040.76889998, 1645038.46904772], // 목포시 "46840": [899587.661355305, 1664175.9893810651], // 무안군 - "52730": [1019648.0651991949, 1770211.22681309], // 무주군 + "45730": [1019648.0651991949, 1770211.22681309], // 무주군 "47280": [1055620.11152262, 1855147.380883595], // 문경시 - "28177": [926226.3594373399, 1940093.5607894901], // 미추홀구 + "28170": [926226.3594373399, 1940093.5607894901], // 미추홀구 "48270": [1117632.749546145, 1722736.830743895], // 밀양시 "44180": [896412.984839845, 1817364.412693855], // 보령시 "46780": [974939.082074685, 1646364.3864357], // 보성군 "43720": [1018843.696119875, 1832681.50774474], // 보은군 "47920": [1125627.975921425, 1881676.019098885], // 봉화군 "26230": [1140857.032737495, 1686905.10585393], // 부산진구 - "52800": [906904.98605649, 1743711.597374285], // 부안군 + "45800": [906904.98605649, 1743711.597374285], // 부안군 "44760": [943835.889385045, 1803731.764881715], // 부여군 "41194": [937043.513148805, 1941917.36078241], // 부천시 소사구 "41196": [937651.62357278, 1948088.650724335], // 부천시 오정구 @@ -214,14 +254,14 @@ export const sigunguCenter: Record = { "48240": [1048464.90586407, 1669923.18795966], // 사천시 "26380": [1134089.12930976, 1669378.70600097], // 사하구 "48860": [1036496.214687915, 1711373.1111203502], // 산청군 - "51230": [1142435.56217199, 1918978.17539709], // 삼척시 + "42230": [1142435.56217199, 1918978.17539709], // 삼척시 "47250": [1050861.110185015, 1827830.141259105], // 상주시 "26140": [1137931.5983933099, 1678744.3981297952], // 서구 "27170": [1094695.438967345, 1764784.74637237], // 서구 "28260": [922809.601799805, 1950975.3525035651], // 서구 "29140": [941246.057711575, 1682370.2693891348], // 서구 "30170": [985795.240808525, 1808929.24401602], // 서구 - "50130": [912245.46105533, 1478972.2801259952], // 서귀포시 + "49130": [912245.46105533, 1478972.2801259952], // 서귀포시 "11410": [950162.9458121, 1953864.48715979], // 서대문구 "44210": [909519.454637895, 1868915.7895147852], // 서산시 "44770": [925279.862903135, 1788678.070235445], // 서천군 @@ -233,7 +273,7 @@ export const sigunguCenter: Record = { "11290": [957924.54027983, 1956512.99273417], // 성북구 "47840": [1065227.20912238, 1769071.96163128], // 성주군 "36110": [979381.304388835, 1841430.83666584], // 세종특별자치시 - "51210": [1089137.1194603802, 2019900.279034885], // 속초시 + "42210": [1089137.1194603802, 2019900.279034885], // 속초시 "11710": [965928.83189988, 1945132.495701395], // 송파구 "27260": [1104712.551021275, 1760363.086093105], // 수성구 "26500": [1146933.8448469099, 1686288.07716536], // 수영구 @@ -241,7 +281,7 @@ export const sigunguCenter: Record = { "41117": [961096.623048695, 1919787.236461525], // 수원시 영통구 "41111": [955699.294199125, 1924459.3724800851], // 수원시 장안구 "41115": [956709.41575029, 1919672.72074137], // 수원시 팔달구 - "52770": [962532.77503817, 1714757.02288094], // 순창군 + "45770": [962532.77503817, 1714757.02288094], // 순창군 "46150": [989441.17839757, 1668074.09581569], // 순천시 "41390": [934025.6249972349, 1932609.450570995], // 시흥시 "46910": [837068.838454425, 1628081.7615658198], // 신안군 @@ -252,14 +292,14 @@ export const sigunguCenter: Record = { "41550": [983047.68986298, 1891835.77152603], // 안성시 "41173": [951774.092625505, 1933701.863194715], // 안양시 동안구 "41171": [947757.35105343, 1934091.7197804102], // 안양시 만안구 - "51800": [1044799.8868826301, 2018930.475621245], // 양구군 + "42800": [1044799.8868826301, 2018930.475621245], // 양구군 "48330": [1140452.0009971252, 1713003.89300298], // 양산시 - "51830": [1097181.1822994999, 2001875.93591869], // 양양군 - "41630": [957059.65493005, 1978556.8707086649], // 양주시 + "42830": [1097181.1822994999, 2001875.93591869], // 양양군 + "41710": [957059.65493005, 1978556.8707086649], // 양주시 "11470": [943115.85871501, 1947726.50098438], // 양천구 "41830": [1006799.81121338, 1946640.3454016], // 양평군 "46130": [1005710.6789662449, 1606473.622557845], // 여수시 - "41670": [1007389.488139985, 1920986.5590416798], // 여주시 + "41730": [1007389.488139985, 1920986.5590416798], // 여주시 "28185": [924301.1973107599, 1932716.5874987599], // 연수구 "26470": [1143967.4104618952, 1688206.29479672], // 연제구 "41800": [955142.1788103101, 2011772.731874695], // 연천군 @@ -270,7 +310,7 @@ export const sigunguCenter: Record = { "11560": [948221.9355719599, 1946989.433783595], // 영등포구 "46830": [918568.42419672, 1645644.03685685], // 영암군 "47760": [1147157.8720550952, 1855483.55416634], // 영양군 - "51750": [1089601.7085692, 1913792.65877573], // 영월군 + "42750": [1089601.7085692, 1913792.65877573], // 영월군 "47210": [1096747.798418135, 1876468.75553605], // 영주시 "47230": [1128168.955619915, 1779896.3669964802], // 영천시 "44810": [935536.49511435, 1852175.0178411552], // 예산군 @@ -279,7 +319,7 @@ export const sigunguCenter: Record = { "43730": [1016925.1630849349, 1812306.15335931], // 옥천군 "28720": [831017.06725137, 1941763.7671776651], // 옹진군 "46890": [934681.072970785, 1580260.96434381], // 완도군 - "52710": [971714.974980355, 1764297.860421155], // 완주군 + "45710": [971714.974980355, 1764297.860421155], // 완주군 "11170": [954152.265892775, 1948105.11473188], // 용산구 "41463": [966362.167328945, 1919086.059435395], // 용인시 기흥구 "41465": [962751.309054115, 1926067.760215145], // 용인시 수지구 @@ -287,7 +327,7 @@ export const sigunguCenter: Record = { "47940": [1339459.86503077, 1939972.251018405], // 울릉군 "31710": [1152103.383022245, 1727062.6953479801], // 울주군 "47930": [1158508.6557213152, 1879083.142978875], // 울진군 - "51130": [1042675.604280725, 1925192.470561375], // 원주시 + "42130": [1042675.604280725, 1925192.470561375], // 원주시 "30200": [985050.9636310451, 1820539.200680445], // 유성구 "11380": [949045.72456328, 1957730.2124330248], // 은평구 "43770": [1010863.03644352, 1888460.954926385], // 음성군 @@ -296,17 +336,18 @@ export const sigunguCenter: Record = { "41430": [954677.940289845, 1928890.756176705], // 의왕시 "41150": [962517.29720437, 1970466.861837395], // 의정부시 "41500": [998578.52141335, 1911408.9081171248], // 이천시 - "52140": [954517.27659099, 1780482.64843965], // 익산시 - "51810": [1065461.7186508449, 2010839.9914423148], // 인제군 - "52750": [978229.1338949, 1735882.14962747], // 임실군 + "45140": [954517.27659099, 1780482.64843965], // 익산시 + "42810": [1065461.7186508449, 2010839.9914423148], // 인제군 + "45750": [978229.1338949, 1735882.14962747], // 임실군 "46880": [932255.0392670301, 1705063.362106785], // 장성군 - "52740": [1002766.6532682499, 1739693.270420835], // 장수군 + "45740": [1002766.6532682499, 1739693.270420835], // 장수군 "46800": [946864.73876017, 1628580.0165673052], // 장흥군 + "45110": [965336.86328101, 1761811.9640769851], // 전주시 "52113": [965336.86328101, 1761811.9640769851], // 전주시 덕진구 "52111": [966893.605588815, 1754468.0213283598], // 전주시 완산구 - "51770": [1110360.32014753, 1931013.538670365], // 정선군 - "52180": [947098.239651715, 1735070.37728938], // 정읍시 - "50110": [912295.3285630699, 1517557.88079664], // 제주시 + "42770": [1110360.32014753, 1931013.538670365], // 정선군 + "45180": [947098.239651715, 1735070.37728938], // 정읍시 + "49110": [910293.463, 1500596.952], //[912295.3285630699, 1517557.88079664], // 제주시 "43150": [1055671.53255738, 1893115.04197246], // 제천시 "11110": [954639.31671291, 1955652.65017071], // 종로구 "11140": [955326.326625775, 1951065.0090038702], // 중구 @@ -318,7 +359,7 @@ export const sigunguCenter: Record = { "11260": [964157.58830932, 1955182.665424475], // 중랑구 "43745": [1009013.34585424, 1864734.46162539], // 증평군 "46900": [870540.7578711801, 1597916.46618356], // 진도군 - "52720": [995028.62264954, 1758625.23076353], // 진안군 + "45720": [995028.62264954, 1758625.23076353], // 진안군 "48170": [1057167.869451315, 1689727.04548209], // 진주시 "43750": [994342.7517215649, 1875793.7535851048], // 진천군 "48740": [1090841.266427235, 1726085.44764784], // 창녕군 @@ -329,7 +370,7 @@ export const sigunguCenter: Record = { "48129": [1111617.62626141, 1680996.6599733299], // 창원시 진해구 "44131": [974478.67761805, 1862026.08139811], // 천안시 동남구 "44133": [971707.02854063, 1875704.530427825], // 천안시 서북구 - "51780": [997447.306165415, 2024301.05104793], // 철원군 + "42780": [997447.306165415, 2024301.05104793], // 철원군 "47820": [1116479.97088183, 1746481.442573125], // 청도군 "47750": [1139213.58132652, 1821067.804006115], // 청송군 "44790": [941752.03871163, 1827462.3607307798], // 청양군 @@ -337,16 +378,16 @@ export const sigunguCenter: Record = { "43112": [994258.23710022, 1838908.2251619152], // 청주시 서원구 "43114": [997183.756680205, 1857171.4242312452], // 청주시 청원구 "43113": [989161.30366111, 1849501.26145491], // 청주시 흥덕구 - "51110": [1023515.451806125, 1986727.7291947599], // 춘천시 + "42110": [1023515.451806125, 1986727.7291947599], // 춘천시 "43130": [1034982.8699803599, 1889790.67989893], // 충주시 "47850": [1086736.697665845, 1779277.075473485], // 칠곡군 - "51190": [1131634.14282853, 1912631.8063723398], // 태백시 + "42190": [1131634.14282853, 1912631.8063723398], // 태백시 "44825": [864678.84145598, 1854929.12571281], // 태안군 "48220": [1085316.421521755, 1640596.827168765], // 통영시 "41480": [941812.744809255, 1983528.9263305948], // 파주시 - "51760": [1088652.567431635, 1949959.4658569149], // 평창군 + "42760": [1088652.567431635, 1949959.4658569149], // 평창군 "41220": [952557.5035727851, 1891740.1058186102], // 평택시 - "41650": [979667.7288193901, 1996457.8400075398], // 포천시 + "41810": [979667.7288193901, 1996457.8400075398], // 포천시 "47111": [1173941.15980316, 1776164.6804896551], // 포항시 남구 "47113": [1155413.511896325, 1798939.39325854], // 포항시 북구 "41450": [974619.56368595, 1947933.69704679], // 하남시 @@ -358,10 +399,10 @@ export const sigunguCenter: Record = { "46820": [907157.24936254, 1615346.232287635], // 해남군 "26350": [1151062.0301465848, 1690808.34175552], // 해운대구 "44800": [919404.43702764, 1841255.1935457601], // 홍성군 - "51720": [1049442.09422194, 1972233.65191397], // 홍천군 + "42720": [1049442.09422194, 1972233.65191397], // 홍천군 "41590": [941810.22622111, 1906896.59289364], // 화성시 "46790": [955520.512544285, 1669429.020528105], // 화순군 - "51790": [1015098.9945956401, 2015706.532260655], // 화천군 - "51730": [1046904.40402372, 1943541.6685614302], // 횡성군 + "42790": [1015098.9945956401, 2015706.532260655], // 화천군 + "42730": [1046904.40402372, 1943541.6685614302], // 횡성군 }; diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index c5c9ef809..9da949bee 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -4,7 +4,6 @@ import React, { useCallback, useEffect, useState } from "react"; import type { ControllerRenderProps, UseFormReturn } from "react-hook-form"; import { FormField } from "../form"; import { FormUi } from "../form_ui"; -import { SelectBox } from "../select"; import { SdmSearchForm } from "./sdmNameBox"; import { SearchAddressModal } from "../search_address/SearchAddressModal"; @@ -80,6 +79,11 @@ type FieldComponent = ( field: ControllerRenderProps, ) => React.ReactElement; +const getReadonlyInputClassName = (isReadonly?: boolean) => + isReadonly + ? "!text-xl text-gray-600 bg-gray-100 cursor-default" + : "!text-xl text-gray-600"; + export function SdmRegForm({ form, onCheckboxChange, @@ -92,11 +96,6 @@ export function SdmRegForm({ readOnly, openNetwork, }: SdmRegFormProps) { - const [sidoValue, setSidoValue] = useState(""); - const [sigunValue, setSigunValue] = useState(""); - const [filteredSigunData, setFilteredSigunData] = useState([ - { text: "전체", val: "0" }, - ]); const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true); const [orgBznmNo, setOrgBznmNo] = useState(""); const [updateCoNm, setUpdateNm] = useState(""); @@ -134,46 +133,12 @@ export function SdmRegForm({ const initializeSigunData = useCallback( (sidoCd: string) => { if (sidoCd === "0") { - setSigunValue("0"); - setFilteredSigunData([{ text: "전체", val: "0" }]); + form.setValue("sggCd", ""); } else { - const newFilteredData = [ - { text: "전체", val: "0" }, - ...selectSigunData.filter( - (item: SelectDataType) => item.val.substring(0, 2) === sidoCd, - ), - ]; - setSigunValue("0"); - setFilteredSigunData(newFilteredData); + form.setValue("sggCd", ""); } }, - [selectSigunData], - ); - - const onSelectValue = useCallback( - ( - val: string, - type: string, - field: ControllerRenderProps | undefined, - ) => { - if (!updateList?.dmdInfoId) - switch (type) { - case "ctpvCd": - initializeSigunData(val); - setSidoValue(val); - field?.onChange(val); - form.setValue("dmdInfoId", ""); - form.setValue("bznmTotNo", ""); - break; - case "sggCd": - setSigunValue(val); - field?.onChange(val); - form.setValue("dmdInfoId", ""); - form.setValue("bznmTotNo", ""); - break; - } - }, - [initializeSigunData, form, updateList], + [form], ); const handleCheckboxChange = useCallback( @@ -207,13 +172,11 @@ export function SdmRegForm({ // 수요처 불러온 후 사업자번호를 바꿀경우를 대비함 setOrgBznmNo(rtnCompData?.dmdInfoId); const sidoCd = rtnCompData?.ctpvCd.trim() || ""; - setSidoValue(sidoCd); form.setValue("ctpvCd", sidoCd); initializeSigunData(sidoCd); setTimeout(() => { const sigunCd = rtnCompData?.sggCd.trim() || ""; - setSigunValue(sigunCd); form.setValue("sggCd", sigunCd); }, 100); @@ -258,7 +221,6 @@ export function SdmRegForm({ ); if (!matchedSido) return; - setSidoValue(matchedSido.val); form.setValue("ctpvCd", matchedSido.val, { shouldValidate: true }); initializeSigunData(matchedSido.val); @@ -279,7 +241,6 @@ export function SdmRegForm({ if (!matchedSigun) return; - setSigunValue(matchedSigun.val); form.setValue("sggCd", matchedSigun.val, { shouldValidate: true }); }, [form, initializeSigunData, selectSidoData, selectSigunData], @@ -364,68 +325,6 @@ export function SdmRegForm({ label: string; component: FieldComponent; }> = [ - { - name: "ctpvCd", - label: "시도", - component: (field) => - updateList?.dmdInfoId ? ( - { - field.onChange(e.target.value); - }} - value={ - selectSidoData.find((item) => item.val === field.value?.trim()) - ?.text ?? "" - } - readOnly={!!updateList?.dmdInfoId} - /> - ) : ( - - onSelectValue(val.toString(), "ctpvCd", field ?? "") - } - className="" - value={sidoValue} - /> - ), - }, - { - name: "sggCd", - label: "시군구", - component: (field) => - updateList?.dmdInfoId ? ( - { - field.onChange(e.target.value); - }} - value={ - selectSigunData.find((item) => item.val === field.value?.trim()) - ?.text ?? "" - } - readOnly={!!updateList?.dmdInfoId} - /> - ) : ( - - onSelectValue(val.toString(), "sggCd", field) - } - className="" - value={sigunValue} - /> - ), - }, { name: "dmdCoNm", label: "회사명", @@ -449,7 +348,7 @@ export function SdmRegForm({ bznNoChange(e, "dmdInfoId", field)} value={formatBusinessNumber(field.value ?? "")} readOnly={!!updateList?.dmdInfoId} @@ -468,7 +367,7 @@ export function SdmRegForm({ bznNoChange(e, "bznmTotNo", field)} // {...field} @@ -488,7 +387,7 @@ export function SdmRegForm({ {/* 우편번호 */} { const value = e.target.value; @@ -521,13 +420,51 @@ export function SdmRegForm({ ), }, + { + name: "ctpvCd", + label: "시도", + component: (field) => ( + { + field.onChange(e.target.value); + }} + value={ + selectSidoData.find((item) => item.val === field.value?.trim()) + ?.text ?? "" + } + readOnly={true} + /> + ), + }, + { + name: "sggCd", + label: "시군구", + component: (field) => ( + { + field.onChange(e.target.value); + }} + value={ + selectSigunData.find((item) => item.val === field.value?.trim()) + ?.text ?? "" + } + readOnly={true} + /> + ), + }, { name: "telno", label: "전화번호", @@ -538,7 +475,7 @@ export function SdmRegForm({ { @@ -557,7 +494,7 @@ export function SdmRegForm({