diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..c3f502a19 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# 디폴트 무시된 파일 +/shelf/ +/workspace.xml +# 에디터 기반 HTTP 클라이언트 요청 +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/apps/common/features/src/widgets/post/ui/post-form.tsx b/apps/common/features/src/widgets/post/ui/post-form.tsx index ae2a84856..8025f123d 100644 --- a/apps/common/features/src/widgets/post/ui/post-form.tsx +++ b/apps/common/features/src/widgets/post/ui/post-form.tsx @@ -77,7 +77,7 @@ function PostForm({ - 제목 + 제목 ({ {!userInfo?.userUnqId && ( - 비밀번호 + 비밀번호 >(new Map()); const [tableSort, setTableSort] = useState(""); - const [postParams, setPostParams] = useState({ + const [keywordType, setKeywordType] = useState("title"); + const [keyword, setKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ keywordType: "title", keyword: "", }); @@ -58,7 +60,7 @@ function PostPage({ bbsId }: { bbsId: string }) { queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, bbsInfo], queryFn: () => PostApi.getPostList(parseInt(bbsId), { - ...postParams, + ...searchParams, upndFixYn: bbsInfo?.upndFixUseYn, }), select: (data) => { @@ -79,10 +81,16 @@ function PostPage({ bbsId }: { bbsId: string }) { isLoading, refetch, } = useQuery({ - queryKey: [ENDPOINT.BOARD_SERVICE.POSTS_USER, bbsId, pagination, tableSort], + queryKey: [ + ENDPOINT.BOARD_SERVICE.POSTS_USER, + bbsId, + searchParams, + pagination, + tableSort, + ], queryFn: () => PostApi.getPostList(parseInt(bbsId), { - ...postParams, + ...searchParams, ansUseYn: bbsInfo?.ansUseYn, page: pagination.pageIndex, size: pagination.pageSize, @@ -128,7 +136,29 @@ function PostPage({ bbsId }: { bbsId: string }) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keywordType, + keyword, + }); + }; + + const handleReset = () => { + setKeywordType("title"); + setKeyword(""); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keywordType: "title", + keyword: "", + }); }; const handleRowClick = (row: Post) => { @@ -141,12 +171,7 @@ function PostPage({ bbsId }: { bbsId: string }) {
- @@ -157,15 +182,21 @@ function PostPage({ bbsId }: { bbsId: string }) { - setPostParams({ ...postParams, keyword: e.target.value }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]" /> +
diff --git a/apps/common/features/start_13000.sh b/apps/common/features/start_13000.sh new file mode 100755 index 000000000..e1ba84bbf --- /dev/null +++ b/apps/common/features/start_13000.sh @@ -0,0 +1,25 @@ +#!/bin/bash + +PORT=13000 +LOG_FILE="start_13000.log" + +# 1. 기존 포트 사용 프로세스 종료 +PID=$(lsof -t -i :$PORT) +if [ -n "$PID" ]; then + echo "Killing process on port $PORT (PID: $PID)" + kill -9 $PID +fi + +# 2. 백그라운드로 앱 시작 (로그 파일로 리디렉션) +echo "Starting app on port $PORT..." +nohup pnpm start > $LOG_FILE 2>&1 & + +# 3. PID 확인 +sleep 1 +NEW_PID=$(lsof -t -i :$PORT) +if [ -n "$NEW_PID" ]; then + echo "App started successfully (PID: $NEW_PID)" + echo "Logs: tail -f $LOG_FILE" +else + echo "Failed to start app. Check logs: $LOG_FILE" +fi \ No newline at end of file diff --git a/apps/cs/src/entities/apilog/api/apilog-service.ts b/apps/cs/src/entities/apilog/api/apilog-service.ts index d7167950c..8c7bdb309 100644 --- a/apps/cs/src/entities/apilog/api/apilog-service.ts +++ b/apps/cs/src/entities/apilog/api/apilog-service.ts @@ -9,12 +9,11 @@ import type { export class ApiLogApiService implements ApiLogService { public async getApiLogList(params: ApiLogParams): Promise { const response = await client.get( - `${ENDPOINT.USER_SERVICE.APILOG}`, + `${ENDPOINT.CMS_SERVICE.APILOG}`, { params }, ); return response.data; } - } export const ApiLogApi = new ApiLogApiService(); diff --git a/apps/cs/src/entities/apilog/model/apilog-interface.ts b/apps/cs/src/entities/apilog/model/apilog-interface.ts index f00e583ad..0b41d796f 100644 --- a/apps/cs/src/entities/apilog/model/apilog-interface.ts +++ b/apps/cs/src/entities/apilog/model/apilog-interface.ts @@ -2,8 +2,9 @@ import type { PageableList, PageableParams } from "@/shared/model"; export interface ApiLogParams extends PageableParams { siteId?: string; - userId?: string; + userUnqId?: string; userNm?: string; + userId?: string; apiHttpPmhd?: string; dmndUrl?: string; ipAddr?: string; diff --git a/apps/cs/src/entities/content/api/contents-service.ts b/apps/cs/src/entities/content/api/contents-service.ts index 00d2a8c67..347764aa7 100644 --- a/apps/cs/src/entities/content/api/contents-service.ts +++ b/apps/cs/src/entities/content/api/contents-service.ts @@ -85,6 +85,15 @@ export class ContentsApiService implements ContentsService { `${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}/approve`, ); } + + public async rejectContents( + contsSn: number, + contsVer: number, + ): Promise { + await client.put( + `${ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS}/${contsSn}/${contsVer}/reject`, + ); + } } export const ContentsApi = new ContentsApiService(); diff --git a/apps/cs/src/entities/content/model/contents-interface.ts b/apps/cs/src/entities/content/model/contents-interface.ts index 72456149b..7709eea08 100644 --- a/apps/cs/src/entities/content/model/contents-interface.ts +++ b/apps/cs/src/entities/content/model/contents-interface.ts @@ -97,4 +97,5 @@ export interface ContentsService { deleteContents(contsSn: number, contsVer: number): Promise; requestApprove(contsSn: number, contsVer: number): Promise; approveContents(contsSn: number, contsVer: number): Promise; + rejectContents(contsSn: number, contsVer: number): Promise; } diff --git a/apps/cs/src/entities/group-user/model/group-user-interface.ts b/apps/cs/src/entities/group-user/model/group-user-interface.ts index 8935bfacc..52fa97fce 100644 --- a/apps/cs/src/entities/group-user/model/group-user-interface.ts +++ b/apps/cs/src/entities/group-user/model/group-user-interface.ts @@ -3,6 +3,7 @@ import type { PageableList, PageableParams } from "@/shared/model"; // 그룹 사용자 검색 파라미터 인터페이스 export interface GroupUserSearchParams extends PageableParams { keyword?: string; + userNm?: string; } // 그룹 사용자 목록 응답 인터페이스 diff --git a/apps/cs/src/entities/group/index.ts b/apps/cs/src/entities/group/index.ts index da1d72a41..30dc07714 100644 --- a/apps/cs/src/entities/group/index.ts +++ b/apps/cs/src/entities/group/index.ts @@ -3,4 +3,5 @@ export { groupFormSchema, type GroupFormData, type GroupListResponseDto, + type GroupSearchParams, } from "./model/group-interface"; diff --git a/apps/cs/src/entities/group/model/group-interface.ts b/apps/cs/src/entities/group/model/group-interface.ts index f8cc9883f..58e9a4489 100644 --- a/apps/cs/src/entities/group/model/group-interface.ts +++ b/apps/cs/src/entities/group/model/group-interface.ts @@ -56,7 +56,10 @@ export const groupFormSchema = z.object({ groupNm: z.string().min(1, { message: "그룹명을 입력해주세요." }), groupSeCd: z.string().min(1, { message: "그룹구분을 선택해주세요." }), groupExpln: z.string().optional(), - delYn: z.string().default("N"), + delYn: z + .string() + .transform((val) => (val === "" || val === undefined ? "N" : val)) + .default("N"), authrtId: z.string().min(1, { message: "권한ID를 선택해주세요." }), siteId: z.string().optional(), mngrYn: z.string().default("N"), diff --git a/apps/cs/src/entities/menu-authority/ui/management-authority-dialog.tsx b/apps/cs/src/entities/menu-authority/ui/management-authority-dialog.tsx index a9ba18333..2d4f6a176 100644 --- a/apps/cs/src/entities/menu-authority/ui/management-authority-dialog.tsx +++ b/apps/cs/src/entities/menu-authority/ui/management-authority-dialog.tsx @@ -74,7 +74,7 @@ function ManagementAuthorityDialog({ menuCd }: ManagementAuthorityDialogProps) { diff --git a/apps/cs/src/entities/menu/api/menu-service.ts b/apps/cs/src/entities/menu/api/menu-service.ts index 4424f8d37..33ad06837 100644 --- a/apps/cs/src/entities/menu/api/menu-service.ts +++ b/apps/cs/src/entities/menu/api/menu-service.ts @@ -1,6 +1,12 @@ import { client } from "@/shared/api"; import { ENDPOINT } from "@/shared/config"; -import type { MenuItem, MenuService } from "../model/menu-interface"; +import type { + MenuService, + Menu, + MenuItem, + MenuFormData, + MenuTemporarilyStoredData, +} from "../model/menu-interface"; export class MenuApiService implements MenuService { async getMenuRoles(siteId: string): Promise { @@ -9,6 +15,56 @@ export class MenuApiService implements MenuService { ); return response.data; } + + public async getMenuInfo(menuCd: number): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`, + ); + return response.data; + } + + public async createMenu(data: MenuFormData): Promise { + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.MENUS}`, + data, + ); + return response.data; + } + + public async updateMenu( + menuCd: number, + data: Omit, + ): Promise { + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`, + data, + ); + return response.data; + } + + public async deleteMenu(menuCd: number): Promise { + await client.delete(`${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`); + } + + public async menuTemporaryStorage( + menuCd: number, + data: MenuFormData, + ): Promise { + const response = await client.post( + `${ENDPOINT.CMS_SERVICE.MENU_TEMPORARY_STORAGE}/${menuCd}`, + data, + ); + return response.data; + } + + public async getMenuTemporarilyStoredData( + menuCd: number, + ): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.MENU_TEMPORARY_STORAGE}/menu/${menuCd}/user`, + ); + return response.data; + } } export const MenuApi = new MenuApiService(); diff --git a/apps/cs/src/entities/menu/index.ts b/apps/cs/src/entities/menu/index.ts index 04f63e38b..e4a9cec40 100644 --- a/apps/cs/src/entities/menu/index.ts +++ b/apps/cs/src/entities/menu/index.ts @@ -1,2 +1,9 @@ +export { MenuApi } from "./api/menu-service"; +export { + MENU_TYPE, + menuFormSchema, + type MenuType, + type MenuItem, + type MenuFormData, +} from "./model/menu-interface"; export { MenuWrapper } from "./lib/menu-wrapper"; -export type { MenuItem } from "./model/menu-interface"; diff --git a/apps/cs/src/entities/menu/model/menu-interface.ts b/apps/cs/src/entities/menu/model/menu-interface.ts index 12c7d007a..b1693f616 100644 --- a/apps/cs/src/entities/menu/model/menu-interface.ts +++ b/apps/cs/src/entities/menu/model/menu-interface.ts @@ -1,3 +1,16 @@ +import { z } from "zod"; + +export const MENU_TYPE = { + EMPTY: "EMPTY", + CONTENTS: "CONTENTS", + BOARD: "BOARD", + INSIDE: "INSIDE", + OUTSIDE: "OUTSIDE", + BOTTOM: "BOTTOM", +} as const; + +export type MenuType = (typeof MENU_TYPE)[keyof typeof MENU_TYPE]; + export interface MenuItem { menuCd: number; menuKornNm: string; @@ -18,6 +31,65 @@ export interface MenuItem { requiredUrlPath: boolean; } +export interface MenuTemporarilyStoredData { + tmprStrgSn: number; + menuCd: number; + menuTmprStrg: string; + regDt: string; + rgtr: string; + mdfcnDt: string; + mdfr: string; +} + +export const menuFormSchema = z.object({ + siteId: z.string(), + menuKornNm: z.string(), + menuSubKornNm: z.string().nullish(), + menuEngNm: z.string().nullish(), + menuSubEngNm: z.string().nullish(), + levelNo: z.number(), + urlPath: z.string().nullish(), + iconNm: z.string().nullish(), + menuLnkgTypeCd: z.enum([ + MENU_TYPE.EMPTY, + MENU_TYPE.CONTENTS, + MENU_TYPE.BOARD, + MENU_TYPE.INSIDE, + MENU_TYPE.OUTSIDE, + MENU_TYPE.BOTTOM, + ]), + menuLnkgSn: z.number().nullish(), + otptYn: z.string().default("Y"), + prntMenuCd: z.number().nullish(), + sortSeq: z.number(), + evlUseYn: z.string().default("Y"), + qrcd: z.string().nullish(), + useYn: z.string().default("Y"), + newWndwYn: z.string().nullish(), + menuLnkgSnNm: z.string().nullish(), + menuPicUserUnqId: z.string().nullish(), + menuPicUserUnqIdNm: z.string().nullish(), + menuPicDsgnYmd: z.string().nullish(), +}); + +export type MenuFormData = z.infer; + +export type Menu = Omit & { + menuCd: number; + iconName?: string; +}; + export interface MenuService { getMenuRoles(siteId: string): Promise; + getMenuInfo: (menuCd: number) => Promise; + createMenu: (data: MenuFormData) => Promise; + updateMenu: ( + menuCd: number, + data: Omit, + ) => Promise; + deleteMenu: (menuCd: number) => Promise; + menuTemporaryStorage: (menuCd: number, data: MenuFormData) => Promise; + getMenuTemporarilyStoredData: ( + menuCd: number, + ) => Promise; } diff --git a/apps/cs/src/pages/admin/ui/admin-page.tsx b/apps/cs/src/pages/admin/ui/admin-page.tsx index a4cd5265d..95d2c4e91 100644 --- a/apps/cs/src/pages/admin/ui/admin-page.tsx +++ b/apps/cs/src/pages/admin/ui/admin-page.tsx @@ -38,10 +38,14 @@ function AdminPage() { const alert = useAlertStore((state) => state.setMessage); const { confirm } = useConfirm(); - const [adminQuery, setAdminQuery] = useState({ + const [keywordType, setKeywordType] = useState(""); + const [keyword, setKeyword] = useState(""); + const [grpId, setGrpId] = useState(""); + const [searchParams, setSearchParams] = useState({ keywordType: "", keyword: "", grpId: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -66,10 +70,10 @@ function AdminPage() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.USERS, pagination], + queryKey: [ENDPOINT.USER_SERVICE.USERS, searchParams, pagination], queryFn: () => UserApi.findPageAdminUser({ - ...adminQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -123,7 +127,28 @@ function AdminPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keywordType, + keyword, + grpId, + }); + }; + + const handleReset = () => { + setKeywordType(""); + setKeyword(""); + setGrpId(""); + setSearchParams({ + ...searchParams, + keywordType: "", + keyword: "", + grpId: "", + }); }; const handleDeleteAdmins = async () => { @@ -161,11 +186,7 @@ function AdminPage() {
- setGrpId(value)}> @@ -183,9 +204,8 @@ function AdminPage() { 관리자 - setAdminQuery({ ...adminQuery, keyword: e.target.value }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} placeholder="검색어 입력" />
+
diff --git a/apps/cs/src/pages/apilog/ui/apilog-page.tsx b/apps/cs/src/pages/apilog/ui/apilog-page.tsx index 51cc960f3..cbcb3dc9a 100644 --- a/apps/cs/src/pages/apilog/ui/apilog-page.tsx +++ b/apps/cs/src/pages/apilog/ui/apilog-page.tsx @@ -26,36 +26,32 @@ type DateRange = { to?: Date | undefined; }; -function ApiLogPage({}) { - // 1주일 전부터 오늘까지 기본 날짜 설정 +function ApiLogPage() { const defaultDateRange: DateRange = { from: dayjs().subtract(7, "day").toDate(), to: dayjs().toDate(), }; - const [dateRange, setDateRange] = useState(defaultDateRange); - const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10, }); - - const [loginlogPostQuery, setLoginlogPostQuery] = useState({ + const [dateRange, setDateRange] = useState(defaultDateRange); + const [userId, setUserId] = useState(""); + const [apiHttpPmhd, setApiHttpPmhd] = useState(""); + const [searchParams, setSearchParams] = useState({ userId: "", - siteId: "", apiHttpPmhd: "", - dmndUrl: "", - ipAddr: "", dmndDtStart: dayjs().subtract(7, "day").format("YYYY-MM-DD"), dmndDtEnd: dayjs().format("YYYY-MM-DD"), - sort: "lgnDt,asc", + sort: "regDt,desc", }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.LOGINLOG, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.APILOG, searchParams, pagination], queryFn: () => ApiLogApi.getApiLogList({ - ...loginlogPostQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -81,13 +77,31 @@ function ApiLogPage({}) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + userId, + apiHttpPmhd, + dmndDtStart: dayjs(dateRange.from).format("YYYY-MM-DD"), + dmndDtEnd: dayjs(dateRange.to).format("YYYY-MM-DD"), + }); }; - const handleLoginlogParamsChange = - (key: keyof ApiLogParams) => (value: unknown) => { - setLoginlogPostQuery({ ...loginlogPostQuery, [key]: value }); - }; + const handleReset = () => { + setUserId(""); + setApiHttpPmhd(""); + setDateRange(defaultDateRange); + setSearchParams({ + ...searchParams, + userId: "", + apiHttpPmhd: "", + dmndDtStart: dayjs().subtract(7, "day").format("YYYY-MM-DD"), + dmndDtEnd: dayjs().format("YYYY-MM-DD"), + }); + }; const handlePresetDateRange = (value: string) => { let presetDateRange: DateRange | undefined; @@ -113,19 +127,7 @@ function ApiLogPage({}) { default: presetDateRange = undefined; } - handleDateRangeChange(presetDateRange); - }; - - const handleDateRangeChange = (value: DateRange | undefined) => { - setDateRange(value || defaultDateRange); - setLoginlogPostQuery({ - ...loginlogPostQuery, - dmndDtStart: - dayjs(value?.from).format("YYYY-MM-DD") ?? - dayjs().subtract(7, "day").format("YYYY-MM-DD"), - dmndDtEnd: - dayjs(value?.to).format("YYYY-MM-DD") ?? dayjs().format("YYYY-MM-DD"), - }); + setDateRange(presetDateRange || defaultDateRange); }; return ( @@ -135,7 +137,7 @@ function ApiLogPage({}) { setDateRange(value || defaultDateRange)} >
setUserId(e.target.value)} className="h-[3.2rem] w-[20rem] rounded-sm !text-[1.3rem]" - value={loginlogPostQuery.userId} - onChange={(e) => - handleLoginlogParamsChange("userId")(e.target.value) - } /> - setApiHttpPmhd(value)} + > @@ -173,12 +176,20 @@ function ApiLogPage({}) { +
-

로그인로그 목록

+

작업로그 목록

- setBannerQuery({ ...bannerQuery, bnrTtl: e.target.value }) - } + value={bnrTtl} + onChange={(e) => setBnrTtl(e.target.value)} /> +
diff --git a/apps/cs/src/pages/bbs/ui/bbs-form.tsx b/apps/cs/src/pages/bbs/ui/bbs-form.tsx index 3d7482bce..3de8342d9 100644 --- a/apps/cs/src/pages/bbs/ui/bbs-form.tsx +++ b/apps/cs/src/pages/bbs/ui/bbs-form.tsx @@ -54,7 +54,7 @@ function BbsForm({ form, bbsId, ...props }: BbsFormProps) { - 게시판명 + 게시판명 - 게시판 설명 + 게시판 설명 - 게시판 유형 + 게시판 유형 - 참조 사용 여부 + 참조 사용 여부 - 첨부파일 사용 여부 + 첨부파일 사용 여부 - 답글 사용 여부 + 답글 사용 여부 - 댓글 사용 여부 + 댓글 사용 여부 - 게시물평가 사용 여부 + 게시물평가 사용 여부 - 팝업 사용 여부 + 팝업 사용 여부 - SMS알림 사용 여부 + SMS알림 사용 여부 - 상단고정 사용 여부 + 상단고정 사용 여부 - 게시기간 사용 여부 + 게시기간 사용 여부 - 개인정보 표시 여부 + 개인정보 표시 여부 - 사용 여부 + 사용 여부 ({}); - const [boardParams, setBoardParams] = useState({ + const [bbsTypeCd, setBbsTypeCd] = useState(""); + const [bbsNm, setBbsNm] = useState(""); + const [searchParams, setSearchParams] = useState({ bbsTypeCd: "", bbsNm: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -39,10 +42,10 @@ function BbsPage() { }); const query = useQuery({ - queryKey: [ENDPOINT.BOARD_SERVICE.BBS, pagination], + queryKey: [ENDPOINT.BOARD_SERVICE.BBS, searchParams, pagination], queryFn: () => BoardApi.getBoardList({ - ...boardParams, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -50,7 +53,25 @@ function BbsPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + bbsTypeCd, + bbsNm, + }); + }; + + const handleReset = () => { + setBbsTypeCd(""); + setBbsNm(""); + setSearchParams({ + ...searchParams, + bbsTypeCd: "", + bbsNm: "", + }); }; const handleRowClick = (row: Board) => { @@ -86,10 +107,8 @@ function BbsPage() { - setBoardParams({ ...boardParams, bbsTypeCd: value }) - } + value={bbsTypeCd} + onValueChange={(value) => setBbsTypeCd(value)} />
diff --git a/apps/cs/src/pages/code/model/lwpocode-table-columns.tsx b/apps/cs/src/pages/code/model/lwpocode-table-columns.tsx index 1bea87275..a119d88d9 100644 --- a/apps/cs/src/pages/code/model/lwpocode-table-columns.tsx +++ b/apps/cs/src/pages/code/model/lwpocode-table-columns.tsx @@ -5,56 +5,62 @@ import type { LwpoCode } from "@/entities/code"; import { LwpoCodeManagementDialog } from "../ui/lwpocode-dialog"; import { useState } from "react"; -export const columns: ColumnDef[] = [ - { - id: "no", - header: "NO", - cell: ({ row, table }) => { - const totalRows = table.getRowCount(); - const { pageIndex, pageSize } = table.getState().pagination; - return totalRows - (pageIndex * pageSize + row.index); +// columns를 함수로 변경하여 onAfterSave를 주입받음 +export function getColumns(onAfterSave: () => void) : ColumnDef[] { + return [ + { + id: "no", + header: "NO", + cell: ({ row, table }) => { + const totalRows = table.getRowCount(); + const { pageIndex, pageSize } = table.getState().pagination; + return totalRows - (pageIndex * pageSize + row.index); + }, }, - }, - { - accessorKey: "lwpoCd", - header: "하위코드", - }, - { - accessorKey: "lwpoCdNm", - header: "하위코드명", - }, - { - accessorKey: "useYn", - header: "사용 여부", - }, - { - accessorKey: "regDt", - header: "등록일", - cell: ({ row }) => { - const date = dayjs(row.original.regDt); - return date.format("YYYY-MM-DD"); + { + accessorKey: "lwpoCd", + header: "하위코드", }, - }, - { - id: "actions", - header: "관리", - cell: ({ row }) => ( -
e.stopPropagation()}> - -
- ), - }, -]; + { + accessorKey: "lwpoCdNm", + header: "하위코드명", + }, + { + accessorKey: "useYn", + header: "사용 여부", + }, + { + accessorKey: "regDt", + header: "등록일", + cell: ({ row }) => { + const date = dayjs(row.original.regDt); + return date.format("YYYY-MM-DD"); + }, + }, + { + id: "actions", + header: "관리", + cell: ({ row }) => ( +
e.stopPropagation()}> + +
+ ), + }, + ]; +} const LwpoCodeManageButton = ({ lwpoCd, upCd, + onAfterSave, }: { lwpoCd: string; upCd: string; + onAfterSave: () => void; }) => { const [dialogOpen, setDialogOpen] = useState(false); return ( @@ -63,6 +69,7 @@ const LwpoCodeManageButton = ({ upCd={upCd} open={dialogOpen} onOpenChange={setDialogOpen} + onAfterSave={onAfterSave} > diff --git a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx index c11c57332..d21f5b60a 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-dialog.tsx @@ -1,7 +1,7 @@ import { memo } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useQuery } from "@tanstack/react-query"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useConfirm } from "@frontend-opensource/use-react-hooks"; import { Button, @@ -38,6 +38,7 @@ type ManagementLwpoCodeDialogProps = { children?: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void; + onAfterSave?: () => void; // 콜백 추가 }; const LwpoCodeManagementDialog = memo( @@ -47,17 +48,18 @@ const LwpoCodeManagementDialog = memo( children, open, onOpenChange, + onAfterSave, // 콜백 사용 ...props }: ManagementLwpoCodeDialogProps) => { const isRegistration = !lwpoCd; - const { confirm } = useConfirm(); + const queryClient = useQueryClient(); const alert = useAlertStore((state) => state.setMessage); const { data: detailData } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, lwpoCd], queryFn: () => LwpoCodeApi.lwpoCodeDetail(upCd!, lwpoCd!), - enabled: !!upCd && !isRegistration, + enabled: !!upCd && !isRegistration && open, }); const { data: upCodeData } = useQuery({ @@ -69,7 +71,13 @@ const LwpoCodeManagementDialog = memo( const { mutateAsync: createLwpoCode } = useMutationWrapper({ mutationFn: (data: LwpoCodeFormData) => LwpoCodeApi.createLwpoCode(data), onSuccess: () => { - alert("등록되었습니다.", () => onOpenChange?.(false)); + alert("등록되었습니다.", () => { + onOpenChange?.(false); + onAfterSave?.(); + }); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd], + }); }, }); @@ -77,7 +85,10 @@ const LwpoCodeManagementDialog = memo( mutationFn: (data: LwpoCodeFormData) => LwpoCodeApi.updateLwpoCode(upCd!, lwpoCd!, data), onSuccess: () => { - alert("수정되었습니다.", () => onOpenChange?.(false)); + alert("수정되었습니다.", () => { + onOpenChange?.(false); + onAfterSave?.(); + }); }, }); @@ -96,15 +107,38 @@ const LwpoCodeManagementDialog = memo( }, }); - const onSubmit = - (callback: (data: LwpoCodeFormData) => void) => - async (data: LwpoCodeFormData) => { - const confirmMessage = isRegistration - ? "등록하시겠습니까?" - : "수정하시겠습니까?"; - - if (await confirm(confirmMessage)) callback(data); - }; + const handleRegister = async () => { + if (!upCd) { + alert("상위코드가 없습니다."); + return; + } + const confirmMessage = "등록하시겠습니까?"; + if (await confirm(confirmMessage)) { + const rawValues = form.getValues(); + const values = { + ...rawValues, + upCd: upCd, + sortSeq: Number(rawValues.sortSeq) || 0, + }; + await createLwpoCode(values); + } + }; + const handleSave = async () => { + if (!upCd) { + alert("상위코드가 없습니다."); + return; + } + const confirmMessage = "수정하시겠습니까?"; + if (await confirm(confirmMessage)) { + const rawValues = form.getValues(); + const values = { + ...rawValues, + upCd: upCd, + sortSeq: Number(rawValues.sortSeq) || 0, + }; + await updateLwpoCode(values); + } + }; return ( @@ -117,9 +151,14 @@ const LwpoCodeManagementDialog = memo(
{ + e.preventDefault(); + if (isRegistration) { + handleRegister(); + } else { + handleSave(); + } + }} className="space-y-4" > @@ -251,6 +290,9 @@ const LwpoCodeManagementDialog = memo( {...field} type="number" value={field.value ?? 0} + onChange={(e) => { + field.onChange(parseInt(e.target.value)); + }} className="!text-[1.3rem]" placeholder="정렬순서를 입력해주세요" /> @@ -292,7 +334,11 @@ const LwpoCodeManagementDialog = memo(
- diff --git a/apps/cs/src/pages/code/ui/lwpocode-section.tsx b/apps/cs/src/pages/code/ui/lwpocode-section.tsx index b1713fa0f..9692c842d 100644 --- a/apps/cs/src/pages/code/ui/lwpocode-section.tsx +++ b/apps/cs/src/pages/code/ui/lwpocode-section.tsx @@ -5,7 +5,7 @@ import { Button, Input, Label } from "@common/components"; import { LwpoCodeApi, type LwpoCodeParams } from "@/entities/code"; import { ENDPOINT } from "@/shared/config"; import { useAlertStore, useDataTable } from "@/shared/lib"; -import { columns } from "../model/lwpocode-table-columns"; +import { getColumns } from "../model/lwpocode-table-columns"; import { LwpoCodeManagementDialog } from "./lwpocode-dialog"; type LwpoCodeSectionProps = { @@ -15,8 +15,10 @@ type LwpoCodeSectionProps = { function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { const alert = useAlertStore((state) => state.setMessage); const [dialogOpen, setDialogOpen] = useState(false); - const [lwpoCodeQuery, setLwpoCodeQuery] = useState({ + const [lwpoCdNm, setLwpoCdNm] = useState(""); + const [searchParams, setSearchParams] = useState({ lwpoCdNm: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -24,10 +26,10 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.LWPO_CODE, upCd, searchParams, pagination], queryFn: () => LwpoCodeApi.getLwpoCodeList({ - ...lwpoCodeQuery, + ...searchParams, upCd, page: pagination.pageIndex, size: pagination.pageSize, @@ -36,6 +38,12 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { placeholderData: keepPreviousData, }); + // 등록/수정 후 목록 재조회 콜백 + const handleAfterSave = () => { + query.refetch(); + }; + const columns = getColumns(handleAfterSave); + const { mutateAsync: codeRefreshAll } = useMutation({ mutationFn: LwpoCodeApi.codeRefreshAll, onSuccess: () => { @@ -59,7 +67,22 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + lwpoCdNm, + }); + }; + + const handleReset = () => { + setLwpoCdNm(""); + setSearchParams({ + ...searchParams, + lwpoCdNm: "", + }); }; useEffect(() => { @@ -75,17 +98,20 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { - setLwpoCodeQuery({ - ...lwpoCodeQuery, - lwpoCdNm: e.target.value, - }) - } + value={lwpoCdNm} + onChange={(e) => setLwpoCdNm(e.target.value)} /> +
@@ -96,8 +122,10 @@ function LwpoCodeSection({ upCd }: LwpoCodeSectionProps) { 코드갱신 diff --git a/apps/cs/src/pages/code/ui/upcode-section.tsx b/apps/cs/src/pages/code/ui/upcode-section.tsx index ffae0f28b..a9e5f6de8 100644 --- a/apps/cs/src/pages/code/ui/upcode-section.tsx +++ b/apps/cs/src/pages/code/ui/upcode-section.tsx @@ -14,8 +14,10 @@ type UpCodeSectionProps = { function UpCodeSection({ handleSelectedUpCd }: UpCodeSectionProps) { const [dialogOpen, setDialogOpen] = useState(false); - const [upCodeQuery, setUpCodeQuery] = useState({ + const [keyword, setKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ keyword: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -23,10 +25,10 @@ function UpCodeSection({ handleSelectedUpCd }: UpCodeSectionProps) { }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.UP_CODE, searchParams, pagination], queryFn: () => UpCodeApi.getUpCodeList({ - ...upCodeQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -40,7 +42,22 @@ function UpCodeSection({ handleSelectedUpCd }: UpCodeSectionProps) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keyword, + }); + }; + + const handleReset = () => { + setKeyword(""); + setSearchParams({ + ...searchParams, + keyword: "", + }); }; const { tableComponent, tableInstance: table } = useDataTable({ @@ -66,17 +83,20 @@ function UpCodeSection({ handleSelectedUpCd }: UpCodeSectionProps) { - setUpCodeQuery({ - ...upCodeQuery, - keyword: e.target.value, - }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} /> +
diff --git a/apps/cs/src/pages/contents/ui/contents-form.tsx b/apps/cs/src/pages/contents/ui/contents-form.tsx index 9db8035b0..01462925f 100644 --- a/apps/cs/src/pages/contents/ui/contents-form.tsx +++ b/apps/cs/src/pages/contents/ui/contents-form.tsx @@ -60,7 +60,7 @@ function ContentsForm({ - 콘텐츠 제목 + 콘텐츠 제목 - 콘텐츠 내용 + 콘텐츠 내용 - 사용여부 + 사용여부 ({ + const [contsTtl, setContsTtl] = useState(""); + const [searchParams, setSearchParams] = useState({ contsTtl: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS, searchParams, pagination], queryFn: () => ContentsApi.getContentsList({ - ...contentsQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -38,7 +40,22 @@ function ContentsPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + contsTtl, + }); + }; + + const handleReset = () => { + setContsTtl(""); + setSearchParams({ + ...searchParams, + contsTtl: "", + }); }; const handleRowClick = (row: Contents) => { @@ -72,12 +89,20 @@ function ContentsPage() { setContentsQuery({ contsTtl: e.target.value })} + value={contsTtl} + onChange={(e) => setContsTtl(e.target.value)} /> +
diff --git a/apps/cs/src/pages/contents/ui/modify-page.tsx b/apps/cs/src/pages/contents/ui/modify-page.tsx index 8bf3b629d..e783e9c1c 100644 --- a/apps/cs/src/pages/contents/ui/modify-page.tsx +++ b/apps/cs/src/pages/contents/ui/modify-page.tsx @@ -97,6 +97,16 @@ function ModifyPage({ sequential }: { sequential: string }) { }, }); + const { mutateAsync: rejectContents } = useMutationWrapper({ + mutationFn: () => ContentsApi.rejectContents(contsSn, contsVer), + onSuccess: () => { + alert("반려되었습니다."); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.CONTENTS_DETAILS], + }); + }, + }); + const form = useForm({ resolver: zodResolver(contentsFormSchema), values: contentsDetail, @@ -107,14 +117,20 @@ function ModifyPage({ sequential }: { sequential: string }) { (contentsVersionList?.content?.[0]?.contsVer ?? 0) > 1; const onRequestApprove = async () => { - const message = - "승인 요청하면 더이상 내용을 수정할 수 없습니다.\n요청하시겠습니까?"; - if (await confirm(message)) requestApprove(); + if ( + await confirm( + "승인 요청하면 더이상 내용을 수정할 수 없습니다.\n요청하시겠습니까?", + ) + ) + requestApprove(); }; const onApprove = async () => { - const message = "승인하시겠습니까?"; - if (await confirm(message)) approveContents(); + if (await confirm("승인하시겠습니까?")) approveContents(); + }; + + const onReject = async () => { + if (await confirm("반려하시겠습니까?")) rejectContents(); }; useEffect(() => { @@ -158,7 +174,9 @@ function ModifyPage({ sequential }: { sequential: string }) { {approveStatus === CONTENTS_APPROVE_STATUS.REQUESTED && ( <> - + )}
diff --git a/apps/cs/src/pages/file/ui/file-page.tsx b/apps/cs/src/pages/file/ui/file-page.tsx index 67a313423..8243d47d1 100644 --- a/apps/cs/src/pages/file/ui/file-page.tsx +++ b/apps/cs/src/pages/file/ui/file-page.tsx @@ -14,8 +14,10 @@ function FilePage() { const { confirm } = useConfirm(); const alert = useAlertStore((state) => state.setMessage); - const [attachmentQuery, setAttachmentQuery] = useState({ + const [orgnlFileNm, setOrgnlFileNm] = useState(""); + const [searchParams, setSearchParams] = useState({ orgnlFileNm: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -23,10 +25,10 @@ function FilePage() { }); const query = useQuery({ - queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, pagination], + queryKey: [ENDPOINT.ATTACH_SERVICE.ATTACHMENTS, searchParams, pagination], queryFn: () => AttachmentApi.getAttachmentsList({ - ...attachmentQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -64,14 +66,24 @@ function FilePage() { }, }); - const handleAttachmentQueryChange = - (key: keyof AttachmentParams) => (value: string) => { - setAttachmentQuery({ ...attachmentQuery, [key]: value }); - }; - const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + orgnlFileNm, + }); + }; + + const handleReset = () => { + setOrgnlFileNm(""); + setSearchParams({ + ...searchParams, + orgnlFileNm: "", + }); }; return ( @@ -86,10 +98,8 @@ function FilePage() { - handleAttachmentQueryChange("orgnlFileNm")(e.target.value) - } + value={orgnlFileNm} + onChange={(e) => setOrgnlFileNm(e.target.value)} placeholder="파일명을 입력하세요" />
@@ -97,6 +107,14 @@ function FilePage() { +
diff --git a/apps/cs/src/pages/groups/model/groups-table-columns.tsx b/apps/cs/src/pages/groups/model/groups-table-columns.tsx index 70f91efa0..18ad4e78a 100644 --- a/apps/cs/src/pages/groups/model/groups-table-columns.tsx +++ b/apps/cs/src/pages/groups/model/groups-table-columns.tsx @@ -4,7 +4,11 @@ import { type GroupListResponseDto } from "@/entities/group"; import { MenuAuthorityDialog } from "../ui/menu-authority-dialog"; import { GroupsDialog } from "../ui/groups-dialog"; -export const columns: ColumnDef[] = [ +export const createColumns = ({ + onDelete, +}: { + onDelete: (groupId: string) => void; +}): ColumnDef[] => [ { accessorKey: "groupId", header: "그룹코드", @@ -20,18 +24,28 @@ export const columns: ColumnDef[] = [ { id: "actions", header: "관리", - cell: ({ row }) => ( -
e.stopPropagation()} - className="flex justify-center gap-2" - > - - - + + - -
- ), +
+ ); + }, }, ]; diff --git a/apps/cs/src/pages/groups/ui/group-form.tsx b/apps/cs/src/pages/groups/ui/group-form.tsx index 423718435..6c1d8b67f 100644 --- a/apps/cs/src/pages/groups/ui/group-form.tsx +++ b/apps/cs/src/pages/groups/ui/group-form.tsx @@ -37,7 +37,7 @@ function GroupForm({ form }: GroupFormProps) { - 그룹코드 + 그룹코드 - 그룹명 + 그룹명 - 그룹구분 + 그룹구분 - 관리권한 + 관리권한 - 권한 + 권한 ({}); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.GROUP_USERS, groupId, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.GROUP_USERS, groupId, pagination, userNm], queryFn: () => GroupUsersApi.findPageGroupUser({ keyword: groupId, + userNm: userNm, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -46,6 +50,20 @@ function GroupUsersSection({ groupId }: GroupUsersSectionProps) { placeholderData: keepPreviousData, }); + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + // userNm이 이미 state에 반영되어 있으므로 별도 처리 불필요 + // 쿼리키에 userNm이 포함되어 있어 자동 refetch됨 + }; + + const handleReset = () => { + setUserNm(""); + }; + const { tableComponent, tableInstance: table } = useDataTable({ query, tableOptions: { @@ -97,6 +115,29 @@ function GroupUsersSection({ groupId }: GroupUsersSectionProps) { return (
+
+
+ + setUserNm(e.target.value)} + /> + + +
+

그룹 사용자 목록

diff --git a/apps/cs/src/pages/groups/ui/groups-dialog.tsx b/apps/cs/src/pages/groups/ui/groups-dialog.tsx index d21852886..427ba4b1b 100644 --- a/apps/cs/src/pages/groups/ui/groups-dialog.tsx +++ b/apps/cs/src/pages/groups/ui/groups-dialog.tsx @@ -43,7 +43,7 @@ const GroupsDialog = memo( const { data: group } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.GROUPS, groupId], queryFn: () => GroupApi.findGroupById(groupId!), - enabled: !!groupId, + enabled: !!groupId && open, // open 시점 groupId가 있을 때만 상세 조회 API 호출 }); const { mutateAsync: createGroup } = useMutationWrapper({ diff --git a/apps/cs/src/pages/groups/ui/groups-section.tsx b/apps/cs/src/pages/groups/ui/groups-section.tsx index f5d1e026b..9c7f5b6ca 100644 --- a/apps/cs/src/pages/groups/ui/groups-section.tsx +++ b/apps/cs/src/pages/groups/ui/groups-section.tsx @@ -1,14 +1,20 @@ "use client"; import { useState } from "react"; -import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { + keepPreviousData, + useQuery, + useQueryClient, +} from "@tanstack/react-query"; import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; -import { Button } from "@common/components"; -import { GroupApi } from "@/entities/group"; +import { Button, Input, Label } from "@common/components"; +import { GroupApi , type GroupSearchParams} from "@/entities/group"; import { ENDPOINT } from "@/shared/config"; import { useDataTable } from "@/shared/lib"; -import { columns } from "../model/groups-table-columns"; +import { createColumns } from "../model/groups-table-columns"; import { GroupsDialog } from "./groups-dialog"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { useAlertStore, useMutationWrapper } from "@/shared/lib"; type GroupsSectionProps = { handleSelectedGroup: (groupId: string) => void; @@ -20,25 +26,73 @@ function GroupsSection({ handleSelectedGroup }: GroupsSectionProps) { pageSize: 10, }); + const [groupNm, setGroupNm] = useState(""); + const [searchParams, setSearchParams] = useState({ + groupNm: "", + delYn :"N", + sort : "groupId,desc", + }); + + + const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.GROUPS, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.GROUPS,searchParams, pagination], queryFn: () => GroupApi.findPageGroup({ + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), placeholderData: keepPreviousData, }); + const { confirm } = useConfirm(); + const alert = useAlertStore((state) => state.setMessage); + const queryClient = useQueryClient(); + const { mutateAsync: deleteGroup } = useMutationWrapper({ + mutationFn: (groupId: string) => GroupApi.deleteGroup(groupId), + onSuccess: () => { + alert("삭제되었습니다."); + queryClient.invalidateQueries({ + predicate: (query) => query.queryKey[0] === ENDPOINT.CMS_SERVICE.GROUPS, + }); + }, + }); + const handleDelete = async (groupId: string) => { + if (await confirm("삭제하시겠습니까?")) { + await deleteGroup(groupId); + } + }; + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + groupNm, + }); + }; + + const handleReset = () => { + setGroupNm(""); + setSearchParams({ + ...searchParams, + groupNm: "", + delYn:"N" + }); + }; const handleRowClick = (row: { groupId: string }) => { table.setRowSelection({ [row.groupId]: true }); - handleSelectedGroup(row.groupId); + handleSelectedGroup(row.groupId); // 1. 리스트에서 선택된 groupId 저장 }; const { tableComponent, tableInstance: table } = useDataTable({ query, tableOptions: { - columns, + columns: createColumns({ onDelete: handleDelete }), state: { pagination }, manualPagination: true, enableMultiRowSelection: false, @@ -54,6 +108,43 @@ function GroupsSection({ handleSelectedGroup }: GroupsSectionProps) { return (
+
+
+ + setGroupNm(e.target.value)} + /> + + + + + setSearchParams({ + ...searchParams, + delYn: e.target.checked ? "Y" : "N", + }) + } + /> +
+

그룹 목록

diff --git a/apps/cs/src/pages/image/ui/image-form.tsx b/apps/cs/src/pages/image/ui/image-form.tsx index 0368ace33..1de7820c5 100644 --- a/apps/cs/src/pages/image/ui/image-form.tsx +++ b/apps/cs/src/pages/image/ui/image-form.tsx @@ -42,8 +42,9 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) { file: uploadFile, response: uploadResponse, progress, + isValid, setFile, - } = useTus(); + } = useTus({ accept: ".jpeg,.jpg,.png" }); const setAttachmentFileCode = useAttachmentStore( (state) => state.setAttachmentFileCode, ); @@ -90,7 +91,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) { - 이미지명 + 이미지명 - 정렬순서 + 정렬순서 - 이미지유형 + 이미지유형 - 첨부파일 + 첨부파일
@@ -269,7 +272,7 @@ function ImageForm({ form, imgSn, ...props }: ImageFormProps) { )} - 사용여부 + 사용여부 ({}); - const [postingTargets, setPostingTargets] = useState([]); - const [imageQuery, setImageQuery] = useState({ - keyword: "" , - sort:"regDt,desc" + const [keyword, setKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ + keyword: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); + const [rowSelection, setRowSelection] = useState({}); + const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.IMAGES, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.IMAGES, searchParams, pagination], queryFn: () => ImageApi.getImageList({ - ...imageQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -47,7 +48,22 @@ function ImagePage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keyword, + }); + }; + + const handleReset = () => { + setKeyword(""); + setSearchParams({ + ...searchParams, + keyword: "", + }); }; const handleRowClick = (row: Image) => { @@ -99,14 +115,20 @@ function ImagePage() { - setImageQuery({ ...imageQuery, keyword: e.target.value }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} /> +
diff --git a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx index 1672a5bd8..cbfb53a07 100644 --- a/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx +++ b/apps/cs/src/pages/loginlog/ui/loginlog-page.tsx @@ -27,8 +27,7 @@ type DateRange = { to?: Date | undefined; }; -function LoginlogPage({}) { - // 1주일 전부터 오늘까지 기본 날짜 설정 +function LoginlogPage() { const defaultDateRange: DateRange = { from: dayjs().subtract(7, "day").toDate(), to: dayjs().toDate(), @@ -41,24 +40,21 @@ function LoginlogPage({}) { pageIndex: 0, pageSize: 10, }); - - const [loginlogPostQuery, setLoginlogPostQuery] = useState({ + const [userId, setUserId] = useState(""); + const [errOcrnYn, setErrOcrnYn] = useState("N"); + const [searchParams, setSearchParams] = useState({ userId: "", - siteId: "", errOcrnYn: "N", - remoteIp: "", - lgnMthd: "", - lgnErrCd: "", searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), searchDateTo: dayjs().format("YYYY-MM-DD"), sort: "lgnDt,desc", }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.LOGINLOG, pagination], + queryKey: [ENDPOINT.USER_SERVICE.LOGINLOG, searchParams, pagination], queryFn: () => LoginlogApi.getLoginlogList({ - ...loginlogPostQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -85,15 +81,34 @@ function LoginlogPage({}) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); setIsManualLoading(true); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + userId, + errOcrnYn, + searchDateFrom: dayjs(dateRange.from).format("YYYY-MM-DD"), + searchDateTo: dayjs(dateRange.to).format("YYYY-MM-DD"), + }); query.refetch().finally(() => { setIsManualLoading(false); }); }; - const handleLoginlogParamsChange = - (key: keyof LoginlogParams) => (value: unknown) => { - setLoginlogPostQuery({ ...loginlogPostQuery, [key]: value }); - }; + const handleReset = () => { + setUserId(""); + setErrOcrnYn("N"); + setDateRange(defaultDateRange); + setSearchParams({ + ...searchParams, + userId: "", + errOcrnYn: "N", + searchDateFrom: dayjs().subtract(7, "day").format("YYYY-MM-DD"), + searchDateTo: dayjs().format("YYYY-MM-DD"), + }); + }; const handlePresetDateRange = (value: string) => { let presetDateRange: DateRange | undefined; @@ -119,19 +134,7 @@ function LoginlogPage({}) { default: presetDateRange = undefined; } - handleDateRangeChange(presetDateRange); - }; - - const handleDateRangeChange = (value: DateRange | undefined) => { - setDateRange(value || defaultDateRange); - setLoginlogPostQuery({ - ...loginlogPostQuery, - searchDateFrom: - dayjs(value?.from).format("YYYY-MM-DD") ?? - dayjs().subtract(7, "day").format("YYYY-MM-DD"), - searchDateTo: - dayjs(value?.to).format("YYYY-MM-DD") ?? dayjs().format("YYYY-MM-DD"), - }); + setDateRange(presetDateRange || defaultDateRange); }; return ( @@ -141,7 +144,7 @@ function LoginlogPage({}) { setDateRange(value || defaultDateRange)} >
- handleLoginlogParamsChange("userId")(e.target.value) - } + value={userId} + onChange={(e) => setUserId(e.target.value)} /> - setErrOcrnYn(value)} + > @@ -183,6 +187,14 @@ function LoginlogPage({}) { ? "조회 중..." : "조회"} +
diff --git a/apps/cs/src/pages/menu/api/menu-history-service.ts b/apps/cs/src/pages/menu/api/menu-history-service.ts new file mode 100644 index 000000000..ecb31878b --- /dev/null +++ b/apps/cs/src/pages/menu/api/menu-history-service.ts @@ -0,0 +1,28 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { PageableList } from "@/shared/model"; +import type { + MenuHistory, + MenuHistorySearchParams, + MenuHistoryService, +} from "../model/menu-history-interface"; + +export class MenuHistoryApiService implements MenuHistoryService { + public async getMenuHistoryList( + params: MenuHistorySearchParams, + ): Promise> { + const response = await client.get>( + `${ENDPOINT.CMS_SERVICE.MENU_HISTORY}`, + { params }, + ); + return response.data; + } + + public async rollbackMenu(hstrySn: number): Promise { + await client.post(`${ENDPOINT.CMS_SERVICE.MENU_HISTORY}/rollback`, { + hstrySn, + }); + } +} + +export const MenuHistoryApi = new MenuHistoryApiService(); diff --git a/apps/cs/src/pages/menu/api/menu-service.ts b/apps/cs/src/pages/menu/api/menu-service.ts deleted file mode 100644 index dbb67cb3e..000000000 --- a/apps/cs/src/pages/menu/api/menu-service.ts +++ /dev/null @@ -1,65 +0,0 @@ -import { client } from "@/shared/api"; -import { ENDPOINT } from "@/shared/config"; -import type { - Menu, - MenuFormData, - MenuService, - TreeMenu, - TreeNode, -} from "../model/menu-interface"; - -export class MenuApiService implements MenuService { - public async getMenuInfo(menuCd: number): Promise { - const response = await client.get( - `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`, - ); - return response.data; - } - - public async createMenu(data: MenuFormData): Promise { - const response = await client.post( - `${ENDPOINT.CMS_SERVICE.MENUS}`, - data, - ); - return response.data; - } - - public async updateMenu( - menuCd: number, - data: Omit, - ): Promise { - const response = await client.put( - `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`, - data, - ); - return response.data; - } - - public async deleteMenu(menuCd: number): Promise { - await client.delete(`${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}`); - } - - public async getTreeMenuList(siteId: string): Promise { - const response = await client.get( - `${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree`, - ); - return response.data; - } - - public async updateTreeMenu(siteId: string, data: TreeNode[]): Promise { - const response = await client.put( - `${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree`, - data, - ); - return response.data; - } - - public async updateMenuName(menuCd: number, name: string): Promise { - const response = await client.put( - `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}/${name}`, - ); - return response.data; - } -} - -export const MenuApi = new MenuApiService(); diff --git a/apps/cs/src/pages/menu/api/tree-menu-service.ts b/apps/cs/src/pages/menu/api/tree-menu-service.ts new file mode 100644 index 000000000..9f36f5383 --- /dev/null +++ b/apps/cs/src/pages/menu/api/tree-menu-service.ts @@ -0,0 +1,33 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; +import type { + TreeMenuService, + TreeMenu, + TreeNode, +} from "../model/tree-menu-interface"; + +export class TreeMenuApiService implements TreeMenuService { + public async getTreeMenuList(siteId: string): Promise { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree`, + ); + return response.data; + } + + public async updateTreeMenu(siteId: string, data: TreeNode[]): Promise { + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree`, + data, + ); + return response.data; + } + + public async updateMenuName(menuCd: number, name: string): Promise { + const response = await client.put( + `${ENDPOINT.CMS_SERVICE.MENUS}/${menuCd}/${name}`, + ); + return response.data; + } +} + +export const TreeMenuApi = new TreeMenuApiService(); diff --git a/apps/cs/src/pages/menu/lib/utils.ts b/apps/cs/src/pages/menu/lib/utils.ts index f6d13be33..a5cb921a6 100644 --- a/apps/cs/src/pages/menu/lib/utils.ts +++ b/apps/cs/src/pages/menu/lib/utils.ts @@ -3,7 +3,7 @@ import type { TreeUserOrganization, TreeUser, } from "@/entities/user-organization"; -import type { TreeMenu, TreeNode } from "../model/menu-interface"; +import type { TreeMenu, TreeNode } from "../model/tree-menu-interface"; export const generateMenuTreeData = ( data: TreeMenu[], @@ -153,6 +153,7 @@ export const filterUserOrganizationTreeDataByKeyword = ( ): NodeModel[] => { return Array.from( treeData.reduce((matchedNodes, node) => { + if (node.data && "ognzSn" in node.data) return matchedNodes; // 조직 노드는 필터링 제외 if (!node.text.includes(keyword)) return matchedNodes; matchedNodes.add(node); diff --git a/apps/cs/src/pages/menu/model/menu-history-columns.tsx b/apps/cs/src/pages/menu/model/menu-history-columns.tsx new file mode 100644 index 000000000..b542e0ff7 --- /dev/null +++ b/apps/cs/src/pages/menu/model/menu-history-columns.tsx @@ -0,0 +1,71 @@ +import type { ColumnDef } from "@tanstack/react-table"; +import { Checkbox } from "@common/components"; +import type { MenuHistory } from "./menu-history-interface"; +import dayjs from "dayjs"; + +export const columns: ColumnDef[] = [ + { + id: "select", + cell: ({ row }) => ( + row.toggleSelected(!!value)} + aria-label="행 선택" + /> + ), + enableSorting: false, + enableHiding: false, + }, + { + accessorKey: "chgTypeNm", + header: "이력구분", + meta: { + width: 80, + }, + }, + { + accessorKey: "menuKornNm", + header: "메뉴명", + meta: { + width: 100, + }, + }, + { + accessorKey: "bchgData", + header: "이전 데이터", + cell: ({ row }) => { + const parsed = JSON.parse(row.original.bchgData); + const stringified = JSON.stringify(parsed, null, 2); + return
{stringified}
; + }, + meta: { + width: 250, + }, + }, + { + accessorKey: "achgData", + header: "변경 데이터", + cell: ({ row }) => { + const parsed = JSON.parse(row.original.achgData); + const stringified = JSON.stringify(parsed, null, 2); + return
{stringified}
; + }, + meta: { + width: 250, + }, + }, + { + accessorKey: "regDt", + header: "변경일시", + cell: ({ row }) => { + return dayjs(row.original.regDt).format("YYYY-MM-DD HH:mm:ss"); + }, + }, + { + accessorKey: "rgtrNm", + header: "변경자", + meta: { + width: 80, + }, + }, +]; diff --git a/apps/cs/src/pages/menu/model/menu-history-interface.ts b/apps/cs/src/pages/menu/model/menu-history-interface.ts new file mode 100644 index 000000000..f3688123c --- /dev/null +++ b/apps/cs/src/pages/menu/model/menu-history-interface.ts @@ -0,0 +1,30 @@ +import type { PageableParams, PageableList } from "@/shared/model"; + +export interface MenuHistorySearchParams extends PageableParams { + keyword?: string; + keywordType?: string; + menuCd?: number; + chgTypeCd?: string; + startDt?: string; + endDt?: string; +} + +export interface MenuHistory { + hstrySn: number; + menuCd: number; + chgTypeCd: string; + chgTypeNm: string; + bchgData: string; + achgData: string; + rgtr: string; + regDt: string; + rgtrNm: string; + menuKornNm: string; +} + +export interface MenuHistoryService { + getMenuHistoryList: ( + params: MenuHistorySearchParams, + ) => Promise>; + rollbackMenu: (hstrySn: number) => Promise; +} diff --git a/apps/cs/src/pages/menu/model/menu-interface.ts b/apps/cs/src/pages/menu/model/menu-interface.ts deleted file mode 100644 index f9650e0e2..000000000 --- a/apps/cs/src/pages/menu/model/menu-interface.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { z } from "zod"; - -export const MENU_TYPE = { - EMPTY: "EMPTY", - CONTENTS: "CONTENTS", - BOARD: "BOARD", - INSIDE: "INSIDE", - OUTSIDE: "OUTSIDE", - BOTTOM: "BOTTOM", -} as const; - -export type MenuType = (typeof MENU_TYPE)[keyof typeof MENU_TYPE]; - -export interface TreeNode { - menuCd?: number; - name?: string; - sortSeq?: number; - parentId?: number | null; - levelNo?: number; - icon?: string; - children?: TreeNode[]; -} - -export interface TreeMenu extends Omit { - menuKornNm: string; - menuEngNm?: string; - iconNm?: string; - children?: TreeMenu[]; - urlPath?: string; - menuLnkgTypeCd: string; - menuLnkgSn?: number; - qrcd?: string; - useYn: string; - otptYn: string; - requiredUrlPath?: boolean; -} - -export const menuFormSchema = z.object({ - siteId: z.string(), - menuKornNm: z.string(), - menuSubKornNm: z.string().nullish(), - menuEngNm: z.string().nullish(), - menuSubEngNm: z.string().nullish(), - levelNo: z.number(), - urlPath: z.string().nullish(), - iconNm: z.string().nullish(), - menuLnkgTypeCd: z.enum([ - MENU_TYPE.EMPTY, - MENU_TYPE.CONTENTS, - MENU_TYPE.BOARD, - MENU_TYPE.INSIDE, - MENU_TYPE.OUTSIDE, - MENU_TYPE.BOTTOM, - ]), - menuLnkgSn: z.number().nullish(), - otptYn: z.string().default("Y"), - prntMenuCd: z.number().nullish(), - sortSeq: z.number(), - evlUseYn: z.string().default("Y"), - qrcd: z.string().nullish(), - useYn: z.string().default("Y"), - newWndwYn: z.string().nullish(), - menuLnkgSnNm: z.string().nullish(), - menuPicUserUnqId: z.string().nullish(), - menuPicUserUnqIdNm: z.string().nullish(), - menuPicDsgnYmd: z.string().nullish(), -}); - -export type MenuFormData = z.infer; -export type Menu = Omit & { - menuCd: number; - iconName?: string; -}; - -export interface MenuService { - getMenuInfo: (menuCd: number) => Promise; - createMenu: (data: MenuFormData) => Promise; - updateMenu: ( - menuCd: number, - data: Omit, - ) => Promise; - deleteMenu: (menuCd: number) => Promise; - getTreeMenuList: (siteId: string) => Promise; - updateTreeMenu: (siteId: string, data: TreeNode[]) => Promise; - updateMenuName: (menuCd: number, name: string) => Promise; -} diff --git a/apps/cs/src/pages/menu/model/tree-menu-interface.ts b/apps/cs/src/pages/menu/model/tree-menu-interface.ts new file mode 100644 index 000000000..39a6f92c9 --- /dev/null +++ b/apps/cs/src/pages/menu/model/tree-menu-interface.ts @@ -0,0 +1,29 @@ +export interface TreeNode { + menuCd?: number; + name?: string; + sortSeq?: number; + parentId?: number | null; + levelNo?: number; + icon?: string; + children?: TreeNode[]; +} + +export interface TreeMenu extends Omit { + menuKornNm: string; + menuEngNm?: string; + iconNm?: string; + children?: TreeMenu[]; + urlPath?: string; + menuLnkgTypeCd: string; + menuLnkgSn?: number; + qrcd?: string; + useYn: string; + otptYn: string; + requiredUrlPath?: boolean; +} + +export interface TreeMenuService { + getTreeMenuList: (siteId: string) => Promise; + updateTreeMenu: (siteId: string, data: TreeNode[]) => Promise; + updateMenuName: (menuCd: number, name: string) => Promise; +} diff --git a/apps/cs/src/pages/menu/ui/base-menu-form.tsx b/apps/cs/src/pages/menu/ui/base-menu-form.tsx index fceb66549..ff27db932 100644 --- a/apps/cs/src/pages/menu/ui/base-menu-form.tsx +++ b/apps/cs/src/pages/menu/ui/base-menu-form.tsx @@ -10,8 +10,8 @@ import { TableHead, TableRow, } from "@common/components"; +import { MENU_TYPE, type MenuFormData } from "@/entities/menu"; import { FormItem, FormControl, FormField } from "@/shared/ui/form"; -import { MENU_TYPE, type MenuFormData } from "../model/menu-interface"; import { InfoTooltip } from "@/shared/ui/info-tooltip"; interface BaseMenuFormProps { @@ -85,7 +85,7 @@ function BaseMenuForm({ form, menuCd }: BaseMenuFormProps) { - 메뉴 유형 + 메뉴 유형 ; @@ -29,8 +41,22 @@ function MenuForm({ handleDelete, }: MenuFormProps) { const isModifyMode = !!menuCd; - + const [open, setOpen] = useState(false); const { confirm } = useConfirm(); + const alert = useAlertStore((state) => state.setMessage); + + const { data: menuTemporarilyStoredData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.MENU_TEMPORARY_STORAGE, menuCd], + queryFn: () => MenuApi.getMenuTemporarilyStoredData(menuCd!), + enabled: !!menuCd, + }); + + const { mutate: menuTemporaryStorage } = useMutationWrapper({ + mutationFn: () => MenuApi.menuTemporaryStorage(menuCd!, form.getValues()), + onSuccess: () => { + alert("메뉴 임시 저장이 완료되었습니다."); + }, + }); const onSubmit = async (data: MenuFormData) => { if (isModifyMode) { @@ -58,36 +84,102 @@ function MenuForm({ } }; + const handleMenuTemporaryStorage = () => { + if (!menuCd || !menuFormSchema.parse(form.getValues())) return; + menuTemporaryStorage(); + }; + + const handleLoadTemporaryData = () => { + if (!menuTemporarilyStoredData?.[0]?.menuTmprStrg) { + alert("불러올 임시 저장 데이터가 없습니다."); + return; + } + + const storedData = menuTemporarilyStoredData[0].menuTmprStrg; + const parsedData = JSON.parse(storedData); + form.reset(parsedData); + }; + const menuType = form.watch("menuLnkgTypeCd"); const isSubmitDisabled = !form.watch("siteId"); return ( -
- -
-
-

- {isModifyMode ? "메뉴 수정" : "메뉴 등록"} -

- + <> + + +
+
+

+ {isModifyMode ? "메뉴 수정" : "메뉴 등록"} +

+
+ + +
+
+
+ + +
-
- - -
-
-
- - {isModifyMode && ( - + )} + {isModifyMode && ( + + )} + {isModifyMode && ( + + )} + - )} -
- - + {isModifyMode && ( + + )} +
+ + + + + + 메뉴 미리보기 + +
+ +
+
+
+ ); } diff --git a/apps/cs/src/pages/menu/ui/menu-history-dialog.tsx b/apps/cs/src/pages/menu/ui/menu-history-dialog.tsx new file mode 100644 index 000000000..a24b77308 --- /dev/null +++ b/apps/cs/src/pages/menu/ui/menu-history-dialog.tsx @@ -0,0 +1,163 @@ +import { useEffect, useState } from "react"; +import { useQuery, useQueryClient } from "@tanstack/react-query"; +import { + getCoreRowModel, + type PaginationState, + type RowSelectionState, +} from "@tanstack/react-table"; +import { useConfirm } from "@frontend-opensource/use-react-hooks"; +import { + Button, + Dialog, + DialogClose, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, + DialogTrigger, + Input, + Label, +} from "@common/components"; +import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useDataTable, useMutationWrapper } from "@/shared/lib"; +import { MenuHistoryApi } from "../api/menu-history-service"; +import type { MenuHistorySearchParams } from "../model/menu-history-interface"; +import { columns } from "../model/menu-history-columns"; + +type MenuHistoryDialogProps = { + menuCd?: number; +} & React.ComponentProps; + +function MenuHistoryDialog({ menuCd }: MenuHistoryDialogProps) { + const { confirm } = useConfirm(); + const queryClient = useQueryClient(); + const alert = useAlertStore((state) => state.setMessage); + + const [open, setOpen] = useState(false); + const [pagination, setPagination] = useState({ + pageIndex: 0, + pageSize: 10, + }); + const [searchParams, setSearchParams] = useState({ + keyword: "", + keywordType: "menuKornNm", + }); + const [rowSelection, setRowSelection] = useState({}); + const selectedHistoryId = parseInt(Object.keys(rowSelection)[0] ?? "0"); + + const query = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.MENU_HISTORY, pagination], + queryFn: () => + MenuHistoryApi.getMenuHistoryList({ + ...searchParams, + menuCd, + page: pagination.pageIndex, + size: pagination.pageSize, + }), + enabled: !!menuCd && open, + }); + + const { mutateAsync: rollbackMenu } = useMutationWrapper({ + mutationFn: (hstrySn: number) => MenuHistoryApi.rollbackMenu(hstrySn), + onSuccess: () => { + alert("메뉴가 성공적으로 복원되었습니다."); + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.MENUS], + }); + setOpen(false); + }, + }); + + const handleRollback = async (hstrySn: number) => { + if (!(await confirm("메뉴를 '이전 데이터'로 되돌리시겠습니까?"))) return; + await rollbackMenu(hstrySn); + }; + + const { tableComponent } = useDataTable({ + query, + tableOptions: { + columns, + state: { pagination, rowSelection }, + manualPagination: true, + enableRowSelection: true, + enableMultiRowSelection: false, + onPaginationChange: setPagination, + onRowSelectionChange: setRowSelection, + getCoreRowModel: getCoreRowModel(), + getRowId: (row) => row.hstrySn.toString(), + }, + dataTableOptions: { + viewPagination: true, + }, + }); + + const handleSearch = (e: React.FormEvent) => { + e.preventDefault(); + e.stopPropagation(); + query.refetch(); + }; + + useEffect(() => { + if (open) { + setSearchParams({ + ...searchParams, + keyword: "", + }); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setRowSelection({}); + } + }, [open]); + + return ( + + + + + + + 메뉴 이력 관리 + + +
+
+ + + setSearchParams({ ...searchParams, keyword: e.target.value }) + } + className="w-[36rem]" + /> + +
+
+ +
{tableComponent}
+ + + + + + + +
+
+ ); +} + +export { MenuHistoryDialog }; diff --git a/apps/cs/src/pages/menu/ui/menu-node.tsx b/apps/cs/src/pages/menu/ui/menu-node.tsx index 5cda4f522..4a2b3624f 100644 --- a/apps/cs/src/pages/menu/ui/menu-node.tsx +++ b/apps/cs/src/pages/menu/ui/menu-node.tsx @@ -4,8 +4,8 @@ import type { NodeModel, TreeMethods } from "@minoru/react-dnd-treeview"; import { Button, cn } from "@common/components"; import { useMutationWrapper } from "@/shared/lib"; import { ENDPOINT } from "@/shared/config"; -import { MenuApi } from "../api/menu-service"; -import type { TreeMenu } from "../model/menu-interface"; +import { TreeMenuApi } from "../api/tree-menu-service"; +import type { TreeMenu } from "../model/tree-menu-interface"; import { EditableNode } from "./editable-node"; type MenuNodeProps = { @@ -37,7 +37,7 @@ function MenuNode({ const { mutateAsync: updateMenuName } = useMutationWrapper({ mutationFn: (nodeName: string) => { const encodedName = encodeURIComponent(nodeName); - return MenuApi.updateMenuName(id as number, encodedName); + return TreeMenuApi.updateMenuName(id as number, encodedName); }, onSuccess: () => { queryClient.invalidateQueries({ diff --git a/apps/cs/src/pages/menu/ui/menu-page.tsx b/apps/cs/src/pages/menu/ui/menu-page.tsx index d212dc970..2d3dedc16 100644 --- a/apps/cs/src/pages/menu/ui/menu-page.tsx +++ b/apps/cs/src/pages/menu/ui/menu-page.tsx @@ -14,19 +14,20 @@ import { SelectTrigger, SelectValue, } from "@common/components"; -import { SiteApi } from "@/entities/site"; -import { ENDPOINT } from "@/shared/config"; -import { useAlertStore, useMutationWrapper } from "@/shared/lib"; -import type { TreeMenu } from "../model/menu-interface"; -import { MenuApi } from "../api/menu-service"; import { + MenuApi, MENU_TYPE, menuFormSchema, type MenuFormData, -} from "../model/menu-interface"; +} from "@/entities/menu"; +import { SiteApi } from "@/entities/site"; +import { ENDPOINT } from "@/shared/config"; +import { useAlertStore, useMutationWrapper } from "@/shared/lib"; +import { generateMenuTreeData } from "../lib/utils"; +import { TreeMenuApi } from "../api/tree-menu-service"; +import type { TreeMenu } from "../model/tree-menu-interface"; import { MenuTree } from "./menu-tree"; import { MenuForm } from "./menu-form"; -import { generateMenuTreeData } from "../lib/utils"; function MenuPage() { const queryClient = useQueryClient(); @@ -46,7 +47,7 @@ function MenuPage() { const { data: menuTreeData } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId], - queryFn: () => MenuApi.getTreeMenuList(siteId), + queryFn: () => TreeMenuApi.getTreeMenuList(siteId), select: (data) => { const treeData = generateMenuTreeData(data); const defaultSortSeq = diff --git a/apps/cs/src/pages/menu/ui/menu-tree.tsx b/apps/cs/src/pages/menu/ui/menu-tree.tsx index a1fa4dacb..5ef15062c 100644 --- a/apps/cs/src/pages/menu/ui/menu-tree.tsx +++ b/apps/cs/src/pages/menu/ui/menu-tree.tsx @@ -11,8 +11,9 @@ import { import { Button } from "@common/components"; import { ENDPOINT } from "@/shared/config"; import { useMutationWrapper } from "@/shared/lib"; -import { MenuApi } from "../api/menu-service"; -import type { MenuFormData, TreeMenu, TreeNode } from "../model/menu-interface"; +import type { MenuFormData } from "@/entities/menu"; +import { TreeMenuApi } from "../api/tree-menu-service"; +import type { TreeMenu, TreeNode } from "../model/tree-menu-interface"; import { handleDropNode, handleSelectNode } from "../lib/utils"; import { MenuNode } from "./menu-node"; import { EditableNode } from "./editable-node"; @@ -41,7 +42,7 @@ function MenuTree({ const { mutate: updateTreeMenu } = useMutationWrapper({ mutationFn: (newTree: TreeNode) => - MenuApi.updateTreeMenu(siteId, [newTree]), + TreeMenuApi.updateTreeMenu(siteId, [newTree]), onSuccess: () => { queryClient.invalidateQueries({ queryKey: [ENDPOINT.CMS_SERVICE.MENUS], diff --git a/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx b/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx index 19e3fcf87..eb942fe11 100644 --- a/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx +++ b/apps/cs/src/pages/menu/ui/organization-search-dialog.tsx @@ -12,7 +12,9 @@ import { import { Button, Dialog, + DialogClose, DialogContent, + DialogFooter, DialogHeader, DialogTitle, DialogTrigger, @@ -52,10 +54,22 @@ function OrganizationSearchDialog({ }); const handleSelectNode = (node: NodeModel) => { + if (node.data && "ognzSn" in node.data) return; setSelectedNode(node); handleUserSelect(node.data as TreeUser); }; + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + e.stopPropagation(); + setTree(filterUserOrganizationTreeDataByKeyword(treeData ?? [], keyword)); + }; + + const handleReset = () => { + setKeyword(""); + setTree(treeData ?? []); + }; + useEffect(() => { setTree(treeData ?? []); }, [treeData]); @@ -73,21 +87,25 @@ function OrganizationSearchDialog({ 담당자 조회
-
- setKeyword(e.target.value)} - /> - +
+
+ setKeyword(e.target.value)} + /> + + +
@@ -116,6 +134,16 @@ function OrganizationSearchDialog({
+ + + + + + + + ); diff --git a/apps/cs/src/pages/menu/ui/type-menu-form.tsx b/apps/cs/src/pages/menu/ui/type-menu-form.tsx index ac62e2520..41c0741e8 100644 --- a/apps/cs/src/pages/menu/ui/type-menu-form.tsx +++ b/apps/cs/src/pages/menu/ui/type-menu-form.tsx @@ -16,8 +16,8 @@ import { import type { BoardPopup } from "@/entities/board"; import type { Contents } from "@/entities/content"; import type { TreeUser } from "@/entities/user-organization"; +import type { MenuFormData, MenuType } from "@/entities/menu"; import { FormItem, FormControl, FormField } from "@/shared/ui/form"; -import type { MenuFormData, MenuType } from "../model/menu-interface"; import { OrganizationSearchDialog } from "./organization-search-dialog"; import { ContentSearchDialog } from "./content-search-dialog"; import { BoardSearchDialog } from "./board-search-dialog"; @@ -171,7 +171,7 @@ function TypeMenuForm({ form, menuType }: TypeMenuFormProps) { )} {(menuType === "CONTENTS" || menuType === "BOARD") && ( - 메뉴 평가 사용 여부 + 메뉴 평가 사용 여부 - 출력 여부 + 출력 여부 - 사용 여부 + 사용 여부 - API명 + API명 - API URL + API URL - 요청 메소드 + 요청 메소드 - 정렬순서 + 정렬순서 - 사용여부 + 사용여부 ({ - authorizationName: "", - httpMethodCode: "", - }); + const [authorizationName, setAuthorizationName] = useState(""); + const [httpMethodCode, setHttpMethodCode] = useState(""); + const [searchParams, setSearchParams] = useState({ + authorizationName: "", + httpMethodCode: "", + sort: "regDt,desc", + }); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10, }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.AUTHORIZATIONS, pagination], + queryKey: [ENDPOINT.USER_SERVICE.AUTHORIZATIONS, searchParams, pagination], queryFn: () => AuthorizationsApi.getAuthorizationsList({ - ...authorizationQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -60,14 +62,27 @@ function ModulePage() { }, }); - const handleAuthorizationQueryChange = - (key: keyof AuthorizationsParams) => (value: string) => { - setAuthorizationQuery({ ...authorizationQuery, [key]: value }); - }; - const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + authorizationName, + httpMethodCode, + }); + }; + + const handleReset = () => { + setAuthorizationName(""); + setHttpMethodCode(""); + setSearchParams({ + ...searchParams, + authorizationName: "", + httpMethodCode: "", + }); }; return ( @@ -81,7 +96,8 @@ function ModulePage() { setHttpMethodCode(value)} />
@@ -91,18 +107,22 @@ function ModulePage() { - handleAuthorizationQueryChange("authorizationName")( - e.target.value, - ) - } + value={authorizationName} + onChange={(e) => setAuthorizationName(e.target.value)} />
+
diff --git a/apps/cs/src/pages/organization/ui/organization-form.tsx b/apps/cs/src/pages/organization/ui/organization-form.tsx index 438ed3549..3b5d3659d 100644 --- a/apps/cs/src/pages/organization/ui/organization-form.tsx +++ b/apps/cs/src/pages/organization/ui/organization-form.tsx @@ -87,7 +87,7 @@ function OrganizationForm({ - 조직명 + 조직명 - 정렬순서 + 정렬순서 { + await client.delete(`${ENDPOINT.CMS_SERVICE.POPUPS}/${popupSn}`); + } } export const PopupApi = new PopupApiService(); diff --git a/apps/cs/src/pages/popup/model/popup-interface.ts b/apps/cs/src/pages/popup/model/popup-interface.ts index 6952d873f..c565df8ca 100644 --- a/apps/cs/src/pages/popup/model/popup-interface.ts +++ b/apps/cs/src/pages/popup/model/popup-interface.ts @@ -68,4 +68,5 @@ export interface PopupService { getPopupInfo(popupSn: number): Promise; createPopup(data: PopupFormData): Promise; updatePopup(popupSn: number, data: PopupUpdateFormData): Promise; + deletePopup(popupSn: number): Promise; } diff --git a/apps/cs/src/pages/popup/ui/modify-page.tsx b/apps/cs/src/pages/popup/ui/modify-page.tsx index fed70cbbb..cffce11bd 100644 --- a/apps/cs/src/pages/popup/ui/modify-page.tsx +++ b/apps/cs/src/pages/popup/ui/modify-page.tsx @@ -52,6 +52,13 @@ function ModifyPage({ popupSn }: { popupSn: number }) { }, }); + const { mutateAsync: deletePopup } = useMutationWrapper({ + mutationFn: () => PopupApi.deletePopup(popupSn), + onSuccess: () => { + alert("삭제되었습니다.", router.back); + }, + }); + const { mutateAsync: savePostingHistory } = useMutationWrapper({ mutationFn: (data: PostPayload[]) => PostingApi.savePosting(data), onSuccess: () => { @@ -101,7 +108,12 @@ function ModifyPage({ popupSn }: { popupSn: number }) {

팝업 수정

- +
diff --git a/apps/cs/src/pages/popup/ui/popup-form.tsx b/apps/cs/src/pages/popup/ui/popup-form.tsx index 8e1e5783f..4580fa19e 100644 --- a/apps/cs/src/pages/popup/ui/popup-form.tsx +++ b/apps/cs/src/pages/popup/ui/popup-form.tsx @@ -32,7 +32,7 @@ const Editor = dynamic( type PopupFormProps = { form: UseFormReturn; - popupSn?: string; + popupSn?: number; handleSave: (data: T) => Promise; handleDelete?: () => Promise; }; @@ -80,7 +80,7 @@ function PopupForm({ - 제목 + 제목 ({ - 팝업 크기 + 팝업 크기
({ - 팝업 위치 + 팝업 위치
({ - 팝업 유형 + 팝업 유형 ({ - 콘텐츠 유형 + 콘텐츠 유형 ({ - 팝업 그만 보기 사용 여부 + 팝업 그만 보기 사용 여부 ({ - 사용 여부 + 사용 여부 ({ + const [keyword, setKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ keyword: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -36,10 +38,10 @@ function PopupPage() { const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.POPUPS, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.POPUPS, searchParams, pagination], queryFn: () => PopupApi.getPopupList({ - ...popupParams, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -48,7 +50,22 @@ function PopupPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keyword, + }); + }; + + const handleReset = () => { + setKeyword(""); + setSearchParams({ + ...searchParams, + keyword: "", + }); }; const handleRowClick = (row: Popup) => { @@ -99,14 +116,20 @@ function PopupPage() { - setPopupParams({ ...popupParams, keyword: e.target.value }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} /> +
diff --git a/apps/cs/src/pages/privacylog/model/table-columns.tsx b/apps/cs/src/pages/privacylog/model/table-columns.tsx index a5b52d796..d84b16524 100644 --- a/apps/cs/src/pages/privacylog/model/table-columns.tsx +++ b/apps/cs/src/pages/privacylog/model/table-columns.tsx @@ -27,7 +27,7 @@ export const columns: ColumnDef[] = [ }, { accessorKey: "rqstrNm", - header: "조회자명", + header: "요청자명", }, { accessorKey: "rqstrIp", diff --git a/apps/cs/src/pages/privacylog/ui/privacylog-page.tsx b/apps/cs/src/pages/privacylog/ui/privacylog-page.tsx index 5cb8bf13d..8207ca9e6 100644 --- a/apps/cs/src/pages/privacylog/ui/privacylog-page.tsx +++ b/apps/cs/src/pages/privacylog/ui/privacylog-page.tsx @@ -3,65 +3,54 @@ import dayjs from "dayjs"; import { useState } from "react"; import { keepPreviousData, useQuery } from "@tanstack/react-query"; +import { getCoreRowModel, type PaginationState } from "@tanstack/react-table"; import { - getCoreRowModel, - type PaginationState, -} from "@tanstack/react-table"; -import { - Button, - DateRangePicker, - Input, + Button, + DateRangePicker, + Input, Label, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, - } from "@common/components"; +} from "@common/components"; import { PrivacyLogPrivacy } from "@/entities/privacylog"; -import { type PrivacyLogParams} from "@/entities/privacylog/model/privacylog-interface"; -import { useDataTable } from "@/shared/lib"; +import type { PrivacyLogParams } from "@/entities/privacylog/model/privacylog-interface"; +import { useDataTable } from "@/shared/lib"; import { ENDPOINT } from "@/shared/config"; import { columns } from "@/pages/privacylog/model/table-columns"; - - type DateRange = { from: Date | undefined; to?: Date | undefined; }; -function PrivacyLogPage({ }) { - - // 1주일 전부터 오늘까지 기본 날짜 설정 +function PrivacyLogPage() { const defaultDateRange: DateRange = { from: dayjs().subtract(7, "day").toDate(), to: dayjs().toDate(), }; - - const [dateRange, setDateRange] = useState(defaultDateRange); const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: 10, }); - - const [privacylogPostQuery, setprivacylogPostQuery] = useState< PrivacyLogParams>({ - siteId: "", - inqInfoKeywordType: "userName", - inqInfoKeyword: "", - rqstrIp: "", - inqDtStart: dayjs().subtract(7, "day").format("YYYY-MM-DD"), - inqDtEnd: dayjs().format("YYYY-MM-DD"), - sort:"inqDt,asc" + const [dateRange, setDateRange] = useState(defaultDateRange); + const [inqInfoKeyword, setInqInfoKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ + inqInfoKeywordType: "userName", + inqInfoKeyword: "", + inqDtStart: dayjs().subtract(7, "day").format("YYYY-MM-DD"), + inqDtEnd: dayjs().format("YYYY-MM-DD"), + sort: "inqDt,desc", }); - - + const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.PRIVACYLOG, pagination], + queryKey: [ENDPOINT.USER_SERVICE.PRIVACYLOG, searchParams, pagination], queryFn: () => PrivacyLogPrivacy.getPrivacyLogList({ - ...privacylogPostQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -87,14 +76,29 @@ function PrivacyLogPage({ }) { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + inqInfoKeyword, + inqDtStart: dayjs(dateRange.from).format("YYYY-MM-DD"), + inqDtEnd: dayjs(dateRange.to).format("YYYY-MM-DD"), + }); }; - const handleprivacylogParamsChange = - (key: keyof PrivacyLogParams) => (value: unknown) => { - setprivacylogPostQuery({ ...privacylogPostQuery, [key]: value }); + const handleReset = () => { + setInqInfoKeyword(""); + setDateRange(defaultDateRange); + setSearchParams({ + ...searchParams, + inqInfoKeyword: "", + inqDtStart: dayjs().subtract(7, "day").format("YYYY-MM-DD"), + inqDtEnd: dayjs().format("YYYY-MM-DD"), + }); }; - + const handlePresetDateRange = (value: string) => { let presetDateRange: DateRange | undefined; switch (value) { @@ -119,23 +123,9 @@ function PrivacyLogPage({ }) { default: presetDateRange = undefined; } - handleDateRangeChange(presetDateRange); + setDateRange(presetDateRange || defaultDateRange); }; - - - const handleDateRangeChange = (value: DateRange | undefined) => { - setDateRange(value || defaultDateRange); - setprivacylogPostQuery({ - ...privacylogPostQuery, - inqDtStart: dayjs(value?.from).format("YYYY-MM-DD") ?? dayjs().subtract(7, "day").format("YYYY-MM-DD"), - inqDtEnd: dayjs(value?.to).format("YYYY-MM-DD") ?? dayjs().format("YYYY-MM-DD"), - }); - }; - - - - return (
@@ -143,7 +133,7 @@ function PrivacyLogPage({ }) { setDateRange(value || defaultDateRange)} >
- + - handleprivacylogParamsChange("inqInfoKeyword")(e.target.value) - } + value={inqInfoKeyword} + onChange={(e) => setInqInfoKeyword(e.target.value)} /> - + +
-

로그인로그 목록

+

+ 개인정보 조회 로그 목록 +

@@ -233,7 +266,10 @@ function RecentPage() { - setBbsId(value ? value : null)} + > @@ -247,7 +283,7 @@ function RecentPage() { - setDelYn(value)}> @@ -259,8 +295,8 @@ function RecentPage() { - handleRecentPostParamsChange("keyword")(e.target.value) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} className="h-[3.2rem] w-[24rem] rounded-sm !text-[1.3rem]" /> +
diff --git a/apps/cs/src/pages/role/ui/role-form.tsx b/apps/cs/src/pages/role/ui/role-form.tsx index cd54d1e0b..355872c9e 100644 --- a/apps/cs/src/pages/role/ui/role-form.tsx +++ b/apps/cs/src/pages/role/ui/role-form.tsx @@ -53,7 +53,7 @@ function RoleForm({ roleId, form, ...props }: RoleFormProps) { - 권한ID + 권한ID - 권한명 + 권한명 - 권한내용 + 권한내용 - 관리권한여부 + 관리권한여부 - 사용여부 + 사용여부 ({ + const [keyword, setKeyword] = useState(""); + const [searchParams, setSearchParams] = useState({ keyword: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -22,10 +24,10 @@ function RolePage() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.ROLES, pagination], + queryKey: [ENDPOINT.USER_SERVICE.ROLES, searchParams, pagination], queryFn: () => RoleApi.getRoles({ - ...roleQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -54,7 +56,22 @@ function RolePage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keyword, + }); + }; + + const handleReset = () => { + setKeyword(""); + setSearchParams({ + ...searchParams, + keyword: "", + }); }; return ( @@ -66,14 +83,20 @@ function RolePage() { - setRoleQuery({ ...roleQuery, keyword: e.target.value }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} /> +
diff --git a/apps/cs/src/pages/schedule/api/schedule-service.ts b/apps/cs/src/pages/schedule/api/schedule-service.ts index b333b43f4..c7e2c8806 100644 --- a/apps/cs/src/pages/schedule/api/schedule-service.ts +++ b/apps/cs/src/pages/schedule/api/schedule-service.ts @@ -34,6 +34,10 @@ class ScheduleApiService implements ScheduleService { ): Promise { await client.put(`${ENDPOINT.CMS_SERVICE.SCHEDULES}/${schdlSn}`, data); } + + public async deleteSchedule(schdlSn: number): Promise { + await client.delete(`${ENDPOINT.CMS_SERVICE.SCHEDULES}/${schdlSn}`); + } } export const ScheduleApi = new ScheduleApiService(); diff --git a/apps/cs/src/pages/schedule/model/schedule-interface.ts b/apps/cs/src/pages/schedule/model/schedule-interface.ts index 98b6a703a..d9e942424 100644 --- a/apps/cs/src/pages/schedule/model/schedule-interface.ts +++ b/apps/cs/src/pages/schedule/model/schedule-interface.ts @@ -71,4 +71,5 @@ export interface ScheduleService { getScheduleInfo(schdlSn: number): Promise; createSchedule(data: ScheduleFormData): Promise; updateSchedule(schdlSn: number, data: ScheduleUpdateFormData): Promise; + deleteSchedule(schdlSn: number): Promise; } diff --git a/apps/cs/src/pages/schedule/ui/modify-page.tsx b/apps/cs/src/pages/schedule/ui/modify-page.tsx index e8f55534b..8b0a07a86 100644 --- a/apps/cs/src/pages/schedule/ui/modify-page.tsx +++ b/apps/cs/src/pages/schedule/ui/modify-page.tsx @@ -35,6 +35,16 @@ function ModifyPage({ schdlSn }: { schdlSn: string }) { }, }); + const { mutateAsync: deleteSchedule } = useMutationWrapper({ + mutationFn: () => ScheduleApi.deleteSchedule(parseInt(schdlSn)), + onSuccess: () => { + queryClient.invalidateQueries({ + queryKey: [ENDPOINT.CMS_SERVICE.SCHEDULES], + }); + alert("일정이 삭제되었습니다.", router.back); + }, + }); + const form = useForm({ resolver: zodResolver(scheduleUpdateFormSchema), values: { @@ -57,7 +67,12 @@ function ModifyPage({ schdlSn }: { schdlSn: string }) {

스케줄 수정

- +
); } diff --git a/apps/cs/src/pages/schedule/ui/schedule-form.tsx b/apps/cs/src/pages/schedule/ui/schedule-form.tsx index 4b0fb4f4e..2ab172b8d 100644 --- a/apps/cs/src/pages/schedule/ui/schedule-form.tsx +++ b/apps/cs/src/pages/schedule/ui/schedule-form.tsx @@ -66,7 +66,7 @@ function ScheduleForm({ - 제목 + 제목 ({ - 일정 기간 + 일정 기간
@@ -243,7 +243,7 @@ function ScheduleForm({ - 일정 유형 + 일정 유형 - 사이트 구분 + 사이트 구분
- 사이트명 + 사이트명 - 기본 사이트 여부 + 기본 사이트 여부 - 사용 여부 + 사용 여부 ({ + const [siteNm, setSiteNm] = useState(""); + const [searchParams, setSearchParams] = useState({ siteNm: "", - sort:"regDt,desc" + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, @@ -25,10 +25,10 @@ function SitePage() { }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SITES, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SITES, searchParams, pagination], queryFn: () => SiteApi.getSiteList({ - ...siteQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -37,7 +37,18 @@ function SitePage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setSearchParams({ + ...searchParams, + siteNm, + }); + }; + + const handleReset = () => { + setSiteNm(""); + setSearchParams({ + ...searchParams, + siteNm: "", + }); }; const handleRowClick = (row: Site) => { @@ -65,17 +76,26 @@ function SitePage() {
-
diff --git a/apps/cs/src/pages/survey/api/survey-service.ts b/apps/cs/src/pages/survey/api/survey-service.ts index 6db4ea52d..66b57561c 100644 --- a/apps/cs/src/pages/survey/api/survey-service.ts +++ b/apps/cs/src/pages/survey/api/survey-service.ts @@ -45,6 +45,10 @@ export class SurveyApiService implements SurveyService { await client.put(`${ENDPOINT.CMS_SERVICE.SURVEY}/${srvySn}`, data); } + public async deleteSurvey(srvySn: number): Promise { + await client.delete(`${ENDPOINT.CMS_SERVICE.SURVEY}/${srvySn}`); + } + public async getQuestionList(params: QuestionParams): Promise { const response = await client.get( `${ENDPOINT.CMS_SERVICE.SURVEY_QUESTION}`, diff --git a/apps/cs/src/pages/survey/ui/detail-page.tsx b/apps/cs/src/pages/survey/ui/detail-page.tsx index de1abc783..59bf28425 100644 --- a/apps/cs/src/pages/survey/ui/detail-page.tsx +++ b/apps/cs/src/pages/survey/ui/detail-page.tsx @@ -29,6 +29,13 @@ function DetailPage({ srvySn }: { srvySn: string }) { queryFn: () => SurveyApi.getSurveyInfo(parseInt(srvySn)), }); + const { mutateAsync: deleteSurvey } = useMutationWrapper({ + mutationFn: () => SurveyApi.deleteSurvey(parseInt(srvySn)), + onSuccess: () => { + alert("삭제되었습니다.", router.back); + }, + }); + const postHistoryQuery = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.POSTINGS, srvySn], queryFn: () => @@ -77,6 +84,12 @@ function DetailPage({ srvySn }: { srvySn: string }) { }, }); + const handleDeleteSurvey = async () => { + if (await confirm("삭제하시겠습니까?")) { + deleteSurvey(); + } + }; + const handleDeletePostingHistory = async () => { const data = postingTable.getFilteredSelectedRowModel().rows.map((row) => ({ ...row.original, @@ -101,7 +114,9 @@ function DetailPage({ srvySn }: { srvySn: string }) { - +
    diff --git a/apps/cs/src/pages/survey/ui/question-form.tsx b/apps/cs/src/pages/survey/ui/question-form.tsx index 3ea196f8c..77a1803cb 100644 --- a/apps/cs/src/pages/survey/ui/question-form.tsx +++ b/apps/cs/src/pages/survey/ui/question-form.tsx @@ -41,7 +41,7 @@ function QuestionForm({ form, actionSlot, handleSave }: QuestionFormProps) { - 문항순번 + 문항순번 - 문항유형 + 문항유형 - 문항내용 + 문항내용 - 설문 제목 + 설문 제목 - 설문 목적 + 설문 목적 ({ + const [srvyTtl, setSrvyTtl] = useState(""); + const [searchParams, setSearchParams] = useState({ srvyTtl: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); const [rowSelection, setRowSelection] = useState({}); const [postingTargets, setPostingTargets] = useState([]); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.SURVEY, searchParams, pagination], queryFn: () => SurveyApi.getSurveyList({ - ...surveyParams, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -71,7 +73,22 @@ function SurveyPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + srvyTtl, + }); + }; + + const handleReset = () => { + setSrvyTtl(""); + setSearchParams({ + ...searchParams, + srvyTtl: "", + }); }; useEffect(() => { @@ -99,14 +116,20 @@ function SurveyPage() { - setSurveyParams({ ...surveyParams, srvyTtl: e.target.value }) - } + value={srvyTtl} + onChange={(e) => setSrvyTtl(e.target.value)} /> +
diff --git a/apps/cs/src/pages/template/ui/template-form.tsx b/apps/cs/src/pages/template/ui/template-form.tsx index 8716afe00..13ef1a2c8 100644 --- a/apps/cs/src/pages/template/ui/template-form.tsx +++ b/apps/cs/src/pages/template/ui/template-form.tsx @@ -39,7 +39,7 @@ function TemplateForm({ form, tmpltSn, ...props }: TemplateFormProps) { - 템플릿 구분 + 템플릿 구분 - 템플릿명 + 템플릿명 - 템플릿 내용 + 템플릿 내용 ({ - tmpltSeCd: "", + const [keyword, setKeyword] = useState(""); + const [tmpltSeCd, setTmpltSeCd] = useState(""); + const [searchParams, setSearchParams] = useState({ keyword: "", - sort:"regDt,desc" + tmpltSeCd: "", + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TEMPLATE, searchParams, pagination], queryFn: () => TemplateApi.getTemplateList({ - ...templateQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -38,7 +39,21 @@ function TemplatePage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setSearchParams({ + ...searchParams, + keyword, + tmpltSeCd, + }); + }; + + const handleReset = () => { + setKeyword(""); + setTmpltSeCd(""); + setSearchParams({ + ...searchParams, + keyword: "", + tmpltSeCd: "", + }); }; const handleRowClick = (row: Template) => { @@ -73,10 +88,8 @@ function TemplatePage() { - setTemplateQuery({ ...templateQuery, tmpltSeCd: value }) - } + value={tmpltSeCd} + onValueChange={(value) => setTmpltSeCd(value)} />
@@ -85,19 +98,22 @@ function TemplatePage() { - setTemplateQuery({ - ...templateQuery, - keyword: e.target.value, - }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} />
+
diff --git a/apps/cs/src/pages/terms/ui/terms-form.tsx b/apps/cs/src/pages/terms/ui/terms-form.tsx index df436e63a..9f0b639ce 100644 --- a/apps/cs/src/pages/terms/ui/terms-form.tsx +++ b/apps/cs/src/pages/terms/ui/terms-form.tsx @@ -39,7 +39,7 @@ function TermsForm({ form, trmsSn, ...props }: TermsFormProps) { - 약관 구분 + 약관 구분 - 약관명 + 약관명 - 약관 내용 + 약관 내용 - 사용 여부 + 사용 여부 ({ + const [keyword, setKeyword] = useState(""); + const [trmsSeCd, setTrmsSeCd] = useState(""); + const [searchParams, setSearchParams] = useState({ + keyword: "", trmsSeCd: "", - keyword: "", - sort:"regDt,desc" + sort: "regDt,desc", }); const [pagination, setPagination] = useState({ pageIndex: 0, - pageSize: 5, + pageSize: 10, }); const query = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.TERMS, pagination], + queryKey: [ENDPOINT.CMS_SERVICE.TERMS, searchParams, pagination], queryFn: () => TermsApi.getTermsList({ - ...termsQuery, + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), @@ -38,7 +40,25 @@ function TermsPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keyword, + trmsSeCd, + }); + }; + + const handleReset = () => { + setKeyword(""); + setTrmsSeCd(""); + setSearchParams({ + ...searchParams, + keyword: "", + trmsSeCd: "", + }); }; const handleRowClick = (row: Terms) => { @@ -73,10 +93,8 @@ function TermsPage() { - setTermsQuery({ ...termsQuery, trmsSeCd: value }) - } + value={trmsSeCd} + onValueChange={(value) => setTrmsSeCd(value)} />
@@ -85,19 +103,22 @@ function TermsPage() { - setTermsQuery({ - ...termsQuery, - keyword: e.target.value, - }) - } + value={keyword} + onChange={(e) => setKeyword(e.target.value)} />
+
diff --git a/apps/cs/src/pages/users/ui/agency-search-dialog.tsx b/apps/cs/src/pages/users/ui/agency-search-dialog.tsx index e5ce204b8..9759d42be 100644 --- a/apps/cs/src/pages/users/ui/agency-search-dialog.tsx +++ b/apps/cs/src/pages/users/ui/agency-search-dialog.tsx @@ -50,6 +50,7 @@ function AgencySearchDialog({ onSelectAgency }: AgencySearchDialogProps) { queryFn: () => LwpoCodeApi.getLwpoCodeList({ ...searchQuery, + upCd: "AGENCYCD", page: pagination.pageIndex, size: pagination.pageSize, }), @@ -70,6 +71,9 @@ function AgencySearchDialog({ onSelectAgency }: AgencySearchDialogProps) { { accessorKey: "lwpoCd", header: "기관코드", + meta: { + width: 200, + }, }, { accessorKey: "lwpoCdNm", @@ -120,11 +124,13 @@ function AgencySearchDialog({ onSelectAgency }: AgencySearchDialogProps) { - + 기관 검색 -
{ e.preventDefault(); @@ -150,9 +156,7 @@ function AgencySearchDialog({ onSelectAgency }: AgencySearchDialogProps) {
- {tableComponent} - -
diff --git a/apps/cs/src/pages/users/ui/users-form.tsx b/apps/cs/src/pages/users/ui/users-form.tsx index d69e918b0..7920ce758 100644 --- a/apps/cs/src/pages/users/ui/users-form.tsx +++ b/apps/cs/src/pages/users/ui/users-form.tsx @@ -140,7 +140,7 @@ function UsersForm({ }, [laeSeCd, watchDtlInstCd]); const enoCdSelectData = useMemo( - () => laeSeCd?.filter((code) => code.unit?.startsWith("G2")) ?? [], + () => laeSeCd?.filter((code) => code.lwpoCd?.startsWith("G2")) ?? [], [laeSeCd], ); @@ -179,7 +179,7 @@ function UsersForm({ {/* 아이디 */} - 아이디 + 아이디 ({ {/* 비밀번호 */} - 비밀번호 + 비밀번호 ({ {/* 비밀번호 힌트 */} - 비밀번호 힌트 + 비밀번호 힌트 ({ {/* 이름 */} - 이름 + 이름 ({ {/* 기관구분 */} - 기관구분 + 기관구분 ({ {/* 소속 */} - 소속 + 소속 (); + 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 { register, watch, setValue, getValues } = useForm({ - defaultValues: { - keywordType: "all", - keyword: "", - userStateCode: "", - aprvYn: "", - grpId: "", - frDateYmd: "", - toDateYmd: "", - sort: "regDt,desc" - }, + const [searchParams, setSearchParams] = useState({ + keywordType: "all", + keyword: "", + userStateCode: "", + aprvYn: "", + grpId: "", + frDateYmd: "", + toDateYmd: "", + sort: "regDt,desc", }); const { data: userSttsStats } = useQuery({ @@ -61,16 +66,16 @@ function UsersPage() { }); const query = useQuery({ - queryKey: [ENDPOINT.USER_SERVICE.USERS, pagination, watch("sort")], + queryKey: [ENDPOINT.USER_SERVICE.USERS, searchParams, pagination], queryFn: () => UserApi.findPageUser({ - ...getValues(), + ...searchParams, page: pagination.pageIndex, size: pagination.pageSize, }), }); - const { data: userStateCode } = useQuery({ + const { data: userStateCodes } = useQuery({ queryKey: [ENDPOINT.CMS_SERVICE.CODE], queryFn: () => CodeApi.getCode("USERSTTS"), }); @@ -98,7 +103,44 @@ function UsersPage() { const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - query.refetch(); + setPagination({ + ...pagination, + pageIndex: 0, + }); + setSearchParams({ + ...searchParams, + keywordType, + keyword, + userStateCode, + aprvYn, + grpId, + frDateYmd: dateRange?.from + ? dayjs(dateRange.from).format("YYYYMMDD") + : "", + toDateYmd: dateRange?.to ? dayjs(dateRange.to).format("YYYYMMDD") : "", + }); + }; + + const handleReset = () => { + setKeywordType("all"); + setKeyword(""); + setUserStateCode(""); + setAprvYn(""); + setGrpId(""); + setDateRange({ + from: undefined, + to: undefined, + }); + setSearchParams({ + ...searchParams, + keywordType: "all", + keyword: "", + userStateCode: "", + aprvYn: "", + grpId: "", + frDateYmd: "", + toDateYmd: "", + }); }; const handlePresetDateRange = (value: string) => { @@ -126,8 +168,6 @@ function UsersPage() { presetDateRange = undefined; } setDateRange(presetDateRange); - setValue("frDateYmd", dayjs(presetDateRange?.from).format("YYYYMMDD")); - setValue("toDateYmd", dayjs(presetDateRange?.to).format("YYYYMMDD")); }; const getUserSttsStatsCnt = (code: string): number => { @@ -135,6 +175,21 @@ function UsersPage() { return userSttsStats.find((item) => item.sttsCd === code)?.cnt ?? 0; }; + const handleUserStateCodeChange = (code: string, checked: boolean) => { + let newUserStateCode = userStateCode; + + if (checked) { + newUserStateCode = userStateCode ? `${userStateCode},${code}` : code; + } else { + newUserStateCode = userStateCode + .split(",") + .filter((c) => c !== code) + .join(","); + } + + setUserStateCode(newUserStateCode); + }; + return (
@@ -195,8 +250,8 @@ function UsersPage() { 회원정보 setKeyword(e.target.value)} className="!text-[1.3rem]" placeholder="검색어를 입력하세요" /> @@ -221,14 +277,7 @@ function UsersPage() {
- { - setDateRange(value); - setValue("frDateYmd", dayjs(value?.from).format("YYYYMMDD")); - setValue("toDateYmd", dayjs(value?.to).format("YYYYMMDD")); - }} - > +
{ - setValue("sort", value); + setSearchParams({ + ...searchParams, + sort: value, + }); }} > diff --git a/apps/cs/src/shared/config/api.ts b/apps/cs/src/shared/config/api.ts index 3159eb23c..cd639a628 100644 --- a/apps/cs/src/shared/config/api.ts +++ b/apps/cs/src/shared/config/api.ts @@ -20,9 +20,7 @@ export const ENDPOINT = { ROLE_AUTHORIZATIONS: "/user-service/api/v1/role-authorizations", ROLES: "/user-service/api/v1/roles", LOGINLOG: "/user-service/api/v1/login-logs", - APILOG: "/user-service/api/v1/api-logs", PRIVACYLOG: "/user-service//api/v1/prvc-inq-logs", - }, CMS_SERVICE: { SITES: "/cms-service/api/v1/sites", @@ -33,6 +31,8 @@ export const ENDPOINT = { MENUS: "/cms-service/api/v1/menus", MENU_ROLES: "/cms-service/api/v1/menu-roles", MENU_AUTHRTS: "/cms-service/api/v1/menu-authrts", + MENU_TEMPORARY_STORAGE: "/cms-service/api/v1/menu-tmpr-strg", + MENU_HISTORY: "/cms-service/api/v1/menu-hstry", CONTENTS: "/cms-service/api/v1/contents", CONTENTS_DETAILS: "/cms-service/api/v1/contents-details", ORGANIZATIONS: "/cms-service/api/v1/ognzs", @@ -52,6 +52,7 @@ export const ENDPOINT = { GROUPS: "/cms-service/api/v1/groups", GROUP_USERS: "/cms-service/api/v1/group-users", MANAGER_IP: "/cms-service/api/v1/mgrip", + APILOG: "/cms-service/api/v1/api-logs", }, BOARD_SERVICE: { BBS: "/board-service/api/v1/bbs", diff --git a/apps/cs/src/shared/lib/use-mutation-wrapper.tsx b/apps/cs/src/shared/lib/use-mutation-wrapper.tsx index ce119d2a7..cea1a8f83 100644 --- a/apps/cs/src/shared/lib/use-mutation-wrapper.tsx +++ b/apps/cs/src/shared/lib/use-mutation-wrapper.tsx @@ -17,15 +17,13 @@ export const useMutationWrapper = < let errorMessage = ""; if (error instanceof AxiosError) { - if (error.response?.status) - errorMessage += `status: ${error.response.status}\n`; if (error.response?.data?.message) errorMessage += `${error.response.data.message}\n`; if (error.response?.data?.errors[0]?.message) errorMessage += `${error.response.data.errors[0].message}\n`; } - alert(`[Error] ${errorMessage}`); + alert(`${errorMessage}`); }, }); }; diff --git a/apps/cs/src/shared/lib/use-tus.ts b/apps/cs/src/shared/lib/use-tus.ts index 30976c23b..9d4bc7c00 100644 --- a/apps/cs/src/shared/lib/use-tus.ts +++ b/apps/cs/src/shared/lib/use-tus.ts @@ -2,9 +2,15 @@ import { useEffect, useState } from "react"; import { type HttpResponse, Upload } from "tus-js-client"; import { AUTH_USER_ID, CLAIM_NAME, ENDPOINT } from "../config"; import { useAttachmentStore } from "./use-attachment-store"; +import { useAlertStore } from "./use-alert-store"; import { getCookie } from "./cookie"; -export const useTus = () => { +type TusProps = { + accept?: string; +}; + +export const useTus = ({ accept }: TusProps = {}) => { + const alert = useAlertStore((state) => state.setMessage); const { attachmentFileCode, setAttachmentFileCode } = useAttachmentStore( (state) => state, ); @@ -13,6 +19,7 @@ export const useTus = () => { const [upload, setUpload] = useState(null); const [response, setResponse] = useState(null); const [progress, setProgress] = useState(0); + const [isValid, setIsValid] = useState(false); const metadata = { filename: file?.name ?? "", @@ -20,6 +27,23 @@ export const useTus = () => { atflCd: attachmentFileCode, }; + const validFileType = (file: File) => { + const allowedExtensions = accept?.split(",") ?? []; + const fileName = file.name; + const fileExtension = fileName + .substring(fileName.lastIndexOf(".")) + .toLowerCase(); + + if (!allowedExtensions.includes(fileExtension)) { + alert("파일 형식이 올바르지 않습니다."); + setIsValid(false); + return false; + } + + setIsValid(true); + return true; + }; + const createUpload = () => { return new Upload(file!, { endpoint: `${ENDPOINT.ATTACH_SERVICE.TUS_UPLOAD}`, @@ -48,6 +72,7 @@ export const useTus = () => { useEffect(() => { if (!file) return; + if (!validFileType(file)) return; const upload = createUpload(); upload.start(); @@ -59,6 +84,7 @@ export const useTus = () => { upload, response, progress, + isValid, setFile, }; }; diff --git a/apps/cs/src/widgets/post/ui/general-file-uploader.tsx b/apps/cs/src/widgets/post/ui/general-file-uploader.tsx index 2012201da..cbd77ca18 100644 --- a/apps/cs/src/widgets/post/ui/general-file-uploader.tsx +++ b/apps/cs/src/widgets/post/ui/general-file-uploader.tsx @@ -102,7 +102,7 @@ function GeneralFileUploader({ {attachment.orgnlFileNm} -
-
- -
- {buttonChk ? : null} -
-
정보를 저장하시겠습니까?
- {ContentComponent && - - } -
-
- ) -} -export default FeatureClickEventPopup; \ No newline at end of file diff --git a/apps/wr/app/map/htdflPrfmncSttnPopup.tsx b/apps/wr/app/map/htdflPrfmncSttnPopup.tsx deleted file mode 100644 index 8d1bec486..000000000 --- a/apps/wr/app/map/htdflPrfmncSttnPopup.tsx +++ /dev/null @@ -1,621 +0,0 @@ -"use client"; - -import { - Form, - FormField, - FormUi, - SelectBox, -} from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { useWrStore } from "@/app/store"; -import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { - hdtflZod, - type customHtdflBdst, -} from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import { useEffect } from "react"; -import BdstReg from "@/components/ui/form/fcltReg/bdstReg/bdstReg"; -import { - formatCommaNumber, - handleCommaNumberChange, -} from "@/components/lib/func/commom"; -import { formH1Class } from "@/components/lib/class/comClass"; - -export default function HtdflPrfmncSttnPopup({ - htdflForm, - isModal, -}: { - htdflForm: customHtdflBdst; - isModal: boolean; -}) { - const { code, htdflBdstUpdate, htdflBdstReg } = useWrStore((state) => state); - - const defaultValues: z.infer = hdtflZod.parse({}); - - const form = useForm>({ - resolver: zodResolver(hdtflZod), - defaultValues: defaultValues, - }); - - const onSubmit = (values: z.infer) => { - if (isModal) { - htdflBdstReg(values, '41'); - } else { - htdflBdstUpdate(values, '41'); - } - }; - - - const cleanHtdflData = (raw: any): z.infer => { - return { - ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), - archChgPrmsnDt: raw?.archChgPrmsnDt - ? new Date(raw?.archChgPrmsnDt) - : null, - chgBuilding: (raw?.chgBuilding || []).map((item: any) => ({ - ...item, - archChgPrmsnDt: - item?.archChgPrmsnDt === null - ? new Date() - : new Date(item?.archChgPrmsnDt), - bdstChgNm: item?.bdstChgNm ?? "", // null → "" - })), - reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ - ...item, - instlCmptnDt: new Date(item?.instlCmptnDt), - htdflObj: { - ...item?.htdflObj, - }, - })), - }; - }; - - useEffect(() => { - console.log("form errors:", form.formState.errors); - }, [form.formState.errors]); - - useEffect(() => { - if (hdtflZod) form.reset(cleanHtdflData(htdflForm)); - }, [htdflForm]); - - return ( -
-
- - {/*
*/} -
-
-

온배수 시설 정보

-
-
- - {isModal && htdflForm != undefined ? : <>} - {isModal ? ( -

- 온배수 시설 정보{" "} -

- ) : ( - <> - )} - -
-
- ( - - - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- ( - - - - )} - /> -
-
-
-

- 온배수 시설 운영현황 -

-
- -
-
- ( - - { - field.onChange(Number(e.target.value)); - }} - readOnly={true} - /> - - )} - /> -
-
- ( - - - - )} - /> -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- ( - - - - )} - /> -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- ( - - - - )} - /> -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- ( - - - - )} - /> -
-
- -
-

- 요구수질 -

-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- -
-
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
- -
- ( - - { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - - )} - /> -
-
- - -
- ); -} diff --git a/apps/wr/app/map/htdflSttn/page.tsx b/apps/wr/app/map/htdflSttn/page.tsx index 7b804b7cd..80830aa90 100644 --- a/apps/wr/app/map/htdflSttn/page.tsx +++ b/apps/wr/app/map/htdflSttn/page.tsx @@ -2,15 +2,12 @@ import Gis from "@common/business_components/ui/map/Gis"; import { useEffect, useRef, useState, useCallback } from "react"; -import FeatureClickEventPopup from "../featureClickEventPopup"; import { mapService } from "../service"; -import { MapSearchBar } from "../mapSearchBar"; import NewWindowPopup from "../newWindowPopup"; import GisApp from "@common/business_components/ui/map/lib/gis.core"; const Map = () => { const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정 - const [selectedFeature, setSelectedFeature] = useState(null); // 선택된 피처 상태 const gisMaps = useRef(null); const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태 const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태 @@ -46,7 +43,7 @@ const Map = () => { // SearchModal, GisContent 등에서 호출 const onFeatureSelect = (data: any) => { - let map = gisMaps.current; + const map = gisMaps.current; if (!map) { console.warn("지도가 초기화되지 않았습니다."); return; @@ -60,7 +57,7 @@ const Map = () => { select.resetSelectedFeature(); // 2. data가 OpenLayers Feature 인스턴스인지 확인 - let foundFeature = null; + let foundFeature: any = null; if ( data && typeof data.getGeometry === "function" && @@ -85,9 +82,9 @@ const Map = () => { // 3. 피처 선택 if (foundFeature) { - let geometry = foundFeature.getGeometry(); + const geometry = foundFeature.getGeometry(); if (geometry) { - let extent = geometry.getExtent(); + const extent = geometry.getExtent(); map.getView().fit(extent, { duration: 300, @@ -136,7 +133,7 @@ const Map = () => { // /> // ) // } - detailView={(props: any) => ( + detailView={(props: any) =>( { {...props} /> )} - onFeatureSelect={undefined} + onFeatureSelect={onFeatureSelect} setIsOpen={setIsOpen} setFeatureData={setFeatureData} featureData={featureData} @@ -152,6 +149,7 @@ const Map = () => { isOpen={isOpen} isSearchModalOpen={isSearchModalOpen} onCheckedLayersChange={handleCheckedLayersChange} + imgVisble={true} />
); diff --git a/apps/wr/app/map/mapSearchBar.tsx b/apps/wr/app/map/mapSearchBar.tsx deleted file mode 100644 index b24b5d83a..000000000 --- a/apps/wr/app/map/mapSearchBar.tsx +++ /dev/null @@ -1,414 +0,0 @@ -// "use client" - -// import { useWrStore } from "@/app/store"; -// import SearchInputText from "@/components/ui/searchInput/searchInput"; -// import type { EnvPartSelectDataType, ReturnType, SelectDataType } from "@common/business_components/ui"; -// import { SelectBox } from "@common/business_components/ui"; -// import { Button, Input, Label } from "@common/components/ui"; -// import React, { useEffect, useMemo, useRef, useState } from "react"; -// import { MapSearchFormLeft } from "./mapSearchForm"; - - -// // 건물 검색 타입 정의 -// interface BuildingInfo { -// bdstInfoPk: number; -// ctpvCd: number; -// sggCd: number; -// daddr: string; -// bdstNm: string; -// frstArchPrmsnDt: string; -// archArea: number; -// ctpvNm: string | null; -// sggNm: string | null; -// lat: number | null; -// lot: number | null; -// regDt: string; -// rgtr: string | null; -// mdfcnDt: string; -// mdfr: string | null; -// } - -// type SearchBaseType = { -// searchType: string; -// selectSidoData?: SelectDataType[] | []; -// selectSigunData?: SelectDataType[] | []; -// selectRegionData?: SelectDataType[] | []; -// selectUnitWaterShedData?: SelectDataType[] | []; -// selectMiddleRegionData?: SelectDataType[] | []; -// selectEnvPartData?: EnvPartSelectDataType[] | []; -// onFeatureSelect: () => void; -// btnClass?: string; -// ref?: React.RefObject; -// isAdmin?: boolean; -// leftClassName?: string; -// rightClassName?: string; -// showQueryButton?: boolean; -// showInitButton?: boolean; -// showApplyButton?: boolean; -// checkedLayers?: string[]; -// checkedLayersData?: any[]; -// } - -// const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}`; - -// const YEARS = Array.from({ length: 100 }, (_, i) => `${2025 - i}`); - -// interface SearchModalProps { -// open: boolean; -// onOpenChange: (open: boolean) => void; -// onFeatureSelect: (row: any) => void; -// } - -// interface SelectedDataTypeWithSggNm { -// text: string; -// val: string; -// sggNm: string; -// } - -// export function MapSearchBar({ -// searchType, -// selectSidoData, -// selectSigunData, -// selectRegionData, -// selectUnitWaterShedData, -// selectMiddleRegionData, -// selectEnvPartData, -// btnClass, -// onFeatureSelect, -// isAdmin = false, -// leftClassName, -// rightClassName, -// showQueryButton = true, -// showInitButton = true, -// showApplyButton = true, -// checkedLayers = [], -// checkedLayersData = [], -// }: SearchBaseType) { - -// // 로딩바 -// const [isLoading, setIsLoading] = useState(false); -// // 상세 정보 조회를 위한 상태 추가 -// const [popupFeature, setPopupFeature] = useState(null); -// const [isChHead, setIsChHead] = useState(false); -// const ref = useRef({} as ReturnType); - -// // zustand store에서 건물 검색 함수와 데이터 가져오기 -// const { -// code, -// bdst, -// findBdst, -// wrMap, -// buildingSearchRes, -// buildingNmSearch, -// buildingNmSearchMultiple -// } = useWrStore((state) => state); - -// const [selectedBuilding, setSelectedBuilding] = useState(null); -// const [buildingSearchText, setBuildingSearchText] = useState(""); -// const [buildingList, setBuildingList] = useState([]); - -// // 전체 목록 -// const [partValue, setPartValue] = useState("A"); -// const [sidoValue, setSidoValue] = useState("0"); -// const [sigunValue, setSigunValue] = useState("0"); -// const [regionValue, setRegionValue] = useState("0"); -// const [untitWaterShedValue, setUntitWaterShedValue] = useState("0"); -// const [middleRegionValue, setMiddleRegionValue] = useState("0"); -// const [envPartValue, setEnvPartValue] = useState("0"); -// const [resetTrigger, setResetTrigger] = useState(false); -// const [sidoText, setSidoText] = useState("0"); -// const [sigunText, setSigunText] = useState("0"); -// // 공급처 후보지 조회 필터 목록 -// const [selectedSido, setSelectedSido] = useState({ text: "전체", val: '0' }); -// const [selectedSigun, setSelectedSigun] = useState({ text: "전체", val: '0' }); -// const [selectedFclt, setSelectedFclt] = useState({ text: "전체", val: '0', sggNm: '전체' }); // 시설명 선택 상태 -// // 전체 시설 -// let allFclt: SelectedDataTypeWithSggNm[] = [{ text: "전체", val: '0', sggNm: '전체' }]; -// const [selectedDong, setSelectedDong] = useState({ text: "전체", val: '0', sggNm: '전체' }); // 시설명 선택 상태 // 행정동 - -// const filteredSigunData = useMemo(() => { -// if (!selectedSido || selectedSido.val === '0' || !selectedSido.val) return [{ text: "전체", val: '0' }]; -// return [ -// { text: "전체", val: '0' }, -// ...code.sggCd.filter((item: { val: string; }) => item.val.substring(0, 2) === selectedSido.val.substring(0, 2)) -// ]; -// }, [selectedSido]); - -// const filteredFcltData = useMemo(() => { -// if (!selectedSigun || selectedSigun.val === '0' || !selectedSigun.val) return [{ text: "전체", val: '0', sggNm: '전체' }]; -// return [ -// { text: "전체", val: '0', sggNm: '전체' }, -// ...allFclt.filter(item => item.sggNm === selectedSido.text) -// ]; -// }, [selectedSigun]); - -// const filteredDong = useMemo(() => { -// if (!selectedSigun || selectedSigun.val === '0' || !selectedSigun.val) return [{ text: "전체", val: '0', sggNm: '전체' }]; -// return [ -// { text: "전체", val: '0', sggNm: '전체' }, -// // ...code.dong.filter(item => item.sggNm === selectedSido.text) -// ]; -// }, [selectedSigun]); - -// // 조회 함수 -// const queryVal = () => { -// // 46 : 하수처리시설 -// // 47 : 하수재이용시설 -// // 48 : 빗물이용시설 -// // 49 : 중수도시설 -// // 50 : 온배수시설 -// console.log("조회버튼 클릭: ", checkedLayers); -// if (checkedLayers && checkedLayers.includes('48')) { -// // searchBuildings -// } -// } - -// // 초기화 함수 -// const initVal = () => { -// setPartValue("A"); -// setSidoValue("0"); -// setSigunValue("0"); -// setRegionValue("0"); -// setUntitWaterShedValue("0"); -// setMiddleRegionValue("0"); -// setEnvPartValue("0"); -// setSidoText("전체"); -// setSigunText("전체"); -// setSelectedSido({ text: "전체", val: '0' }); -// setSelectedSigun({ text: "전체", val: '0' }); -// setSelectedFclt({ text: "전체", val: '0', sggNm: '전체' }); -// setSelectedDong({ text: "전체", val: '0', sggNm: '전체' }); -// setResetTrigger(true); -// }; - -// // 적용 버튼 -// const applyVal = () => { -// onFeatureSelect(); -// }; - -// useEffect(() => { -// if (resetTrigger) { -// setResetTrigger(false); -// } -// }, [resetTrigger]); - -// // 시설 조회 -// useEffect(() => { -// const fetchData = async () => { -// setIsLoading(true); -// if (!selectedSigun || selectedSigun.val === '0' || !selectedSigun.val) { -// allFclt = ([{ text: "전체", val: '0', sggNm: '전체' }]); -// setIsLoading(false); -// return; -// } - -// try { -// const queryParamsFacility = new URLSearchParams({ -// lyrTypeNm: 'tb_il_swage_prcs_fclt', -// page: '0', -// size: '100000', -// sort: 'string', -// }); -// const cqlFiltersFacility: string[] = []; -// if (selectedSigun.text && selectedSigun.val !== '0') { -// cqlFiltersFacility.push(`sgg_nm ILIKE '%${selectedSigun.text}%'`); -// } -// if (cqlFiltersFacility.length > 0) { -// queryParamsFacility.append('cqlFiter', cqlFiltersFacility.join(' and ')); -// } -// console.log("BaseLayout API URL for Facilities:", `v1/fclts?${queryParamsFacility.toString()}`); - -// const facilityRes = await fetch(`${API_URL}/v1/fclts?${queryParamsFacility.toString()}`, { -// method: "GET", -// headers: { accept: "application/json" } -// }).then(res => res.json()); - -// const facilities = (facilityRes.data || []).map((item: any) => ({ -// text: item.swtrmtFcltNm, -// val: item.fid, -// sggNm: item.sggNm -// })); -// allFclt = (facilities); - -// } catch (error) { -// console.error("BaseLayout: 지역/시설 데이터 조회 중 오류 발생:", error); -// allFclt = ([{ text: "전체", val: '0', sggNm: '전체' }]); -// } finally { -// setIsLoading(false); -// } -// }; - -// fetchData(); -// }, [selectedSigun]); - -// useEffect(() => { -// if (ref && ref.current) { -// const customRef = ref.current; -// customRef.partValue = partValue; -// customRef.sidoValue = sidoValue; -// customRef.sigunValue = sigunValue; -// customRef.regionValue = regionValue; -// customRef.unitWaterShedValue = untitWaterShedValue; -// customRef.middleRegionValue = middleRegionValue; -// customRef.envPartValue = envPartValue; -// customRef.sidoText = selectedSido.text; -// customRef.sigunText = selectedSigun.text; -// } -// }, [partValue, sidoValue, sigunValue, regionValue, untitWaterShedValue, middleRegionValue, envPartValue, ref]); - -// // buildingSearchText가 변경될 때 API 호출 -// useEffect(() => { -// if (buildingSearchText && buildingSearchText.length > 1) { -// if (checkedLayers && checkedLayers.length > 0) { -// // 다중 레이어 검색 -// // buildingNmSearchMultiple(checkedLayers, selectedSigun.val || "", buildingSearchText); -// buildingNmSearch("RNB", selectedSigun.val, buildingSearchText); -// } else { -// // 단일 레이어 검색 -// // buildingNmSearch(checkedLayers[0], selectedSigun.val, buildingSearchText); -// } -// } else { -// // 검색 텍스트가 짧으면 리스트 초기화 -// if (checkedLayers && checkedLayers.length > 0) { -// // buildingNmSearchMultiple(checkedLayers, selectedSigun.val || "", ""); -// } else { -// buildingNmSearch("RNB", selectedSigun.val || "", ""); -// } -// } -// }, [buildingSearchText]); - -// return ( -//
-//
-//
-// {searchType == "공급처 후보지 조회" && ( -// <> -// { -// const selected = code.cityCd.find((item: { val: string | number; }) => (item.val === val)); -// setSelectedSido(selected || { text: "전체", val: '0' }); -// setSelectedSigun({ text: "전체", val: '0' }); -// }} -// value={selectedSido.val} -// selectClass={'w-32'} -// /> -// { -// const selected = filteredSigunData.find(item => (item.val === val)); -// setSelectedSigun(selected || { text: "전체", val: '0' }); -// setSelectedFclt({ text: "전체", val: '0', sggNm: '전체' }); -// }} -// value={selectedSigun.val} -// selectClass={'w-32'} -// /> -//
-// -//
-// { -// setBuildingSearchText(searchNm || ""); -// }} -// setRtnData={function (rtnData: any): void { -// // 선택된 건물 데이터 처리 -// // if (rtnData && rtnData.bdstInfoPk) { -// // setSelectedBuilding(rtnData); -// // setBuildingSearchText(rtnData.bdstNm || ""); -// // } -// }} -// searchList={buildingSearchRes || []} -// /> -//
-//
-// -// )} -// {searchType == "우리동네가뭄지도보기" && ( -// <> -// { -// const selected = code.cityCd.find((item: { val: string | number; }) => (item.val === val)); -// setSelectedSido(selected || { text: "전체", val: '0' }); -// setSelectedSigun({ text: "전체", val: '0' }); -// }} -// value={selectedSido.val} -// selectClass={'w-44'} -// /> -// { -// const selected = filteredSigunData.find(item => (item.val === val)); -// setSelectedSigun(selected || { text: "전체", val: '0' }); -// setSelectedDong({ text: "전체", val: '0', sggNm: '전체' }); -// }} -// value={selectedSigun.val} -// selectClass={'w-32'} -// /> -// { -// const selected = filteredDong.find(item => (item.val === val)); -// setSelectedDong(selected || { text: "전체", val: '0', sggNm: '전체' }); -// }} -// value={selectedDong.val} -// selectClass={'w-32'} -// /> -// -// )} -// {searchType == "지도보기" && ( -//
-//
{/* SearchFormLeft 래퍼 */} -// -//
-// -//
-// -//
-//
-// )} -//
-// {/* 버튼 부분 */} -//
-// {showQueryButton && } -// {showInitButton && } -// {showApplyButton && } -//
-//
-//
-// ) -// } diff --git a/apps/wr/app/map/mapSearchForm.tsx b/apps/wr/app/map/mapSearchForm.tsx deleted file mode 100644 index 70927996b..000000000 --- a/apps/wr/app/map/mapSearchForm.tsx +++ /dev/null @@ -1,340 +0,0 @@ -"use client" - -import React, { useEffect, useState } from 'react'; -import type { SelectDataType } from '@common/business_components/ui/search_input_select'; -import { SelectBox } from '@common/business_components/ui/select'; - -/** - * 검색 폼 왼쪽 컴포넌트 타입 - * - * @param isShowPart 구분 조회 여부 - * @param children 자식 컴포넌트 - * @param selectSidoData 시도 데이터 - * @param selectSigunData 시군구 데이터 - * @param selectRegionData 유역 데이터 - * @param selectUnitWaterShedData 단위유역 데이터 - * @param selectMiddleRegionData 중권역 데이터 - * @param selectEnvPartData 환경청 데이터 - * @param selectEnvPartSidoData 환경청 시도 데이터 - * @param selectEnvPartSigunData 환경청 시군구 데이터 - * @param setRtnPartValue 부분 값 변경 핸들러 - */ -type SearchFormLeftProps = { - isShowPart?: boolean | undefined; - children: React.ReactNode; - selectSidoData?: SelectDataType[] | []; - selectSigunData?: SelectDataType[] | []; - selectRegionData?: SelectDataType[] | []; - selectUnitWaterShedData?: SelectDataType[] | []; - selectMiddleRegionData?: SelectDataType[] | []; - selectEnvPartData?: EnvPartSelectDataType[] | []; - selectEnvPartSidoData?: SelectDataType[] | []; - selectEnvPartSigunData?: SelectDataType[] | []; - - setRtnPartValue?: (value: string) => void; - setRtnSidoValue?: (value: string) => void; - setRtnSigunValue?: (value: string) => void; - setRtnRegionValue?: (value: string) => void; - setRtnUnitWaterShedValue?: (value: string) => void; - setRtnMiddleRegionValue?: (value: string) => void; - setRtnEnvPartValue?: (value: string) => void; - setRtnEnvPartSidoValue?: (value: string) => void; - setRtnEnvPartSigunValue?: (value: string) => void; - setRtnSidoText?: (value: string) => void; - setRtnSigunText?: (value: string) => void; - resetTrigger?: boolean; - isAdmin?: boolean; -} - -export type EnvPartSelectDataType = SelectDataType & { - adstDliStrCd: string, -} - -const selectPartData: SelectDataType[] = [ - { text: "행정별", val: 'A' }, - { text: "유역별", val: 'R' }, - { text: "환경청별", val: 'G' }, -]; - -function MapSearchFormLeft({ isShowPart = false, children, selectSidoData = [], selectSigunData = [], selectRegionData = [], selectUnitWaterShedData = [], selectMiddleRegionData = [], selectEnvPartData = [], setRtnPartValue, setRtnSidoValue, setRtnSidoText, setRtnSigunValue, setRtnSigunText, setRtnRegionValue, setRtnUnitWaterShedValue, setRtnMiddleRegionValue, setRtnEnvPartValue, setRtnEnvPartSidoValue, setRtnEnvPartSigunValue, resetTrigger = false, isAdmin = false }: SearchFormLeftProps) { - /******************선택된 데이터******************/ - const [partValue, setPartValue] = useState('A'); - //행정별 시도 시군구 - const [sidoValue, setSidoValue] = useState('0'); - const [sigunValue, setSigunValue] = useState('0'); - const [sidoText, setSidoText] = useState(''); - const [sigunText, setSigunText] = useState(''); - //유역별 - const [regionValue, setRegionValue] = useState('0'); - const [unitWaterShedValue, setUnitWaterShedValue] = useState('0'); - const [middleRegionValue, setMiddleRegionValue] = useState('0'); - //환경청별 시도 시군구 - const [envPartValue, setEnvPartValue] = useState('0'); - // 환경청 - const [filteredEnvPartSigunDataSelected, setFilteredEnvPartSigunDataSelected] = useState([]); - - /****************** 셀렉트 리스트 데이터. ******************/ - // 조회된 조건에 맞는 시도 시군 유역 - const [filteredSigunData, setFilteredSigunData] = useState([{ text: "전체", val: '0' }]); - const [filteredUnitWaterShedData, setFilteredUnitWaterShedData] = useState([{ text: "전체", val: '0' }]); - const [filteredMiddleRegionData, setFilteredMiddleRegionData] = useState([{ text: "전체", val: '0' }]); - // 조회된 조건에 맞는 환경청 시도 시군 - const [filteredEnvPartData, setFilteredEnvPartData] = useState([{ text: "전체", val: '0', adstDliStrCd: '' }]); - const [filteredEnvPartSidoData, setFilteredEnvPartSidoData] = useState([{ text: "전체", val: '0', adstDliStrCd: '' }]); - const [filteredEnvPartSigunData, setFilteredEnvPartSigunData] = useState([{ text: "전체", val: '0' }]); - - // 시군구 세팅 - const initializeSigunData = (sidoCd: string) => { - if (sidoCd === '0') { - setSigunValue('0'); - setFilteredSigunData([{ text: "전체", val: '0' }]); - } else { - const newFilteredData = [ - { text: "전체", val: '0' }, - ...selectSigunData.filter((item: SelectDataType) => item.val.substring(0, 2) === sidoCd) - ]; - setSigunValue('0'); - setFilteredSigunData(newFilteredData); - } - } - - // 단위유역 세팅 - const initializeUnitWaterShedData = (regionCd: string) => { - if (regionCd === '0') { - setUnitWaterShedValue('0'); - setFilteredUnitWaterShedData([{ text: "전체", val: '0' }]); - } else { - const newFilteredData = [ - { text: "전체", val: '0' }, - ...selectUnitWaterShedData.filter((item: SelectDataType) => item.val.substring(0, 1) === regionCd) - ]; - setUnitWaterShedValue('0'); - setFilteredUnitWaterShedData(newFilteredData); - } - } - - // 중권역 세팅 - const initializeMiddleRegionData = (unitWaterShedCd: string) => { - if (unitWaterShedCd === '0') { - setMiddleRegionValue('0'); - setFilteredMiddleRegionData([{ text: "전체", val: '0' }]); - } else { - const newFilteredData = [ - { text: "전체", val: '0' }, - ...selectMiddleRegionData.filter((item: SelectDataType) => item.val.substring(0, 2) === unitWaterShedCd) - ]; - setMiddleRegionValue('0'); - setFilteredMiddleRegionData(newFilteredData); - } - } - - // 환경청 세팅 - 시도 - const initializeCityDataByEnvPartSido = (envPartCd: string) => { - const foundEnvPart = selectEnvPartData.find((item: EnvPartSelectDataType) => item.val === envPartCd); - const cityArray = foundEnvPart?.adstDliStrCd.toString().split('|').join('').split(','); - - // 시군구 데이터 - const envSigunData = selectSigunData.filter((item: SelectDataType) => cityArray?.includes(item.val)); - - // 환경청 시도 데이터 - const sidoArray = [...new Set(envSigunData.map((item: SelectDataType) => item.val.substring(0, 2)))]; - const envSidoData = selectSidoData.filter((item: SelectDataType) => sidoArray?.includes(item.val)); - setFilteredEnvPartSigunDataSelected(envSigunData); - - setFilteredEnvPartSidoData([ - { text: "전체", val: '0', adstDliStrCd: '' }, - ...envSidoData.map((item: SelectDataType) => ({ text: item.text, val: item.val, adstDliStrCd: '' })) - ]); - } - - // 환경청 세팅 - 시군구 - const initializeCityDataByEnvPartSigun = (sidoCd: string) => { - const envSigunData = filteredEnvPartSigunDataSelected.filter((item: SelectDataType) => item.val.substring(0, 2) === sidoCd); - setFilteredEnvPartSigunData([ - { text: "전체", val: '0' }, - ...envSigunData.map((item: SelectDataType) => ({ text: item.text, val: item.val })) - ]); - } - - const onSelectValue = (val: string, type: string) => { - let selectedSido; - let selectedSigun; - let selectedEnvPartSido; - let selectedEnvPartSigun; - - switch (type) { - case 'part': - setPartValue(val); - if (setRtnPartValue) { - setRtnPartValue(val); - } - // 구분 - if (val == 'R') { - initializeMiddleRegionData('0'); - initializeUnitWaterShedData('0'); - } else if (val == 'G') { - setFilteredEnvPartData([ - { text: "전체", val: '0', adstDliStrCd: '' }, - ...selectEnvPartData.filter((item: EnvPartSelectDataType) => item.val !== null && item.adstDliStrCd !== '') - ]); - setEnvPartValue('0'); - initializeCityDataByEnvPartSido('0'); - } else { - initializeSigunData('0'); - onSelectValue(selectSigunData[0]?.val || '0', 'sigun'); - } - - // 다른 selectbox 전체로 초기화 - onSelectValue(selectSidoData[0]?.val || '0', 'sido'); - onSelectValue(selectSigunData[0]?.val || '0', 'sigun'); - break; - case 'sido': - setSidoValue(val); - selectedSido = selectSidoData.find(item => item.val === val); - setSidoText(selectedSido?.text || ''); - if (setRtnSidoValue) { - setRtnSidoValue(val); - } - if (setRtnSidoText) { - setRtnSidoText(selectedSido?.text || ''); - } - initializeSigunData(val); - onSelectValue(selectSigunData[0]?.val || '0', 'sigun'); - break; - case 'sigun': - if (setRtnSigunValue) { - setRtnSigunValue(val); - } - setSigunValue(val); - selectedSigun = filteredSigunData.find(item => item.val === val); - if (setRtnSigunText) { - setRtnSigunText(selectedSigun?.text || ''); - } - setSigunText(selectedSigun?.text || ''); - break; - - // 유역 세팅 - case 'region': - setRegionValue(val); - if (setRtnRegionValue) { - setRtnRegionValue(val); - } - initializeUnitWaterShedData(val); - onSelectValue(selectUnitWaterShedData[0]?.val || '0', 'unitWaterShed'); - break; - case 'unitWaterShed': - setUnitWaterShedValue(val); - if (setRtnUnitWaterShedValue) { - setRtnUnitWaterShedValue(val); - } - initializeMiddleRegionData(val); - onSelectValue(selectMiddleRegionData[0]?.val || '0', 'middleRegion'); - break; - case 'middleRegion': - setMiddleRegionValue(val); - if (setRtnMiddleRegionValue) { - setRtnMiddleRegionValue(val); - } - break; - - // 환경청 세팅 - case 'envPart': - setEnvPartValue(val); - if (setRtnEnvPartValue) { - setRtnEnvPartValue(val); - } - initializeCityDataByEnvPartSido(val); - onSelectValue(filteredEnvPartSidoData[0]?.val || '0', 'envPartSido'); - break; - case 'envPartSido': - setSidoValue(val); - selectedEnvPartSido = filteredEnvPartSidoData.find(item => item.val === val); - setSidoText(selectedEnvPartSido?.text || ''); - if (setRtnEnvPartSidoValue) { - setRtnEnvPartSidoValue(val); - } - initializeCityDataByEnvPartSigun(val); - onSelectValue(filteredEnvPartSigunData[0]?.val || '0', 'envPartSigun'); - break; - case 'envPartSigun': - setSigunValue(val); - selectedEnvPartSigun = filteredEnvPartSigunData.find(item => item.val === val); - setSigunText(selectedEnvPartSigun?.text || ''); - if (setRtnEnvPartSigunValue) { - setRtnEnvPartSigunValue(val); - } - break; - } - } - - // 리셋 함수 - const resetAllValues = () => { - setPartValue('A'); - setSidoValue('0'); - setSigunValue('0'); - setRegionValue('0'); - setUnitWaterShedValue('0'); - setMiddleRegionValue('0'); - setEnvPartValue('0'); - - setFilteredSigunData([{ text: "전체", val: '0' }]); - setFilteredUnitWaterShedData([{ text: "전체", val: '0' }]); - setFilteredMiddleRegionData([{ text: "전체", val: '0' }]); - setFilteredEnvPartData([{ text: "전체", val: '0', adstDliStrCd: '' }]); - setFilteredEnvPartSidoData([{ text: "전체", val: '0', adstDliStrCd: '' }]); - setFilteredEnvPartSigunData([{ text: "전체", val: '0' }]); - - if (setRtnPartValue) setRtnPartValue('A'); - if (setRtnSidoValue) setRtnSidoValue('0'); - if (setRtnSigunValue) setRtnSigunValue('0'); - if (setRtnRegionValue) setRtnRegionValue('0'); - if (setRtnUnitWaterShedValue) setRtnUnitWaterShedValue('0'); - if (setRtnMiddleRegionValue) setRtnMiddleRegionValue('0'); - if (setRtnEnvPartValue) setRtnEnvPartValue('0'); - if (setRtnEnvPartSidoValue) setRtnEnvPartSidoValue('0'); - if (setRtnEnvPartSigunValue) setRtnEnvPartSigunValue('0'); - }; - - // 리셋 트리거 변경 감지 - useEffect(() => { - if (resetTrigger) { - resetAllValues(); - // 리셋 후 트리거를 false로 설정 - if (setRtnPartValue) { - setRtnPartValue('0'); - } - } - }, [resetTrigger]); - - return ( - isShowPart ? ( -
- onSelectValue(val.toString(), 'part')} value={partValue} selectClass={'w-32'} /> - {partValue === 'R' ? ( - <> - onSelectValue(val.toString(), 'region')} value={regionValue} selectClass={'w-44'} /> - onSelectValue(val.toString(), 'unitWaterShed')} value={unitWaterShedValue} selectClass={'w-44'} /> - onSelectValue(val.toString(), 'middleRegion')} value={middleRegionValue} selectClass={'w-44'} /> - - ) : partValue === 'G' ? ( - <> - onSelectValue(val.toString(), 'envPart')} value={envPartValue} selectClass={'w-44'} /> - onSelectValue(val.toString(), 'envPartSido')} value={sidoValue} selectClass={'w-44'} /> - onSelectValue(val.toString(), 'envPartSigun')} value={sigunValue} selectClass={'w-44'} /> - - ) : ( - <> - onSelectValue(val.toString(), 'sido')} value={sidoValue} selectClass={'w-44'} /> - onSelectValue(val.toString(), 'sigun')} value={sigunValue} selectClass={'w-44'} /> - - )} -
- ) : ( -
- {children} -
- ) - ) -} - -export { MapSearchFormLeft }; diff --git a/apps/wr/app/map/newWindowPopup.tsx b/apps/wr/app/map/newWindowPopup.tsx index ebfcac1ca..faba4c81f 100644 --- a/apps/wr/app/map/newWindowPopup.tsx +++ b/apps/wr/app/map/newWindowPopup.tsx @@ -1,55 +1,40 @@ -import { useWrStore } from "@/app/store"; -import { btnClass } from "@/app/store/common/code"; -import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import { excelDownload } from "@/components/lib/func/commom"; -import { Title, UiTable, UITab, ContentsDiv } from '@common/business_components'; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import { Button } from "@common/components/ui"; -import React, { useCallback, useState, useEffect } from 'react'; +"use client" import NewWindowPortal from '@/app/map/newWindowPortal'; -import PbnstPrfmncSttnPopup from "@/app/map/pbnstPrfmncSttnPopup"; -import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; -import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; -import type { chgBuilding, customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import RainPrfmncSttnPopup from "@/app/map/rainPrfmncSttnPopup"; -import RswtrPrfmncsSttnPopup from "@/app/map/rswtrPrfmncSttnPopup"; -import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import HtdflPrfmncSttnPopup from "@/app/map/htdflPrfmncSttnPopup"; +import { useWrStore } from "@/app/store"; import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import type { customPbnst, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; +import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; +import { fetchType, getFetch, postFectch } from "@/components/lib/api"; +import { tableData } from "@/components/lib/func/commom"; +import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; +import { Title, UITab, UiTable } from '@common/business_components'; +import { useGisContext } from "@common/business_components/ui/map/Gis"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; +import React, { useCallback, useEffect, useState } from 'react'; interface NewWindowPopupProps { featureData: any; - checkedLayers?: string[]; - checkedLayersData?: any[]; + seletectedLayerNm?: string + viewMode?: 'list' | 'detail' | 'nothing' + onFeatureSelect: (data: any) => void; onClose: () => void; } -// 탭 -const TABS = [ - { val: "0", text: "재이용시설1" }, - { val: "1", text: "재이용시설2" }, - { val: "2", text: "재이용시설n" }, -]; - -// 데이터의 속성(key)을 사용자에게 보여줄 한글 이름으로 변환하기 위한 맵 -// 실제 데이터에 맞게 이 부분을 확장해야 합니다. -const propertyNameMap: { [key: string]: string } = { - fid: '고유 ID', - fcltNm: '시설명', - opertDe: '운영일자', - addr: '주소', - // ... 필요한 만큼 속성 매핑 추가 -}; - const NewWindowPopup: React.FC = ({ featureData, - checkedLayers = [], - checkedLayersData = [], + seletectedLayerNm, + onFeatureSelect, onClose }) => { - const [activeTab, setActiveTab] = useState(TABS[0]?.val ?? "0"); - // swcho : useState의 true, false 값 변경하여 목록, 상태 테스트 하였음 - const [showDetailView, setShowDetailView] = useState(true); // 상세정보 화면 표시 상태 추가 + const { gisMap } = useGisContext() as unknown as { checkedLayerIds: React.MutableRefObject; treeData: { lyrSn: number }[] | null; gisCore: any; gisMap: any; }; + const [tabData, setTabData] = useState<{ id: string; name: string; data: any }[]>([]); + const [activeTab, setActiveTab] = useState('0'); + const [viewMode, setViewMode] = useState<'list' | 'detail' | 'nothing'>('list'); + const [fcltPk, setFcltPk] = useState(''); + // onClose 함수를 useCallback으로 메모이제이션 const memoizedOnClose = useCallback(() => { @@ -62,320 +47,631 @@ const NewWindowPopup: React.FC = ({ pbnstSttn, pbnstSttnSearch, pbnSttnInit, - getPbnStnDetail, - pbnNmSearch, + getFlcts } = useWrStore((state) => state); - const [bdstTable, setBdstTable] = useState(); - const [pageNation, setPageNation] = useState(1); - const [pbnDetaileData, setPbnDetaileData] = useState<{ - isModal: boolean; - data: customPbnst; - }>({ isModal: false, data: {} as customPbnst }); + const { fclts, pbnstSttnResCount } = pbnstSttn + const [bdstTable, setBdstTable] = useState() // 빗물재이용시설 변수 const { rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( (state) => state ); - const { rainSttnRes } = rainSttn; + const { rainSttnRes, rainSttnResCount } = rainSttn; const [rainTable, setRainTable] = useState(); - const [rainBdstChgProps, setRainBdstChgProps] = useState<{ - isOpen: boolean; - chBuilding: chgBuilding[]; - }>({ isOpen: false, chBuilding: [] }); + const [rainPage, setRainPage] = useState(1) const [rainDetailModal, setRainDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }); + const [rainList, setRainList] = useState(rainSttnRes || []); // 중수도시설 변수 const { rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( (state) => state ); - const { rswtSttnRes } = rswtSttn; + const { rswtSttnRes, rswtSttnResCount } = rswtSttn; const [rswtrTable, setRswtrTable] = useState(); const [rswtrDetailModal, setRswtrDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }); - const [rswtrBdstChgProps, setRswtrBdstChgProps] = useState<{ - isOpen: boolean; - chBuilding: chgBuilding[]; - }>({ isOpen: false, chBuilding: [] }); + const [rswtrPage, setRswtrPage] = useState(1); + const [rswtrList, setRswtrList] = useState(rswtSttnRes || []); // 온배수시설 변수 const { htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore((state) => state); - const { htdflSttnRes } = htdflSttn; + const { htdflSttnRes,htdflSttnResCount } = htdflSttn; const [htdflTable, setHtdflTable] = useState(); const [htdflDetailModal, setHtdflDetailModal] = useState<{ isOpen: boolean, data: customHtdflBdst | undefined }>({ data: undefined, isOpen: false }); - const [bdstChgProps, setBdstChgProps] = useState<{ isOpen: boolean, chBuilding: chgBuilding[] }>({ isOpen: false, chBuilding: [] }); + const [htdflPage, setHtdflPage] = useState(1) + const [htdflList, setHtdflList] = useState(htdflSttnRes || []); - if (!featureData) { - return null; + //하수처리시설 변수 + const { + pbnst, + pubHasuInit, + } = useWrStore((state) => state); + const { pubFacHeadList, pbnstHasuRes } = pbnst; + const [hasuList, setHasuList] = useState(pbnstHasuRes || []); + const [isRuseReg, setIsRuseReg] = useState<{ + data: any | undefined; + }>({ data: undefined }); + const [hasuTable, setHasuTable] = useState(); + const [hasuPage, setHasuPage] = useState(1); + ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// + const getSelectedLayers = () => { + let result = null; + const layers = gisMap ? gisMap.getLayers().getArray().filter((l: any) => l.getVisible()) : []; // gisMap이 null인지 확인 후 레이어 가져오기 + let featureLayer: { get: (key: string) => any } = {get:()=> null}; + layers.forEach((layer: any) => { + const source = layer.getSource(); + if (source && source.hasFeature && featureData + && typeof featureData.getId === 'function' && source.hasFeature(featureData)) { + featureLayer = layer; // 피처가 속한 레이어 찾기) + } + }); + result = featureLayer.get('lyrNm'); + + return result; + }; + const fetchpbnstDetail = async (featureCd: string) => { + try { + const response = await getFetch("wr", `/reuseFc/pubFc/${featureCd}`); + // 중복 데이터 추가 방지 + setTabDataFunc(response, featureCd); + } catch (error) { + console.error("Error fetching data:", error); + } + }; + const fetchHasuDetail = async (featureCd: string, data: string) => { + try { + const rainRes = await postFectch(`/prcsFclt/ruseInfo/1/10/A/0/0/1/SW/${featureCd}`, [data], fetchType.COMMON) + setHasuList( + rainRes.data.map((item: any) => { + return { + ...item, + fctCpc: Number(item.fctCpc) || 0, + ruse: item.ruse === false ? "N" : "Y", + }; + }) + ) + } catch (error) { + console.error("Error fetching data:", error); + } + }; + const detainSttn = async (featureCd: string, layerNm: string) => { + if (layerNm == '빗물이용시설') { + const res = await getFetch(fetchType.WR, `/reuseFc/rainyInfoList/1/20/0/${featureCd}`) + setRainList(res) + } + else if(layerNm == '중수도시설'){ + const res = await getFetch(fetchType.WR,`/reuseFc/waterreuseFc/1/20/0/${featureCd}`) + setRswtrList(res) + } + else{ + const res = await getFetch(fetchType.WR, `/drain/facilityList/1/20/0/${featureCd}`) + setHtdflList(res) + setHtdflDetailModal({ isOpen: true, data: htdflSttnRes[0] }); + } } + // 상세 목록 데이터 상태 처리 + useEffect(()=>{ + if (hasuList.length > 0) setIsRuseReg({ data: [hasuList[0]] }); + },[hasuList]) + useEffect(()=>{ + if (rainList.length > 0) setRainDetailModal({ isOpen: true, data: rainList[0] }); + },[rainList]) + useEffect(()=>{ + if (rswtrList.length > 0) setRswtrDetailModal({ isOpen: true, data: rswtrList[0] }); + },[rswtrList]) + useEffect(()=>{ + if (htdflList.length > 0) setHtdflDetailModal({ isOpen: true, data: htdflList[0] }); + },[htdflList]) - // 2. RuseMngTable에 필요한 tableData를 생성합니다. (단일 행 데이터) - const tableData = [featureData]; - console.log("tableData", tableData); + const layerId = getSelectedLayers(); + if (featureData && typeof featureData.getProperties === "function") { + const selectedVal = featureData.getProperties(); + let featureCd = layerId == '하수재이용시설' ? selectedVal?.swtrmt_fclt_cd : layerId == '빗물이용시설' || layerId == '중수도시설' || layerId == '온배수시설' ? selectedVal?.bdst_nm : layerId == '하수처리시설' ? selectedVal?.swtrmt_fclt_nm : null; + if (featureCd && featureCd !== fcltPk) { + if (layerId == '하수재이용시설') { + featureCd = selectedVal?.swtrmt_fclt_cd; + setFcltPk(featureCd); // 현재 호출된 featureCd 저장 + setActiveTab(featureCd) + fetchpbnstDetail(featureCd); // 상세정보 + } + else if (layerId == '하수처리시설') { + featureCd = selectedVal?.swtrmt_fclt_nm; + setFcltPk(featureCd); // 현재 호출된 featureCd 저장 + fetchHasuDetail(featureCd, selectedVal?.swtrmt_fclt_cd); + } + else { + featureCd = selectedVal?.bdst_nm; + setFcltPk(featureCd) + if (layerId) { + detainSttn(featureCd, layerId); + } + } + setViewMode("detail") + } + } else if (layerId === null && seletectedLayerNm) { setViewMode("list") } + ///////////////////////////////////////////// 피쳐데이터 선택 시 각 시설별 데이터 처리 /////////////////////////////////////////////// - // 물재이용시설 cellClick 이벤트 (상세정보) + ///////////////////////////////////////////// 하수재이용시설 ////////////////////////////////////////////////// + // 재이용시설 cellClick 이벤트 (상세정보) const pbnstCellClick = (index: number | undefined) => { if ( index !== undefined && pbnstSttn.pbnstSttnRes && pbnstSttn.pbnstSttnRes[index] ) { - const pbnstRuseFcltPk = pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk; - getPbnStnDetail(pbnstRuseFcltPk); + setFcltPk(pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltId); + onFeatureSelect(pbnstSttn.pbnstSttnRes[index]); + onClose() } }; + // 재이용 현황 초기값 + useEffect(() => { + if (!pbnstSttn.isInit) { + getFlcts() + } + }, [seletectedLayerNm, pbnstSttn.isInit, getFlcts]); + useEffect(()=>{ + pbnSttnInit("1", "15", { + partValue: "A", + sidoValue: '0', + sigunValue: "0", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "" + }, String(new Date().getFullYear()), pbnstSttn.fclts); + }, [fclts, pbnSttnInit, pbnstSttn.fclts]) useEffect(() => { setBdstTable(pbnstSttn.pbnstSttnRes); - }, [pbnstSttn.pbnstSttnRes]); - - useEffect(() => { - if (pbnstSttn.pbnstDetail.pbnstRuseFcltPk) setShowDetailView(true); - }, [pbnstSttn.pbnstDetail]); + }, [seletectedLayerNm, pbnstSttn.pbnstSttnRes]); + // 재이용시설 상세정보 + const setTabDataFunc = (res: any, pk: string) => { + setTabData((prev) => { + if (prev.some((tab) => tab.id === pk)) { + return prev; // 이미 존재하는 탭이면 추가하지 않음 + } + return [...prev, { id: pk, name: `재이용시설 ${prev.length + 1}`, data: res }]; + }); + } + // 재이용시설 조회 + // 재이용시설 페이징처리 관련 함수 + const onPageChangeHandler = useCallback((page: number) => { + pbnstSttnSearch( + false, + String(page), + String(13), + { + partValue: "A", + sidoValue: "0", + sigunValue: "0", + regionValue: "", + unitWaterShedValue: "", + middleRegionValue: "", + envPartValue: "", + sidoText: "", + sigunText: "", + }, + "", + String(new Date().getFullYear()), fclts + ); + }, [fclts, pbnstSttnSearch]); +// FIXME: 윤선화차장님 요구사항으로 엑셀 다운로드 삭제. + // const excelClick = useCallback(() => { + // // if (codeData) pbnstSttnSearch(1, "10000", codeData); + // excelDownload( + // [[]], + // "하수재이용시설 현황", + // "sample_pbnstSttn.xlsx", + // "A1:U2" + // ); + // }, [pbnstSttnSearch]); + ///////////////////////////////////////////// 하수재이용시설 ////////////////////////////////////////////////// + ///////////////////////////////////////////// 빗물 재이용 ////////////////////////////////////////////////// // 빗물재이용시설 cellClick 이벤트 (상세정보) const rainCellClick = (index: number | undefined, headId: string) => { if ( index !== undefined && rainTable !== undefined && headId !== 'chBuildingYn') { - setRainDetailModal({ isOpen: true, data: rainTable[index] }) - } else if (headId === 'chBuildingYn' && index !== undefined && rainTable !== undefined) { - if (rainTable[index] && rainTable[index]?.chgBuilding[0]?.bdstChgNm !== null) - setRainBdstChgProps({ isOpen: true, chBuilding: rainTable[index].chgBuilding }); + // setRainDetailModal({ isOpen: true, data: rainTable[index] }) + // setViewMode('detail') + onFeatureSelect(rainTable[index]); + onClose(); } } + + useEffect(() => { + if (!rainSttn.isInit) { + rainSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, rainSttn.isInit, rainSttnInit]); + + useEffect(() => { + const data = tableData(rainSttnRes, { code }); + const chData = data + .map((item: any) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].rainyObj, + dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.dtfcltCpct, + instlCst: item.reuseBuilding[0].instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCst, + instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCstSprtAmt, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.pntfColArea, + filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, + archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, + }; + }) + .filter((item: any) => item.rainyObj !== undefined); + setRainTable(chData); + }, [code, rainSttnRes, rainSttn.rainSttHeadList]); + + useEffect(() => { + rainSttnSearch(false, rainPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, rainPage, rainSttnSearch]); + ///////////////////////////////////////////// 빗물 재이용 ////////////////////////////////////////////////// + + ///////////////////////////////////////////// 중수도 시설 ////////////////////////////////////////////////// // 중수도시설 cellClick 이벤트 (상세정보) const rswtCellClick = (index: number | undefined, headId: string) => { if (headId !== 'chBuildingYn' && index !== undefined && rswtrTable !== undefined) { - setRswtrDetailModal({ isOpen: true, data: rswtrTable[index] }) - } else if (headId === 'chBuildingYn' && index !== undefined && rswtrTable !== undefined) { - if (rswtrTable[index] && rswtrTable[index]?.chBuildingYn === 'Y') { - setRswtrBdstChgProps({ isOpen: true, chBuilding: rswtrTable[index].chgBuilding }); - } + // setRswtrDetailModal({ isOpen: true, data: rswtrTable[index] }); + // setViewMode('detail') + onFeatureSelect(rswtrTable[index]); + onClose(); } } + useEffect(() => { + if (!rswtSttn.isInit) { + rswtSttnInit(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, rswtSttn.isInit, rswtSttnInit]); + useEffect(() => { + const data = tableData(rswtSttnRes, { code }); + const chData = data + .map((item: customRswtBdst) => { + return { + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0]?.rswtrObj, + chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', + instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, + instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, + archArea: item?.archArea.split('.')[0] !== '-1' ? item?.archArea.split('.')[0] : '확인불가' + } + }) + .filter( + (item: customRswtBdst) => + item.reuseBuilding[0]?.rswtrObj !== undefined + ); + setRswtrTable(chData); + }, [code, rswtSttnRes]); + // FIXME: 윤선화 차장님 요구사항으로 엑셀 다운로드 삭제. + // const rswtSttnExcelDownload = useCallback(() => { + // if (rswtSttn.excelList.length > 0) { + // if (rswtSttn.excelList.length === 0) return; + // excelDownload( + // rswtSttn.excelList, + // "중수도시설 현황", + // "sample_rswtSttn.xlsx", + // "A1:W3", + // ); + // } + // }, [rswtSttn.excelList]) + + useEffect(() => { + rswtSttnSearch(false, rswtrPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, rswtSttnSearch, rswtrPage]); + ///////////////////////////////////////////// 중수도 시설 ////////////////////////////////////////////////// + + ///////////////////////////////////////////// 온배수 시설 ////////////////////////////////////////////////// // 온배수시설 cellClick 이벤트 (상세정보) - const htdflCellClick = (index: number | undefined, headId: string) => { - if ( - headId !== "chBuildingYn" && - index !== undefined && - htdflTable !== undefined - ) { - setHtdflDetailModal({ isOpen: true, data: htdflTable[index] }); + const htdflCellClick = (index: number | undefined) => { + if (index !== undefined && htdflTable !== undefined) { + onFeatureSelect(htdflTable[index]); + onClose(); } }; + useEffect(() => { + if (!htdflSttn.isInit) { + initHtdfl(false, 1, "20", "0", '', code.cityCd, code.sggCd); + } + }, [code.cityCd, code.sggCd, htdflSttn.isInit, initHtdfl]); - const excelClick = useCallback(() => { - // if (codeData) pbnstSttnSearch(1, "10000", codeData); - excelDownload( - [[]], - "하수재이용시설 현황", - "sample_pbnstSttn.xlsx", - "A1:U2" - ); - }, [pbnstSttnSearch]); + useEffect(() => { + const data = tableData(htdflSttnRes, { code }); + const chData = data + .map((item: any) => ({ + ...item, + ...item.reuseBuilding[0], + ...item.reuseBuilding[0].htdflObj, + chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", + })) + .filter((item: any) => item.htdflObj !== undefined); + setHtdflTable(chData); + }, [code, htdflSttnRes, htdflSttn.htdflSttHeadList]); + + useEffect(() => { + htdflSttnSearch(true, htdflPage, "20", '', '', code.cityCd, code.sggCd); + }, [code.cityCd, code.sggCd, htdflPage, htdflSttnSearch]); + ///////////////////////////////////////////// 온배수 시설 ////////////////////////////////////////////////// + + ///////////////////////////////////////////// 하수처리 시설 ////////////////////////////////////////////////// + useEffect(() => { + if (code.sggCd.length && pbnstHasuRes.length > 0) { + setHasuTable(tableData(pbnstHasuRes, { code })); + } + }, [code, pbnstHasuRes]); + useEffect(() => { + if (!pbnst.isInit) { + pubHasuInit("1", "0"); + } + }, [pbnst.isInit, pubHasuInit]); + useEffect(() => { + pubHasuInit(String(hasuPage), "0"); + }, [hasuPage, pubHasuInit]); + + const hasuCellClick = (index: number | undefined) => { + if (index !== undefined && pbnstHasuRes !== undefined) { + onFeatureSelect(pbnstHasuRes[index]); + onClose(); + } + }; + ///////////////////////////////////////////// 하수처리 시설 ////////////////////////////////////////////////// // 체크된 레이어에 따른 조건부 컴포넌트 렌더링 함수 const renderConditionalContent = () => { - // 특정 레이어가 체크되었는지 확인 - const hasWaterTreatmentLayer = checkedLayersData.some(layer => - layer.data?.lyrNm?.includes('하수처리') || layer.data?.lyrNm?.includes('재이용시설') - ); - - // swcho : true, false 값 변경하여 시설 변경하여 테스트하였음 + const actTabData = tabData.find((tab) => tab.id === activeTab); + let layerId:string | undefined | null = getSelectedLayers(); + if (layerId === null || layerId === undefined) { + layerId = seletectedLayerNm || ''; + } + //하수처리시설 + const isPrcsFclt = layerId == '하수처리시설' // 재이용시설 - const isPbnst = true; + const isPbnst = layerId == '하수재이용시설'; // 빗물이용시설 - const isRain = false; + const isRain = layerId == '빗물이용시설'; // 중수도시설 - const isRswt = false; + const isRswt = layerId == '중수도시설'; // 온배수시설 - const isHtdfl = false; + const isHtdfl = layerId == '온배수시설'; + if (isPrcsFclt) { + if (viewMode == 'list') { + return ( + <> +
+ + </div> + {/* 높이 조정 */} + <UiTable + tableData={hasuTable || []} + headlist={pubFacHeadList} + pageSize={10} + total={5000} + headName={""} + cellClick={hasuCellClick} + onPageChange={setHasuPage} + /> + </> + ) + } else { + return ( + <> + <div className="flex justify-between items-center mb-4"> + <Title title="하수처리시설 상세정보" /> + </div> + {/* 높이 조정 */} + <UiTable + tableData={isRuseReg?.data || []} + headlist={pubFacHeadList.slice(0, 4)} + pageSize={1} + total={0} + headName={"위치정보"} + cellClick={() => { }} + onPageChange={() => { }} + /> + <UiTable + tableData={isRuseReg?.data || []} + headlist={pubFacHeadList.slice(4)} + pageSize={1} + total={0} + headName={"기본정보"} + cellClick={() => { }} + onPageChange={() => { }} + /> + </> + ) + } + } + if (isPbnst) { + if (viewMode == 'detail') { + // 재이용시설 상세 + return ( + <> + <div className="flex justify-between items-center mb-4"> + <Title title="하수재이용시설 상세정보" /> + </div> + <div className="flex justify-between items-center mb-8"> + <UITab + defaultValue={activeTab} + tabList={tabData.map((tab) => ({ + value: tab.id, + label: tab.name, + onClick: () => setActiveTab(tab.id), + }))} + /> + </div> + <PbnstSttnModal + data={actTabData?.data[0] || ({} as customPbnst)} + titleVisible={false} + /> + </> + ); + } else { + // 재이용시설 목록 + return ( + <> + <div className="flex justify-between items-center"> + <Title title="하수재이용시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={bdstTable || []} + headlist={pbnstSttn.pbnstSttHeadList} + pageSize={20} + total={pbnstSttnResCount || 0} + cellClick={(index: number | undefined) => { + pbnstCellClick(index); + }} + onPageChange={onPageChangeHandler} + > + <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> + </UiTable> + </> + ); + } + } + if (isRain) { + if (viewMode == 'detail') { + // 빗물이용시설 상세 + return ( + <SttnDetailModal type={"RNB"} formObj={rainDetailModal.data as customRainBdst} /> + ); + } else { + // 빗물이용시설 목록 + return ( + <> + <div className="flex justify-between items-center"> + <Title title="빗물이용시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={rainTable || []} + headlist={rainSttn.rainSttHeadList} + pageSize={20} + total={rainSttnResCount} + cellClick={(index: number | undefined, headId: string) => { + rainCellClick(index ?? undefined, headId); + }} + onPageChange={setRainPage} + > + <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> + </UiTable> + </> + ); + } + } - return ( - <div className="mt-4"> - {/* 체크된 레이어가 없는 경우 (재이용시설 목록) */} - {isPbnst && ( + if (isRswt) { + if (viewMode == 'detail') { + // 중수도시설 상세 + return ( + <SttnDetailModal type={"RST"} formObj={rswtrDetailModal.data as customRswtBdst} /> + ); + } else { + // 중수도시설 목록 + return ( <> - {showDetailView ? ( - // 재이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='하수재이용시설 상세정보' /> - </div> - <div className="flex justify-between items-center mb-8"> - <UITab - defaultValue={TABS[0]?.val} - tabList={TABS.map((tab) => ({ - value: tab.val, - label: tab.text, - onClick: () => setActiveTab(tab.val), - }))} - children={undefined} - /> - </div> - <PbnstSttnModal - data={pbnDetaileData.data || ({} as customPbnst)} - titleVisible={false} - /> - <PbnstPrfmncSttnPopup isVisible={false} /> - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='하수재이용시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> - } - headlist={pbnstSttn.pbnstSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - pbnstCellClick(index); - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center"> + <Title title="중수도시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={rswtSttnExcelDownload}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={rswtrTable || []} + headlist={rswtSttn.rswtSttHeadList} + pageSize={20} + total={rswtSttnResCount} + cellClick={(index: number | undefined, headId: string) => { + rswtCellClick(index, headId); + }} + onPageChange={setRswtrPage} + > + <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> + </UiTable> </> - )} - {/* 빗물이용시설 */} - {isRain && ( + ); + } + } + + if (isHtdfl) { + if (viewMode == 'detail') { + // 온배수시설 상세 + return ( + <SttnDetailModal type={"HTB"} formObj={htdflDetailModal.data as customHtdflBdst} /> + ); + } else { + // 온배수시설 목록 + return ( <> - {showDetailView ? ( - // 빗물이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='빗물이용시설 상세정보' /> - </div> - <RainPrfmncSttnPopup rainForm={rainDetailModal.data as customRainBdst} isModal={false} /> - {/* TODO: 지도 점검 결과 현황 추가 할 것 */} - </> - ) : ( - // 빗물이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='빗물이용시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={rainTable || []} - children={ - <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> - } - headlist={rainSttn.rainSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - rainCellClick(index ?? undefined, headId) - }} - onPageChange={setPageNation} - /> - </> - )} + <div className="flex justify-between items-center"> + <Title title="온배수시설 현황" /> + {/* <div className="flex gap-2 mt-8"> + <Button className={btnClass} color="primary" onClick={excelClick}> + 엑셀다운로드 + </Button> + </div> */} + </div> + <UiTable + headName={[]} + tableData={htdflTable || []} + headlist={htdflSttn.htdflSttHeadList} + pageSize={20} + total={htdflSttnResCount || 0} + cellClick={(index: number | undefined) => { + htdflCellClick(index ?? undefined); + }} + onPageChange={setHtdflPage} + > + <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> + </UiTable> </> - )} - {/* 중수도시설 */} - {isRswt && ( - <> - {showDetailView ? ( - // 재이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='중수도시설 상세정보' /> - </div> - <RswtrPrfmncsSttnPopup rswtForm={rswtrDetailModal.data as customRswtBdst} isModal={false} /> - {/* TODO: 지도 점검 결과 현황 추가 할 것 */} - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='중수도시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={rswtrTable || []} - children={ - <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> - } - headlist={rswtSttn.rswtSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - rswtCellClick(index, headId); - }} - onPageChange={setPageNation} - /> - </> - )} - </> - )} - {/* 온배수시설 */} - {isHtdfl && ( - <> - {showDetailView ? ( - // 재이용시설 상세 - <> - <div className="flex justify-between items-center mb-4"> - <Title title='온배수시설 상세정보' /> - </div> - {/* <HtdflPrfmncSttnPopup htdflForm={htdflDetailModal.data as customHtdflBdst} isModal={false} /> */} - <HtdflPrfmncSttnPopup htdflForm={htdflDetailModal.data as customHtdflBdst} isModal={false} /> - </> - ) : ( - // 재이용시설 목록 - <> - <div className="flex justify-between items-center"> - <Title title='온배수시설 현황' /> - <div className="flex gap-2 mt-8"> - <Button className={btnClass} color="primary" onClick={excelClick}>엑셀다운로드</Button> - </div> - </div> - <UiTable - headName={[]} - tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> - } - headlist={htdflSttn.htdflSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { - htdflCellClick(index ?? undefined, headId); - }} - onPageChange={setPageNation} - /> - </> - )} - </> - )} - </div> - ); + ); + } + } + + return null; // 조건에 맞는 콘텐츠가 없을 경우 }; return ( - <NewWindowPortal onClose={memoizedOnClose} title="시설 상세 정보"> - {/* 체크된 레이어에 따른 조건부 렌더링 */} - {renderConditionalContent()} - </NewWindowPortal> + viewMode == 'nothing' ? <></> : + <NewWindowPortal onClose={memoizedOnClose} title="시설 상세 정보"> + {/* 체크된 레이어에 따른 조건부 렌더링 */} + {renderConditionalContent()} + </NewWindowPortal> ); }; diff --git a/apps/wr/app/map/newWindowPortal.tsx b/apps/wr/app/map/newWindowPortal.tsx index 49949e0f4..fc28495ad 100644 --- a/apps/wr/app/map/newWindowPortal.tsx +++ b/apps/wr/app/map/newWindowPortal.tsx @@ -48,7 +48,7 @@ const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, ti if (newWindowRef.current && !newWindowRef.current.closed) return; // 1. 새 창을 열고 참조를 저장합니다. - newWindowRef.current = window.open('', title, 'width=1400,height=1024,resizable=yes,scrollbars=yes'); + newWindowRef.current = window.open('', title, 'width=900,height=800,resizable=yes,scrollbars=yes'); if (newWindowRef.current) { newWindowRef.current.document.title = title; @@ -81,7 +81,7 @@ const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, ti onCloseRef.current(); // onClose(); } - }, [onClose, title]); + }, [handleUnload, onClose, title]); // `createPortal`을 사용해 children을 새 창의 container div에 렌더링합니다. return container ? createPortal(children, container) : null; diff --git a/apps/wr/app/map/pbnstPrfmncSttnPopup.tsx b/apps/wr/app/map/pbnstPrfmncSttnPopup.tsx deleted file mode 100644 index f6d870092..000000000 --- a/apps/wr/app/map/pbnstPrfmncSttnPopup.tsx +++ /dev/null @@ -1,596 +0,0 @@ -"use client"; - -import { useWrStore } from "@/app/store"; -import { initValInUsage, initValOutUsage, subTotalObj, totalObj, type FcPrfType, type PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; -import { CHART_FORM, ContentsDiv, MainChart, ScrollArea, SelectBox, UiTable, type ChartConfig, type ReturnType } from "@common/business_components"; -import ListDiv from "@common/business_components/ui/list_div"; -import { useEffect, useRef, useState } from "react"; -import { Toaster } from "react-hot-toast"; - -interface PbnstPrfmncSttnPopupProps { - isVisible?: boolean; -} - -export default function PbnstPrfmncSttnPopup({ isVisible = true }: PbnstPrfmncSttnPopupProps) { - const { code, tableHeadMaker, pbnstPrfmncSttn, pbnstPrfmncInit, pbnstPrfmncSearch, prfmnc } = useWrStore((state) => state); - const { monthHeadList } = prfmnc - const { pbnstPrfHeadList, pbnstPrfmncRes, prfmncRes, rawData, selectYearList } = pbnstPrfmncSttn; - const [isChHead, setIsChHead] = useState(false); - const [fromDate, setFromDate] = useState<string>(String(new Date().getFullYear())); - const [toDate, setToDate] = useState<string>(String(new Date().getFullYear())); - const [year, setYear] = useState<string>(String(new Date().getFullYear())); - const [bdstTable, setbdstTable] = useState<FcPrfType[]>(); - const ref = useRef<ReturnType>({} as ReturnType); - const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>(); - const [chartConfig, setChartConfig] = useState<ChartConfig>({}); - const [chartData, setChartData] = useState<dnChartForm[]>([]); - const [dnInUsage, setDnInUsage] = useState<dnChartForm[]>([]); - const [dnInChartConfig, setDnInChartConfig] = useState<ChartConfig>({}); - const [dnOutUsage, setDnOutUsage] = useState<dnChartForm[]>([]); - const [dnOutChartConfig, setDnOutChartConfig] = useState<ChartConfig>({}); - const [barData, setBarData] = useState<barChartForm[]>([]); - const [barChartConfig, setBarChartConfig] = useState<ChartConfig>({}); - const [prfData, setPrfData] = useState<any[]>(); - const [lnInChartConfig, setLnInChartConfig] = useState<ChartConfig>({}); - const [lnOutChartConfig, setLnOutChartConfig] = useState<ChartConfig>({}); - const [inLineData, setInLineData] = useState<{ - chartData1: lineChartDataProps[]; - chartData2: lineChartDataProps[]; - chartData3: lineChartDataProps[]; - chartData4: lineChartDataProps[]; - chartData5: lineChartDataProps[]; - chartData6: lineChartDataProps[]; - chartData7: lineChartDataProps[]; - chartData8: lineChartDataProps[]; - chartData9: lineChartDataProps[]; - }>(); - // const [lnInChartConfig, setLnInChartConfig] = useState<ChartConfig>({}); - const [outLineData, setOutLineData] = useState<{ - chartData1: lineChartDataProps[]; - chartData2: lineChartDataProps[]; - chartData3: lineChartDataProps[]; - chartData4: lineChartDataProps[]; - chartData5: lineChartDataProps[]; - chartData6: lineChartDataProps[]; - }>(); - - - - type dnChartForm = { label: string, val: number, fill?: string }; - type barChartForm = { label: string, "장내용수": number, "장외용수": number }; - type lineChartDataProps = { label: string, val: number, color: string }; - - const prfTableData = (prfList: PrfType[], year: string) => { - const inUsageData = initValInUsage; - const outUsageData = initValOutUsage; - - const inSubtotal = subTotalObj; - const outSubtotal = subTotalObj; - - console.log(' prfList ', prfList) - const prfFilter = prfList?.filter((e) => e.ym.slice(0, 4) === year) - if (prfList && prfFilter.length > 0) { - prfList?.forEach((prfItem) => { - const month = Number(prfItem?.ym?.slice(4)); // "MM" - const monthKey = `${month}월`; - - inUsageData.forEach((inData: any) => { - const usageKey = inData.usage; - const value = (prfItem as any)[usageKey] ?? 0; - - inData[monthKey] = value; - inData.total += value; - - if (inSubtotal && usageKey !== "subtotal") { - (inSubtotal as any)[monthKey] = - ((inSubtotal as any)[monthKey] ?? 0) + value; - inSubtotal.total += value; - } - }); - - outUsageData.forEach((outData: any) => { - const usageKey = outData.usage; - const value = (prfItem as any)[usageKey] ?? 0; - - outData[monthKey] = value; - outData.total += value; - - if (usageKey !== "subtotal") { - (outSubtotal as any)[monthKey] = - ((outSubtotal as any)[monthKey] ?? 0) + value; - outSubtotal.total += value; - } - }); - }); - inUsageData.push(inSubtotal); - outUsageData.push(outSubtotal); - const usageTotalObj: { [key: string]: any } = totalObj; - for (const key in usageTotalObj) { - if (["usage", "gubun", "edit"].includes(key)) continue; - const val = - (Number((inSubtotal as any)[key]) || 0) + - (Number((outSubtotal as any)[key]) || 0); - - (usageTotalObj as any)[key] = val; - } - const tableData = [...inUsageData, ...outUsageData, usageTotalObj]; - setPrfData(tableData); - - } else { - setPrfData([]); - } - } - useEffect(() => { - let wshwtr = 0; - let coolUswtr = 0; - let cleanUswtr = 0; - let drwtUswtr = 0; - let dltnUswtr = 0; - let ithlRswtr = 0; - let ithlEtcUswtr = 0; - let cleanToilUswtr = 0; - let resn = 0; - let lndwtr = 0; - let hydUswtr = 0; - let ugwtChr = 0; - let farmUswtr = 0; - let rvrKeepUswtr = 0; - let indstUswtr = 0; - if (rawData) { - rawData.forEach((item) => { - prfTableData(item.prfList, year); - item.prfList.filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - - wshwtr += element.wshwtr; //세척수 - coolUswtr += element.coolUswtr; //냉각수 - cleanUswtr += element.cleanUswtr; //청소수 - drwtUswtr += element.drwtUswtr; //식수대 - dltnUswtr += element.dltnUswtr //희석용수 - ithlRswtr += element.ithlRswtr //중수도 - ithlEtcUswtr += element.ithlEtcUswtr //기타 - cleanToilUswtr += element.cleanToilUswtr //청소화장실용수 - resn += element.resn //세척살수용수 - - lndwtr += element.lndwtr; //조경용수 - hydUswtr += element.hydUswtr; //친수용수 - ugwtChr += element.ugwtChr; //지하수충전 - farmUswtr += element.farmUswtr //농업용수 - rvrKeepUswtr += element.rvrKeepUswtr //하천등유지용수 - indstUswtr += element.indstUswtr //공업용수 - - }); - }) - const data: dnChartForm[] = [] - data?.push({ label: "세척수", val: wshwtr, fill: "red" }) - data?.push({ label: "냉각수", val: coolUswtr, fill: "orange" }) - data?.push({ label: "청소수", val: cleanUswtr, fill: "yellow" }) - data?.push({ label: "식수대", val: drwtUswtr, fill: "green" }) - data?.push({ label: "희석용수", val: dltnUswtr, fill: "skyblue" }) - data?.push({ label: "중수도", val: ithlRswtr, fill: "blue" }) - data?.push({ label: "기타", val: ithlEtcUswtr, fill: "purple" }) - data?.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "red" }) - data?.push({ label: "세척살수용수", val: resn, fill: "orange" }) - data?.push({ label: "조경용수", val: lndwtr, fill: "yellow" }) - data?.push({ label: "친수용수", val: hydUswtr, fill: "green" }) - data?.push({ label: "지하수충전", val: ugwtChr, fill: "skyblue" }) - data?.push({ label: "농업용수", val: farmUswtr, fill: "blue" }) - data?.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "purple" }) - data?.push({ label: "공업용수", val: indstUswtr, fill: "black" }) - setChartData(data); - } - }, [rawData, year]) - - - useEffect(() => { - const newChartConfig = chartData.reduce((config, element) => { - config[element.label] = { - label: element.label, - fill: element.fill - }; - return config; - }, {} as Record<string, { label: string; fill?: string }>) satisfies ChartConfig; - setChartConfig(newChartConfig); - }, [chartData]); - - // 장내용수 도넛차트 - useEffect(() => { - let wshwtr = 0; - let coolUswtr = 0; - let cleanUswtr = 0; - let drwtUswtr = 0; - let dltnUswtr = 0; - let ithlRswtr = 0; - let ithlEtcUswtr = 0; - let cleanToilUswtr = 0; - let resn = 0; - if (rawData) { - rawData.forEach((item) => { - item.prfList.filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - - wshwtr += element.wshwtr; //세척수 - coolUswtr += element.coolUswtr; //냉각수 - cleanUswtr += element.cleanUswtr; //청소수 - drwtUswtr += element.drwtUswtr; //식수대 - dltnUswtr += element.dltnUswtr //희석용수 - ithlRswtr += element.ithlRswtr //중수도 - ithlEtcUswtr += element.ithlEtcUswtr //기타 - cleanToilUswtr += element.cleanToilUswtr //청소화장실용수 - resn += element.resn //세척살수용수 - }); - }) - const data: dnChartForm[] = [] - data?.push({ label: "세척수", val: wshwtr, fill: "yellow" }) - data?.push({ label: "냉각수", val: coolUswtr, fill: "green" }) - data?.push({ label: "청소수", val: cleanUswtr, fill: "yellow" }) - data?.push({ label: "식수대", val: drwtUswtr, fill: "green" }) - data?.push({ label: "희석용수", val: dltnUswtr, fill: "yellow" }) - data?.push({ label: "중수도", val: ithlRswtr, fill: "green" }) - data?.push({ label: "기타", val: ithlEtcUswtr, fill: "yellow" }) - data?.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "green" }) - data?.push({ label: "세척살수용수", val: resn, fill: "yellow" }) - setDnInUsage(data); - } - }, [rawData, year]) - - useEffect(() => { - const newChartConfig = dnInUsage.reduce((config, element) => { - config[element.label] = { - label: element.label, - fill: element.fill - }; - return config; - }, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig; - setDnInChartConfig(newChartConfig); - }, [dnInUsage]); - - // 장외용수 도넛차트 - useEffect(() => { - let lndwtr = 0; - let hydUswtr = 0; - let ugwtChr = 0; - let farmUswtr = 0; - let rvrKeepUswtr = 0; - let indstUswtr = 0; - if (rawData) { - rawData.forEach((item) => { - item.prfList.filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - lndwtr += element.lndwtr; //조경용수 - hydUswtr += element.hydUswtr; //친수용수 - ugwtChr += element.ugwtChr; //지하수충전 - farmUswtr += element.farmUswtr //농업용수 - rvrKeepUswtr += element.rvrKeepUswtr //하천등유지용수 - indstUswtr += element.indstUswtr //공업용수 - - }); - }) - const data: dnChartForm[] = [] - data?.push({ label: "조경용수", val: lndwtr, fill: "yellow" }) - data?.push({ label: "친수용수", val: hydUswtr, fill: "black" }) - data?.push({ label: "지하수충전", val: ugwtChr, fill: "yellow" }) - data?.push({ label: "농업용수", val: farmUswtr, fill: "black" }) - data?.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "yellow" }) - data?.push({ label: "공업용수", val: indstUswtr, fill: "black" }) - setDnOutUsage(data); - } - }, [rawData, year]) - - useEffect(() => { - const newChartConfig = dnOutUsage.reduce((config, element) => { - config[element.label] = { - label: element.label, - fill: element.fill - }; - return config; - }, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig; - setDnOutChartConfig(newChartConfig); - }, [dnOutUsage]); - - //월별 장내외 용수 총 실적 막대차트 - useEffect(() => { - let wshwtr = 0; - let coolUswtr = 0; - let cleanUswtr = 0; - let drwtUswtr = 0; - let dltnUswtr = 0; - let ithlRswtr = 0; - let ithlEtcUswtr = 0; - let cleanToilUswtr = 0; - let resn = 0; - let lndwtr = 0; - let hydUswtr = 0; - let ugwtChr = 0; - let farmUswtr = 0; - let rvrKeepUswtr = 0; - let indstUswtr = 0; - let inUsageSum = 0; - let outUsageSum = 0; - let inUsageArr = []; - let outUsageArr = []; - - - if (rawData) { - const data: barChartForm[] = [] - rawData.forEach((item) => { - item.prfList - .filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - - wshwtr = element.wshwtr; //세척수 - coolUswtr = element.coolUswtr; //냉각수 - cleanUswtr = element.cleanUswtr; //청소수 - drwtUswtr = element.drwtUswtr; //식수대 - dltnUswtr = element.dltnUswtr //희석용수 - ithlRswtr = element.ithlRswtr //중수도 - ithlEtcUswtr = element.ithlEtcUswtr //기타 - cleanToilUswtr = element.cleanToilUswtr //청소화장실용수 - resn = element.resn //세척살수용수 - - lndwtr = element.lndwtr; //조경용수 - hydUswtr = element.hydUswtr; //친수용수 - ugwtChr = element.ugwtChr; //지하수충전 - farmUswtr = element.farmUswtr //농업용수 - rvrKeepUswtr = element.rvrKeepUswtr //하천등유지용수 - indstUswtr = element.indstUswtr //공업용수 - - inUsageSum = wshwtr + coolUswtr + cleanUswtr + drwtUswtr + dltnUswtr + ithlRswtr + ithlEtcUswtr + cleanToilUswtr + resn; - inUsageArr.push(inUsageSum) - outUsageSum = lndwtr + hydUswtr + ugwtChr + farmUswtr + rvrKeepUswtr + indstUswtr; - outUsageArr.push(outUsageSum) - - const month = Number(element.ym.slice(4, 6)) - data.push({ label: `${month}월`, "장내용수": inUsageSum, "장외용수": outUsageSum }) - - }, - ); - - }) - - setBarData(data); - } - }, [rawData, year]) - - useEffect(() => { - const newChartConfig = barData.reduce((config, element) => { - config[element.label] = { - label: element.label, - }; - return config; - - }, {} as Record<string, { label: string }>) satisfies ChartConfig; - setBarChartConfig(newChartConfig); - }, [barData]); - - //월별 장내 용수 실적 라인차트 - useEffect(() => { - - if (rawData) { - const wshwtrData: lineChartDataProps[] = [] - const coolUswtrData: lineChartDataProps[] = [] - const cleanUswtrData: lineChartDataProps[] = [] - const drwtUswtrData: lineChartDataProps[] = [] - const dltnUswtrData: lineChartDataProps[] = [] - const ithlRswtrData: lineChartDataProps[] = [] - const ithlEtcUswtrData: lineChartDataProps[] = [] - const cleanToilUswtrData: lineChartDataProps[] = [] - const resnData: lineChartDataProps[] = [] - rawData.forEach((item) => { - item.prfList.filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - const month = Number(element.ym.slice(4, 6)) - wshwtrData.push({ label: `${month}월`, val: element.wshwtr, color: "red" }) - coolUswtrData.push({ label: `${month}월`, val: element.coolUswtr, color: "red" }) - cleanUswtrData.push({ label: `${month}월`, val: element.cleanUswtr, color: "red" }) - drwtUswtrData.push({ label: `${month}월`, val: element.drwtUswtr, color: "red" }) - dltnUswtrData.push({ label: `${month}월`, val: element.dltnUswtr, color: "red" }) - ithlRswtrData.push({ label: `${month}월`, val: element.ithlRswtr, color: "red" }) - ithlEtcUswtrData.push({ label: `${month}월`, val: element.ithlEtcUswtr, color: "red" }) - cleanToilUswtrData.push({ label: `${month}월`, val: element.cleanToilUswtr, color: "red" }) - resnData.push({ label: `${month}월`, val: element.resn, color: "red" }) - - }, - ); - }) - const rtndata = { - chartData1: wshwtrData, - chartData2: coolUswtrData, - chartData3: cleanUswtrData, - chartData4: drwtUswtrData, - chartData5: dltnUswtrData, - chartData6: ithlRswtrData, - chartData7: ithlEtcUswtrData, - chartData8: cleanToilUswtrData, - chartData9: resnData - } - - setInLineData(rtndata) - } - }, [rawData, year]) - - useEffect(() => { - if (inLineData?.chartData1) { - const newChartConfig = { - chartData1: { - label: '세척수', - color: "red", - }, - chartData2: { - label: '냉각수', - color: "orange", - }, - chartData3: { - label: '청소수', - color: "yellow", - }, - chartData4: { - label: '식수대', - color: "pink", - }, - chartData5: { - label: '희석용수', - color: "purple", - }, - chartData6: { - label: '중수도', - color: "green", - }, - chartData7: { - label: '기타', - color: "blue", - }, - chartData8: { - label: '청소화장실용수', - color: "magenta", - }, - chartData9: { - label: '세척살수용수', - color: "skyblue", - }, - } satisfies ChartConfig; - setLnInChartConfig(newChartConfig); - } - }, [inLineData]); - - //월별 장외 용수 실적 라인차트 - useEffect(() => { - if (rawData) { - const lndwtrData: lineChartDataProps[] = [] - const hydUswtrData: lineChartDataProps[] = [] - const ugwtChrData: lineChartDataProps[] = [] - const farmUswtrData: lineChartDataProps[] = [] - const rvrKeepUswtrData: lineChartDataProps[] = [] - const indstUswtrData: lineChartDataProps[] = [] - rawData.forEach((item) => { - item.prfList.filter((e) => e.ym.slice(0, 4) === year).forEach((element) => { - const month = Number(element.ym.slice(4, 6)) - lndwtrData.push({ label: `${month}월`, val: element.lndwtr, color: "red" }) - hydUswtrData.push({ label: `${month}월`, val: element.hydUswtr, color: "red" }) - ugwtChrData.push({ label: `${month}월`, val: element.ugwtChr, color: "red" }) - farmUswtrData.push({ label: `${month}월`, val: element.farmUswtr, color: "red" }) - rvrKeepUswtrData.push({ label: `${month}월`, val: element.rvrKeepUswtr, color: "red" }) - indstUswtrData.push({ label: `${month}월`, val: element.indstUswtr, color: "red" }) - }, - ); - }) - setOutLineData({ - chartData1: lndwtrData, - chartData2: hydUswtrData, - chartData3: ugwtChrData, - chartData4: farmUswtrData, - chartData5: rvrKeepUswtrData, - chartData6: indstUswtrData, - }) - } - }, [rawData, year]) - - useEffect(() => { - if (outLineData?.chartData1) { - const newChartConfig = { - chartData1: { - label: '조경용수', - color: "red", - }, - chartData2: { - label: '친수용수', - color: "orange", - }, - chartData3: { - label: '지하수충전', - color: "yellow", - }, - chartData4: { - label: '농업용수', - color: "green", - }, - chartData5: { - label: '하천등유지용수', - color: "blue", - }, - chartData6: { - label: '공업용수', - color: "purple", - }, - } satisfies ChartConfig; - setLnOutChartConfig(newChartConfig); - } - }, [outLineData]); - - useEffect(() => { - if (!pbnstPrfmncSttn.isInit) { - pbnstPrfmncInit("1", "11"); - } - }, [pbnstPrfmncSttn.isInit, pbnstPrfmncInit]); - - useEffect(() => { - setbdstTable(prfmncRes); - }, [prfmncRes]); - - return ( - <> - <ContentsDiv> - <ListDiv> - <hr /> - <h3 className="mt-4 ml-2 text-2xl font-medium text-label">하수재이용실적 상세현황</h3> - - <SelectBox - className="w-1/12 text-2xl mt-4 ml-2" - label="연도" - selectClass={""} - selectArray={selectYearList} - value={year} - onSelectValue={(val: string | number) => setYear(String(val))} /> - <h1 className="mt-4 ml-2">장내·외 용도별 하수재이용실적 현황(계)</h1> - - <div className="flex"> - <div className="w-1/3"> - <MainChart chartConfig={chartConfig} chartData={chartData} chartTitle={"장내·외 용수 총 실적"} chartForm={CHART_FORM.DN} /> - </div> - <div className="w-1/3"> - <MainChart chartConfig={dnInChartConfig} chartData={dnInUsage} chartTitle={"장내용수 실적"} chartForm={CHART_FORM.DN} /> - </div> - <div className="w-1/3"> - <MainChart chartConfig={dnOutChartConfig} chartData={dnOutUsage} chartTitle={"장외용수 실적"} chartForm={CHART_FORM.DN} /> - </div> - </div> - <h1 className="">장내·외 월별 하수재이용실적 현황</h1> - <div className="flex"> - <div className="w-1/3"> - <MainChart chartConfig={barChartConfig} chartData={barData} chartTitle={"월별 장내·외 용수 총 실적"} chartForm={CHART_FORM.DOUBLEBAR} /> - </div> - <div className="w-1/3"> - <MainChart chartConfig={lnInChartConfig} chartData={inLineData} chartTitle={"월별 장내 용수 실적"} chartForm={CHART_FORM.LINE} /> - </div> - <div className="w-1/3"> - <MainChart chartConfig={lnOutChartConfig} chartData={outLineData} chartTitle={"월별 장외 용수 총 실적"} chartForm={CHART_FORM.LINE} /> - </div> - </div> - {/* 하수재이용실적 현황 - 조건부 렌더링 */} - {isVisible && ( - <> - <h1 className="">하수재이용실적 현황</h1> - <ListDiv className="col-span-8 pr-6 "> - <ScrollArea className="h-[60vh]"> - <div className="card-header"> - <h3 className="text-2xl font-medium text-label"> - {"하수처리수재이용 실적(m3) 등록결과"} - </h3> - </div> - - <UiTable - headName={undefined} - tableData={prfData || []} - headlist={monthHeadList} - pageSize={0} - total={0} - cellClick={undefined} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - }}> - </UiTable> - </ScrollArea> - </ListDiv> - </> - )} - </ListDiv> - </ContentsDiv> - <Toaster position="top-center" /> - </> - ) -} diff --git a/apps/wr/app/map/rainPrfmncSttnPopup.tsx b/apps/wr/app/map/rainPrfmncSttnPopup.tsx deleted file mode 100644 index 18cdac8e6..000000000 --- a/apps/wr/app/map/rainPrfmncSttnPopup.tsx +++ /dev/null @@ -1,421 +0,0 @@ -"use client"; - -import { useWrStore } from "@/app/store"; -import { - rainZod, - selectClass, - TEST_UUID, - type customRainBdst, -} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { DatePicker, FormUi } from "@common/business_components"; -import { Form, FormField, SelectBox } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; -import { useForm, useWatch, type UseFormReturn } from "react-hook-form"; -import { z } from "zod"; -import BdstReg from "@/components/ui/form/fcltReg/bdstReg/bdstReg"; -import { - formatCommaNumber, - handleCommaNumberChange, -} from "@/components/lib/func/commom"; -import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; -import { Label } from "@common/business_components/ui/form/lib/label"; - -export default function RainPrfmncSttnPopup({ - rainForm, - isModal, -}: { - rainForm: customRainBdst; - isModal: boolean; -}) { - const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore( - (state) => state - ); - const { rainFcltCd } = code; - const defaultValues: z.infer<typeof rainZod> = rainZod.parse({}); - - const form = useForm<z.infer<typeof rainZod>>({ - resolver: zodResolver(rainZod), - defaultValues: defaultValues, - }); - - const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn] = form.watch([ - "reuseBuilding.0.grntchBdstCertYn", - "reuseBuilding.0.instlCstSprtYn", - "reuseBuilding.0.rainyObj.filtrTrtmfctYn", - ]); - - const cleanRainData = (raw: any): z.infer<typeof rainZod> => { - return { - ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), - archChgPrmsnDt: raw?.archChgPrmsnDt - ? new Date(raw?.archChgPrmsnDt) - : null, - reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ - ...item, - instlCmptnDt: new Date(item?.instlCmptnDt), - operMngCd: item?.operMngCd ?? "", // null → "" - grntchBdstCertYr: - typeof item?.grntchBdstCertYr === "string" - ? item?.grntchBdstCertYr - : "", // null → "" - rainObj: { - ...item?.rainObj, - }, - })), - }; - }; - - useEffect(() => { - if (grntchBdstCertYn === "N") { - form.setValue("reuseBuilding.0.grntchBdstCertYr", ""); - form.setValue("reuseBuilding.0.grntchBdstCertNo", ""); - form.setValue("reuseBuilding.0.grntchBdstCertGrd", ""); - } else if (instlCstSprtYn === "N") { - form.setValue("reuseBuilding.0.instlCstSprtAmt", 0); - } else if (filtrTrtmfctYn === "N") { - form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctCpct", 0); - form.setValue("reuseBuilding.0.rainyObj.filtrTrtmfctPrs", ""); - } - }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn]); - - // form 값이 변경될 때마다 로그 출력 - useEffect(() => { - const subscription = form.watch((value) => { - }); - - - return () => subscription.unsubscribe(); - }, [form]); - - useEffect(() => { - console.log("form errors:", form.formState.errors); - }, [form.formState.errors]); - - const onSubmit = (values: z.infer<typeof rainZod>) => { - if (isModal) { - rainBdstReg(values, "41"); - } else { - rainBdstUpdate(values, "41"); - } - }; - - useEffect(() => { - if (rainZod) form.reset(cleanRainData(rainForm)); - }, [rainForm]); - - - return ( - <div className="!mx-[1.6rem] !p-0r"> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)}> - <div> - <div className="grid grid-cols-12 flex items-center card-header"> - <h1 className="text-2xl font-medium text-label col-span-10"> - {isModal ? "건축물 운영정보" : "빗물이용시설 정보"} - </h1> - </div> - </div> - {isModal && rainForm != undefined ? <BdstReg form={form} /> : <></>} - {isModal ? ( - <h1 className="pl-3 text-xl col-span-10 mt-4"> - 빗물이용시설 정보{" "} - </h1> - ) : ( - <></> - )} - <h1 className={formH1Class}> - 기본정보 - </h1> - - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCmptnDt" - render={({ field }) => ( - <FormUi label="설치완료일"> - <DatePicker - mode="single" - field={{ - value: - field.value && !isNaN(new Date(field.value).getTime()) - ? new Date(field.value) - : new Date(), // Provide a default Date value - onChange: (date) => field.onChange(date), - }} - selectClass={"w-full"} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCst" - render={({ field }) => ( - <FormUi label="설치비"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - </div> - <div className=""> - <h1 className={formH1Class}> - 빗물이용시설 정보 - </h1> - </div> - <div> - <h2 className={formH2Class}>집수면</h2> - </div> - <div className="grid grid-cols-10 gap-4 mt-4 "> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.pntfColKnd" - render={({ field }) => ( - <FormUi label="종류"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={rainFcltCd} - onSelectValue={field.onChange} - value={field.value ?? rainFcltCd[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.pntfColArea" - render={({ field }) => ( - <FormUi label="면적(m³)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - /> - </FormUi> - )} - /> - </div> - </div> - - <div> - <h2 className={formH2Class}>여과 등 처리시설</h2> - </div> - <div className="grid grid-cols-12 gap-2 mt-4"> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctYn" - render={({ field }) => ( - <FormUi label="유무"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctCpct" - render={({ field }) => ( - <FormUi label="용량(m³/일)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={filtrTrtmfctYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctPrs" - render={({ field }) => ( - <FormUi label="처리공정"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={filtrTrtmfctYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - </div> - <div className=" my-2"> - <h1 className={formH1Class}> - 인센티브 정보 - </h1> - </div> - <div> - <h2 className={formH2Class}>설치비 지원</h2> - </div> - <div className="grid grid-cols-10 gap-2 mt-4"> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtYn" - render={({ field }) => ( - <FormUi label="지원 여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => ( - <FormUi label="지원금액(원)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={instlCstSprtYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - </div> - - <div> - <h2 className={formH2Class}>녹색건축물 인증</h2> - </div> - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYn" - render={({ field }) => ( - <FormUi label="인증여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => ( - <FormUi label="인증년도"> - <Input - className={'w-full !text-xl'} - placeholder="2024" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={grntchBdstCertYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3 "> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => ( - <FormUi label="인증번호"> - <Input - className={'w-full !text-xl'} - placeholder="ab1234678" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={grntchBdstCertYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertGrd" - render={({ field }) => ( - <FormUi label="인증등급"> - <Input - className={'w-full !text-xl'} - placeholder="A" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={grntchBdstCertYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - </div> - </form> - </Form> - </div> - ); -} diff --git a/apps/wr/app/map/rswtrPrfmncSttnPopup.tsx b/apps/wr/app/map/rswtrPrfmncSttnPopup.tsx deleted file mode 100644 index e7f94a3b5..000000000 --- a/apps/wr/app/map/rswtrPrfmncSttnPopup.tsx +++ /dev/null @@ -1,404 +0,0 @@ -"use client"; - -import { - DatePicker, - Form, - FormField, - FormUi, - SelectBox, -} from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { useWrStore } from "@/app/store"; -import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { - rswtZod, - type customRswtBdst, -} from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import { useEffect } from "react"; -import BdstReg from "@/components/ui/form/fcltReg/bdstReg/bdstReg"; -import { - formatCommaNumber, - handleCommaNumberChange, -} from "@/components/lib/func/commom"; -import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; -import { Label } from "@common/business_components/ui/form/lib/label"; - -export default function RswtrPrfmncsSttnPopup({ - rswtForm, - isModal, -}: { - rswtForm: customRswtBdst; - isModal: boolean; -}) { - const { rswt, code, rswtBdstUpdate, rswtBdstReg } = useWrStore( - (state) => state - ); - - const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({}); - - const form = useForm<z.infer<typeof rswtZod>>({ - resolver: zodResolver(rswtZod), - defaultValues: defaultValues, - }); - - const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs] = form.watch([ - "reuseBuilding.0.grntchBdstCertYn", - "reuseBuilding.0.instlCstSprtYn", - "reuseBuilding.0.rswtrObj.filtrTrtmfctProcs", - ]); - - const onSubmit = (values: z.infer<typeof rswtZod>) => { - if (isModal) { - rswtBdstReg(values, "41"); - } else { - rswtBdstUpdate(values, "41"); - } - }; - const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { - return { - ...raw, - frstArchPrmsnDt: new Date(raw?.frstArchPrmsnDt || null), - archChgPrmsnDt: raw?.archChgPrmsnDt - ? new Date(raw?.archChgPrmsnDt) - : null, - reuseBuilding: (raw?.reuseBuilding || []).map((item: any) => ({ - ...item, - instlCmptnDt: new Date(item?.instlCmptnDt), - operMngCd: item?.operMngCd ?? "", // null → "" - grntchBdstCertYr: - typeof item?.grntchBdstCertYr === "string" - ? item?.grntchBdstCertYr - : "", // null → "" - rswtrObj: { - ...item?.rswtrObj, - }, - })), - }; - }; - - useEffect(() => { - console.log("form errors:", form.formState.errors); - }, [form.formState.errors]); - - useEffect(() => { - console.log("filtrTrtmfctProcs ", filtrTrtmfctProcs); - if (grntchBdstCertYn === "N") { - form.setValue("reuseBuilding.0.grntchBdstCertYr", ""); - form.setValue("reuseBuilding.0.grntchBdstCertNo", ""); - form.setValue("reuseBuilding.0.grntchBdstCertGrd", ""); - } else if (instlCstSprtYn === "N") { - form.setValue("reuseBuilding.0.instlCstSprtAmt", 0); - } - }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs]); - - useEffect(() => { - if (rswtZod) form.reset(cleanRswtData(rswtForm)); - }, [rswtForm]); - - return ( - <div className="!mx-[1.6rem] !p-0r"> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)}> - {/* <div className="flex justify-between items-center mx-3"> */} - <div> - <div className="grid grid-cols-12 flex items-center card-header"> - <h1 className="text-2xl font-medium text-label col-span-10"> - 건축물 운영정보 - </h1> - </div> - </div> - - {isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>} - {isModal ? ( - <h1 className="pl-3 text-xl col-span-10 mt-4 "> - 중수도 시설 정보{" "} - </h1> - ) : ( - <></> - )} - <h1 className={formH1Class}>기본정보</h1> - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCmptnDt" - render={({ field }) => ( - <FormUi label="설치완료일"> - <DatePicker - mode="single" - field={{ - value: - field.value && !isNaN(new Date(field.value).getTime()) - ? new Date(field.value) - : new Date(), // Provide a default Date value - onChange: (date) => field.onChange(date), - }} - selectClass={"w-full"} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCst" - render={({ field }) => ( - <FormUi label="설치비"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - </div> - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.wtrUsqty" - render={({ field }) => ( - <FormUi label="물사용량(m³)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.oblgTrgtWtrUsqty" - render={({ field }) => ( - <FormUi label="의무대상 물사용량(m³)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - </div> - <div className=" my-4"> - <h1 className={formH1Class}>중수도 시설 정보</h1> - </div> - - <div className="grid grid-cols-12 gap-1 mt-4"> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.filtrTrtmfctCpct" - render={({ field }) => ( - <FormUi label="처리시설 용량"> - <Input - className={'w-full !text-xl'} - placeholder="0" - type="number" - value={field.value ?? ""} - onChange={(e)=>{field.onChange(Number(e.target.value))} } - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.orgwtKndCd" - render={({ field }) => ( - <FormUi label="원수 종류"> - <SelectBox - className={""} - label={""} - selectClass={selectClass} - selectArray={code.orgwtKndCd} - onSelectValue={field.onChange} - value={field.value ?? code.orgwtKndCd[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.filtrTrtmfctProcs" - render={({ field }) => ( - <FormUi label="주요처리공정"> - <Input - className={'w-full !text-xl'} - placeholder="주요처리공정" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - </div> - - <div className=" my-2"> - <h1 className={formH1Class}>인센티브 정보</h1> - </div> - <div> - <h2 className={formH2Class}>설치비 지원</h2> - </div> - <div className="grid grid-cols-2 gap-2 mt-4"> - <div className="col-span-1"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtYn" - render={({ field }) => ( - <FormUi label="설치비 지원여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-1"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => ( - <FormUi label="지원금액(원)"> - <Input - className={'w-full !text-xl'} - placeholder="1,000,000" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={instlCstSprtYn !== "Y"} - /> - </FormUi> - )} - /> - </div> - </div> - - <div> - <h2 className={formH2Class}>녹색건축물 인증</h2> - </div> - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYn" - render={({ field }) => ( - <FormUi label="인증여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => ( - <FormUi label="인증년도"> - <Input - className={'w-full !text-xl'} - placeholder="2024" - type="text" - {...field} - value={field.value ?? ""} - onChange={field.onChange} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => ( - <FormUi label="인증번호"> - <Input - className={'w-full !text-xl'} - placeholder="ab1234678" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertGrd" - render={({ field }) => ( - <FormUi label="인증등급"> - <Input - className={'w-full !text-xl'} - placeholder="A" - type="" - value={field.value ?? ""} - onChange={field.onChange} - readOnly={true} - /> - </FormUi> - )} - /> - </div> - </div> - </form> - </Form> - </div> - ); -} diff --git a/apps/wr/app/matMng/coMat/coMatRvw/page.tsx b/apps/wr/app/matMng/coMat/coMatRvw/page.tsx index 15bff0b32..a1f484b83 100644 --- a/apps/wr/app/matMng/coMat/coMatRvw/page.tsx +++ b/apps/wr/app/matMng/coMat/coMatRvw/page.tsx @@ -1,13 +1,13 @@ "use client"; import { useWrStore } from "@/app/store"; +import { usageProcData } from "@/app/store/matDmd/coMatRvw/headList"; import { DmdCoReqSchema, - type DedMatUpdateType, type DmdCoReqType, type DmdMatTableType, } from "@/app/store/matDmd/coMatRvw/type"; -import { formH1Class, formTableName } from "@/components/lib/class/comClass"; +import { formH1Class } from "@/components/lib/class/comClass"; import { formatPhoneNumber, getCity, @@ -15,33 +15,30 @@ import { tableData, yearOptions, } from "@/components/lib/func/commom"; +import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { ContentsDiv, Form, FormField, FormUi, - ScrollArea, SearchDiv, SearchFormLeft, SearchFormRight, SearchInput, SelectBox, Title, - UiModal, UiTable, type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button, Input, Label } from "@common/components/ui"; +import { zodResolver } from "@hookform/resolvers/zod"; +import moment from "moment"; import { useEffect, useRef, useState } from "react"; import { useForm, useWatch } from "react-hook-form"; import toast, { Toaster } from "react-hot-toast"; import { z } from "zod"; -import moment from "moment"; -import { usageProcData } from "@/app/store/matDmd/coMatRvw/headList"; -import { zodResolver } from "@hookform/resolvers/zod"; -import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm"; -import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; export default function CoMatRvw() { const { code, coRvw, coMatRvwInit, coMatRvwSearch, coMatRvwInqua } = @@ -119,7 +116,7 @@ export default function CoMatRvw() { useEffect(() => { if (coMatRvwRes&&coMatRvwRes.length > 0) { - const data = coMatRvwRes?.map((item, index) => { + const data = coMatRvwRes?.map((item) => { let flag = ""; flag = getdmdMatFlag(item?.demandMatching?.splyFcltFlg ||undefined); @@ -238,7 +235,7 @@ export default function CoMatRvw() { <div className="flex flex-row space-x-2"> <Button size={"sm"} - onClick={(e) => { + onClick={() => { if (fromDate && toDate) { const fromNum = Number(fromDate); const toNum = Number(toDate); @@ -277,12 +274,12 @@ export default function CoMatRvw() { headlist={coRvwHeadList} pageSize={20} total={coMatRvwCount} - cellClick={(index: number | undefined, headId: string) => { + cellClick={(index: number | undefined) => { if (index !== undefined && index >= 0) { TableCellClick(index); } }} - onPageChange={() => {}} + onPageChange={(val) => {setPageNatiion(val)}} ></UiTable> </ListDiv> <hr /> diff --git a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx index a81a85e19..e45a0a0f2 100644 --- a/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseCaseMng/page.tsx @@ -5,7 +5,6 @@ import { ruseUtzType } from "@/app/store/matDmd/ruseCaseMng/headList"; import { excelDownload, getCity } from "@/components/lib/func/commom"; import RuseCaseMngExcel from "@/components/ui/modal/coMat/ruseCaseMng/ruseCaseMngExcelModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { ContentsDiv, filePickedBlobArray, @@ -22,7 +21,7 @@ import { import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; import { useEffect, useState } from "react"; -import { toast, Toaster } from "react-hot-toast"; +import { Toaster } from "react-hot-toast"; export default function RuseCaseMng() { const { code, ruseCaseMng, selectRuseCaseMng } = useWrStore((state) => state); @@ -37,7 +36,7 @@ export default function RuseCaseMng() { // 물재이용사례 조회 const searchRuseCaseMng = async (pageNo: number, pageSize: number) => { - const res = await selectRuseCaseMng( + await selectRuseCaseMng( pageNo, pageSize, sidoCd ?? "", @@ -237,11 +236,10 @@ export default function RuseCaseMng() { <UiTable headName={"물재이용사례 현황"} tableData={ruseCaseMngList} - children={undefined} headlist={ruseCaseMng.ruseHeadList} pageSize={20} total={count} - cellClick={(index: number | undefined, headId: string) => {}} + cellClick={() => {}} onPageChange={(pageNo: number) => { searchRuseCaseMng(pageNo, 10); }} diff --git a/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx b/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx index d0a6bcb93..75fd6825f 100644 --- a/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx +++ b/apps/wr/app/matMng/coMat/ruseRvwHstry/page.tsx @@ -10,9 +10,9 @@ import { formatPhoneNumber, getCity, getdmdMatFlag, + tableData, yearOptions, } from "@/components/lib/func/commom"; -import ConCostForm from "@/components/ui/form/coMat/conCostForm/conCostForm"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { ContentsDiv, @@ -26,15 +26,12 @@ import { type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button, DatePicker, Input, Label } from "@common/components/ui"; +import { Button, Label } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import moment from "moment"; import { useCallback, useEffect, useState } from "react"; -import { set, useFieldArray, useForm } from "react-hook-form"; -import { z } from "zod"; -import { tableData } from "@/components/lib/func/commom"; +import { useForm } from "react-hook-form"; import toast, { Toaster } from "react-hot-toast"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; export default function RuseRvwHstry() { const { code, @@ -44,7 +41,7 @@ export default function RuseRvwHstry() { ruseRvwInqua, ruseRvwComplete, } = useWrStore((state) => state); - const { rvwHistRes, ruseHistHeadList,rvwHistCount } = ruseHist; + const { rvwHistRes, ruseHistHeadList, rvwHistCount } = ruseHist; const [pageNation, setPageNatiion] = useState<number>(1); const [dmdCoNm, setDmdCoNm] = useState<string>(""); @@ -70,18 +67,16 @@ export default function RuseRvwHstry() { setObjSearch({ city: cityValue, sgg: "0" }); }; - useEffect(() =>{ - getButtonSearch() - },[pageNation]) + useEffect(() => { + getButtonSearch(); + }, [pageNation]); - const getButtonSearch=()=>{ + const getButtonSearch = () => { if (fromDate && toDate) { const fromNum = Number(fromDate); const toNum = Number(toDate); if (fromNum > toNum) { - toast.error( - "시작년도가 종료년도 이후로 설정할 수 없습니다." - ); + toast.error("시작년도가 종료년도 이후로 설정할 수 없습니다."); } else { let con: string | number = ""; if (String(objSearch.city).length > 0) { @@ -90,16 +85,10 @@ export default function RuseRvwHstry() { if (String(objSearch.sgg).length > 0 && objSearch.sgg !== "0") { con = String(objSearch.sgg); } - getSearch( - fromNum, - toNum, - con, - dmdCoNm, - ruseUtztnFcltNm - ); + getSearch(fromNum, toNum, con, dmdCoNm, ruseUtztnFcltNm); } } - } + }; const getSgg = (val: string | number) => { console.log(val); setObjSearch({ ...objSearch, sgg: String(val) }); @@ -123,8 +112,6 @@ export default function RuseRvwHstry() { ruseUtztnFcltNm ); } else { - - ruseRvwInqua(pageNation, 13, String(startYear), String(endYear), sggCd); } }; @@ -150,7 +137,7 @@ export default function RuseRvwHstry() { const confrirmToast = () => { const completeData = rvwHistData ?.map((item) => { - form.clearErrors; + form.clearErrors(); if (item?.completeYn) { return Number(item.dmdInfoSn); } @@ -166,7 +153,7 @@ export default function RuseRvwHstry() { <button onClick={() => { toast.dismiss(t.id); - ruseRvwComplete(completeData as Number[]); + ruseRvwComplete(completeData as number[]); }} > 확인 @@ -175,7 +162,7 @@ export default function RuseRvwHstry() { </span> )); } else { - ruseRvwComplete(completeData as Number[]); + ruseRvwComplete(completeData as number[]); } }; useEffect(() => { @@ -191,33 +178,33 @@ export default function RuseRvwHstry() { useEffect(() => { if (rvwHistRes) { - const data = rvwHistRes?.map((item, index) => { + const data = rvwHistRes?.map((item) => { let flag = ""; - flag = getdmdMatFlag(item.demandMatching?.splyFcltFlg ?? ""); - const formatDate = (dateStr: string | null | undefined) => { - // null, undefined, 빈 문자열인 경우 '없음'을 반환합니다. - if (!dateStr) return "없음"; - // "YYYYMMDD" 형식으로 날짜를 파싱합니다. - const d = moment(dateStr, "YYYYMMDD"); - // 파싱된 날짜가 유효한 경우에만 포맷하고, 그렇지 않으면 '없음'을 반환합니다. - return d.isValid() ? d.format("YYYY-MM-DD") : "없음"; - }; - + flag = getdmdMatFlag(item.demandMatching?.splyFcltFlg ?? ""); + const formatDate = (dateStr: string | null | undefined) => { + // null, undefined, 빈 문자열인 경우 '없음'을 반환합니다. + if (!dateStr) return "없음"; + // "YYYYMMDD" 형식으로 날짜를 파싱합니다. + const d = moment(dateStr, "YYYYMMDD"); + // 파싱된 날짜가 유효한 경우에만 포맷하고, 그렇지 않으면 '없음'을 반환합니다. + return d.isValid() ? d.format("YYYY-MM-DD") : "없음"; + }; + return { ...item, ctpvCd: item.demandCo?.ctpvCd, sggCd: item.demandCo?.sggCd, dmdCoNm: item.demandCo?.dmdCoNm, daddr: item.demandCo?.daddr, - telno: formatPhoneNumber(item.demandCo?.telno ||''), + telno: formatPhoneNumber(item.demandCo?.telno || ""), dmndTmng: item?.dmndTmng ? moment(item?.dmndTmng).format("YYYY-MM-DD") : "없음", - rvwCmptnYmd: formatDate(item.demandMatching?.rvwCmptnYmd), - mtchnCmptnYmd: formatDate(item.demandMatching?.mtchnCmptnYmd), - - ruseUtztnFcltNm: item.ruseUtztnFcltNm, + rvwCmptnYmd: formatDate(item.demandMatching?.rvwCmptnYmd), + mtchnCmptnYmd: formatDate(item.demandMatching?.mtchnCmptnYmd), + + ruseUtztnFcltNm: item.ruseUtztnFcltNm, dmndQty: item.dmndQty, splyFcltFlg: flag, completeYn: false, @@ -228,7 +215,6 @@ export default function RuseRvwHstry() { } }, [rvwHistRes]); - useEffect(() => { console.log("변경여부 ", form.formState.isDirty); }, [form.formState]); @@ -308,8 +294,8 @@ export default function RuseRvwHstry() { <div className="flex flex-row space-x-2"> <Button size={"sm"} - onClick={(e) => { - getButtonSearch() + onClick={() => { + getButtonSearch(); }} > 조회 @@ -333,16 +319,12 @@ export default function RuseRvwHstry() { headlist={ruseHistHeadList} pageSize={20} total={rvwHistCount} - cellClick={(index: number | undefined, headId: string) => { + cellClick={(index: number | undefined) => { TableCellClick(index); }} - onPageChange={ - (page)=>{ - setPageNatiion(page) - - } - - } + onPageChange={(page) => { + setPageNatiion(page); + }} ></UiTable> {/* <hr /> <h3 className="mt-4 ml-2 text-2xl font-medium text-label"> diff --git a/apps/wr/app/matMng/coMng/coSttn/page.tsx b/apps/wr/app/matMng/coMng/coSttn/page.tsx index e828f4226..d385493d9 100644 --- a/apps/wr/app/matMng/coMng/coSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/coSttn/page.tsx @@ -2,15 +2,15 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; +import { excelCoSttnParsing } from "@/app/store/matDmd/coSttn/excel"; import { fetchType, getFetch } from "@/components/lib/api"; import { excelDownload, formatPhoneNumber, getCity, - tableData + tableData, } from "@/components/lib/func/commom"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { ContentsDiv, SearchDiv, @@ -42,7 +42,6 @@ export default function CoSttn() { updateDemandCompany, coSttnTxtSearch, demandCompList, - dmdIsSucees } = useWrStore((state) => state); const [bdstTable, setBdstTable] = useState<DemandCompType[]>(); @@ -60,17 +59,21 @@ export default function CoSttn() { const [seartchTxt, setSearchTxt] = useState<string>(); const [upadateData, setUpdateData] = useState<DemandCompType>(); - - const getSelCity = useCallback((val: string | number) => { + + const getSelCity = useCallback( + (val: string | number) => { const cityValue = String(val); const data = getCity(cityValue, code.sggCd); setSelectSgg(data); // 시/도를 변경하면 시/군/구는 '전체'("0")로 초기화합니다. setObjSearch({ city: cityValue, sgg: "0" }); - }, [code.sggCd]); + }, + [code.sggCd] + ); const getSgg = useCallback((val: string | number) => { setObjSearch((prev) => ({ ...prev, sgg: String(val) })); + setPageNation(1); }, []); useEffect(() => { @@ -83,7 +86,7 @@ export default function CoSttn() { } } }, [code.cityCd, objSearch.city, getSelCity]); - + useEffect(() => { if (!coSttn.isInit) { coSttnInit("1", "13", "0"); @@ -91,15 +94,13 @@ export default function CoSttn() { }, [coSttn.isInit, coSttnInit]); useEffect(() => { - if(coSttnRes){ - + if (coSttnRes) { if (coSttnRes?.length > 0 && code.cityCd.length > 0) { const data = tableData(coSttnRes, { code }); const chData = data.map((item: any) => ({ ...item, - telno:formatPhoneNumber(item.telno||undefined), - regDt: moment(item.regDt).format("YYYY-MM-DD") - + telno: formatPhoneNumber(item.telno || undefined), + regDt: moment(item.regDt).format("YYYY-MM-DD"), })); // .filter((item: any) => item !== undefined); setBdstTable(chData); @@ -112,41 +113,46 @@ export default function CoSttn() { useEffect(() => { if (coSttn.excelList.length > 0) { if (coSttn.excelList.length === 0) return; - excelDownload( + + const coExcel = excelCoSttnParsing( coSttn.excelList, + code.cityCd, + code.sggCd + ); + excelDownload( + coExcel as [], "수요처 관리", "sample_coSttn.xlsx", - "A1:F1", + "A1:H1", 2 ); } - }, [coSttn.excelList]); - - useEffect(() => { - const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city ? objSearch.city : "0"; - if(con){ - coSttnSearch(String(pageNation), "13", String(con)); - } - }, [coSttnSearch, objSearch.city, objSearch.sgg, pageNation]); + }, [coSttn.excelList, code]); const excelClick = useCallback(() => { - const con = objSearch.sgg ? objSearch.sgg : objSearch.city; + const con = + objSearch.sgg && objSearch.sgg !== "0" ? objSearch.sgg : objSearch.city; + if (con) coSttnSearch("1", "10000", String(con)); }, [coSttnSearch, objSearch.city, objSearch.sgg]); - + // }, [excelDownload, bdstTable]); const searchClick = () => { - const con = (objSearch.sgg && objSearch.sgg !== "0") ? objSearch.sgg : objSearch.city; - + const con = + objSearch.sgg && objSearch.sgg !== "0" ? objSearch.sgg : objSearch.city; if (con) { if (seartchTxt && seartchTxt?.length > 0) { - - console.log(' seartchTxt ', seartchTxt) - coSttnTxtSearch("1", "13", String(con), seartchTxt ?? ""); + coSttnTxtSearch( + String(pageNation), + "13", + String(con), + seartchTxt ?? "" + ); } else { - coSttnSearch("1", "13", String(con)); + coSttnSearch(String(pageNation), "13", String(con)); } } }; + return ( <> <ContentsDiv> @@ -161,7 +167,10 @@ export default function CoSttn() { label="시도" selectClass={""} selectArray={code.cityCd || []} - onSelectValue={getSelCity} + onSelectValue={(val) => { + getSelCity(val); + setPageNation(1); + }} value={objSearch.city} /> <SelectBox @@ -191,7 +200,6 @@ export default function CoSttn() { size={"sm"} className={btnClass} onClick={() => { - setUpdateData(undefined); setIsDmdModal({ ...isDmdModal, isMoal: true }); }} @@ -204,11 +212,12 @@ export default function CoSttn() { onClick={() => { /* 저장 로직 */ if (!upadateData) { - toast.error("수요처 변경을 원하는 행을 선택해주세요") - }else{ + toast.error("수요처 변경을 원하는 행을 선택해주세요"); + } else { setIsDmdModal({ ...isDmdModal, - isMoal: true}) + isMoal: true, + }); } }} > @@ -233,21 +242,30 @@ export default function CoSttn() { headName={[]} tableData={bdstTable || []} headlist={coSttn.coSttHeadList} - pageSize={bdstTable?.length ? Math.ceil(bdstTable.length / 13) : 0} - total={ coSttnResCount || 0 } - cellClick={(index: number | undefined, headId: string) => { + pageSize={20} + total={coSttnResCount + 10 || 0} + cellClick={(index: number | undefined) => { setUpdateData(coSttnRes[index as number]); }} - onPageChange={setPageNation} + onPageChange={(page) => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + setPageNation(page); + coSttnSearch(String(page), "13", String(con)); + }} ></UiTable> </ListDiv> </div> </div> <UiModal - bodyClass={"w-[40vw] max-w-none h-[90vh]"} + bodyClass={ + "w-[40vw] max-w-none h-[80vh] " // +upadateData?.dmdInfoId?'h-[60vh]':'h-[90vh]' + } open={isDmdModal.isMoal} onOpenChange={() => { - setIsDmdModal({ isMoal: false, data: {} as DemandCompType }); + setIsDmdModal({ isMoal: false, data: {} as DemandCompType }); }} body={ <SdmInsertForm @@ -257,24 +275,38 @@ export default function CoSttn() { rtnValue={(searchText: string, pageCnt: number) => { getDemandCompList(searchText, pageCnt); }} - rtnInputData={ async(data) => { - if(upadateData?.dmdInfoPk){ - updateDemandCompany(data as DemandCompType) - }else{ - const dmd= await getFetch(fetchType.WR,`/reuseFc/request/${data.dmdInfoPk}`) - if(dmd) { - toast.error(`사업자번호 ${dmd.dmdInfoPk}는 이미 등록되었습니다. 다시등록해주세요`) - return - } - regDemandCompany(data as DemandCompType); + rtnInputData={async (data) => { + const con = + objSearch.sgg && objSearch.sgg !== "0" + ? objSearch.sgg + : objSearch.city; + console.log("data ", data); + if (upadateData?.dmdInfoId) { + console.log("data ", data); + await updateDemandCompany(data as DemandCompType); + coSttnInit("1", "13", String(con)); + setIsDmdModal({ + isMoal: false, + data: data as DemandCompType, + }); + } else { + const dmd = await getFetch( + fetchType.WR, + `/reuseFc/request/${data.dmdInfoId}` + ); + if (dmd) { + toast.error( + `사업자번호 ${dmd.dmdInfoId}는 이미 등록되었습니다. 다시등록해주세요` + ); + return; + } + await regDemandCompany(data as DemandCompType); + coSttnInit("1", "13", String(con)); + setIsDmdModal({ + isMoal: false, + data: data as DemandCompType, + }); } - if(dmdIsSucees ==='success'){ - toast.success(`수요처 등록 및 수정 완료되었습니다..`) - setIsDmdModal({ isMoal: false, data: data as DemandCompType }); - }else{ - toast.error(`수요처 등록 및 수정 에러입니다.`) - } - }} bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"} updateList={upadateData} diff --git a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx index 55dbeb454..4e51a1ed8 100644 --- a/apps/wr/app/matMng/coMng/drgtSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/drgtSttn/page.tsx @@ -24,12 +24,12 @@ export default function DrgtSttn() { const [excelData, setExcelData] = useState<any[]>(); const [drgtModal, setDrgtModal] = useState<{ isOpen: boolean; - data: customDrgt | undefined; + data: customDrgt[] | undefined; }>({ data: undefined, isOpen: false }); - const cellClick = (index: number | undefined, headId: string) => { - if (fromDate && toDate) { - drgtModalSearch(fromDate, toDate, drgtRes[index].sggNm); + const cellClick = (index: number) => { + if (fromDate && toDate && drgtRes[index]) { + drgtModalSearch(fromDate, toDate, drgtRes[index].sggNm ?? ''); } else { toast.error("조회기간을 선택해주세요."); } @@ -151,12 +151,12 @@ export default function DrgtSttn() { <div className="flex flex-row w-1/4"> <DateMonthPicker field={{ - value: fromDate, - onChange: (date: string) => { - const year = date.slice(0, 4); - let month = date.slice(4); - if (month.length < 2) { - month = month.padStart(2, "0"); + value: fromDate ?? "", + onChange: (date: string | undefined) => { + const year = date ? date.slice(0, 4) : ''; + let month = date?.slice(4); + if (month&&month?.length < 2) { + month = month?.padStart(2, "0"); } const formatted = `${year}${month}`; setFromDate(formatted); @@ -167,12 +167,12 @@ export default function DrgtSttn() { <span className="ml-2 text-center">~</span> <DateMonthPicker field={{ - value: toDate, - onChange: (date: string) => { - const year = date.slice(0, 4); - let month = date.slice(4); - if (month.length < 2) { - month = month.padStart(2, "0"); + value: toDate ?? "", + onChange: (date: string | undefined) => { + const year = date ? date.slice(0, 4) : ''; + let month = date?.slice(4); + if (month&&month.length < 2) { + month = month?.padStart(2, "0"); } const formatted = `${year}${month}`; setToDate(formatted); @@ -190,9 +190,9 @@ export default function DrgtSttn() { <div className="flex flex-row space-x-2 items-center"> <Button size={"sm"} - onClick={(e) => { - let sidoText = ''; - let sggText = []; + onClick={() => { + let sidoText: string = ''; + let sggText: string | string[] = ''; if (objSearch?.city.toString().length > 0) { sidoText = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? ''; @@ -210,7 +210,7 @@ export default function DrgtSttn() { sggText = sidoText; } - const searchArr = []; + const searchArr:string[] = []; if (sidoText) searchArr.push(sidoText); if (Array.isArray(sggText)) { searchArr.push(...sggText); @@ -252,8 +252,8 @@ export default function DrgtSttn() { headlist={drgtHeadListExport} pageSize={14} total={0} - cellClick={(index: number | undefined, headId: string) => { - cellClick(index ?? undefined, headId); + cellClick={(index: number | undefined) => { + cellClick(index ?? -1); }} onPageChange={() => { }} ></UiTable> @@ -267,7 +267,7 @@ export default function DrgtSttn() { setDrgtModal({ ...drgtModal, isOpen: !drgtModal.isOpen }); }} bodyClass={"w-[50vw] max-w-none h-[80vh]"} - body={<DrgtDetailModal data={drgtModal.data} />} + body={<DrgtDetailModal data={drgtModal.data as customDrgt[]} />} /> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx index eb43b29bf..763595ece 100644 --- a/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx +++ b/apps/wr/app/matMng/coMng/ldrmntCoSttn/page.tsx @@ -3,11 +3,11 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import { type customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; -import { ldrmntHeadListExport, ldrmntNodeListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; +import { ldrmntHeadListExport } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { + confirmToast, excelDownload, getCity, - getCityOrSgg, tableData } from "@/components/lib/func/commom"; import CoRegExcel from "@/components/ui/modal/coReg/coRegExcel/coRegExcelModal"; @@ -24,60 +24,83 @@ import { Title, UiModal, UiTable, - type ReturnType, type SelectDataType } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { Button } from "@common/components/ui"; -import { useCallback, useEffect, useRef, useState } from "react"; +import { useCallback, useEffect, useState } from "react"; +import { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function LdrmntCoSttn() { - const { code, ldrmnt, ldrmntInit, ldrmntSearch, } = useWrStore( + const { code, ldrmnt, ldrmntInit, ldrmntSearch, ldrmntUpdate } = useWrStore( (state) => state ); - const { ldrmntRes, excelList } = ldrmnt; + const { ldrmntRes, excelList, ldrmntResCount } = ldrmnt; const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customLdrmnt | undefined }>({ data: undefined, isOpen: false }) const [pageNation, setPageNation] = useState(1); const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [bdstTable, setBdstTable] = useState<customLdrmnt[]>(); const [searchTxt, setSearchTxt] = useState<string>(); - const ref = useRef<ReturnType>({} as ReturnType); const [excelData, setExcelData] = useState<any[]>(); - const [isExcelDownload, setIsExcelDownload] = useState(false); + const [resetPage, isResetPage] = useState(false); + const { t } = useTranslation('base'); + // const [isExcelDownload, setIsExcelDownload] = useState(false); const excelClick = useCallback(() => { excelDownload( [[]], - "잠재수요처 관리", + "잠재수요처 등록양식", "sample_ldrmntCoSttn.xlsx", "A1:AL1", 2 ); }, []); - const excelDownloadClick = () => { - ldrmntSearch(1, "10000", "0", ""); - setIsExcelDownload(true); - } + const computeCityNm = () => { + let cityTxt = ""; + let sggTxt = ""; + + if (objSearch.city) { + cityTxt = + code.cityCd.find((c) => c.val === objSearch.city)?.text || ""; + } + if (objSearch.sgg) { + sggTxt = + code.sggCd.find((s) => s.val === objSearch.sgg)?.text || ""; + } + + if (cityTxt === "" || cityTxt === "전체") cityTxt = "0"; + + return sggTxt && sggTxt !== "0" + ? `${cityTxt} ${sggTxt}` + : cityTxt; + }; + + const excelDownloadClick = useCallback(() => { + const cityNm = computeCityNm(); + ldrmntSearch(true, 1, String(ldrmntResCount), cityNm, searchTxt || ""); + // setIsExcelDownload(true); + }, [objSearch, searchTxt, code, ldrmntSearch, computeCityNm, ldrmntResCount]); useEffect(() => { - if (isExcelDownload && excelData && excelData.length > 0) { + if (/*isExcelDownload &&*/ excelData && excelData.length > 0) { downloadExcel({ data: excelData, fileName: "잠재수요처 관리", sheetNameArray: ["Sheet1"], headerRange: "A1:F1" }); - setIsExcelDownload(false); + // setIsExcelDownload(false); } - }, [excelData, isExcelDownload]); + }, [excelData, /*isExcelDownload*/]); const [isExcelOpen, setIsExcelOpen] = useState<{ isModal: boolean; }>({ isModal: false }); - const cellClick = (index: number | undefined, headId: string) => { + const cellClick = (index: number | undefined) => { if (index !== undefined) { setDetailModal({ isOpen: true, data: ldrmntRes[index] }); } @@ -92,7 +115,6 @@ export default function LdrmntCoSttn() { } else { const data = getCity(cityValue, code.sggCd); setSelectSgg(data); - const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); setObjSearch({ city: cityValue, sgg: firstSggVal }); } @@ -141,33 +163,8 @@ export default function LdrmntCoSttn() { }, [excelList]) useEffect(() => { - let cityTxt = '' - let sggTxt = '' - - if (objSearch?.city.toString().length > 0) { - cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? ''; - } - - if (objSearch?.sgg.toString().length > 1) { - sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? ''; - } - - if (cityTxt === '전체' || cityTxt === '') { - cityTxt = '0' - } - - let cityNm = "" - - if (sggTxt !== "0") { - cityNm = cityTxt + " " + sggTxt - } else { - cityNm = cityTxt - } - if (cityNm) { - ldrmntSearch(pageNation, '20', cityNm, searchTxt || ""); - } else { - ldrmntSearch(pageNation, '20', '0', searchTxt || ""); - } + ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || ""); + isResetPage(false) }, [pageNation]); return ( @@ -209,33 +206,9 @@ export default function LdrmntCoSttn() { <div className="flex flex-row space-x-2 items-center"> <Button size={"sm"} - onClick={(e) => { - - let cityTxt = '' - let sggTxt = '' - - if (objSearch?.city.toString().length > 0) { - cityTxt = code.cityCd.find((item) => item.val === objSearch?.city)?.text ?? ''; - } - - if (objSearch?.sgg.toString().length > 1) { - sggTxt = code.sggCd.find((item) => item.val === objSearch?.sgg)?.text ?? ''; - } - - if (cityTxt === '전체' || cityTxt === '') { - cityTxt = '0' - } - - let cityNm = "" - - if (sggTxt !== "0") { - cityNm = cityTxt + " " + sggTxt - } else { - cityNm = cityTxt - } - if (cityNm) { - ldrmntSearch(pageNation, '20', cityNm, searchTxt || ""); - } + onClick={() => { + ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || ""); + isResetPage(true) }} > 조회 @@ -273,13 +246,14 @@ export default function LdrmntCoSttn() { <div className="overflow-x-auto"> <ListDiv className="min-w-max"> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} headlist={ldrmntHeadListExport} pageSize={20} - total={10000} - cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }} + total={ldrmntResCount || 0} + cellClick={(index: number | undefined) => { cellClick(index ?? undefined) }} onPageChange={setPageNation} + resetPageNo={resetPage} /> </ListDiv> </div> @@ -290,7 +264,18 @@ export default function LdrmntCoSttn() { setDetailModal({ ...detailModal, isOpen: !detailModal.isOpen }) }} bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"} - body={<CoDetailModal formObj={detailModal.data} />} + body={<CoDetailModal formObj={detailModal.data} onFormSubmit={async (value) => { + // confirmToast(t('isUpdateMsg'), await ldrmntUpdate(value)) + // // await ldrmntUpdate(value) + // setDetailModal({ ...detailModal, isOpen: false }) + // ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || ""); + const handleConfirm = async () => { + await ldrmntUpdate(value); + setDetailModal({ ...detailModal, isOpen: false }); + ldrmntSearch(false, pageNation, '20', computeCityNm(), searchTxt || ""); + }; + confirmToast(t('isUpdateMsg'), handleConfirm); + }} />} /> <UiModal @@ -299,8 +284,9 @@ export default function LdrmntCoSttn() { setIsExcelOpen({ isModal: !isExcelOpen.isModal }) }} bodyClass={"w-[40vw] max-w-none"} - body={<CoRegExcel />} + body={<CoRegExcel isModal={(isOpen) => setIsExcelOpen({ isModal: isOpen })} />} /> + <Toaster position="top-center"></Toaster> </div> diff --git a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx index 9b3688e61..3bc6532a9 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/htdflReg/page.tsx @@ -1,6 +1,10 @@ "use client"; import { useWrStore } from "@/app/store"; +import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { tableData } from "@/components/lib/func/commom"; +import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; +import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { ContentsDiv, ScrollArea, @@ -12,21 +16,14 @@ import { UiModal, UiTable, } from "@common/business_components"; -import { Button } from "@common/components"; import ListDiv from "@common/business_components/ui/list_div"; +import { Button } from "@common/components"; import { useEffect, useState } from "react"; -import { tableData } from "@/components/lib/func/commom"; -import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; -import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; -import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { Toaster } from "react-hot-toast"; export default function Home() { - const { code, htdfl, initHtdflReg, getHtdflBdstData ,htdflNmSearch} = useWrStore( - (state) => state - ); + const { code, htdfl, initHtdflReg, getHtdflBdstData, htdflNmSearch } = + useWrStore((state) => state); const [searchTxt, setSearchTxt] = useState(""); const [pageNation, setPageNation] = useState(1); @@ -34,42 +31,41 @@ export default function Home() { const [bdstTable, setbdstTable] = useState<customHtdflBdst[]>(); const [issNewReg, setIsNewReg] = useState<boolean>(false); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chgBuilding: chgBuilding[]; - }>({ isOpen: false, chgBuilding: [] }); + // const [bdstChgProps, setBdstChgProps] = useState<{ + // isOpen: boolean; + // chgBuilding: chgBuilding[]; + // }>({ isOpen: false, chgBuilding: [] }); - const { htdflRes } = htdfl; + const { htdflRes ,htdflResCount} = htdfl; useEffect(() => { if (!htdfl.isInit) { - initHtdflReg('41') + initHtdflReg("0"); } }, [htdfl.isInit, initHtdflReg]); useEffect(() => { - if (htdflRes&&htdflRes.length>0) { - - console.log('htdflRes ', htdflRes) + if (htdflRes && htdflRes.length > 0) { const htdflData = tableData(htdflRes, { code }).map( (item: customHtdflBdst) => { - let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' + const archArea = + item?.archArea.split(".")[0] !== "-1" + ? item?.archArea.split(".")[0] + : "확인불가"; return { ...item, - archArea:archArea - + archArea: archArea, }; } ); setbdstTable(htdflData); - }else{ + } else { setbdstTable([]); } }, [code, htdflRes]); const cellClick: (val: number | undefined, headId: string) => void = ( - val, - headId + val ) => { if ((bdstTable ?? []).length > 0 && val !== undefined) { { @@ -78,7 +74,7 @@ export default function Home() { } // if (headId === "bdstChgYn" && val !== undefined) { // if ( - // htdflRes[val]?.bdstInfoPk != null && + // htdflRes[val]?.bdstInfoSn != null && // htdflRes[val]?.chgBuilding?.length > 0 // ) { // bdstChgModal(htdflRes[val]?.chgBuilding as chgBuilding[]); @@ -89,7 +85,7 @@ export default function Home() { // setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); // }; useEffect(() => { - getHtdflBdstData(pageNation, "41"); + getHtdflBdstData(pageNation, "0"); }, [pageNation]); return ( @@ -102,7 +98,7 @@ export default function Home() { <SearchFormLeft> <SearchInput className="col-span-3 my-7 !text-3xl" - label="건물명" + label="시설명" textValue={searchTxt || ""} setText={(e) => { setSearchTxt(e); @@ -114,11 +110,10 @@ export default function Home() { <Button size={"sm"} onClick={() => { - if(searchTxt&&searchTxt.length>0){ - htdflNmSearch(String(41),searchTxt) - }else{ - initHtdflReg(String(41) ); - + if (searchTxt && searchTxt.length > 0) { + htdflNmSearch(String(0), searchTxt); + } else { + initHtdflReg(String(0)); } }} > @@ -139,9 +134,9 @@ export default function Home() { <UiTable tableData={bdstTable || []} headlist={htdfl.upHeadList} - pageSize={100} - total={10} - headName={"건축물 목록"} + pageSize={20} + total={htdflResCount} + headName={"시설물 목록"} cellClick={(val, headId) => { cellClick(val || undefined, headId); }} @@ -175,17 +170,7 @@ export default function Home() { }} /> -<Toaster position="top-center" /> -{/* <UiModal - bodyClass={""} - open={bdstChgProps.isOpen} - body={ - <BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal> - } - onOpenChange={(open) => { - setBdstChgProps({ ...bdstChgProps, isOpen: open }); - }} - /> */} + <Toaster position="top-center" /> </ContentsDiv> </> ); diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx index 9f243627c..64b90c1fb 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/page.tsx @@ -14,7 +14,7 @@ import { useWrStore } from "../../../store"; import { Tabs, TabsList, TabsTrigger, TabsContent } from "@common/components"; import { useCallback, useEffect, useState } from "react"; import ListDiv from "@common/business_components/ui/list_div"; -import { tableData } from "@/components/lib/func/commom"; +import { confirmToast, tableData } from "@/components/lib/func/commom"; import type { customPbnst, fcBizType, @@ -24,7 +24,6 @@ import type { import { pbnstRegZod, pbnstRegArrayZod, - fcBizSchema, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm"; @@ -34,10 +33,8 @@ import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; import { useFieldArray, useForm, type FieldErrors } from "react-hook-form"; // FieldErrors 타입 추가 import { zodResolver } from "@hookform/resolvers/zod"; import { z } from "zod"; - import { createDefaultPbnstItem } from "./utilsZod"; - - +import { useTranslation } from "react-i18next"; export default function PublicReuseFaciltyInsert() { const { @@ -50,12 +47,13 @@ export default function PublicReuseFaciltyInsert() { pubHasuSearch, pbnstRuseBizUpdate, } = useWrStore((state) => state); - const { pubFacHeadList, pbnstHasuRes, pbnstRes } = pbnst; - const [currentTab, setCurrentTab] = useState<string>("mng"); + const { t } = useTranslation("base"); + const { pubFacHeadList, pbnstHasuResCount, pbnstHasuRes, pbnstRes } = pbnst; + const [, setCurrentTab] = useState<string>("mng"); const [isRuseReg, setIsRuseReg] = useState<{ isModal: boolean; }>({ isModal: false }); - + const [resetPage, isResetPage] = useState(false); const [indexMng, setIndexMng] = useState<number>(0); const [indexBiz, setIndexBiz] = useState<number>(0); const [searchTxt, setSearchTxt] = useState<string>(); @@ -89,18 +87,19 @@ export default function PublicReuseFaciltyInsert() { }, [pbnst.isInit, pubHasuInit]); const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { - if (!isDirty) { toast.error("변경사항이 없습니다."); // 변경사항이 없으면 메시지 표시 return; - } const data = writeRgtrAndMdfr(valuse.items); + } + const data = writeRgtrAndMdfr(valuse.items); let bizs = [] as fcBizType[]; data.forEach((fclt) => { bizs = [...bizs, ...fclt.fcBizs]; }); + const pbnst = data.map((fclt) => { return { - pbnstRuseFcltPk: fclt.pbnstRuseFcltPk, + pbnstRuseFcltId: fclt.pbnstRuseFcltId, fcltCpct: fclt.fcltCpct, ruseCpct: fclt.ruseCpct, splyExtraCpct: fclt.splyExtraCpct, @@ -110,63 +109,89 @@ export default function PublicReuseFaciltyInsert() { fcOpers: fclt.fcOpers, }; }); - await pbnstRuseFcltUpdate(pbnst as customPbnst[]) - await pbnstRuseBizUpdate(bizs); + const handleConfirm = async () => { + Promise.allSettled([ + pbnstRuseFcltUpdate(pbnst as customPbnst[]), + pbnstRuseBizUpdate(bizs), + ]).then(([resFclt, resBiz]) => { + const isFcltSuccess = resFclt.status === "fulfilled"; + const isBizSuccess = resBiz.status === "fulfilled"; + if (isFcltSuccess && isBizSuccess) { + toast.success("하수 재이용 시설 및 사업이 수정되었습니다. "); + // 메시지 표시, 페이지 이동 등 + } else { + let message = ""; + // ✅ 각각 어떤 항목이 실패했는지도 로그/알림 처리 + if (!isFcltSuccess) { + message = "하수재이용 시설 "; + } + if (!isBizSuccess) { + message += "하수재이용 시설 사업 "; + } + toast.error(message + "오류 입니다 "); + pubHasuInit("1", "41"); + } + }); + }; + confirmToast(t("isUpdatetMsg"), handleConfirm); }; // 폼 유효성 검사 실패 시 호출될 함수 - const onInvalid = (errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => { - console.log("errors:", errors); - + const onInvalid = ( + errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }> + ) => { const findAllErrors = ( errorObject: any, path: (string | number)[] = [] ): { message: string; path: (string | number)[] }[] => { if (!errorObject) return []; - + return Object.keys(errorObject).flatMap((key) => { const value = errorObject[key]; const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key; const newPath = [...path, currentKey]; - + if (value && typeof value === "object") { if (value.message) { return [{ message: value.message, path: newPath }]; } - + return findAllErrors(value, newPath); } return []; }); }; - + const errorList = findAllErrors(errors); - + if (errorList.length > 0) { errorList.forEach((errorInfo) => { const { message, path } = errorInfo; let prefix = ""; - + const itemsIndex = path.indexOf("items"); - + if (itemsIndex > -1 && path.length > itemsIndex + 1) { const itemIdx = path[itemsIndex + 1] as number; - const facilityName = form.getValues(`items.${itemIdx}.ruseUtztnFcltNm`); + const facilityName = form.getValues( + `items.${itemIdx}.ruseUtztnFcltNm` + ); if (facilityName) { prefix += `[${facilityName}] `; } - + const fcBizsIndex = path.indexOf("fcBizs"); if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) { const bizIdx = path[fcBizsIndex + 1] as number; - const cycle = form.getValues(`items.${itemIdx}.fcBizs.${bizIdx}.cycl`); + const cycle = form.getValues( + `items.${itemIdx}.fcBizs.${bizIdx}.cycl` + ); if (cycle) { prefix += `[${cycle}차수] `; } } } - // 최종 오류 메시지 출력 toast.error(`${prefix}${message}`); }); @@ -176,6 +201,10 @@ export default function PublicReuseFaciltyInsert() { console.log("form errors:", form.formState.errors); }, [form.formState.errors]); + useEffect(() => { + console.log("formState", items); + }, [items]); + useEffect(() => { if (code.sggCd.length && pbnstHasuRes.length > 0) { setbdstTable(tableData(pbnstHasuRes, { code })); @@ -197,17 +226,6 @@ export default function PublicReuseFaciltyInsert() { setCurrentTab(value); }; - useEffect(() => { - if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) { - - - - form.reset({ items: pbnst.pbnstRes }); - - } else { - form.reset({ items: [] }); - } - }, [pbnst.pbnstRes]); useEffect(() => { if (indexMng) { setIndexBiz(0); @@ -215,56 +233,33 @@ export default function PublicReuseFaciltyInsert() { }, [indexMng]); useEffect(() => { - console.log("form errors:", form.formState.errors); - }, [form.formState.errors]); + if (pbnst.pbnstRes && pbnst.pbnstRes?.length > 0) { + form.reset({ items: pbnst.pbnstRes }); + } else { + form.reset({ items: [] }); + } + }, [pbnst.pbnstRes]); const appendPbnstRuseFclt = useCallback(() => { - const selecTableRow = selectRow; if (pbnstRes && pbnstRes.length > 0) { - const lastPbnst = pbnstRes[pbnstRes.length - 1]; - if (lastPbnst && selecTableRow) { - // append( - // pbnstRegZod.parse({ - // pbnstRuseFcltPk: - // String(selecTableRow.bscFctCd) + String(pbnstRes.length + 1), - // ruseUtztnFcltNm: null, - // fcBizs: [ - // fcBizSchema.parse({ - // pbnstRuseFcltFk: - // String(lastPbnst.pbnstRuseFcltPk) + - // String(pbnstRes.length + 1), - // cycl: 1, - // }), - // ] as fcBizType[], - // }) - // ); - append(createDefaultPbnstItem(selecTableRow, pbnstRes.length)); - + if (selectRow) { + // pbnstRes.length를 사용하여 새로운 항목의 인덱스를 결정 + append(createDefaultPbnstItem(selectRow, pbnstRes.length)); setIsRuseReg({ isModal: true }); } } else { - if (selecTableRow) { - append( - pbnstRegZod.parse({ - pbnstRuseFcltPk: String(selecTableRow.bscFctCd) + "1", - ruseUtztnFcltNm: "", - regDt: null, - mdfcnDt: null, - fcBizs: [ - fcBizSchema.parse({ - pbnstRuseFcltFk: String(selecTableRow.bscFctCd) + "1", - cycl: 1, - }), - ] as fcBizType[], - }) - ); + if (selectRow) { + // pbnstRes가 비어있으면 첫 항목이므로 인덱스 0 + + append(createDefaultPbnstItem(selectRow, 0)); setIsRuseReg({ isModal: true }); } } - }, [pbnstRegZod, pbnstRes, append, selectRow, form]); + }, [pbnstRes, append, selectRow]); useEffect(() => { pubHasuInit(String(pageNation), "41"); + isResetPage(false); }, [pageNation, pubHasuInit]); return ( @@ -287,10 +282,13 @@ export default function PublicReuseFaciltyInsert() { <Button className="" size={"sm"} - onClick={(e) => { - searchTxt && searchTxt?.length > 0 - ? pubHasuSearch(String(pageNation), "41", searchTxt) - : pubHasuInit(String(pageNation), "41"); + onClick={() => { + if (searchTxt && searchTxt?.length > 0) { + pubHasuSearch(String(pageNation), "41", searchTxt); + } else { + pubHasuInit(String(pageNation), "41"); + } + isResetPage(true); }} > 조회 @@ -328,40 +326,39 @@ export default function PublicReuseFaciltyInsert() { tableData={bdstTable || []} headlist={pubFacHeadList} pageSize={10} - total={100000} - headName={"공공 하수처리시설 등록"} + total={pbnstHasuResCount || 20} + headName={"공공 하수처리시설 목록"} cellClick={cellClick} onPageChange={setPageNation} - children={undefined} + resetPageNo={resetPage} /> </ScrollArea> </ListDiv> </div> <ListDiv className="col-span-2 pr-6 "> - <ScrollArea className="h-[60vh]"> - {formWatch && formWatch[0]?.pbnstRuseFcltPk ? ( - <Tabs defaultValue="mng" onValueChange={handleTabChange}> - <TabsList className=""> - <TabsTrigger className="!text-xl" value="mng"> - 시설정보 - </TabsTrigger> - <TabsTrigger className="!text-xl" value="buse"> - 차수별정보 - </TabsTrigger> - <Button - size={"sm"} - onClick={form.handleSubmit(onSubmit, onInvalid)} - className="!justify-end" // 저장 버튼 위치 조정 - > - 저장 - </Button> - </TabsList> + {formWatch && formWatch[0]?.pbnstRuseFcltId ? ( + <Tabs defaultValue="mng" onValueChange={handleTabChange}> + <TabsList className=""> + <TabsTrigger className="!text-xl" value="mng"> + 시설정보 + </TabsTrigger> + <TabsTrigger className="!text-xl" value="buse"> + 차수별정보 + </TabsTrigger> + <Button + size={"sm"} + onClick={form.handleSubmit(onSubmit, onInvalid)} + className="!justify-end" // 저장 버튼 위치 조정 + > + 저장 + </Button> + </TabsList> + <ScrollArea className="h-[60vh]"> <TabsContent className="max-h-full" value="mng"> <PbnstMngForm formType="update" form={form} setIndexMng={(index: number) => { - console.log("setIndexMng", index); setIndexMng(index); }} indexMng={indexMng} @@ -378,17 +375,18 @@ export default function PublicReuseFaciltyInsert() { indexBiz={indexBiz} /> </TabsContent> - </Tabs> - ) : ( - <> + </ScrollArea> + </Tabs> + ) : ( + <> <div className="card-header text-2xl"> - 등록된 재이용시설 정보가 없습니다. + 등록된 재이용시설 정보가 없습니다. </div> - <div className="!mx-[1.6rem] !p-0r flex flex-col items-center justify-center h-64 border rounded-md"> - <p className="text-3xl mb-4"> - 신규등록 버튼을 클릭하여 재이용시설을 등록해주세요. - </p> - <Button + <div className="!mx-[1.6rem] !p-0r flex flex-col items-center justify-center h-64 border rounded-md"> + <p className="text-3xl mb-4"> + 신규등록 버튼을 클릭하여 재이용시설을 등록해주세요. + </p> + <Button size={"sm"} className="" onClick={() => { @@ -405,11 +403,9 @@ export default function PublicReuseFaciltyInsert() { > 신규등록 </Button> - </div> - </> - - )} - </ScrollArea> + </div> + </> + )} </ListDiv> <UiModal body={ @@ -421,8 +417,7 @@ export default function PublicReuseFaciltyInsert() { setIsRuseReg({ isModal: false }); } }} - - onInvalid ={onInvalid} + onInvalid={onInvalid} ></PbnstRegModal> } bodyClass="w-[68vw] max-w-none h-[90vh]" diff --git a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx index 3433a62c5..f61697e7e 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/pbnstReg/utilsZod.tsx @@ -1,37 +1,46 @@ -import type { fcBizType, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +import type { fcBizType, operType, pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -export function createDefaultPbnstItem( - selecTableRow: pubHasuType, - index: number - ) { - const pk = String(selecTableRow.bscFctCd) + String(index + 1); - +export function createDefaultPbnstItem(row: pubHasuType, index: number) { + const pk = row.bscFctCd + String(index + 1); + + return JSON.parse(JSON.stringify({ + pbnstRuseFcltId: pk, + swtrmtFcltId: "", + ruseUtztnFcltNm: "", + fcltCpct: 0, + ruseCpct: 0, + splyExtraCpct: 0, + regDt: null, + rgtr: "", + mdfcnDt: null, + mdfr: "", + fcFiles: [], + fcBizs: [createDefaultBiz(pk, 1)], + fcOpers: [], // 빈 배열 강제 + })); +} + + + export function createDefaultOper(pbnstRuseFcltId: string): operType { return { - pbnstRuseFcltPk: pk, - swtrmtFcltFk: "", - ruseUtztnFcltNm: "", // 필수 입력이므로 빈 문자열로 - fcltCpct: 0, - ruseCpct: 0, - splyExtraCpct: 0, - regDt: null, - rgtr: "test", - mdfcnDt: null, - mdfr: "test", - fcFiles: [], - fcBizs: [ - createDefaultBiz(pk, 1), // 첫 차수 - ], - fcOpers: [], - }; + pbnstRuseFcltId, + operMthd: "", + rprtvBzenty: "", + bgngDt: new Date(), + endDt: new Date(), + choose: false, + rgtr: "", + mdfr: "", + } as operType; } export function createDefaultBiz( - pbnstRuseFcltFk: string, + pbnstRuseFcltId: string, cycl: number ): fcBizType { return { - pbnstRuseFcltFk, + pbnstRuseFcltId, cycl, // 필요한 값 있으면 여기에 추가 } as fcBizType; diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx index 8ecc1221f..828129bf6 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rainReg/page.tsx @@ -1,12 +1,10 @@ "use client"; import { useWrStore } from "@/app/store"; import { - type chgBuilding, type customRainBdst, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { tableData } from "@/components/lib/func/commom"; import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm"; -import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { ContentsDiv, @@ -29,16 +27,12 @@ export default function Home() { return state; } ); - const { rainRes } = rain; + const { rainRes, rainResCount } = rain; const [rainForm, setRainForm] = useState<customRainBdst>(); const [issNewReg, setIsNewReg] = useState<boolean>(false); const [pageNation, setPageNation] = useState(1); const [bdstTable, setbdstTable] = useState<customRainBdst[]>(); const [searchTxt, setSearchTxt] = useState<string>(); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chgBuilding: chgBuilding[]; - }>({ isOpen: false, chgBuilding: [] }); useEffect(() => { setIsNewReg(false); @@ -49,41 +43,34 @@ export default function Home() { useEffect(() => { if (code.sggCd.length > 0) { - const rainData = tableData(rainRes, { code }).map( - (item: customRainBdst) => { - let archArea = item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' - return { - ...item, - archArea:archArea, - - bdstChgYn: item.chgBuilding.length > 0 ? "Y" : "N", - }; - } - ); + if (rainRes && rainRes.length > 0) { + const rainData = tableData(rainRes, { code }).map( + (item: customRainBdst) => { + const archArea = + item?.archArea.split(".")[0] !== "-1" + ? item?.archArea.split(".")[0] + : "확인불가"; + return { + ...item, + archArea: archArea, - setbdstTable(rainData); + }; + } + ); + + setbdstTable(rainData); + } else { + setbdstTable([]); + } } }, [code, rainRes]); - const cellClick: (val: number | undefined, headId: string) => void = ( - val, - headId + const cellClick: (val: number | undefined) => void = ( + val ) => { if (val !== undefined) { setRainForm(rainRes[val]); } - if (headId === "bdstChgYn" && val !== undefined) { - if ( - rainRes[val]?.bdstInfoPk != null && - rainRes[val]?.chgBuilding.length > 0 - ) { - bdstChgModal(rainRes[val].chgBuilding); - } - } - }; - - const bdstChgModal = (chgBuilding: chgBuilding[]) => { - setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); }; useEffect(() => { @@ -110,8 +97,9 @@ export default function Home() { <Button className="" size={"sm"} - onClick={(e) => { - rainSearch(searchTxt || "", pageNation, "41"); + onClick={() => { + rainSearch(searchTxt || "", 1, "41"); + //rainSearch(searchTxt || "", pageNation, "41"); }} > 조회 @@ -139,10 +127,10 @@ export default function Home() { tableData={bdstTable || []} headlist={rain.upHeadList} pageSize={20} - total={10000} + total={rainResCount} headName={"건축물 목록"} - cellClick={(val, headId) => { - cellClick(val, headId); + cellClick={(val) => { + cellClick(val); }} onPageChange={setPageNation} ></UiTable> @@ -175,17 +163,6 @@ export default function Home() { }} /> - <UiModal - bodyClass={""} - open={bdstChgProps.isOpen} - body={ - <BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal> - } - onOpenChange={(open) => { - setBdstChgProps({ ...bdstChgProps, isOpen: open }); - }} - /> - <Toaster position="top-center" /> </ContentsDiv> </> diff --git a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx index 94224d40d..6945788c4 100644 --- a/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltReg/rswtReg/page.tsx @@ -1,10 +1,8 @@ "use client"; import { useWrStore } from "@/app/store"; -import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { tableData } from "@/components/lib/func/commom"; import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm"; -import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; import { BdstReg } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { ContentsDiv, @@ -32,59 +30,57 @@ export default function Home() { const [pageNation, setPageNation] = useState(1); const [selectVal, setSelect] = useState<number>(); const [bdstTable, setbdstTable] = useState<customRswtBdst[]>(); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chgBuilding: chgBuilding[]; - }>({ isOpen: false, chgBuilding: [] }); - const { rswtRes } = rswt; + const { rswtRes, rswtResCount } = rswt; useEffect(() => { if (!rswt.isInit) { initRswt("41"); } }, [rswt.isInit, initRswt]); useEffect(() => { - if (code.sggCd.length > 0 && rswtRes?.length > 0) { - const rswtData = tableData(rswtRes, { code })?.map( - (item: customRswtBdst) => { - let archArea = - item?.archArea.split(".")[0] !== "-1" - ? item?.archArea.split(".")[0] - : "확인불가"; - return { - ...item, - archArea: archArea, - bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N", - bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd, - }; - } - ); - setbdstTable(rswtData); + if (code.sggCd.length > 0) { + + if (rswtRes?.length > 0) { + const rswtData = tableData(rswtRes, { code })?.map( + (item: customRswtBdst) => { + const archArea = + item?.archArea.split(".")[0] !== "-1" + ? item?.archArea.split(".")[0] + : "확인불가"; + return { + ...item, + archArea: archArea, + bdstChgYn: item.chgBuilding[0]?.bdstChgNm != null ? "Y" : "N", + bdstUsgCd: item.reuseBuilding[0]?.bdstUsgCd, + }; + } + ); + setbdstTable(rswtData); + setRswtForm(rswtRes[selectVal ?? 0]); + } else { + setbdstTable([]); + setRswtForm({} as customRswtBdst); + } + } + // }, [code, rswtRes, selectVal]); + + }, [code, rswtRes]); + useEffect(() => { + if (rswtRes && rswtRes.length > 0) { setRswtForm(rswtRes[selectVal ?? 0]); } - }, [code, rswtRes, selectVal]); + }, [rswtRes, selectVal]); + const cellClick: (val: number | undefined, headId: string) => void = ( - val, - headId + val ) => { if ((bdstTable ?? []).length > 0 && val !== undefined) { { setSelect(val); - setRswtForm(rswtRes[val]); } } - if (headId === "bdstChgYn" && val !== undefined) { - if ( - rswtRes[val]?.bdstInfoPk != null && - rswtRes[val]?.chgBuilding?.length > 0 - ) { - bdstChgModal(rswtRes[val].chgBuilding); - } - } - }; - const bdstChgModal = (chgBuilding: chgBuilding[]) => { - setBdstChgProps({ isOpen: true, chgBuilding: chgBuilding }); }; + useEffect(() => { getRswtBdstData(pageNation, "41"); }, [pageNation]); @@ -111,7 +107,7 @@ export default function Home() { <Button size={"sm"} className="mr-4 " - onClick={(e) => { + onClick={() => { rswtBdstSearch(searchTxt || "", pageNation, "41"); }} > @@ -137,7 +133,7 @@ export default function Home() { tableData={bdstTable || []} headlist={rswt.upHeadList} pageSize={20} - total={10000} + total={rswtResCount} headName={"건축물 목록"} cellClick={cellClick} onPageChange={setPageNation} @@ -170,16 +166,6 @@ export default function Home() { setIsNewReg(open); }} /> - <UiModal - bodyClass={""} - open={bdstChgProps.isOpen} - body={ - <BdstChgModal chgBuilding={bdstChgProps.chgBuilding}></BdstChgModal> - } - onOpenChange={(open) => { - setBdstChgProps({ ...bdstChgProps, isOpen: open }); - }} - /> <Toaster position="top-center" /> </ContentsDiv> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx index 959367202..147b9a674 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/htdflSttn/page.tsx @@ -3,20 +3,18 @@ import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; import type { - chgBuilding, - customRainBdst, + customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { excelDownload, getCity, - getCityOrSgg, - tableData, + tableData } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { ContentsDiv, - SearchBaseForm, SearchDiv, SearchFormLeft, SearchFormRight, @@ -25,26 +23,26 @@ import { Title, UiModal, UiTable, - type ReturnType, - type SelectDataType, + type SelectDataType } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; -import { excelHtdflSttnParsing } from "@/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function HtdflSttn() { const { code, htdflSttn, htdflSttnSearch, initHtdfl } = useWrStore( (state) => state ); - const { htdflSttnRes } = htdflSttn; - - const ref = useRef<ReturnType>({} as ReturnType); + const { htdflSttnRes, htdflSttnResCount } = htdflSttn; + const isDownloadTriggered = useRef(false); + const { t } = useTranslation('base'); const [pageNation, setPageNation] = useState(1); const [isChHead, setIsChHead] = useState(false); + const [resetPage, isResetPage] = useState(false); const [bdstTable, setBdstTable] = useState<customRainBdst[]>(); const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); @@ -52,20 +50,15 @@ export default function HtdflSttn() { isOpen: boolean; data: customRainBdst | undefined; }>({ data: undefined, isOpen: false }); - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chBuilding: chgBuilding[]; - }>({ isOpen: false, chBuilding: [] }); + // const [bdstChgProps, setBdstChgProps] = useState<{ + // isOpen: boolean; + // chBuilding: chgBuilding[]; + // }>({ isOpen: false, chBuilding: [] }); const [fcltNm, setFcltNm] = useState<string>(""); - const excelClick = useCallback(() => { - // 최신 검색 조건 반영 - const con = getConValue(); - htdflSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); - }, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd]); - useEffect(() => { - htdflSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + htdflSttnSearch(false, pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + isResetPage(false) }, [pageNation]); const getSelCity = (val: string | number) => { @@ -106,21 +99,32 @@ export default function HtdflSttn() { setDetailModal({ isOpen: true, data: bdstTable[index] }); } }; + + const excelClick = useCallback(() => { + isDownloadTriggered.current = true; + htdflSttnSearch(true, 1, String(htdflSttnResCount), String(getConValue()), fcltNm, code.cityCd, code.sggCd); + }, [htdflSttnSearch, objSearch, code.cityCd, code.sggCd, fcltNm, htdflSttnResCount]); + useEffect(() => { + if (!isDownloadTriggered.current) { + return; + } if (htdflSttn.excelList.length > 0) { - if (htdflSttn.excelList.length === 0) return; excelDownload( htdflSttn.excelList, "온배수시설 현황", "sample_htdflSttn.xlsx", - "A1:S3" + "A1:R3" ); + } else { + toast.error(t('excelDownErrMsg')); } + isDownloadTriggered.current = false; }, [htdflSttn.excelList, code]); useEffect(() => { if (!htdflSttn.isInit) { - initHtdfl(1, "20", "0", fcltNm, code.cityCd, code.sggCd); + initHtdfl(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [htdflSttn.isInit, initHtdfl]); @@ -181,8 +185,8 @@ export default function HtdflSttn() { <Button size={"sm"} onClick={() => { - const con = getConValue(); - htdflSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + htdflSttnSearch(false, 1, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + isResetPage(true) }} > 조회 @@ -214,17 +218,17 @@ export default function HtdflSttn() { <UiTable headName={undefined} tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> - } headlist={htdflSttn.htdflSttHeadList} pageSize={20} - total={100000} + total={htdflSttnResCount || 0} cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId); }} onPageChange={setPageNation} - ></UiTable> + resetPageNo={resetPage} + > + <HeadMakeColSpan upHeadList={htdflSttn.htdflSttNodeList} /> + </UiTable> </ListDiv> </div> </div> @@ -253,6 +257,7 @@ export default function HtdflSttn() { body={<SttnDetailModal type={"HTB"} formObj={detailModal.data} />} /> </ContentsDiv> + <Toaster position="top-center" /> </> ); } diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx index 7a7a125d2..38a3c15ca 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/pbnstSttn/page.tsx @@ -18,7 +18,6 @@ import { useCallback, useEffect, useRef, useState } from "react"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import type { customPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { excelDownload, yearOptions } from "@/components/lib/func/commom"; -import SearchInputText from "@/components/ui/searchInput/searchInput"; import type { WaterReuseFacility } from "@/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type"; import { PbnstSttnModal } from "@/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal"; @@ -29,9 +28,10 @@ export default function PbnstSttn() { pbnstSttnSearch, pbnSttnInit, getPbnStnDetail, - pbnNmSearch, + getFlcts, } = useWrStore((state) => state); + const { pbnstSttnRes, fclts, pbnstSttnResCount } = pbnstSttn; const ref = useRef<ReturnType>({} as ReturnType); const [searchYear, setSearchYear] = useState<string>( String(new Date().getFullYear()) @@ -46,21 +46,25 @@ export default function PbnstSttn() { const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); const excelClick = useCallback(() => { - pbnstSttnSearch("1", "10000", ref.current, "", searchYear); - }, [pbnstSttnSearch, searchYear, ref.current]); + pbnstSttnSearch( + true, + String(1), + "100000", + ref.current, + pbnRuseNm, + searchYear, + fclts + ); + }, [pbnstSttnSearch, fclts, pbnRuseNm]); const cellCLick = useCallback( (index: number | undefined) => { - if ( - index !== undefined && - pbnstSttn.pbnstSttnRes && - pbnstSttn.pbnstSttnRes[index] - ) { - const pbnstRuseFcltPk = pbnstSttn.pbnstSttnRes[index].pbnstRuseFcltPk; - getPbnStnDetail(pbnstRuseFcltPk); + if (index !== undefined && pbnstSttnRes && pbnstSttnRes[index]) { + const pbnstRuseFcltId = pbnstSttnRes[index].pbnstRuseFcltId; + getPbnStnDetail(pbnstRuseFcltId); } }, - [getPbnStnDetail, pbnstSttn.pbnstSttnRes] + [getPbnStnDetail, pbnstSttnRes] ); useEffect(() => { @@ -69,30 +73,30 @@ export default function PbnstSttn() { pbnstSttn.excelList, "하수재이용시설 현황", "sample_pbnstSttn.xlsx", - "A1:U2" + "A1:U2", + 3 ); } }, [pbnstSttn.excelList]); useEffect(() => { if (!pbnstSttn.isInit) { - pbnSttnInit("1", "13", ref.current, searchYear); + getFlcts(); } }, [pbnstSttn.isInit, pbnSttnInit, ref.current]); useEffect(() => { - setBdstTable(pbnstSttn.pbnstSttnRes); - }, [pbnstSttn.pbnstSttnRes]); - - // useEffect(() => { - // pbnstSttnSearch("1", "20", ref.current, pbnRuseNm, searchYear); - // }, [pageNation, ref.current, pbnRuseNm, searchYear, pbnstSttnSearch]); - - // useEffect(() => { - // if (pbnRuseNm.length > 1) - // pbnNmSearch(String(pageNation), "23", ref.current, pbnRuseNm, searchYear); - // }, [pbnRuseNm,pageNation]); + if (pbnstSttnRes && pbnstSttnRes.length > 0) { + setBdstTable(pbnstSttnRes); + } else { + setBdstTable([]); + } + }, [pbnstSttnRes]); useEffect(() => { - if (pbnstSttn.pbnstDetail.pbnstRuseFcltPk) + pbnSttnInit("1", "15", ref.current, searchYear, pbnstSttn.fclts); + }, [fclts]); + + useEffect(() => { + if (pbnstSttn.pbnstDetail.pbnstRuseFcltId) setPbnDetaileData({ isModal: true, data: pbnstSttn.pbnstDetail, @@ -127,34 +131,44 @@ export default function PbnstSttn() { } leftChildren={ <div className="col-span-3 flex items-center"> - <SelectBox - className="w-48 h-full text-2xl" - label="연도" - selectClass={"w-full "} - selectArray={yearOptions} - value={searchYear} - onSelectValue={(val: string | number) => - setSearchYear(String(val)) - } - /> - <Label className="w-64 mt-2 mx-4 text-xl text-gray-600"> - {"하수처리시설명 "} - </Label> - <SearchInput - className={"text-2xl w-full ㅍ"} - label="" - textValue={pbnRuseNm || ""} - setText={(e) => { - setPbnRuseNm(e || ""); - }} - /> - </div> + <SelectBox + className="w-48 h-full text-2xl" + label="연도" + selectClass={"w-full "} + selectArray={yearOptions} + value={searchYear} + onSelectValue={(val: string | number) => + setSearchYear(String(val)) + } + /> + <Label className="w-64 mt-2 mx-4 text-xl text-gray-600"> + {"하수처리시설명 "} + </Label> + <SearchInput + className={"text-2xl w-full ㅍ"} + label="" + textValue={pbnRuseNm || ""} + setText={(e) => { + setPbnRuseNm(e || ""); + }} + /> + </div> } queryClick={function (returnType: ReturnType): void { - pbnstSttnSearch("1", "20", returnType, pbnRuseNm, searchYear); + pbnstSttnSearch( + false, + "1", + "15", + returnType, + pbnRuseNm, + searchYear, + fclts + ); }} excelClick={excelClick} - initClick={function (): void {}} + initClick={function (): void { + setPbnRuseNm(""); + }} btnClass={btnClass} ref={ref} isAdmin={false} @@ -165,27 +179,28 @@ export default function PbnstSttn() { <div className="col-span-6"> <ListDiv> <UiTable - headName={[]} + headName={undefined} tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> - } headlist={pbnstSttn.pbnstSttHeadList} - pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { + pageSize={15} + total={pbnstSttnResCount} + cellClick={(index: number | undefined) => { cellCLick(index); }} onPageChange={(page: number) => { pbnstSttnSearch( + false, String(page), - String(13), + String(15), ref.current, pbnRuseNm, - searchYear + searchYear, + fclts ); }} - ></UiTable> + > + <HeadMakeColSpan upHeadList={pbnstSttn.pbnstSttNodeList} /> + </UiTable> </ListDiv> </div> </div> @@ -214,7 +229,9 @@ export default function PbnstSttn() { bodyClass="w-[68vw] max-w-none h-[90vh]" open={pbnDetaileData.isModal} onOpenChange={(open) => { - setPbnDetaileData({ data: {} as customPbnst, isModal: false }); + //TODO:OPEN 상태 확인필요 + if(!open) + setPbnDetaileData({ data: {} as customPbnst, isModal: open }); }} /> </ContentsDiv> diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx index 0b6dffe07..be2f82319 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rainSttn/page.tsx @@ -1,17 +1,19 @@ -/* eslint-disable @typescript-eslint/no-explicit-any */ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; +import type { + customRainBdst, +} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { excelDownload, getCity, - getCityOrSgg, tableData, } from "@/components/lib/func/commom"; +import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; +import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { ContentsDiv, - SearchBaseForm, SearchDiv, SearchFormLeft, SearchFormRight, @@ -20,68 +22,61 @@ import { Title, UiModal, UiTable, - type ReturnType, type SelectDataType, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; +import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; -import type { - chgBuilding, - customRainBdst, -} from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; -import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; -import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; +import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function RainSttn() { const { code, rainSttn, rainSttnSearch, rainSttnInit } = useWrStore( (state) => state ); - const { rainSttnRes } = rainSttn; - const ref = useRef<ReturnType>({} as ReturnType); + const { rainSttnRes, rainSttnResCount } = rainSttn; const [pageNation, setPageNation] = useState(1); const [isChHead, setIsChHead] = useState(false); const [bdstTable, setBdstTable] = useState<customRainBdst[]>(); - const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() - const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); - const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRainBdst | undefined }>({ data: undefined, isOpen: false }) - const [bdstChgProps, setBdstChgProps] = useState<{ + const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>(); + const [resetPage, isResetPage] = useState(false); + const isDownloadTriggered = useRef(false); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + const [detailModal, setDetailModal] = useState<{ isOpen: boolean; - chBuilding: chgBuilding[]; - }>({ isOpen: false, chBuilding: [] }); + data: customRainBdst | undefined; + }>({ data: undefined, isOpen: false }); + const [fcltNm, setFcltNm] = useState<string>(""); + const { t } = useTranslation("base"); - const cellClick = (index: number | undefined, headId: string) => { - - if (headId !== 'chBuildingYn' && index !== undefined && bdstTable !== undefined) { - setDetailModal({ isOpen: true, data: bdstTable[index] }) - } else if (headId === 'chBuildingYn' && index !== undefined && bdstTable !== undefined) { - if (bdstTable[index] && bdstTable[index]?.chgBuilding[0]?.bdstChgNm !== null) { - setBdstChgProps({ isOpen: true, chBuilding: bdstTable[index].chgBuilding }); - } + const cellClick = (index: number | undefined) => { + if (index !== undefined && bdstTable !== undefined) { + setDetailModal({ isOpen: true, data: bdstTable[index] }); } }; const getSelCity = (val: string | number) => { const cityValue = String(val); - if (cityValue === "0") { setSelectSgg([]); setObjSearch({ city: cityValue, sgg: "" }); } else { const data = getCity(cityValue, code.sggCd); setSelectSgg(data); - - const firstSggVal = data.find(item => item.val === "0")?.val || (data[0]?.val ?? ""); + const firstSggVal = + data.find((item) => item.val === "0")?.val || (data[0]?.val ?? ""); setObjSearch({ city: cityValue, sgg: firstSggVal }); } }; const getSgg = (val: string | number) => { - setObjSearch({ ...objSearch, sgg: String(val) }) + setObjSearch({ ...objSearch, sgg: String(val) }); }; const getConValue = () => { @@ -96,7 +91,7 @@ export default function RainSttn() { useEffect(() => { if (!rainSttn.isInit) { - rainSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd); + rainSttnInit(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [rainSttn.isInit, rainSttnInit]); @@ -108,50 +103,84 @@ export default function RainSttn() { ...item, ...item.reuseBuilding[0], ...item.reuseBuilding[0].rainyObj, - dtfcltCpct: item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.dtfcltCpct, - instlCst: item.reuseBuilding[0].instlCst === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCst, - instlCstSprtAmt: item.reuseBuilding[0].instlCstSprtAmt === -1 - ? "확인불가" - : item.reuseBuilding[0].instlCstSprtAmt, + dtfcltCpct: + item.reuseBuilding[0].rainyObj.dtfcltCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.dtfcltCpct, + instlCst: + item.reuseBuilding[0].instlCst === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCst, + instlCstSprtAmt: + item.reuseBuilding[0].instlCstSprtAmt === -1 + ? "확인불가" + : item.reuseBuilding[0].instlCstSprtAmt, chBuildingYn: item.chgBuilding[0]?.bdstChgNm !== null ? "Y" : "N", - pntfColArea: item.reuseBuilding[0].rainyObj.pntfColArea === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.pntfColArea, - filtrTrtmfctCpct: item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 - ? "확인불가" - : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, - archArea: Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, + pntfColArea: + item.reuseBuilding[0].rainyObj.pntfColArea === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.pntfColArea, + filtrTrtmfctCpct: + item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct === -1 + ? "확인불가" + : item.reuseBuilding[0].rainyObj.filtrTrtmfctCpct, + archArea: + Math.floor(item.archArea) === -1 ? "확인불가" : item.archArea, }; }) .filter((item: any) => item.rainyObj !== undefined); setBdstTable(chData); - }, [code, rainSttnRes, rainSttn.rainSttHeadList]); + }, [code, rainSttnRes]); useEffect(() => { - rainSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + rainSttnSearch( + false, + pageNation, + "20", + String(getConValue()), + fcltNm, + code.cityCd, + code.sggCd + ); + isResetPage(false); }, [pageNation]); useEffect(() => { + if (!isDownloadTriggered.current) { + return; + } if (rainSttn.excelList.length > 0) { - if (rainSttn.excelList.length === 0) return; excelDownload( rainSttn.excelList, "빗물재이용시설 현황", "sample_rainSttn.xlsx", "A1:W3" ); + } else { + toast.error(t("excelDownErrMsg")); } + isDownloadTriggered.current = false; }, [rainSttn.excelList]); const excelClick = useCallback(() => { - // 최신 검색 조건 반영 - const con = getConValue(); - rainSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); - }, [rainSttnSearch, objSearch, code.cityCd, code.sggCd]); + isDownloadTriggered.current = true; + rainSttnSearch( + true, + 1, + String(rainSttnResCount), + String(getConValue()), + fcltNm, + code.cityCd, + code.sggCd + ); + }, [ + rainSttnSearch, + objSearch, + code.cityCd, + code.sggCd, + fcltNm, + rainSttnResCount, + ]); return ( <> @@ -190,14 +219,21 @@ export default function RainSttn() { </div> </div> </SearchFormLeft> - <SearchFormRight - className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> + <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> <div className="flex flex-row space-x-2 items-center"> <Button size={"sm"} onClick={() => { - const con = getConValue(); - rainSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + rainSttnSearch( + false, + 1, + "20", + String(getConValue()), + fcltNm, + code.cityCd, + code.sggCd + ); + isResetPage(true); }} > 조회 @@ -229,15 +265,17 @@ export default function RainSttn() { <UiTable headName={undefined} tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> - } headlist={rainSttn.rainSttHeadList} pageSize={20} - total={100000} - cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }} + total={rainSttnResCount || 0} + cellClick={(index: number | undefined) => { + cellClick(index ?? undefined); + }} onPageChange={setPageNation} - ></UiTable> + resetPageNo={resetPage} + > + <HeadMakeColSpan upHeadList={rainSttn.rainSttNodeList} /> + </UiTable> </ListDiv> </div> </div> @@ -265,17 +303,8 @@ export default function RainSttn() { bodyClass={"w-[40vw] max-w-none max-h-[calc(100%-70px)]"} body={<SttnDetailModal type={"RNB"} formObj={detailModal.data} />} /> - <UiModal - bodyClass={""} - open={bdstChgProps.isOpen} - body={ - <BdstChgModal chgBuilding={bdstChgProps.chBuilding}></BdstChgModal> - } - onOpenChange={(open) => { - setBdstChgProps({ ...bdstChgProps, isOpen: open }); - }} - /> </ContentsDiv> + <Toaster position="top-center" /> </> ); } diff --git a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx index ee7a344f8..e8b845077 100644 --- a/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/fcltSttn/rswtSttn/page.tsx @@ -1,21 +1,17 @@ "use client"; import { useWrStore } from "@/app/store"; import { btnClass } from "@/app/store/common/code"; -import type { chgBuilding } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { excelDownload, getCity, - getCityOrSgg, - tableData, + tableData } from "@/components/lib/func/commom"; -import BdstChgModal from "@/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal"; import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import HeadChModal from "@/components/ui/modal/sttn/headChModal/headChModal"; import SttnDetailModal from "@/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal"; import { ContentsDiv, - SearchBaseForm, SearchDiv, SearchFormLeft, SearchFormRight, @@ -24,13 +20,14 @@ import { Title, UiModal, UiTable, - type ReturnType, - type SelectDataType, + type SelectDataType } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; +import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function RswtSttn() { const { code, rswtSttn, rswtSttnSearch, rswtSttnInit } = useWrStore( @@ -38,31 +35,21 @@ export default function RswtSttn() { ); const [pageNation, setPageNation] = useState(1); - const { rswtSttnRes } = rswtSttn; + const { rswtSttnRes, rswtSttnResCount } = rswtSttn; const [isChHead, setIsChHead] = useState(false); - const ref = useRef<ReturnType>({} as ReturnType); + const [resetPage, isResetPage] = useState(false); const [bdstTable, setBdstTable] = useState<customRswtBdst[]>(); + const isDownloadTriggered = useRef(false); const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() const [objSearch, setObjSearch] = useState<objSearchType>({ sgg: "", city: "" }); const [detailModal, setDetailModal] = useState<{ isOpen: boolean, data: customRswtBdst | undefined }>({ data: undefined, isOpen: false }) - const [bdstChgProps, setBdstChgProps] = useState<{ - isOpen: boolean; - chBuilding: chgBuilding[]; - }>({ isOpen: false, chBuilding: [] }); const [fcltNm, setFcltNm] = useState<string>(""); + const { t } = useTranslation('base'); + const cellClick = (index: number | undefined) => { - const cellClick = (index: number | undefined, headId: string) => { - - if (headId !== 'chBuildingYn' && index !== undefined && bdstTable !== undefined) { + if ( index !== undefined && bdstTable !== undefined) { setDetailModal({ isOpen: true, data: bdstTable[index] }) - } else if (headId === 'chBuildingYn' && index !== undefined && bdstTable !== undefined) { - if ( - bdstTable[index] && - bdstTable[index]?.chBuildingYn === 'Y' - ) { - setBdstChgProps({ isOpen: true, chBuilding: bdstTable[index].chgBuilding }); - } - } + } } const getSelCity = (val: string | number) => { @@ -96,7 +83,7 @@ export default function RswtSttn() { useEffect(() => { if (!rswtSttn.isInit) { - rswtSttnInit(1, "20", "0", fcltNm, code.cityCd, code.sggCd); + rswtSttnInit(false, 1, "20", "0", fcltNm, code.cityCd, code.sggCd); } }, [rswtSttn.isInit, rswtSttnInit]); @@ -111,7 +98,7 @@ export default function RswtSttn() { chBuildingYn: item?.chgBuilding[0]?.bdstChgNm !== null && item?.chgBuilding.length > 0 ? 'Y' : 'N', instlCst: item.reuseBuilding[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCst, instlCstSprtAmt: item.reuseBuilding[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding[0]?.instlCstSprtAmt, - archArea : item?.archArea.split('.')[0]!=='-1'?item?.archArea.split('.')[0]:'확인불가' + archArea: item?.archArea.split('.')[0] !== '-1' ? item?.archArea.split('.')[0] : '확인불가' } }) .filter( @@ -123,25 +110,30 @@ export default function RswtSttn() { }, [code, rswtSttnRes]); useEffect(() => { + if (!isDownloadTriggered.current) { + return; + } if (rswtSttn.excelList.length > 0) { - if (rswtSttn.excelList.length === 0) return; excelDownload( rswtSttn.excelList, "중수도시설 현황", "sample_rswtSttn.xlsx", "A1:W3", ); + } else { + toast.error(t('excelDownErrMsg')); } + isDownloadTriggered.current = false; }, [rswtSttn.excelList]); const excelClick = useCallback(() => { - // 최신 검색 조건 반영 - const con = getConValue(); - rswtSttnSearch(1, "10000", String(con), fcltNm, code.cityCd, code.sggCd); - }, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd]); + isDownloadTriggered.current = true; + rswtSttnSearch(true, 1, String(rswtSttnResCount), String(getConValue()), fcltNm, code.cityCd, code.sggCd); + }, [rswtSttnSearch, objSearch, code.cityCd, code.sggCd, fcltNm, rswtSttnResCount]); useEffect(() => { - rswtSttnSearch(pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + rswtSttnSearch(false, pageNation, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + isResetPage(false) }, [pageNation]); return ( @@ -158,7 +150,9 @@ export default function RswtSttn() { label="시도" selectClass={""} selectArray={code.cityCd} - onSelectValue={getSelCity} + onSelectValue={ + getSelCity + } /> <SelectBox className="col-span-2 w-1/6 h-full text-2xl ml-4" @@ -166,7 +160,9 @@ export default function RswtSttn() { selectClass={""} selectArray={selectSgg || []} value={objSearch.sgg} // value props 추가 - onSelectValue={getSgg} + onSelectValue={ + getSgg + } /> <div className="col-span-2 flex flex-row space-x-2"> <Label className="w-28 mt-2 text-xl text-gray-600"> @@ -187,8 +183,8 @@ export default function RswtSttn() { <Button size={"sm"} onClick={() => { - const con = getConValue(); - rswtSttnSearch(pageNation, "20", String(con), fcltNm, code.cityCd, code.sggCd); + rswtSttnSearch(false, 1, "20", String(getConValue()), fcltNm, code.cityCd, code.sggCd); + isResetPage(true) }} > 조회 @@ -220,15 +216,15 @@ export default function RswtSttn() { <UiTable headName={undefined} tableData={bdstTable || []} - children={ - <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> - } headlist={rswtSttn.rswtSttHeadList} pageSize={20} - total={10000} - cellClick={(index: number | undefined, headId: string) => { cellClick(index ?? undefined, headId) }} + total={rswtSttnResCount || 0} + cellClick={(index: number | undefined) => { cellClick(index ?? undefined) }} onPageChange={setPageNation} - ></UiTable> + resetPageNo={resetPage} + > + <HeadMakeColSpan upHeadList={rswtSttn.rswtSttNodeList} /> + </UiTable> </ListDiv> </div> </div> @@ -257,17 +253,8 @@ export default function RswtSttn() { body={<SttnDetailModal type={"RST"} formObj={detailModal.data} />} /> - <UiModal - bodyClass={""} - open={bdstChgProps.isOpen} - body={ - <BdstChgModal chgBuilding={bdstChgProps.chBuilding}></BdstChgModal> - } - onOpenChange={(open) => { - setBdstChgProps({ ...bdstChgProps, isOpen: open }); - }} - /> </ContentsDiv> + <Toaster position="top-center" /> </> ); } diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx index 0ac9145a5..03397255c 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/chkgdnReg/page.tsx @@ -11,6 +11,7 @@ import { type rswtrChkDetailsZodType, } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { + confirmToast, excelArrayDownload, excelDownload, yearOptions, @@ -39,6 +40,7 @@ import { } from "@common/components/ui/tooltip"; import { useCallback, useEffect, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function Page() { const { @@ -92,6 +94,7 @@ export default function Page() { commonCd, fcltNm ); + setRainPageNation(1); } else { rainChkInit(rainPageNation, rainPageSize, searchYear, commonCd); } @@ -104,6 +107,7 @@ export default function Page() { commonCd, fcltNm ); + setRswtPageNation(1); } else { rswtChkgdnInit(rswtPageNation, rswtPageSize, searchYear, commonCd); } @@ -199,25 +203,32 @@ export default function Page() { } }, [rainChkgdn.isSttn, rswtChkgdn.isSttn]); + const { t } = useTranslation('base'); const clickDelete = (data: number[], selFcltDiv: string) => { if (data.length > 0) { if (selFcltDiv === "RNB") { - rainChkDelete(data); + const handleConfirm = async () => { + rainChkDelete(data, searchYear); + }; + confirmToast(t('isDeleteMsg'), handleConfirm); } else { - rswtChkDelete(data); + const handleConfirm = async () => { + rswtChkDelete(data, searchYear); + }; + confirmToast(t('isDeleteMsg'), handleConfirm); } } }; const chkUpdateTable = (selFcltDiv: string) => { if (selFcltDiv === "RNB") { if (updateRainDetail && updateRainDetail.length > 0) { - rainChkDetilUpdate(updateRainDetail); - } else { + rainChkDetilUpdate(updateRainDetail, searchYear); + } else { toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 "); } } else { if (updateRswtDetail && updateRswtDetail.length > 0) { - rswtChkDetilsUpdate(updateRswtDetail); + rswtChkDetilsUpdate(updateRswtDetail, searchYear); } else { toast.error("수정을 원하는 행을 선택하고 저장버튼을 눌러주세요 "); } @@ -279,7 +290,7 @@ export default function Page() { <div className="flex flex-row space-x-2"> <Button size={"sm"} - onClick={(e) => { + onClick={() => { cellClick(); }} > @@ -297,14 +308,14 @@ export default function Page() { <TooltipProvider> <Tooltip> <TooltipTrigger asChild> - <Button - size={"sm"} - onClick={() => { - chkUpdateTable(selFcltDiv); - }} - > - 저장 - </Button> + <Button + size={"sm"} + onClick={() => { + chkUpdateTable(selFcltDiv); + }} + > + 저장 + </Button> </TooltipTrigger> <TooltipContent side="bottom" sideOffset={5}> <h2 className="text-xl"> @@ -314,7 +325,6 @@ export default function Page() { </Tooltip> </TooltipProvider> - <Button size={"sm"} onClick={() => { @@ -343,7 +353,8 @@ export default function Page() { rainChkData={rainChkgdn.rainChk} pageNation={rainPageNation} onPageChange={rainPageChange} - pageCount={rainChkgdn.rainChkCount} /> + pageCount={rainChkgdn.rainChkCount} + /> ) : ( <RswtChkgdTable detaiRswtlUpdate={setUpdateRSwtDetail} @@ -380,6 +391,9 @@ export default function Page() { <ChkgdExcel type={selFcltDiv} setIsRegExcel={setIsRegExcel} + setYearChange={(year) => { + setSearchYear(year); + }} ></ChkgdExcel> } /> diff --git a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx index c54725ff2..4e0a7b4d7 100644 --- a/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncReg/pbnstPrfmncReg/page.tsx @@ -1,19 +1,28 @@ "use client"; import { useWrStore } from "@/app/store"; -import type { pubHasuType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import { excelDownload, yearOptions } from "@/components/lib/func/commom"; +import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel"; +import { + initValInUsage, + initValOutUsage, + subTotalObj, + totalObj, + type FcPrfType, + type PrfType, +} from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; +import { confirmToast, excelDownload, yearOptions } from "@/components/lib/func/commom"; +import { InputTableBody } from "@/components/lib/func/TableData"; import PbnPrfExcelModal from "@/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal"; import { ContentsDiv, - Title, + ScrollArea, SearchDiv, SearchFormLeft, - SelectBox, - SearchInput, SearchFormRight, - ScrollArea, - UiTable, + SearchInput, + SelectBox, + Title, UiModal, + UiTable, } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; import { @@ -23,27 +32,16 @@ import { TableBody, TableHeader, } from "@common/components/ui"; -import { useState, useEffect, useCallback } from "react"; -import { set } from "react-hook-form"; +import { useCallback, useEffect, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; import { headMakeprfmnc } from "../chkgdnReg/TableHead"; -import { InputTableBody } from "@/components/lib/func/TableData"; -import { - initValInUsage, - initValOutUsage, - subTotalObj, - totalObj, - type FcPrfType, - type PrfType, -} from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; -import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel"; -import data from "@common/components/ui/icon-finder/data"; -export default function prfmncPrfmncReg() { - const { code, prfmnc, prfmncHasuInit, prfmnRegData } = useWrStore( +export default function PrfmncPrfmncReg() { + const { prfmnc, prfmncHasuInit, prfmnRegData, prfmncHasuNmSearch } = useWrStore( (state) => state ); - const { pbnstPrfmncHeadList, monthHeadList, prfmncRes } = prfmnc; + const { pbnstPrfmncHeadList, monthHeadList, prfmncRes, prfmncResCount } = prfmnc; const [bdstTable, setbdstTable] = useState<FcPrfType[]>(); const [searchTxt, setSearchTxt] = useState<string>(); const [isExcelOpen, setIsExcelOPen] = useState<{ @@ -51,7 +49,7 @@ export default function prfmncPrfmncReg() { data: FcPrfType; }>({ isModal: false, data: {} as FcPrfType }); const [inputData, setInputData] = useState<any[]>(); - const [pbnstRuseFcltPk, setPbnstRuseFcltPk] = useState<string>(); + const [pbnstRuseFcltId, setpbnstRuseFcltId] = useState<string>(); const [pageNation, setPageNation] = useState<number>(1); const [cellNum, setCellNum] = useState<number>(1); const [searchYear, setSearchYear] = useState<string>( @@ -66,20 +64,40 @@ export default function prfmncPrfmncReg() { "A1:O1" ); }, [prfmnc.excelList]); + /* + const onSave = useCallback( + async() => { + if (pbnstRuseFcltId) { + await prfmnRegData(pageNation,'41', + excelToPbnPrfData( + inputData as unknown as JSON[], + searchYear, + pbnstRuseFcltId + ) as unknown as PrfType + ); + // cellClick(cellNum) + } + }, [inputData, searchYear, pbnstRuseFcltId, pageNation,cellNum]);*/ - const onSave = useCallback( - async() => { - if (pbnstRuseFcltPk) { - await prfmnRegData(pageNation,'41', + const { t } = useTranslation('base'); + const onSave = useCallback(() => { + const handleConfirm = async () => { + if (!pbnstRuseFcltId) return; + + prfmnRegData( + pageNation, + '41', excelToPbnPrfData( inputData as unknown as JSON[], searchYear, - pbnstRuseFcltPk + pbnstRuseFcltId ) as unknown as PrfType + ,searchYear ); - // cellClick(cellNum) - } - }, [inputData, searchYear, pbnstRuseFcltPk, pageNation,cellNum]); + }; + + confirmToast(t('isUpdateMsg'), handleConfirm); + }, [inputData, searchYear, pbnstRuseFcltId, pageNation, cellNum]); const cellClick = useCallback( (index: number | undefined) => { @@ -153,7 +171,7 @@ export default function prfmncPrfmncReg() { (usageTotalObj as any)[key] = val; } const tableData = [...inUsageData, ...outUsageData, usageTotalObj]; - setPbnstRuseFcltPk(prfmncRes[index].pbnstRuseFcltPk); + setpbnstRuseFcltId(prfmncRes[index].pbnstRuseFcltId); setInputData(tableData); } else { setInputData([]); @@ -165,11 +183,17 @@ export default function prfmncPrfmncReg() { useEffect(() => { if (!prfmnc.isInit) { - prfmncHasuInit(1, "41"); + const year = new Date().getFullYear() + prfmncHasuInit(1, "41", String(year)); } }, [prfmnc.isInit, prfmncHasuInit]); useEffect(() => { - setbdstTable(prfmncRes); + + + if (prfmncRes && prfmncRes.length > 0) { + + setbdstTable(prfmncRes); + } // cellNum이 0일 경우(첫 번째 행)도 유효한 인덱스이므로 undefined 여부만 체크합니다. if (cellNum !== undefined) { @@ -217,7 +241,17 @@ export default function prfmncPrfmncReg() { <SearchFormRight className="w-2/12 mx-5 flex flex-col items-center justify-center space-x-2 "> <div className="space-y"> <div className="flex flex-row space-x-2"> - <Button size={"sm"} onClick={(e) => {}}> + <Button size={"sm"} onClick={() => { + + if (searchTxt && searchTxt?.length > 0) { + prfmncHasuNmSearch(1, '41', searchYear, searchTxt) + setPageNation(1) + } else { + prfmncHasuInit(1, '41', searchYear) + setPageNation(1) + } + + }}> 조회 </Button> <Button @@ -260,14 +294,17 @@ export default function prfmncPrfmncReg() { tableData={bdstTable || []} headlist={pbnstPrfmncHeadList} pageSize={10} - total={10000} + total={prfmncResCount} headName={"하수재이용시설 목록"} - cellClick={(index: number | undefined, headId: string) => { + cellClick={(index: number | undefined) => { cellClick(index); setCellNum(index ?? 0); }} - onPageChange={setPageNation} - children={undefined} + onPageChange={ + (page) => { + prfmncHasuInit(page, "41", searchYear); + setPageNation(page) + }} /> </ScrollArea> </ListDiv> @@ -279,12 +316,11 @@ export default function prfmncPrfmncReg() { {"하수처리수재이용 실적(m3) 등록결과"} </h3> </div> - <Table variant="secondary"> <TableHeader className="font-bold"> {headMakeprfmnc(monthHeadList, [])} </TableHeader> - <TableBody key={prfmnc.pageKey+'pageKey'}> + <TableBody key={prfmnc.pageKey + 'pageKey'}> {InputTableBody(inputData ?? [], monthHeadList, setInputData)} </TableBody> </Table> @@ -299,15 +335,15 @@ export default function prfmncPrfmncReg() { data={isExcelOpen.data} setIsExcelOPen={(open) => { setIsExcelOPen({ ...isExcelOpen, isModal: open }) - }} - setModalExcelData={ async(excelData ) =>{ - await prfmnRegData(pageNation,'41', + setModalExcelData={async (excelData) => { + await prfmnRegData(pageNation, '41', excelData, + searchYear ); // 데이터 저장 후 UI 업데이트는 useEffect가 감지하여 처리하므로 여기서는 호출하지 않습니다. } - } + } ></PbnPrfExcelModal> } open={isExcelOpen.isModal} diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx index a191de9ee..a2955f386 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/chkgdnSttn/page.tsx @@ -23,11 +23,11 @@ import { import ListDiv from "@common/business_components/ui/list_div"; import { Button, Label } from "@common/components/ui"; import { useCallback, useEffect, useState } from "react"; -import { Toaster } from "react-hot-toast"; +import toast, { Toaster } from "react-hot-toast"; +import { useTranslation } from "react-i18next"; export default function Page() { const { - code, rainChkSttn, rswtChkSttn, rainChkSttnInit, @@ -97,7 +97,6 @@ export default function Page() { useEffect(() => { if (!rainChkSttn.isInit) { isRainSttn(true) - console.log("여기", rainPageSize) rainChkSttnInit(1, rainPageSize, new Date().getFullYear().toString(), commonCd); setIsModal({ data: {}, open: false }); } @@ -119,8 +118,13 @@ export default function Page() { }, [isModal] ); + const { t } = useTranslation('base'); const excelDown = () => { if (rainChkSttn.sttnExcelList && selFcltDiv === "RNB") { + if (!rainChkSttn.sttnExcelList || rainChkSttn.sttnExcelList.length === 0) { + toast.error(t('excelDownErrMsg')); + return; + } excelDownload( rainChkSttn.sttnExcelList, "빗물이용시설 지도점검 현황", @@ -129,6 +133,10 @@ export default function Page() { 3 ); } else if (rswtChkSttn.sttnExcelList && selFcltDiv === "RST") { + if (!rswtChkSttn.sttnExcelList || rswtChkSttn.sttnExcelList.length === 0) { + toast.error(t('excelDownErrMsg')); + return; + } excelDownload( rswtChkSttn.sttnExcelList, "중수도시설 지도점검 현황", @@ -191,13 +199,13 @@ export default function Page() { <div className="flex flex-row space-x-2"> <Button size={"sm"} - onClick={(e) => { + onClick={() => { cellClick(); }} > 조회 </Button> - <Button color="green" size={"sm"} onClick={(e) => { excelDown() }}> + <Button color="green" size={"sm"} onClick={() => { excelDown() }}> 다운로드 </Button> </div> diff --git a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx index 3e860d744..898f50601 100644 --- a/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx +++ b/apps/wr/app/ruseFcltMng/prfmncSttn/pbnstPrfmncSttn/page.tsx @@ -6,20 +6,19 @@ import { initValInUsage, initValOutUsage, subTotalObj, totalObj, type FcPrfType, import { excelPrfmncSttnParsing } from "@/app/store/prfmncSttn/pbnstPrfmncSttn/excel"; import { excelDownload, yearOptions } from "@/components/lib/func/commom"; import SearchInputText from "@/components/ui/searchInput/searchInput"; -import { CHART_FORM, ContentsDiv, MainChart, ScrollArea, SearchBaseForm, SearchInput, SelectBox, Title, UiTable, type ChartConfig, type ReturnType } from "@common/business_components"; +import { CHART_FORM, ContentsDiv, MainChart, SearchBaseForm, SelectBox, Title, UiTable, type ChartConfig, type ReturnType } from "@common/business_components"; import ListDiv from "@common/business_components/ui/list_div"; -import { Button, Label, Table, TableBody, TableHeader } from "@common/components/ui"; +import { Label } from "@common/components/ui"; import { useCallback, useEffect, useRef, useState } from "react"; import toast, { Toaster } from "react-hot-toast"; -import { headMakeprfmnc } from "../../prfmncReg/chkgdnReg/TableHead"; -import { InputTableBody } from "@/components/lib/func/TableData"; +import { useTranslation } from "react-i18next"; export default function PbnstPrfmncSttn() { const { code, tableHeadMaker, pbnstPrfmncSttn, - pbnstPrfmncInit, + // pbnstPrfmncInit, pbnstPrfmncSearch, prfmnc, pbnstSttn, @@ -27,20 +26,22 @@ export default function PbnstPrfmncSttn() { } = useWrStore((state) => state); const { monthHeadList } = prfmnc const { pbnstPrfHeadList, prfmncRes, rawData, selectYearList } = pbnstPrfmncSttn; - const [isChHead, setIsChHead] = useState(false); + // const [isChHead, setIsChHead] = useState(false); const [fromDate, setFromDate] = useState<string>(String(new Date().getFullYear())); const [toDate, setToDate] = useState<string>(String(new Date().getFullYear())); const [year, setYear] = useState<string>(String(new Date().getFullYear())); const [bdstTable, setbdstTable] = useState<FcPrfType[]>(); const ref = useRef<ReturnType>({} as ReturnType); - const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>(); + // const [swtrmtFcltNm, setSwtrmtFcltNm] = useState<string>(); const [pbnRuseNm, setPbnRuseNm] = useState<string>(""); - - const [searchYear, setSearchYear] = useState<string>( - String(new Date().getFullYear()) - ); + const { t } = useTranslation('base'); + const searchYear = String(new Date().getFullYear()); const [excelData, setExcelData] = useState<any[]>([]); const excelClick = useCallback(() => { + if (!excelData || excelData.length === 0) { + toast.error(t('excelDownErrMsg')); + return; + } excelDownload( excelData, "하수재이용실적 현황", @@ -80,18 +81,18 @@ export default function PbnstPrfmncSttn() { chartData8: lineChartDataProps[]; }>(); - type dnChartForm = { label: string, val: number, fill?: string }; + type dnChartForm = { label: string, val: number, color?: string }; type barChartForm = { label: string, "장내용수": number, "장외용수": number }; type lineChartDataProps = { label: string, val: number, color: string }; const prfTableData = (prfList: PrfType[], year: string) => { const inUsageData = structuredClone(initValInUsage).map(row => ({ - ...row, - 구분: "장내용수", + ...row + // 구분: "장내용수", })); const outUsageData = structuredClone(initValOutUsage).map(row => ({ - ...row, - 구분: "장외용수", + ...row + // 구분: "장외용수", })); const inSubtotal = { ...structuredClone(subTotalObj), 구분: "장내용수" }; const outSubtotal = { ...structuredClone(subTotalObj), 구분: "장외용수" }; @@ -173,7 +174,7 @@ export default function PbnstPrfmncSttn() { let inUsageSum = 0, outUsageSum = 0; - let inUsageArr: number[] = [], + const inUsageArr: number[] = [], outUsageArr: number[] = []; // 라인차트용 데이터 @@ -206,10 +207,10 @@ export default function PbnstPrfmncSttn() { rawData.forEach((item) => { // 실적 테이블 데이터 if (chartId) { - if (item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltFk === chartId) { + if (item.prfList?.[0]?.ym.slice(0, 4) === year && item.prfList?.[0]?.pbnstRuseFcltId === chartId) { prfTableData(item.prfList, year); } - item.prfList.filter((e) => e.ym.slice(0, 4) === year && e.pbnstRuseFcltFk === chartId).forEach((element) => { + item.prfList.filter((e) => e.ym.slice(0, 4) === year && e.pbnstRuseFcltId === chartId).forEach((element) => { // 누적 wshwtr += element.wshwtr; coolUswtr += element.coolUswtr; @@ -284,27 +285,45 @@ export default function PbnstPrfmncSttn() { }) // 도넛차트 데이터 - dnData.push({ label: "장내용수", val: dnTotalIn, fill: "#8DD8FF" }); - dnData.push({ label: "장외용수", val: dnTotalOut, fill: "#FFF085" }); + dnData.push({ label: "장내용수", val: dnTotalIn, color: "#8DD8FF" }); + dnData.push({ label: "장외용수", val: dnTotalOut, color: "#FFF085" }); // 장내용수 도넛 - dnInData.push({ label: "세척수", val: wshwtr, fill: "#F7CFD8" }); - dnInData.push({ label: "냉각수", val: coolUswtr, fill: "#F4F8D3" }); - dnInData.push({ label: "청소수", val: cleanUswtr, fill: "#A6D6D6" }); - dnInData.push({ label: "식수대", val: drwtUswtr, fill: "#8E7DBE" }); - dnInData.push({ label: "희석용수", val: dltnUswtr, fill: "#FF8383" }); - dnInData.push({ label: "중수도", val: ithlRswtr, fill: "#FFF574" }); - dnInData.push({ label: "기타", val: ithlEtcUswtr, fill: "#A1D6CB" }); + dnInData.push({ label: "세척수", val: wshwtr, color: "#F7CFD8" }); + dnInData.push({ label: "냉각수", val: coolUswtr, color: "#F4F8D3" }); + dnInData.push({ label: "청소수", val: cleanUswtr, color: "#A6D6D6" }); + dnInData.push({ label: "식수대", val: drwtUswtr, color: "#8E7DBE" }); + dnInData.push({ label: "희석용수", val: dltnUswtr, color: "#FF8383" }); + dnInData.push({ label: "중수도", val: ithlRswtr, color: "#FFF574" }); + dnInData.push({ label: "기타", val: ithlEtcUswtr, color: "#A1D6CB" }); // 장외용수 도넛 - dnOutData.push({ label: "청소화장실용수", val: cleanToilUswtr, fill: "#A19AD3" }); - dnOutData.push({ label: "세척살수용수", val: resn, fill: "#B1F0F7" }); - dnOutData.push({ label: "조경용수", val: lndwtr, fill: "#81BFDA" }); - dnOutData.push({ label: "친수용수", val: hydUswtr, fill: "#F5F0CD" }); - dnOutData.push({ label: "지하수충전", val: ugwtChr, fill: "#FADA7A" }); - dnOutData.push({ label: "농업용수", val: farmUswtr, fill: "#A6AEBF" }); - dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, fill: "#C5D3E8" }); - dnOutData.push({ label: "공업용수", val: indstUswtr, fill: "#D0E8C5" }); + dnOutData.push({ label: "청소화장실용수", val: cleanToilUswtr, color: "#A19AD3" }); + dnOutData.push({ label: "세척살수용수", val: resn, color: "#B1F0F7" }); + dnOutData.push({ label: "조경용수", val: lndwtr, color: "#81BFDA" }); + dnOutData.push({ label: "친수용수", val: hydUswtr, color: "#F5F0CD" }); + dnOutData.push({ label: "지하수충전", val: ugwtChr, color: "#FADA7A" }); + dnOutData.push({ label: "농업용수", val: farmUswtr, color: "#A6AEBF" }); + dnOutData.push({ label: "하천등유지용수", val: rvrKeepUswtr, color: "#C5D3E8" }); + dnOutData.push({ label: "공업용수", val: indstUswtr, color: "#D0E8C5" }); + + // 라인차트 데이터 월별 오름차순 정렬 + const sortFn = (a: { label: string }, b: { label: string }) => parseInt(a.label) - parseInt(b.label); + wshwtrData.sort(sortFn); + coolUswtrData.sort(sortFn); + cleanUswtrData.sort(sortFn); + drwtUswtrData.sort(sortFn); + dltnUswtrData.sort(sortFn); + ithlRswtrData.sort(sortFn); + ithlEtcUswtrData.sort(sortFn); + cleanToilUswtrData.sort(sortFn); + resnData.sort(sortFn); + lndwtrData.sort(sortFn); + hydUswtrData.sort(sortFn); + ugwtChrData.sort(sortFn); + farmUswtrData.sort(sortFn); + rvrKeepUswtrData.sort(sortFn); + indstUswtrData.sort(sortFn); // 라인차트 데이터 setInLineData({ @@ -326,6 +345,7 @@ export default function PbnstPrfmncSttn() { chartData7: rvrKeepUswtrData, chartData8: indstUswtrData, }); + barData.sort((a, b) => parseInt(a.label) - parseInt(b.label)); setBarData(barData); setChartData(dnData); setDnInUsage(dnInData); @@ -337,10 +357,10 @@ export default function PbnstPrfmncSttn() { const newChartConfig = chartData.reduce((config, element) => { config[element.label] = { label: element.label, - fill: element.fill + color: element.color }; return config; - }, {} as Record<string, { label: string; fill?: string }>) satisfies ChartConfig; + }, {} as Record<string, { label: string; color?: string }>) satisfies ChartConfig; setChartConfig(newChartConfig); }, [chartData]); @@ -348,7 +368,7 @@ export default function PbnstPrfmncSttn() { const newChartConfig = dnInUsage.reduce((config, element) => { config[element.label] = { label: element.label, - fill: element.fill + color: element.color ?? "gray" }; return config; }, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig; @@ -359,7 +379,7 @@ export default function PbnstPrfmncSttn() { const newChartConfig = dnOutUsage.reduce((config, element) => { config[element.label] = { label: element.label, - fill: element.fill + color: element.color ?? "gray" }; return config; }, {} as Record<string, { label: string; color: string; }>) satisfies ChartConfig; @@ -471,20 +491,26 @@ export default function PbnstPrfmncSttn() { }, []); useEffect(() => { - setbdstTable(prfmncRes); - if (prfmncRes?.[0]?.pbnstRuseFcltPk) setChartId(prfmncRes[0].pbnstRuseFcltPk) + setbdstTable(prfmncRes.map((e, idx) => { + + return ({ + ...e, + number: String(idx + 1) + }) + })) + if (prfmncRes?.[0]?.pbnstRuseFcltId) setChartId(prfmncRes[0].pbnstRuseFcltId) }, [prfmncRes]); useEffect(() => { if (pbnRuseNm.length > 1) - pbnNmSearch("1", "23", ref.current, pbnRuseNm, searchYear); + pbnNmSearch("1", "23", ref.current, pbnRuseNm, searchYear,[]); }, [pbnRuseNm]); const cellClick = (index: number | undefined, headId: string) => { if (index !== undefined && headId !== undefined) { - setChartId(prfmncRes[index].pbnstRuseFcltPk) + setChartId(prfmncRes[index].pbnstRuseFcltId) } } @@ -501,14 +527,7 @@ export default function PbnstPrfmncSttn() { selectUnitWaterShedData={code.lgbsnCd} selectMiddleRegionData={code.mdmbsnCd} selectEnvPartData={code.lclgvrnmntCd} - rightChildren={<Button - className={btnClass} - onClick={() => { - setIsChHead(true); - }} - > - 조회항목설정 - </Button>} + rightChildren={undefined} leftChildren={<div className="col-span-5"> <div className="flex flex-row"> <div className="flex flex-row items-center"> @@ -534,9 +553,9 @@ export default function PbnstPrfmncSttn() { setValue={(searchNm?: string) => { setPbnRuseNm(searchNm || ""); }} - setRtnData={function (rtnData: any[]): void { - // setbdstTable(rtnData); - }} + setRtnData={/*function (rtnData: any[]): void {setbdstTable(rtnData);}*/ + ()=>{} + } searchList={pbnstSttn.pbnstSearchData || []} ></SearchInputText> {/* <SelectBox @@ -639,9 +658,7 @@ export default function PbnstPrfmncSttn() { pageSize={0} total={0} cellClick={undefined} - onPageChange={function (page: number): void { - throw new Error("Function not implemented."); - }}> + onPageChange={()=>{}}> </UiTable> {/* <ListDiv className="col-span-8 pr-6 "> diff --git a/apps/wr/app/stats/matStat/page.tsx b/apps/wr/app/stats/matStat/page.tsx deleted file mode 100644 index a147ff597..000000000 --- a/apps/wr/app/stats/matStat/page.tsx +++ /dev/null @@ -1,74 +0,0 @@ -'use client' -import { useWrStore } from "@/app/store"; -import { yearOptions } from "@/components/lib/func/commom"; -import { ContentsDiv, Title, SearchDiv, SearchFormLeft, SelectBox, UiTable } from "@common/business_components/ui"; -import ListDiv from "@common/business_components/ui/list_div"; -import { Button } from "@common/components/ui"; -import { useState } from "react"; - -export default function MatStat(){ -const { code, matStat } = useWrStore((state) => { - return state; - }); - const [pageNation, setPageNation] = useState(1); - const [searchYear, setSearchYear] = useState<string>( - String(new Date().getFullYear()) - ); - - return( - <> - <ContentsDiv> - <div className="grid grid-cols-4 gap-4"> - <div className="col-span-4"> - <Title title={"재이용 통계"} /> - <SearchDiv> - <SearchFormLeft> - <SelectBox - className="w-full h-full text-2xl" - label="통계년도" - selectClass={""} - selectArray={yearOptions} - value={searchYear} - onSelectValue={(val: string | number) => - setSearchYear(String(val)) - } - /> - <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={(e) => {}}> - 조회 - </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> - 다운로드 - </Button> - <Button className="" size={"sm"} onClick={(e) => {}}> - 전체통계다운로드 - </Button> - </div> - </SearchFormLeft> - {/* <SearchFormRight> - - </SearchFormRight> */} - </SearchDiv> - </div> - </div> - <div className="grid grid-cols-6 gap-4"> - <div className="col-span-6 h-full min-h-0"> - <ListDiv className="min-h-0"> - {/* <ScrollArea className="h-[60vh]"> */} - <UiTable - tableData={[]} - headlist={matStat.matStatHeadList} - pageSize={20} - total={10000} - headName={"건축물 목록"} - cellClick={(val, headId) => {}} - onPageChange={setPageNation} - ></UiTable> - {/* </ScrollArea> */} - </ListDiv> - </div> - </div> - </ContentsDiv> - </> - ) -} \ No newline at end of file diff --git a/apps/wr/app/stats/rainStat/page.tsx b/apps/wr/app/stats/rainStat/page.tsx index 45d32d3a4..591ea5fdf 100644 --- a/apps/wr/app/stats/rainStat/page.tsx +++ b/apps/wr/app/stats/rainStat/page.tsx @@ -29,7 +29,7 @@ export default function RainStat() { useEffect(() => { searchRainStatList(searchYear); - }, [code.cityCd, code.sggCd, searchRainStatList, searchYear]) + }, [code.cityCd, code.sggCd, searchRainStatList]) const excelDetailDownLoad=() =>{ const sidoList = new Set<string>(); @@ -237,7 +237,7 @@ export default function RainStat() { /> </div> <div className="flex flex-row space-x-2 items-center"> - <Button className="" size={"sm"} onClick={() => { }}> + <Button className="" size={"sm"} onClick={()=>{searchRainStatList(searchYear);}}> 조회 </Button> <Button className="" size={"sm"} onClick={() => excelClick()}> diff --git a/apps/wr/app/stats/rswtStat/page.tsx b/apps/wr/app/stats/rswtStat/page.tsx index 997e95ca5..c200d0319 100644 --- a/apps/wr/app/stats/rswtStat/page.tsx +++ b/apps/wr/app/stats/rswtStat/page.tsx @@ -26,14 +26,14 @@ export default function RswtStat() { useEffect(() => { searchRswtStatList(searchYear) - }, [searchRswtStatList, searchYear]) + }, [searchRswtStatList]) const excelClick = () => { downloadExcel({ data: (excelData as unknown as JSON[]) ?? [], fileName: "중수도재이용통계", sheetNameArray: ["Sheet1"], - headerRange: "A1:O1" + headerRange: "A1:N1" }) } @@ -59,7 +59,7 @@ export default function RswtStat() { return { "시도": item.cityText, "개소": item.ctpvCnt, - "건축연면적(m³)": item.archArea, + // "건축연면적(m³)": item.archArea, "처리용량(m³)": item.filtrTrtmfctCpct, "물사용량(m³/년)": item.wtrUsqty, "중수도+대체수이용량(m³/년)": item.rswtAltSum, diff --git a/apps/wr/app/store/common/code/basicCode.tsx b/apps/wr/app/store/common/code/basicCode.tsx index 56c59b502..12b01f952 100644 --- a/apps/wr/app/store/common/code/basicCode.tsx +++ b/apps/wr/app/store/common/code/basicCode.tsx @@ -1,5 +1,8 @@ import type { SelectDataType } from "@common/business_components"; +export const numSize = 12; +export const txtSize = 20; + export const yn: SelectDataType[] = [ { val: "Y", text: "Y" }, { val: "N", text: "N" }, @@ -181,10 +184,26 @@ export const rswtPrscCdMthdCd = [ ]; export const htdPowerMthdCd= [ + { + val: "해당없음", + text: "해당없음", + }, { val: "석탄화력발전", text: "석탄화력발전", }, + { + val: "화력발전", + text: "화력발전", + }, + { + val: "수력발전", + text: "수력발전", + }, + { + val: "태양관발전", + text: "태양관발전", + }, ]; //(공업용수/양식장/농업용수) diff --git a/apps/wr/app/store/common/code/index.ts b/apps/wr/app/store/common/code/index.ts index b3cf48603..e33b14f94 100644 --- a/apps/wr/app/store/common/code/index.ts +++ b/apps/wr/app/store/common/code/index.ts @@ -3,6 +3,10 @@ import type { EnvPartSelectDataType, SelectDataType } from "@common/business_com import { bdstFilterYn, bdstGrntchClass, bdstIncenYn, bdstUsgCd, chBuCd, dmdUszCd, erctUswtrPrcsMeth, htdPowerMthdCd, htdUtztnUsgCd, orgwtKndCd, pplLenght, pplQulity, rainFcltCd, rswtPrscCdMthdCd, ruseBizMthdCd, ruseMngMtd, rusePrcsMthdCd, ruseSeCd, yn } from "./basicCode"; export const btnClass = "p-4 m-2 text-white rounded-sm text-lg font-medium " + +const laeSecd = '41' + + export const buildingType = { RST:"RST", RNB:"RNB", @@ -167,6 +171,8 @@ export type comCodeState = { rswtPrscCdMthdCd:SelectDataType[]; htdPowerMthdCd:SelectDataType[] htdUtztnUsgCd:SelectDataType[] + userSiSggCd : string; + }; }; @@ -203,6 +209,7 @@ export const comCodeStateExport: comCodeState = { rswtPrscCdMthdCd:rswtPrscCdMthdCd, htdPowerMthdCd:htdPowerMthdCd, htdUtztnUsgCd:htdUtztnUsgCd, + userSiSggCd:laeSecd, }, }; diff --git a/apps/wr/app/store/common/searchCode/index.ts b/apps/wr/app/store/common/searchCode/index.ts index 656bc33d9..03d1b0fc5 100644 --- a/apps/wr/app/store/common/searchCode/index.ts +++ b/apps/wr/app/store/common/searchCode/index.ts @@ -7,16 +7,15 @@ import { import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; import type { conCostFeeType, rateFeeType } from "./type"; +import toast from "react-hot-toast"; export const comFcltStateExport: comFcltState = { searchFclts: [] as pubHasuType[], demandCompList: [], - dmdIsSucees: '', checkDemand: { index: 0, - dmdInfoPk: "", - dmdInfoFk: "", + dmdInfoId: "", bzmnNo: "", dmdCoNm: "", daddr: "", @@ -52,7 +51,6 @@ export type comFcltType = comFcltState & comFcltActions; export type comFcltState = { searchFclts: pubHasuType[]; demandCompList: DemandCompType[]; - dmdIsSucees: string; checkDemand: DemandCompType; constCostRes:conCostFeeType[], rateFeeRes:rateFeeType[], @@ -110,19 +108,20 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { data, fetchType.WR ); - let message = ""; if (response.status === 200) { - message = "success"; - } else { - message = "fail"; + toast.success('수요처가 등록되었습니다. ') + set((state: comFcltState) => { + + return { + ...state, + dmdIsSucees: "success" + } + }); } - - - set((state: comFcltState) => { - return state.dmdIsSucees = message; - }); } catch (err) { console.log(err); + toast.error('수요처가 등록 오류입니다.. ') + } }, updateDemandCompany: async (data: DemandCompType) => { @@ -132,15 +131,21 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { let message = ""; if (response.status === 200) { message = "success"; + toast.success('수요처 정보가 변경되었습니다. ' ) } else { message = "fail"; } set((state: comFcltState) => { - return state.dmdIsSucees = message; + return { + ...state, + dmdIsSucees: message + } }); } catch (err) { console.log(err); + toast.success('수요처 정보가 오류입니다. ' ) + } }, getRateFee: async (year: string) => { @@ -149,7 +154,11 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { const rateFeeRes = await getFetch(fetchType.COMMON, url); set((state: comFcltState) => { - return state.rateFeeRes = rateFeeRes;; + + return { + ...state, + rateFeeRes: rateFeeRes + } }); } catch (e) { console.log(" error ", e); @@ -159,9 +168,15 @@ export const comFcltSearchAction: (set: any) => comFcltActions = (set: any) => { const url = `/prcsFclt/CstRuse/${year}`; const constCost = await getFetch(fetchType.COMMON, url); set((state: comFcltState) => { - return state.constCostRes = constCost;; + + return { + ...state, + constCostRes: constCost + } + }); }catch (e) { + console.log('getConstCostFee ', e) } } diff --git a/apps/wr/app/store/common/type/header.tsx b/apps/wr/app/store/common/type/header.tsx index f064b7580..29780ba03 100644 --- a/apps/wr/app/store/common/type/header.tsx +++ b/apps/wr/app/store/common/type/header.tsx @@ -22,6 +22,7 @@ export type TableUpperProps = { selectData ?:string; // type 이 seelct 일경우 selectarray 정하기 위해 row?:number; mergeCell?:boolean // 셀을 합칠경우 + maxLength?:number readonly?:boolean }; diff --git a/apps/wr/app/store/map/index.tsx b/apps/wr/app/store/map/index.tsx deleted file mode 100644 index 6a1e76c9b..000000000 --- a/apps/wr/app/store/map/index.tsx +++ /dev/null @@ -1,185 +0,0 @@ -import { getFetch } from "@/components/lib/api"; - -export type wrMapType = wrMapState & wrMapActions; - -export type wrMapState = { - wrMap: { - buildingSearchRes: any[] - } // 건물 검색 결과 데이터 -}; - -type wrMapActions = { - buildingNmSearch: ( - flg: string, - sigunCode: string, - searchNm: string | undefined - ) => void; - buildingNmSearchMultiple: ( - checkedLayers: string[], - sigunCode: string, - searchNm: string | undefined - ) => void; // 여러 레이어 동시 검색 함수 추가 -}; - -export const wrMapStateExport: wrMapState = { - wrMap: { - buildingSearchRes: [] - } -}; - -// 레이어 타입과 플래그 매핑 -const LAYER_FLAG_MAP: { [key: string]: string } = { - // '46': '???', // 하수처리시설 - // '47': '???', // 하수재이용시설 - '48': 'RNB', // 빗물이용시설 - '49': 'RST', // 중수도시설 - '50': 'HTB', // 온배수시설 -}; - -const findBdst = async (flg: string, sggCd: string, searchTxt: string | undefined) => { - return await getFetch('wr', `/reuseFc/building/${flg}/${sggCd}` + (searchTxt ? `/${searchTxt}` : '')) -} - -export const wrMapActionsExport: (set: any) => wrMapActions = ( - set: any -) => { - return { - buildingNmSearch: async ( - flg: string, - sigunCode: string, - searchNm: string | undefined - ) => { - try { - // if (!searchNm || searchNm.length < 2) { - // set((state: wrMapState) => ({ - // ...state, - // buildingSearchData: [] - // })); - // return; - // } - console.log("건축물 코드, 시군구 코드, 검색어: ", flg, sigunCode, searchNm); - - const response = await findBdst(flg, sigunCode, searchNm); - console.log("response: ", response); - - // API 응답을 SearchInputText 형식으로 변환 - const searchListFormatted = (response || []).map((building: any) => ({ - searchNm: building.bdstNm, - searchPk: String(building.bdstInfoPk), - dmdCoNm: building.bdstNm, - layerType: flg, - ...building - })); - - // findBdst와 유사한 API 호출 - // findBdst(flg, sigunCode || "", searchNm).then(() => { - // console.log("건물 검색 API 호출: ", sigunCode, searchNm, flg); - // // bdst.bdstBase를 SearchInputText 형식으로 변환 - // const searchListFormatted = (state.bdst.bdstBase || []).map((building: any) => ({ - // searchNm: building.bdstNm, - // searchPk: String(building.bdstInfoPk), - // dmdCoNm: building.bdstNm, - // layerType: flg, - // ...building - // })); - - // set((state: any) => ({ - // ...state, - // wrMap: { - // ...state.wrMap, - // buildingSearchData: searchListFormatted - // } - // })); - // }); - set((state: wrMapState) => ({ - ...state, - wrMap: { - ...state.wrMap, - buildingSearchRes: searchListFormatted - } - })); - } catch (error) { - console.error("건물 검색 중 오류:", error); - } - }, - - buildingNmSearchMultiple: async ( - checkedLayers: string[], - sigunCode: string, - searchNm: string | undefined - ) => { - try { - if (!searchNm || searchNm.length < 2) { - set((state: any) => ({ - ...state.wrMap, - buildingSearchData: [] - })); - return; - } - - // 체크된 레이어들에 대해 병렬로 API 호출 - const searchPromises = checkedLayers - .filter(layer => LAYER_FLAG_MAP[layer]) // 매핑된 레이어만 필터링 - .map(layer => { - const flg = LAYER_FLAG_MAP[layer]; - - return findBdst(flg, sigunCode, searchNm) - .then(response => { - console.log(`레이어 ${layer}(${flg}) API 응답:`, response); - - const searchListFormatted = (state.bdst.bdstBase || []).map((building: any) => ({ - searchNm: building.bdstNm, - searchPk: String(building.bdstInfoPk), - dmdCoNm: building.bdstNm, - layerType: flg, - ...building - })); - - return { - layerType: layer, - flg: flg, - data: bdstNames - }; - }) - .catch(error => { - console.error(`레이어 ${layer}(${flg}) 검색 중 오류:`, error); - return { layerType: layer, flg: flg, data: [] }; - }); - }); - - const results = await Promise.all(searchPromises); - console.log("다중 레이어 검색 결과:", results); - - // 모든 결과를 하나의 배열로 합치기 - const allSearchResults = results.reduce((acc, result) => { - const formatted = result.data.map((building: any) => ({ - searchNm: building.bdstNm, - searchPk: String(building.bdstInfoPk), - dmdCoNm: building.bdstNm, - layerType: result.layerType, - flg: result.flg, - ...building.originalData - })); - return [...acc, ...formatted]; - }, [] as any[]); - - console.log("최종 합쳐진 검색 결과:", { - totalCount: allSearchResults.length, - sampleData: allSearchResults.slice(0, 3) - }); - - set((state: any) => ({ - ...state.wrMap, - buildingSearchData: allSearchResults - })); - - } catch (error) { - console.error("다중 레이어 검색 중 오류:", error); - set((state: any) => ({ - ...state, - buildingSearchData: [] - })); - } - } - }; -}; \ No newline at end of file diff --git a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx index 6d9bf8862..e7363b0c1 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/headList.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/headList.tsx @@ -1,4 +1,4 @@ -import type { CommonTableProps, TableUpperProps } from "../../common/type/header"; +import type { CommonTableProps } from "../../common/type/header"; diff --git a/apps/wr/app/store/matDmd/coMatRvw/index.tsx b/apps/wr/app/store/matDmd/coMatRvw/index.tsx index 21239fce3..9e857d4d3 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/index.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/index.tsx @@ -1,13 +1,13 @@ +import { fetchType, getFetchWithCount, putFectch } from "@/components/lib/api"; +import toast from "react-hot-toast"; +import type { CommonTableProps } from "../../common/type/header"; import { constCostHeadListExport, coRvwHeadListExport, coRvwNodeListExport, rateFeeHeadListExport, } from "./headList"; -import type { CommonTableProps } from "../../common/type/header"; import type { DedMatUpdateType, DmdCoReqType } from "./type"; -import { fetchType, getFetch, getFetchWithCount, putFectch } from "@/components/lib/api"; -import toast from "react-hot-toast"; const coRvwHeadList = coRvwHeadListExport; const coRvwNodeList = coRvwNodeListExport; @@ -139,6 +139,7 @@ export const coRvwActionsExport: (set: any) => coRvwActions = (set: any) => { } } catch (e) { toast.error("매칭 검토 저장 오류입니다."); + console.error("coMatRvwUpdate error", e); } }, coMatRvwSearch: async ( diff --git a/apps/wr/app/store/matDmd/coMatRvw/type.tsx b/apps/wr/app/store/matDmd/coMatRvw/type.tsx index 2121c49fe..719071188 100644 --- a/apps/wr/app/store/matDmd/coMatRvw/type.tsx +++ b/apps/wr/app/store/matDmd/coMatRvw/type.tsx @@ -2,7 +2,7 @@ import { z } from "zod"; const DemandInfoSchema = z.object({ dmdInfoSn: z.number(), - dmdInfoFk: z.string().nullish(), + dmdInfoId: z.string().nullish(), dmndTmng: z.coerce.date().nullish(), dmndQty: z.number().nullish(), wntUntprc: z.number().nullish(), @@ -22,10 +22,10 @@ const DemandInfoSchema = z.object({ }); const DemandMatchingSchema = z.object({ - dmdInfoFk: z.string().nullish(), - splyFcltFk: z.string().nullish(), + dmdInfoId: z.string().nullish(), + pbnstRuseFcltId: z.string().nullish(), splyFcltFlg: z.string().nullish(), - pbnstRuseFcltBizFk: z.number().nullish(), + pbnstRuseFcltBizSn: z.number().nullish(), splyBgngDay: z.coerce.date().nullish(), splyEndDay: z.coerce.date().nullish(), splyCpct: z.number().nullish(), @@ -38,7 +38,7 @@ const DemandMatchingSchema = z.object({ }); const DemandCoSchema = z.object({ - dmdInfoPk: z.string().nullish(), + dmdInfoId: z.string().nullish(), dmdCoNm: z.string().nullish(), ctpvCd: z.string().nullish(), sggCd: z.string().nullish(), @@ -70,7 +70,7 @@ export const DmdCoReqSchema = z.object({ cityText: z.string().nullish(), sggText: z.string().nullish(), dmdInfoSn: z.number().default(0), - dmdInfoFk: z.string().default(''), + dmdInfoId: z.string().default(''), dmndTmng: z.coerce.date().nullish(), dmndQty: z.number().nullish(), // null 또는 undefined 허용 blgcOxygDmndQnt: z.number().nullish(), diff --git a/apps/wr/app/store/matDmd/coSttn/excel.tsx b/apps/wr/app/store/matDmd/coSttn/excel.tsx index 39d669664..84c982292 100644 --- a/apps/wr/app/store/matDmd/coSttn/excel.tsx +++ b/apps/wr/app/store/matDmd/coSttn/excel.tsx @@ -1,16 +1,17 @@ -import type { customCoSttnBdst } from "."; +import type { SelectDataType } from "@common/business_components/ui"; +import moment from "moment"; -export const excelCoSttnParsing = (data: customCoSttnBdst[]): string[][] => { +export const excelCoSttnParsing = (data: any[],sidoCode:SelectDataType[] , sggCode:SelectDataType[]): string[][] => { const excelExportData: string[][] = []; - data.forEach((item) => { excelExportData.push([ - String(item.ctpvCd), - String(item.sggCd), + sidoCode.find((sido) => sido.val === item.ctpvCd.toString().trim() )?.text ?? "", + sggCode.find((sgg) => sgg.val === item.sggCd.toString().trim() )?.text ?? "", item.dmdCoNm ?? "", item.daddr ?? "", - String(item.dmdInfoPk ?? ""), - item.telno ?? "" + String(item.dmdInfoId ?? ""), + item.telno ?? "", + moment(item.regDt).format("YYYY-MM-DD") ?? "" ]); }); return excelExportData; diff --git a/apps/wr/app/store/matDmd/coSttn/headList.tsx b/apps/wr/app/store/matDmd/coSttn/headList.tsx index 62c3002ac..b3b87aac8 100644 --- a/apps/wr/app/store/matDmd/coSttn/headList.tsx +++ b/apps/wr/app/store/matDmd/coSttn/headList.tsx @@ -35,7 +35,7 @@ export const coSttHeadListExport: z.infer<typeof sttnHeadListType> = [ visible: true, }, { - id: "dmdInfoPk", + id: "dmdInfoId", title: "사업자번호", visible: true, }, @@ -85,7 +85,7 @@ export const coSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "dmdInfoPk", + id: "dmdInfoId", title: "사업자번호", visible: true, row: 1, diff --git a/apps/wr/app/store/matDmd/coSttn/index.tsx b/apps/wr/app/store/matDmd/coSttn/index.tsx index 5e8baf859..cc1db4566 100644 --- a/apps/wr/app/store/matDmd/coSttn/index.tsx +++ b/apps/wr/app/store/matDmd/coSttn/index.tsx @@ -1,8 +1,7 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; -import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; -import { coSttHeadListExport, coSttNodeListExport } from "./headList"; -import { excelCoSttnParsing } from "./excel"; +import { fetchType, getFetchWithCount } from "@/components/lib/api"; import type { DemandCompType } from "@common/business_components/ui/sdmInsertForm/form"; +import { coSttHeadListExport, coSttNodeListExport } from "./headList"; // 테이블 헤드 리스트 const coSttNodeList = coSttNodeListExport; @@ -53,6 +52,8 @@ export const coSttnActionsExport: (set: any) => coSttnActions = ( `/reuseFc/request/${pageNo}/${pageCnt}/${con}` ); + console.log('coSttnRes ', coSttnRes) + set((state: coSttnState) => { return { ...state, @@ -75,14 +76,13 @@ export const coSttnActionsExport: (set: any) => coSttnActions = ( `/reuseFc/request/${pageNo}/${pageCnt}/${con}` ); if (Number(pageCnt) >= 10000) { - const coExcel = excelCoSttnParsing(coSttnRes.data); set((state: coSttnState) => { return { ...state, coSttn: { ...state.coSttn, - excelList: coExcel, - isInit: false, + excelList: coSttnRes.data, + //isInit: false, }, }; }); @@ -104,7 +104,7 @@ export const coSttnActionsExport: (set: any) => coSttnActions = ( }, coSttnTxtSearch: async (pageNo:string, pageCnt:string, con: string, txt: string) => { try { - const coSttnRes = await getFetch( + const coSttnRes = await getFetchWithCount( fetchType.WR, `/reuseFc/request/${pageNo}/${pageCnt}/${con}/${txt}`) set((state: coSttnState) => { @@ -112,7 +112,8 @@ export const coSttnActionsExport: (set: any) => coSttnActions = ( ...state, coSttn: { ...state.coSttn, - coSttnRes: coSttnRes, + coSttnRes: coSttnRes.data, + coSttnResCount: coSttnRes.count, isInit: false, }}}) } catch (erTxt) { diff --git a/apps/wr/app/store/matDmd/drgtSttn/index.tsx b/apps/wr/app/store/matDmd/drgtSttn/index.tsx index 4211d2d08..ba71f8a7d 100644 --- a/apps/wr/app/store/matDmd/drgtSttn/index.tsx +++ b/apps/wr/app/store/matDmd/drgtSttn/index.tsx @@ -1,7 +1,7 @@ import { fetchType, getFetch, postFectch } from "@/components/lib/api"; +import type { z } from "zod"; import type { CommonTableProps } from "../../common/type/header"; import { drgtHeadListExport, drgtZod } from "./headList"; -import type { z } from "zod"; const drgtHeadList = drgtHeadListExport; @@ -21,7 +21,7 @@ export type drgtState = { type drgtActions = { drgtInit: () => void drgtSearch: (fromDate: string, toDate: string, sido: string[]) => void - drgtModalSearch: (fromDate: string, toDate: string, sgg: string) => void + drgtModalSearch: (fromDate: string, toDate: string, sgg?: string) => void }; export type drgtType = drgtState & drgtActions; @@ -57,11 +57,11 @@ console.log("sido",sido) }, {}); const data = Object.values(statusMap); - const formatStatus = data.map((item) => { + const formatStatus = data.map((item: any) => { const attention = item['관심'] || 0; const caution = item['주의'] || 0; return { - sggNm: item.sggNm, + sggNm: item['sggNm'], normal: String(item['정상'] || 0), caution: String(caution), attention: String(attention), @@ -99,7 +99,6 @@ export const drgtActionsExport: (set: any) => drgtActions = ( const year = today.getFullYear(); const month = String(today.getMonth() + 1).padStart(2, '0'); const formatted = `${year}${month}`; - const fromDate = formatted; const toDate = formatted; //FIXME: 페이지 처음 로딩될때 데이터 보려고 6월로 박아놓음 이거 fromDate로 고치기 @@ -135,7 +134,7 @@ export const drgtActionsExport: (set: any) => drgtActions = ( console.log(e) } }, - drgtModalSearch: async (fromDate: string, toDate: string, sgg: string) => { + drgtModalSearch: async (fromDate: string, toDate: string, sgg?: string) => { try { const drgtMoData = await getFetch( fetchType.WR, diff --git a/apps/wr/app/store/matDmd/index.tsx b/apps/wr/app/store/matDmd/index.tsx index ed8ecd919..cc7094bc7 100644 --- a/apps/wr/app/store/matDmd/index.tsx +++ b/apps/wr/app/store/matDmd/index.tsx @@ -1,55 +1,53 @@ import type { SelectDataType } from "@common/business_components/ui"; - - const selectSido = [ - { text: '서울', val: "1" }, - { text: "인천", val: "2" }, - { text: "부산", val: "3" }, - ]; + { text: "서울", val: "1" }, + { text: "인천", val: "2" }, + { text: "부산", val: "3" }, +]; const selectSgg = [ - { text: '종로구', val: "1" }, - { text: "성북구", val: "2" }, - { text: "강남구", val: "3" }, - ]; - const selectUsg = [ - { text: '민간', val: "1" }, - { text: "공공", val: "2" }, - ]; - const selectYN= [ - { text: 'Y', val: "1" }, - { text: 'N', val: "2" }, - ]; + { text: "종로구", val: "1" }, + { text: "성북구", val: "2" }, + { text: "강남구", val: "3" }, +]; +const selectUsg = [ + { text: "민간", val: "1" }, + { text: "공공", val: "2" }, +]; +const selectYN = [ + { text: "Y", val: "1" }, + { text: "N", val: "2" }, +]; -export type matDmdState ={ dmd:{ +export type matDmdState = { + dmd: { isInit: boolean; - selectSido:SelectDataType[]; - selectSgg:SelectDataType[]; - selectUsg:SelectDataType[]; - selectYN:SelectDataType[]; -}} + selectSido: SelectDataType[]; + selectSgg: SelectDataType[]; + selectUsg: SelectDataType[]; + selectYN: SelectDataType[]; + }; +}; type matDmdActions = { - decrementList: () => void -} + decrementList: () => void; +}; export type matDmdType = matDmdState & matDmdActions; -export const matDmdStateExport:matDmdState= {dmd:{ - isInit:false, - selectSido:selectSido, +export const matDmdStateExport: matDmdState = { + dmd: { + isInit: false, + selectSido: selectSido, selectSgg: selectSgg, selectUsg: selectUsg, - selectYN:selectYN, - - -}} -export const matDmdActionsExport:(set:any)=>matDmdActions=(set: any) => { - return { - decrementList:()=>set( - (state:matDmdState) => { - return ( - {rain:{ - }})} - ) - } -} + selectYN: selectYN, + }, +}; +export const matDmdActionsExport: (set: any) => matDmdActions = (set: any) => { + return { + decrementList: () => + set(() => { + return { rain: {} }; + }), + }; +}; diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx index ad7990cfc..55af81643 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/excel.tsx @@ -1,4 +1,3 @@ -import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; type nameMap = { [key: string]: string; diff --git a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx index 6a5f18247..c268ca1e6 100644 --- a/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx +++ b/apps/wr/app/store/matDmd/ldrmntCoSttn/index.tsx @@ -1,6 +1,6 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; -import { deleteFectch, fetchType, getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; +import { deleteFectch, fetchType, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; +import toast from "react-hot-toast"; import { z } from "zod"; import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; import { ldrmntHeadListExport, ldrmntNodeListExport, ldrmntZod } from "./headList"; @@ -20,6 +20,8 @@ export type ldrmntState = { excelList: ExcelType[]; isInit: boolean; ldrmntRes: customLdrmnt[]; + isLoading: boolean; + ldrmntResCount: number; }; }; @@ -32,9 +34,10 @@ const excelDownList: ExcelType[] = []; type ldrmntActions = { ldrmntRegData: (data: any[]) => void, ldrmntInit: (con: string) => void - ldrmntSearch: (page: number, sggCd: string, total: string, coNm: string) => void; + ldrmntSearch: (isExcel: boolean, page: number, sggCd: string, total: string, coNm: string) => void; ldrmntUpdate: (ldrmntRes: customLdrmnt) => void; ldrmntDelete: () => void; + loadingOpen: (isOpen: boolean) => void }; export type ldrmntType = ldrmntState & ldrmntActions; @@ -46,6 +49,8 @@ export const ldrmntStateExport: ldrmntState = { excelList: [], isInit: false, ldrmntRes: ldrmntRes, + isLoading: false, + ldrmntResCount: 1, }, }; @@ -55,7 +60,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( return { ldrmntInit: async (con: string) => { try { - const ldrmntRes = await getFetch( + const ldrmntRes = await getFetchWithCount( fetchType.WR, `/reuseFc/request/temp/1/20/${con}` ); @@ -65,7 +70,8 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ...state, ldrmnt: { ...state.ldrmnt, - ldrmntRes: ldrmntRes, + ldrmntRes: ldrmntRes.data, + ldrmntResCount: ldrmntRes.count, isInit: false, excelList: excelDownList, }, @@ -75,33 +81,32 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( console.log(e) } }, - ldrmntRegData: async (data) => { - try { - const response = await postFectch( - "/reuseFc/request/temp", - data, - fetchType.WR - ); - - console.log('response ', response) - - if (response.status === 200) { - ToastFormUi({ - body: "잠재수요처 등록이 완료되었습니다. ", - title: "잠재수요처 등록", - }); - - } - } catch (e) { - console.log(e) - ToastFormUi({ - body: "잠재수요처 등록이 실패하였습니다. ", - title: "잠재수요처 등록", - }); - - } + loadingOpen: (isOpen) => { + return set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: isOpen, + }, + }; + }); }, - ldrmntSearch: async (page: number, total: string, sggCd: string, coNm: string) => { + ldrmntRegData: async (data) => { + await deleteFectch( + `/reuseFc/request/temp`, + ); + + const response = await postFectch( + "/reuseFc/request/temp", + data, + fetchType.WR + ); + + console.log('response ', response) + + }, + ldrmntSearch: async (isExcel: boolean, page: number, total: string, sggCd: string, coNm: string) => { let searchUrl = ""; if (sggCd !== "") { @@ -112,14 +117,14 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( } } try { - const ldrmntRes = await getFetch( + const ldrmntRes = await getFetchWithCount( fetchType.WR, searchUrl ); - - if (Number(total) > 5000) { - let excelDownList: ExcelType[] = []; - ldrmntRes.forEach((item: customLdrmnt) => { + console.log("알이에스", ldrmntRes) + if (isExcel) { + const excelDownList: ExcelType[] = []; + ldrmntRes.data.forEach((item: customLdrmnt) => { excelDownList.push({ ctpvCd: item.ctpvCd, sggCd: item.sggCd, @@ -135,7 +140,7 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ldrmnt: { ...state.ldrmnt, excelList: excelDownList, - + ldrmntResCount: ldrmntRes.count, }, }; }); @@ -146,7 +151,8 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( ...state, ldrmnt: { ...state.ldrmnt, - ldrmntRes: ldrmntRes, + ldrmntRes: ldrmntRes.data, + ldrmntResCount: ldrmntRes.count, isInit: false, }, }; @@ -157,32 +163,48 @@ export const ldrmntActionsExport: (set: any) => ldrmntActions = ( } }, ldrmntUpdate: async (ldrmntRes: customLdrmnt) => { + if(ldrmntRes) try { ldrmntRes.rgtr = TEST_UUID; - const response = await putFectch( + const res = await putFectch( `/reuseFc/request/temp`, ldrmntRes ); - return set((state: ldrmntState) => ({ - ...state, - ldrmnt: { - ...state.ldrmnt, - ldrmntRes: ldrmntRes, - }, - })); - + if (res.ok) { + toast.success("잠재수요처 상세정보가 수정되었습니다.",) + } } catch (error) { console.error("Error ldrmntUpdate:", error); + toast.error("잠재수요처 상세정보 수정에 실패하였습니다.") } }, ldrmntDelete: async () => { try { - const response = await deleteFectch( + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: true, + }, + }; + }); + await deleteFectch( `/reuseFc/request/temp`, ); } catch (error) { + console.log("error", error) + set((state: ldrmntState) => { + return { + ...state, + ldrmnt: { + ...state.ldrmnt, + isLoading: false, + }, + }; + }); console.error("Error ldrmntDelete:", error); } }, diff --git a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx index 5a2ad235e..5ae2e67b4 100644 --- a/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx +++ b/apps/wr/app/store/matDmd/ruseCaseMng/index.tsx @@ -1,7 +1,7 @@ -import { fetchType, getFetch, getFetchWithCount, postFectch } from "@/components/lib/api"; +import { fetchType, getFetchWithCount, postFectch } from "@/components/lib/api"; +import { toast } from "react-hot-toast"; import type { TableUpperProps } from "../../common/type/header"; import { ruseCaseHeadListExport } from "./headList"; -import { toast } from "react-hot-toast"; export type ruseCaseState = { ruseCaseMng: { ruseHeadList:TableUpperProps[]; diff --git a/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx b/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx index cfd991b4d..65f2d2730 100644 --- a/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx +++ b/apps/wr/app/store/matDmd/ruseRvwHstry/index.tsx @@ -1,14 +1,11 @@ -import type { z } from "zod"; -import type { sttnHeadListType } from "../coSttn/headList"; -import type { - CommonTableProps, - TableUpperProps, -} from "../../common/type/header"; -import { ruseHstryHeadListExport } from "./headList"; -import { fetchType, getFetch, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; -import type { DmdCoReqType } from "../coMatRvw/type"; +import { fetchType, getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; import toast from "react-hot-toast"; +import type { + TableUpperProps +} from "../../common/type/header"; import { TEST_UUID } from "../../ruseFcltMng/fcltReg/rainReg"; +import type { DmdCoReqType } from "../coMatRvw/type"; +import { ruseHstryHeadListExport } from "./headList"; const ruseHistHeadList = ruseHstryHeadListExport; @@ -72,7 +69,7 @@ type ruseHstryActions = { endYear: string, sggCd: string ) => void; - ruseRvwComplete:( data: Number[]) => void; + ruseRvwComplete:( data: number[]) => void; }; const irvwHistInit = async ( @@ -81,7 +78,7 @@ const irvwHistInit = async ( startYear: string, endYear: string, ) => { - let url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; + const url = `/reuseFc/request/infoList/Matched/${pageNo}/${pageCnt}/${startYear}/${endYear}`; // console.log("sggCd ", sggCd); // if (sggCd) { @@ -102,7 +99,6 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( pageCnt: number, startYear: string, endYear: string, - sggCd?: string ) => { const rvwHistRes = await irvwHistInit( pageNo, @@ -213,7 +209,7 @@ export const ruseHstryActionsExport: (set: any) => ruseHstryActions = ( console.log(" error ", e); } }, - ruseRvwComplete: async (data: Number[]) => { + ruseRvwComplete: async (data: number[]) => { try { const complet = await postFectch( `/reuseFc/request/completeCheck`, diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx index 58e8d6bf0..a0cde9d80 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/excel.tsx @@ -1,7 +1,6 @@ +import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { SelectDataType } from "@common/business_components"; import type { rainChkZodType } from "."; -import { TEST_UUID } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { buildingType } from "../../../common/code/index"; export const useTypes = [ "조경용수", "청소화장실용수", @@ -13,7 +12,7 @@ export const useTypes = [ ]; export type Buildingtype = { - bdstInfoPk: number; + bdstInfoSn: number; ctpvCd: 1; sggCd: 1001; daddr: "string3"; @@ -35,7 +34,7 @@ export const buildingToExcelType = ( buildings.forEach((building) => { useTypes.forEach((useType) => { excelData.push([ - building.bdstInfoPk.toString(), + building.bdstInfoSn.toString(), sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) ?.text || "", sggCdoe.find((sido) => sido.val === building.sggCd.toString()) @@ -85,6 +84,7 @@ export const buildingToExcelType = ( }; export const excelToRainChkData = (excelData: any, year: string) => { + // const errors: string[] = []; const rainChkgdData: rainChkZodType[] = excelData.map((item: any) => { if (item["점검일"] !== undefined) { const checkYmd = item["점검일"].replace(/\./g, "") @@ -106,10 +106,9 @@ export const excelToRainChkData = (excelData: any, year: string) => { flg: "RNB", }; }); - return { - - bdstRuseFcltFk: Number(item["NO"]), + bdstNm:item["시설명"] ?? "", + bdstRuseFcltSn: Number(item["NO"]), chckYmd: checkYmd, spwtPositn: item["유량측정방법"] ?? "", rgtr: TEST_UUID, @@ -133,5 +132,69 @@ export const excelToRainChkData = (excelData: any, year: string) => { }; } }).filter((el: any) => el !== undefined); + return rainChkgdData; + // // ✨ 오류 검사 - 가공된 데이터 기준 + // const isInvalidNumber = (val: any) => + // val !== undefined && val !== null && val !== "" && isNaN(Number(val)); + + // const isInvalidDate = (val: any) => + // typeof val === "string" && !/^\d{4}\.\d{2}\.\d{2}$/.test(val.trim()); + + // const buildErrorMessage = (item: any, issues: string[]): string => { + // const 시설명 = item.bdstNm ?? ""; + // const 점검일 = item.chckYmd ?? ""; + // const 이용용도 = item.utztnUsgCd ?? ""; + // return `시설명: ${시설명}, 점검일: ${점검일}, 이용용도: ${이용용도} (=> ${issues.join(", ")})`; + // }; + + // if (rainChkgdData.length > 0) { + // rainChkgdData.forEach((rain: any) => { + // const item = rain.__origin; // 원본 item + // const issues: string[] = []; + + // if (rain.chckYmd && isInvalidDate(rain.chckYmd)) { + // issues.push(`점검일: 날짜 형식 아님 (${rain.chckYmd})`); + // } + + // if (rain.vltnDt && isInvalidDate(rain.vltnDt)) { + // issues.push(`과태료 부과일(위반일): 날짜 형식 아님 (${rain.vltnDt})`); + // } + + // // [ + // // "연간운영비(원/년)", "PH", "탁도", "총대장균군수", "과태료부과금액(천원)" + // // ].forEach((key) => { + // // if (isInvalidNumber(item[key])) { + // // issues.push(`${key}: 숫자 형식 아님 (${item[key]})`); + // // } + // // } + + // // ); + + // for (let i = 1; i <= 12; i++) { + // const month = `${i}월`; + // if (isInvalidNumber(item[`대체_${month}`])) { + // issues.push(`대체_${month}: 숫자 형식 아님 (${item[`대체_${month}`]})`); + // } + // if (isInvalidNumber(item[`빗물_${month}`])) { + // issues.push(`빗물_${month}: 숫자 형식 아님 (${item[`빗물_${month}`]})`); + // } + // } + + // if (issues.length > 0) { + // errors.push(buildErrorMessage(item, issues)); + // } + // }); + // } + + // if (errors.length > 0) { + // return { rainChkgdData: [], errors }; + // } + + // return { rainChkgdData, errors: [] }; + + // return rainChkgdData; }; + + + diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx index 3cf1b5b11..e53c6b374 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList.tsx @@ -2,7 +2,7 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import { z } from "zod"; export const chkgdRegExcel = z.object({ - bdstInfoPk: z.number().default(111111111), + bdstInfoSn: z.number().default(111111111), chckYr: z .string() .default("") @@ -21,7 +21,7 @@ export const chkgdRegExcel = z.object({ }); export const guideDetail = z.object({ - chkgdnFk: z.number().nullable(), + chkgdnSn: z.number().nullable(), utztnUsgCd: z.string(), chckYmd: z.string(), ym: z.string(), @@ -30,8 +30,8 @@ export const guideDetail = z.object({ flg: z.string(), }); export const rainChkZod = z.object({ - chkgdnPk: z.number().nullable(), - bdstRuseFcltFk: z.number(), + chkgdnSn: z.number().nullable(), + bdstRuseFcltSn: z.number(), chckYmd: z.string(), cityText:z.string().nullish(), sggText:z.string().nullish(), @@ -45,7 +45,7 @@ export const rainChkZod = z.object({ guideDetails: z.array(guideDetail), building: z .object({ - bdstInfoPk: z.number(), + bdstInfoSn: z.number(), ctpvCd: z.number(), sggCd: z.number(), daddr: z.string().nullable(), @@ -60,7 +60,7 @@ export const rainChkZod = z.object({ .nullable(), rainyDetails: z.array( z.object({ - chkgdnFk: z.number().nullable(), + chkgdnSn: z.number().nullable(), utztnUsgCd: z.string(), ph: z.number().nullable(), trbt: z.number().nullable(), diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx index 069f1f760..36e3b1812 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rainChkgdn/index.tsx @@ -68,14 +68,14 @@ type rainChkgdnActions = { sggCd: string, searchTxt: string ) => void; - rainChkDetilUpdate(rainChk: rainChkZodType[]): Promise<void>; + rainChkDetilUpdate(rainChk: rainChkZodType[] ,year:string) : Promise<void>; rainChkGuidUpdate(rainChk: rainChkZodType): Promise<void>; rainChkExcelDownload( sidoCode: SelectDataType[], sggCode: SelectDataType[] ): Promise<void>; - rainChkExcelDataUPload(excelData: rainChkZodType[]): Promise<void>; - rainChkDelete(chkgdnPks: number[]): Promise<void>; + rainChkExcelDataUPload(excelData: rainChkZodType[] ,year :string) : Promise<void>; + rainChkDelete(chkgdnSns: number[] ,year :string): Promise<void>; rainChkHeadChange: (rainChkgdn: rainChkgdnState, isEdit: boolean) => void; rainChkNmSearch: ( pageNo: number, @@ -107,7 +107,7 @@ export const rainChkgdnStateExport: rainChkgdnState = { }, }; -const makeMdfrChk = (data: rainChkZodType[], type: string, toDo: string) => { +const makeMdfrChk = (data: rainChkZodType[], type: string) => { const chData = data.map((item) => { item.mdfr = TEST_UUID; item.rgtr = TEST_UUID; @@ -165,17 +165,16 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( }, })); }, - rainChkExcelDataUPload: async (excelData: rainChkZodType[]) => { + rainChkExcelDataUPload: async (excelData: rainChkZodType[] ,year:string) => { set((state: rainChkgdnType) => ( { rainChkgdn: { ...state.rainChkgdn, isLoading: true } })); try { const res = await postFectch("/reuseChk/rainy", excelData); if (res.status === 200) { - const currentYear = new Date().getFullYear().toString(); const rainChkRes = await initFetch( 1, rainPageSize, - currentYear, + year, commonCd ); set((state: rainChkgdnState) => ({ @@ -255,20 +254,19 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( console.log(error); } }, - rainChkDetilUpdate: async (rainChk: rainChkZodType[]) => { + rainChkDetilUpdate: async (rainChk: rainChkZodType[] ,year:string) => { try { - const chData = await makeMdfrChk(rainChk, "rain", "rainDetil"); + const chData = await makeMdfrChk(rainChk, "rain"); const res = await putFectch("/reuseChk/rainy/list", chData); if (res) { toast.success( "지도점검 대체수 및 밋물이용량 수정이 완료되었습니다. " ); - const currentYear = new Date().getFullYear().toString(); const rainChkRes = await initFetch( 1, rainPageSize, - currentYear, + year, "41" ); return set((state: rainChkgdnState) => ({ @@ -314,21 +312,21 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( } } catch (error) { + console.log(' 지도점검 수질 및 과태료 수정 오류', error) toast.error("지도점검 수질 및 과태료 수정 오류입니다."); } }, - rainChkDelete: async (chkgdnPks: number[]) => { + rainChkDelete: async (chkgdnSns: number[] ,year :string) => { try { - const res = await deleteFectch(`/reuseChk/rainy`, chkgdnPks); + const res = await deleteFectch(`/reuseChk/rainy`, chkgdnSns); if (res) { toast.success("삭제가 완료되었습니다. "); - const currentYear = new Date().getFullYear().toString(); const rainChkRes = await initFetch( 1, rainPageSize, - currentYear, + year, "41" ); return set((state: rainChkgdnState) => ({ @@ -344,6 +342,8 @@ export const rainChkgdnActionsExport: (set: any) => rainChkgdnActions = ( } } catch (error) { + console.log(' 삭제시 오류가 발생하였습니다', error) + toast.error("삭제시 오류가 발생하였습니다.. "); } }, diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx index 1364d6660..aa79a2b10 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/excel.tsx @@ -16,7 +16,7 @@ export const rswtMakeExcelSample = ( buildings.forEach((building) => { useTypes.forEach((useType) => { excelSite.guideDetail.push([ - building.bdstInfoPk.toString(), + building.bdstInfoSn.toString(), sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) ?.text || "", sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text || @@ -62,7 +62,7 @@ export const rswtMakeExcelSample = ( buildings.forEach((building) => { useTypes.forEach((useType) => { excelSite.polutions.push([ - building.bdstInfoPk.toString(), + building.bdstInfoSn.toString(), sidoCode.find((sido) => sido.val === building.ctpvCd.toString()) ?.text || "", sggCdoe.find((sido) => sido.val === building.sggCd.toString())?.text || @@ -146,7 +146,7 @@ export const excelToRswtGuideData = (excelData: any, year: string) => { }); return { - bdstRuseFcltFk: Number(item["NO"]), + bdstRuseFcltSn: Number(item["NO"]), operMngCd: item["운영관리형태"], anlOperCst: Number(item["연간운영비(원/년)"]) ?? 0, prcsCpct: item["처리용량(m³)"], @@ -164,7 +164,7 @@ export const excelToRswtGuideData = (excelData: any, year: string) => { return rainChkgdData; }; -export const excelToRswtPolution = (excelData: any, year: string) => { +export const excelToRswtPolution = (excelData: any) => { const rainChkgdData: rswtChkZodType[] = excelData .map((item: any) => { if (item["점검일"] !== undefined) { @@ -177,7 +177,7 @@ export const excelToRswtPolution = (excelData: any, year: string) => { const makePoluttion = Array.from({ length: 4 }, (_, i) => { - let quarter = `${i+1}`; + const quarter = `${i+1}`; const grssClfgUswtr = item[`${quarter}분기_총대장균군수`]; const combResdch = item[`${quarter}분기_결합잔류염소`]; const trbt = item[`${quarter}분기_탁도`]; @@ -209,7 +209,7 @@ export const excelToRswtPolution = (excelData: any, year: string) => { }); return { - bdstRuseFcltFk: Number(item["NO"]), + bdstRuseFcltSn: Number(item["NO"]), chckYmd: checkYmd, utztnUsgCd: item["이용용도"], operMngCd: item["운영관리형태"], diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx index c9fc9f078..c9136f4a4 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList.tsx @@ -19,8 +19,8 @@ export type polutionType = { edit?:boolean }; const reuseBuildingZod = z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), + bdstInfoSn: z.number().nullish(), instlCmptnDt: z.string().nullable(), // Assuming it's a date string or null instlCst: z.number(), operMngCd: z.string().nullable(), @@ -41,7 +41,7 @@ const reuseBuildingZod = z.object({ }); const buildingZod = z.object({ - bdstInfoPk: z.number().nullable(), + bdstInfoSn: z.number().nullable(), ctpvCd: z.number(), sggCd: z.number(), daddr: z.string().nullable(), @@ -75,7 +75,7 @@ export const rswtrPolutionsZode = z.object({ export const rswtrDetailsZod = z.object({ chkgdnDtlPk: z.string().nullish(), - chkgdnFk: z.string().nullish(), + chkgdnSn: z.string().nullish(), utztnUsgCd: z.string(), vltnDt: z.string(), vltnMttr: z.string(), @@ -87,8 +87,8 @@ export const rswtrDetailsZod = z.object({ }) export const rswtChkgdZod = z.object({ - chkgdnPk: z.number().nullish(), - bdstRuseFcltFk: z.number().nullish(), + chkgdnSn: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), chckYmd: z.string(), prcsCpct: z.number(), dtfcltCpct: z.number(), diff --git a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx index 4f647da1e..5f72998d1 100644 --- a/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx +++ b/apps/wr/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/index.tsx @@ -78,9 +78,9 @@ type rswtChkgdnActions = { sggCode: SelectDataType[] ): Promise<void>; rswtChkExceDataUpload: (excelData: rswtChkZodType[]) => void; - rswtChkDelete: (chkgdnPks: number[]) => void; - rswtChkDetilsUpdate: (rswtChkDetails: rswtrChkDetailsZodType[]) => void; - rswtChkPolAndGuide: (chkGdnPk: number) => void; + rswtChkDelete: (chkgdnSns: number[] ,year:string) => void; + rswtChkDetilsUpdate: (rswtChkDetails: rswtrChkDetailsZodType[] ,year:string) => void; + rswtChkPolAndGuide: (chkgdnSn: number) => void; rswtChkPolInit: () => void; rwstPolAndGuideUpdate: (rswtChk: rswtChkZodType[]) => void; rswtChkHeadChange: (rswtChkgdn: rswtChkgdnState, isEdit: boolean) => void; @@ -189,7 +189,6 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( try { const rswtChkRes = await initFetch(pageNo, cnt, year, sggCd); - console.log("rswtChkRes", rswtChkRes) set((state: rswtChkgdnState) => ({ ...state, @@ -201,7 +200,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }, })); } catch (error) { - // console.log(error); + console.error(error); // set((state: rswtChkgdnType) => ({ // rswtChkgdn: { ...state.rswtChkgdn, isInit: true }, // })); @@ -271,7 +270,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( } }, - rswtChkDetilsUpdate: async (rswtChk: rswtrChkDetailsZodType[]) => { + rswtChkDetilsUpdate: async (rswtChk: rswtrChkDetailsZodType[] ,year:string) => { try { const chData = await makeMdfrChk(rswtChk); @@ -279,8 +278,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( if (res.ok) { toast.success("지도점검 과태료 수정이 완료되었습니다. ",) } - const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, year, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { @@ -295,15 +293,14 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( } }, - rswtChkDelete: async (chkgdnPks: number[]) => { + rswtChkDelete: async (chkgdnSns: number[] ,year:string) => { try { - const res = await deleteFectch(`/reuseChk/reuseWater`, chkgdnPks); + const res = await deleteFectch(`/reuseChk/reuseWater`, chkgdnSns); if (res) { toast.success("삭제가 완료되었습니다.") } - const currentYear = new Date().getFullYear().toString(); - const rswtChkRes = await initFetch(1, rswtPageSize, currentYear, "0"); + const rswtChkRes = await initFetch(1, rswtPageSize, year, "0"); return set((state: rswtChkgdnState) => ({ ...state, rswtChkgdn: { @@ -314,13 +311,14 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( })); } catch (error) { toast.error("삭제 오류입니다.") + console.error(error); } }, - rswtChkPolAndGuide: async (chkGdnPk: number) => { + rswtChkPolAndGuide: async (chkgdnSn: number) => { try { const rswtChkPolGuide = await getFetch( "wr", - `/reuseChk/reuseWater/${chkGdnPk}` + `/reuseChk/reuseWater/${chkgdnSn}` ); return set((state: rswtChkgdnState) => ({ @@ -331,9 +329,7 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( }, })); } catch (error) { - - - + console.error(error); } }, rswtChkPolInit: () => { @@ -345,13 +341,15 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( rswtChkPolGuide: undefined, }, })); - } catch (error) {} + } catch (error) { + console.error(error); + } }, rwstPolAndGuideUpdate: async (rswtChk: rswtChkZodType[]) => { try { const chData = await makeMdfrChk(rswtChk); const res = await putFectch( - `/reuseChk/reuseWater/${rswtChk[0]?.chkgdnPk}`, + `/reuseChk/reuseWater/${rswtChk[0]?.chkgdnSn}`, chData[0] ); if (res.ok) { @@ -391,7 +389,9 @@ export const rswtChkgdnActionsExport: (set: any) => rswtChkgdnActions = ( rswtDetailHeadList: rswtDetailHeadList, }, })); - } catch (e) {} + } catch (e) { + console.error(e); + } }, }; }; diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/excel.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/excel.tsx index d8160cab9..c75011361 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/excel.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/excel.tsx @@ -23,7 +23,7 @@ type NameMap = { }; -export const excelToPbnPrfData = (excelData: JSON[], year: string,pbnstRuseFcltFk:string) => { +export const excelToPbnPrfData = (excelData: JSON[], year: string,pbnstRuseFcltId:string) => { // 월별 데이터 하나로 병합 const merged = {} as any; excelData.forEach((item: any) => { @@ -46,7 +46,7 @@ export const excelToPbnPrfData = (excelData: JSON[], year: string,pbnstRuseFcltF return({ ...(item as object), - pbnstRuseFcltFk:pbnstRuseFcltFk, + pbnstRuseFcltId:pbnstRuseFcltId, rgtr: TEST_UUID, mdfr: TEST_UUID, }) diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx index abde1778f..0e19fe52b 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/headList.tsx @@ -4,7 +4,7 @@ import type { TableUpperProps } from "../../common/type/header"; export const pbnPrfRegExcelZod = z.object({ ym: z.string().default(""), bscFctNm: z.string().default(""), - pbnstRuseFcltFk: z.string(), + pbnstRuseFcltId: z.string(), pbnstRuseFcltNm: z.string().default(""), file: z.instanceof(File).optional(), }); @@ -14,7 +14,7 @@ export const pbnstPrfmncHeadListExport: TableUpperProps[] = [ { id: "gugun", title: "시군구" }, { id: "bscFctNm", title: "시설명" }, { id: "ruseUtztnFcltNm", title: "재이용시설명" }, - { id: "pbnstRuseFcltPk", title: "재이용시설코드" }, + { id: "pbnstRuseFcltId", title: "재이용시설코드" }, ]; export const monthHeadListExport: TableUpperProps[] = [ diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx index 387f56eb7..fbdd4fba6 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/index.tsx @@ -3,7 +3,6 @@ import { pbnstPrfmncHeadListExport, monthHeadListExport } from "./headList"; import type { pubHasuType } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; import type { FcPrfType, PrfType } from "./type"; import type { TableUpperProps } from "../../common/type/header"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import toast from "react-hot-toast"; const pbnstPrfmncHeadList = pbnstPrfmncHeadListExport; @@ -15,7 +14,8 @@ export type pbnstPrfmncState = { pbnstPrfmncHeadList: TableUpperProps[]; monthHeadList: TableUpperProps[]; prfmncRes: FcPrfType[]; - excelList: Number[]; + prfmncResCount:number; + excelList: number[]; pageKey:number }; }; @@ -26,6 +26,7 @@ export const pbnstPrfmncStateExport: pbnstPrfmncState = { pbnstPrfmncHeadList: pbnstPrfmncHeadList, monthHeadList: monthHeadList, prfmncRes: [], + prfmncResCount:1, excelList: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], pageKey:1 }, @@ -34,27 +35,30 @@ export const pbnstPrfmncStateExport: pbnstPrfmncState = { export type pbnstPrfmncType = pbnstPrfmncState & pbnstPrfmncActions; type pbnstPrfmncActions = { - prfmncHasuInit: (page: number, sggOrCity: string) => void; - prfmnRegData: (page:number,sggOrCity:string, data: PrfType) => void; + prfmncHasuInit: (page: number, sggOrCity: string ,year:string) => void; + prfmncHasuNmSearch: (page: number, sggOrCity: string , txt:string ,year:string) => void; + prfmnRegData: (page:number,sggOrCity:string, data: PrfType,year:string) => void; }; -const checkWrRegList = async () => { - const wrRegList = await getFetch("wr", `/reuseFc/pubDetailList`); +const checkWrRegList = async (year:string) => { + const url =`/reuseFc/pubDetailList` + if(year&& year.length>0){ + // url+=`/${year}` + } + const wrRegList = await getFetch("wr", url); return wrRegList; }; -const hasuListFetch = async (page: number, sggOrCity: string) => { - const checkWrRegListRes = await checkWrRegList(); +const hasuListFetch = async (page: number, sggOrCity: string , year:string,searchNm?:string ) => { + const checkWrRegListRes = await checkWrRegList(year); const rainRes = await postFectch( `/prcsFclt/ruseInfo/${page ? page : 1}/10/A/${sggOrCity ? sggOrCity : "11"}/0/1/SW`, checkWrRegListRes?.fcltCds, fetchType.COMMON ); - - - const findData = rainRes.data.map((item: pubHasuType) => { + let findData = rainRes.data.map((item: pubHasuType) => { const data = checkWrRegListRes?.fcPrfList.find( (fclt: FcPrfType) => - fclt.pbnstRuseFcltPk.substring(0, 11) === item?.bscFctCd + fclt.pbnstRuseFcltId.substring(0, 11) === item?.bscFctCd ); if(data !==undefined){ return( { @@ -64,26 +68,32 @@ const hasuListFetch = async (page: number, sggOrCity: string) => { bscFctNm: item.bscFctNm, bscFctCd: item.bscFctCd, ruseUtztnFcltNm: data.ruseUtztnFcltNm, - pbnstRuseFcltPk: data.pbnstRuseFcltPk, + pbnstRuseFcltId: data.pbnstRuseFcltId, prfList: data.prfList, }); } - }); + }).filter(Boolean); // undefined 값을 제거합니다. - return findData; + if(searchNm){ + + findData= findData.filter((ruse:any) => ruse.ruseUtztnFcltNm.includes(searchNm)) + } + + return {data:findData, count:findData.length}; }; export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( set: any ) => { return { - prfmncHasuInit: async (page: number, sggOrCity: string) => { + prfmncHasuInit: async (page: number, sggOrCity: string,year:string) => { try { - const prfmncRes = await hasuListFetch(page, sggOrCity); + const prfmncRes = await hasuListFetch(page, sggOrCity, year); return set((state: pbnstPrfmncState) => ({ ...state, prfmnc: { ...state.prfmnc, - prfmncRes: prfmncRes, + prfmncRes: prfmncRes.data, + prfmncResCount: prfmncRes.count, isInit: false, }, })); @@ -91,7 +101,23 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( console.log(errorHasu); } }, - prfmnRegData: async (page:number,sggOrCity:string,data: PrfType) => { + prfmncHasuNmSearch: async (page: number, sggOrCity: string,fcltNm:string ,year:string)=> { + try { + const prfmncRes = await hasuListFetch(page, sggOrCity,fcltNm ,year); + return set((state: pbnstPrfmncState) => ({ + ...state, + prfmnc: { + ...state.prfmnc, + prfmncRes: prfmncRes.data, + prfmncResCount: prfmncRes.count, + isInit: false, + }, + })); + } catch (errorHasu) { + console.log(errorHasu); + } + }, + prfmnRegData: async (page:number,sggOrCity:string,data: PrfType,year:string) => { try { const ressponse = await postFectch( "/reuseFc/pubFcPrf", @@ -102,12 +128,15 @@ export const pbnstPrfmncActionsExport: (set: any) => pbnstPrfmncActions = ( if (ressponse.status === 200) { toast.success("하수재이용 시설 실적 등록이 완료되었습니다."); - const prfmncRes = await hasuListFetch(page, sggOrCity); + const prfmncRes = await hasuListFetch(page, sggOrCity,year) ; + + return set((state: pbnstPrfmncState) => ({ ...state, prfmnc: { ...state.prfmnc, - prfmncRes: prfmncRes, + prfmncRes: prfmncRes.data, + prfmncResCount: prfmncRes.count, isInit: false, pageKey: state.prfmnc.pageKey + 1 }, diff --git a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/type.tsx b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/type.tsx index f6d5ff43f..6723f3922 100644 --- a/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/type.tsx +++ b/apps/wr/app/store/prfmncReg/pbnstPrfmncReg/type.tsx @@ -1,9 +1,22 @@ import { z } from "zod"; -import type { TableUpperProps } from "../../common/type/header"; import { fcOperSchema } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; + + +type Month = `${1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12}월`; + +export type PrfUsageSummary = { + 구분?: string; + usage: string; + 용수명?: string; + total: number; + edit?:boolean +} & Record<Month, number>; + + + export const PrfSchema = z.object({ - pbnstRuseFcltFk: z.string(), + pbnstRuseFcltId: z.string(), ym: z.string(), // 예: "202310" wshwtr: z.number(), coolUswtr: z.number(), @@ -27,7 +40,7 @@ export const PrfSchema = z.object({ }); export const FcPrfSchema = z.object({ - pbnstRuseFcltPk: z.string(), + pbnstRuseFcltId: z.string(), ruseUtztnFcltNm: z.string(), fcltCpct: z.number(), ruseCpct: z.number(), @@ -44,8 +57,9 @@ export const FcPrfSchema = z.object({ export type FcPrfType = z.infer<typeof FcPrfSchema>; export type PrfType = z.infer<typeof PrfSchema>; -export const initValInUsage = [ +export const initValInUsage:PrfUsageSummary[] = [ { + 구분: "장내용수", usage: "wshwtr", 용수명: "세척수", total: 0, @@ -63,6 +77,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "coolUswtr", 용수명: "냉각수", total: 0, @@ -80,6 +95,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "cleanUswtr", 용수명: "청소수", total: 0, @@ -97,6 +113,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "drwtUswtr", 용수명: "식수대", total: 0, @@ -114,6 +131,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "dltnUswtr", 용수명: "희석용수", total: 0, @@ -131,6 +149,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "ithlRswtr", 용수명: "중수도", total: 0, @@ -148,6 +167,7 @@ export const initValInUsage = [ "12월": 0, }, { + 구분: "장내용수", usage: "ithlEtcUswtr", 용수명: "기타", total: 0, @@ -166,8 +186,9 @@ export const initValInUsage = [ }, ]; -export const initValOutUsage = [ +export const initValOutUsage: PrfUsageSummary[] = [ { + 구분: "장외용수", usage: "resn", 용수명: "세척살수용수", total: 0, @@ -185,6 +206,7 @@ export const initValOutUsage = [ "12월": 0, }, { + 구분: "장외용수", usage: "cleanToilUswtr", 용수명: "청소화장실용수", total: 0, @@ -202,6 +224,7 @@ export const initValOutUsage = [ "12월": 0, }, { + 구분: "장외용수", usage: "lndwtr", 용수명: "조경용수", total: 0, @@ -219,6 +242,7 @@ export const initValOutUsage = [ "12월": 0, }, { + 구분: "장외용수", usage: "hydUswtr", 용수명: "친수용수", total: 0, @@ -236,6 +260,7 @@ export const initValOutUsage = [ "12월": 0, }, { + 구분: "장외용수", usage: "ugwtChr", 용수명: "지하수충전", total: 0, @@ -253,6 +278,7 @@ export const initValOutUsage = [ "12월": 0, }, { + 구분: "장외용수", usage: "farmUswtr", 용수명: "농업용수", total: 0, @@ -271,6 +297,7 @@ export const initValOutUsage = [ }, { + 구분: "장외용수", usage: "rvrKeepUswtr", 용수명: "하천등유지용수", total: 0, @@ -289,6 +316,7 @@ export const initValOutUsage = [ }, { + 구분: "장외용수", usage: "indstUswtr", 용수명: "공업용수", total: 0, @@ -307,7 +335,7 @@ export const initValOutUsage = [ }, ]; -export const subTotalObj = { +export const subTotalObj:PrfUsageSummary = { usage: "subtotal", 용수명: "소계", edit: false, @@ -326,7 +354,7 @@ export const subTotalObj = { "12월": 0, }; -export const totalObj = { +export const totalObj:PrfUsageSummary = { usage: "total", 용수명: "총합계", edit: false, diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/excel.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/excel.tsx index 78e0b878f..cf1cd93a5 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/excel.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rainChkgdnSttn/excel.tsx @@ -1,21 +1,7 @@ -import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -type rainSttnExcelType = { - bdstInfoPk: number; - ctpvCd: 1; - sggCd: 1001; - daddr: "string3"; - bdstNm: "string"; - frstArchPrmsnDt: "2025-03-25"; - archArea: 0; - regDt: "2025-04-16"; - rgtr: null; - mdfcnDt: "2025-04-16"; - mdfr: null; -}; export const buildingExcelRainSttn = (excelList: any[]) => { const excelData: string[][] = []; - excelList.forEach((item, index) => { + excelList.forEach((item) => { excelData.push([ String(item.cityText) ?? "", String(item.sggText) ?? "", diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx index 6e6b5730c..55eaf2df1 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/excel.tsx @@ -1,7 +1,7 @@ export const buildingExcelRswtSttn = (excelList: any[]) => { const excelData: string[][] = []; - excelList.forEach((item, index) => { + excelList.forEach((item) => { excelData.push([ String(item.cityText) ?? "", String(item.sggText) ?? "", diff --git a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx index 7891d73fb..0426ed9f5 100644 --- a/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/chkgdnSttn/rswtChkgdnSttn/index.tsx @@ -2,7 +2,7 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { rswtHeadNmExport } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn/headList"; -import { getFetch, getFetchWithCount } from "@/components/lib/api"; +import { getFetchWithCount } from "@/components/lib/api"; import { buildingExcelRswtSttn } from "./excel"; import { rswtChkSttnHeadListExport, rswtDetailSttnHeadListExport } from "./headList"; diff --git a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/headList.tsx b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/headList.tsx index d04ef7b20..9095d96b9 100644 --- a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/headList.tsx +++ b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/headList.tsx @@ -1,5 +1,4 @@ -import { z } from "zod"; -import type { TableUpperProps } from "../../ruseFcltMng/fcltReg/rainReg"; +import type { TableUpperProps } from "../../common/type/header"; export const pbnstPrfmncSttnHeadListExport: TableUpperProps[] = [ { @@ -37,6 +36,7 @@ export const pbnstPrfmncSttnHeadListExport: TableUpperProps[] = [ export const pbnstYearHeadListExport: TableUpperProps[] = [ { + id: "year", title: "년도", colSpan: 3, row: 0 @@ -57,3 +57,25 @@ export const pbnstYearHeadListExport: TableUpperProps[] = [ row: 1 }, ] + + + + + +export const monthSttnHeadListExport: TableUpperProps[] = [ + { id: "구분", title: "구분", mergeCell: true }, + { id: "용수명", title: "용수명" }, + { id: "total", title: "계" }, + { id: "1월", title: "1월" }, + { id: "2월", title: "2월" }, + { id: "3월", title: "3월" }, + { id: "4월", title: "4월" }, + { id: "5월", title: "5월" }, + { id: "6월", title: "6월" }, + { id: "7월", title: "7월" }, + { id: "8월", title: "8월" }, + { id: "9월", title: "9월" }, + { id: "10월", title: "10" }, + { id: "11월", title: "11월" }, + { id: "12월", title: "12월", }, +]; \ No newline at end of file diff --git a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx index db8b6a717..92fcb9b76 100644 --- a/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx +++ b/apps/wr/app/store/prfmncSttn/pbnstPrfmncSttn/index.tsx @@ -1,6 +1,6 @@ import { fetchType, getFetch, postFectch } from "@/components/lib/api"; import type { TableUpperProps } from "../../common/type/header"; -import { pbnstPrfmncSttnHeadListExport, pbnstYearHeadListExport } from "./headList"; +import { monthSttnHeadListExport, pbnstPrfmncSttnHeadListExport, pbnstYearHeadListExport } from "./headList"; import type { FcPrfType, PrfType } from "../../prfmncReg/pbnstPrfmncReg/type"; import type { pubHasuType, selectLabel } from "../../ruseFcltMng/fcltReg/pbnstReg/type"; import type { ReturnType } from "@common/business_components"; @@ -22,6 +22,7 @@ export type pbnstPrfmncSttnState = { isInit: boolean; rawData: any[]; selectYearList: selectLabel[] + monthSttnHeadList:TableUpperProps[]; } } @@ -34,7 +35,8 @@ export const pbnstPrfmncSttnExport: pbnstPrfmncSttnState = { prfmncRes: prfmncRes, isInit: false, rawData: [], - selectYearList: [] + selectYearList: [], + monthSttnHeadList:monthSttnHeadListExport } } @@ -52,14 +54,14 @@ const hasuListFetch = async (page: string, sggOrCity: string) => { const data = checkWrRegListRes.fcPrfList.map((item: FcPrfType) => { const findData = rainRes.data.find( (fclt: pubHasuType) => - fclt.bscFctCd === item.pbnstRuseFcltPk.substring(0, 11) + fclt.bscFctCd === item.pbnstRuseFcltId.substring(0, 11) ); return { sido: findData?.sido, gugun: findData?.gugun, bscFctNm: findData?.bscFctNm, ruseUtztnFcltNm: item.ruseUtztnFcltNm, - pbnstRuseFcltPk: item.pbnstRuseFcltPk, + pbnstRuseFcltId: item.pbnstRuseFcltId, }; }); return data; @@ -78,9 +80,7 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions yearHead.forEach((item: { id?: string; }) => { if (item.id) { item.id = i + item.id; - } - }) if (yearHead[0]) yearHead[0].title = i + "년도" @@ -145,17 +145,16 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions ) let inUsageSum = 0; let outUsageSum = 0; - let usageSum = 0; let year = ""; - const yearsData = [] + const yearsData = [] as any - res.data.forEach((item) => { + res.data.forEach((item : any) => { if (item.prfList.length === 0) { - const year = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출 - const yearVal = { year: year, pbnstRuseFcltPk: item.pbnstRuseFcltPk ?? "", ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" }; - yearVal[year + "inUsage"] = 0; - yearVal[year + "outUsage"] = 0; - yearVal[year + "total"] = 0; + const year: string = ""; // 연도 정보가 없으면 빈 문자열, 필요시 item에서 추출. + const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: item.pbnstRuseFcltId ?? "", ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" }; + yearVal[`${year}inUsage`] = 0; + yearVal[`${year}outUsage`] = 0; + yearVal[`${year}total`] = 0; yearsData.push(yearVal); } item.prfList.forEach((acc) => { @@ -180,29 +179,30 @@ export const pbnstPrfmncSttnActionsExport: (set: any) => pbnstPrfmncSttnActions const yearData = yearsData.find( (yearItem) => yearItem.year === year && - yearItem.pbnstRuseFcltPk == acc.pbnstRuseFcltFk + yearItem.pbnstRuseFcltId == acc.pbnstRuseFcltId ); if (yearData) { - yearData[year + "inUsage"] += inUsageSum; - yearData[year + "outUsage"] += outUsageSum; - yearData[year + "total"] += (inUsageSum + outUsageSum); + yearData[`${year}inUsage`] += inUsageSum; + yearData[`${year}outUsage`] += outUsageSum; + yearData[`${year}total`] += (inUsageSum + outUsageSum); } else { - const yearVal = { year: year, pbnstRuseFcltPk: acc.pbnstRuseFcltFk, ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" }; - yearVal[year + "inUsage"] = inUsageSum; - yearVal[year + "outUsage"] = outUsageSum; - yearVal[year + "total"] = inUsageSum + outUsageSum; + const yearVal: { [key: string]: any } = { year: year, pbnstRuseFcltId: acc.pbnstRuseFcltId, ruseUtztnFcltNm : item.ruseUtztnFcltNm ?? "" }; + yearVal[`${year}inUsage`] = inUsageSum; + yearVal[`${year}outUsage`] = outUsageSum; + yearVal[`${year}total`] = inUsageSum + outUsageSum; yearsData.push(yearVal); } }); }); const resData: any[] = [] pbnstRes.forEach((acc) => { - let data = yearsData.find((item) => item.pbnstRuseFcltPk.substring(0, 11) === acc.bscFctCd) + const data = yearsData.find((item) => item.pbnstRuseFcltId.substring(0, 11) === acc.bscFctCd) if (data) { resData.push({ ...acc, ...data }) } }) + console.log("resData", resData) return set((state: pbnstPrfmncSttnState) => ({ ...state, pbnstPrfmncSttn: { diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx index da1fa6f09..53c18f56d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/headList.tsx @@ -3,7 +3,7 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; export const htdTableHeadList: TableUpperProps[] = [ { id: "cityText", title: "시도" }, { id: "sggText", title: "시군구" }, - { id: "bdstNm", title: "발전소명" }, + { id: "bdstNm", title: "시설명" }, { id: "daddr", title: "위치" }, { id: "frstArchPrmsnDt", title: "준공년도" }, { id: "archArea", title: "건축면적" }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx index 317f68e10..db2b56d30 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/htdflReg/index.tsx @@ -1,21 +1,18 @@ -import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding } from "../rainReg"; +import { getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; +import type { TableUpperProps } from "@/app/store/common/type/header"; +import toast from "react-hot-toast"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; import { - baseReuseBuildingSchema, - chgBuildingSchema, htdflReuseBuildingSchema, - validationMessages, + validationMessages } from "../rainReg/type"; // Import baseReuseBuildingSchema, chgBuildingSchema, validationMessages -import type { TableUpperProps } from "@/app/store/common/type/header"; import { htdTableHeadList } from "./headList"; -import toast from "react-hot-toast"; const hdtflObjSchema = z.object({ htdflFcltPk: z.number().nullish(), - bdstRuseFcltFk: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), etgtType: z .string() .min(1, { message: validationMessages.required("에너지원 종류") }), @@ -64,7 +61,7 @@ const hdtflObjSchema = z.object({ }); export const hdtflZod = z.object({ - bdstInfoPk: z.number().nullish(), + bdstInfoSn: z.number().nullish(), ctpvCd: z.number().default(0), sggCd: z.number().default(0), cityText: z.string().nullish(), @@ -96,6 +93,7 @@ export type htdflFacState = { isInit: boolean; upHeadList: TableUpperProps[]; htdflRes: customHtdflBdst[]; + htdflResCount:number }; }; type htdflFacSActions = { @@ -114,19 +112,18 @@ export const htdflFacStateExport: htdflFacState = { isInit: false, upHeadList: htdTableHeadList, htdflRes: htdflRes, + htdflResCount:1, }, }; const initFetch = async (code: string) => { - - console.log(' initFetch code ', code) - let url = `/drain/facilityList/1/20` + let url = `/drain/facilityList/1/10` url+=`/${code}` - const rswtRes = await getFetch("wr", url); + const rswtRes = await getFetchWithCount("wr", url); return rswtRes; }; export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( @@ -135,15 +132,16 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( return { getHtdflBdstData: async (pageNation: number, code: string | number) => { try { - const rswtRes = await getFetch( + const htdflRes = await getFetchWithCount( "wr", - `/drain/facilityList/${pageNation}/20/${code}` + `/drain/facilityList/${pageNation}/10/${code}` ); return set((state: htdflFacState) => ({ ...state, htdfl: { ...state.htdfl, - htdflRes: rswtRes, + htdflRes: htdflRes.data, + htdflResCount:htdflRes.count, isInit: false, }, })); @@ -159,7 +157,8 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( ...state, htdfl: { ...state.htdfl, - htdflRes: htdflRes, + htdflRes: htdflRes.data, + htdflResCount:htdflRes.count, isInit: false, }, }; @@ -170,29 +169,27 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( }, htdflBdstUpdate: async (data: customHtdflBdst, code: string | number) => { try { - - const chData = await makeMdfr(data); const res = await putFectch("/drain/facility", chData); - if (res.status) { - toast.success("온배수 건축물 수정이 완료되었습니다."); + toast.success("온배수 시설물 수정이 완료되었습니다."); } - - const htdflRes = await getFetch( + const htdflRes = await getFetchWithCount( "wr", - `/drain/facilityList/1/20/${code}` + `/drain/facilityList/1/10/${code}` ); set((state: htdflFacState) => ({ ...state, htdfl: { ...state.htdfl, - htdflRes: htdflRes, + htdflRes: htdflRes.data, + htdflResCount:htdflRes.count, isInit: false, }, })); } catch (errorUpdate) { - toast.error("온배수 건축물 수정 오류입니다.."); + toast.error("온배수 시설물 수정 오류입니다.."); + console.log(errorUpdate); } }, htdflBdstReg: async (data: customHtdflBdst, code: string | number) => { @@ -203,31 +200,33 @@ export const htdflFacActionsExport: (set: any) => htdflFacSActions = ( const chData = makeRstr(data); const res = await postFectch("/drain/facility", chData); if (res.status ===200) { - toast.success("온배수 건축물 등록이 완료되었습니다."); + toast.success("온배수 시설 등록이 완료되었습니다."); } const htdflRes = await initFetch(String(code)); set((state: htdflFacState) => ({ ...state, htdfl: { ...state.htdfl, - htdflRes: htdflRes, + htdflRes: htdflRes.data, + htdflResCount:htdflRes.count, isInit: false, }, })); } catch (errorReg) { - toast.error("온배수 건축물 등록 오류입니다.."); + toast.error("온배수 시설물 등록 오류입니다.."); + console.log(errorReg); } },htdflNmSearch :async(code:string | number, fcltNm:string) =>{ try { - - const htdflRes = await getFetch("wr", `/drain/facilityList/1/20/${code}/${fcltNm}`); + const htdflRes = await getFetchWithCount("wr", `/drain/facilityList/1/10/${code}/${fcltNm}`); set((state: htdflFacState) => { return { ...state, htdfl: { ...state.htdfl, - htdflRes: htdflRes, + htdflRes: htdflRes.data, + htdflResCount:htdflRes.count, isInit: false, }, }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx index d77f4d7f0..84413fbc2 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx @@ -7,15 +7,15 @@ export const pubFacHeadListExport: TableUpperProps[] = [ { id: "bscFctNm", title: "시설명" }, { id: "addr", title: "위치" }, { id: "efflWqltStndrdNm", title: "지역구분" }, - { id: "fctCpc", title: "시설용량" }, + { id: "fctCpc", title: "시설용량(m³/일)" }, { id: "ruse", title: "재이용여부" }, { id: "rswtrYn", title: "등록여부" }, ]; export const pbnstMngUpHeadListExport: TableUpperProps[] = [ { id: "choose", title: "선택", type: "checkbox" }, - { id: "operMthd", title: "운영방식",type: "select", selectData: "ruseMngMtd" }, - { id: "rprtvBzenty", title: "대행업체", edit: true }, + { id: "operMthd", title: "운영방식",type: "select", selectData: "ruseMngMtd" }, + { id: "rprtvBzenty", title: "대행업체", edit: true ,maxLength:10 }, { id: "bgngDt", title: "시작일", @@ -47,10 +47,10 @@ export const pbnstDemandHeadListExport: TableUpperProps[] = [ export const pbnstOrgwtHeadListRxport: TableUpperProps[] = [ { id: "ruseUtztnFcltNm", title: "하수처리장명" }, - { id: "orgwtWtritQnt", title: "원수취수량" }, + { id: "orgwtWtritQnt", title: "원수취수량" , type:'number'}, { id: "tmsYn", title: "하수처리량TMS 전후" }, { id: "dschgFmYn", title: "하수처리장 방류 유량계 전·후​" }, - { id: "dtlPstnExpln", title: "상세위치 설명" }, + { id: "dtlPstnExpln", title: "상세위치", edit: true }, ]; export const fcOrgwtsHeadListExport: TableUpperProps[] = [ { id: "choose", title: "선택", type: "checkbox" }, diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index e4bedff60..493783d8e 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -55,20 +55,17 @@ export type pubFacState = { fcOrgwtsNmList:pubHasuType[]; dmdComList: any[]; apiMessage:string; + pbnstHasuResCount:number }; }; type pubFacActions = { pubHasuInit: (page: string, sggOrCity: string) => void; pbnstRegClick: (pubHasuRes: pubHasuType) => void; - pbnstReg: (txt: string | undefined) => void; + //pbnstReg: (txt: string | undefined) => void; pbnstInsert(pbnstRes: customPbnst): Promise<void>; appendRuseFclt(array: customPbnst[]): void; fileDelete: (atflCd: string) => void; fileDownLoad: (atflCd: string) => void; - //pbnstMngData: (data: customPbnst[]) => void; - //pbnstBizData(data: fcBizType): void; - // getBizCycle: (pbnstObj: customPbnst) => void; - getpbnstInsertIndex: (data: pbnstInsertIndex) => void; pbnstRuseFcltUpdate: (ruseRes: customPbnst[]) => void; pbnstRuseBizUpdate: (ruseRes: fcBizType[]) => void; pubHasuSearch :(page: string, sggOrCity: string , searchTxt:string) => void @@ -95,7 +92,8 @@ export const pubFacStateExport: pubFacState = { pbnsUpdateIndex: {} as pbnstInsertIndex, fcOrgwtsNmList:[], dmdComList: [], - apiMessage:'' + apiMessage:'', + pbnstHasuResCount:1 }, }; @@ -124,11 +122,12 @@ if(searchTxt){ const hasuList = rainRes.data.map((item: any) => { return { ...item, + fctCpc: Number(item.fctCpc) || 0, ruse: item.ruse === false ? "N" : "Y", }; }); - return hasuList; + return {data: hasuList, count:rainRes.count}; }; const initFetch = async (ruseFcltPk: string | undefined) => { @@ -179,13 +178,12 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { pubHasuInit: async (page: string, sggOrCity: string) => { try { const pbnstHasuRes = await hasuListFetch(page, sggOrCity); - - return set((state: pubFacState) => ({ ...state, pbnst: { ...state.pbnst, - pbnstHasuRes: pbnstHasuRes, + pbnstHasuRes: pbnstHasuRes.data, + pbnstHasuResCount:pbnstHasuRes.count, isInit: false, }, })); @@ -200,7 +198,8 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { ...state, pbnst: { ...state.pbnst, - pbnstHasuRes: pbnstHasuRes, + pbnstHasuRes: pbnstHasuRes.data, + pbnstHasuResCount:pbnstHasuRes.count, isInit: false, }, })); @@ -223,22 +222,6 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { console.log(errorHasu); } }, - - pbnstReg: async (txt: string | undefined) => { - try { - const pbnstRes = await hasuListFetch("11", "11"); - return set((state: pubFacState) => ({ - ...state, - pbnst: { - ...state.pbnst, - pbnstRes: pbnstRes, - isInit: false, - }, - })); - } catch (errorHasu) { - console.log(errorHasu); - } - }, pbnstInsert: async (pbnstRes: customPbnst) => { try { @@ -250,13 +233,12 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { toast.success(`${pbnstRes.ruseUtztnFcltNm} 하수재이용 시설이 등록되었습니다.`); } const pbnstHasuRes = await hasuListFetch('1', '0'); - - return set((state: pubFacState) => ({ ...state, pbnst: { ...state.pbnst, - pbnstRes: pbnstHasuRes, + pbnstHasuRes: pbnstHasuRes.data, + pbnstHasuResCount:pbnstHasuRes.count, isInit: false, }, })); @@ -266,44 +248,24 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { },pbnstRuseFcltUpdate : async(ruseRes:customPbnst[])=>{ try { - const response = await putFectch( + await putFectch( `/reuseFc/pubFc`, ruseRes ); - - if(response){ - - toast.success(` 하수재이용 시설 정보가 수정되었습니다.`); - } + } catch (error) { console.error("Error pbnstRuseFcltUpdate:", error); - toast.error(` 하수재이용 시설 정보가 수정오류입니다.`); } } ,pbnstRuseBizUpdate : async(ruseRes:fcBizType[])=>{ try { - console.log('ruseRes ', ruseRes) - const response = await putFectch( + await putFectch( `/reuseFc/pubFcBiz`, ruseRes ); - if(response){ - toast.success(` 하수재이용 시설 사업이 수정되었습니다.`); - } - const pbnstRes = await hasuListFetch("11", "11"); - - return set((state: pubFacState) => ({ - ...state, - pbnst: { - ...state.pbnst, - pbnstRes: pbnstRes, - isInit: false, - }, - })); } catch (error) { console.error("Error pbnstRuseFcltUpdate:", error); - toast.error(` 하수재이용 시설 사업이 수정이 실패되엇습니다..`); } } , getBizCycle: async (pbnstObj: customPbnst) => { @@ -346,60 +308,17 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { }, fileDownLoad: async (atflCd: string) => { try { - const response = await getFetch( + await getFetch( fetchType.CS, `/attach-service/api/v1/atflcd/download/${atflCd}` ); - - if (!response.ok) { - throw new Error(`Error downloading file: ${response.statusText}`); - } } catch (error) { console.error("Error downloading file:", error); + throw new Error(`Error downloading file: ${error}`); + } }, - - // pbnstMngData: (data: customPbnst[]) => { - // if (data.length > 0) { - // } - // return set((state: pubFacState) => { - // state.pbnst.pbnstMngRegData = data; - // state.pbnst.pbnstBizCycle = - // data.length <= 0 - // ? [{ text: "없음", val: "1" }] - // : state.pbnst.pbnstBizCycle; - // return state; - // }); - // }, - - // pbnstBizData: (data: fcBizType) => { - // return set((state: pubFacState) => { - // if (state.pbnst.pbnstMngRegData) { - // const regData = state.pbnst.pbnstMngRegData.find( - // (item) => data.pbnstRuseFcltFk === item.pbnstRuseFcltPk - // ); - // if (regData) { - // const bizIdx = regData.fcBizs.findIndex( - // (item) => item.pbnstRuseFcltBizPk == data.pbnstRuseFcltBizPk - // ); - - // if (bizIdx >= 0) { - // regData.fcBizs[bizIdx] = data; - // const pbnstData = state.pbnst.pbnstMngRegData - // state.pbnst.pbnstMngRegData= [...pbnstData] - - // } - // } - // } - // return state; - // }); - // }, - getpbnstInsertIndex: async (data: pbnstInsertIndex) => { - return set((state: pubFacState) => { - state.pbnst.pbnsUpdateIndex = data; - return state; - }); - }, + appendRuseFclt: async (array: customPbnst[]) => { try { return set((state: pubFacState) => ({ @@ -414,10 +333,9 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { console.log(e); } },getFcOrgwts : async (fcltPkList: string[] ,size:number) => { - let url = `/prcsFclt/ruseInfo/1/${size}/A/0/0/1/SW`; const fcOrgwtsNmList = await postFectch( - url, + `/prcsFclt/ruseInfo/1/${size}/A/0/0/1/SW`, fcltPkList, fetchType.COMMON ); @@ -429,9 +347,7 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { fcOrgwtsNmList:fcOrgwtsNmList.data??[] }, })); - - - } + }; }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx index ad3496a54..f8bb81b88 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/type.tsx @@ -1,5 +1,4 @@ import { z } from "zod"; -import { TEST_UUID } from "../rainReg"; export type customPbnst = z.infer<typeof pbnstRegZod>; @@ -31,12 +30,12 @@ export type publicReuseFacilityType = { area?: string; reuse?: string; register?: string; - swtrmtFcltFk: string; + swtrmtFcltId: string; }; export type ruseFcltType = { - swtrmtFcltFk: string; - pbnstRuseFcltPk: string; + swtrmtFcltId: string; + pbnstRuseFcltId: string; fcltNm: string; fcltCpct: number; swtrmtCpct: number; @@ -45,7 +44,7 @@ export type ruseFcltType = { }; export type PbnstDemandComType = { - dmdInfoPk: string | ""; + dmdInfoId: string | ""; bzmnNo: string | ""; dmdCoNm: string | ""; daddr: string | ""; @@ -57,10 +56,10 @@ export type PbnstDemandComType = { dmdAplyPswd: string | ""; splyCpct: number | 0; splyFmYn: string | "Y"; - // dmdInfoFk:string|'' + // dmdInfoId:string|'' }; -const pubHasuZod = z.object({ +export const pubHasuZod = z.object({ choose: z.boolean().default(false), bscFctCd: z.string(), sido: z.string().default(""), @@ -86,7 +85,7 @@ const zNumNullish = zNum.nullish(); const zNumDefaultZero = zNum.default(0).nullish(); const pplInstlSchema = z.object({ - ruseFcltBizFk: zNumNullish, + pbnstRuseFcltBizSn: zNumNullish, choose: z.boolean().default(false), pdmt: z.string().default(""), ppMqlt: z.string().default(""), @@ -94,7 +93,7 @@ const pplInstlSchema = z.object({ }); const fcFileSchema = z.object({ - ruseFcltFk: z.string().nullish(), + pbnstRuseFcltId: z.string().nullish(), fileTkn: z.string(), filePath: z.string(), fileKnd: z.string(), @@ -105,8 +104,8 @@ const fcFileSchema = z.object({ }); export const fcOperSchema = z.object({ - pbnstRuseFcltOperInfoPk: zNumNullish, - pbnstRuseFcltFk: z.string().nullish(), + pbnstRuseFcltOperInfoSn: zNumNullish, + pbnstRuseFcltId: z.string().nullish(), operMthd: z.string(), rprtvBzenty: z.string(), bgngDt: zDateDefaultNow, @@ -119,8 +118,8 @@ export const fcOperSchema = z.object({ }); const fcOrgwtSchema = z.object({ - pbnstRuseFcltBizFk: zNumNullish, - swtrmtFcltFk: z.string().nullish(), + pbnstRuseFcltBizSn: zNumNullish, + swtrmtFcltId: z.string().nullish(), orgwtWtritQnt: zNum, tmsYn: z.enum(["Y", "N"]).default("N"), dschgFmYn: z.enum(["Y", "N"]).default("N"), @@ -134,7 +133,7 @@ const fcOrgwtSchema = z.object({ }); const dmdColist = z.object({ - dmdInfoPk: z.string().default(""), + dmdInfoId: z.string().default(""), dmdCoNm: z.string().default(""), daddr: z.string(), useUsgCd: z.string().nullish(), @@ -144,14 +143,13 @@ const dmdColist = z.object({ splyFmYn: z.string().nullish(), rgtr: z.string().nullish(), mdfr: z.string().nullish(), - pbnstRuseFcltBizPk: zNumDefaultZero, - pbnstRuseFcltFk: z.string().nullish(), + pbnstRuseFcltBizSn: zNumDefaultZero, + pbnstRuseFcltId: z.string().nullish(), }); export const fcBizSchema = z.object({ - pbnstRuseFcltBizPk: zNumNullish, - pbnstRuseFcltFk: z.string().nullish(), - superkey: z.string().default("").nullish(), + pbnstRuseFcltBizSn: zNumNullish, + pbnstRuseFcltId: z.string().nullish(), cycl: zNum.default(1), seCd: z.string().max(10, "구분은 10자를 초과할 수 없습니다.").default(""), bizMthdCd: z.string().default(""), @@ -234,27 +232,33 @@ export const fcBizSchema = z.object({ }); export const pbnstRegZod = z.object({ - pbnstRuseFcltPk: z.string().default(""), - swtrmtFcltFk: z.string().default(""), - ruseUtztnFcltNm: z - .preprocess( + pbnstRuseFcltId: z.string().default(""), + swtrmtFcltId: z.string().default(""), + ruseUtztnFcltNm: //z.string().default(''), + z.preprocess( (v) => (v !== null && v !== undefined ? String(v).trim() : ""), // null/undefined → "", 공백 제거 z.string().min(1, "시설 이름을 입력하세요")), - fcltCpct: zNumDefaultZero, - ruseCpct: zNumDefaultZero, - splyExtraCpct: zNumDefaultZero, + fcltCpct: z.preprocess( + (v) => (v !== null && v !== undefined ? Number(v) : v), + z.number().gte(0, { message: "재이용시설 용량은 0보다 크거나 같아야 합니다" }) + ), + ruseCpct: z.preprocess( + (v) => (v !== null && v !== undefined ? Number(v) : v), + z.number().gte(0, { message: "재이용시설 재이용수 공급량은 0보다 크거나 같아야 합니다" }) + ), + splyExtraCpct: z.preprocess( + (v) => (v !== null && v !== undefined ? Number(v) : v), + z.number().gte(0, { message: "재이용시설 공급가능량은 0보다 크거나 같아야 합니다" }) + ), regDt: zDateDefaultNow, rgtr: z.string().default("test"), mdfcnDt: zDateDefaultNow, mdfr: z.string().default("test"), fcFiles: z.array(fcFileSchema).default([]).nullish(), fcBizs: z.array(fcBizSchema).default([]), - fcOpers: z - .array(fcOperSchema) - .refine((val) => val.length >= 1, { - message: "재이용시설의 운영정보를 최소 하나를 등록해주세요", - }) - .default([]), // 기본값 설정 + fcOpers://z.array(fcOperSchema).default([]), + z .array(fcOperSchema) + .min(1, { message: "재이용시설의 운영정보를 최소 하나를 등록해주세요" }) }); export const pbnstRegArrayZod = z.array(pbnstRegZod); diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx index 6ceb75531..e3e9ef336 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/index.tsx @@ -1,8 +1,8 @@ import type { TableUpperProps } from "@/app/store/common/type/header"; -import { getFetch, postFectch, putFectch } from "@/components/lib/api"; +import { getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; +import toast from "react-hot-toast"; import { z } from "zod"; import { makeMdfr, makeRstr } from "../bdstReg"; -import toast from "react-hot-toast"; import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "./type"; export const TEST_UUID= '2d4b151d-1828-41e0-91d9-4cd28ea1cc7e' @@ -27,9 +27,9 @@ const rainyObjSchema = z.object({ }) export const rainZod = z.object({ - bdstInfoPk: z.number().optional(), - ctpvCd: z.number().default(0), - sggCd: z.number().default(0), + bdstInfoSn: z.number().optional(), + ctpvCd: z.number().optional(), + sggCd: z.number().optional(), daddr: z.string().default(""), bdstNm: z.string().default(""), frstArchPrmsnDt: z.date().default(() => new Date()), @@ -43,7 +43,7 @@ export const rainZod = z.object({ }) export type chgBuilding={ - bdstInfoFk?: number|null, + bdstInfoSn?: number|null, archChgPrmsnDt?: Date, archChgArea?: string, bdstChgNm?: string @@ -74,6 +74,7 @@ export type rainFacState = { isInit: boolean; upHeadList: TableUpperProps[]; rainRes: customRainBdst[]; + rainResCount:number; }; }; type rainFacSActions = { @@ -82,6 +83,7 @@ type rainFacSActions = { rainSearch: (txt:string,pageNation:number,code:string|number) => void; rainBdstReg: (data: customRainBdst, code:string|number) => void; rainBdstUpdate: (data: customRainBdst, code:string|number) => void; + }; export type rainFacType = rainFacState & rainFacSActions; @@ -90,12 +92,14 @@ export const rainFacStateExport: rainFacState = { rain: { isInit: false, rainRes: rainRes, + rainResCount:1, upHeadList: upHeadList, }, }; const initFetch = async (code:string|number) => { - const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/10/${code}`); + // const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/1/10/${code}`); + const rainRes =await getFetchWithCount("wr", `/reuseFc/rainyInfoList/1/10/${code}`); return rainRes; }; export const rainFacActionsExport: (set: any) => rainFacSActions = ( @@ -104,15 +108,15 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( return { getRainData: async(pageNation:number, code:string|number) =>{ try{ - const rainRes =await getFetch("wr", `/reuseFc/rainyInfoList/${pageNation}/10/${code}`); - - + const rainRes =await getFetchWithCount("wr", `/reuseFc/rainyInfoList/${pageNation}/10/${code}`); + // 여기서 상태 업데이트 return set((state: rainFacState) => ({ ...state, rain: { ...state.rain, - rainRes: rainRes, + rainRes: rainRes.data, + rainResCount:rainRes.count, isInit: false, }, })); @@ -132,7 +136,8 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( ...state, rain: { ...state.rain, - rainRes: rainRes, + rainRes: rainRes.data, + rainResCount:rainRes.count, isInit: false, }, })); @@ -143,12 +148,15 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( rainSearch: async(txt:string,pageNation:number) =>{ try{ - const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:'')) + // const rainRes = await getFetch('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:'')) + const rainRes = await getFetchWithCount('wr' , `/reuseFc/rainyInfoList/${pageNation}/20/41` +(txt? `/${txt}`:'')) + console.log("rainRes", rainRes) set((state: rainFacState) => { return { rain: { ...state.rain, - rainRes: rainRes, + rainRes: rainRes.data, + rainResCount:rainRes.count, isInit: false, }, }; @@ -165,11 +173,11 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( if(res.status===200){ if(data.chgBuilding.length > 0){ - const chPK = res?.data?.bdstInfoPk + const chPK = res?.data?.bdstInfoSn const makeCh= res.data.chgBuilding.map((item: chgBuilding) => ( { ...item, - bdstInfoFk: chPK, + bdstInfoSn: chPK, }) ); const chch= await postFectch("/reuseFc/chgBuilding", makeCh); @@ -190,7 +198,8 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( ...state, rain: { ...state.rain, - rainRes: rainRes, + rainRes: rainRes.data, + rainResCount:rainRes.count, isInit: false, }, })); @@ -213,7 +222,8 @@ export const rainFacActionsExport: (set: any) => rainFacSActions = ( ...state, rain: { ...state.rain, - rainRes: rainRes, + rainRes: rainRes.data, + rainResCount:rainRes.count, isInit: false, }, })); diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx index 2d17b4601..7850fec93 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rainReg/type.tsx @@ -8,10 +8,13 @@ export const validationMessages = { }; export const baseReuseBuildingSchema = z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), + bdstInfoSn: z.number().nullish(), instlCmptnDt: z.coerce.date().default(() => new Date()), - instlCst: z.number().nullish(), + instlCst: z + .number() + .max(9_999_999, { message: "최대 9,999,999까지 입력 가능합니다." }) + .nullish(), operMngCd: z.string().optional().default(""), anlOperCst: z.number().default(0), instlCstSprtYn: z.string().default("Y"), @@ -44,7 +47,7 @@ export const baseReuseBuildingSchema = z.object({ }); export const chgBuildingSchema = z.object({ - bdstInfoFk: z.number().nullish(), + bdstInfoSn: z.number().nullish(), archChgPrmsnDt: z.coerce.date({required_error: validationMessages.required("허가일")}), archChgArea: z.string().default("-"), bdstChgNm: z.string().min(1, { message: validationMessages.requiredSelect("구분") }), @@ -55,8 +58,8 @@ export const chgBuildingSchema = z.object({ export const htdflReuseBuildingSchema = z.object({ - bdstRuseFcltPk: z.number().nullish(), - bdstInfoFk: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), + bdstInfoSn: z.number().nullish(), instlCmptnDt: z.coerce.date().default(() => new Date()), instlCst: z.number().nullish(), operMngCd: z.string().optional().nullish(), diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx index d39412d8d..cdfd48f61 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/rswtReg/index.tsx @@ -1,14 +1,14 @@ -import { getFetch, postFectch, putFectch } from "@/components/lib/api"; -import { upHeadList, type chgBuilding } from "../rainReg"; +import { getFetchWithCount, postFectch, putFectch } from "@/components/lib/api"; +import { upHeadList, type chgBuilding } from "../rainReg"; import type { TableUpperProps } from "@/app/store/common/type/header"; -import { z } from "zod"; -import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type"; -import { makeMdfr, makeRstr } from "../bdstReg"; import toast from "react-hot-toast"; +import { z } from "zod"; +import { makeMdfr, makeRstr } from "../bdstReg"; +import { baseReuseBuildingSchema, chgBuildingSchema, validationMessages } from "../rainReg/type"; const rswtrObjSchema = z.object({ - bdstRuseFcltFk: z.number().nullish(), + bdstRuseFcltSn: z.number().nullish(), //wtrUsqty: z.number({ required_error: validationMessages.required("물사용량(m³)") }).positive({ message: validationMessages.required("물사용량(m³)") }), //oblgTrgtWtrUsqty: z.number().nullish().default(0), orgwtKndCd: z.string({ required_error: validationMessages.requiredSelect("원수 종류") }).min(1, { message: validationMessages.requiredSelect("원수 종류") }), @@ -29,9 +29,9 @@ import toast from "react-hot-toast"; }) export const rswtZod = z.object({ - bdstInfoPk: z.number().nullish(), - ctpvCd: z.number().default(0), - sggCd: z.number().default(0), + bdstInfoSn: z.number().nullish(), + ctpvCd: z.number({ required_error: '시도를 선택하세요.' }), + sggCd: z.number({ required_error: '시군구를 선택하세요.' }), daddr: z.string().default(""), bdstNm: z.string().default(""), frstArchPrmsnDt: z.date().default(() => new Date()), @@ -57,6 +57,7 @@ export type rswtFacState = { isInit: boolean; upHeadList: TableUpperProps[]; rswtRes: customRswtBdst[]; + rswtResCount:number; }; }; type rswtFacSActions = { @@ -78,11 +79,12 @@ export const rswtFacStateExport: rswtFacState = { isInit: false, upHeadList: upHeadList, rswtRes: rswtRes, + rswtResCount:1, }, }; const initFetch = async (code: string | number) => { - const rswtRes = await getFetch("wr", `/reuseFc/waterreuseFc/1/10/${code}`); + const rswtRes = await getFetchWithCount("wr", `/reuseFc/waterreuseFc/1/10/${code}`); return rswtRes; }; export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( @@ -95,9 +97,9 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( code: string | number ) => { try { - const rswtRes = await getFetch( + const rswtRes = await getFetchWithCount( "wr", - `/reuseFc/waterreuseFc/${pageNation}/20/${code}` + + `/reuseFc/waterreuseFc/${pageNation}/10/${code}` + (txt ? `/${txt}` : "") ); set((state: rswtFacState) => { @@ -105,7 +107,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( ...state, rswt: { ...state.rswt, - rswtRes: rswtRes, + rswtRes: rswtRes.data, + rswtResCount:rswtRes.count, isInit: false, }, }; @@ -116,7 +119,7 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( }, getRswtBdstData: async (pageNation: number, code: string | number) => { try { - const rswtRes = await getFetch( + const rswtRes = await getFetchWithCount( "wr", `/reuseFc/waterreuseFc/${pageNation}/10/${code}` ); @@ -126,7 +129,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( ...state, rswt: { ...state.rswt, - rswtRes: rswtRes, + rswtRes: rswtRes.data, + rswtResCount:rswtRes.count, isInit: false, }, })); @@ -141,7 +145,8 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( ...state, rswt: { ...state.rswt, - rswtRes: rswtRes, + rswtRes: rswtRes.data, + rswtResCount:rswtRes.count, isInit: false, }, })); @@ -160,14 +165,15 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( ...state, rswt: { ...state.rswt, - rswtRes: rswtRes, + rswtRes: rswtRes.data, + rswtResCount:rswtRes.count, isInit: false, }, })); } } catch (errorUpdate) { toast.error("중수도 건축물 수정 오류입니다. "); - + console.error(errorUpdate); } finally { } }, @@ -176,34 +182,37 @@ export const rswtFacActionsExport: (set: any) => rswtFacSActions = ( const chData = await makeRstr(data); const res = await postFectch("/reuseFc/waterreuseFc", chData); if (res.status===200) { - if(data.chgBuilding.length > 0){ + if(data.chgBuilding.length>0 ){ - const chPK = res?.data?.bdstInfoPk + const chPK = res?.data?.bdstInfoSn const makeCh= res.data.chgBuilding.map((item: chgBuilding) => ( { ...item, - bdstInfoFk: chPK, + bdstInfoSn: chPK, }) ); const chch= await postFectch("/reuseFc/chgBuilding", makeCh); if(chch.status ===200) { - toast.success("건축물 등록이 완료되었습니다."); + + console.log('chch.status' , chch.status) + toast.success("건축물(중수도) 및 증축/개축/중축 등록이 완료되었습니다."); }else{ - toast.error("건축물 증축/개축/중축 오류입니다."); + toast.error("건축물(중수도 증축/개축/중축 오류입니다."); } } else { - toast.success("건축물 등록이 완료되었습니다."); + toast.success("건축물(중수도 등록이 완료되었습니다."); } }else{ - toast.error("건축물 등록이 완료되었습니다."); + toast.error("건축물(중수도) 등록이 완료하였습니다."); } - const rainRes = await initFetch(code); + const rswtRes = await initFetch(code); set((state: rswtFacState) => ({ ...state, rain: { ...state.rswt, - rswtRes: rswtRes, + rswtRes: rswtRes.data, + rswtResCount:rswtRes.count, isInit: false, }, })); diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel.tsx index 591623911..18e045025 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/excel.tsx @@ -2,13 +2,13 @@ import type { SelectDataType } from "@common/business_components/ui"; import type { customHtdflBdst } from "../../fcltReg/htdflReg"; export const excelHtdflSttnParsing = ( - data: customHtdflBdst[], + excel: { data: customHtdflBdst[] }, sidoCode: SelectDataType[], sggCode: SelectDataType[] ): string[][] => { const excelExportData: string[][] = []; - data.forEach((item) => { + excel.data.forEach((item) => { excelExportData.push([ sidoCode.find((sido) => sido.val === item.ctpvCd.toString())?.text ?? "", sggCode.find((sgg) => sgg.val === item.sggCd.toString())?.text ?? "", diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/headList.tsx index 756c47b9b..e1a8daec6 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/headList.tsx @@ -105,7 +105,7 @@ export const htdflSttHeadListExport: z.infer<typeof sttnHeadListType> = [ export const htdflSttNodeListExport: CommonTableProps[] = [ { id: "bdnstInfo", - title: "1.건축물정보", + title: "건축물정보", visible: true, row: 1, rowSpan: 1, @@ -113,7 +113,7 @@ export const htdflSttNodeListExport: CommonTableProps[] = [ }, { id: "htdflFcltInfo", - title: "2.온배수 시설현황", + title: "온배수 시설현황", visible: true, row: 1, rowSpan: 1, @@ -121,11 +121,11 @@ export const htdflSttNodeListExport: CommonTableProps[] = [ }, { id: "htdflMngInfo", - title: "3.온배수운영현황", + title: "온배수운영현황", visible: true, row: 1, rowSpan: 1, - colSpan: 11, + colSpan: 10, }, { @@ -255,7 +255,7 @@ export const htdflSttNodeListExport: CommonTableProps[] = [ { id: "prcsProcsYn", title: "처리공정여부", - upName: "prcsProcs", + upName: "htdflMngInfo", visible: true, row: 2, rowSpan: 2, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx index eb37d0d73..d62ee3340 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/htdflSttn/index.tsx @@ -1,11 +1,12 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; -import { htdflSttHeadListExport, htdflSttNodeListExport } from "./headList"; -import type { sttnHeadListType } from "../rainSttn/headList"; -import type { z } from "zod"; -import { controlHeadView } from "../rainSttn"; -import type { customHtdflBdst } from "../../fcltReg/htdflReg"; -import { fetchType, getFetch } from "@/components/lib/api"; +import { fetchType, getFetchWithCount } from "@/components/lib/api"; import type { SelectDataType } from "@common/business_components/ui"; +import type { z } from "zod"; +import type { customHtdflBdst } from "../../fcltReg/htdflReg"; +import { controlHeadView } from "../rainSttn"; +import type { sttnHeadListType } from "../rainSttn/headList"; +import { excelHtdflSttnParsing } from "./excel"; +import { htdflSttHeadListExport, htdflSttNodeListExport } from "./headList"; const htdflSttHeadList = htdflSttHeadListExport; const htdflSttNodeList = htdflSttNodeListExport; @@ -17,16 +18,16 @@ export type htdflSttnState = { htdflSttNodeList: CommonTableProps[]; htdflSttnRes: customHtdflBdst[] excelList: []; - + htdflSttnResCount: number; }; }; type htdflSttnActions = { - initHtdfl: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; - htdflSttnSearch: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; + initHtdfl: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; + htdflSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; htdflChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -41,12 +42,11 @@ export const htdflSttnStateExport: htdflSttnState = { htdflSttnRes: [], excelList: [], isInit: false, + htdflSttnResCount: 1, }, }; -const initFetch = async (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => { - const htdflRes = await getFetch( +const initFetch = async (page: number, total: string, con: string, txt: string) => { + const htdflRes = await getFetchWithCount( "wr", `/drain/facilityList` + (page ? `/${page}` : "/1") + @@ -62,31 +62,44 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = ( set: any ) => { return { - initHtdfl: async (page: number, total: string, con: string, txt: string, + initHtdfl: async (isExcel: boolean, page: number, total: string, con: string, txt: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => { try { - const htdflSttnRes = await initFetch(page, total, con, txt, sidoCode, sggCode); - set((state: htdflSttnState) => { - return { - ...state, - htdflSttn: { - ...state.htdflSttn, - htdflSttnRes: htdflSttnRes, - isInit: false, - }, - }; - }); + const htdflSttnRes = await initFetch(page, total, con, txt); + if (isExcel) { + const htdflExcel = excelHtdflSttnParsing(htdflSttnRes, sidoCode, sggCode); + set((state: htdflSttnState) => { + return { + ...state, + htdflSttn: { + ...state.htdflSttn, + excelList: htdflExcel, + }, + }; + }); + } else { + set((state: htdflSttnState) => { + return { + ...state, + htdflSttn: { + ...state.htdflSttn, + htdflSttnRes: htdflSttnRes.data, + htdflSttnResCount: htdflSttnRes.count, + isInit: false, + }, + }; + }); + } } catch (error) { console.log(error); } }, - htdflSttnSearch: async (page: number, total: string, con: string, txt: string, + htdflSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => { try { - console.log("page", page) - const htdflSttnRes = await getFetch( + const htdflSttnRes = await getFetchWithCount( fetchType.WR, `/drain/facilityList` + (page ? `/${page}` : "/1") + @@ -95,13 +108,14 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = ( (txt ? `/${txt}` : "") ); - if (Number(total) > 9000) { + if (isExcel) { + const htdflExcel = excelHtdflSttnParsing(htdflSttnRes, sidoCode, sggCode); set((state: htdflSttnState) => { return { ...state, htdflSttn: { ...state.htdflSttn, - excelList: htdflSttnRes, + excelList: htdflExcel, }, }; }); @@ -111,7 +125,8 @@ export const htdflSttnActionsExport: (set: any) => htdflSttnActions = ( ...state, htdflSttn: { ...state.htdflSttn, - htdflSttnRes: htdflSttnRes, + htdflSttnRes: htdflSttnRes.data, + htdflSttnResCount: htdflSttnRes.count, isInit: false, }, }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/excel.tsx index 8a1db05a2..9e0af4ffa 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/excel.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/excel.tsx @@ -1,4 +1,3 @@ -import type { customPbnst } from "../../fcltReg/pbnstReg/type"; export const excelPbnstSttnParsing = (data: any[]): string[][] => { const excelExportData: string[][] = []; @@ -13,15 +12,19 @@ export const excelPbnstSttnParsing = (data: any[]): string[][] => { String(item.gugun ?? ""), String(item.bscFctNm ?? ""), String(item.efflWqltStndrdNm ?? ""), - String(item.fctCpc ?? ""), String(item.tel ?? ""), + String(item.fctCpc ?? ""), String(item.ruseUtztnFcltNm ?? ""), String(item.fcltCpct ?? ""), String(item.splyExtraCpct ?? ""), String(item.ruseCpct ?? ""), String(item.usageTotal ?? ""), String(item.inUsage ?? ""), - String(item.outUsage ?? ""), + String(item.outUsage ?? ""), + String(item.operMthd ?? ""), + String(item.rprtvBzenty ?? ""), + String(item.bgngDt ?? ""), + String(item.endDt ?? ""), ]) }) return excelExportData; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx index 7c2953932..075b91261 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/headList.tsx @@ -100,7 +100,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 3, }, { - id: "operMngCd", + id: "rgnNm", title: "환경청", visible: true, row: 1, @@ -116,7 +116,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 2, }, { - id: "bdnstNm", + id: "bscFctNm", title: "시설명", visible: true, row: 1, @@ -124,7 +124,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "locDiv", + id: "efflWqltStndrdNm", title: "지역구분", visible: true, row: 1, @@ -148,7 +148,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "rusNm", + id: "ruseUtztnFcltNm", title: "재이용시설명", visible: true, row: 1, @@ -180,7 +180,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 4, }, { - id: "a", + id: "rvbsn", title: "권역", upName: "catchment", visible: true, @@ -189,7 +189,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "aaa", + id: "lgbsn", title: "단위유역", upName: "catchment", visible: true, @@ -198,7 +198,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "aaaa", + id: "mdmbsn", title: "중권역", upName: "catchment", visible: true, @@ -207,7 +207,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "cityText", + id: "sido", title: "시도", upName: "adminDiv", visible: true, @@ -216,7 +216,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "sggText", + id: "gugun", title: "시군구", upName: "adminDiv", visible: true, @@ -234,7 +234,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "trbt", + id: "splyExtraCpct", title: "하수처리량(m³/일)", upName: "rusSup", visible: true, @@ -252,7 +252,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "total", + id: "usageTotal", title: "합계", upName: "yearResult", visible: true, @@ -261,7 +261,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "ithlWtr", + id: "inUsage", title: "장내용수", upName: "yearResult", visible: true, @@ -270,7 +270,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "othlWtr", + id: "outUsage", title: "장외용수", upName: "yearResult", visible: true, @@ -279,7 +279,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "mngMeth", + id: "operMthd", title: "운영방식", upName: "mngInfo", visible: true, @@ -297,7 +297,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "firstDay", + id: "bgngDt", title: "시작일", upName: "mngInfo", visible: true, @@ -306,7 +306,7 @@ export const pbnstSttNodeListExport: CommonTableProps[] = [ colSpan: 1, }, { - id: "LastDay", + id: "endDt", title: "종료일", upName: "mngInfo", 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 33bce5520..e94c7a002 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/index.tsx @@ -1,15 +1,15 @@ import type { CommonTableProps, TableUpperProps } from "@/app/store/common/type/header"; -import type { z } from "zod"; -import { pbnSttHeadListExport, pbnstSttNodeListExport, ruseDmdHeadListExport, ruseFcltHeadListExport, ruseFcltNodeListExport, ruseGuranteeHeadListExport, rusePplHeadListExport, ruseSplyHeadListExport } from "./headList"; +import type { FcPrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; import { fetchType, getFetch, postFectch } from "@/components/lib/api"; +import type { ReturnType } from "@common/business_components/ui"; +import moment from "moment"; +import { type z } from "zod"; +import type { customPbnst, pubHasuType } from "../../fcltReg/pbnstReg/type"; import { controlHeadView } from "../rainSttn"; import type { sttnHeadListType } from "../rainSttn/headList"; -import type { customPbnst, pubHasuType } from "../../fcltReg/pbnstReg/type"; import { excelPbnstSttnParsing } from "./excel"; -import type { FcPrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; -import type { ReturnType } from "@common/business_components/ui"; +import { pbnSttHeadListExport, pbnstSttNodeListExport, ruseDmdHeadListExport, ruseFcltHeadListExport, ruseFcltNodeListExport, ruseGuranteeHeadListExport, rusePplHeadListExport, ruseSplyHeadListExport } from "./headList"; import type { WaterReuseFacility } from "./type"; -import moment from "moment"; const pbnstSttHeadList = pbnSttHeadListExport; const pbnstSttNodeList = pbnstSttNodeListExport; @@ -21,13 +21,15 @@ export type pbnstSttnState = { pbnstSttHeadList: CommonTableProps[]; pbnstSttNodeList: CommonTableProps[]; pbnstDetail: customPbnst; - ruseFcltNodeList:TableUpperProps[] - ruseSplyHeadList:TableUpperProps[] - rusePplHeadList:TableUpperProps[] - ruseGuranteeHeadList:TableUpperProps[] - ruseDmdHeadList:TableUpperProps[] - ruseFcltHeadList:TableUpperProps[] + ruseFcltNodeList: TableUpperProps[] + ruseSplyHeadList: TableUpperProps[] + rusePplHeadList: TableUpperProps[] + ruseGuranteeHeadList: TableUpperProps[] + ruseDmdHeadList: TableUpperProps[] + ruseFcltHeadList: TableUpperProps[] + pbnstSttnResCount:number; excelList: []; + fclts:string[] isInit: boolean; }; }; @@ -35,25 +37,30 @@ export type pbnstSttnState = { type pbnstSttnActions = { pbnstChSttnHead: (headList: z.infer<typeof sttnHeadListType>) => void; pbnstSttnSearch: ( + isExcel: boolean, page: string, total: string, reurnValue: ReturnType, searchNm: string | undefined, - year: string + year: string, + fclts:string[] ) => void; + getFlcts:()=>void; pbnSttnInit: ( page: string, total: string, reurnValue: ReturnType, - year: string + year: string, + flcts:string[] ) => void; - getPbnStnDetail: (pbnstRuseFcltPk: string) => void; + getPbnStnDetail: (pbnstRuseFcltId: string) => void; pbnNmSearch: ( page: string, total: string, reurnValue: ReturnType, searchNm: string | undefined, - year: string + year: string, + flcts:string[] ) => void; }; @@ -63,16 +70,18 @@ export const pbnstSttnStateExport: pbnstSttnState = { pbnstSttn: { pbnstSttHeadList: pbnstSttHeadList, pbnstSttNodeList: pbnstSttNodeList, - ruseFcltNodeList:ruseFcltNodeListExport, - ruseSplyHeadList:ruseSplyHeadListExport, - rusePplHeadList:rusePplHeadListExport, - ruseGuranteeHeadList:ruseGuranteeHeadListExport, - ruseDmdHeadList:ruseDmdHeadListExport, - ruseFcltHeadList:ruseFcltHeadListExport, + ruseFcltNodeList: ruseFcltNodeListExport, + ruseSplyHeadList: ruseSplyHeadListExport, + rusePplHeadList: rusePplHeadListExport, + ruseGuranteeHeadList: ruseGuranteeHeadListExport, + ruseDmdHeadList: ruseDmdHeadListExport, + ruseFcltHeadList: ruseFcltHeadListExport, pbnstSttnRes: [], + pbnstSttnResCount:1, pbnstDetail: {} as customPbnst, pbnstSearchData: [], excelList: [], + fclts:[], isInit: false, }, }; @@ -82,99 +91,118 @@ const hasuListFetch = async ( total: string, reurnValue: ReturnType, searchNm: string | undefined, - year: string + year: string, + flcts:string[] ) => { - let url = ""; + let url = `/prcsFclt/ruseInfo/`; + if (reurnValue.partValue === "A") { - url = `/prcsFclt/info/${page}/${total}/${reurnValue.partValue}/${ - reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue + url+=`${page}/${total}/${reurnValue.partValue}/${ + // reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue + reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue }/0/1/SW` } else if (reurnValue.partValue === "R") { - url = `/prcsFclt/info/${page}/${total}/${reurnValue.partValue}/${ - reurnValue.regionValue - ? reurnValue.regionValue - : reurnValue.unitWaterShedValue - ? reurnValue.unitWaterShedValue - : reurnValue.middleRegionValue + url += `${page}/${total}/${reurnValue.partValue}/${reurnValue.regionValue + ? reurnValue.regionValue + : reurnValue.unitWaterShedValue + ? reurnValue.unitWaterShedValue + : reurnValue.middleRegionValue }/0/1/SW` - } else { - url = `/prcsFclt/info/${page}/${total}/${reurnValue.envPartValue}/${reurnValue.sidoValue ? reurnValue.sidoValue : reurnValue.sigunValue}/0/1/SW` - + } else if( reurnValue.partValue === 'G'){ + + + url += `${page}/${total}/${reurnValue.envPartValue}/${reurnValue.sigunValue !== '0' ? reurnValue.sigunValue : reurnValue.sidoValue}/0/1/SW` + + }else{ + url += `1/2/A/0/0/1/SW` } - if( searchNm&& searchNm?.length>0){ - url+="/"+searchNm + + if (searchNm && searchNm?.length > 0) { + url += "/" + searchNm } - const pbnList = await getFetch(fetchType.COMMON, url); - const arrayList = pbnList.map((item: pubHasuType) => item.bscFctCd); + + console.log(' flcts ' ,flcts) + const pbnList = await postFectch(url, flcts,fetchType.COMMON); const getRuseList = await postFectch( `/reuseFc/pubDetailList/${year}`, - arrayList, + flcts, fetchType.WR ); const checkWrRegListRes = getRuseList.data; + + const data: WaterReuseFacility[] = checkWrRegListRes.map( (item: FcPrfType) => { - const findData = pbnList.find( + const findData = pbnList.data.find( (fclt: pubHasuType) => - fclt.bscFctCd === item.pbnstRuseFcltPk.substring(0, 11) + fclt.bscFctCd === item.pbnstRuseFcltId.substring(0, 11) ); - const usage = item.prfList.reduce( - (acc, cur) => { - acc.inUsage += - cur.wshwtr + - cur.coolUswtr + - cur.cleanUswtr + - cur.drwtUswtr + - cur.dltnUswtr + - cur.ithlRswtr + - cur.ithlEtcUswtr + - cur.cleanToilUswtr + - cur.resn; - acc.outUsage += - cur.lndwtr + - cur.hydUswtr + - cur.ugwtChr + - cur.farmUswtr + - cur.rvrKeepUswtr + - cur.indstUswtr; - acc.total = acc.inUsage + acc.outUsage; + if(findData){ - return acc; - }, - { total: 0, inUsage: 0, outUsage: 0 } - ); + const usage = item.prfList.reduce( + (acc, cur) => { + acc.inUsage += + cur.wshwtr + + cur.coolUswtr + + cur.cleanUswtr + + cur.drwtUswtr + + cur.dltnUswtr + + cur.ithlRswtr + + cur.ithlEtcUswtr + + cur.cleanToilUswtr + + cur.resn; + acc.outUsage += + cur.lndwtr + + cur.hydUswtr + + cur.ugwtChr + + cur.farmUswtr + + cur.rvrKeepUswtr + + cur.indstUswtr; + acc.total = acc.inUsage + acc.outUsage; + + return acc; + }, + { total: 0, inUsage: 0, outUsage: 0 } + ); + console.log('findData ', findData) + return { + rvbsn: findData?.rvbsn ||'-', + lgbsn: findData?.lgbsn||'-', + mdmbsn: findData?.mdmbsn||'-', + rgnNm: findData?.rgnNm||'-', + sido: findData?.sido||'-', + gugun: findData?.gugun||'-', + bscFctNm: findData?.bscFctNm||'-', + efflWqltStndrdNm: findData?.efflWqltStndrdNm||'-', + fctCpc: Number(findData?.fctCpc)||0, + tel: findData?.tel ?? "-", + ruseUtztnFcltNm: item?.ruseUtztnFcltNm||'-', + fcltCpct: item?.fcltCpct||'-', + splyExtraCpct: item?.splyExtraCpct||'-', + ruseCpct: item?.ruseCpct||'-', + pbnstRuseFcltId: item.pbnstRuseFcltId||'-', + usageTotal: usage?.total, + inUsage: usage?.inUsage, + outUsage: usage?.outUsage, + operMthd: item.operList[0]?.operMthd||'-', + rprtvBzenty: item.operList[0]?.rprtvBzenty, + bgngDt: moment(item.operList[0]?.bgngDt).format("YYYY-MM-DD") ?? "", + endDt: moment(item.operList[0]?.endDt).format("YYYY-MM-DD") ?? "", + searchNm: findData?.bscFctNm||'-', + searchPk: findData?.bscFctCd||'-', + prfList: item?.prfList ?? [] + }; + } - return { - rvbsn: findData?.rvbsn, - lgbsn: findData?.lgbsn, - mdmbsn: findData?.mdmbsn, - rgnNm: findData?.rgnNm, - sido: findData?.sido, - gugun: findData?.gugun, - bscFctNm: findData?.bscFctNm, - efflWqltStndrdNm: findData?.efflWqltStndrdNm, - fctCpc: findData.fctCpc, - tel: findData?.tel ?? "-", - ruseUtztnFcltNm: item.ruseUtztnFcltNm, - fcltCpct: item.fcltCpct, - splyExtraCpct: item.splyExtraCpct, - ruseCpct: item.ruseCpct, - pbnstRuseFcltPk: item.pbnstRuseFcltPk, - usageTotal: usage.total, - inUsage: usage.inUsage, - outUsage: usage.outUsage, - operMthd: item.operList[0]?.operMthd, - rprtvBzenty: item.operList[0]?.rprtvBzenty, - bgngDt: moment(item.operList[0]?.bgngDt).format("YYYY-MM-DD") ?? "", - endDt: moment(item.operList[0]?.endDt).format("YYYY-MM-DD") ?? "", - searchNm: findData.bscFctNm, - searchPk: findData.bscFctCd, - prfList:item?.prfList??[] - }; } - ); + ).filter(Boolean); + + + console.log( ' checkWrRegListRes ', getRuseList.data) + console.log( ' data ', data) + return data; }; @@ -182,6 +210,15 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( set: any ) => { return { + getFlcts:async ()=>{ + const fclts= await getFetch(fetchType.WR,'/reuseFc/pubFc') + return set((state: pbnstSttnState) => ({ + pbnstSttn: { + ...state.pbnstSttn, + fclts:fclts + }, + })); + }, pbnstChSttnHead: async ( headList: z.infer<typeof sttnHeadListType> ): Promise<void> => { @@ -196,22 +233,28 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( })); }, pbnstSttnSearch: async ( + isExcel: boolean, page: string, total: string, reurnValue: ReturnType, searchNm: string | undefined, - year: string + year: string, + fclts:string[] ) => { try { + + const pbnstSttnRes = await hasuListFetch( page, total, reurnValue, searchNm, - year + year, + fclts, ); - console.log("pbnstSttnRes", pbnstSttnRes); - if (Number(total) > 9000) { + + // if (Number(total) > 9000) { + if (isExcel) { const pbnstExcel = excelPbnstSttnParsing(pbnstSttnRes); set((state: pbnstSttnState) => { return { @@ -222,44 +265,48 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( }, }; }); - } else + } else{ + set((state: pbnstSttnState) => { return { ...state, pbnstSttn: { ...state.pbnstSttn, pbnstSttnRes: pbnstSttnRes, - isInit: false, + pbnstSttnResCount:pbnstSttnRes.length + // isInit: false, }, }; }); + } } catch (erTxt) { console.log("error", erTxt); } }, - pbnSttnInit: async ( + pbnSttnInit: async( page: string, total: string, reurnValue: ReturnType, - year: string + year: string, + fclts:string[] ) => { try { - const pbnstSttnRes = await hasuListFetch( - page, - total, - reurnValue, - undefined, - year - ); - - console.log('pbnstSttnRes ', pbnstSttnRes) - set((state: pbnstSttnState) => { + page, + total, + reurnValue, + undefined, + year, + fclts + ); + console.log('pbnstSttnRes ' , pbnstSttnRes) + set( (state: pbnstSttnState) => { return { ...state, pbnstSttn: { ...state.pbnstSttn, pbnstSttnRes: pbnstSttnRes, + pbnstSttnResCount:pbnstSttnRes.length, isInit: false, }, }; @@ -268,13 +315,12 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( console.log("error", erTxt); } }, - getPbnStnDetail: async (pbnstRuseFcltPk: string) => { + getPbnStnDetail: async (pbnstRuseFcltId: string) => { try { - let pbnstDetail = await getFetch("wr", `/reuseFc/pubFc/${pbnstRuseFcltPk}`); - if(pbnstDetail.length>=0){ - pbnstDetail= pbnstDetail.find((item: customPbnst) =>item.pbnstRuseFcltPk === pbnstRuseFcltPk) + let pbnstDetail = await getFetch("wr", `/reuseFc/pubFc/${pbnstRuseFcltId}`); + if (pbnstDetail.length >= 0) { + pbnstDetail = pbnstDetail.find((item: customPbnst) => item.pbnstRuseFcltId === pbnstRuseFcltId) } - console.log( 'pbnstDetail ', pbnstDetail) set((state: pbnstSttnState) => { return { ...state, @@ -293,17 +339,19 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( total: string, reurnValue: ReturnType, searchNm: string | undefined, - year: string - ) => { + year: string, + flcts:string[] + ) => { try { - - const pbnstSttnRes = await hasuListFetch( - page, - total, - reurnValue, - searchNm, - year - ); + + const pbnstSttnRes = await hasuListFetch( + page, + total, + reurnValue, + searchNm, + year, + flcts + ); set((state: pbnstSttnState) => { return { @@ -311,6 +359,7 @@ export const pbnstSttnActionsExport: (set: any) => pbnstSttnActions = ( pbnstSttn: { ...state.pbnstSttn, pbnstSearchData: pbnstSttnRes, + pbnstSttnResCount:pbnstSttnRes.length, }, }; }); diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx index e4e86da5d..7d0f8a068 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/pbnstSttn/type.tsx @@ -10,7 +10,7 @@ export type WaterReuseFacility = { lgbsn: string; // 대수계 (예: "한강본류") mdmbsn: string; // 중권역 (예: "한강서울") outUsage: number; // 유출량 (예: 900) - pbnstRuseFcltPk: string; // 공공하수 재이용 시설 PK (예: "11000SW001R1") + pbnstRuseFcltId: string; // 공공하수 재이용 시설 PK (예: "11000SW001R1") rgnNm: string; // 관할 기관명 (예: "한강유역환경청") ruseCpct: number; // 재이용 가능 용량 (예: 123) ruseUtztnFcltNm: string; // 재사용 활용 시설명 (예: "난지 재사용") diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx index 13530a81f..3de4ee1a6 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/excel.tsx @@ -2,19 +2,19 @@ import type { SelectDataType } from "@common/business_components/ui"; import type { customRainBdst } from "../../fcltReg/rainReg"; export const excelRainSttnParsing = ( - data: customRainBdst[], + excel: { data: customRainBdst[] }, sidoCode: SelectDataType[], sggCode: SelectDataType[] ): string[][] => { const excelExportData: string[][] = []; - data.forEach((item) => { + excel.data.forEach((item) => { excelExportData.push([ - sidoCode.find((sido) => sido.val === item.ctpvCd.toString())?.text ?? "", - sggCode.find((sgg) => sgg.val === item.sggCd.toString())?.text ?? "", + sidoCode.find((sido) => sido.val === item.ctpvCd?.toString())?.text ?? "", + sggCode.find((sgg) => sgg.val === item.sggCd?.toString())?.text ?? "", item.bdstNm ?? "", item.daddr ?? "", - String(item.bdstInfoPk ?? ""), + String(item.bdstInfoSn ?? ""), String(item.frstArchPrmsnDt ?? ""), String(item.archArea ?? ""), String(item.chgBuilding.length > 0 ? "Y" : "N"), diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx index 8dd2a4d6f..fd8c2173e 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/headList.tsx @@ -136,7 +136,7 @@ export const rainSttHeadListExport: z.infer<typeof sttnHeadListType> = [ export const rainSttNodeListExport: CommonTableProps[] = [ { id: "bdnstInfo", - title: "1.건축물정보", + title: "건축물정보", visible: true, row: 1, rowSpan: 1, @@ -144,7 +144,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [ }, { id: "rainFcltInfo", - title: "2.빗물이용시설정보", + title: "빗물이용시설정보", visible: true, row: 1, rowSpan: 1, @@ -152,7 +152,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [ }, { id: "insenInfo", - title: "3.인센티브 정보", + title: "인센티브 정보", visible: true, row: 1, rowSpan: 1, @@ -343,7 +343,7 @@ export const rainSttNodeListExport: CommonTableProps[] = [ id: "filtrTrtmfct", title: "여과등 처리시설", visible: true, - upName: "insenInfo", + upName: "rainFcltInfo", row: 2, rowSpan: 1, colSpan: 3, diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx index eb2c08d37..6c987298f 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rainSttn/index.tsx @@ -1,5 +1,5 @@ import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; -import { fetchType, getFetch } from "@/components/lib/api"; +import { fetchType, getFetch, getFetchWithCount } from "@/components/lib/api"; import { type customRainBdst, } from "../../fcltReg/rainReg"; @@ -96,15 +96,16 @@ export type rainSttnState = { rainChkRes: rainChkZodType excelList: []; isInit: boolean; + rainSttnResCount: number; }; }; type rainSttnActions = { - rainSttnInit: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void - rainSttnSearch: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; + rainSttnInit: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void + rainSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; rainChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -123,6 +124,7 @@ export const rainSttnStateExport: rainSttnState = { rainChkRes: rainChkRes, excelList: [], isInit: false, + rainSttnResCount: 1, }, }; @@ -130,12 +132,12 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( set: any ) => { return { - rainSttnInit: async (page: number, total: string, con: string, txt: string, + rainSttnInit: async (isExcel: boolean, page: number, total: string, con: string, txt: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => { try { - const rainSttnRes = await getFetch( + const rainSttnRes = await getFetchWithCount( fetchType.WR, `/reuseFc/rainyInfoList` + (page ? `/${page}` : "/1") + @@ -143,33 +145,7 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( (con ? `/${con}` : "/0") + (txt ? `/${txt}` : "") ); - set((state: rainSttnState) => { - return { - ...state, - rainSttn: { - ...state.rainSttn, - rainSttnRes: rainSttnRes, - isInit: false, - }, - }; - }); - } catch (e) { - console.log(e) - } - }, - rainSttnSearch: async (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => { - try { - const rainSttnRes = await getFetch( - fetchType.WR, - `/reuseFc/rainyInfoList` + - (page ? `/${page}` : "/1") + - (total ? `/${total}` : "/20") + - (con ? `/${con}` : "/0") + - (txt ? `/${txt}` : "") - ); - if (Number(total) > 9000) { + if (isExcel) { const rainExcel = excelRainSttnParsing(rainSttnRes, sidoCode, sggCode); set((state: rainSttnState) => { return { @@ -180,13 +156,54 @@ export const rainSttnActionsExport: (set: any) => rainSttnActions = ( }, }; }); + } else { + set((state: rainSttnState) => { + return { + ...state, + rainSttn: { + ...state.rainSttn, + rainSttnRes: rainSttnRes.data, + isInit: false, + }, + }; + }); + } + } catch (e) { + console.log(e) + } + }, + rainSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { + try { + const rainSttnRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/rainyInfoList` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") + ); + if (isExcel) { + const rainExcel = excelRainSttnParsing(rainSttnRes, sidoCode, sggCode); + set((state: rainSttnState) => { + return { + ...state, + rainSttn: { + ...state.rainSttn, + excelList: rainExcel, + rainSttnResCount: rainSttnRes.count, + }, + }; + }); } else set((state: rainSttnState) => { return { ...state, rainSttn: { ...state.rainSttn, - rainSttnRes: rainSttnRes, + rainSttnRes: rainSttnRes.data, + rainSttnResCount: rainSttnRes.count, isInit: false, }, }; diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx index ac57a8016..803dc2d83 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/excel.tsx @@ -1,35 +1,35 @@ +import { bdstUsgCd } from "@/app/store/common/code/basicCode"; import type { SelectDataType } from "@common/business_components/ui"; import type { customRswtBdst } from "../../fcltReg/rswtReg"; -import { useWrStore } from "@/app/store"; export const excelRSwtSttnParsing = ( - data: customRswtBdst[], + excel: { data: customRswtBdst[] }, sidoCode: SelectDataType[], sggCode: SelectDataType[] ): string[][] => { const excelExportData: string[][] = []; - - data.forEach((item) => { + excel.data.forEach((item) => { + console.log("item", item) excelExportData.push([ sidoCode.find((sido) => sido.val === item.ctpvCd.toString())?.text ?? "", sggCode.find((sgg) => sgg.val === item.sggCd.toString())?.text ?? "", item.bdstNm ?? "", item.daddr ?? "", - String(item.bdstUsgText ?? ""), + bdstUsgCd.find((cd)=> cd.val === item.reuseBuilding?.[0]?.bdstUsgCd.toString())?.text ?? "", //건축물용도 String(item.frstArchPrmsnDt ?? ""), - String(item.archArea ?? ""), - String(item.reuseBuilding?.[0]?.rswtrObj.wtrUsqty ?? "0"), //물사용량 + String(item.archArea.split('.')[0] === '-1' ? '확인불가' : item.archArea.split('.')[0]), + // String(item.reuseBuilding?.[0]?.rswtrObj.wtrUsqty ?? "0"), //물사용량 String(item.chgBuilding.length > 0 ? "Y" : "N"), //중축・개축・재축여부 String(item.reuseBuilding?.[0]?.lawTrgtYn ?? ""), //법적의무대상여부 - String(item.reuseBuilding?.[0]?.rswtrObj.oblgTrgtWtrUsqty ?? ""), //의무대상물사용량 + // String(item.reuseBuilding?.[0]?.rswtrObj.oblgTrgtWtrUsqty ?? ""), //의무대상물사용량 String(item.reuseBuilding?.[0]?.instlCmptnDt ?? ""), //설치완료일시 - String(item.reuseBuilding?.[0]?.instlCst ?? ""), //설치비용 + String(item.reuseBuilding?.[0]?.instlCst === -1 ? "확인불가" : item.reuseBuilding?.[0]?.instlCst ?? ""), //설치비용 item.reuseBuilding?.[0]?.rswtrObj?.orgwtKndCd ?? "", //원수종류 String(item.reuseBuilding?.[0]?.rswtrObj.filtrTrtmfctCpct ?? ""), //처리시설용량 String(item.reuseBuilding?.[0]?.rswtrObj?.filtrTrtmfctProcs ?? ""), //주요처리공정 String(item.reuseBuilding?.[0]?.rswtrObj?.filtrTrtmfctUsgCd ?? ""), //이용용도 String(item.reuseBuilding?.[0]?.instlCstSprtYn ?? ""), //설치지원비용여부 - String(item.reuseBuilding?.[0]?.instlCstSprtAmt ?? ""), //설치지원비용 + String(item.reuseBuilding?.[0]?.instlCstSprtAmt === -1 ? "확인불가" : item.reuseBuilding?.[0]?.instlCstSprtAmt ?? ""), //설치지원비용 String(item.reuseBuilding?.[0]?.grntchBdstCertYn ?? ""), String(item.reuseBuilding?.[0]?.grntchBdstCertYr ?? ""), String(item.reuseBuilding?.[0]?.grntchBdstCertNo ?? ""), diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx index 804617ad8..2f44b2c33 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/headList.tsx @@ -38,11 +38,11 @@ export const rswtSttHeadListExport: z.infer<typeof sttnHeadListType> = [ title: "건축면적", visible: true, }, - { - id: "wtrUsqty", - title: "물사용량", - visible: true, - }, + // { + // id: "wtrUsqty", + // title: "물사용량", + // visible: true, + // }, { id: "chBuildingYn", title: "중축・개축・재축여부", @@ -54,12 +54,11 @@ export const rswtSttHeadListExport: z.infer<typeof sttnHeadListType> = [ title: "법적의무대상여부", visible: true, }, - - { - id: "oblgTrgtWtrUsqty", - title: "의무대상물사용량 ", - visible: true, - }, + // { + // id: "oblgTrgtWtrUsqty", + // title: "의무대상물사용량 ", + // visible: true, + // }, { id: "instlCmptnDt", title: "설치완료일시", @@ -130,15 +129,15 @@ export const rswtSttHeadListExport: z.infer<typeof sttnHeadListType> = [ export const rswtSttNodeListExport: CommonTableProps[] = [ { id: "bdnstInfo", - title: "1.건축물정보", + title: "건축물정보", visible: true, row: 1, rowSpan: 1, - colSpan: 12, + colSpan: 10, }, { id: "rswtFcltInfo", - title: "2.중수도시설정보", + title: "중수도시설정보", visible: true, row: 1, rowSpan: 1, @@ -146,7 +145,7 @@ export const rswtSttNodeListExport: CommonTableProps[] = [ }, { id: "insenInfo", - title: "3.인센티브 정보", + title: "인센티브 정보", visible: true, row: 1, rowSpan: 1, @@ -229,15 +228,15 @@ export const rswtSttNodeListExport: CommonTableProps[] = [ rowSpan: 2, colSpan: 1, }, - { - id: "wtrUsqty", - title: "물사용량", - upName: "bdnstInfo", - visible: true, - row: 2, - rowSpan: 2, - colSpan: 1, - }, + // { + // id: "wtrUsqty", + // title: "물사용량", + // upName: "bdnstInfo", + // visible: true, + // row: 2, + // rowSpan: 2, + // colSpan: 1, + // }, { id: "chBuildingYn", title: "중축・개축・재축여부", @@ -257,15 +256,15 @@ export const rswtSttNodeListExport: CommonTableProps[] = [ rowSpan: 2, colSpan: 1, }, - { - id: "oblgTrgtWtrUsqty", - title: "의무대상물사용량", - upName: "bdnstInfo", - visible: true, - row: 2, - rowSpan: 2, - colSpan: 1, - }, + // { + // id: "oblgTrgtWtrUsqty", + // title: "의무대상물사용량", + // upName: "bdnstInfo", + // visible: true, + // row: 2, + // rowSpan: 2, + // colSpan: 1, + // }, { id: "instlCmptnDt", title: "설치완료일시", diff --git a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx index 8fbe2c26d..97c9dfe5b 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltSttn/rswtSttn/index.tsx @@ -1,12 +1,12 @@ import type { CommonTableProps } from "@/app/store/common/type/header"; -import { fetchType, getFetch } from "@/components/lib/api"; +import { fetchType, getFetchWithCount } from "@/components/lib/api"; +import type { SelectDataType } from "@common/business_components/ui"; import type { z } from "zod"; import type { customRswtBdst } from "../../fcltReg/rswtReg"; import { controlHeadView } from "../rainSttn"; import type { sttnHeadListType } from "../rainSttn/headList"; import { excelRSwtSttnParsing } from "./excel"; import { rswtSttHeadListExport, rswtSttNodeListExport } from "./headList"; -import type { SelectDataType } from "@common/business_components/ui"; @@ -24,16 +24,17 @@ export type rswtSttnState = { rswtSttNodeList: CommonTableProps[]; excelList: []; isInit: boolean; + rswtSttnResCount: number; }; }; type rswtSttnActions = { - rswtSttnInit: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; - rswtSttnSearch: (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => void; + rswtSttnInit: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; + rswtSttnSearch: (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => void; rswtChSttnHead: ( headList: z.infer<typeof sttnHeadListType>, ) => void; @@ -48,6 +49,7 @@ export const rswtSttnStateExport: rswtSttnState = { rswtSttnRes: rswtSttnRes, excelList: [], isInit: false, + rswtSttnResCount: 1, }, }; @@ -57,12 +59,11 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = ( set: any ) => { return { - rswtSttnInit: async (page: number, total: string, con: string, txt: string, + rswtSttnInit: async (isExcel: boolean, page: number, total: string, con: string, txt: string, sidoCode: SelectDataType[], sggCode: SelectDataType[]) => { try { - - const rswtSttnRes = await getFetch( + const rswtSttnRes = await getFetchWithCount( fetchType.WR, `/reuseFc/waterreuseFc` + (page ? `/${page}` : "/1") + @@ -70,34 +71,7 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = ( (con ? `/${con}` : "/0") + (txt ? `/${txt}` : "") ); - set((state: rswtSttnState) => { - return { - ...state, - rswtSttn: { - ...state.rswtSttn, - rswtSttnRes: rswtSttnRes, - isInit: false, - }, - }; - }); - } catch (e) { - console.log(e) - } - }, - rswtSttnSearch: async (page: number, total: string, con: string, txt: string, - sidoCode: SelectDataType[], - sggCode: SelectDataType[]) => { - try { - console.log("헐", page) - const rswtSttnRes = await getFetch( - fetchType.WR, - `/reuseFc/waterreuseFc` + - (page ? `/${page}` : "/1") + - (total ? `/${total}` : "/20") + - (con ? `/${con}` : "/0") + - (txt ? `/${txt}` : "") - ); - if (Number(total) > 9000) { + if (isExcel) { const rswtExcel = excelRSwtSttnParsing(rswtSttnRes, sidoCode, sggCode); set((state: rswtSttnState) => { return { @@ -115,7 +89,48 @@ export const rswtSttnActionsExport: (set: any) => rswtSttnActions = ( ...state, rswtSttn: { ...state.rswtSttn, - rswtSttnRes: rswtSttnRes, + rswtSttnRes: rswtSttnRes.data, + rswtSttnResCount: rswtSttnRes.count, + isInit: false, + }, + }; + }); + } catch (e) { + console.log(e) + } + }, + rswtSttnSearch: async (isExcel: boolean, page: number, total: string, con: string, txt: string, + sidoCode: SelectDataType[], + sggCode: SelectDataType[]) => { + try { + const rswtSttnRes = await getFetchWithCount( + fetchType.WR, + `/reuseFc/waterreuseFc` + + (page ? `/${page}` : "/1") + + (total ? `/${total}` : "/20") + + (con ? `/${con}` : "/0") + + (txt ? `/${txt}` : "") + ); + if (isExcel) { + const rswtExcel = excelRSwtSttnParsing(rswtSttnRes, sidoCode, sggCode); + set((state: rswtSttnState) => { + return { + ...state, + rswtSttn: { + ...state.rswtSttn, + excelList: rswtExcel, + }, + }; + }); + } else + set((state: rswtSttnState) => { + + return { + ...state, + rswtSttn: { + ...state.rswtSttn, + rswtSttnRes: rswtSttnRes.data, + rswtSttnResCount: rswtSttnRes.count, isInit: false, }, }; diff --git a/apps/wr/app/store/stats/matStat/headList.tsx b/apps/wr/app/store/stats/matStat/headList.tsx deleted file mode 100644 index 881662774..000000000 --- a/apps/wr/app/store/stats/matStat/headList.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import type { TableUpperProps } from "../../common/type/header"; - -export const matStatHeadListExport :TableUpperProps[]=[ - { - id: "시도", - title: "시도", - row:0, - rowSpan:2 - }, - { - id: "개소", - title: "개소", - row:0, - rowSpan:2 - }, - { - id: "요구수량", - title: "요구수량", - row:0, - rowSpan:2 - }, - - - { - id: "용도", - title: "용도", - row:0, - colSpan:6 - }, - { - id: "조경용수", - title: "조경용수", - row:1, - }, - { - id: "청소화장실용수", - title: "청소화장실용수", - row:1, - }, - { - id: "농업용수", - title: "농업용수", - row:1, - }, - { - id: "공업용수", - title: "공업용수", - row:1, - }, - { - id: "친수용수", - title: "친수용수", - row:1, - }, - { - id: "기타", - title: "기타", - row:1, - }, - { - id: "사업비", - title: "사업비(천원)", - row:0, - rowSpan:2 - }, - - -] \ No newline at end of file diff --git a/apps/wr/app/store/stats/matStat/index.tsx b/apps/wr/app/store/stats/matStat/index.tsx deleted file mode 100644 index 3f2e5813f..000000000 --- a/apps/wr/app/store/stats/matStat/index.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import type { TableUpperProps } from "../../common/type/header"; -import { matStatHeadListExport } from "./headList"; - -type matStatActions = { -} - - -export type matStatState = { - matStat: { - matStatHeadList:TableUpperProps[] - } -} - -export type matStatType = matStatState & matStatActions; - -export const matStatExport: matStatState = { - matStat: { - matStatHeadList:matStatHeadListExport - } -} - -export const matStatActionsExport: (set: any) => matStatActions = ( - set: any -) => { - return { - - } -} \ No newline at end of file diff --git a/apps/wr/app/store/stats/rainStat/index.tsx b/apps/wr/app/store/stats/rainStat/index.tsx index d6e48a53e..c54f1542e 100644 --- a/apps/wr/app/store/stats/rainStat/index.tsx +++ b/apps/wr/app/store/stats/rainStat/index.tsx @@ -4,6 +4,7 @@ import { excelRainStat } from "./excel"; import { rainStatHeadListExport } from "./headList"; export type RainStatProps = { + cityText: string ctpvCd: string //시도 sggCd: string //시군구 areaNm: string //행정구역명 diff --git a/apps/wr/app/store/stats/rswtStat/excel.tsx b/apps/wr/app/store/stats/rswtStat/excel.tsx index 35f567253..7c6e2b4cc 100644 --- a/apps/wr/app/store/stats/rswtStat/excel.tsx +++ b/apps/wr/app/store/stats/rswtStat/excel.tsx @@ -25,7 +25,7 @@ export const excelRswtStat = (excelList:RswtStatProps[]) : (string | number)[][] //String(item.instlCst) ?? "", "", //건축물면적 - item.archArea ?? "", + // item.archArea ?? "", //처리용량 item.filtrTrtmfctCpct ?? "", //물사용량 diff --git a/apps/wr/app/store/stats/rswtStat/headList.tsx b/apps/wr/app/store/stats/rswtStat/headList.tsx index 877089092..c0860fea7 100644 --- a/apps/wr/app/store/stats/rswtStat/headList.tsx +++ b/apps/wr/app/store/stats/rswtStat/headList.tsx @@ -13,21 +13,22 @@ export const rswtStatHeadListExport :TableUpperProps[]=[ row:0, rowSpan:2 }, - { - id: "a", - title: "시설현황", - row:0, - colSpan:2 - }, - { - id: "archArea", - title: "건축연면적(m³)", - row:1, - }, + // { + // id: "a", + // title: "시설현황", + // row:0, + // colSpan:2 + // }, + // { + // id: "archArea", + // title: "건축연면적(m³)", + // row:1, + // }, { id: "filtrTrtmfctCpct", title: "처리용량(m³)", - row:1, + row:0, + rowSpan:2 }, { id: "wtrUsqty", diff --git a/apps/wr/app/store/stats/rswtStat/index.tsx b/apps/wr/app/store/stats/rswtStat/index.tsx index 4e2a7ecc8..af106c3b3 100644 --- a/apps/wr/app/store/stats/rswtStat/index.tsx +++ b/apps/wr/app/store/stats/rswtStat/index.tsx @@ -4,6 +4,7 @@ import { rswtStatHeadListExport } from "./headList"; import { excelRswtStat } from "./excel"; export type RswtStatProps = { + cityText: string //시도명 ctpvCd: string //시도 sggCd : string //시군구 areaNm: string //행정구역명 @@ -72,7 +73,6 @@ export const rswtStatActionsExport: (set: any) => rswtStatActions = ( return { searchRswtStatList: async (year: string) => { const res = await getFetch(fetchType.WR, `/reuseChk/reuseWater/stat/${year}`) - const rswtStatList: RswtStatProps[] = []; const cityArr: any[] = []; res.forEach((item: RswtStatProps) => { diff --git a/apps/wr/app/store/store.tsx b/apps/wr/app/store/store.tsx index 7520f7998..63a4eee13 100644 --- a/apps/wr/app/store/store.tsx +++ b/apps/wr/app/store/store.tsx @@ -11,12 +11,19 @@ import { type comCodeState, type comCodeType, } from "./common/code"; +import { comFcltSearchAction, comFcltStateExport, type comFcltState, type comFcltType } from "./common/searchCode"; import { matDmdActionsExport, matDmdStateExport, type matDmdState, type matDmdType, } from "./matDmd"; +import { coRvwActionsExport, coRvwStateExport, type coRvwState, type coRvwType } from "./matDmd/coMatRvw"; +import { coSttnActionsExport, coSttnStateExport, type coSttnState, type coSttnType } from "./matDmd/coSttn"; // 옮겨야함 +import { drgtActionsExport, drgtStateExport, type drgtState, type drgtType } from "./matDmd/drgtSttn"; +import { ldrmntActionsExport, ldrmntStateExport, type ldrmntState, type ldrmntType } from "./matDmd/ldrmntCoSttn"; +import { ruseCaseActionsExport, ruseCaseStateExport, type ruseCaseState, type ruseCaseType } from "./matDmd/ruseCaseMng"; +import { ruseHstryActionsExport, ruseHstryStateExport, type ruseHstryState, type ruseHstryType } from "./matDmd/ruseRvwHstry"; import { rainChkgdnActionsExport, rainChkgdnStateExport, @@ -29,6 +36,15 @@ import { type rswtChkgdnState, type rswtChkgdnType, } from "./prfmncReg/chkgdnReg/rswrtChkgdn"; +import { pbnstPrfmncActionsExport, pbnstPrfmncStateExport, type pbnstPrfmncState, type pbnstPrfmncType } from "./prfmncReg/pbnstPrfmncReg"; +import { + rainChkSttnActionsExport, + rainChkSttnStateExport, + type rainChkSttnState, + type rainChkSttnType, +} from "./prfmncSttn/chkgdnSttn/rainChkgdnSttn"; +import { rswtChkStateExport, rswtChkSttnActionsExport, type rswtChkSttnState, type rswtChkSttnType } from "./prfmncSttn/chkgdnSttn/rswtChkgdnSttn"; +import { pbnstPrfmncSttnActionsExport, pbnstPrfmncSttnExport, type pbnstPrfmncSttnState, type pbnstPrfmncSttnType } from "./prfmncSttn/pbnstPrfmncSttn"; import { bdstActionsExport, bdstStateExport, @@ -59,6 +75,13 @@ import { type rswtFacState, type rswtFacType, } from "./ruseFcltMng/fcltReg/rswtReg"; +import { + htdflSttnActionsExport, + htdflSttnStateExport, + type htdflSttnState, + type htdflSttnType, +} from "./ruseFcltMng/fcltSttn/htdflSttn"; +import { pbnstSttnActionsExport, pbnstSttnStateExport, type pbnstSttnState, type pbnstSttnType } from "./ruseFcltMng/fcltSttn/pbnstSttn"; import { rainSttnActionsExport, rainSttnStateExport, @@ -71,32 +94,8 @@ import { type rswtSttnState, type rswtSttnType, } from "./ruseFcltMng/fcltSttn/rswtSttn"; -import { - htdflSttnActionsExport, - htdflSttnStateExport, - type htdflSttnState, - type htdflSttnType, -} from "./ruseFcltMng/fcltSttn/htdflSttn"; -import { - rainChkSttnActionsExport, - rainChkSttnStateExport, - type rainChkSttnState, - type rainChkSttnType, -} from "./prfmncSttn/chkgdnSttn/rainChkgdnSttn"; -import { rswtChkStateExport, rswtChkSttnActionsExport, type rswtChkSttnState, type rswtChkSttnType } from "./prfmncSttn/chkgdnSttn/rswtChkgdnSttn"; -import { pbnstSttnActionsExport, pbnstSttnStateExport, type pbnstSttnState, type pbnstSttnType } from "./ruseFcltMng/fcltSttn/pbnstSttn"; -import { coSttnActionsExport, coSttnStateExport, type coSttnState, type coSttnType } from "./matDmd/coSttn"; // 옮겨야함 -import { comFcltStateExport, comFcltSearchAction, type comFcltState, type comFcltType } from "./common/searchCode"; -import { pbnstPrfmncActionsExport, pbnstPrfmncStateExport, type pbnstPrfmncState, type pbnstPrfmncType } from "./prfmncReg/pbnstPrfmncReg"; -import { coRvwActionsExport, coRvwStateExport, type coRvwState, type coRvwType } from "./matDmd/coMatRvw"; -import { ruseHstryActionsExport, ruseHstryStateExport, type ruseHstryState, type ruseHstryType } from "./matDmd/ruseRvwHstry"; -import { pbnstPrfmncSttnActionsExport, pbnstPrfmncSttnExport, type pbnstPrfmncSttnState, type pbnstPrfmncSttnType } from "./prfmncSttn/pbnstPrfmncSttn"; -import { drgtActionsExport, drgtStateExport, type drgtState, type drgtType } from "./matDmd/drgtSttn"; -import { ruseCaseActionsExport, ruseCaseStateExport, type ruseCaseType, type ruseCaseState } from "./matDmd/ruseCaseMng"; import { rainStatActionsExport, rainStatExport, type rainStatState, type rainStatType } from "./stats/rainStat"; -import { type rswtStatType, type rswtStatState, rswtStatExport, rswtStatActionsExport } from "./stats/rswtStat"; -import { matStatActionsExport, matStatExport, type matStatState, type matStatType } from "./stats/matStat"; -import { ldrmntActionsExport, ldrmntStateExport, type ldrmntState, type ldrmntType } from "./matDmd/ldrmntCoSttn"; +import { rswtStatActionsExport, rswtStatExport, type rswtStatState, type rswtStatType } from "./stats/rswtStat"; export type WrStore = comCodeType & pubFacType & @@ -123,7 +122,6 @@ export type WrStore = comCodeType & ruseCaseType& rainStatType& rswtStatType& - matStatType& comFcltType ; @@ -153,8 +151,7 @@ export const StoreZus = ( drgtState& ruseCaseState& rainStatState& - rswtStatState& - matStatState + rswtStatState = { ...comCodeStateExport, ...pubFacStateExport, @@ -181,7 +178,6 @@ export const StoreZus = ( ...ruseCaseStateExport, ...rainStatExport, ...rswtStatExport, - ...matStatExport, ...comFcltStateExport } ) => { @@ -219,8 +215,7 @@ export const StoreZus = ( ...drgtActionsExport(set), ...ruseCaseActionsExport(set), ...rainStatActionsExport(set), - ...rswtStatActionsExport(set), - ...matStatActionsExport(set) + ...rswtStatActionsExport(set) }; }); }; diff --git a/apps/wr/components/lib/api/index.ts b/apps/wr/components/lib/api/index.ts index 452788eb0..8772959e1 100644 --- a/apps/wr/components/lib/api/index.ts +++ b/apps/wr/components/lib/api/index.ts @@ -1,6 +1,6 @@ //8880 -import { CS_URL, DEV_URL_FO, DEV_URL_WR, LOCAL_URL } from "../config/"; +import { DEV_URL_FO, DEV_URL_WR, LOCAL_URL } from "../config/"; export const fetchType = { COMMON: "common", WR: "wr", LOCAL: "LOCAL" , CS: "CS" }; @@ -66,11 +66,14 @@ export const getFetchWithCount = async (type: string, url: string) => { if (!response.ok) { console.log(`오류 발생: ${response.status}`); } + const contentType = response.headers.get("content-type") ?? ""; if (contentType.includes("application/json")) { // JSON 응답 처리 const res = await response.json(); + + return res; } else { // 파일 응답 처리 (ex. PDF, Excel 등) @@ -105,8 +108,18 @@ export const postFectch = async (url: string, params: any, type?: string) => { return await response.json(); }; -export const putFectch = async (url: string, params: any) => { - const response = await fetch(DEV_URL_WR + url, { +export const putFectch = async (url: string, params: any,type?:string) => { + const div = + type === fetchType.COMMON + ? DEV_URL_FO + : type === fetchType.LOCAL + ? LOCAL_URL + : type === fetchType.CS + ? '' + : DEV_URL_WR; + + + const response = await fetch(div + url, { method: "PUT", headers: { "Content-Type": "application/json", @@ -129,7 +142,6 @@ export const deleteFectch = async (url: string, params?: any, type?: string) => ? '' : DEV_URL_WR; - console.log("deleteFectch url", div + url); const response = await fetch(div + url, { method: "DELETE", headers: { diff --git a/apps/wr/components/lib/func/TableData.tsx b/apps/wr/components/lib/func/TableData.tsx index 8bed17187..8fc3b7eef 100644 --- a/apps/wr/components/lib/func/TableData.tsx +++ b/apps/wr/components/lib/func/TableData.tsx @@ -1,15 +1,15 @@ +import { numSize } from "@/app/store/common/code/basicCode"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { rainChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; import { Checkbox, Input, TableCell, TableRow } from "@common/components/ui"; -import { useEffect } from "react"; export const rainChkTableData = (chkData: rainChkZodType[]) => { - // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 + // 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기 const maketotal = chkData.map((item: rainChkZodType) => { const selectTotal = item.guideDetails.reduce((acc: any, cur: any) => { const code = cur.utztnUsgCd; - const fk = cur.chkgdnFk; + const fk = cur.chkgdnSn; const key = `${fk}_${code}`; acc[key] = acc[key] || { @@ -22,7 +22,7 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => { return acc; }, {}); - return selectTotal; // 모든 키: `${chkgdnFk}_${utztnUsgCd}` 형태 + return selectTotal; // 모든 키: `${chkgdnSn}_${utztnUsgCd}` 형태 }); // 2. 누계 정보들을 하나의 객체로 합치기 (평탄화) @@ -33,7 +33,7 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => { const updatedRainyDetails: any[] = []; chkData.forEach((rd: rainChkZodType) => { rd.rainyDetails.forEach((rainyItem: any) => { - const key = `${rainyItem.chkgdnFk}_${rainyItem.utztnUsgCd}`; + const key = `${rainyItem.chkgdnSn}_${rainyItem.utztnUsgCd}`; const totals = flatTotalMap[key] || { totalSplyUswtrUtztnQnt: 0, totalRuseFcltUtztnQnt: 0, @@ -53,11 +53,11 @@ export const rainChkTableData = (chkData: rainChkZodType[]) => { }; export const rswtChkTableData = (chkData: rswtChkZodType[]) => { - // 1. chkgdnFk + utztnUsgCd 기준 누계 정보 만들기 + // 1. chkgdnSn + utztnUsgCd 기준 누계 정보 만들기 const makeRswtData: any[] = []; - if(chkData&&chkData.length>0){ + if (chkData && chkData.length > 0) { chkData?.forEach((root) => { root.rswtrDetails.forEach((detail) => { @@ -99,10 +99,11 @@ export const chRowspanTable = ( let order = 0 // rowspan된 셀 렌더링 여부 추적용 const renderedMap = new Map<string, Set<number>>(); - + return ( <> - {makeTableData.map((row, rowIndex) => ( + {/* {makeTableData.map((row, rowIndex) => ( */} + {makeTableData && makeTableData.length > 0 ? (makeTableData.map((row, rowIndex) => ( <TableRow key={rowIndex}> {headList .map((head) => { @@ -132,9 +133,9 @@ export const chRowspanTable = ( > {key === "checkBox" ? ( <Checkbox - checked={selectedIds.includes(row.chkgdnPk)} + checked={selectedIds.includes(row.chkgdnSn)} onCheckedChange={(checked) => - toggleSelection(row.chkgdnPk, checked === true) + toggleSelection(row.chkgdnSn, checked === true) } ></Checkbox> ) : key === "order" ? ( @@ -161,7 +162,14 @@ export const chRowspanTable = ( handleChange(rowIndex, head.id, e.target.value); }} value={value || ""} - disabled={!selectedIds.includes(row.chkgdnPk)} + disabled={!selectedIds.includes(row.chkgdnSn)} + maxLength={numSize} + //input type number일때 slice 처리 + onInput={(e: React.ChangeEvent<HTMLInputElement>) => { + if (head.type === 'number' && e.target.value.length > numSize) { + e.target.value = e.target.value.slice(0, numSize); + } + }} /> ) : ( (head.id === "totalSplyUswtrUtztnQnt" || head.id === "totalRuseFcltUtztnQnt" || head.id === "splyUswtrUtztnQnt" || head.id === "ruseFcltUtztnQnt") ? ( @@ -177,7 +185,13 @@ export const chRowspanTable = ( })} </TableRow> - ))} + ))) : ( + <TableRow> + <TableCell colSpan={headList.length} className="h-24 text-center text-gray-500"> + 조회된 결과가 없습니다. + </TableCell> + </TableRow> + )} </> ); }; @@ -235,44 +249,44 @@ export const InputTableBody = ( } return span; }; - return ( + return ( <> {chgRes.map((data, dataIndex) => { // 소계/총합계 행 판별 const isSubTotal = data["용수명"] === "소계"; const isTotal = data["구분"] === 0; - + const bgClass = isTotal ? "bg-[#d5e1eb] font-bold" : isSubTotal - ? "bg-[#e6eef5] font-semibold" - : ""; + ? "bg-[#e6eef5] font-semibold" + : ""; return ( <TableRow key={dataIndex + "row"}> {headList.map((head, headIndex) => { - // 총합계 행이면 "구분"에서 colSpan=2로 병합 - if ( - data["구분"] === 0 && - head.id === "구분" - ) { - return ( - <TableCell - key={head.id + headIndex} - colSpan={2} - className="font-bold text-center bg-[#d5e1eb]" - > - 총합계 - </TableCell> - ); - } - // 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음 - if ( - data["구분"] === 0 && - head.id === "용수명" - ) { - return null; - } + // 총합계 행이면 "구분"에서 colSpan=2로 병합 + if ( + data["구분"] === 0 && + head.id === "구분" + ) { + return ( + <TableCell + key={head.id + headIndex} + colSpan={2} + className="font-bold text-center bg-[#d5e1eb]" + > + 총합계 + </TableCell> + ); + } + // 총합계(합계) 행이면 "용수명" 컬럼은 렌더링하지 않음 + if ( + data["구분"] === 0 && + head.id === "용수명" + ) { + return null; + } // mergeCell 처리 if (head.mergeCell) { const rowSpan = getRowSpan(chgRes, head.id, dataIndex); @@ -292,6 +306,7 @@ export const InputTableBody = ( handleChange(dataIndex, head.id, e.target.value, setInputData) } value={data[head.id as keyof any] ?? ""} + maxLength={numSize} /> </TableCell> ) : ( diff --git a/apps/wr/components/lib/func/commom.tsx b/apps/wr/components/lib/func/commom.tsx index 7d8c2ffcc..5c2ce97ff 100644 --- a/apps/wr/components/lib/func/commom.tsx +++ b/apps/wr/components/lib/func/commom.tsx @@ -1,29 +1,31 @@ import type { comCodeState } from "@/app/store/common/code"; import { filePickedBlob, - type SelectDataType, - type ReturnType, filePickedBlobArray, + type ReturnType, + type SelectDataType, type SheetParameter, } from "@common/business_components/ui"; +import { Button } from "@common/components/ui"; import type { RefObject } from "react"; +import toast from "react-hot-toast"; export const getCity = (val: string, sggCd: SelectDataType[]) => { - let data:any - if(val !=='0'){ + let data: any + if (val !== '0') { data = sggCd - .filter((item) => String(item.val).substring(0, 2) === val) - .map((item) => ({ - val: item.val, - text: item.text, // 한국어 텍스트 - })); - }else{ + .filter((item) => String(item.val).substring(0, 2) === val) + .map((item) => ({ + val: item.val, + text: item.text, // 한국어 텍스트 + })); + } else { data = sggCd - .map((item) => ({ - val: item.val, - text: item.text, // 한국어 텍스트 - })); + .map((item) => ({ + val: item.val, + text: item.text, // 한국어 텍스트 + })); } data.unshift({ val: "0", text: "전체" }); return data; @@ -92,7 +94,7 @@ export const excelDownload = ( export const excelArrayDownload = ( fileNm: string, sampleFile: string, - sheetArray:SheetParameter [] + sheetArray: SheetParameter[] ) => { if (!sheetArray) return; fetch(`/${sampleFile}`, {}).then(async (response) => { @@ -113,7 +115,7 @@ export const handleCommaNumberChange = ( ) => { const raw = e.target.value.replace(/,/g, ""); if (!/^\d*$/.test(raw)) return; - onChange(raw === "" ? "" : Number(raw)); + onChange(raw === "" ? "" : Number(raw)); }; @@ -124,7 +126,7 @@ export const handleMinusNumberChange = ( ) => { const raw = e.target.value.replace(/,/g, ""); if (!/^\d*$/.test(raw)) return; - onChange(raw === "" ? -1 : Number(raw)); + onChange(raw === "" ? -1 : Number(raw)); }; // 숫자입력시 , 삽입 @@ -175,14 +177,14 @@ export const getdmdMatFlag = (flag: string | undefined | null) => { case "Matched": return "매칭완료"; case "Checked": - return '검토완료'; + return '검토완료'; default: return "신청"; } }; -export const formatPhoneNumber=(tel:string) => { +export const formatPhoneNumber = (tel: string) => { const onlyNums = tel.replace(/[^0-9]/g, ''); if (onlyNums.length === 10) { return onlyNums.replace(/(\d{2})(\d{4})(\d{4})/, '$1-$2-$3'); @@ -191,4 +193,32 @@ export const formatPhoneNumber=(tel:string) => { } else { return tel; // 유효하지 않으면 빈 문자열 } +} + +export const confirmToast = (content: string, saveFunc: () => void) => { + toast((t) => ( + <span className="flex flex-col items-center"> + <div className="mb-6"> + {content} + </div> + <div className="flex flex-row space-x-2"> + <Button + size={"sm"} + onClick={() => { + saveFunc(); + toast.dismiss(t.id); + }} + > + 확인 + </Button> + <Button + size={"sm"} + onClick={() => toast.dismiss(t.id)}>취소</Button> + </div> + </span> + ), + { + id: "global-confirm-toast", // 중복 토스트 방지 + duration: Infinity, // 자동 사라짐 방지 + }); } \ No newline at end of file diff --git a/apps/wr/components/lib/useTus_wr/useTusWr.tsx b/apps/wr/components/lib/useTus_wr/useTusWr.tsx index b9441e6a4..c7580f84f 100644 --- a/apps/wr/components/lib/useTus_wr/useTusWr.tsx +++ b/apps/wr/components/lib/useTus_wr/useTusWr.tsx @@ -1,12 +1,14 @@ +import type { FilesType } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; +import toast from "react-hot-toast"; import { Upload, + type DetailedError, type HttpRequest, type HttpResponse, type OnSuccessPayload, - type DetailedError, } from "tus-js-client"; -import { CS_TUS_UPLOAD, CS_URL } from "../config"; -import type { FilesType } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; +import { fetchType, putFectch } from "../api"; +import { CS_TUS_UPLOAD } from "../config"; type UploadOptions = { handleUploadStart?: (upload: Upload) => void; @@ -23,16 +25,14 @@ export type ReturnFileType = { lnkgDmnId: string | null; lnkgDmnNm: string | null; regDt: Date | null; - atflCd: String; + atflCd: string; atflSn: number; - atflId: String; - physFileNm: String; + atflId: string; + physFileNm: string; }; export const TusClientUpload = (oFile: FilesType, options?: UploadOptions) => new Promise<ReturnFileType>((resolve, reject) => { try { - const Authorization = "Authorization"; - const AUTH_USER_ID = "token-id"; let fileInfo: string | undefined; //CS_URL const uploader = new Upload(oFile.file, { @@ -60,8 +60,30 @@ export const TusClientUpload = (oFile: FilesType, options?: UploadOptions) => onSuccess(payload: OnSuccessPayload) { options?.handleSuccess?.(payload); if (fileInfo) { - console.log('fileInfo', fileInfo); - resolve(JSON.parse(fileInfo) as ReturnFileType); + + + const WrTableInfo = { + lnkgDmnNm: "tbWrRuseFcltFile", + lnkgDmnId: "fileTkn", + }; + + console.log('fileInfo ', fileInfo) + const fileParse = JSON.parse(fileInfo) as ReturnFileType; + putFectch( + `/attach-service/api/v1/atfl/attachments/${fileParse.atflCd}/info`, + WrTableInfo, + fetchType.CS + ) + .then(() => { + resolve(fileParse); + }) + .catch(() => { + reject({ + causingError: { + cause: "파일 업로드 업데이트 실패", + }, + } as DetailedError); + }); } else reject({} as DetailedError); }, }); @@ -71,6 +93,8 @@ export const TusClientUpload = (oFile: FilesType, options?: UploadOptions) => } catch (e) { console.log(e); reject(e as DetailedError); + + toast.error(String(e)); } // setUpload(uploader); }); diff --git a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx index ee06893c9..f39181078 100644 --- a/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx +++ b/apps/wr/components/ui/form/coMat/conCostForm/conCostForm.tsx @@ -1,3 +1,4 @@ +"use client"; import { useWrStore } from "@/app/store"; import { usageProcData } from "@/app/store/matDmd/coMatRvw/headList"; import type { @@ -18,7 +19,6 @@ import { Form, FormField, FormUi, - UiModal, UiTable, } from "@common/business_components/ui"; import PopoverUi from "@common/business_components/ui/popover_ui"; @@ -65,30 +65,6 @@ export default function ConCostForm({ }, [selectionVersion]); - const confrirmToast = () => { - - if (checkFinish) { - toast((t) => ( - <span className="flex flex-col items-center"> - 검토완료 변경시 공사비는 변경할수 없습니다. - <br /> - 진행하시겠습니까? - <Button - onClick={() => { - toast.dismiss(t.id); - - - }} - > - 확인 - </Button> - <Button onClick={() => toast.dismiss(t.id)}>취소</Button> - </span> - )); - } else { - - } - }; const zipDowonLoad = () => { fetch(`/2024_constarctFeeProgram.zip`, {}).then(async (response) => { @@ -105,7 +81,6 @@ export default function ConCostForm({ const dmndQtyWatch = form.watch("dmndQty"); const totalConstCost = form.watch("totalConstCost"); const cstrnCst = form.watch("demandCst.cstrnCst"); - const useUsgCdWatch = form.watch("useUsgCd"); const calculateConstCost = useCallback(() => { const usgPrcsProcs = usgPrcsProcsWatch; @@ -205,7 +180,7 @@ export default function ConCostForm({ onClick={() => { toast.dismiss(t.id); - coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data); + coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoId"), data); }} > 확인 @@ -217,7 +192,7 @@ export default function ConCostForm({ </span> )); } else { - coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoFk"), data); + coMatRvwUpdate("11000SW001R1", form.getValues("dmdInfoId"), data); } } } else if (type === "hist") { @@ -233,7 +208,7 @@ export default function ConCostForm({ useEffect(() => { form.register("dmdInfoSn"); - form.register("dmdInfoFk"); + form.register("dmdInfoId"); form.register("ruseUtztnFcltNm"); }, []); @@ -372,6 +347,7 @@ export default function ConCostForm({ type="number" step="0.001" onChange={(e) => { + console.log('dmndQty ', e) //field.onChange(Number(e.target.value) * 365 ); }} value={Number(field.value) * 365 || 0} @@ -398,9 +374,7 @@ export default function ConCostForm({ } childrenBody={ <> - <ConstCostFeeTable - setReturnData={(e) => {}} - ></ConstCostFeeTable> + <ConstCostFeeTable/> </> } bodyClassName={"w-[40vw] h-full"} @@ -437,9 +411,8 @@ export default function ConCostForm({ } childrenBody={ <> - <RateFeeTableModal - setReturnData={(e) => {}} - ></RateFeeTableModal> + <RateFeeTableModal/> + </> } bodyClassName={"w-[22vw]"} @@ -499,7 +472,10 @@ export default function ConCostForm({ className="mt-2" type="number" step="0.01" - onChange={(e) => {}} + onChange={(e) => { + console.log('totalConstCost ', e) + + }} value={field.value ?? 0} readOnly /> diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx new file mode 100644 index 000000000..bafa7566d --- /dev/null +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstAdd.tsx @@ -0,0 +1,143 @@ +"use client"; + +import { useWrStore } from "@/app/store"; +import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { formH1Class } from "@/components/lib/class/comClass"; +import { safeDate } from "@/components/lib/func/commom"; +import { DatePicker, FormField, FormUi, SelectBox } from "@common/business_components"; +import { Button, Checkbox, Input } from "@common/components"; +import { useState } from "react"; +import { useFieldArray } from "react-hook-form"; + +export default function BdstAdd({ form, readonly }: { form: any; readonly?: boolean; }) { + + const { code } = useWrStore((state) => { + return state; + }); + + const { fields, append, remove } = useFieldArray({ + name: "chgBuilding", + control: form?.control, // Provide a fallback to avoid errors + }); + + const plusHist = () => { + append({ + bdstNm: "", + daddr: "", + bdstUsgCd: "", + }); + }; + const [selectedIds, setSelectedIds] = useState<string[]>([]); + + const toggleSelect = (id: string) => { + setSelectedIds((prev) => + prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] + ); + }; + + const removeSelected = () => { + const idxsToRemove = fields + .map((item, idx) => (selectedIds.includes(item.id) ? idx : -1)) + .filter((index) => index > -1) + .sort((prevIndex, nextIndex) => nextIndex - prevIndex); + + remove(idxsToRemove); + setSelectedIds([]); + }; + + return ( + <> + <h1 className={formH1Class}>중축, 개축, 재축</h1> + {!readonly && ( + <div className="flex justify-end gap-2 mt-4"> + + <Button type="button" className="" size={"sm"} onClick={plusHist}> + 이력추가 + </Button> + <Button + type="button" + className="!bg-red-500 text-white" + size={"sm"} + onClick={removeSelected} + > + 삭제 + </Button> + + </div> + )} + {fields.map((field, index) => ( + <div + key={field.id} + // className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center" + className={`grid ${ + readonly ? "grid-cols-3" : "grid-cols-[auto,1fr,1fr,1fr]" + } gap-2 mt-4 items-center`} + > + {!readonly && ( + <div className="col-span-1 flex justify-center mr-4"> + <Checkbox + checked={selectedIds.includes(field.id)} + onCheckedChange={() => toggleSelect(field.id)} + /> + </div> + )} + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.bdstChgNm`} + render={({ field: f }) => ( + <FormUi label="구분"> + <SelectBox + selectClass={selectClass} + selectArray={code.chBuCd} + onSelectValue={(val) => f.onChange(val)} + value={f.value ?? code.chBuCd[0]?.val} + className={""} + label={""} + /> + </FormUi> + )} + /> + </div> + + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgPrmsnDt`} + render={({ field: f }) => ( + <FormUi label="허가일"> + <DatePicker + mode="single" + field={{ + value: safeDate(f.value) || new Date(), + onChange: (date) => f.onChange(date), + }} + selectClass="w-full" + /> + </FormUi> + )} + /> + </div> + <div className=""> + <FormField + control={form.control} + name={`chgBuilding.${index}.archChgArea`} + render={({ field: f }) => ( + <FormUi label="면적"> + <Input + placeholder="-" + type="text" + onChange={(e) => f.onChange(e.target.value)} + value={f.value || ''} + className={selectClass} + /> + </FormUi> + )} + /> + </div> + </div> + ))} + <div className="border-b border-gray-300 my-4"> </div> + </> + ) +} \ No newline at end of file diff --git a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx index 31e8dbacb..726f4e689 100644 --- a/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx +++ b/apps/wr/components/ui/form/fcltReg/bdstReg/bdstReg.tsx @@ -1,13 +1,6 @@ import { useWrStore } from "@/app/store"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { formH1Class } from "@/components/lib/class/comClass"; -import { - formatCommaNumber, - getCity, - handleCommaNumberChange, - safeDate, -} from "@/components/lib/func/commom"; -import type { objSearchType } from "@/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal"; import { FormField, FormUi, @@ -15,61 +8,55 @@ import { SelectBox, type SelectDataType, } from "@common/business_components"; -import { Button, Checkbox, Input } from "@common/components"; +import { Input } from "@common/components"; import { useEffect, useState } from "react"; -import { useFieldArray } from "react-hook-form"; export default function BdstReg({ form, type }: { form: any; type?: string }) { const { code } = useWrStore((state) => { return state; }); - const { fields, append, remove } = useFieldArray({ - name: "chgBuilding", - control: form?.control, // Provide a fallback to avoid errors - }); + const {userSiSggCd } =code + const [useCityCd, setUserCityCd] = useState<SelectDataType[]>([]) + const [useSggCd, setUserSggCd] = useState<SelectDataType[]>([]) + + // const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>(); + // const [objSearch, setObjSearch] = useState<objSearchType>({ + // sgg: "", + // city: "", + // }); - const plusHist = () => { - append({ - bdstNm: "", - daddr: "", - bdstUsgCd: "", + useEffect(() =>{ + if(userSiSggCd.length===2 && code.cityCd.length>0){ + const city = code.cityCd.filter((item) => item.val === userSiSggCd) + const sgg = code.sggCd.filter((item) => item.val.slice(0,2) === userSiSggCd ) + sgg.unshift({text:'전체' , val:'0'}) + setUserCityCd(city) // Fix: Ensure city is of type SelectDataType[] + setUserSggCd(sgg) + if (city[0]?.val) { + // 여기 중요 + queueMicrotask(() => { + form.setValue("ctpvCd", Number(city[0]?.val), { shouldDirty: true, shouldTouch: true, shouldValidate: true }); }); - }; - const removeSelected = () => { - const idxsToRemove = fields - .map((item, idx) => (selectedIds.includes(item.id) ? idx : -1)) - .filter((index) => index > -1) - .sort((prevIndex, nextIndex) => nextIndex - prevIndex); + } + }else if(userSiSggCd.length===5 && code.cityCd.length>0 && code.sggCd.length>0) { + const city = code.cityCd.filter((item) => item.val === userSiSggCd.slice(0,2)) + const sgg = code.sggCd.filter((item) => item.val === userSiSggCd) + setUserSggCd(sgg) + setUserCityCd(city) + form.setValue('ctpvCd',Number(city[0]?.val) ) + form.setValue('sggCd',Number(sgg[0]?.val) ) - remove(idxsToRemove); - setSelectedIds([]); - }; + } + },[form, userSiSggCd, code.cityCd, code.sggCd]) - const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>(); - const [objSearch, setObjSearch] = useState<objSearchType>({ - sgg: "", - city: "", - }); - const getSelCity = (val: string) => { - const data = getCity(val, code.sggCd); - setSelectSgg(data); - const sgg = form.getValues("sggCd"); - setObjSearch({ city: val, sgg: "" }); - }; - - const getSgg = (val: string | number) => { - const sgg = form.getValues("sggCd"); - setObjSearch({ ...objSearch, sgg: val != "" ? String(val) : sgg }); - }; - - useEffect(() => { - const city = form.getValues("ctpvCd"); - const sgg = form.getValues("sggCd"); - setObjSearch({ city: city, sgg: sgg }); - }, [selectSgg]); + // useEffect(() => { + // const city = form.getValues("ctpvCd"); + // const sgg = form.getValues("sggCd"); + // setObjSearch({ city: city, sgg: sgg }); + // }, [selectSgg]); useEffect(() => { const subscription = form.form?.watch((value: any) => { @@ -79,17 +66,17 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { return () => subscription?.unsubscribe(); }, [form.form]); - const [selectedIds, setSelectedIds] = useState<string[]>([]); - const toggleSelect = (id: string) => { - setSelectedIds((prev) => - prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id] - ); - }; + + useEffect(() =>{ + + console.log('form.formState ', form.watch()) + + },[form.formState]) return ( <> - <h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '발전소 기본 정보'}</h1> + <h1 className={formH1Class}> { type !== "HTB"?"건축물 기본 정보": '시설 기본 정보'}</h1> <div className="grid grid-cols-6 gap-2 mt-4"> <div className="col-span-3"> <FormField @@ -101,12 +88,11 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { className="col-span-3" label={""} selectClass={selectClass} - selectArray={code.cityCd} + selectArray={useCityCd} onSelectValue={(val) => { - getSelCity(String(val)); field.onChange(Number(val)); }} - value={field.value} + value={typeof field.value !== "undefined" ? field.value : useCityCd[0]?.val} /> </FormUi> )} @@ -122,9 +108,8 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { className="col-span-3" label={""} selectClass={`w-full min-h-[2.9rem] ${selectClass}`} - selectArray={selectSgg ? selectSgg : code.sggCd || []} + selectArray={useSggCd} onSelectValue={(val) => { - getSgg(val); field.onChange(Number(val)); }} value={field.value} @@ -140,12 +125,15 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { control={form.control} name="bdstNm" render={({ field }) => ( - <FormUi label={ type !== "HTB"?"건축물명": '발전소명'}> + <FormUi label={ type !== "HTB"?"건축물명": '시설명'}> <Input className={selectClass} - placeholder= {type !== "HTB"?"건축물 명 입력하세요":'발전소명 입력하세요' } + placeholder= {type !== "HTB"?"건축물 명 입력하세요":'시설명 입력하세요' } type="text" - {...field} + onChange={(e) => { + field.onChange(e.target.value) + }} + value={field.value||''} /> </FormUi> )} @@ -156,12 +144,15 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { control={form.control} name="daddr" render={({ field }) => ( - <FormUi label= { type !== "HTB"?"건축물 주소": '발전소 주소'} > + <FormUi label= { type !== "HTB"?"건축물 주소": '시설 주소'} > <Input className={selectClass} placeholder="위치를 입력해주세요" type="search" - {...field} + onChange={(e) => { + field.onChange(e.target.value) + }} + value={field.value||''} /> </FormUi> )} @@ -180,6 +171,9 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { value: field.value ?? new Date(), onChange: (date: Date | undefined) => field.onChange(date), }} + // modifiers={{ + // disabled: { after: new Date() } + // }} selectClass={"w-full"} ></DatePicker> </FormUi> @@ -225,7 +219,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { onChange={(e) => { field.onChange(e.target.value) }} - value={field.value} + value={field.value||''} /> </FormUi> )} @@ -252,88 +246,7 @@ export default function BdstReg({ form, type }: { form: any; type?: string }) { /> </div> </div> - <h1 className={formH1Class}>중축, 개축, 재축</h1> - <div className="flex justify-end gap-2 mt-4"> - <Button type="button" className="" size={"sm"} onClick={plusHist}> - 이력추가 - </Button> - <Button - type="button" - className="!bg-red-500 text-white" - size={"sm"} - onClick={removeSelected} - > - 삭제 - </Button> - </div> - {fields.map((field, index) => ( - <div - key={field.id} - className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center" - > - <div className="col-span-1 flex justify-center mr-4"> - <Checkbox - checked={selectedIds.includes(field.id)} - onCheckedChange={() => toggleSelect(field.id)} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.bdstChgNm`} - render={({ field: f }) => ( - <FormUi label="구분"> - <SelectBox - selectClass={selectClass} - selectArray={code.chBuCd} - onSelectValue={(val) => f.onChange(val)} - value={f.value ?? code.chBuCd[0]?.val} - className={""} - label={""} - /> - </FormUi> - )} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.archChgPrmsnDt`} - render={({ field: f }) => ( - <FormUi label="허가일"> - <DatePicker - mode="single" - field={{ - value: safeDate(f.value) || new Date(), - onChange: (date) => f.onChange(date), - }} - selectClass="w-full" - /> - </FormUi> - )} - /> - </div> - <div className=""> - <FormField - control={form.control} - name={`chgBuilding.${index}.archChgArea`} - render={({ field: f }) => ( - <FormUi label="면적"> - <Input - placeholder="-" - type="text" - onChange={(e) => f.onChange} - value={f.value} - className={selectClass} - /> - </FormUi> - )} - /> - </div> - </div> - ))} - <div className="border-b border-gray-300 my-4"> </div> - </> + </> ) : ( <></> )} diff --git a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx index 83051672d..4cfba4fd5 100644 --- a/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/htdflReg/htdflRegForm.tsx @@ -1,29 +1,32 @@ "use client"; +import { useWrStore } from "@/app/store"; +import { numSize, txtSize } from "@/app/store/common/code/basicCode"; +import { + hdtflZod, + type customHtdflBdst, +} from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; +import { formH1Class } from "@/components/lib/class/comClass"; +import { + confirmToast, + formatCommaNumber, + handleCommaNumberChange, +} from "@/components/lib/func/commom"; import { Form, FormField, FormUi, SelectBox, } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; +import { Button, Input, ScrollArea } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; +import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; -import { z } from "zod"; -import { useWrStore } from "@/app/store"; -import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { - hdtflZod, - type customHtdflBdst, -} from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import { useEffect } from "react"; -import BdstReg from "../bdstReg/bdstReg"; -import { - formatCommaNumber, - handleCommaNumberChange, -} from "@/components/lib/func/commom"; -import { formH1Class } from "@/components/lib/class/comClass"; import toast from "react-hot-toast"; +import { useTranslation } from "react-i18next"; +import { z } from "zod"; +import BdstReg from "../bdstReg/bdstReg"; export default function HtdflRegForm({ htdflForm, @@ -46,19 +49,27 @@ export default function HtdflRegForm({ }); const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]); + const bdstNm = form.watch("bdstNm"); + const isPowerPlant = bdstNm?.includes("발전소"); + const { t } = useTranslation('base'); const onSubmit = (values: z.infer<typeof hdtflZod>) => { if (isModal) { const data = regCtpvCd ? regCtpvCd : regSggcd ? regSggcd : "noCd"; - if (data === "noCd") { toast.error("시도/시군구 코드를 선택해야합니다."); return; } - htdflBdstReg(values,data); - if (setIsModal) setIsModal(false); + const handleConfirm = async () => { + htdflBdstReg(values, data); + if (setIsModal) setIsModal(false); + }; + confirmToast(t('isInsertMsg'), handleConfirm); } else { + const handleConfirm = async () => { + htdflBdstUpdate(values, "0"); + }; + confirmToast(t('isUpdateMsg'), handleConfirm); - htdflBdstUpdate(values, "41"); } }; @@ -86,6 +97,16 @@ export default function HtdflRegForm({ })), }; }; + const [divStyle, setDivStyle] = useState("h-[53vh]"); + useEffect(() => { + if (isModal === true) { + setDivStyle("h-[53vh] max-h-[37vh]") + } else if (readonly === true) { + setDivStyle("h-[62vh]") + } else { + setDivStyle("h-[53vh]") + } + }, [isModal, readonly]); useEffect(() => { console.log("form errors:", form.formState.errors); @@ -98,7 +119,7 @@ export default function HtdflRegForm({ form.reset(cleanHtdflData(htdflForm)); } // Case 2: 데이터가 없는 순수 신규 등록 모드인 경우 - if(isModal) { + if (isModal) { const firstYnValue = code.yn?.[0]?.val; const firstHtdPowerMthdCd = code.htdPowerMthdCd?.[0]?.val; const firstHtdUtztnUsgCd = code.htdUtztnUsgCd?.[0]?.val; @@ -117,12 +138,25 @@ export default function HtdflRegForm({ } }, [htdflForm, code, form]); + useEffect(() => { + if (!isPowerPlant) { + form.setValue( + "reuseBuilding.0.htdflObj.etgtType", + "해당없음", // 빈 문자열로 초기화 + { shouldDirty: true } // dirty 상태로 남길지 여부는 취사선택 + ); + } + }, [isPowerPlant, form]); + return ( <div className="!mx-[1.6rem] !p-0r"> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> {/* <div className="flex justify-between items-center mx-3"> */} <div> + <h1 className="text-2xl font-bold text-gray-900 mt-3 ml-1"> + {readonly && `(${htdflForm?.bdstNm})`} + </h1> <div className="grid grid-cols-12 flex items-center card-header"> <h1 className="text-2xl font-medium text-label col-span-10"> 온배수 시설 등록 @@ -138,549 +172,569 @@ export default function HtdflRegForm({ )} </div> </div> + <ScrollArea className={divStyle}> + {isModal && htdflForm != undefined ? ( + <BdstReg form={form} type="HTB" /> + ) : ( + <></> + )} + {isModal ? ( + <div className=" my-4"> + <h1 className={formH1Class}>온배수 시설 정보 </h1> + </div> + ) : ( + <></> + )} - {isModal && htdflForm != undefined ? ( - <BdstReg form={form} type="HTB" /> - ) : ( - <></> - )} - {isModal ? ( + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.etgtType" + render={({ field }) => ( + <FormUi label="발전유형"> + <SelectBox + className={""} + label={""} + selectClass={selectClass} + selectArray={code.htdPowerMthdCd} + onSelectValue={readonly ? () => { } : field.onChange} + // value={field.value ?? ""} + value={field.value || (code?.htdPowerMthdCd[0] &&code?.htdPowerMthdCd[0].val)} + readOnly={readonly || !isPowerPlant} + /> + </FormUi> + )} + /> + </div> + + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.fclCpct" // 이름 이상함. + render={({ field }) => ( + <FormUi label="설비용량(KW)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.plwtYn" + render={({ field }) => ( + <FormUi label="담수화 여부"> + <SelectBox + className={""} + label={""} + selectClass={selectClass} + selectArray={code.yn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? ""} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + </div> <div className=" my-4"> - <h1 className={formH1Class}>온배수 시설 정보 </h1> - </div> - ) : ( - <></> - )} - - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.etgtType" - render={({ field }) => ( - <FormUi label="발전유형"> - <SelectBox - className={""} - label={""} - selectClass={selectClass} - selectArray={code.htdPowerMthdCd} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? ""} - readOnly={readonly} - /> - </FormUi> - )} - /> + <h1 className={formH1Class}>온배수 시설 운영현황</h1> </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.fclCpct" // 이름 이상함. - render={({ field }) => ( - <FormUi label="설비용량(KW)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.plwtYn" - render={({ field }) => ( - <FormUi label="담수화 여부"> - <SelectBox - className={""} - label={""} - selectClass={selectClass} - selectArray={code.yn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? ""} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> - <div className=" my-4"> - <h1 className={formH1Class}>온배수 시설 운영현황</h1> - </div> - - <div className="grid grid-cols-10 gap-1 mt-4"> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.orgwtWtritSpt" - render={({ field }) => ( - <FormUi label="원수취수 지점"> - <Input - className={selectClass} - placeholder="" - type="text" - value={field.value ?? ''} - onChange={(e) => { - if (!readonly) field.onChange((e.target.value)); - }} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.orgwtOcrnProcs" - render={({ field }) => ( - <FormUi label="원수발생 공정"> - <Input - className={selectClass} - placeholder="" - type="text" - value={field.value ?? ""} - onChange={(e) => { - if (!readonly) field.onChange(e.target.value); - }} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.wtritEntrcTp" - render={({ field }) => ( - <FormUi label="취수구 온도(℃)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.emsnExitTp" - render={({ field }) => ( - <FormUi label="배출구 온도(℃)"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.amtgnr" - render={({ field }) => ( - <FormUi label="발생량(m³/년)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.prcsProcsYn" - render={({ field }) => ( - <FormUi label="처리공정 유무"> - <SelectBox - className={""} - label={""} - selectClass={selectClass} - selectArray={code.yn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? ""} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.prcsFcltCpct" - render={({ field }) => ( - <FormUi label="처리시설 용량(m³/년)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.fmYn" - render={({ field }) => ( - <FormUi label="유량계유무"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.yn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? ""} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.utztnCpct" - render={({ field }) => ( - <FormUi label="이용량(m³/년)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.utztnUsg" - render={({ field }) => ( - <FormUi label="이용용도"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.htdUtztnUsgCd} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? ""} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> - - <div className=" my-2"> - <h1 className={formH1Class}>수질</h1> - </div> - - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.grssClfg" - render={({ field }) => ( - <FormUi label="총대장균군"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className="grid grid-cols-10 gap-1 mt-4"> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.orgwtWtritSpt" + render={({ field }) => ( + <FormUi label="원수취수 지점"> + <Input + className={selectClass} + placeholder="" + type="text" + value={field.value ?? ''} + onChange={(e) => { + if (!readonly) field.onChange((e.target.value)); + }} + readOnly={readonly} + maxLength={txtSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.orgwtOcrnProcs" + render={({ field }) => ( + <FormUi label="원수발생 공정"> + <Input + className={selectClass} + placeholder="" + type="text" + value={field.value ?? ""} + onChange={(e) => { + if (!readonly) field.onChange(e.target.value); + }} + readOnly={readonly} + maxLength={txtSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.wtritEntrcTp" + render={({ field }) => ( + <FormUi label="취수구 온도(℃)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.emsnExitTp" + render={({ field }) => ( + <FormUi label="배출구 온도(℃)"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.amtgnr" + render={({ field }) => ( + <FormUi label="발생량(m³/년)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.prcsProcsYn" + render={({ field }) => ( + <FormUi label="처리공정 유무"> + <SelectBox + className={""} + label={""} + selectClass={selectClass} + selectArray={code.yn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? ""} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.prcsFcltCpct" + render={({ field }) => ( + <FormUi label="처리시설 용량(m³/년)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.fmYn" + render={({ field }) => ( + <FormUi label="유량계유무"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.yn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? ""} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.utztnCpct" + render={({ field }) => ( + <FormUi label="이용량(m³/년)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.utztnUsg" + render={({ field }) => ( + <FormUi label="이용용도"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.htdUtztnUsgCd} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? ""} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> </div> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.tn" - render={({ field }) => ( - <FormUi label="총질소"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> - - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.combResdch" - render={({ field }) => ( - <FormUi label="결합잔류염소"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className=" my-2"> + <h1 className={formH1Class}>수질</h1> </div> - <div className="col-span-6 "> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.tph" - render={({ field }) => ( - <FormUi label="총인"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.grssClfg" + render={({ field }) => ( + <FormUi label="총대장균군"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.trbt" - render={({ field }) => ( - <FormUi label="탁도"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.tn" + render={({ field }) => ( + <FormUi label="총질소"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> </div> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.ph" - render={({ field }) => ( - <FormUi label="수소이온농도"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.combResdch" + render={({ field }) => ( + <FormUi label="결합잔류염소"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.bod" - render={({ field }) => ( - <FormUi label="생물학적 산소요구량"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className="col-span-6 "> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.tph" + render={({ field }) => ( + <FormUi label="총인"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> </div> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.clIonQnt" - render={({ field }) => ( - <FormUi label="염화물"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.trbt" + render={({ field }) => ( + <FormUi label="탁도"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.smll" - render={({ field }) => ( - <FormUi label="냄새"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.ph" + render={({ field }) => ( + <FormUi label="수소이온농도"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> </div> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.cdtnv" - render={({ field }) => ( - <FormUi label="전기전도도"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.bod" + render={({ field }) => ( + <FormUi label="생물학적 산소요구량"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> - <div className="grid grid-cols-12 gap-4"> - <div className="col-span-6"> - <FormField - control={form.control} - name="reuseBuilding.0.htdflObj.crmty" - render={({ field }) => ( - <FormUi label="색도"> - <Input - className={selectClass} - placeholder="10" - type="text" - onChange={(e) => { - if (!readonly) - handleCommaNumberChange(e, field.onChange); - }} - value={formatCommaNumber(field.value)} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.clIonQnt" + render={({ field }) => ( + <FormUi label="염화물"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> </div> - </div> + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.smll" + render={({ field }) => ( + <FormUi label="냄새"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.cdtnv" + render={({ field }) => ( + <FormUi label="전기전도도"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + </div> + + <div className="grid grid-cols-12 gap-4"> + <div className="col-span-6"> + <FormField + control={form.control} + name="reuseBuilding.0.htdflObj.crmty" + render={({ field }) => ( + <FormUi label="색도"> + <Input + className={selectClass} + placeholder="10" + type="text" + onChange={(e) => { + if (!readonly) + handleCommaNumberChange(e, field.onChange); + }} + value={formatCommaNumber(field.value)} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + )} + /> + </div> + </div> + </ScrollArea> </form> </Form> </div> diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx index a1d433f2d..37e6d3a5c 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx @@ -13,7 +13,6 @@ import { fcBizSchema, type fcBizType, type PbnstRegArrrayType, - type ppInstlType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { @@ -22,13 +21,12 @@ import { formTableName, } from "@/components/lib/class/comClass"; import FcOrgwtsRegModal from "@/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal"; -import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable"; import { SelectBox } from "@common/business_components"; import { DatePicker, FormUi, UiModal } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; -import { Button, DataTable, Input, Label } from "@common/components"; +import { Button, Input, Label } from "@common/components"; import { useEffect, useRef, useState } from "react"; -import { useFieldArray, useForm, type UseFormReturn } from "react-hook-form"; +import { useFieldArray, type UseFormReturn } from "react-hook-form"; import MngRegFormDetail from "../mngReg/mngRegFormDetail/mngRegFormDetail"; import { formatCommaNumber, @@ -54,7 +52,6 @@ export function PbnstBuseForm({ indexBiz: number; setIndexBiz: (index: number) => void; }) { - const ref = useRef<ppInstlType[] | null>(null); const { code, pbnst, @@ -68,10 +65,10 @@ export function PbnstBuseForm({ control: form.control, name: `items.${indexMng}.fcBizs`, }); - const [ppiSelectList, setPpiSelectList] = - useState<[{ name: string; val: SelectDataType[] }]>(); + const [ppiSelectList, setPpiSelectList] = useState< + { name: string; val: SelectDataType[] }[] | undefined + >(); const [ppiYn, setPpiYn] = useState("Y"); - const [selectBizCycle, setSelectBizCycle] = useState< { text: string; @@ -111,15 +108,12 @@ export function PbnstBuseForm({ const fcOrgwts = form.watch(`items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`); useEffect(() => { - console.log("fcOrgwts", fcOrgwts); if (fcOrgwts && fcOrgwts?.length > 0) { - const swtrmtFcltFkList = fcOrgwts?.map((item) => item.swtrmtFcltFk); + const swtrmtFcltIdList = fcOrgwts?.map((item) => item.swtrmtFcltId); - console.log("swtrmtFcltFkList ", swtrmtFcltFkList); - - if (swtrmtFcltFkList.length > 0) { + if (swtrmtFcltIdList.length > 0) { getFcOrgwts( - swtrmtFcltFkList.filter((item): item is string => item != null), + swtrmtFcltIdList.filter((item): item is string => item != null), fcOrgwts?.length ); } @@ -128,13 +122,11 @@ export function PbnstBuseForm({ useEffect(() => { if (fcOrgwtsNmList && fcOrgwtsNmList.length > 0) { - fcOrgwts?.forEach((item, index) => { const orgwtNm = fcOrgwtsNmList.find( - (orgwt) => orgwt.bscFctCd === item.swtrmtFcltFk + (orgwt) => orgwt.bscFctCd === item.swtrmtFcltId )?.bscFctNm; - console.log("orgwtNm ", orgwtNm); if (orgwtNm) { form.setValue( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts.${index}.ruseUtztnFcltNm`, @@ -171,7 +163,7 @@ export function PbnstBuseForm({ // 🧩 새로운 fcBizs 기본 객체 생성 (필수값만 채우고 나머지는 default로) const newItem = fcBizSchema.parse({ cycl: pbnstBizCycle + 1, - pbnstRuseFcltFk: formRuse.pbnstRuseFcltPk, + pbnstRuseFcltId: formRuse.pbnstRuseFcltId, fcOrgwts: undefined, pplInstls: undefined, fcDemands: undefined, @@ -179,15 +171,7 @@ export function PbnstBuseForm({ appendBiz(newItem); setIndexBiz(pbnstBizCycle); // 새로 추가된 차수로 포커스 이동 } - useEffect(() => { - //console.log("form ", form.watch()); - }, [form.formState]); - - const { - fields: fcDemands, - append: appendDemand, - remove: removeDemand, - } = useFieldArray({ + const { fields: fcDemands, append: appendDemand } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcBizs.${indexBiz}.fcDemands`, }); @@ -209,15 +193,7 @@ export function PbnstBuseForm({ prevDemandsLengthRef.current = fcDemands.length; }, [fcDemands.length]); - const { fields: fcOrgwtFiled } = useFieldArray({ - control: form.control, - name: `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts`, - }); - const { - fields: pplInstls, - append: appendPpl, - remove: removePpl, - } = useFieldArray({ + const { append: appendPpl, remove: removePpl } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcBizs.${indexBiz}.pplInstls`, }); @@ -230,11 +206,11 @@ export function PbnstBuseForm({ const plusHist = () => { if ( - form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizPk`) + form.getValues(`items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizSn`) ) { appendPpl({ - ruseFcltBizFk: form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizPk` + pbnstRuseFcltBizSn: form.getValues( + `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizSn` ), choose: false, ppMqlt: "", @@ -260,14 +236,14 @@ export function PbnstBuseForm({ splyEndDay: new Date(), splyCpct: 0, splyFmYn: "Y", - pbnstRuseFcltBizPk: form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizPk` + pbnstRuseFcltBizSn: form.getValues( + `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltBizSn` ), - pbnstRuseFcltFk: + pbnstRuseFcltId: form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltFk` + `items.${indexMng}.fcBizs.${indexBiz}.pbnstRuseFcltId` ) ?? "", - dmdInfoPk: "", + dmdInfoId: "", //telno: "", }); }; @@ -293,7 +269,7 @@ export function PbnstBuseForm({ if (code.pplLenght) { ppl.push({ name: "pplQulity", val: code.pplQulity }); } - if (ppl.length > 0) { + if (ppl && ppl.length > 0) { setPpiSelectList(ppl); } else { setPpiSelectList(undefined); @@ -314,7 +290,12 @@ export function PbnstBuseForm({ setSumCpct(sum); }, [form.formState, indexMng, indexBiz]); + useEffect(() => { + console.log("form.formState ", form.formState); + }, [form.formState]); + const pbnstBiz = form.watch(`items.${indexMng}.fcBizs`); + return ( <> {pbnstBiz && pbnstBiz?.length > 0 ? ( @@ -417,17 +398,19 @@ export function PbnstBuseForm({ 추가등록 </Button> </div> - <RuseMngTable + <RuseMngTableForm key={`fcOrgwts-${indexMng}-${indexBiz}`} // 이게 핵심! - tableData={ form.getValues( `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts` - ) ?? [] + ) || [] + // fcOrgwtWatch||[] } + form={form} headList={pbnst.pbnstOrgwtHeadList} upHeadList={[]} indexMng={indexMng} + formNm={"fcOrgwts"} indexBiz={indexBiz} /> </div> @@ -445,7 +428,7 @@ export function PbnstBuseForm({ <Label className="text-right">합계</Label> <Input type="text" - value={ formatCommaNumber(sumCpct)} + value={formatCommaNumber(sumCpct)} readOnly={true} className="w-32 border-gray-300 rounded pr-8 " /> @@ -479,26 +462,15 @@ export function PbnstBuseForm({ form.getValues( `items.${indexMng}.fcBizs.${indexBiz}.pplInstls` ) ?? [] + // pplInstlsWatch||[] } headList={pbnst.pplInstlsHeadLisat} code={ppiSelectList ?? []} - //ref={ref} indexMng={indexMng} indexBiz={indexBiz} form={form} formNm={"pplInstls"} upHeadList={[]} - onTableSet={(val) => { - const pplSum = form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.pplInstls` - ); - if (!pplSum) return; - let sum = 0; - pplSum.forEach((item) => { - sum += Number(item.cpct) || 0; - }); - setSumCpct(sum); - }} /> </div> @@ -543,173 +515,173 @@ export function PbnstBuseForm({ </div> <div ref={demandsContainerRef}> {fcDemands.map((field, index) => ( - <div + <div key={field.id} // useFieldArray의 고유 id를 key로 사용 className="grid grid-cols-12 gap-4 mt-3 border-b border-gray-400 pb-3" - > - <div key={index + "keySon1"} className="col-span-4"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.dmdCoNm`} - render={({ field: f }) => ( - <FormUi label="수요처명"> - <SearchInputText - label={"수요처"} - initValue={f.value} - setValue={(val) => { - f.onChange(val); - if (val && val.length > 2) { - getDemandCompList(val, 3); + > + <div key={index + "keySon1"} className="col-span-4"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.dmdCoNm`} + render={({ field: f }) => ( + <FormUi label="수요처명"> + <SearchInputText + label={"수요처"} + initValue={f.value} + setValue={(val) => { + f.onChange(val); + if (val && val.length > 2) { + getDemandCompList(val, 3); + } + }} + setRtnData={(valList: any) => { + if (valList) { + form.setValue( + `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.daddr`, + valList.daddr + ); + form.setValue( + `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.useUsgCd`, + valList.useUsgCd + ); + form.setValue( + `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`, + valList.splyCpct + ); + form.setValue( + `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.dmdInfoId`, + valList.dmdInfoId?.toString() + ); + } + }} + searchList={demandCompList?.map((item) => { + return { + ...item, + searchNm: item.dmdCoNm, + searchPk: item.dmdInfoId, + }; + })} + ></SearchInputText> + </FormUi> + )} + /> + </div> + <div key={index + "keySon2"} className="col-span-4"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.daddr`} + render={({ field: f }) => ( + <FormUi label="위치(주소)"> + <Input + placeholder="-" + type="text" + readOnly + onChange={(e) => f.onChange(e.target.value)} + value={f.value} + className={selectClass} + /> + </FormUi> + )} + /> + </div> + <div key={index + "keySon3"} className="col-span-4"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.useUsgCd`} + render={({ field: f }) => ( + <FormUi label="사용용도"> + <SelectBox + label={""} + selectClass={""} + className="w-full" + selectArray={code.dmdUszCd} + onSelectValue={f.onChange} + value={f.value ?? code.dmdUszCd[0]?.val} + /> + </FormUi> + )} + /> + </div> + <div key={index + "keySon4"} className="col-span-3"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyBgngDay`} + render={({ field: f }) => ( + <FormUi label="공급시작일"> + <DatePicker + mode={"single"} + field={{ + value: safeDate(f.value) || new Date(), + onChange: (date: Date | undefined) => + f.onChange(date), + }} + selectClass={"rounded-lg !w-full"} + /> + </FormUi> + )} + /> + </div> + <div key={index + "keySon5"} className="col-span-3"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyEndDay`} + render={({ field: f }) => ( + <FormUi label="공급종료일"> + <DatePicker + mode={"single"} + onSelect={(date: Date | undefined) => + f.onChange(date) } - }} - setRtnData={(valList: any) => { - if (valList) { - form.setValue( - `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.daddr`, - valList.daddr - ); - form.setValue( - `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.useUsgCd`, - valList.useUsgCd - ); - form.setValue( - `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`, - valList.splyCpct - ); - form.setValue( - `items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.dmdInfoPk`, - valList.dmdInfoPk?.toString() - ); + field={{ + value: safeDate(f.value) || new Date(), + onChange: (date: Date | undefined) => + f.onChange(date), + }} + selectClass={"rounded-lg !w-full"} + /> + </FormUi> + )} + /> + </div> + <div key={index + "keySon6"} className="col-span-3"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`} + render={({ field: f }) => ( + <FormUi label="(계약)공급량(m³/일)"> + <Input + placeholder="" + type="text" + onChange={(e) => { + handleCommaNumberChange(e, f.onChange); + }} + value={formatCommaNumber(f.value)} + /> + </FormUi> + )} + /> + </div> + <div key={index + "keySon7"} className="col-span-3"> + <FormField + control={form.control} + name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyFmYn`} + render={({ field: f }) => ( + <FormUi label="공급 유량계 유무"> + <SelectBox + label={""} + selectClass={""} + className="w-full" + selectArray={code.yn} + onSelectValue={(val: string | number) => + f.onChange(val) } - }} - searchList={demandCompList?.map((item) => { - return { - ...item, - searchNm: item.dmdCoNm, - searchPk: item.dmdInfoPk, - }; - })} - ></SearchInputText> - </FormUi> - )} - /> + value={f.value ?? code.yn[0]?.val} + /> + </FormUi> + )} + /> + </div> </div> - <div key={index + "keySon2"} className="col-span-4"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.daddr`} - render={({ field: f }) => ( - <FormUi label="위치(주소)"> - <Input - placeholder="-" - type="text" - readOnly - onChange={(e) => f.onChange(e.target.value)} - value={f.value} - className={selectClass} - /> - </FormUi> - )} - /> - </div> - <div key={index + "keySon3"} className="col-span-4"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.useUsgCd`} - render={({ field: f }) => ( - <FormUi label="사용용도"> - <SelectBox - label={""} - selectClass={""} - className="w-full" - selectArray={code.dmdUszCd} - onSelectValue={f.onChange} - value={f.value ?? code.dmdUszCd[0]?.val} - /> - </FormUi> - )} - /> - </div> - <div key={index + "keySon4"} className="col-span-3"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyBgngDay`} - render={({ field: f }) => ( - <FormUi label="공급시작일"> - <DatePicker - mode={"single"} - field={{ - value: safeDate(f.value) || new Date(), - onChange: (date: Date | undefined) => - f.onChange(date), - }} - selectClass={"rounded-lg !w-full"} - /> - </FormUi> - )} - /> - </div> - <div key={index + "keySon5"} className="col-span-3"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyEndDay`} - render={({ field: f }) => ( - <FormUi label="공급종료일"> - <DatePicker - mode={"single"} - onSelect={(date: Date | undefined) => - f.onChange(date) - } - field={{ - value: safeDate(f.value) || new Date(), - onChange: (date: Date | undefined) => - f.onChange(date), - }} - selectClass={"rounded-lg !w-full"} - /> - </FormUi> - )} - /> - </div> - <div key={index + "keySon6"} className="col-span-3"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyCpct`} - render={({ field: f }) => ( - <FormUi label="(계약)공급량(m³/일)"> - <Input - placeholder="" - type="text" - onChange={(e) => { - handleCommaNumberChange(e, f.onChange); - }} - value={formatCommaNumber(f.value)} - /> - </FormUi> - )} - /> - </div> - <div key={index + "keySon7"} className="col-span-3"> - <FormField - control={form.control} - name={`items.${indexMng}.fcBizs.${indexBiz}.fcDemands.${index}.splyFmYn`} - render={({ field: f }) => ( - <FormUi label="공급 유량계 유무"> - <SelectBox - label={""} - selectClass={""} - className="w-full" - selectArray={code.yn} - onSelectValue={(val: string | number) => - f.onChange(val) - } - value={f.value ?? code.yn[0]?.val} - /> - </FormUi> - )} - /> - </div> - </div> ))} </div> </div> @@ -723,9 +695,11 @@ export function PbnstBuseForm({ bodyClass={"w-[70vw] max-w-none max-h-[90vh] overflow-y-auto"} body={ <FcOrgwtsRegModal - initTableData={form.getValues( - `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts` - ) ?? []} + initTableData={ + form.getValues( + `items.${indexMng}.fcBizs.${indexBiz}.fcOrgwts` + ) ?? [] + } closeModal={() => { setIsFcOrgwts(false); }} diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx index e1454342b..52730f64b 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx @@ -9,9 +9,8 @@ import { } from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; import { Button, Input } from "@common/components"; -import { useEffect, useState } from "react"; -import { useFieldArray, useWatch, type UseFormReturn } from "react-hook-form"; -import { z } from "zod"; +import { useEffect, useRef, useState } from "react"; +import { useFieldArray, type UseFormReturn } from "react-hook-form"; import { commonButonSize, formH1Class, @@ -19,8 +18,6 @@ import { } from "@/components/lib/class/comClass"; import { TusClientUpload } from "@/components/lib/useTus_wr/useTusWr"; import { - pbnstRegZod, - type customPbnst, type fcFileType, type PbnstRegArrrayType, type selectLabel, @@ -33,6 +30,7 @@ import { handleCommaNumberChange, formatCommaNumber, } from "@/components/lib/func/commom"; +import { numSize, txtSize } from "@/app/store/common/code/basicCode"; export type FilesType = { atflCd: string; file: File; @@ -46,15 +44,13 @@ export function PbnstMngForm({ }: { form: UseFormReturn<{ items: PbnstRegArrrayType }>; formType: string; - firstFcltData?: customPbnst; indexMng: number; setIndexMng: (index: number) => void; }) { - const { code, pbnst, pbnstInsert, fileDelete, fileDownLoad } = useWrStore( + const { code, pbnst, fileDelete, fileDownLoad } = useWrStore( (state) => state ); - - const { pbnstRes } = pbnst; + const fileInitRef = useRef<{ index: number; key: string } | null>(null); const [regFileList, setRegFileList] = useState<fcFileType[] | null>(null); const [planFiles, setPlanFiles] = useState<FilesType[] | null>(null); const [relationfiles, setRelationFiles] = useState<FilesType[] | null>(null); @@ -64,23 +60,23 @@ export function PbnstMngForm({ const { fields: fcOpersField, - append, + prepend, remove, } = useFieldArray({ control: form.control, name: `items.${indexMng}.fcOpers`, }); - const watchedItem = useWatch({ + const { fields: mngRegForm } = useFieldArray({ control: form.control, - name: `items.${indexMng}`, + name: `items`, }); const plusHist = () => { - append({ + prepend({ choose: false, - pbnstRuseFcltFk: - form.getValues(`items.${indexMng}.pbnstRuseFcltPk`) ?? "", + pbnstRuseFcltId: + form.getValues(`items.${indexMng}.pbnstRuseFcltId`) ?? "", rgtr: "", mdfr: "", operMthd: "", @@ -88,6 +84,8 @@ export function PbnstMngForm({ bgngDt: new Date(), endDt: new Date(), }); + //trigger(`items.${indexMng}.fcOpers`); + }; const removeSelected = () => { @@ -121,6 +119,7 @@ export function PbnstMngForm({ atflCd: tusFile.atflCd.toString(), file: item, }); + // eslint-disable-next-line @typescript-eslint/no-unused-expressions type === "relation" ? setRelationFiles(setReFiles) : setPlanFiles(setReFiles); @@ -147,6 +146,7 @@ export function PbnstMngForm({ } }); } + // eslint-disable-next-line @typescript-eslint/no-unused-expressions type === "relation" ? setRelationFiles(setReFiles) : setPlanFiles(setReFiles); @@ -171,68 +171,69 @@ export function PbnstMngForm({ }; useEffect(() => { - if (indexMng >= 0) { - const defaultFiles = watchedItem?.fcFiles; - if (defaultFiles && defaultFiles.length > 0) { - const relationFileList = defaultFiles.filter( - (item) => item.fileKnd === "계통도" - ); + const currentItem = form.getValues(`items.${indexMng}`); + const currentKey = JSON.stringify(currentItem); + const isNewItem = + !fileInitRef.current || + fileInitRef.current.index !== indexMng || + fileInitRef.current.key !== currentKey; - const planFileList = defaultFiles.filter( - (item) => item.fileKnd === "평면도" - ); - if (relationFileList.length > 0) - setRelationFiles( - relationFileList.map((item) => ({ - atflCd: item.fileTkn, - file: new File([] as BlobPart[], item.filePath), - })) - ); - else { - setRelationFiles(null); - } + if (!isNewItem) return; // - if (planFileList.length > 0) - setPlanFiles( - planFileList.map((item) => ({ - atflCd: item.fileTkn, - file: new File([] as BlobPart[], item.filePath), - })) - ); - else { - setPlanFiles(null); - } + const defaultFiles = currentItem?.fcFiles || []; + + const relationFileList = defaultFiles.filter( + (item) => item.fileKnd === "계통도" + ); + const planFileList = defaultFiles.filter( + (item) => item.fileKnd === "평면도" + ); + + setRelationFiles( + relationFileList.length > 0 + ? relationFileList.map((item) => ({ + atflCd: item.fileTkn, + file: new File([], item.filePath), + })) + : null + ); + + setPlanFiles( + planFileList.length > 0 + ? planFileList.map((item) => ({ + atflCd: item.fileTkn, + file: new File([], item.filePath), + })) + : null + ); + // ✅ 다음 루프에선 다시 안 하도록 저장 + fileInitRef.current = { + index: indexMng, + key: currentKey, + }; + }, [indexMng, form.getValues(`items.${indexMng}`)]); + + useEffect( + () => { + //폼이 들어오면 폼에 대한 이름 셀렉트박스를만들기 위해 + if (mngRegForm && mngRegForm.length >= 0) { + const fcltNmList = mngRegForm?.map((item, index) => ({ + text: item.ruseUtztnFcltNm, + val: String(index), + })); + if (fcltNmList) setFcltNm(fcltNmList); } else { - setRelationFiles(null); - setPlanFiles(null); + setFcltNm(null); } - } - }, [watchedItem, indexMng]); + }, //pbnst.pbnstRes + [mngRegForm] + ); useEffect(() => { - // pbnstMngData(pbnst.pbnstMngRegData); - }, [pbnst.pbnstMngRegData]); - - useEffect(() => { - if (pbnst.pbnstRes && pbnst.pbnstRes?.length >= 0) { - const fcltNmList = pbnst.pbnstRes?.map((item, index) => ({ - text: item.ruseUtztnFcltNm, - val: String(index), - })); - - console.log(" fcltNmList ", fcltNmList); - if (fcltNmList) setFcltNm(fcltNmList); - } else { - setFcltNm(null); + if (regFileList && regFileList?.length > 0) { + form.setValue(`items.${indexMng}.fcFiles`, regFileList); } - }, [pbnst.pbnstRes]); - - // 2. Define a submit handler. - function onSubmit(values: z.infer<typeof pbnstRegZod>) { - values.fcOpers = []; - values.fcFiles = regFileList || []; - pbnstInsert(values); - } + }, [regFileList, indexMng]); useEffect(() => { if (relationfiles) { @@ -251,14 +252,6 @@ export function PbnstMngForm({ } }, [code]); - useEffect(() => { - // console.log(' fcltNm ', watchedItem?.ruseUtztnFcltNm) - }, [watchedItem]); - - useEffect(() => { - console.log(" form indexMng ", indexMng); - }, [indexMng]); - return ( <div className=" !mx-[1.6rem] !p-0r"> <div> @@ -301,6 +294,7 @@ export function PbnstMngForm({ }} value={field.value ?? ""} readOnly={formType === "sttn" ? true : false} + maxLength={txtSize} /> </FormUi> )} @@ -310,34 +304,36 @@ export function PbnstMngForm({ </div> <div> + {/* <div className="h-[200px] overflow-y-auto"> */} + <div className="flex justify-between items-center mx-3 mb-3"> + <span className={formTableName}>재이용시설 운영정보</span> + {formType === "sttn" ? ( + <></> + ) : ( + <div> + <Button + type="button" + size={commonButonSize} + className="!text-xl" + onClick={plusHist} + > + 추가등록 + </Button> + <Button + type="button" + size={commonButonSize} + className="!text-xl !bg-red-500 !text-white ml-1" + onClick={removeSelected} + > + 삭제 + </Button> + </div> + )} + </div> <div className="h-[200px] overflow-y-auto"> - <div className="flex justify-between items-center mx-3 mb-3"> - <span className={formTableName}>재이용시설 운영정보</span> - {formType === "sttn" ? ( - <></> - ) : ( - <div> - <Button - type="button" - size={commonButonSize} - className="!text-xl" - onClick={plusHist} - > - 추가등록 - </Button> - <Button - type="button" - size={commonButonSize} - className="!text-xl !bg-red-500 !text-white ml-1" - onClick={removeSelected} - > - 삭제 - </Button> - </div> - )} - </div> <RuseMngTableForm - tableData={form.getValues(`items.${indexMng}.fcOpers`) || []} + key={`ruse-table-${indexMng}-${fcOpersField.length}`} // 🔥 length까지 넣어야 동기화됨 + tableData={form.getValues(`items.${indexMng}.fcOpers`) ||[]} headList={ formType === "sttn" ? pbnst.pbnstMngUpHeadList.map((item) => { @@ -350,9 +346,7 @@ export function PbnstMngForm({ } upHeadList={pbnst.pbnstMngNm} code={mngMtdCode || []} - onTableSet={(val) => { - //setFcOpresData(val); - }} + indexMng={indexMng} form={form} formNm={"fcOpers"} @@ -373,6 +367,7 @@ export function PbnstMngForm({ <Input key={`items.${indexMng}.fcltCpct`} placeholder="" + maxLength={numSize} //입력제한 type="text" onChange={(e) => { if (formType !== "sttn") @@ -396,6 +391,7 @@ export function PbnstMngForm({ <Input key={`items.${indexMng}.ruseCpct`} placeholder="" + maxLength={numSize} //입력제한 type="text" onChange={(e) => { if (formType !== "sttn") @@ -418,6 +414,7 @@ export function PbnstMngForm({ <Input key={`items.${indexMng}.splyExtraCpct`} placeholder="" + maxLength={numSize} //입력제한 type="text" onChange={(e) => { if (formType !== "sttn") diff --git a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx index 234efa7c7..8ec7a5a05 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegFormDetail/mngRegFormDetail.tsx @@ -1,5 +1,6 @@ "use client"; import { useWrStore } from "@/app/store"; +import { numSize, txtSize } from "@/app/store/common/code/basicCode"; import type { formDetailType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/headList"; import { formH1Class } from "@/components/lib/class/comClass"; import { formatCommaNumber, handleCommaNumberChange, safeDate } from "@/components/lib/func/commom"; @@ -23,7 +24,7 @@ export default function MngRegFormDetail({ }: { formList: formDetailType[]; h1Title?: string; - subTitle?:string + subTitle?: string form: any; moClass?: string; indexBiz?: number; @@ -41,9 +42,9 @@ export default function MngRegFormDetail({ {formList?.map((formHead, index) => { const fieldId = typeof indexMng === "number" && - indexMng >= 0 && - typeof indexBiz === "number" && - indexBiz >= 0 + indexMng >= 0 && + typeof indexBiz === "number" && + indexBiz >= 0 ? `items.${indexMng}.fcBizs.${indexBiz}.${formHead.id}` : typeof indexMng === "number" && indexMng >= 0 ? `items.${indexMng}.${formHead.id}` @@ -82,7 +83,7 @@ export default function MngRegFormDetail({ value={formatCommaNumber(field.value)} readOnly={formHead.option === "readOnly" ? true : false} disabled={formHead.option === "disabled" ? true : false} - + maxLength={numSize} /> ) : formHead.type === "select" ? ( (() => { @@ -101,7 +102,7 @@ export default function MngRegFormDetail({ : [] } onSelectValue={field.onChange} - value={field.value?.trim() ?? (Array.isArray(potentialOptions) && potentialOptions[0]?.val )} + value={field.value?.trim() ?? (Array.isArray(potentialOptions) && potentialOptions[0]?.val)} readOnly={formHead.option === "readOnly"} /> ); @@ -114,6 +115,7 @@ export default function MngRegFormDetail({ onChange={field.onChange} readOnly={formHead.option === "readOnly" ? true : false} disabled={formHead.option === "disabled" ? true : false} + maxLength={txtSize} /> )} </FormUi> diff --git a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx index 7333f6091..bacf4532b 100644 --- a/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rainReg/rainRegForm.tsx @@ -8,18 +8,22 @@ import { } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; import { + confirmToast, formatCommaNumber, handleMinusNumberChange, } from "@/components/lib/func/commom"; import { DatePicker, FormUi } from "@common/business_components"; import { Form, FormField, SelectBox } from "@common/business_components/ui"; -import { Button, Checkbox, Input, Label } from "@common/components/ui"; +import { Button, Input, ScrollArea } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useState } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import BdstReg from "../bdstReg/bdstReg"; import toast from "react-hot-toast"; +import BdstAdd from "../bdstReg/bdstAdd"; +import { useTranslation } from "react-i18next"; +import { numSize, txtSize } from "@/app/store/common/code/basicCode"; export default function RainRegForm({ rainForm, @@ -32,16 +36,15 @@ export default function RainRegForm({ setIsModal?: (modal: boolean) => void; readonly?: boolean; }) { - const { code, rainBdstReg, rainBdstUpdate, rain } = useWrStore( + const { code, rainBdstReg, rainBdstUpdate } = useWrStore( (state) => state ); const { rainFcltCd } = code; - const defaultValues: z.infer<typeof rainZod> = rainZod.parse({}); const form = useForm<z.infer<typeof rainZod>>({ resolver: zodResolver(rainZod), - defaultValues: defaultValues, + // defaultValues: defaultValues, }); - const instlCst = form.watch(`reuseBuilding.0.instlCst`); + const { t } = useTranslation('base'); const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctYn] = form.watch([ "reuseBuilding.0.grntchBdstCertYn", @@ -49,6 +52,17 @@ export default function RainRegForm({ "reuseBuilding.0.rainyObj.filtrTrtmfctYn", ]); + const [divStyle, setDivStyle] = useState("h-[53vh]"); + useEffect(() => { + if (isModal === true) { + setDivStyle("h-[53vh] max-h-[37vh]") + } else if (readonly === true) { + setDivStyle("h-[62vh]") + } else { + setDivStyle("h-[53vh]") + } + }, [isModal, readonly]); + const cleanRainData = (raw: any): z.infer<typeof rainZod> => { const buildings = raw?.reuseBuilding && raw.reuseBuilding.length > 0 @@ -108,11 +122,6 @@ export default function RainRegForm({ const [regCtpvCd, regSggcd] = form.watch(["ctpvCd", "sggCd"]); - // form 값이 변경될 때마다 로그 출력 - useEffect(() => { - const subscription = form.watch((value) => {}); - return () => subscription.unsubscribe(); - }, [form]); useEffect(() => { console.log("form errors:", form.formState.errors); @@ -127,10 +136,16 @@ export default function RainRegForm({ return; } - rainBdstReg(values, data); - if (setIsModal) setIsModal(false); + const handleConfirm = async () => { + rainBdstReg(values, data); + if (setIsModal) setIsModal(false); + }; + confirmToast(t('isInsertMsg'), handleConfirm); } else { - rainBdstUpdate(values, "41"); + const handleConfirm = async () => { + rainBdstUpdate(values, "41"); + }; + confirmToast(t('isUpdateMsg'), handleConfirm); } }; @@ -143,6 +158,9 @@ export default function RainRegForm({ <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> <div> + <h1 className="text-2xl font-bold text-gray-900 mt-3 ml-1"> + {readonly && `(${rainForm?.bdstNm})`} + </h1> <div className="grid grid-cols-12 flex items-center card-header"> <h1 className="text-2xl font-medium text-label col-span-10"> {isModal ? "건축물 정보" : "빗물이용시설 정보"} @@ -158,148 +176,55 @@ export default function RainRegForm({ )} </div> </div> - {isModal && rainForm != undefined ? <BdstReg form={form} /> : <></>} - {isModal ? ( - <h1 className="pl-3 text-xl col-span-10 mt-4"> - 빗물이용시설 정보{" "} - </h1> - ) : ( - <></> - )} - <h1 className={formH1Class}>기본정보</h1> - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCmptnDt" - render={({ field }) => ( - <FormUi label="설치완료일"> - <DatePicker - mode="single" - field={{ - value: - field.value && !isNaN(new Date(field.value).getTime()) - ? new Date(field.value) - : new Date(), - onChange: (date: Date | undefined) => - field.onChange(date), - }} - selectClass={"w-full"} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> + <ScrollArea className={divStyle}> + {isModal && rainForm != undefined ? <BdstReg form={form} /> : <></>} + {isModal ? ( + <h1 className="pl-3 text-xl col-span-10 mt-4"> + 빗물이용시설 정보{" "} + </h1> + ) : ( + <></> + )} + <h1 className={formH1Class}>기본정보</h1> + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCmptnDt" + render={({ field }) => ( + <FormUi label="설치완료일"> + <DatePicker + mode="single" + field={{ + value: + field.value && !isNaN(new Date(field.value).getTime()) + ? new Date(field.value) + : new Date(), + onChange: (date: Date | undefined) => + field.onChange(date), + }} + selectClass={"w-full"} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> - <div className="col-span-3"> - <FormField - control={form.control} - name={`reuseBuilding.0.instlCst`} - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="설치비(원)"> - <Input - placeholder="1,000,000" - type="text" - className={selectClass} - readOnly={readonly} - value={ - isUnknown ? "확인불가" : formatCommaNumber(value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} - /> - </FormUi> - ); - }} - /> - </div> - </div> - <div className=""> - <h1 className={formH1Class}>빗물이용시설 정보</h1> - </div> - <div> - <h2 className={formH2Class}>집수면 및 저류조</h2> - </div> - <div className="grid grid-cols-12 gap-4 mt-4 "> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.dtfcltCpct" - render={({ field }) => { - const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="저류조 용량(m³)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - value={ - isUnknown - ? "확인불가" - : formatCommaNumber(field.value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} - readOnly={readonly} - /> - </FormUi> - ); - }} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.pntfColKnd" - render={({ field }) => ( - <FormUi label="집수면 종류"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={rainFcltCd} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? rainFcltCd[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.pntfColArea" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - return ( - <div className="flex items-center gap-2"> - <FormUi label="집수면 용량(m³)"> + <div className="col-span-3"> + <FormField + control={form.control} + name={`reuseBuilding.0.instlCst`} + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="설치비(원)"> <Input - className={selectClass} placeholder="1,000,000" type="text" + className={selectClass} + readOnly={readonly} value={ isUnknown ? "확인불가" : formatCommaNumber(value) } @@ -313,276 +238,379 @@ export default function RainRegForm({ if (readonly) return; handleMinusNumberChange(e, field.onChange); }} - readOnly={readonly} + maxLength={numSize} /> </FormUi> - </div> - ); - }} - /> + ); + }} + /> + </div> </div> - </div> - - <div> - <h2 className={formH2Class}>여과 등 처리시설</h2> - </div> - <div className="grid grid-cols-12 gap-2 mt-4"> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctYn" - render={({ field }) => ( - <FormUi label="유무"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstFilterYn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className=""> + <h1 className={formH1Class}>빗물이용시설 정보</h1> </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctCpct" - render={({ field }) => { - const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="용량(m³/일)"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - value={ - isUnknown - ? "확인불가" - : formatCommaNumber(field.value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 + <div> + <h2 className={formH2Class}>집수면 및 저류조</h2> + </div> + <div className="grid grid-cols-12 gap-4 mt-4 "> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.dtfcltCpct" + render={({ field }) => { + const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="저류조 용량(m³)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown + ? "확인불가" + : formatCommaNumber(field.value) } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + ); + }} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.pntfColKnd" + render={({ field }) => ( + <FormUi label="집수면 종류"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={rainFcltCd} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? rainFcltCd[0]?.val} readOnly={readonly} - disabled={filtrTrtmfctYn !== "Y"} /> </FormUi> - ); - }} - /> + )} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.pntfColArea" + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <div className="flex items-center gap-2"> + <FormUi label="집수면 용량(m³)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + </div> + ); + }} + /> + </div> </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rainyObj.filtrTrtmfctPrs" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === "-"; // 또는 Number(value) === -1 - return ( - <div className="flex items-center gap-2"> - <FormUi label="처리공정"> + <div> + <h2 className={formH2Class}>여과 등 처리시설</h2> + </div> + <div className="grid grid-cols-12 gap-2 mt-4"> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.filtrTrtmfctYn" + render={({ field }) => ( + <FormUi label="유무"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstFilterYn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? code.yn[0]?.val} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.filtrTrtmfctCpct" + render={({ field }) => { + const isUnknown = field.value === null || field.value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="용량(m³/일)"> <Input - className={" h-full !text-xl col-span-4"} - placeholder="처리공정 입력" + className={selectClass} + placeholder="1,000,000" type="text" - value={field.value ?? ""} - onChange={field.onChange} + value={ + isUnknown + ? "확인불가" + : formatCommaNumber(field.value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} readOnly={readonly} disabled={filtrTrtmfctYn !== "Y"} + maxLength={numSize} /> </FormUi> - </div> - ); - }} - /> - </div> - </div> - <div className=" my-2"> - <h1 className={formH1Class}>인센티브 정보</h1> - </div> - <div> - <h2 className={formH2Class}>설치비 지원</h2> - </div> - <div className="grid grid-cols-10 gap-2 mt-4"> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtYn" - render={({ field }) => ( - <FormUi label="지원 여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstIncenYn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.yn[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-5"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="지원금액(원)"> - <Input - className={selectClass} - placeholder="" - type="text" - readOnly={readonly || isUnknown} - value={ - isUnknown ? "확인불가" : formatCommaNumber(value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} - disabled={instlCstSprtYn !== "Y"} - /> - </FormUi> - ); - }} - /> - </div> - </div> - <div> - <h2 className={formH2Class}>녹색건축물 인증</h2> - </div> - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYn" - render={({ field }) => ( - <FormUi label="인증여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstIncenYn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.yn[0]?.val} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => { - const isUnknown = - field.value === null || field.value === "0000"; // 또는 Number(value) === -1 - return ( - <FormUi label="인증년도"> - <Input - className={selectClass} - placeholder="2024" - type="" - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - value={isUnknown ? "확인불가" : (field.value ?? "")} - onChange={(e) => { - if (readonly) return; - if (e.target.value === "확인불가") { - field.onChange("0000"); - } else { - field.onChange(e.target.value); - } - }} - disabled={grntchBdstCertYn !== "Y"} - max={4} - /> - </FormUi> - ); - }} - /> - </div> - <div className="col-span-3 "> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => { - const isUnknown = - field.value === null || field.value === "0000"; // 또는 Number(value) === -1 - return ( - <FormUi label="인증번호"> - <Input - className={selectClass} - placeholder="ab1234678" - type="" - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - value={isUnknown ? "확인불가" : (field.value ?? "")} - onChange={(e) => { - if (readonly) return; + ); + }} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rainyObj.filtrTrtmfctPrs" + render={({ field }) => { + // const value = field.value; + // const isUnknown = value === null || value === "-"; // 또는 Number(value) === -1 - if (e.target.value === "확인불가") { - field.onChange(""); - } else { - field.onChange(e.target.value); - } - }} - disabled={grntchBdstCertYn !== "Y"} + return ( + <div className="flex items-center gap-2"> + <FormUi label="처리공정"> + <Input + className={" h-full !text-xl col-span-4"} + placeholder="처리공정 입력" + type="text" + value={field.value ?? ""} + onChange={field.onChange} + readOnly={readonly} + disabled={filtrTrtmfctYn !== "Y"} + maxLength={txtSize} + /> + </FormUi> + </div> + ); + }} + /> + </div> + </div> + <div className=" my-2"> + <h1 className={formH1Class}>인센티브 정보</h1> + </div> + <div> + <h2 className={formH2Class}>설치비 지원</h2> + </div> + <div className="grid grid-cols-10 gap-2 mt-4"> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCstSprtYn" + render={({ field }) => ( + <FormUi label="지원 여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? code.yn[0]?.val} + readOnly={readonly} /> </FormUi> - ); - }} - /> + )} + /> + </div> + <div className="col-span-5"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCstSprtAmt" + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="지원금액(원)"> + <Input + className={selectClass} + placeholder="" + type="text" + readOnly={readonly || isUnknown} + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + disabled={instlCstSprtYn !== "Y"} + maxLength={numSize} + /> + </FormUi> + ); + }} + /> + </div> </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertGrd" - render={({ field }) => ( - <FormUi label="인증등급"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstGrntchClass} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.bdstGrntchClass[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div> + <h2 className={formH2Class}>녹색건축물 인증</h2> </div> - </div> + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertYn" + render={({ field }) => ( + <FormUi label="인증여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? code.yn[0]?.val} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertYr" + render={({ field }) => { + const isUnknown = + field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( + <FormUi label="인증년도"> + <Input + className={selectClass} + placeholder="2024" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={isUnknown ? "확인불가" : (field.value ?? "")} + onChange={(e) => { + if (readonly) return; + if (e.target.value === "확인불가") { + field.onChange("0000"); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn !== "Y"} + max={4} + /> + </FormUi> + ); + }} + /> + </div> + <div className="col-span-3 "> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertNo" + render={({ field }) => { + const isUnknown = + field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( + <FormUi label="인증번호"> + <Input + className={selectClass} + placeholder="ab1234678" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={isUnknown ? "확인불가" : (field.value ?? "")} + onChange={(e) => { + if (readonly) return; + + if (e.target.value === "확인불가") { + field.onChange(""); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn !== "Y"} + maxLength={txtSize} + /> + </FormUi> + ); + }} + /> + </div> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertGrd" + render={({ field }) => ( + <FormUi label="인증등급"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstGrntchClass} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value ?? code.bdstGrntchClass[0]?.val} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + </div> + <BdstAdd form={form} readonly={readonly}></BdstAdd> + </ScrollArea> </form> </Form> </div> diff --git a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx index 0fbffbf59..d37e4f9be 100644 --- a/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/rswtrReg/rswtrRegForm.tsx @@ -8,9 +8,9 @@ import { } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; import { formH1Class, formH2Class } from "@/components/lib/class/comClass"; import { + confirmToast, formatCommaNumber, - handleCommaNumberChange, - handleMinusNumberChange, + handleMinusNumberChange } from "@/components/lib/func/commom"; import { DatePicker, @@ -19,12 +19,15 @@ import { FormUi, SelectBox, } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; +import { Button, Input, ScrollArea } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect } from "react"; -import { useForm, type UseFormReturn } from "react-hook-form"; +import { useEffect, useState } from "react"; +import { useForm } from "react-hook-form"; import { z } from "zod"; +import BdstAdd from "../bdstReg/bdstAdd"; import BdstReg from "../bdstReg/bdstReg"; +import { useTranslation } from "react-i18next"; +import { numSize, txtSize } from "@/app/store/common/code/basicCode"; export default function RswtrRegForm({ rswtForm, @@ -37,15 +40,24 @@ export default function RswtrRegForm({ setIsModal?: (isModal: boolean) => void; readonly?: boolean; }) { - const { rswt, code, rswtBdstUpdate, rswtBdstReg } = useWrStore( + const { code, rswtBdstUpdate, rswtBdstReg } = useWrStore( (state) => state ); - - const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({}); + const [divStyle, setDivStyle] = useState("h-[53vh]"); + useEffect(() => { + if (isModal === true) { + setDivStyle("h-[53vh] max-h-[37vh]") + } else if (readonly === true) { + setDivStyle("h-[62vh]") + } else { + setDivStyle("h-[53vh]") + } + }, [isModal, readonly]); + // const defaultValues: z.infer<typeof rswtZod> = rswtZod.parse({}); const form = useForm<z.infer<typeof rswtZod>>({ resolver: zodResolver(rswtZod), - defaultValues: defaultValues, + // defaultValues: defaultValues, }); const [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs] = form.watch([ @@ -54,17 +66,25 @@ export default function RswtrRegForm({ "reuseBuilding.0.rswtrObj.filtrTrtmfctProcs", ]); + const { t } = useTranslation('base'); const onSubmit = (values: z.infer<typeof rswtZod>) => { if (isModal) { - rswtBdstReg(values, "41"); - if (setIsModal) setIsModal(false); + const handleConfirm = async () => { + rswtBdstReg(values, "41"); + if (setIsModal) setIsModal(false); + }; + confirmToast(t('isInsertMsg'), handleConfirm); + } else { - rswtBdstUpdate(values, "41"); + const handleConfirm = async () => { + rswtBdstUpdate(values, "41"); + }; + confirmToast(t('isUpdateMsg'), handleConfirm); } }; const filtrTrtmfctCpct = form.watch('reuseBuilding.0.rswtrObj.filtrTrtmfctCpct') - const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { + const cleanRswtData = (raw: any): z.infer<typeof rswtZod> => { console.log('raw ', raw) return { @@ -80,9 +100,9 @@ export default function RswtrRegForm({ instlCmptnDt: item?.instlCmptnDt ? new Date(item.instlCmptnDt) : new Date(), // item?.instlCmptnDt가 유효하지 않으면 현재 날짜로 초기화 - operMngCd: item?.operMngCd ?? "", // null → "" + operMngCd: item?.operMngCd || "", // null → "" instlCstSprtYn: item?.instlCstSprtYn || code.yn[0]?.val, // null → "Y" - grntchBdstCertYn: item?.grntchBdstCertYn|| code.yn[0]?.val, + grntchBdstCertYn: item?.grntchBdstCertYn || code.yn[0]?.val, rswtrObj: { ...item?.rswtrObj, filtrTrtmfctYn: item?.rainyObj?.filtrTrtmfctYn || code.yn[0]?.val, @@ -96,10 +116,10 @@ export default function RswtrRegForm({ // useEffect(() =>{ // console.log(' formform ', form.watch()) // },[form.formState]) - useEffect(() =>{ + useEffect(() => { console.log(' filtrTrtmfctCpct ', filtrTrtmfctCpct) - },[filtrTrtmfctCpct]) - + }, [filtrTrtmfctCpct]) + useEffect(() => { console.log("form errors:", form.formState.errors); }, [form.formState.errors]); @@ -119,7 +139,7 @@ export default function RswtrRegForm({ form.setValue("reuseBuilding.0.grntchBdstCertGrd", "확인불가"); } else if (instlCstSprtYn === "D") { form.setValue("reuseBuilding.0.instlCstSprtAmt", -1); - } + } }, [grntchBdstCertYn, instlCstSprtYn, filtrTrtmfctProcs, form]); @@ -133,6 +153,9 @@ export default function RswtrRegForm({ <form onSubmit={form.handleSubmit(onSubmit)}> {/* <div className="flex justify-between items-center mx-3"> */} <div> + <h1 className="text-2xl font-bold text-gray-900 mt-3 ml-1"> + {readonly && `(${rswtForm?.bdstNm})`} + </h1> <div className="grid grid-cols-12 flex items-center card-header"> <h1 className="text-2xl font-medium text-label col-span-10"> 건축물 운영정보 @@ -148,334 +171,337 @@ export default function RswtrRegForm({ )} </div> </div> - - {isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>} - {isModal ? ( - <h1 className="pl-3 text-xl col-span-10 mt-4 "> - 중수도 시설 정보{" "} - </h1> - ) : ( - <></> - )} - <h1 className={formH1Class}>기본정보</h1> - <div className="grid grid-cols-4 gap-2 mt-4"> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCmptnDt" - render={({ field }) => ( - <FormUi label="설치완료일"> - <DatePicker - mode="single" - field={{ - value: - field.value && !isNaN(new Date(field.value).getTime()) - ? new Date(field.value) - : new Date(), // Provide a default Date value - onChange: (date) => field.onChange(date), - }} - selectClass={"w-full"} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-2"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCst" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="설치비"> - <Input - className={selectClass} - placeholder="1,000,000" - type="text" - value={ - isUnknown ? "확인불가" : formatCommaNumber(value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); + <ScrollArea className={divStyle}> + {isModal && rswtForm != undefined ? <BdstReg form={form} /> : <></>} + {isModal ? ( + <h1 className="pl-3 text-xl col-span-10 mt-4 "> + 중수도 시설 정보{" "} + </h1> + ) : ( + <></> + )} + <h1 className={formH1Class}>기본정보</h1> + <div className="grid grid-cols-4 gap-2 mt-4"> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCmptnDt" + render={({ field }) => ( + <FormUi label="설치완료일"> + <DatePicker + mode="single" + field={{ + value: + field.value && !isNaN(new Date(field.value).getTime()) + ? new Date(field.value) + : new Date(), // Provide a default Date value + onChange: (date) => field.onChange(date), }} + selectClass={"w-full"} readOnly={readonly} /> </FormUi> - ); - }} - /> - </div> - </div> - <div className=" my-4"> - <h1 className={formH1Class}>중수도 시설 정보</h1> - </div> - - <div className="grid grid-cols-12 gap-1 mt-4"> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.filtrTrtmfctCpct" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - - return ( - <FormUi label="처리시설 용량"> - <Input - className={selectClass} - placeholder="" - type="text" - value={ - isUnknown ? "확인불가" : formatCommaNumber(value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - - console.log('value') - field.onChange(""); // 초기화 + )} + /> + </div> + <div className="col-span-2"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCst" + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="설치비(원)"> + <Input + className={selectClass} + placeholder="1,000,000" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + ); + }} + /> + </div> + </div> + <div className=" my-4"> + <h1 className={formH1Class}>중수도 시설 정보</h1> + </div> + + <div className="grid grid-cols-12 gap-1 mt-4"> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rswtrObj.filtrTrtmfctCpct" + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + + return ( + <FormUi label="처리시설 용량"> + <Input + className={selectClass} + placeholder="" + type="text" + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + + console.log('value') + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + readOnly={readonly} + maxLength={numSize} + /> + </FormUi> + ); + }} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rswtrObj.orgwtKndCd" + render={({ field }) => ( + <FormUi label="원수 종류"> + <SelectBox + className={""} + label={""} + selectClass={selectClass} + selectArray={code.orgwtKndCd} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value || code.orgwtKndCd[0]?.val} readOnly={readonly} /> </FormUi> - ); - }} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.orgwtKndCd" - render={({ field }) => ( - <FormUi label="원수 종류"> - <SelectBox - className={""} - label={""} - selectClass={selectClass} - selectArray={code.orgwtKndCd} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.orgwtKndCd[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-4"> - <FormField - control={form.control} - name="reuseBuilding.0.rswtrObj.filtrTrtmfctProcs" - render={({ field }) => ( - <FormUi label="주요처리공정"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.rswtPrscCdMthdCd} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.rswtPrscCdMthdCd[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> - - <div className=" my-2"> - <h1 className={formH1Class}>인센티브 정보</h1> - </div> - <div> - <h2 className={formH2Class}>설치비 지원</h2> - </div> - <div className="grid grid-cols-2 gap-2 mt-4"> - <div className="col-span-1"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtYn" - render={({ field }) => ( - <FormUi label="설치비 지원여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstIncenYn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.bdstIncenYn[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - <div className="col-span-1"> - <FormField - control={form.control} - name="reuseBuilding.0.instlCstSprtAmt" - render={({ field }) => { - const value = field.value; - const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 - return ( - <FormUi label="지원금액(원)"> - <Input - className={selectClass} - placeholder="" - type="text" - readOnly={readonly || isUnknown} - value={ - isUnknown ? "확인불가" : formatCommaNumber(value) - } - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - onChange={(e) => { - if (readonly) return; - handleMinusNumberChange(e, field.onChange); - }} - disabled={instlCstSprtYn === "N"||instlCstSprtYn === "D"} + )} + /> + </div> + <div className="col-span-4"> + <FormField + control={form.control} + name="reuseBuilding.0.rswtrObj.filtrTrtmfctProcs" + render={({ field }) => ( + <FormUi label="주요처리공정"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.rswtPrscCdMthdCd} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value || code.rswtPrscCdMthdCd[0]?.val} + readOnly={readonly} /> </FormUi> - ); - }} - /> + )} + /> + </div> </div> - </div> - <div> - <h2 className={formH2Class}>녹색건축물 인증</h2> - </div> - <div className="grid grid-cols-6 gap-2 mt-4"> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYn" - render={({ field }) => ( - <FormUi label="인증여부"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstIncenYn} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value || code.yn[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> + <div className=" my-2"> + <h1 className={formH1Class}>인센티브 정보</h1> </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertYr" - render={({ field }) => - { - const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1 - return ( - <FormUi label="인증년도"> - <Input - className={selectClass} - placeholder="2024" - type="" - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - value={ - isUnknown?'확인불가':field.value ?? ""} - onChange={(e) => { - if (readonly) return - if (e.target.value === '확인불가') { - field.onChange('0000'); - }else{ - field.onChange(e.target.value); - } - }} - disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} - max={4} - /> - </FormUi> - )}} - /> + <div> + <h2 className={formH2Class}>설치비(원) 지원</h2> </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertNo" - render={({ field }) => - { + <div className="grid grid-cols-2 gap-2 mt-4"> + <div className="col-span-1"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCstSprtYn" + render={({ field }) => ( + <FormUi label="설치비(원) 지원여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value || code.bdstIncenYn[0]?.val} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-1"> + <FormField + control={form.control} + name="reuseBuilding.0.instlCstSprtAmt" + render={({ field }) => { + const value = field.value; + const isUnknown = value === null || value === -1; // 또는 Number(value) === -1 + return ( + <FormUi label="지원금액(원)"> + <Input + className={selectClass} + placeholder="" + type="text" + readOnly={readonly || isUnknown} + value={ + isUnknown ? "확인불가" : formatCommaNumber(value) + } + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + onChange={(e) => { + if (readonly) return; + handleMinusNumberChange(e, field.onChange); + }} + disabled={instlCstSprtYn === "N" || instlCstSprtYn === "D"} + maxLength={numSize} + /> + </FormUi> + ); + }} + /> + </div> + </div> + + <div> + <h2 className={formH2Class}>녹색건축물 인증</h2> + </div> + <div className="grid grid-cols-6 gap-2 mt-4"> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertYn" + render={({ field }) => ( + <FormUi label="인증여부"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstIncenYn} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value || code.yn[0]?.val} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertYr" + render={({ field }) => { const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1 - return ( - <FormUi label="인증번호"> - <Input - className={selectClass} - placeholder="ab1234678" - type="" - onFocus={() => { - // 입력 시 자동으로 확인불가 해제 - if (isUnknown && !readonly) { - field.onChange(""); // 초기화 - } - }} - value={ - isUnknown?'확인불가':field.value ?? ""} - onChange={(e) => { - if (readonly) return - - if (e.target.value === '확인불가') { - field.onChange(''); - }else{ - field.onChange(e.target.value); - } - }} - disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} - + return ( + <FormUi label="인증년도"> + <Input + className={selectClass} + placeholder="2024" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={ + isUnknown ? '확인불가' : field.value ?? ""} + onChange={(e) => { + if (readonly) return + if (e.target.value === '확인불가') { + field.onChange('0000'); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} + max={4} + /> + </FormUi> + ) + }} + /> + </div> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertNo" + render={({ field }) => { + const isUnknown = field.value === null || field.value === "0000"; // 또는 Number(value) === -1 + return ( + <FormUi label="인증번호"> + <Input + className={selectClass} + placeholder="ab1234678" + type="" + onFocus={() => { + // 입력 시 자동으로 확인불가 해제 + if (isUnknown && !readonly) { + field.onChange(""); // 초기화 + } + }} + value={ + isUnknown ? '확인불가' : field.value ?? ""} + onChange={(e) => { + if (readonly) return - - /> - </FormUi> - )}} - /> + if (e.target.value === '확인불가') { + field.onChange(''); + } else { + field.onChange(e.target.value); + } + }} + disabled={grntchBdstCertYn == "N" || grntchBdstCertYn == "D"} + maxLength={txtSize} + /> + </FormUi> + ) + }} + /> + </div> + <div className="col-span-3"> + <FormField + control={form.control} + name="reuseBuilding.0.grntchBdstCertGrd" + render={({ field }) => ( + <FormUi label="인증등급"> + <SelectBox + className={""} + selectClass={selectClass} + label={""} + selectArray={code.bdstGrntchClass} + onSelectValue={readonly ? () => { } : field.onChange} + value={field.value || code.bdstGrntchClass[0]?.val} + readOnly={readonly} + /> + </FormUi> + )} + /> + </div> </div> - <div className="col-span-3"> - <FormField - control={form.control} - name="reuseBuilding.0.grntchBdstCertGrd" - render={({ field }) => ( - <FormUi label="인증등급"> - <SelectBox - className={""} - selectClass={selectClass} - label={""} - selectArray={code.bdstGrntchClass} - onSelectValue={readonly ? () => {} : field.onChange} - value={field.value ?? code.bdstGrntchClass[0]?.val} - readOnly={readonly} - /> - </FormUi> - )} - /> - </div> - </div> + <BdstAdd form={form} readonly={readonly}></BdstAdd> + </ScrollArea> </form> </Form> </div> diff --git a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx index 5aa67fd3a..b35f4c3a1 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdExcel/chkgdExcel.tsx @@ -16,7 +16,6 @@ import { SelectBox, Title, } from "@common/business_components/ui"; -import { Card } from "@common/business_components/ui/chart/lib/card"; import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useState } from "react"; @@ -24,8 +23,8 @@ import { useForm } from "react-hook-form"; import toast from "react-hot-toast"; import type { z } from "zod"; -export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setIsRegExcel:(open:boolean) =>void }) { - const { rswtChkgdn, rainChkExcelDataUPload, rswtChkExceDataUpload } = +export default function ChkgdExcel({ type,setIsRegExcel ,setYearChange }: { type: string, setIsRegExcel:(open:boolean) =>void ,setYearChange:(year:string)=> void }) { + const { rainChkExcelDataUPload, rswtChkExceDataUpload } = useWrStore((state) => { return state; }); @@ -72,28 +71,40 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI if (file) if (type === "RNB") { filePicked(file, 0).then((res) => { - if (res !== undefined) - setExcelData(excelToRainChkData(res, form.getValues("chckYr"))); - }); + // if (res !== undefined){ + + const excelData = excelToRainChkData(res, form.getValues("chckYr")) + if(res !== undefined) + setExcelData(excelData) + // if( excelData&&excelData.errors.length>0){ + + // excelData.errors.forEach((err) =>{ + // toast.error(err) + // }) + // }else{ + + // } + + // } + + + + }) } else if (type === "RST") { filePickedArray(file, 0).then((res) => { if (res && res?.length > 1) { - const excelArray = []; const guideData = excelToRswtGuideData( res[0], form.getValues("chckYr") ); - const polutionData = excelToRswtPolution( - res[1], - form.getValues("chckYr") - ); + const polutionData = excelToRswtPolution(res[1]); const keyGenerator = (item: rswtChkZodType) => - `${item.bdstRuseFcltFk}|${item.chckYmd}|${item.utztnUsgCd}`; + `${item.bdstRuseFcltSn}|${item.chckYmd}|${item.utztnUsgCd}`; const totalData: rswtChkZodType[] = guideData.map((guide) => { const fusion = polutionData.find( (polution) => - guide.bdstRuseFcltFk === polution.bdstRuseFcltFk && + guide.bdstRuseFcltSn === polution.bdstRuseFcltSn && guide.chckYmd === polution.chckYmd && guide.utztnUsgCd === polution.utztnUsgCd ); @@ -129,18 +140,18 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI } }, [file]); - function findMatchingItems<T>( - arrayA: T[], - arrayB: T[], - keySelector: (item: T) => string, - condition?: (item: T) => boolean - ): T[] { - const bKeySet = new Set(arrayB.map(keySelector)); - return arrayA.filter( - (item) => - (!condition || condition(item)) && bKeySet.has(keySelector(item)) - ); - } + // function findMatchingItems<T>( + // arrayA: T[], + // arrayB: T[], + // keySelector: (item: T) => string, + // condition?: (item: T) => boolean + // ): T[] { + // const bKeySet = new Set(arrayB.map(keySelector)); + // return arrayA.filter( + // (item) => + // (!condition || condition(item)) && bKeySet.has(keySelector(item)) + // ); + // } const onSubmit = (values: z.infer<typeof chkgdRegExcel>) => { if (values.chckYr === "") { @@ -154,8 +165,9 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI return; } else { - rainChkExcelDataUPload(excelData as rainChkZodType[]); + rainChkExcelDataUPload(excelData as rainChkZodType[] , form.getValues("chckYr")) ; setIsRegExcel(false) + setYearChange(form.getValues("chckYr")) } } else if (type === "RST") { if (excelRswtData === undefined || excelRswtData?.length === 0) { @@ -165,10 +177,11 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI } else { rswtChkExceDataUpload(excelRswtData as rswtChkZodType[]); setIsRegExcel(false) + setYearChange(form.getValues("chckYr")) + } } } - }; return ( <> @@ -211,7 +224,6 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI </FormUi> )} /> - <FormField control={form.control} name="file" @@ -220,7 +232,11 @@ export default function ChkgdExcel({ type,setIsRegExcel }: { type: string, setI <div className="space-y-4 p-4"> <Input type="file" - onChange={handleFileChange} + onChange={(file) =>{ + handleFileChange( file) + ////TODO : 폼 을 써야하는 지 확인 필요 + console.log(field.value) + } } accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" /> </div> diff --git a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx index edbd9e570..2b74cf8af 100644 --- a/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/chkgdModal/chkgdModal.tsx @@ -213,6 +213,7 @@ export default function ChkgdModal({ type, obj, setIsModal }: { type: string; ob }); obj.guideDetails = realGuideDetail; if (type === "RNB") { + rainChkGuidUpdate(obj); setIsModal(false) } else { diff --git a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx index b4b87663e..427323c1e 100644 --- a/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx +++ b/apps/wr/components/ui/modal/chkgd/pbnPrfExcelModal/pbnPrfExcelModal.tsx @@ -1,17 +1,16 @@ -import { useWrStore } from "@/app/store"; import { excelToPbnPrfData } from "@/app/store/prfmncReg/pbnstPrfmncReg/excel"; import { pbnPrfRegExcelZod } from "@/app/store/prfmncReg/pbnstPrfmncReg/headList"; -import type { FcPrfType, PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; +import type { + FcPrfType, + PrfType, +} from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; import { yearOptions } from "@/components/lib/func/commom"; -import { ToastFormUi } from "@/components/ui/toast/toastFromUi"; import { - FileUpload, FormField, FormUi, SelectBox, Form, Title, - type SelectDataType, filePicked, } from "@common/business_components/ui"; import { Button, Input } from "@common/components/ui"; @@ -21,9 +20,15 @@ import { useForm } from "react-hook-form"; import toast from "react-hot-toast"; import type { z } from "zod"; -export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelData}: { data: FcPrfType ,setIsExcelOPen:(open:boolean )=>void,setModalExcelData:(excelData :PrfType)=>void }) { - const { prfmnRegData } = useWrStore((state) => state); - +export default function PbnPrfExcelModal({ + data, + setIsExcelOPen, + setModalExcelData, +}: { + data: FcPrfType; + setIsExcelOPen: (open: boolean) => void; + setModalExcelData: (excelData: PrfType) => void; +}) { const [file, setFile] = useState<File | null>(null); const [excelData, setExcelData] = useState<PrfType[]>(); const form = useForm<z.infer<typeof pbnPrfRegExcelZod>>({ @@ -40,29 +45,27 @@ export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelDa } }; const onSubmit = (values: z.infer<typeof pbnPrfRegExcelZod>) => { - if (excelData) { - // prfmnRegData(1,'41', excelData as unknown as PrfType); + ////TODO: 궅이 서브밋을 써야하는 이유가 있는지 ? + console.log("values ", values); + // prfmnRegData(1,'41', excelData as unknown as PrfType); 활성화시 스토어 활성화 칠요 - setModalExcelData(excelData as unknown as PrfType) - setIsExcelOPen(false) + setModalExcelData(excelData as unknown as PrfType); + setIsExcelOPen(false); } - - }; useEffect(() => { if (data && data.bscFctNm) - form.setValue("pbnstRuseFcltFk", data.pbnstRuseFcltPk); + form.setValue("pbnstRuseFcltId", data.pbnstRuseFcltId); form.setValue("bscFctNm", data.bscFctNm || ""); form.setValue("pbnstRuseFcltNm", data.ruseUtztnFcltNm); }, [data]); - useEffect(() => { if (file) { - const isFile = file + const isFile = file; if (form.getValues("ym").length < 1) { - toast.error("파일업로드 이전에 등록년도를 작성해주세요 " ); + toast.error("파일업로드 이전에 등록년도를 작성해주세요 "); setFile(null); return; } @@ -70,7 +73,13 @@ export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelDa if (isFile) { filePicked(isFile, 0).then((res) => { if (res !== undefined) - setExcelData(excelToPbnPrfData(res as unknown as JSON[], form.getValues("ym"), form.getValues('pbnstRuseFcltFk')) as PrfType[]) + setExcelData( + excelToPbnPrfData( + res as unknown as JSON[], + form.getValues("ym"), + form.getValues("pbnstRuseFcltId") + ) as PrfType[] + ); }); } } @@ -117,7 +126,7 @@ export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelDa <FormUi label="시설명"> <Input className="text-3xl" - value={field.value || ''} + value={field.value || ""} onChange={field.onChange} readOnly /> @@ -133,7 +142,7 @@ export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelDa <FormUi label="재이용시설명"> <Input className="flex-1 text-3xl" - value={field.value || ''} + value={field.value || ""} onChange={field.onChange} readOnly /> @@ -160,13 +169,16 @@ export default function PbnPrfExcelModal({ data ,setIsExcelOPen ,setModalExcelDa ></FileUpload> */} -<div className="space-y-4 p-4"> - <Input - type="file" - onChange={handleFileChange} - accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" + <div className="space-y-4 p-4"> + <Input + type="file" + onChange={(file) => { + console.log(" field. valus", field.value); + if (file) handleFileChange(file); + }} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" /> - </div> + </div> </FormUi> )} /> diff --git a/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx b/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx index efd47c69b..f34e777c7 100644 --- a/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx +++ b/apps/wr/components/ui/modal/coMat/constCostFeeTable.tsx @@ -9,15 +9,11 @@ import { yearOptions } from "@/components/lib/func/commom"; import { SelectBox, UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Label, ScrollArea } from "@common/components/ui"; -import { useEffect, useRef, useState } from "react"; +import { Label, } from "@common/components/ui"; +import { useEffect, useState } from "react"; -export function ConstCostFeeTable({ - setReturnData, -}: { - setReturnData: (data: any) => void; -}) { - const { coRvw, constCostRes, getConstCostFee } = useWrStore((state) => state); +export function ConstCostFeeTable() { + const { coRvw, constCostRes } = useWrStore((state) => state); const [year, setYear] = useState<string>(String(new Date().getFullYear())); const [constCostData, setConstCostData] = useState<ContCostMap[]>([]); diff --git a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx index 880c789c3..500a0cf40 100644 --- a/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx +++ b/apps/wr/components/ui/modal/coMat/drgtDetailModal.tsx @@ -11,9 +11,11 @@ import { useEffect, useState } from "react" export default function DrgtDetailModal({ data, }: { - data: customDrgt; + data: customDrgt[]; }) { - const [excelData, setExcelData] = useState<any[]>(); + + // const [isSggNm, setIsSggNm] = useState('') + const [excelData, setExcelData] = useState<any[]>(); const excelClick = () => { downloadExcel({ data: excelData ?? [], @@ -30,10 +32,14 @@ export default function DrgtDetailModal({ return { "년": item.year, "월": item.month, - "가뭄상태": item.drgtState, + "가뭄상태": item.drgtState, // Access drgtState directly from the item } }) : []; setExcelData(exData) + // if(data&&data[0].sggNm){ + ////TODO: data.sggNm [0[인지 data.sggNm 인지 사용하는지 확인필요 + // setIsSggNm(data[0].sggNm) + // } }, [data]) return ( @@ -41,7 +47,7 @@ export default function DrgtDetailModal({ <div className="grid grid-cols-4 gap-4 h-full"> <div className="col-span-4"> <div className="flex items-center justify-between"> - <Title title={`우리동네가뭄 상세내용 - ${data[0].sggNm}`} /> + <Title title={`우리동네가뭄 상세내용 - ${data[0]&&data[0].sggNm ?data[0].sggNm:'' }`} /> <div className="flex flex-row space-x-2"> <Button size={"sm"} @@ -59,11 +65,15 @@ export default function DrgtDetailModal({ <ScrollArea className="h-[63vh]"> <UiTable headName={undefined} - tableData={data} + tableData={data } headlist={drgtDetailHeadListExport} pageSize={10} total={10000} - cellClick={(index: number | undefined, headId: string) => { }} + cellClick={(index: number | undefined, headId: string) => { + console.log(' indx ' , index) + console.log(' headId ' , headId) + + }} onPageChange={() => { }} ></UiTable> </ScrollArea> diff --git a/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx b/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx index ee82420a8..cc7de726a 100644 --- a/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx +++ b/apps/wr/components/ui/modal/coMat/rateFeeModal.tsx @@ -2,20 +2,13 @@ import { useWrStore } from "@/app/store"; import type { rateFeeType } from "@/app/store/common/searchCode/type"; -import { yearOptions } from "@/components/lib/func/commom"; -import { SelectBox, UiTable } from "@common/business_components/ui"; +import { UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { Input, Label, ScrollArea } from "@common/components/ui"; -import { Scroll } from "lucide-react"; +import { Label } from "@common/components/ui"; import { useEffect, useState } from "react"; -export function RateFeeTableModal({ - setReturnData, -}: { - setReturnData: (data: any) => void; -}) { - const { code, coRvw, rateFeeRes } = useWrStore((state) => state); - const [year, setYear] = useState<string>(String(new Date().getFullYear())); +export function RateFeeTableModal() { + const { coRvw, rateFeeRes } = useWrStore((state) => state); const [reateFeeTable, setRateFeeTable] = useState<rateFeeType[]>([]); const gubunLabelMap: Record<number, string> = { @@ -39,32 +32,32 @@ export function RateFeeTableModal({ }; const fetchData = async (rateFeeRes: rateFeeType[]) => { - const data = await rateFeeRes?.filter((item: rateFeeType) => { - return item.incExpCd !== "SS"; - }) - .reduce((acc: any, cur: rateFeeType) => { - const key = cur.stdCost; - let target = acc.find((item: any) => item.stdCost === key); - if (!target) { - target = { - stdCost: cur.stdCost, - BD: 0, - SE: 0, - CE: 0, - }; - acc.push(target); - } - target[cur.incExpCd] = cur.rt; - return acc; - }, []); - + const data = await rateFeeRes + ?.filter((item: rateFeeType) => { + return item.incExpCd !== "SS"; + }) + .reduce((acc: any, cur: rateFeeType) => { + const key = cur.stdCost; + let target = acc.find((item: any) => item.stdCost === key); + if (!target) { + target = { + stdCost: cur.stdCost, + BD: 0, + SE: 0, + CE: 0, + }; + acc.push(target); + } + target[cur.incExpCd] = cur.rt; + return acc; + }, []); const dataGubun = data?.map((item: any) => { return { ...item, gubun: gubunLabelMap[item.stdCost] || item.stdCost, }; - }) + }); return dataGubun?.sort((a: any, b: any) => a.stdCost - b.stdCost); }; @@ -88,26 +81,20 @@ export function RateFeeTableModal({ <div className="col-span-5 flex items-center"> <Label className=" text-xl text-gray-600">기준년도</Label> - <Input - className="col-span-1 text-2xl text-right ml-2 w-32" - placeholder="" - type="text" - onChange={(e) => {}} - value={new Date().getFullYear() || ""} - /> + <span>{new Date().getFullYear() || ""}</span> </div> <div className="col-span-6 pr-6"> - <UiTable - className="min-w-full pr-12" - key={"rateTable" + reateFeeTable?.length} - headName={""} - tableData={reateFeeTable || []} - headlist={coRvw.rateFeeHeadList} - onPageChange={() => {}} - pageSize={0} - total={0} - cellClick={undefined} - /> + <UiTable + className="min-w-full pr-12" + key={"rateTable" + reateFeeTable?.length} + headName={""} + tableData={reateFeeTable || []} + headlist={coRvw.rateFeeHeadList} + onPageChange={() => {}} + pageSize={0} + total={0} + cellClick={undefined} + /> </div> </div> </ListDiv> diff --git a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx index 89f15a3cc..66fdf91d0 100644 --- a/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx +++ b/apps/wr/components/ui/modal/coReg/coRegExcel/coRegExcelModal.tsx @@ -1,75 +1,85 @@ import { useWrStore } from "@/app/store"; import { coRegExcel } from "@/app/store/matDmd/coSttn/headList"; -import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { names } from "@/app/store/matDmd/ldrmntCoSttn/excel"; -import { filePicked, FileUpload, FormUi, Title } from "@common/business_components/ui"; -import { Form, FormField } from "@common/business_components/ui/form"; -import { Button, Progress } from "@common/components/ui"; +import { filePicked, Title } from "@common/business_components/ui"; +import { Form } from "@common/business_components/ui/form"; +import LoadingOverlay from "@common/business_components/ui/loadingBar"; +import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; +import { useState } from "react"; import { useForm } from "react-hook-form"; +import toast from "react-hot-toast"; import type { z } from "zod"; -export default function CoRegExcel() { - - +export default function CoRegExcel({ + isModal, +}: { + isModal: (open: boolean) => void; +}) { + const { ldrmnt, loadingOpen } = useWrStore((state) => state); + const { isLoading } = ldrmnt; const form = useForm<z.infer<typeof coRegExcel>>({ resolver: zodResolver(coRegExcel), }); - const { ldrmntRegData, ldrmntDelete } = useWrStore((state) => state); - const [excelData, setExcelData] = useState<customLdrmnt[]>(); - + const { ldrmntRegData } = useWrStore((state) => state); const [file, setFiles] = useState<File | undefined>(); - const onSubmit = (values: z.infer<typeof coRegExcel>) => { - ldrmntDelete(); + // const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => { + // const selectedFile = e.target.files?.[0]; + // if (selectedFile) { + // setFiles(selectedFile); + // } + // }; + + //TODO:Onsubmit을 써야하는지 + const onSubmit = () => { + loadingOpen(true); if (file) { - filePicked(file, 0).then((res) => { - //TODO:loading - try { - let array: { [key: string]: string | number }[] = [] - let isError = false; - if (Array.isArray(res)) { - res.some((item, index) => { - let object: { [key: string]: string | number } = {} - Object.keys(names).some((key) => { - if (item && names[key] !== undefined) { - // if (key === "공장관리번호") { - // item[key] = String(item[key]) - // } else { - object[names[key] as string] = item[key]; - // } - } + filePicked(file, 0) + .then(async (res) => { + try { + const array: { [key: string]: string | number }[] = []; + if (Array.isArray(res)) { + res.some((item) => { + const object: { [key: string]: string | number } = {}; + Object.keys(names).some((key) => { + if (item && names[key] !== undefined) { + // if (key === "공장관리번호") { + // item[key] = String(item[key]) + // } else { + object[names[key] as string] = item[key]; + // } + } + return false; + }); + + array.push(object); + return false; - }) - if (isError === true) - return true; - array.push(object) - - if (index != 0 && index % 5000 == 0) { - ldrmntRegData(array); - array = [] - array.length = 0; - } - return false; - }) + }); + } + await ldrmntRegData(array); + isModal(false); + loadingOpen(false); + toast.success(`잠재수요처 등록이 완료되었습니다.`); + } catch (e) { + console.log(e); + loadingOpen(false); + alert(e); + return true; } - if (isError === false) - ldrmntRegData(array); - } catch (e) { - console.log(e) - alert(e) - return true; - } - - }); - }; - } + }) + .catch((e) => { + console.log("file", e); + }); + } + }; return ( <> <div> + <LoadingOverlay isLoading={isLoading}></LoadingOverlay> <Form {...form}> <form onSubmit={form.handleSubmit(onSubmit)}> <div> @@ -79,29 +89,22 @@ export default function CoRegExcel() { <h3 className="text-2xl font-bold text-gray-900 mt-1 ml-7"> {"잠재수요처 파일"} </h3> - - <Button className="" type="submit" size={"sm"}> + <Button className="" type="submit" size={"sm"} onClick={onSubmit}> 저장 </Button> </div> <div> - <FormField - control={form.control} - name="file" - render={({ field }) => ( - <FormUi label=""> - <FileUpload - files={file ? [file] : []} - setFiles={(files: File[] | null) => { - if (files && files?.length === 1) setFiles(files[0]); - }} - fileTypes="" - maxFiles={1} - ></FileUpload> - </FormUi> - )} - /> + <div className="space-y-4 p-4"> + <Input + type="file" + onChange={(e) => { + const selectedFile = e.target.files?.[0]; + if (selectedFile) setFiles(selectedFile); + }} + accept=".csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, application/vnd.ms-excel" + /> + </div> </div> </form> </Form> diff --git a/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx b/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx index 0b071aa91..09f66ed2a 100644 --- a/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/bdstChgModal/bdstChgModal.tsx @@ -1,8 +1,6 @@ import { useWrStore } from "@/app/store"; import { UiTable } from "@common/business_components/ui"; import ListDiv from "@common/business_components/ui/list_div"; -import { useEffect } from "react"; - import type { @@ -10,7 +8,7 @@ import type { } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; export default function BdstChgModal({ chgBuilding }: { chgBuilding:chgBuilding[] }) { -const {bdst,rain} = useWrStore((state) => { +const {bdst} = useWrStore((state) => { return state; }); const { bdstChgHeadList } = bdst; @@ -26,7 +24,6 @@ const { bdstChgHeadList } = bdst; onPageChange={() => {}} headName={"○건축물 변경 이력"} tableData={chgBuilding} - children={undefined} cellClick={undefined} /> </ListDiv> diff --git a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx index c534c38af..d1de75ba1 100644 --- a/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/bdstRegModal/bdstRegModal.tsx @@ -1,97 +1,131 @@ "use client"; import { useWrStore } from "@/app/store"; +import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import { selectClass, type customRainBdst, } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { ScrollArea, SelectBox, UiTable, type SelectDataType } from "@common/business_components"; -import { Button, Input, Label } from "@common/components"; -import { useEffect, useState } from "react"; -import { getCity, tableData } from "@/components/lib/func/commom"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; +import { tableData } from "@/components/lib/func/commom"; +import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; import RainRegForm from "@/components/ui/form/fcltReg/rainReg/rainRegForm"; import RswtrRegForm from "@/components/ui/form/fcltReg/rswtrReg/rswtrRegForm"; -import HtdflRegForm from "@/components/ui/form/fcltReg/htdflReg/htdflRegForm"; +import { + ScrollArea, + SelectBox, + UiTable, + type SelectDataType, +} from "@common/business_components"; +import { Button, Input, Label } from "@common/components"; +import { useEffect, useState } from "react"; export type objSearchType = { - sgg: string|number; - city: string|number; - }; + sgg: string | number; + city: string | number; +}; //RNB(빗물), RST(중수도), HTB(온배수) - type MoType = 'RNB' | 'RST' | 'HTB'; // 여기에 'htdf' 추가 +type MoType = "RNB" | "RST" | "HTB"; // 여기에 'htdf' 추가 - type BdstTypeMap = { +type BdstTypeMap = { RNB: customRainBdst; RST: customRswtBdst; - HTB: customRswtBdst; // 해야해// 아직 아노딤 + HTB: customRswtBdst; // 해야해// 아직 아노딤 }; - interface BdstRegProps<T extends MoType> { +interface BdstRegProps<T extends MoType> { moType: T; - isModal:boolean; + isModal: boolean; setIsModal?: (open: boolean) => void; } -export function BdstReg<T extends MoType>({ moType,setIsModal,isModal }: BdstRegProps<T>) { - const { rain, code, bdst,findBdst } = useWrStore((state) => { +export function BdstReg<T extends MoType>({ + moType, + setIsModal, + isModal, +}: BdstRegProps<T>) { + const { code, bdst, findBdst } = useWrStore((state) => { return state; }); + + const { userSiSggCd } = code; + const [bdstTable, setbdstTable] = useState<BdstTypeMap[T][]>(); - const [rainBdstForm, setRainBdstForm] = useState<BdstTypeMap[T]>({} as BdstTypeMap[T]); - const [searchTxt, setSearchTxt] = useState<string>() - const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>() - const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""}); + const [rainBdstForm, setRainBdstForm] = useState<BdstTypeMap[T]>( + {} as BdstTypeMap[T] + ); + const [searchTxt, setSearchTxt] = useState<string>(); + const [objSearch, setObjSearch] = useState<objSearchType>({ + sgg: "", + city: "", + }); + const [useCityCd, setUserCityCd] = useState<SelectDataType[]>([]); + const [useSggCd, setUserSggCd] = useState<SelectDataType[]>([]); - const getSelCity = (val: string | number) => { - const cityValue = String(val); // Ensure val is treated as a string - const data = getCity(cityValue, code.sggCd); + const searchBdst = (searchTxt: string | undefined) => { + let data = objSearch.city; - setSelectSgg(data); - // getSgg(data[0]?.val || ""); - setObjSearch({ city: cityValue, sgg: '' }); + if (objSearch.sgg !== "" && objSearch.sgg !== "0") { + data = objSearch.sgg; + } + //RNB(빗물), RST(중수도), HTB(온배수) + findBdst(String(data), searchTxt || "", moType); }; - const getSgg = (val: string | number) => { - setObjSearch({...objSearch,sgg: String(val)}) - }; - - const searchBdst=(searchTxt: string | undefined)=>{ - let data =objSearch.city; - if(objSearch.city==="" ){ - - data = String(code.cityCd[0]?.val) - } - if(objSearch.sgg !=="" ){ - data = objSearch.sgg - } - - //RNB(빗물), RST(중수도), HTB(온배수) - findBdst(String(data), searchTxt || "",moType ) - - } - useEffect(() => { if (code.sggCd.length > 0) { - - setbdstTable( tableData(bdst.bdstBase, { code })); - } - }, [ bdst]); + const bdstData = bdst.bdstBase.map((bdst) => { + const archArea = + bdst?.archArea.split(".")[0] !== "-1" + ? bdst?.archArea.split(".")[0] + : "확인불가"; + return { + ...bdst, + archArea: archArea, + }; + }); + setbdstTable(tableData(bdstData, { code })); + } + }, [bdst]); + useEffect(() => { + if (userSiSggCd.length === 2 && code.cityCd.length > 0) { + const city = code.cityCd.filter((item) => item.val === userSiSggCd); + const sgg = code.sggCd.filter( + (item) => item.val.slice(0, 2) === userSiSggCd + ); + sgg.unshift({ text: "전체", val: "0" }); + setUserCityCd(city); // Fix: Ensure city is of type SelectDataType[] + setObjSearch({ ...objSearch, city: String(city[0]?.val) }); + setUserSggCd(sgg); + } else if ( + userSiSggCd.length === 5 && + code.cityCd.length > 0 && + code.sggCd.length > 0 + ) { + const city = code.cityCd.filter( + (item) => item.val === userSiSggCd.slice(0, 2) + ); + setUserCityCd(city); + const sgg = code.sggCd.filter((item) => item.val === userSiSggCd); + setUserSggCd(sgg); + setObjSearch({ city: String(city[0]?.val), sgg: String(sgg[0]?.val) }); + } + }, [userSiSggCd, code.cityCd, code.sggCd]); - const tableClick: (val: number | undefined , headId:string) => void = (val ,headId) => { - - if(val!==undefined && bdst?.bdstBase.length>0){ - const data:BdstTypeMap[T] =bdst?.bdstBase[val] - if (data) { - setRainBdstForm(data); - } + const tableClick: (val: number | undefined, headId: string) => void = ( + val + ) => { + if (val !== undefined && bdst?.bdstBase.length > 0) { + const data: BdstTypeMap[T] = bdst?.bdstBase[val]; + if (data) { + setRainBdstForm(data); } - } + } + }; - useEffect(()=>{ - setbdstTable([]) // 초기화 작업 - },[]) + useEffect(() => { + setbdstTable([]); // 초기화 작업 + }, []); return ( <> <div className="grid grid-cols-12 gap-4 mt-4 items-center"> @@ -99,31 +133,50 @@ export function BdstReg<T extends MoType>({ moType,setIsModal,isModal }: BdstReg className="col-span-3 h-full" label={"시도"} selectClass={selectClass} - selectArray={code.cityCd || []} - onSelectValue={getSelCity} - > - {""} - </SelectBox> + selectArray={useCityCd} + onSelectValue={(val) => { + setObjSearch({ ...objSearch, city: String(val) }); + }} + value={objSearch.city || useCityCd[0]?.val} + ></SelectBox> <SelectBox className="col-span-3 h-full" label={"시군구"} selectClass={selectClass} - selectArray={selectSgg || []} - onSelectValue={getSgg} - value={objSearch.sgg || ""} + selectArray={useSggCd || []} + onSelectValue={(val) => { + if (val) setObjSearch({ ...objSearch, sgg: String(val) }); + }} + value={objSearch.sgg || useSggCd[0]?.val} > {" "} </SelectBox> - <Label className="w-full text-xl text-gray-600 text-right">건축물명</Label> - <Input className="w-full h-full !text-xl col-span-2 col-start-8" type="text" value={searchTxt || ''} onChange={(e) => setSearchTxt(e.target.value)}/> - <Button className="" size={"sm"} onClick={()=>{searchBdst(searchTxt)}}>조회</Button> + <Label className="w-full text-xl text-gray-600 text-right"> + 시설명 + </Label> + <Input + className="w-full h-full !text-xl col-span-2 col-start-8" + type="text" + value={searchTxt || ""} + onChange={(e) => setSearchTxt(e.target.value)} + /> + <Button + className="" + size={"sm"} + onClick={() => { + searchBdst(searchTxt); + }} + > + 조회 + </Button> </div> <div className="border-t border-gray-300 my-4"></div> <div className="h-auto"> <h1 className="text-2xl font-medium text-label pl-8"> 건축물 목록 <span className="!text-2xl text-base text-blue-500"> - (유의 사항: 신규등록하려는 건축물이 목록에 없을 경우 하단 건축물 정보에 추가하여 주시기 바랍니다.) + (유의 사항: 신규등록하려는 건축물이 목록에 없을 경우 하단 건축물 + 정보에 추가하여 주시기 바랍니다.) </span> </h1> <ScrollArea className="h-[30vh]"> @@ -134,25 +187,46 @@ export function BdstReg<T extends MoType>({ moType,setIsModal,isModal }: BdstReg pageSize={-10} total={-1} headName={undefined} - cellClick={(idx, headId) => (tableClick(idx, headId || ""))} + cellClick={(idx, headId) => tableClick(idx, headId || "")} onPageChange={function (page: number): void { + console.log("page ", page); throw new Error("Function not implemented."); - }}> - </UiTable> + }} + ></UiTable> </div> </ScrollArea> <div className="border-t border-gray-300 my-4"></div> - <ScrollArea className="h-[40vh]"> - <div> - { moType === 'RNB'? - <RainRegForm rainForm={rainBdstForm as customRainBdst} isModal={isModal} setIsModal={setIsModal} /> - :moType==='RST' - ? <RswtrRegForm rswtForm={rainBdstForm as customRswtBdst} isModal={isModal} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></RswtrRegForm> - :<HtdflRegForm htdflForm={rainBdstForm as unknown as customHtdflBdst} isModal={true} setIsModal={(open) =>{setIsModal && setIsModal(open)}}></HtdflRegForm> - } - - </div> - </ScrollArea> + {/* <ScrollArea className="h-[40vh]"> */} + <div> + {moType === "RNB" ? ( + <RainRegForm + rainForm={rainBdstForm as customRainBdst} + isModal={isModal} + setIsModal={setIsModal} + /> + ) : moType === "RST" ? ( + <RswtrRegForm + rswtForm={rainBdstForm as customRswtBdst} + isModal={isModal} + setIsModal={(open?: boolean) => { + if (setIsModal && open) { + setIsModal(open); + } + }} + ></RswtrRegForm> + ) : ( + <HtdflRegForm + htdflForm={rainBdstForm as unknown as customHtdflBdst} + isModal={true} + setIsModal={(open?: boolean) => { + if (setIsModal && open) { + setIsModal(open); + } + }} + ></HtdflRegForm> + )} + </div> + {/* </ScrollArea> */} </div> </> ); diff --git a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx index 5b1a6f0f6..cc38b1f30 100644 --- a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx @@ -2,13 +2,11 @@ import { useWrStore } from "@/app/store"; import type { pubHasuType, - fcBizType, fcOrgwtType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; -import type { TableUpperProps } from "@/app/store/common/type/header"; import { tableData } from "@/components/lib/func/commom"; import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable"; -import { Title, UiTable } from "@common/business_components/ui"; +import { Title } from "@common/business_components/ui"; import { Label } from "@common/business_components/ui/form/lib/label"; import { Button } from "@common/business_components/ui/table/lib/button"; import { Input } from "@common/components/ui"; @@ -41,7 +39,7 @@ export default function FcOrgwtsRegModal({ (rightData as pubHasuType[])?.map((item) => { return { ...item, - swtrmtFcltFk: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정 + swtrmtFcltId: item.bscFctCd, // 임시값, 실제 데이터에 맞게 수정 orgwtWtritQnt: Number(item.fctCpc), // 임시값, 실제 데이터에 맞게 수정 tmsYn: "N", // 임시값, 실제 데이터에 맞게 수정 dschgFmYn: "N", // 임시값, 실제 데이터에 맞게 수정 @@ -93,7 +91,7 @@ export default function FcOrgwtsRegModal({ addr: item.dtlPstnExpln, orgwtWtritQnt: String(item.orgwtWtritQnt), fctCpc: String(item.orgwtWtritQnt), - swtrmtFcltFk: item.swtrmtFcltFk, + swtrmtFcltId: item.swtrmtFcltId, }))); rightRef.current = initTableData.map(item => ({ ...item })); } diff --git a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx index 846e427c6..e068c6c91 100644 --- a/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx +++ b/apps/wr/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal.tsx @@ -1,10 +1,8 @@ "use client"; -import { useWrStore } from "@/app/store"; import { pbnstRegZod, type customPbnst, type PbnstRegArrrayType, - type pubHasuType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; import { ScrollArea } from "@common/business_components"; @@ -17,105 +15,41 @@ import { } from "@common/components/ui"; import { useEffect, useState } from "react"; import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm"; -import { - useFieldArray, - type FieldErrors, - type UseFormReturn, -} from "react-hook-form"; +import { type FieldErrors, type UseFormReturn } from "react-hook-form"; import { writeRgtrAndMdfr } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg"; -import toast from "react-hot-toast"; import type { z } from "zod"; +import { confirmToast } from "@/components/lib/func/commom"; +import { useTranslation } from "react-i18next"; export function PbnstRegModal({ form, setPbnstInsert, - onInvalid + onInvalid, }: { form: UseFormReturn<{ items: PbnstRegArrrayType }>; setPbnstInsert: (data: customPbnst) => void; - onInvalid:(errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }>) => void + onInvalid: ( + errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }> + ) => void; }) { - const { pbnstInsert } = useWrStore((state) => { - return state; - }); - const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>( - {} as customPbnst - ); - const [currentTab, setCurrentTab] = useState<string>("mng"); + const { t } = useTranslation("base"); + + //TODO: 유즈 스테이트에 set만해도 되나? + const [, setCurrentTab] = useState<string>("mng"); const [indexMng, setIndexMng] = useState<number>(0); const [indexBiz, setIndexBiz] = useState<number>(0); - - const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { - const item = valuse.items[indexMng]; - const data = item ? writeRgtrAndMdfr([item]) : []; - if (data && data[0]) { - setPbnstInsert(data[0]); - } - }; - // const onInvalid = ( - // errors: FieldErrors<{ items: z.infer<typeof pbnstRegZod>[] }> - // ) => { - // // 재귀 함수를 사용해 중첩된 에러 객체에서 모든 에러 메시지와 경로를 찾습니다. - - - // const findAllErrors = ( - // errorObject: any, - // path: (string | number)[] = [] - // ): { message: string; path: (string | number)[] }[] => { - // if (!errorObject) return []; - - // return Object.keys(errorObject).flatMap((key) => { - // const value = errorObject[key]; - // const currentKey = !isNaN(parseInt(key)) ? parseInt(key) : key; - // const newPath = [...path, currentKey]; - // if (value && typeof value === "object") { - // if (typeof value.message === "string") { - // return [{ message: value.message, path: newPath }]; // 에러 메시지와 경로 반환 - // } - // return findAllErrors(value, newPath); - // } - // return []; - // }); - // }; - - - // const errorList = findAllErrors(errors); - - - // if (errorList.length > 0) { - // errorList.forEach((errorInfo) => { - // const { message, path } = errorInfo; - // let prefix = ""; - // const itemsIndex = path.indexOf("items"); - - - // if (itemsIndex > -1 && path.length > itemsIndex + 1) { - // const itemIdx = path[itemsIndex + 1] as number; - // const facilityName = form.getValues( - // `items.${itemIdx}.ruseUtztnFcltNm` - // ); - // if (facilityName) { - // prefix += `[${facilityName}] `; - // } - - // const fcBizsIndex = path.indexOf("fcBizs"); - // if (fcBizsIndex > -1 && path.length > fcBizsIndex + 1) { - // const bizIdx = path[fcBizsIndex + 1] as number; - // const cycle = form.getValues( - // `items.${itemIdx}.fcBizs.${bizIdx}.cycl` - // ); - // if (cycle) { - // prefix += `[${cycle}차수] `; - // } - // } - // } - - - // toast.error(`${prefix}${message}`); - // }); - // } - // }; + const onSubmit = async (valuse: { items: PbnstRegArrrayType }) => { + const item = valuse.items[indexMng]; + const data = item ? writeRgtrAndMdfr([item]) : []; +// + const handleConfirm = () => { + if (data && data[0]) { + setPbnstInsert(data[0]); + } + }; + confirmToast(t("isInsertMsg"), handleConfirm); + }; const handleTabChange = (value: string) => { setCurrentTab(value); @@ -159,7 +93,6 @@ export function PbnstRegModal({ <PbnstMngForm form={form} formType={"reg"} - firstFcltData={pbnstBdstForm} indexMng={indexMng} setIndexMng={setIndexMng} /> @@ -171,7 +104,6 @@ export function PbnstRegModal({ indexBiz={indexBiz} setIndexBiz={setIndexBiz} formType={"reg"} - firstBizData={pbnstBdstForm.fcBizs} /> </TabsContent> </Tabs> diff --git a/apps/wr/components/ui/modal/ldrmntSttn/ldrmntExcelModal.tsx b/apps/wr/components/ui/modal/ldrmntSttn/ldrmntExcelModal.tsx deleted file mode 100644 index 5427c5dd2..000000000 --- a/apps/wr/components/ui/modal/ldrmntSttn/ldrmntExcelModal.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { useWrStore } from "@/app/store"; -import { pbnPrfRegExcelZod } from "@/app/store/prfmncReg/pbnstPrfmncReg/headList"; -import type { FcPrfType, PrfType } from "@/app/store/prfmncReg/pbnstPrfmncReg/type"; -import { yearOptions } from "@/components/lib/func/commom"; -import { FileUpload, Form, FormField, FormUi, SelectBox, Title } from "@common/business_components/ui"; -import { Button, Input } from "@common/components/ui"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { useState } from "react"; -import { useForm } from "react-hook-form"; -import type { z } from "zod"; - -export default function LdrmntExcelModal({ data }: { data: FcPrfType }) { - const { prfmnRegData } = useWrStore((state) => state); - const [excelData, setExcelData] = useState<PrfType[]>(); - const form = useForm<z.infer<typeof pbnPrfRegExcelZod>>({ - resolver: zodResolver(pbnPrfRegExcelZod), - defaultValues: { - ym: String(new Date().getFullYear()), - }, - }); - const onSubmit = (values: z.infer<typeof pbnPrfRegExcelZod>) => { - if (excelData) { - prfmnRegData(excelData as unknown as PrfType); - } - }; - const [files, setFiles] = useState<File[] | null>(null); - return ( - <> - <div> - <Form {...form}> - <form onSubmit={form.handleSubmit(onSubmit)}> - <div> - <Title title={"잠재수요처 등록"}> -
-
-

- {"잠재수요처 파일"} -

- - -
-
- ( - - { - if (files) setFiles(files); - }} - fileTypes="xlsx" - > - - )} - /> -
- - -
- - ) - -} \ No newline at end of file diff --git a/apps/wr/components/ui/modal/sttn/headChModal/headChModal.tsx b/apps/wr/components/ui/modal/sttn/headChModal/headChModal.tsx index 83a5a3523..0673f3ca5 100644 --- a/apps/wr/components/ui/modal/sttn/headChModal/headChModal.tsx +++ b/apps/wr/components/ui/modal/sttn/headChModal/headChModal.tsx @@ -1,39 +1,47 @@ import { useWrStore } from "@/app/store"; -import { sttnHeadListType } from "@/app/store/ruseFcltMng/fcltSttn/rainSttn/headList"; -import { Form, FormControl, FormDescription, FormField, FormItem, FormLabel, FormMessage } from "@common/business_components/ui"; +import { sttnHeadListType } from "@/app/store/ruseFcltMng/fcltSttn/rainSttn/headList"; +import { Form, FormControl, FormField, FormItem, FormLabel, } from "@common/business_components/ui"; import { Button, Checkbox } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; -export default function HeadChModal({headList, type }:{headList : z.infer ,type:string }) { - const { rainChSttnHead , rswtChSttnHead, htdflChSttnHead, pbnstChSttnHead} = useWrStore((state) => state); - - - let items = headList.map(item => ({id:item.id, title:item.title, val:item.visible })); - - - const form = useForm>({ - resolver: zodResolver(sttnHeadListType), - defaultValues: [], - }) +export default function HeadChModal({ headList, type }: { headList: z.infer, type: string }) { + const { rainChSttnHead, rswtChSttnHead, htdflChSttnHead, pbnstChSttnHead } = useWrStore((state) => state); - useEffect(() =>{ - form.reset(headList) + const items = headList.map(item => ({ id: item.id, title: item.title, val: item.visible })); + const form = useForm>({ + resolver: zodResolver(sttnHeadListType), + defaultValues: headList, + }); - },[headList]) + useEffect(() => { + form.reset(headList); + }, [headList, form]); - const onSubmit = (valueList : z.infer ) =>{ - if(type==='RNB'){ + const rawValues = form.watch(); + const values: Array<{ visible: boolean }> = Array.isArray(rawValues) + ? rawValues + : Object.values(rawValues); + + const allChecked = values.every((v) => v.visible); + + const toggleAll = (checked: boolean) => { + const newValues = values.map((v) => ({ ...v, visible: checked })); + form.reset(newValues); + }; + + const onSubmit = (valueList: z.infer) => { + if (type === 'RNB') { rainChSttnHead(valueList) - }else if(type=== 'RST'){ + } else if (type === 'RST') { rswtChSttnHead(valueList) - }else if(type === 'HTB'){ + } else if (type === 'HTB') { htdflChSttnHead(valueList) - }else if(type === 'PBN'){ + } else if (type === 'PBN') { pbnstChSttnHead(valueList) } } @@ -42,42 +50,50 @@ export default function HeadChModal({headList, type }:{headList : z.infer
- - -
-

조회항목 설정

-
- {items.map((item,index) => ( - - { - return ( - - - - { - field.onChange(checked); - return; - } - } - /> - - - {item.title} - - - ); - }} - /> - ))} + + +
+

조회항목 설정

+
+ {/* 전체 선택/해제 체크박스 */} + + + toggleAll(checked as boolean)} + /> + + 전체 + + {items.map((item, index) => ( + { + return ( + + + { + field.onChange(checked); + return; + } + } + /> + + + {item.title} + + + ); + }} + /> + ))} diff --git a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx index cec8babd0..1e87590b8 100644 --- a/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx +++ b/apps/wr/components/ui/modal/sttn/pbnstSttnModal/pbnstSttnModal.tsx @@ -1,3 +1,4 @@ +import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import { @@ -14,29 +15,29 @@ import { type fcBizType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { formH1Class } from "@/components/lib/class/comClass"; +import { InputTableBody } from "@/components/lib/func/TableData"; import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm"; import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; +import ListDiv from "@common/business_components/ui/list_div"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; import { + Table, + TableBody, + TableHeader, Tabs, + TabsContent, TabsList, TabsTrigger, - Button, - TabsContent, } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; import { useEffect, useState } from "react"; -import { set, useForm } from "react-hook-form"; +import { useForm } from "react-hook-form"; import { z } from "zod"; export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titleVisible?: boolean }) { - const { code, pbnstSttn, prfmnc } = useWrStore((state) => state); + const { pbnstSttn, prfmnc , pbnstPrfmncSttn} = useWrStore((state) => state); const [fcltTab, setFcltTab] = useState("fclt"); const [ruseTab, setRuseTab] = useState("totalPrf"); - const [ruseBizData, setRuseBizData] = useState<{ - data: any[]; - head: TableUpperProps[]; - }>(); const [ruseHeadList, setRuseHeadList] = useState([]); const [ruseTableData, setRuseTableData] = useState([]); const [prfData, setPrfData] = useState<{ @@ -45,7 +46,6 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl totalPrf: any[]; }>(); const [indexMng, setIndexMng] = useState(0); - const [indexBiz, setIndexBiz] = useState(0); const form = useForm<{ items: z.infer[]; }>({ @@ -55,7 +55,6 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl }); - const { monthHeadList } = prfmnc; useEffect(() => { let tableData; if (fcltTab === "fclt") { @@ -180,6 +179,7 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl const usageKey = inData.usage; const value = (prfItem as any)[usageKey] ?? 0; + inData[monthKey] = value; inData.total += value; @@ -227,11 +227,10 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl useEffect(() => { if (pbnstSttn.pbnstSttnRes && data) { const prfList = pbnstSttn.pbnstSttnRes.find( - (item) => item.pbnstRuseFcltPk === data.pbnstRuseFcltPk + (item) => item.pbnstRuseFcltId === data.pbnstRuseFcltId )?.prfList; if (prfList) { - console.log("prfList", prfList); getTablePrfData(prfList); } @@ -296,15 +295,14 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl pageSize={0} total={0} cellClick={undefined} - onPageChange={function (page: number): void { + onPageChange={function (): void { throw new Error("Function not implemented."); }} - children={ - fcltTab === "fclt" ? ( + > + {fcltTab === "fclt" ? ( - ) : undefined - } - > + ) : undefined} +
@@ -324,17 +322,23 @@ export function PbnstSttnModal({ data, titleVisible }: { data: customPbnst; titl {prfData && ( - + + +
+

+ {"하수처리수재이용 실적(m3) 등록결과"} +

+
+ + + {headMakeprfmnc(pbnstPrfmncSttn.monthSttnHeadList, [])} + + + {InputTableBody(prfData[ruseTab as keyof typeof prfData] || [], pbnstPrfmncSttn.monthSttnHeadList, setPrfData as any)} + +
+
+
)}
diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx index b7229a559..8ad5da057 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/coDatailModal.tsx @@ -1,36 +1,28 @@ "use client"; -import { useWrStore } from "@/app/store"; +import { txtSize } from "@/app/store/common/code/basicCode"; import type { customLdrmnt } from "@/app/store/matDmd/ldrmntCoSttn"; import { ldrmntZod } from "@/app/store/matDmd/ldrmntCoSttn/headList"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; -import { handleCommaNumberChange } from "@/components/lib/func/commom"; -import { DatePicker, Form, FormField, FormUi, ScrollArea } from "@common/business_components/ui"; +import { formatCommaNumber, handleCommaNumberChange } from "@/components/lib/func/commom"; +import { Form, FormField, FormUi, ScrollArea } from "@common/business_components/ui"; import { Button, Input } from "@common/components/ui"; import { zodResolver } from "@hookform/resolvers/zod"; -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { useForm } from "react-hook-form"; import type { z } from "zod"; -export default function SttnDetailModal({ - formObj, +export default function CoDetailModal({ + formObj,onFormSubmit }: { formObj: any; + onFormSubmit:(values:customLdrmnt)=>void; }) { - const { ldrmntUpdate } = useWrStore( - (state) => state - ); const defaultValues: z.infer = ldrmntZod.parse({}); const form = useForm>({ resolver: zodResolver(ldrmntZod), defaultValues: defaultValues, }); - const onSubmit = (values: customLdrmnt) => { - console.log("values", values) - if (values) - ldrmntUpdate(values) - }; - useEffect(() => { if (ldrmntZod) form.reset(formObj); }, [formObj]); @@ -55,7 +47,7 @@ export default function SttnDetailModal({
- +

잠재수요처 상세정보 @@ -74,8 +66,6 @@ export default function SttnDetailModal({ className={selectClass} placeholder="" type="hidden" - onChange={(e) => { - }} value={field.value ?? ""} /> @@ -96,7 +86,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -115,7 +106,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -137,7 +129,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -156,7 +149,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -177,7 +171,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -196,7 +191,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -215,7 +211,8 @@ export default function SttnDetailModal({ onChange={(e) => { field.onChange(e.target.value); }} - value={field.value ?? "" ?? ""} + value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -237,6 +234,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -257,6 +255,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -278,6 +277,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -297,6 +297,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -316,6 +317,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={13} /> )} @@ -334,13 +336,14 @@ export default function SttnDetailModal({ { // field.onChange(e.target.value); handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} min={0} + maxLength={8} /> )} @@ -355,12 +358,13 @@ export default function SttnDetailModal({ { - field.onChange(e.target.value); + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} min={0} + maxLength={8} /> )} @@ -375,12 +379,13 @@ export default function SttnDetailModal({ { - field.onChange(e.target.value); + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} min={0} + maxLength={8} /> )} @@ -395,12 +400,13 @@ export default function SttnDetailModal({ { - field.onChange(e.target.value); + handleCommaNumberChange(e, field.onChange); }} - value={field.value ?? 0} + value={formatCommaNumber(field.value)} min={0} + maxLength={8} /> )} @@ -444,6 +450,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -463,6 +470,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -482,6 +490,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -504,6 +513,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -523,6 +533,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -542,6 +553,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -565,6 +577,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -584,6 +597,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -603,6 +617,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -626,6 +641,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -645,6 +661,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -664,6 +681,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -686,6 +704,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -705,6 +724,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -724,6 +744,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -745,6 +766,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={txtSize} /> )} @@ -754,7 +776,7 @@ export default function SttnDetailModal({ ( + render={({ field }) => ( )} @@ -786,6 +809,7 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={50} /> )} @@ -805,15 +829,13 @@ export default function SttnDetailModal({ field.onChange(e.target.value); }} value={field.value ?? ""} + maxLength={50} /> )} />

- - - diff --git a/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx b/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx index 0f7dbf706..6610a826a 100644 --- a/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx +++ b/apps/wr/components/ui/modal/sttn/sttnDetailModal/sttnDetailModal.tsx @@ -1,17 +1,16 @@ "use client"; -import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; -import RainRegForm from "../../../form/fcltReg/rainReg/rainRegForm"; -import RswtrRegForm from "../../../form/fcltReg/rswtrReg/rswtrRegForm"; -import HtdflRegForm from "../../../form/fcltReg/htdflReg/htdflRegForm"; +import { useWrStore } from "@/app/store"; +import type { CommonTableProps } from "@/app/store/common/type/header"; +import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; import type { customRainBdst } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import type { customRswtBdst } from "@/app/store/ruseFcltMng/fcltReg/rswtReg"; -import type { customHtdflBdst } from "@/app/store/ruseFcltMng/fcltReg/htdflReg"; -import { useWrStore } from "@/app/store"; -import { useEffect, useState } from "react"; -import type { CommonTableProps } from "@/app/store/common/type/header"; -import { rainChkTableData, rswtChkTableData } from "@/components/lib/func/TableData"; +import { rainChkTableData } from "@/components/lib/func/TableData"; +import { ScrollArea, Title, UiTable } from "@common/business_components/ui"; import { HeadMakeColSpan } from "@common/business_components/ui/table/HeadMakeColSpan"; -import type { rswtChkZodType } from "@/app/store/prfmncReg/chkgdnReg/rswrtChkgdn"; +import { useEffect, useState } from "react"; +import HtdflRegForm from "../../../form/fcltReg/htdflReg/htdflRegForm"; +import RainRegForm from "../../../form/fcltReg/rainReg/rainRegForm"; +import RswtrRegForm from "../../../form/fcltReg/rswtrReg/rswtrRegForm"; export default function SttnDetailModal({ type, @@ -20,7 +19,7 @@ export default function SttnDetailModal({ type: string; formObj: any; }) { - const { code, rainSttn, rswtSttn, rainSttnChkSearch,rswtChkPolAndGuide } = useWrStore( + const { rainSttn, rswtSttn, rainSttnChkSearch } = useWrStore( (state) => state ); const [detailData, setDetailData] = useState({ @@ -30,19 +29,19 @@ export default function SttnDetailModal({ }); useEffect(() => { - if (type === "RNB" && formObj.reuseBuilding[0]) { - rainSttnChkSearch(formObj.reuseBuilding[0].bdstRuseFcltPk); + if (type === "RNB" && formObj?.reuseBuilding[0]) { + rainSttnChkSearch(formObj.reuseBuilding[0].bdstRuseFcltSn); } else if (type === "RST") { - // rswtChkPolAndGuide(formObj.reuseBuilding[0].bdstRuseFcltPk) + // rswtChkPolAndGuide(formObj.reuseBuilding[0].bdstRuseFcltSn) } }, [type, formObj]); useEffect(() => { if ( type === "RNB" && - formObj.reuseBuilding[0] && - rainSttn.rainChkRes?.bdstRuseFcltFk + formObj?.reuseBuilding[0] && + rainSttn.rainChkRes?.bdstRuseFcltSn ) { const tableTotalData = rainChkTableData([rainSttn.rainChkRes]); const data = tableTotalData.map((item) => { @@ -79,7 +78,6 @@ export default function SttnDetailModal({ useEffect(() =>{ setDetailData({data:[] , head:[], node:[]}) - },[]) return ( @@ -104,15 +102,17 @@ export default function SttnDetailModal({ } tableData={detailData.data || []} headlist={detailData.head || []} - children={ } pageSize={0} total={0} cellClick={undefined} onPageChange={function (page: number): void { + console.log('page ', page) throw new Error("Function not implemented."); }} - >:<>} + > + + :<>}
diff --git a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx index 627537dcb..7676f7e71 100644 --- a/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/guideDetailTable/guideDetailTable.tsx @@ -1,26 +1,21 @@ "use client"; import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; -import { useWrStore } from "@/app/store"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; import { InputTableBody } from "@/components/lib/func/TableData"; import { - Input, Table, TableBody, - TableCell, TableHeader, - TableRow, } from "@common/components/ui"; -import { useEffect, useState, type Dispatch, type SetStateAction } from "react"; +import { useEffect, useState } from "react"; export function GuideDetailsTable({ chgRes, headList, upheadList, - type, setChGuidData, }: { chgRes: any[]; @@ -29,7 +24,6 @@ export function GuideDetailsTable({ type: string; setChGuidData: (chgRes: any[]) => void; }) { - const { code, rainChkgdn } = useWrStore((state) => state); const [inputData, setInputData] = useState(); useEffect(() => { diff --git a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx index aba225687..f607c289e 100644 --- a/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rainChkgd/rainChkgdTable.tsx @@ -97,7 +97,7 @@ export default function RainChkgdTable({ //현황 페이지에서 필요한 엑셀 데이터를 바뀔때마다 넣기 위해서 getRainSttnExcel(makeTableData); - const selectedData = makeTableData.filter((item) => selectedIds.includes(item.chkgdnPk)); + const selectedData = makeTableData.filter((item) => selectedIds.includes(item.chkgdnSn)); if (selectedData.length > 0) { const updateTableData = rainChkgdn.rainChk @@ -108,7 +108,7 @@ export default function RainChkgdTable({ // 변경 데이터는 평탄화한 데이터 즉 루트에 변경되어 있음 이용용도까지 잇음 그걸로 찾기 const findRain = selectedData.find( (sd) => - rd.chkgdnFk === sd.chkgdnPk && rd.utztnUsgCd === sd.utztnUsgCd + rd.chkgdnSn === sd.chkgdnSn && rd.utztnUsgCd === sd.utztnUsgCd ); if (findRain != undefined) { diff --git a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx index 7a43df3d8..7cb647579 100644 --- a/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx +++ b/apps/wr/components/ui/table/chkgdTable/rswtChkgd/rswtChkgdTable.tsx @@ -35,7 +35,7 @@ export default function RswtChkgdTable({ onPageChange: (page: number) => void; pageCount: number; }) { - const { code, rswtChkgdn, rswtChkSttn, rswtChkgdnInit, rswtChkPolAndGuide, getRswtSttnExcel } = useWrStore( + const { code, rswtChkgdn, rswtChkSttn, rswtChkPolAndGuide, getRswtSttnExcel } = useWrStore( (state) => state ); const [headList, setHeadList] = useState<{ headList: TableUpperProps[], upHeadList: chHeadType[] }>({ headList: [], upHeadList: [] }); @@ -65,7 +65,7 @@ export default function RswtChkgdTable({ const handleCellClick = useCallback( (index: number, headId: string) => { if (headId === "splyUswtrUtztnQnt" || headId === "ruseFcltUtztnQnt") { - rswtChkPolAndGuide(makeTableData[index].chkgdnPk); + rswtChkPolAndGuide(makeTableData[index].chkgdnSn); } }, [makeTableData, handleRswtClick] @@ -80,14 +80,14 @@ export default function RswtChkgdTable({ const selectedData = makeTableData .map((item) => { return { - chkgdnFk: item.chkgdnFk, + chkgdnSn: item.chkgdnSn, utztnUsgCd: item.utztnUsgCd, vltnDt: item.vltnDt, vltnMttr: item.vltnMttr, levyAmt: Number(item.levyAmt), }; }) - .filter((item) => selectedIds.includes(item.chkgdnFk)); + .filter((item) => selectedIds.includes(item.chkgdnSn)); if (selectedData) setUpRswttDetail(selectedData); }, [makeTableData, selectedIds]); diff --git a/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx b/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx index e4ffc1f8d..07e7c1e8d 100644 --- a/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx +++ b/apps/wr/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable.tsx @@ -35,11 +35,14 @@ const RuseMngTable = React.forwardRef( { tableData, headList, upHeadList, code, onTableSet, indexMng, indexBiz }, ref ) => { + + const [tableState, setTableState] = useState([...tableData]); useEffect(() => { if (ref && typeof ref === "object" && "current" in ref) { ref.current = tableState; } + if (onTableSet) onTableSet(tableState); }, [tableState, onTableSet]); @@ -152,4 +155,6 @@ const RuseMngTable = React.forwardRef( ); } ); +RuseMngTable.displayName = "RuseMngTable"; + export default RuseMngTable; diff --git a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx index 6f4832c68..2efa1c795 100644 --- a/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx +++ b/apps/wr/components/ui/table/pbnstReg/ruseMngTableForm/ruseMngTableForm.tsx @@ -1,7 +1,6 @@ import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead"; import type { TableUpperProps } from "@/app/store/common/type/header"; import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList"; -import type { customPbnst as OriginalCustomPbnst } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg"; import { formatCommaNumber, @@ -32,7 +31,6 @@ type RuseMngTableProps = { headList: TableUpperProps[]; upHeadList: chHeadType[]; code?: { name: string; val: SelectDataType[] }[]; - onTableSet?: (item: any) => void; indexMng?: number; indexBiz?: number; form?: any; @@ -46,7 +44,6 @@ const RuseMngTableForm = React.forwardRef( headList, upHeadList, code, - onTableSet, indexMng, form, formNm, @@ -56,7 +53,8 @@ const RuseMngTableForm = React.forwardRef( ) => { return ( <> - +
{upHeadList ? ( headMakeprfmnc(headList, upHeadList) @@ -76,20 +74,20 @@ const RuseMngTableForm = React.forwardRef( {tableData.map((item, i) => ( - + {headList.map((head, j) => ( {}} + onClick={() => { }} > = 0 && - typeof indexBiz === "number" && - indexBiz >= 0 + indexMng >= 0 && + typeof indexBiz === "number" && + indexBiz >= 0 ? `items.${indexMng}.fcBizs.${indexBiz}.${formNm}.${i}.${head.id}` : typeof indexMng === "number" && indexMng >= 0 ? `items.${indexMng}.${formNm}.${i}.${head.id}` @@ -114,6 +112,7 @@ const RuseMngTableForm = React.forwardRef( : field.value || "" } readOnly={head.readonly ? true : false} + maxLength={head.maxLength?head.maxLength:15} /> ) : head.type === "select" ? ( ( } }} readOnly={head.readonly ? true : false} - // Disabled prop removed as SelectBox does not support it + // Disabled prop removed as SelectBox does not support it > ) : head.type === "date" ? ( ( }} > ) : ( - `${item[head.id] || ""}` + ( + + { + head.type === "number" + ? formatCommaNumber(field.value) + : field.value || "" + } + ) )} )} @@ -176,4 +182,7 @@ const RuseMngTableForm = React.forwardRef( ); } ); + +RuseMngTableForm.displayName = "RuseMngTableForm"; + export default RuseMngTableForm; diff --git a/apps/wr/eslint.config.mjs b/apps/wr/eslint.config.mjs index c85fb67c4..73d6b7492 100644 --- a/apps/wr/eslint.config.mjs +++ b/apps/wr/eslint.config.mjs @@ -1,6 +1,6 @@ +import { FlatCompat } from "@eslint/eslintrc"; import { dirname } from "path"; import { fileURLToPath } from "url"; -import { FlatCompat } from "@eslint/eslintrc"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); @@ -11,6 +11,10 @@ const compat = new FlatCompat({ const eslintConfig = [ ...compat.extends("next/core-web-vitals", "next/typescript"), + {rules:{ + // other rules.. + "@typescript-eslint/no-explicit-any": "off", + }}, ]; export default eslintConfig; diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts index 5acc41863..9b0c8dc84 100644 --- a/apps/wr/middleware.ts +++ b/apps/wr/middleware.ts @@ -6,6 +6,7 @@ const CLAIM_NAME = "Authorization"; const AUTH_USER_ID = "token-id"; const serverApiUrl = CS_URL; const GEOSERVER_URL = process.env.NEXT_PUBLIC_GEOSERVER_URL || ""; +const LX_GEOSERVER_URL = process.env.NEXT_PUBLIC_LX_GEOSERVER_URL || ""; const SEWERAGE_API_URL = process.env.NEXT_PUBLIC_SEWERAGE_API_URL || ""; export function middleware(req: NextRequest) { @@ -48,10 +49,44 @@ export function middleware(req: NextRequest) { } if (pathname.startsWith("/geoserver")) { - const queryParams = searchParams.toString(); - const newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${ - queryParams ? `?${queryParams}` : "" - }`; + let queryParams = searchParams.toString(); + const typename = searchParams.get("TYPENAME"); + console.log("typename ", typename); + + let newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + + if ( + typename == "hasudo:tb_il_swage_prcs_fclt" //하수처리시설 + || typename == "hasudo:tb_ms_swage_prcs_zone" //하수처리구역 + || typename == "hasudo:tb_ms_sbmrg_dngr_map" //침수위험지도 + || typename == "hasudo:tb_ms_flood_dngr_map" //도시침수지도 + ) { + newUrl = `${GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + } + else if ( + typename == "hasudo:tb_ms_swage_ppl" //관로 + || typename == "hasudo:tb_ms_swage_mhl" //맨홀 + || typename == "hasudo:tb_ms_swage_pmstn" //펌프장 + || typename == "hasudo:tb_ms_stofcbr" //우수토실 + ) { + newUrl = `${LX_GEOSERVER_URL}${pathname.replace("/geoserver", "")}${queryParams ? `?${queryParams}` : ""}`; + } + else if ( + typename == "hasudo:om_dt_untrt_swg_rain" //중점우수토실 + || typename == "hasudo:om_wqlt_station" //관측소 + || typename == "hasudo:tb_wr_bdst_ruse_fclt" //재이용시설 + || typename == "hasudo:tb_wr_rnwtr_utztn_fclt" //빗물이용시설 + || typename == "hasudo:tb_wr_rswtr_fclt" //중수도시설 + || typename == "hasudo:tb_wr_htdfl_fclt" //온배수시설 + || typename == "hasudo:tb_wr_ruse_fclt_dmd_co" //수요처 + || typename == "hasudo:tb_wr_tmpr_dmd_co" //잠재수요처 + ){ + const url = req.nextUrl.clone(); + url.searchParams.set('TYPENAME', typename.replace("hasudo:","")); + queryParams = url.searchParams.toString(); + newUrl = `${SEWERAGE_API_URL}/v1/map/geometry${queryParams ? `?${queryParams}` : ""}`; + } + console.log(`[Middleware] Rewriting from '/geoserver' path to: ${newUrl}`); return NextResponse.rewrite(new URL(newUrl)); } diff --git a/apps/wr/package.json b/apps/wr/package.json index 44ba5a06b..5507b08fa 100644 --- a/apps/wr/package.json +++ b/apps/wr/package.json @@ -5,7 +5,7 @@ "scripts": { "dev": "next dev -p 3001", "build": "next build", - "start": "next start", + "start": "next start -p 3001", "lint": "next lint" }, "dependencies": { @@ -16,11 +16,13 @@ "@tanstack/react-table": "^8.21.2", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "i18next": "^25.3.2", "lucide-react": "^0.474.0", "moment": "^2.30.1", "next": "15.1.7", "react-hook-form": "^7.54.2", "react-hot-toast": "^2.5.2", + "react-i18next": "^15.6.0", "tailwind-merge": "^3.0.1", "tailwindcss-animate": "^1.0.7", "tus-js-client": "^4.3.1", diff --git a/apps/wr/public/images/map/layericon/Layer_Select_BTN.png b/apps/wr/public/images/map/layericon/Layer_Select_BTN.png new file mode 100644 index 000000000..1e810feaf Binary files /dev/null and b/apps/wr/public/images/map/layericon/Layer_Select_BTN.png differ diff --git a/apps/wr/public/locales/ko/message.json b/apps/wr/public/locales/ko/message.json new file mode 100644 index 000000000..96931ee72 --- /dev/null +++ b/apps/wr/public/locales/ko/message.json @@ -0,0 +1,25 @@ +{ + "deleteMsg" : "{{name}}가 삭제되었습니다.", + "insertMsg": "{{name}}가 저장되었습니다.", + "updateMsg": "{{name}}가 수정되었습니다.", + "errorMsg": "{{name}} 중 오류가 발생했습니다.", + "fileErrMsg": "빈 파일 또는 파일 오류입니다.", + "selectErrMsg": "{{name}}을(를) 선택해주세요.", + "noChangedErrMsg": "변경사항이 없습니다.", + "dateErrMsg": "시작년도를 종료년도 이후로 설정할 수 없습니다.", + "fileDateErrMsg": "파일업로드 이전에 등록년도를 작성해주세요.", + "isDeleteMsg": "선택한 정보를 삭제하시겠습니까?", + "isUpdateMsg": "수정한 정보를 저장하시겠습니까?", + "isInsertMsg": "등록하시겠습니까?", + "isUpdatetMsg": "수정하시겠습니까?", + + "excelDownErrMsg": "다운로드할 데이터가 없습니다.", + + "alreadyInsertedErrMsg": "사업자번호 {{num}}(은)는 이미 등록되었습니다. 다시 등록해주세요.", + "saveRowErrMsg": "수정을 원하는 행을 선택하고 저장버튼을 눌러주세요.", + "costCalcErrMsg":"공사비 계산 진행 후 저장을 눌러주세요", + "maxYearErrMsg": "최대 {{year}}년까지 선택가능합니다.", + "checkQtyMsg": "요구수량(M3/d)을 확인해주세요 계산할 수 없습니다." + +} + diff --git a/apps/wr/public/sample_coSttn.xlsx b/apps/wr/public/sample_coSttn.xlsx index 836ee002e..222813c49 100644 Binary files a/apps/wr/public/sample_coSttn.xlsx and b/apps/wr/public/sample_coSttn.xlsx differ diff --git a/apps/wr/public/sample_htdflSttn.xlsx b/apps/wr/public/sample_htdflSttn.xlsx index fd1dc5a89..463c1ca87 100644 Binary files a/apps/wr/public/sample_htdflSttn.xlsx and b/apps/wr/public/sample_htdflSttn.xlsx differ diff --git a/apps/wr/public/sample_rswtSttn.xlsx b/apps/wr/public/sample_rswtSttn.xlsx index f64b37ea3..d97a79b6d 100644 Binary files a/apps/wr/public/sample_rswtSttn.xlsx and b/apps/wr/public/sample_rswtSttn.xlsx differ diff --git a/apps/wr/tsconfig.json b/apps/wr/tsconfig.json index d897e147f..493584782 100644 --- a/apps/wr/tsconfig.json +++ b/apps/wr/tsconfig.json @@ -2,6 +2,7 @@ "$schema": "https://json.schemastore.org/tsconfig", "extends": "../../tsconfig.base.json", "compilerOptions": { + "noImplicitAny": false, "baseUrl": ".", "target": "ES2017", "lib": ["dom", "dom.iterable", "esnext"], diff --git a/package.json b/package.json index 1af128b94..02d2d3cbd 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,7 @@ "packages/*" ], "scripts": { - "build": "turbo run build --filter=!wr --filter=!cs", + "build": "turbo run build", "build:common": "turbo run build --filter=@common/*", "dev": "turbo run dev", "dev:cs": "turbo run dev --filter=cs", diff --git a/packages/common/business_components/src/ui/chart/index.tsx b/packages/common/business_components/src/ui/chart/index.tsx index 898a65a79..6e0010f9a 100644 --- a/packages/common/business_components/src/ui/chart/index.tsx +++ b/packages/common/business_components/src/ui/chart/index.tsx @@ -1,9 +1,8 @@ - import React from 'react'; -import BarChart from './BarChart'; -import DoughnutChart from './DoughnutChart'; -import LineChart from './LineChart'; -import LineBarchart from './LineBarChart'; + import BarChart from './BarChart'; import DoubleBarChart from './DoubleBar'; +import DoughnutChart from './DoughnutChart'; +import LineBarchart from './LineBarChart'; +import LineChart from './LineChart'; /**차트 FORM */ const CHART_FORM = { @@ -36,7 +35,8 @@ const CHART_FORM = { // 각 차트에서 사용하는 ChartConfig 타입 정의 type ChartConfigItem = { label: string; - fill: string; + fill?: string; + color?: string; }; type ChartConfig = { @@ -80,5 +80,6 @@ function MainChart(props: MainChartProps) { } export { MainChart }; +export type { ChartConfig }; // eslint-disable-next-line react-refresh/only-export-components export { CHART_FORM }; diff --git a/packages/common/business_components/src/ui/date_picker_range/index.tsx b/packages/common/business_components/src/ui/date_picker_range/index.tsx index 70565230a..7cf19d819 100644 --- a/packages/common/business_components/src/ui/date_picker_range/index.tsx +++ b/packages/common/business_components/src/ui/date_picker_range/index.tsx @@ -4,21 +4,23 @@ import { format } from "date-fns"; import { CalendarIcon } from "lucide-react"; import type { DayPickerSingleProps } from "react-day-picker"; +import { Button, Calendar, Popover, PopoverContent, PopoverTrigger } from "@common/components/ui"; import { cn } from "../../lib/utils"; -import { Button } from "@common/components/ui"; -import { Calendar } from "@common/components/ui"; -import { Popover, PopoverContent, PopoverTrigger } from "@common/components/ui"; type DatePickerRangeProps = { placeholder?: string; disabled?: boolean | ((date: Date) => boolean); + onSelect: (date: Date | undefined) => void; } & DayPickerSingleProps; export function DatePickerRange({ className, placeholder = "날짜 선택", disabled, - ...props + mode, + selected, + onSelect, + defaultMonth, }: DatePickerRangeProps) { return ( @@ -29,16 +31,17 @@ export function DatePickerRange({ disabled={typeof disabled === "boolean" ? disabled : false} > - {props.selected ? ( - format(props.selected, "yyyy-MM-dd") + {selected ? ( + format(selected, "yyyy-MM-dd") ) : ( {placeholder} )} - diff --git a/packages/common/business_components/src/ui/map/Gis.js b/packages/common/business_components/src/ui/map/Gis.js index 3a7bec1b8..a723b2340 100644 --- a/packages/common/business_components/src/ui/map/Gis.js +++ b/packages/common/business_components/src/ui/map/Gis.js @@ -8,6 +8,7 @@ import * as olProj from 'ol/proj'; import { register } from 'ol/proj/proj4'; import proj4 from 'proj4'; import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react'; +import { createRoot } from 'react-dom/client'; import GisLonLat from './GisLonLat'; import GisMapToggle from './GisMapToggle'; import GisSelect from './GisSelect'; @@ -90,11 +91,11 @@ function Gis({ if (layerName === '하수재이용시설') { featureId = data.searchPk; } else if (layerName === '빗물이용시설'|| layerName == '중수도시설') { - featureId = data.bdstInfoPk; + featureId = data.bdstInfoSn; } else if (layerName === '하수처리시설') { featureId = data.bscFctCd; } else if (layerName === '온배수시설' ) { - featureId = data.bdstRuseFcltPk; + featureId = data.bdstRuseFcltSn; } else { console.warn('해당 레이어에 대한 featureId 매핑 없음', layerNm); featureId = data.fid || data.id || data.ftrIdn; diff --git a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx index 7b41bf30c..786b07925 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/form.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/form.tsx @@ -1,18 +1,16 @@ -import React from 'react'; -import { FormField } from "../form"; -import { SelectBox } from "../select"; -import { Input } from "@common/components"; -import { FormUi } from "../form_ui"; -import { useCallback, useEffect, useState } from "react"; +import { Input } from "@common/components"; import { AsYouType } from "libphonenumber-js"; +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"; // 수요처 정보 export type DemandCompType = { index : number | ''; - dmdInfoPk : string | ''; - dmdInfoFk : string | ''; + dmdInfoId : string | ''; bzmnNo : string | ''; dmdCoNm : string | ''; daddr : string | ''; @@ -50,7 +48,7 @@ interface FormSchema { ctpvCd: string; sggCd: string; dmdCoNm: string; - dmdInfoPk: string; + dmdInfoId: string; daddr: string; telno: string; bznmTotNo?: string; @@ -128,19 +126,19 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun type: string, field: ControllerRenderProps | undefined ) => { - if(!updateList?.dmdInfoPk) + if(!updateList?.dmdInfoId) switch (type) { case "ctpvCd": initializeSigunData(val); setSidoValue(val); field?.onChange(val); - form.setValue('dmdInfoPk', ''); + form.setValue('dmdInfoId', ''); form.setValue('bznmTotNo', ''); break; case "sggCd": setSigunValue(val); field?.onChange(val); - form.setValue('dmdInfoPk', ''); + form.setValue('dmdInfoId', ''); form.setValue('bznmTotNo', ''); break; } @@ -159,11 +157,11 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun const rtnCompData = item; form.setValue('dmdCoNm', rtnCompData?.dmdCoNm || ''); - form.setValue('dmdInfoPk', rtnCompData?.dmdInfoPk.substring(0,10) || ''); - form.setValue('bznmTotNo', rtnCompData?.dmdInfoPk.substring(10,14)==='0000' ? '' : rtnCompData?.dmdInfoPk.substring(10,14)); + form.setValue('dmdInfoId', rtnCompData?.dmdInfoId.substring(0,10) || ''); + form.setValue('bznmTotNo', rtnCompData?.dmdInfoId.substring(10,14)==='0000' ? '' : rtnCompData?.dmdInfoId.substring(10,14)); // 수요처 불러온 후 사업자번호를 바꿀경우를 대비함 - setOrgBznmNo(rtnCompData?.dmdInfoPk); + setOrgBznmNo(rtnCompData?.dmdInfoId); const sidoCd = rtnCompData?.ctpvCd.trim() || ''; setSidoValue(sidoCd); form.setValue('ctpvCd', sidoCd); @@ -175,7 +173,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun form.setValue('sggCd', sigunCd); }, 100); - if(rtnCompData?.dmdInfoPk.substring(10,14) === '0000') { + if(rtnCompData?.dmdInfoId.substring(10,14) === '0000') { handleCheckboxChange(true); } else { handleCheckboxChange(false); @@ -195,7 +193,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun const bznNoChange = useCallback((e: React.ChangeEvent, noType: string, field?: ControllerRenderProps) => { const value = e.target.value; - if(noType === 'dmdInfoPk') { + if(noType === 'dmdInfoId') { // 숫자만 추출하여 저장 (포맷팅 제거) const digitsOnly = value.replace(/\D/g, ""); @@ -217,15 +215,15 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun useEffect(() => { - if(updateList?.dmdInfoPk){ + if(updateList?.dmdInfoId){ form.reset(updateList) - if(updateList?.dmdInfoPk.slice(10,14) !== '0000') { + if(updateList?.dmdInfoId.slice(10,14) !== '0000') { handleCheckboxChange( false); - form.setValue('bznmTotNo', updateList?.dmdInfoPk.slice(10,14)); + form.setValue('bznmTotNo', updateList?.dmdInfoId.slice(10,14)); } else { handleCheckboxChange( true); } - form.setValue('dmdInfoPk', updateList?.dmdInfoPk.slice(0,10)); + form.setValue('dmdInfoId', updateList?.dmdInfoId.slice(0,10)); setUpdateNm(updateList?.dmdCoNm) // setSigunValue(updateList?.sggCd) }else{ @@ -246,14 +244,14 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun name: "ctpvCd", label: "시도", component: (field) => ( - updateList?.dmdInfoPk ? ( + updateList?.dmdInfoId ? ( {field.onChange(e.target.value)} } value={ selectSidoData.find(item => item.val === field.value?.trim() )?.text??''} - readOnly={!!updateList?.dmdInfoPk} + readOnly={!!updateList?.dmdInfoId} /> ) : ( ( - updateList?.dmdInfoPk ? ( + updateList?.dmdInfoId ? ( {field.onChange(e.target.value)} } value={selectSigunData.find(item => item.val === field.value?.trim() )?.text??''} - readOnly={!!updateList?.dmdInfoPk} + readOnly={!!updateList?.dmdInfoId} /> ) : ( ( bznNoChange(e, 'dmdInfoPk', field)} + onChange={(e) => bznNoChange(e, 'dmdInfoId', field)} value={formatBusinessNumber(field.value || '')} - readOnly={!!updateList?.dmdInfoPk} + readOnly={!!updateList?.dmdInfoId} /> ) }, @@ -339,7 +337,7 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun onChange={(e) => bznNoChange(e, 'bznmTotNo', field)} // {...field} value={ field.value} - readOnly={!!updateList?.dmdInfoPk} + readOnly={!!updateList?.dmdInfoId} /> ) @@ -407,12 +405,12 @@ export function SdmRegForm({ form, onCheckboxChange, selectSidoData, selectSigun return ( <> {formFields - .filter(({ name }) => !(updateList?.dmdInfoPk && (name === "dmdAplyPswd" || name === "dmdAplyPswdConfirm"))) + .filter(({ name }) => !(updateList?.dmdInfoId && (name === "dmdAplyPswd" || name === "dmdAplyPswdConfirm"))) .map(({ name, label, component }) => { const error = form.formState.errors[name]; const inputId = `${name}-input`; const errorId = `${name}-error`; - const isRequired = ["ctpvCd", "sggCd", "dmdCoNm", "dmdInfoPk", "daddr", "telno", "dmdAplyPswd", "dmdAplyPswdConfirm"].includes(name); + const isRequired = ["ctpvCd", "sggCd", "dmdCoNm", "dmdInfoId", "daddr", "telno", "dmdAplyPswd", "dmdAplyPswdConfirm"].includes(name); return ( isBznmTotNoDisabled ? !isDuplicate : true, "이미 등록된 사업자등록번호입니다"), @@ -43,11 +43,11 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,up .max(11, "전화번호는 11자 이내로 입력해주세요") .regex(/^[0-9]+$/, "전화번호는 숫자만 입력 가능합니다"), rgtr: z.string().optional(), - dmdAplyPswd : updateList?.dmdInfoPk // 업데이트일경우 + dmdAplyPswd : updateList?.dmdInfoId // 업데이트일경우 ? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음 : z.string().optional() .refine((val) => !val || (val.length >= 8 && val.length <= 16), "패스워드는 8자 이상 16자 이내로 입력해주세요"), - dmdAplyPswdConfirm: updateList?.dmdInfoPk // 업데이트일경우 + dmdAplyPswdConfirm: updateList?.dmdInfoId // 업데이트일경우 ? z.string().optional() // 패스워드는 선택 사항이며 길이 제한 없음 :z.string() .min(1, "패스워드확인을 입력해주세요"), @@ -68,7 +68,7 @@ const defaultValues: FormSchema = { ctpvCd: '', sggCd: '', dmdCoNm: '', - dmdInfoPk: '', + dmdInfoId: '', bznmTotNo: '', daddr: '', telno: '', @@ -152,11 +152,11 @@ export default function SdmInsertForm({selectSidoData, selectSigunData, dataList return; } - const dmdInfoPk = data.dmdInfoPk + (data.bznmTotNo || '0000'); + const dmdInfoId = data.dmdInfoId + (data.bznmTotNo || '0000'); const formData = { ...data, - dmdInfoPk, - bzmnNo: data.dmdInfoPk, + dmdInfoId, + bzmnNo: data.dmdInfoId, }; console.log(' formData ', formData) diff --git a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx index 059d63d90..59800b31e 100644 --- a/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx +++ b/packages/common/business_components/src/ui/sdmInsertForm/sdmNameBox.tsx @@ -102,19 +102,19 @@ export const SdmSearchForm = ({ } }} > - {item.dmdInfoPk.substring(10, 14) !== "0000" ? ( + {item.dmdInfoId.substring(10, 14) !== "0000" ? ( <> 사업자번호 : {" "} - {item.dmdInfoPk.substring(0, 10)}  + {item.dmdInfoId.substring(0, 10)}  종사업자번호 :{" "} {" "} - {item.dmdInfoPk.substring(10, 14)}  + {item.dmdInfoId.substring(10, 14)}  ) : ( <> 사업자번호 : {" "} - {item.dmdInfoPk.substring(0, 10)}  + {item.dmdInfoId.substring(0, 10)}  )} {item.dmdCoNm} diff --git a/packages/common/business_components/src/ui/table/index.tsx b/packages/common/business_components/src/ui/table/index.tsx index 095092a43..85ffb85ea 100644 --- a/packages/common/business_components/src/ui/table/index.tsx +++ b/packages/common/business_components/src/ui/table/index.tsx @@ -49,12 +49,6 @@ export function UiTable({ tableData, headlist, pageSize, total, headName, childr } }, [resetSelection]); - // 테이블 데이터가 변경될 때마다 선택된 행 초기화하는 useEffect 추가 - useEffect(() => { - // 새로운 데이터가 로드되면 선택 상태 초기화 - setIdx(-1); - }, [tableData]); - useEffect(() => { if (headerRef.current) { setHeaderHeight(headerRef.current.offsetHeight-5); diff --git a/packages/common/components/src/api/menu.ts b/packages/common/components/src/api/menu.ts index bd8fe1599..8d58a3499 100644 --- a/packages/common/components/src/api/menu.ts +++ b/packages/common/components/src/api/menu.ts @@ -21,6 +21,10 @@ export interface MenuItem { requiredUrlPath: boolean; } +export interface TreeMenu extends MenuItem { + menuHlpCn: string; +} + const client = getApiClient(); export const getMenuList = async (siteId: string) => { @@ -29,3 +33,10 @@ export const getMenuList = async (siteId: string) => { ); return response.data; }; + +export const getPreviewTreeMenuList = async (siteId: string) => { + const response = await client.get( + `${ENDPOINT.CMS_SERVICE.MENUS}/${siteId}/tree/preview`, + ); + return response.data; +}; diff --git a/packages/common/components/src/config/api.ts b/packages/common/components/src/config/api.ts index 12efdd8bd..0ead6b0bc 100644 --- a/packages/common/components/src/config/api.ts +++ b/packages/common/components/src/config/api.ts @@ -1,5 +1,6 @@ export const ENDPOINT = { CMS_SERVICE: { + MENUS: "/cms-service/api/v1/menus", MENU_ROLES: "/cms-service/api/v1/menu-roles", SITES: "/cms-service/api/v1/sites", POPUPS: "/cms-service/api/v1/popups", diff --git a/packages/common/components/src/ui/date-picker/index.tsx b/packages/common/components/src/ui/date-picker/index.tsx index ee5d37872..919e22435 100644 --- a/packages/common/components/src/ui/date-picker/index.tsx +++ b/packages/common/components/src/ui/date-picker/index.tsx @@ -2,7 +2,7 @@ import "./date-picker.css"; import { format } from "date-fns"; import { CalendarIcon } from "lucide-react"; -import type { DayPickerSingleProps } from "react-day-picker"; +import type { DayPicker } from "react-day-picker"; import { cn } from "../../lib/utils"; import { Button } from "../button"; @@ -12,7 +12,8 @@ import { Popover, PopoverContent, PopoverTrigger } from "../popover"; type DatePickerProps = { placeholder?: string; disabled?: boolean; -} & DayPickerSingleProps; + selected?: Date; +} & React.ComponentProps; export function DatePicker({ className, @@ -37,7 +38,7 @@ export function DatePicker({ - + ); diff --git a/packages/common/components/src/ui/index.ts b/packages/common/components/src/ui/index.ts index 8839d2298..75231add8 100644 --- a/packages/common/components/src/ui/index.ts +++ b/packages/common/components/src/ui/index.ts @@ -15,6 +15,7 @@ export * from "./icon-finder"; export * from "./input"; export * from "./label"; export * from "./layout"; +export * from "./lnb"; export * from "./loading"; export * from "./page-title"; export * from "./popover"; diff --git a/packages/common/components/src/ui/lnb/index.tsx b/packages/common/components/src/ui/lnb/index.tsx index 552a7d67a..650fd2474 100644 --- a/packages/common/components/src/ui/lnb/index.tsx +++ b/packages/common/components/src/ui/lnb/index.tsx @@ -3,9 +3,7 @@ import { useState, useEffect, useRef } from "react"; import { useQuery } from "@tanstack/react-query"; import { ChevronRight } from "lucide-react"; -import { ENDPOINT } from "../../config"; -import { cn, setCookie } from "../../lib"; -import { getMenuList, type MenuItem } from "../../api"; +import { getParentIds } from "./lib"; import { Sidebar, SidebarContent, @@ -22,29 +20,47 @@ import { CollapsibleContent, CollapsibleTrigger, } from "../collapsible"; -import { getParentIds } from "./lib"; -import { getCookie } from "../../lib"; - -const siteId = getCookie("site-id-key") ?? ""; +import { ENDPOINT } from "../../config"; +import { cn, getCookie, setCookie } from "../../lib"; +import { getMenuList, getPreviewTreeMenuList, type MenuItem } from "../../api"; export function LNB({ viewOnly, currentPath, + propSiteId, + previewMode, + classNames, handleMenuClick, }: { viewOnly?: boolean; currentPath?: string; + propSiteId?: string; + previewMode?: boolean; + classNames?: { + wrapper?: string; + }; handleMenuClick?: (item: MenuItem) => void; }) { - const { data: menuList } = useQuery({ - queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES], - queryFn: () => getMenuList(siteId), - enabled: !viewOnly, - }); - const [defaultOpenMenuIds, setDefaultOpenMenuIds] = useState([]); const prevPathRef = useRef(currentPath); + const cookieSiteId = getCookie("site-id-key") ?? ""; + const siteId = propSiteId ?? cookieSiteId; + + const { data: menuListData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.MENU_ROLES], + queryFn: () => getMenuList(siteId), + enabled: !viewOnly && !previewMode, + }); + + const { data: previewTreeMenuListData } = useQuery({ + queryKey: [ENDPOINT.CMS_SERVICE.MENUS, siteId, "preview"], + queryFn: () => getPreviewTreeMenuList(siteId), + enabled: previewMode, + }); + + const menuList = previewMode ? previewTreeMenuListData : menuListData; + function isPathMatched(path: string) { if (!path) return false; return currentPath?.startsWith(path); @@ -133,13 +149,22 @@ export function LNB({ } function MenuGroup({ item }: { item: MenuItem }) { - const { open: isSidebarOpen } = useSidebar(); + const { open: isSidebarOpen, setOpen: setSidebarOpen } = useSidebar(); const [isOpen, setIsOpen] = useState( defaultOpenMenuIds.includes(item.menuCd), ); + const handleOpenChange = (open: boolean) => { + setIsOpen(open); + if (!isSidebarOpen) setSidebarOpen(true); + }; + return ( - + diff --git a/packages/common/components/src/ui/table/index.tsx b/packages/common/components/src/ui/table/index.tsx index 8ced24202..3d4e2251d 100644 --- a/packages/common/components/src/ui/table/index.tsx +++ b/packages/common/components/src/ui/table/index.tsx @@ -29,7 +29,11 @@ const TableHeader = React.forwardRef< HTMLTableSectionElement, React.HTMLAttributes >(({ className, ...props }, ref) => ( - + )); TableHeader.displayName = "TableHeader";