diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx index 659aa714d..62feda6dc 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/headList.tsx @@ -45,12 +45,19 @@ export const pbnstDemandHeadListExport: TableUpperProps[] = [ export const pbnstOrgwtHeadListRxport: TableUpperProps[] = [ - { id: "ruseUtztnFcltNm", title: "운영방식" }, + { id: "ruseUtztnFcltNm", title: "운영방식" }, { id: "orgwtWtritQnt", title: "원수취수량" }, { id: "tmsYn", title: "하수처리량TMS 전후", }, { id: "dschgFmYn", title: "하수처리장 방류 유량계 전·후​", }, { id: "dtlPstnExpln", title: "상세위치 설명", }, ]; +export const fcOrgwtsHeadListExport: TableUpperProps[] = [ + { id: "sido", title: "운영방식" }, + { id: "gugun", title: "원수취수량" }, + { id: "bscFctNm", title: "시설명" }, + { id: "addr", title: "상세위치 설명" }, + +] export const pbnstMngNmExport: chHeadType[] = [ { headNm: "upChangeRe", text: "운영대행기간", length: 2 }, @@ -126,4 +133,3 @@ export const ruseWaterQulityList:formDetailType[]=[ ] - diff --git a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx index 29af7285a..6f725870d 100644 --- a/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx +++ b/apps/wr/app/store/ruseFcltMng/fcltReg/pbnstReg/index.tsx @@ -16,6 +16,7 @@ import { pubFacHeadListExport, pplInstlsHeadListExport, pbnstDemandHeadListExport, + fcOrgwtsHeadListExport, } from "./headList"; const selectLabel: SelectDataType[] = [{ text: "test", val: "1" }]; @@ -25,6 +26,8 @@ const pbnstOrgwtHeadList = pbnstOrgwtHeadListRxport; const pbnstMngNm = pbnstMngNmExport; const pplInstlsHeadLisat = pplInstlsHeadListExport; const pbnstDemandHeadList = pbnstDemandHeadListExport; +const fcOrgwtsHeadList=fcOrgwtsHeadListExport + export type pubFacState = { pbnst: { @@ -39,6 +42,7 @@ export type pubFacState = { pbnstOrgwtHeadList: TableUpperProps[]; pplInstlsHeadLisat: TableUpperProps[]; pbnstDemandHeadList: TableUpperProps[]; + fcOrgwtsHeadList: TableUpperProps[]; }; }; type pubFacActions = { @@ -64,6 +68,7 @@ export const pubFacStateExport: pubFacState = { selectLabel: selectLabel, pplInstlsHeadLisat: pplInstlsHeadLisat, pbnstDemandHeadList: pbnstDemandHeadList, + fcOrgwtsHeadList: fcOrgwtsHeadList, }, }; @@ -206,6 +211,17 @@ export const pubFacActionsExport: (set: any) => pubFacActions = (set: any) => { } catch (error) { console.error("Error updating pbnst:", error); } - }, + },fileDelete(atflCd:string){ + try { + const response = postFectch( + `/ratfl/attachments/atflCd/${atflCd}`, + null, + fetchType.COMMON + ); + return response; + + } catch (error) { + } + } }; }; diff --git a/apps/wr/components/lib/useTus_wr/useTusWr.tsx b/apps/wr/components/lib/useTus_wr/useTusWr.tsx index 4aedb71d3..b9441e6a4 100644 --- a/apps/wr/components/lib/useTus_wr/useTusWr.tsx +++ b/apps/wr/components/lib/useTus_wr/useTusWr.tsx @@ -1,53 +1,78 @@ -import { Upload, type HttpRequest, type HttpResponse, type OnSuccessPayload } from "tus-js-client"; +import { + Upload, + 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"; type UploadOptions = { handleUploadStart?: (upload: Upload) => void; handleProgress?: (percentage: string) => void; - handleSuccess?: (payload :OnSuccessPayload) => void; - handleResponse?: (req:HttpRequest, res: HttpResponse) => void; + handleSuccess?: (payload: OnSuccessPayload) => void; + handleResponse?: (req: HttpRequest, res: ReturnFileType) => void; }; +export type ReturnFileType = { + orgnlFileNm: string; + atflFlieSz: number; + atflType: string; + dwnldNocs: number; + delYn: string; + lnkgDmnId: string | null; + lnkgDmnNm: string | null; + regDt: Date | null; + atflCd: String; + atflSn: number; + atflId: String; + physFileNm: String; +}; +export const TusClientUpload = (oFile: FilesType, options?: UploadOptions) => + new Promise((resolve, reject) => { + try { + const Authorization = "Authorization"; + const AUTH_USER_ID = "token-id"; + let fileInfo: string | undefined; + //CS_URL + const uploader = new Upload(oFile.file, { + endpoint: CS_TUS_UPLOAD, + chunkSize: 10 * 1024 * 1024, + headers: { + Authorization: "", + AUTH_USER_ID: "", + }, + metadata: { + filename: oFile.file.name, + filetype: oFile.file.type, + }, + onError(error) { + reject(error); + }, + onProgress(bytesUploaded, bytesTotal) { + const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2); + options?.handleProgress?.(percentage); + }, + onAfterResponse(req, res: HttpResponse) { + fileInfo = res.getHeader("X-File-Info"); + if (fileInfo === undefined || fileInfo === null) return; + }, + onSuccess(payload: OnSuccessPayload) { + options?.handleSuccess?.(payload); + if (fileInfo) { + console.log('fileInfo', fileInfo); + resolve(JSON.parse(fileInfo) as ReturnFileType); + } else reject({} as DetailedError); + }, + }); -export function TusClientUpload(oFile: File, setUpload: (upload: Upload) => void, options?: UploadOptions) { - const Authorization = "Authorization"; - const AUTH_USER_ID = "token-id"; - - //CS_URL - const uploader = new Upload(oFile, { - endpoint: 'http://localhost:3001' + CS_TUS_UPLOAD, - chunkSize: 10* 1024 * 1024, - headers: { - Authorization: "", - AUTH_USER_ID: "", - }, - metadata: { - filename: oFile.name, - filetype: oFile.type, - }, - onError(error) { - console.error(`Failed because: ${error}`); - }, - onProgress(bytesUploaded, bytesTotal) { - const percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2); - options?.handleProgress?.(percentage); - }, - onAfterResponse(req, res) { - const fileInfo = res.getHeader("X-File-Info"); - if (fileInfo === undefined || fileInfo === null) return; - - options?.handleResponse?.(res); - }, - onSuccess(payload :OnSuccessPayload) { - options?.handleSuccess?.(payload); - }, + options?.handleUploadStart?.(uploader); + uploader.start(); + } catch (e) { + console.log(e); + reject(e as DetailedError); + } + // setUpload(uploader); }); - uploader.start(); - - options?.handleUploadStart?.(uploader); - - console.log("upload start >>>>>", uploader); - - - // setUpload(uploader); -} +// // 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 e9ec31965..1743e3b8c 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm.tsx @@ -1,12 +1,16 @@ "use client"; import { SelectBox } from "@common/business_components"; -import { FormUi, type SelectDataType } from "@common/business_components/ui"; +import { + FormUi, + UiModal, + type SelectDataType, +} from "@common/business_components/ui"; import { Form, FormField } from "@common/business_components/ui/form"; import { Button, Input, Label, TableHead, TableRow } from "@common/components"; import { zodResolver } from "@hookform/resolvers/zod"; +import { set, useFieldArray, useForm } from "react-hook-form"; import { use, useEffect, useRef, useState } from "react"; -import { useFieldArray, useForm } from "react-hook-form"; import { z } from "zod"; import { useWrStore } from "@/app/store"; import { @@ -35,6 +39,7 @@ import { type ppInstlType, } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable"; +import FcOrgwtsRegModal from "@/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal"; export function PbnstBuseForm({ data }: { data: fcBizType[] }) { // const ref = useRef(data[0]?.pplInstls ?? null); @@ -47,6 +52,10 @@ export function PbnstBuseForm({ data }: { data: fcBizType[] }) { const [ppiSelectList, setPpiSelectList] = useState<[{ name: string; val: SelectDataType[] }]>(); const [ppiYn, setPpiYn] = useState("Y"); +const [ isFcOrgwts, setIsFcOrgwts] = useState(false); + + + const form = useForm({ resolver: zodResolver(fcBizSchema), }); @@ -66,6 +75,8 @@ export function PbnstBuseForm({ data }: { data: fcBizType[] }) { name: "pplInstls", }); + + const plusHist = () => { append({ choose: false, @@ -140,7 +151,7 @@ export function PbnstBuseForm({ data }: { data: fcBizType[] }) { }} > - + 재이용 원수취수 현황
- +
+ + setIsFcOrgwts(open)} + bodyClass={"w-[68vw] max-w-none h-[60vh]"} + body={} + > ); } 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 4ffae932d..6f0a1ac02 100644 --- a/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx +++ b/apps/wr/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm.tsx @@ -9,42 +9,51 @@ import { useEffect, useRef, useState } from "react"; import { useFieldArray, useForm } from "react-hook-form"; import { z } from "zod"; -import { pbnstRegZod, type customPbnst, type operType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; import { commonButonSize, formH1Class, - formTableName + formTableName, } from "@/components/lib/class/comClass"; import { TusClientUpload } from "@/components/lib/useTus_wr/useTusWr"; import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable"; import type { Upload } from "tus-js-client"; +import { + pbnstRegZod, + type customPbnst, + type operType, + type ruseFcltType, +} from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type"; +export type FilesType = { + atflCd: String; + file: File; +}; export function PbnstMngForm({ data }: { data: customPbnst }) { - const { pbnst ,pbnstUpdate} = useWrStore((state) => state); - const { pbnstMngUpHeadList} = pbnst; + const { pbnst, pbnstUpdate } = useWrStore((state) => state); + const { pbnstMngUpHeadList } = pbnst; const [ruseOperData, setRuseOperData] = useState(); const [planFiles, setPlanFiles] = useState(null); - const [relationfiles, setRelationFiles] = useState(null); - + const [relationfiles, setRelationFiles] = useState(null); const [isModalOpen, setIsModalOpen] = useState(false); const [upload, setUpload] = useState(null); const [progress, setProgress] = useState(0); const handleProgress = (percentage: string) => { - setProgress(Number(percentage)); }; - - const ref = useRef(data?.fcOpers ?? null); const form = useForm>({ resolver: zodResolver(pbnstRegZod), defaultValues: pbnstRegZod.parse({}), }); - - const { fields: fcOpersField, append, remove } = useFieldArray({ + + const { + fields: fcOpersField, + append, + remove, + } = useFieldArray({ control: form.control, name: "fcOpers", }); @@ -64,63 +73,95 @@ export function PbnstMngForm({ data }: { data: customPbnst }) { }; const removeSelected = () => { - console.log("ref", ref.current); - console.log("fcOpersField", fcOpersField); - if(!ref.current) return; + if (!ref.current) return; const selectedIdxs = ref.current - .map((item, idx) => (item.choose ? idx : -1)) - .filter(idx => idx !== -1); - selectedIdxs.reverse().forEach(idx => remove(idx)); + .map((item, idx) => (item.choose ? idx : -1)) + .filter((idx) => idx !== -1); + selectedIdxs.reverse().forEach((idx) => remove(idx)); }; const onSelectValue = (val: string) => {}; useEffect(() => { + if (!data) return; form.reset(data); setRuseOperData(data.fcOpers); }, [data]); // 2. Define a submit handler. function onSubmit(values: z.infer) { + console.log("submit", values); + // pbnstUpdate(values); values.fcOpers = ref.current || []; console.log("form values:", values); pbnstUpdate(values); } + const fileHandler = (files: File[]) => { + console.log('fileHandler', files); + let setReFiles = [...(relationfiles || [])]; + if (files && (!relationfiles || relationfiles.length < files.length)) { + files.find((item) => { + if ( + !relationfiles || + relationfiles?.findIndex((reFile) => reFile.file === item) < 0 + ) { + TusClientUpload({ atflCd: "", file: item }) + .then((tusFile) => { + setReFiles.push({ atflCd: tusFile.atflCd, file: item }); + console.log("after async setReFiles", setReFiles); + setRelationFiles(setReFiles); + }) + .catch((e) => { + console.log(e); + }); + return item; + } + }); + } else if ( + relationfiles && + (!files || relationfiles.length > files.length) + ) { + if (!files) { + //TODO: 파일삭제 + setReFiles = []; + setReFiles.length = 0; + } else { + //TODO: 파일삭제 + relationfiles?.forEach((item, index) => { + const idx = files?.indexOf(item.file); + if (idx < 0) { + setReFiles.slice(index); + } + }); + } + setRelationFiles(setReFiles) + } + }; + + useEffect(() => { + console.log("relationfiles changed:", relationfiles); + }, [relationfiles]); const testFile = () => { - if (relationfiles && relationfiles[0]) - TusClientUpload(relationfiles[0], setUpload, { - handleUploadStart: () => { - console.log("handleUploadStart"); - }, - handleProgress, - handleResponse: (req, res) => { - console.log("handleResponse req", req); - console.log("handleResponse res", res); - }, - handleSuccess: (a) => { - console.log("req", a); - - }, - }); + // if (relationfiles && relationfiles[0]) + // TusClientUpload(relationfiles[0], setUpload, { + // handleUploadStart: () => { + // console.log("handleUploadStart"); + // }, + // handleProgress, + // handleResponse: (req, res) => { + // console.log("handleResponse req", req); + // console.log("handleResponse res", res); + // }, + // handleSuccess: (a) => { + // console.log("req", a); + // }, + // }); }; useEffect(() => { console.log("form errors:", form.formState.errors); }, [form.formState.errors]); - useEffect(() => { - if (relationfiles && relationfiles[0]) - console.log("relationfiles ", relationfiles[0]); - - // TusClientUpload( - // relationfiles[0],{ - // handleUploadStart: setUpload, - // handleProgress, - // handleSuccess: setUpload, - // }) - }, [relationfiles]); - - return (
@@ -131,11 +172,16 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {

재이용 시설명

- {form.getValues("ruseUtztnFcltNm") ? ": " + form.getValues("ruseUtztnFcltNm") : ""} + + {form.getValues("ruseUtztnFcltNm") + ? ": " + form.getValues("ruseUtztnFcltNm") + : ""} +
- - +
@@ -143,22 +189,22 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
재이용시설 운영정보
- - + +
( - + )} /> @@ -189,7 +240,12 @@ export function PbnstMngForm({ data }: { data: customPbnst }) { name="hasuhasu" render={({ field }) => ( - + )} /> @@ -200,7 +256,12 @@ export function PbnstMngForm({ data }: { data: customPbnst }) { name="ruseCpct" render={({ field }) => ( - + )} /> @@ -211,7 +272,12 @@ export function PbnstMngForm({ data }: { data: customPbnst }) { name="splyExtraCpct" render={({ field }) => ( - + )} /> @@ -228,8 +294,10 @@ export function PbnstMngForm({ data }: { data: customPbnst }) { render={({}) => ( item.file) || []} + setFiles={(files: File[] | null) => { + if (files) fileHandler(files); + }} fileTypes="PDF" > diff --git a/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx new file mode 100644 index 000000000..dc4144073 --- /dev/null +++ b/apps/wr/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal.tsx @@ -0,0 +1,64 @@ +"use client"; +import { useWrStore } from "@/app/store"; +import { Title, UiTable } from "@common/business_components/ui"; +import { ArrowLeft, ArrowRight } from "lucide-react"; +import { useEffect, useState } from "react"; + +export default function FcOrgwtsRegModal() { + const { code, pbnst } = useWrStore((state) => state); + const { fcOrgwtsHeadList } = pbnst; + + const [isFcOrgwtsData, setIsFcOrgwtsData] = useState(false); + + useEffect(() => { + console.log("isFcOrgwtsData", isFcOrgwtsData); + }, [isFcOrgwtsData]); + return ( + <> +
+
+ + </div> + <div className="flex flex-row flex-grow gap-4 mt-4"> + <div className="w-3/7"> + <UiTable + headName={"공공하수처리시설 목록"} + tableData={[]} + headlist={fcOrgwtsHeadList} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + ></UiTable> + </div> + <div className="flex flex-col items-center justify-center w-1/7 gap-2"> + <ArrowRight + type="button" + onClick={() => { + setIsFcOrgwtsData(!isFcOrgwtsData); + }} + className="w-12 h-12 text-gray-500" + /> + <ArrowLeft className="w-12 h-12 text-gray-500" /> + </div> + {/* Right Table container: Takes 2/5 of the width */} + <div className="w-3/7"> + <UiTable + headName={"취수하수처리장 목록"} + tableData={[]} + headlist={fcOrgwtsHeadList} + pageSize={0} + total={0} + cellClick={undefined} + onPageChange={function (page: number): void { + throw new Error("Function not implemented."); + }} + ></UiTable> + </div> + </div> + </div> + </> + ); +} diff --git a/apps/wr/middleware.ts b/apps/wr/middleware.ts index 3ac0d64ed..fdd0a3c9c 100644 --- a/apps/wr/middleware.ts +++ b/apps/wr/middleware.ts @@ -21,16 +21,18 @@ export function middleware(req: NextRequest) { if (pathname.startsWith("/attach-service")) { const requestHeaders = new Headers(req.headers); - const token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhMGVjN2EwNy03NTJhLTRmN2YtODlhNi04NTRlNjNkMmUzYTAiLCJpYXQiOjE3NDc4MTM2MDksImV4cCI6MTc0NzgxMzkwOX0.XGiDHC-ljuEdN6M638q0nDet6XRQcO8o66LKvZZ07r4rGykn2ba8yagC_-8LVpVjrkPzIVZnW10I2fQWgAGT5Q" - const userId = 'a0ec7a07-752a-4f7f-89a6-854e63d2e3a0'; + const token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhMGVjN2EwNy03NTJhLTRmN2YtODlhNi04NTRlNjNkMmUzYTAiLCJhdXRob3JpdGllcyI6IlJPTEVfQURNSU4sUk9MRV9BTk9OWU1PVVMiLCJleHAiOjE3NDgzOTk3ODl9.wbYXSIFNSvVJKyofFW0C3Yg99AZ99oLYSCMjcoRvZB6DqfxCbqxHPxUgwWyFE6oHJWYrX6q4BvMY2TdVOtzxnA" + const userId = 'a0ec7a07-752a-4f7f-89a6-854e63d2e3a0' //const token = req.cookies.get(CLAIM_NAME)?.value; //const userId = req.cookies.get(AUTH_USER_ID)?.value; const newUrl = `${serverApiUrl}${pathname}`; console.log("serverApiUrl ", serverApiUrl); console.log("pathname ", pathname); + //wr:dev: pathname /attach-service/api/v1/tus/upload/5e60b70a-956e-40c3-be5a-cdd3100bf8ad + //http://dev.onasys.co.kr:8000/attach-service/api/v1/tus/upload/5e60b70a-956e-40c3-be5a-cdd3100bf8ad if (token) requestHeaders.set(CLAIM_NAME, token); if (userId) requestHeaders.set(AUTH_USER_ID, userId); @@ -48,3 +50,4 @@ export function middleware(req: NextRequest) { export const config = { matcher: ["/server/:path*", "/attach-service/:path*"], }; + diff --git a/packages/common/business_components/src/ui/file-upload/index.tsx b/packages/common/business_components/src/ui/file-upload/index.tsx index a78965954..1c70b99af 100644 --- a/packages/common/business_components/src/ui/file-upload/index.tsx +++ b/packages/common/business_components/src/ui/file-upload/index.tsx @@ -45,7 +45,7 @@ export const FileUpload = files.map((file:File, i:number) => ( <FileUploaderItem key={i} index={i}> <Paperclip className="h-4 w-4 stroke-current" /> - <span>{file.name}</span> + <span className="w-4/5 overflow-hidden">{file.name}</span> </FileUploaderItem> ))} </FileUploaderContent> diff --git a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx index 3db4bcceb..c18c3740d 100644 --- a/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx +++ b/packages/common/business_components/src/ui/file-upload/lib/file_upload.tsx @@ -271,7 +271,7 @@ export const FileUploaderContent = forwardRef< {...props} ref={ref} className={cn( - "flex rounded-xl gap-1", + "w-full flex rounded-xl gap-1", orientation === "horizontal" ? "flex-raw flex-wrap" : "flex-col", className, )} @@ -295,22 +295,25 @@ export const FileUploaderItem = forwardRef< ref={ref} className={cn( buttonVariants({ variant: "ghost" }), - "h-6 p-1 justify-between cursor-pointer relative", + "h-6 p-1 justify-between cursor-pointer relative w-full", className, isSelected ? "bg-muted" : "", )} {...props} + onClick={() =>{ + console.log('onclick'); + removeFileFromSet(index)}} > - <div className="font-medium leading-none tracking-tight flex items-center gap-1.5 h-full w-full"> + <div className="font-medium leading-none tracking-tight flex items-center gap-1.5 h-full !w-4/5 overflow-hidden "> {children} </div> <button type="button" className={cn( "absolute", + "!w-1/5 z-50", direction === "rtl" ? "top-1 left-1" : "top-1 right-1", )} - onClick={() => removeFileFromSet(index)} > <span className="sr-only">remove item {index}</span> <RemoveIcon className="w-4 h-4 hover:stroke-destructive duration-200 ease-in-out" />