Merge commit '66df8b21b3939af172a66f8a562faad2dadbca49' into iipbs/wr/hasuReg

This commit is contained in:
leedj312
2025-05-28 09:14:41 +09:00
9 changed files with 292 additions and 84 deletions
@@ -6,6 +6,7 @@ import {
SearchFormLeft,
SearchInput,
Title,
UiModal,
UiTable,
} from "@common/business_components";
import { Button, Input } from "@common/components";
@@ -18,6 +19,7 @@ import type { customPbnst, fcBizSchema, fcBizType, ruseFcltType } from "@/app/st
import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm";
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
import { z } from "zod";
import { PbnstRegModal } from "@/components/ui/modal/fcltReg/pbnstRegModal/pbnstRegModal";
export default function PublicReuseFaciltyInsert() {
const { code, pbnst, pubHasuInit,pbnstRegInit } = useWrStore((state) => state);
@@ -25,6 +27,7 @@ export default function PublicReuseFaciltyInsert() {
const [currentTab, setCurrentTab] = useState<string>("mng");
const [fcltMng, setFcltMng] = useState<ruseFcltType[]>();
const [pbnstBiz, setPbnstBiz] = useState<fcBizType[]>();
const [issNewReg, setIsNewReg] = useState<boolean>(false);
const [searchTxt, setSearchTxt] = useState<string>();
const [bdstTable, setbdstTable] = useState<customPbnst[]>();
@@ -96,7 +99,7 @@ useEffect(() => {
<Button
size={"sm"}
className=""
onClick={() =>{}}
onClick={() => setIsNewReg(!issNewReg) }
>
신규등록
</Button>
@@ -137,6 +140,14 @@ useEffect(() => {
</Tabs>
</ScrollArea>
</ListDiv>
<UiModal
body={<PbnstRegModal></PbnstRegModal>}
bodyClass="w-[68vw] max-w-none h-[90vh]"
open={issNewReg}
onOpenChange={(open) => {
setIsNewReg(open);
}}
/>
</div>
</ContentsDiv>
</>
@@ -17,6 +17,7 @@ export const pubFacHeadListExport: TableUpperProps[] = [
];
export const pbnstMngUpHeadListExport: TableUpperProps[] = [
{ id: "choose", title: "선택", type: "checkbox" },
{ id: "operMthd", title: "운영방식", edit: true},
{ id: "rprtvBzenty", title: "대행업체", edit: true},
{ id: "bgngDt", title: "시작일", upName: "upChangeRe", upSequnce: 1, type: "date"},
@@ -25,9 +26,10 @@ export const pbnstMngUpHeadListExport: TableUpperProps[] = [
export const pplInstlsHeadListExport: TableUpperProps[] = [
{ id: "choose", title: "선택", type: "checkbox" },
{ id: "ppMqlt", title: "관재질", type: "select", selectData:'pplQulity' },
{ id: "pdmt", title: "관경", type: "select", selectData:'pplLenght'},
{ id: "cpct", title: "연장", },
{ id: "cpct", title: "연장", edit: true, type: "number" },
];
@@ -73,6 +73,7 @@ const fcOperSchema = z.object({
rgtr: z.string(),
mdfcnDt: z.date().nullish(),
mdfr: z.string().default("test"),
choose: z.boolean().default(false),
});
const fcOrgwtSchema = z.object({
@@ -289,15 +290,15 @@ export const exampleData = {
pplInstls: [
{
ruseFcltBizFk: "10",
pdmt: "관경",
ppMqlt: "1",
cpct: "100",
pdmt: "D200",
ppMqlt: "도복장강관",
cpct: "1",
},
{
ruseFcltBizFk: "10",
pdmt: "관경",
ppMqlt: "2",
cpct: "200",
pdmt: "D100",
ppMqlt: "PE관",
cpct: "2",
},
],
fcOrgwts: [
@@ -15,7 +15,8 @@ import {
SelectBox,
type SelectDataType,
} from "@common/business_components";
import { Button, Input } from "@common/components";
import { Button, Checkbox, Input } from "@common/components";
import { Check } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useFieldArray } from "react-hook-form";
@@ -42,18 +43,15 @@ export default function BdstReg({ form }: { form: any }) {
// remove(fields.length - 1);
// }
// };
// 이건 삭제해도되는거
const removeSelected = () => {
// fields 배열에서 selectedIds 에 포함된 field.id 의 인덱스만 골라내기
const idxsToRemove = fields
.map((f, i) => selectedIds.includes(f.id) ? i : -1)
.filter(i => i > -1)
// 내림차순 정렬: 인덱스 뒤쪽부터 제거해야 안전합니다.
.sort((a,b) => b - a);
.map((item, idx) => selectedIds.includes(item.id) ? idx : -1)
.filter(index => index > -1)
.sort((prevIndex, nextIndex) => nextIndex - prevIndex);
remove(idxsToRemove);
setSelectedIds([]);
};
remove(idxsToRemove);
setSelectedIds([]);
};
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | undefined>();
@@ -89,9 +87,6 @@ export default function BdstReg({ form }: { form: any }) {
return () => subscription?.unsubscribe();
}, [form.form]);
// 여기서부터는 자유롭게 삭제 가능
const [selectedIds, setSelectedIds] = useState<string[]>([]);
const toggleSelect = (id: string) => {
@@ -280,19 +275,13 @@ export default function BdstReg({ form }: { form: any }) {
</Button>
</div>
{fields.map((field, index) => (
//여기서부터 자유롭게 삭제 가능
<div key={field.id} className="grid grid-cols-[auto,1fr,1fr,1fr] gap-2 mt-4 items-center">
{/* 1) 체크박스 */}
<div className="col-span-1 flex justify-center mr-4">
<input
type="checkbox"
<Checkbox
checked={selectedIds.includes(field.id)}
onChange={() => toggleSelect(field.id)}
className="h-6 w-6"
onCheckedChange={() => toggleSelect(field.id)}
/>
</div>
{/* 2) 구분 */}
<div className="">
<FormField
control={form.control}
@@ -308,8 +297,6 @@ export default function BdstReg({ form }: { form: any }) {
)}
/>
</div>
{/* 3) 허가일 */}
<div className="">
<FormField
control={form.control}
@@ -328,8 +315,6 @@ export default function BdstReg({ form }: { form: any }) {
)}
/>
</div>
{/* 4) 면적 */}
<div className="">
<FormField
control={form.control}
@@ -9,8 +9,8 @@ import {
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 { use, useEffect, useState } from "react";
import { set, useFieldArray, useForm } from "react-hook-form";
import { use, useEffect, useRef, useState } from "react";
import { z } from "zod";
import { useWrStore } from "@/app/store";
import {
@@ -42,6 +42,10 @@ import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTab
import FcOrgwtsRegModal from "@/components/ui/modal/fcltReg/fcOrgwtsRegModal/fcOrgwtsRegModal";
export function PbnstBuseForm({ data }: { data: fcBizType[] }) {
// const ref = useRef<ppInstlType[] | null>(data[0]?.pplInstls ?? null);
const ref = useRef<ppInstlType[] | null>(
Array.isArray(data) && data.length > 0 ? data[0]?.pplInstls ?? null : null
);
const { code, pbnst } = useWrStore((state) => state);
const { pbnstBizCycle, pbnstRes } = pbnst;
const [getBizCycle, setBizCycle] = useState("1");
@@ -66,27 +70,38 @@ const [ isFcOrgwts, setIsFcOrgwts] = useState<boolean>(false);
name: "fcOrgwts",
});
const { fields: pplInstls } = useFieldArray({
const { fields: pplInstls, append, remove } = useFieldArray({
control: form.control,
name: "pplInstls",
});
const fcOrgwtsReg = () =>{
const plusHist = () => {
append({
choose: false,
ppMqlt: "",
pdmt: "",
cpct: "",
});
};
console.log("fcOrgwtsReg");
//ref로바꿔야함
setFcOrgwts({isOpen:true , data:fcOrgwtFiled as fcOrgwtType[]});
}
const removeSelected = () => {
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));
};
useEffect(() => {
if (data) {
const index = Number(getBizCycle) - 1;
form.reset(data[index]);
ref.current = data[index]?.pplInstls ?? null;
console.log("form reset with data:", data[index]);
}
}, [getBizCycle, data]);
@@ -202,10 +217,22 @@ const [ isFcOrgwts, setIsFcOrgwts] = useState<boolean>(false);
readOnly
className="w-32 border-gray-300 rounded pr-8 "
/>
<Button className="ml-7" size={commonButonSize}>
추가등록
</Button>
<Button size={commonButonSize}>삭제</Button>
<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>
@@ -213,7 +240,8 @@ const [ isFcOrgwts, setIsFcOrgwts] = useState<boolean>(false);
tableData={pplInstls}
headList={pbnst.pplInstlsHeadLisat}
code={ppiSelectList ?? []}
/>
ref={ref}
upHeadList={[]} />
</div>
<MngRegFormDetail
@@ -1,27 +1,21 @@
"use client";
import { SelectBox } from "@common/business_components";
import { FileUpload, FormUi, UiTable } from "@common/business_components/ui";
import { Form, FormField } from "@common/business_components/ui/form";
import { Button, Input, TableHead, TableRow } from "@common/components";
import { zodResolver } from "@hookform/resolvers/zod";
import { use, useEffect, useRef, useState } from "react";
import { set, useFieldArray, useForm } from "react-hook-form";
import { nullable, z } from "zod";
import { useWrStore } from "@/app/store";
import {
selectClass,
type TableUpperProps,
} from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { FileUpload, FormUi } from "@common/business_components/ui";
import { Form, FormField } from "@common/business_components/ui/form";
import { Button, Input } from "@common/components";
import { zodResolver } from "@hookform/resolvers/zod";
import { useEffect, useRef, useState } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { z } from "zod";
import {
commonButonSize,
formH1Class,
formH2Class,
formTableName,
formTableName
} from "@/components/lib/class/comClass";
import RuseMngTable from "@/components/ui/table/pbnstReg/ruseMngTable/ruseMngTable";
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,
@@ -33,6 +27,7 @@ export type FilesType = {
atflCd: String;
file: File;
};
export function PbnstMngForm({ data }: { data: customPbnst }) {
const { pbnst, pbnstUpdate } = useWrStore((state) => state);
const { pbnstMngUpHeadList } = pbnst;
@@ -48,17 +43,42 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
setProgress(Number(percentage));
};
const ref = useRef<operType[] | null>(data.fcOpers ?? null);
const ref = useRef<operType[] | null>(data?.fcOpers ?? null);
const form = useForm<z.infer<typeof pbnstRegZod>>({
resolver: zodResolver(pbnstRegZod),
defaultValues: pbnstRegZod.parse({}),
});
const { fields: fcOpersField } = useFieldArray({
const { fields: fcOpersField, append, remove } = useFieldArray({
control: form.control,
name: "fcOpers",
});
const plusHist = () => {
append({
choose: false,
rgtr: "",
mdfr: "",
pbnstRuseFcltFk: 0,
pbnstRuseFcltOperInfoPk: 0,
operMthd: "",
rprtvBzenty: "",
bgngDt: new Date(),
endDt: new Date(),
});
};
const removeSelected = () => {
console.log("ref", ref.current);
console.log("fcOpersField", fcOpersField);
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));
};
const onSelectValue = (val: string) => {};
useEffect(() => {
@@ -71,6 +91,9 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
console.log("submit", values);
testFile;
// pbnstUpdate(values);
values.fcOpers = ref.current || [];
console.log("form values:", values);
pbnstUpdate(values);
}
const fileHandler = (files:File[]) => {
const setReFiles = [...(relationfiles || [])];
@@ -105,8 +128,21 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
setRelationFiles(setReFiles);
};
const testFile = () => {
if (relationfiles && relationfiles[0])
TusClientUpload(relationfiles[0], setUpload);
// 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);
@@ -132,20 +168,31 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
<Button type="submit" size={commonButonSize}>
저장
</Button>
</div>
<div>
<div className="h-[200px] overflow-y-auto">
<div className="h-[200px] overflow-y-auto">
<div className="flex justify-between items-center mx-3 mb-3">
<span className={formTableName}>재이용시설 운영정보</span>
<div>
<Button
type="button"
size={commonButonSize}
className="!text-xl"
onClick={() => testFile()}
onClick={plusHist}
>
추가등록
</Button>
<Button
type="button"
size={commonButonSize}
className="!text-xl !bg-red-500 !text-white ml-1"
onClick={removeSelected}
>
삭제
</Button>
</div>
</div>
<RuseMngTable
tableData={fcOpersField}
@@ -158,7 +205,7 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
<div>
<h1 className={formH1Class}>재이용수 공급 가능량</h1>
<div className="grid grid-cols-12 gap-4">
<div className="col-span-3">
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="fcltCpct"
@@ -174,7 +221,7 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
)}
/>
</div>
<div className="col-span-3">
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="hasuhasu"
@@ -190,7 +237,7 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
)}
/>
</div>
<div className="col-span-3">
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="ruseCpct"
@@ -206,7 +253,7 @@ export function PbnstMngForm({ data }: { data: customPbnst }) {
)}
/>
</div>
<div className="col-span-3">
<div className="col-span-3 mt-4">
<FormField
control={form.control}
name="splyExtraCpct"
@@ -42,7 +42,7 @@ export default function MngRegFormDetail({
onSelect={(date: Date | undefined) =>
field.onChange(date)
}
className={"rounded-lg w-full"}
className={"rounded-lg !w-full"}
/>
) : item.type === "number" ? (
<Input placeholder="" type="number" value={field.value??0} onChange={field.onChange} />
@@ -0,0 +1,121 @@
"use client";
import { useWrStore } from "@/app/store";
import type { customPbnst, fcBizType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { selectClass } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { getCity } from "@/components/lib/func/commom";
import { PbnstMngForm } from "@/components/ui/form/fcltReg/pbnstReg/mngReg/mngRegForm";
import { ScrollArea, SelectBox, UiTable, type SelectDataType } from "@common/business_components";
import { Button, Input, Label, Tabs, TabsContent, TabsList, TabsTrigger } from "@common/components/ui";
import { useState } from "react";
import type { objSearchType } from "../bdstRegModal/bdstRegModal";
import { PbnstBuseForm } from "@/components/ui/form/fcltReg/pbnstReg/buseReg/bugRegForm";
export function PbnstRegModal() {
const {code, pbnst} = useWrStore((state) => {
return state;
});
const { pubFacHeadList, pbnstHasuRes, pbnstRes } = pbnst;
const [selectSgg, setSelectSgg] = useState<SelectDataType[] | []>()
const [objSearch, setObjSearch] = useState<objSearchType>({sgg:"",city:""});
const [searchTxt, setSearchTxt] = useState<string>()
const [bdstTable, setbdstTable] = useState<customPbnst[]>();
const [selectBdst, setSelectBdst] = useState<customPbnst | null>(null);
const [pbnstBiz, setPbnstBiz] = useState<fcBizType[]>();
const [pbnstBdstForm, setPbnstBdstForm] = useState<customPbnst>({} as customPbnst);
const [currentTab, setCurrentTab] = useState<string>("mng");
// const nodeList = headMakeColSpan(pubFacHeadList.moUpHeadList);
const getSelCity = (val: string | number) => {
const cityValue = String(val);
const data = getCity(cityValue, code.sggCd);
setSelectSgg(data);
setObjSearch({ city: cityValue, sgg: '' });
};
const getSgg = (val: string | number) => {
console.log(val);
setObjSearch({...objSearch,sgg: String(val)})
};
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 handleTabChange = (value: string) => {
setCurrentTab(value);
};
return (
<>
<div className="grid grid-cols-12 gap-4 mt-4 items-center">
<SelectBox
className="col-span-3 h-full"
label={"시도"}
selectClass={selectClass}
selectArray={code.cityCd || []}
onSelectValue={getSelCity}
>
{""}
</SelectBox>
<SelectBox
className="col-span-3 h-full"
label={"시군구"}
selectClass={selectClass}
selectArray={selectSgg || []}
onSelectValue={getSgg}
>
{" "}
</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={()=>{}}/>
<Button className="" size={"sm"} onClick={()=>{}}>조회</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">공공 하수처리시설 목록</h1>
<ScrollArea className="h-[30vh]">
<div>
<UiTable
tableData={bdstTable || []}
headlist={pbnst.pubFacHeadList}
pageSize={-10}
total={-1}
headName={undefined}
cellClick={(idx, headId) => (tableClick(idx, headId || ""))}
onPageChange={function (page: number): void {
throw new Error("Function not implemented.");
}}>
{/* {nodeList} */}
</UiTable>
</div>
</ScrollArea>
<div className="border-t border-gray-300 my-4"></div>
<ScrollArea className="h-[40vh]">
<Tabs defaultValue="mng" onValueChange={handleTabChange}>
<TabsList className="">
<TabsTrigger className="!text-xl" value="mng">시설정보</TabsTrigger>
<TabsTrigger className="!text-xl" value="buse">차수별정보</TabsTrigger>
</TabsList>
<TabsContent className="max-h-full" value="mng">
<PbnstMngForm mngForm={pbnstBdstForm as customPbnst} isModal={true} />
</TabsContent>
<TabsContent className="max-h-full" value="buse">
<PbnstBuseForm buseForm={pbnstBdstForm as customPbnst} isModal={true} />
</TabsContent>
</Tabs>
<div>
</div>
</ScrollArea>
</div>
</>
)
}
@@ -1,9 +1,9 @@
import { headMakeprfmnc } from "@/app/ruseFcltMng/prfmncReg/chkgdnReg/TableHead";
import type { chHeadType } from "@/app/store/prfmncReg/chkgdnReg/rainChkgdn/headList";
import type { customPbnst, fcltOperInfoType, fcOrgwtType, operType, ppInstlType } from "@/app/store/ruseFcltMng/fcltReg/pbnstReg/type";
import { selectClass, type TableUpperProps } from "@/app/store/ruseFcltMng/fcltReg/rainReg";
import { DatePicker, SelectBox, type SelectDataType } from "@common/business_components/ui";
import {
Checkbox,
Input,
Table,
TableBody,
@@ -12,7 +12,6 @@ import {
TableHeader,
TableRow,
} from "@common/components/ui";
import moment from "moment";
import React, { useEffect, useState } from "react";
type RuseMngTableProps = {
@@ -31,6 +30,7 @@ const RuseMngTable = React.forwardRef<any[], RuseMngTableProps>(
}, ref) => {
const [tableState, setTableState] = useState([...tableData]);
useEffect(() => {
console.log("tableState", tableState);
if (ref && typeof ref === "object" && "current" in ref) {
ref.current = tableState;
}
@@ -71,11 +71,11 @@ const RuseMngTable = React.forwardRef<any[], RuseMngTableProps>(
type={head.type}
onChange={(txt) => {
setTableState(prev => {
const next = [...prev];
next[i] = { ...next[i], [head.id]: txt.target.value };
return next;
})
}}
const next = [...prev];
next[i] = { ...next[i], [head.id]: txt.target.value };
return next;
})
}}
value={tableState[i][head.id] || ""}
/>
) : head.type === "select" ? (
@@ -83,7 +83,7 @@ const RuseMngTable = React.forwardRef<any[], RuseMngTableProps>(
label=""
selectArray={code.find(item => item.name === head.selectData)?.val ?? []}
value={
item[head.id]
tableState[i][head.id] || ""
}
className={""}
selectClass={selectClass}
@@ -99,18 +99,31 @@ const RuseMngTable = React.forwardRef<any[], RuseMngTableProps>(
mode="single"
field={{
value:
tableState[i][head.id], // Provide a default Date value
tableState[i][head.id], // Provide a default Date value
onChange: (date) => {
setTableState(prev => {
const next = [...prev];
next[i] = { ...next[i], [head.id]: date };
return next;
})
}
}
}
}
selectClass={"w-full"}
/>
) : head.type === "checkbox" ? (
<Checkbox
className=""
checked={!!tableState[i][head.id]}
onCheckedChange={(checked) => {
console.log("checked", checked);
setTableState((prev) => {
prev[i][head.id] = checked
return [...prev]
})
}}
>
</Checkbox>
) : (
`${item[head.id] || ""}`
)}