Merge branch 'iipbs/sn/dev'
This commit is contained in:
@@ -58,7 +58,7 @@ export default function MyForm() {
|
||||
dataList={demandCompList}
|
||||
rtnValue={callback}
|
||||
rtnInputData={handleInsertSdmData}
|
||||
openNetwork={false}
|
||||
openNetwork={true}
|
||||
/>
|
||||
<Toaster position="top-center" />
|
||||
</div>
|
||||
|
||||
+16
-29
@@ -42,9 +42,8 @@ export function middleware(req: NextRequest) {
|
||||
.map(([key, value]) => `${key}=${decodeURIComponent(value)}`)
|
||||
.join("&");
|
||||
|
||||
const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${
|
||||
decodedParams ? `?${decodedParams}` : ""
|
||||
}`;
|
||||
const newUrl = `${serverApiUrl}${pathname.replace("/server", "")}${decodedParams ? `?${decodedParams}` : ""
|
||||
}`;
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
@@ -55,33 +54,25 @@ export function middleware(req: NextRequest) {
|
||||
|
||||
if (pathname.startsWith("/attach-service")) {
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
// const token =
|
||||
// "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJhMGVjN2EwNy03NTJhLTRmN2YtODlhNi04NTRlNjNkMmUzYTAiLCJhdXRob3JpdGllcyI6IlJPTEVfQURNSU4sUk9MRV9BTk9OWU1PVVMiLCJtbmdyWW4iOiJZIiwiZXhwIjoxNzUyMTM1OTk3fQ.itGY6M6mC2iwKvEpXw2KS6354T_B_OFz4hD26ResIgwJhpwiDJCMuSXD-rZ3AarmAIKd0udpCuJR7UlvFMN2ww";
|
||||
// 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}`;
|
||||
|
||||
//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);
|
||||
|
||||
console.log(
|
||||
`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`
|
||||
);
|
||||
console.log(`[Middleware] Rewriting from '/attach-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl), {
|
||||
headers: requestHeaders,
|
||||
});
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/user-service")) {
|
||||
if (pathname.startsWith("/user-service")
|
||||
|| pathname.startsWith("/cms-service")) {
|
||||
let queryParams = searchParams.toString();
|
||||
const requestHeaders = new Headers(req.headers);
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
const newUrl = `${serverApiUrl}${pathname}${queryParams ? `?${queryParams}` : ""}`;
|
||||
|
||||
console.log(
|
||||
`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`
|
||||
);
|
||||
console.log(`[Middleware] Rewriting from '/user-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl), {
|
||||
headers: requestHeaders,
|
||||
});
|
||||
@@ -130,27 +121,24 @@ export function middleware(req: NextRequest) {
|
||||
|
||||
if (pathname.startsWith("/reuse-service")) {
|
||||
const queryParams = searchParams.toString();
|
||||
const newUrl = `${SERVER_API_WR_URL}${pathname.replace("/reuse-service", "")}${
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
const newUrl = `${SERVER_API_WR_URL}${pathname.replace("/reuse-service", "")}${queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/reuse-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/operation-service")) {
|
||||
const queryParams = searchParams.toString();
|
||||
const newUrl = `${SERVER_API_FO_URL}${pathname.replace("/operation-service", "")}${
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
const newUrl = `${SERVER_API_FO_URL}${pathname.replace("/operation-service", "")}${queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/operation-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/sewerage-service")) {
|
||||
const queryParams = searchParams.toString();
|
||||
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service", "")}${
|
||||
queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
const newUrl = `${SEWERAGE_API_URL}${pathname.replace("/sewerage-service", "")}${queryParams ? `?${queryParams}` : ""
|
||||
}`;
|
||||
console.log(`[Middleware] Rewriting from '/sewerage-service' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
@@ -174,9 +162,7 @@ export function middleware(req: NextRequest) {
|
||||
const newUrl = `${BUSINESS_JUSO_API_URL}?${params.toString()}`;
|
||||
console.log(`[Middleware] Request to business.juso.go.kr`);
|
||||
console.log(req.url);
|
||||
console.log(
|
||||
`[Middleware] Rewriting from '/business.juso.go.kr' path to: ${newUrl}`
|
||||
);
|
||||
console.log(`[Middleware] Rewriting from '/business.juso.go.kr' path to: ${newUrl}`);
|
||||
return NextResponse.rewrite(new URL(newUrl));
|
||||
}
|
||||
|
||||
@@ -187,6 +173,7 @@ export const config = {
|
||||
matcher: [
|
||||
"/server/:path*",
|
||||
"/user-service/:path*",
|
||||
"/cms-service/:path*",
|
||||
"/attach-service/:path*",
|
||||
"/geoserver/:path*",
|
||||
"/operation-service/:path*",
|
||||
|
||||
@@ -302,7 +302,7 @@ export default function CoSttn() {
|
||||
</div>
|
||||
<UiModal
|
||||
bodyClass={
|
||||
"w-[40vw] max-w-none h-[83vh] " // +updateData?.dmdInfoId?'h-[60vh]':'h-[90vh]'
|
||||
"w-[40vw] max-w-none h-[90vh] overflow-y-auto" // +updateData?.dmdInfoId?'h-[60vh]':'h-[90vh]'
|
||||
}
|
||||
open={isDmdModal.isMoal}
|
||||
onOpenChange={() => {
|
||||
@@ -350,7 +350,7 @@ export default function CoSttn() {
|
||||
}}
|
||||
bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"}
|
||||
updateList={updateData}
|
||||
openNetwork={false}
|
||||
openNetwork={true}
|
||||
></SdmInsertForm>
|
||||
}
|
||||
></UiModal>
|
||||
|
||||
@@ -766,7 +766,7 @@ export function PbnstBuseForm({
|
||||
></UiModal>
|
||||
|
||||
<UiModal
|
||||
bodyClass={"w-[40vw] max-w-none h-[90vh]"}
|
||||
bodyClass={"w-[40vw] max-w-none h-[100vh] overflow-y-auto"}
|
||||
open={isDmdModal.isMoal}
|
||||
onOpenChange={() => {
|
||||
setIsDmdModal({ isMoal: false, data: {} as DemandCompType });
|
||||
@@ -787,9 +787,10 @@ export function PbnstBuseForm({
|
||||
});
|
||||
}}
|
||||
bodyClassNm={"w-full mx-auto bg-white rounded-lg shadow-md p-6"}
|
||||
openNetwork={false}
|
||||
openNetwork={true}
|
||||
></SdmInsertForm>
|
||||
}
|
||||
noFooterYn={"Y"}
|
||||
></UiModal>
|
||||
</div>
|
||||
) : (
|
||||
|
||||
@@ -60,7 +60,8 @@ export function middleware(req: NextRequest) {
|
||||
}
|
||||
|
||||
if (pathname.startsWith("/cms-service")) {
|
||||
const newUrl = `${serverApiUrl}${pathname}`;
|
||||
let queryParams = searchParams.toString();
|
||||
const newUrl = `${serverApiUrl}${pathname}${queryParams ? `?${queryParams}` : ""}`;
|
||||
console.log(`[Middleware] Rewriting from '/cms-service' path to: ${newUrl}`);
|
||||
const rewriteRequest = rewriteWith(newUrl, req, true);
|
||||
return rewriteRequest;
|
||||
|
||||
@@ -31,19 +31,21 @@ export function UiModal({
|
||||
<>
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className={bodyClass}>
|
||||
{noHeaderYn === 'N' && (
|
||||
<DialogHeader>
|
||||
<DialogDescription className={headerTitleClass}>
|
||||
{headerTitle}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
)}
|
||||
{(open && body) ?
|
||||
useDirectRender
|
||||
? body
|
||||
: <>{body}</>
|
||||
: <></>
|
||||
}
|
||||
{noHeaderYn === 'N' && (
|
||||
<DialogHeader>
|
||||
<DialogDescription className={headerTitleClass}>
|
||||
{headerTitle}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
)}
|
||||
<div>
|
||||
{(open && body) ?
|
||||
useDirectRender
|
||||
? body
|
||||
: <>{body}</>
|
||||
: <></>
|
||||
}
|
||||
</div>
|
||||
{noFooterYn === 'N' && (
|
||||
<DialogFooter className="sm:justify-start">
|
||||
{footerContent}
|
||||
|
||||
@@ -14,7 +14,7 @@ export * from "./search_form_left";
|
||||
export * from "./search_form_right";
|
||||
export * from "./search_input";
|
||||
export * from "./search_input_select";
|
||||
export * from "./search_input_address";
|
||||
// export * from "./search_input_address";
|
||||
export * from "./select";
|
||||
export * from "./tab";
|
||||
export * from "./table";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Input } from "@common/components";
|
||||
import { Button, Input, Label } from "@common/components";
|
||||
import { AsYouType } from "libphonenumber-js";
|
||||
import React, { useCallback, useEffect, useState } from "react";
|
||||
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
|
||||
@@ -6,8 +6,10 @@ import { FormField } from "../form";
|
||||
import { FormUi } from "../form_ui";
|
||||
import { SelectBox } from "../select";
|
||||
import { SdmSearchForm } from "./sdmNameBox";
|
||||
import SearchInputAddress from "../search_input_address";
|
||||
import type { addressType } from "../search_input_address/findAddress";
|
||||
import { UiModal, UiTable } from '../../ui';
|
||||
import type { Zip, ZipSearchParams } from "../search_input_address/zipService";
|
||||
import { findAddress } from "../search_input_address/findAddress";
|
||||
import { cn } from "@common/components";
|
||||
|
||||
// 수요처 정보
|
||||
export type DemandCompType = {
|
||||
@@ -18,7 +20,7 @@ export type DemandCompType = {
|
||||
daddr: string | "";
|
||||
telno: string | "";
|
||||
rgtr: string | "";
|
||||
mdfr?:string ;
|
||||
mdfr?: string;
|
||||
useUsgCd: string | "";
|
||||
ctpvCd: string | "";
|
||||
sggCd: string | "";
|
||||
@@ -89,6 +91,7 @@ export function SdmRegForm({
|
||||
readOnly,
|
||||
openNetwork,
|
||||
}: SdmRegFormProps) {
|
||||
const PAGE_SIZE = 10;
|
||||
const [sidoValue, setSidoValue] = useState<string>("");
|
||||
const [sigunValue, setSigunValue] = useState<string>("");
|
||||
const [filteredSigunData, setFilteredSigunData] = useState<SelectDataType[]>([
|
||||
@@ -97,6 +100,34 @@ export function SdmRegForm({
|
||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(true);
|
||||
const [orgBznmNo, setOrgBznmNo] = useState<string>("");
|
||||
const [updateCoNm, setUpdateNm] = useState<string>("");
|
||||
const [isZipModalOpen, setIsZipModalOpen] = useState<boolean>(false);
|
||||
const [zipId, setZipId] = useState<number | undefined>(undefined);
|
||||
const [address, setAddress] = useState<string | undefined>("");
|
||||
const [detailedAddress, setDetailedAddress] = useState<string>("");
|
||||
const [curPage, setCurPage] = useState<number>(1);
|
||||
// 우편번호 검색 관련 상태
|
||||
const [zipSearchResults, setZipSearchResults] = useState<Zip[]>([]);
|
||||
const [zipTotalElements, setZipTotalElements] = useState<number>(-1);
|
||||
const [searchQuery, setSearchQuery] = useState<ZipSearchParams>({
|
||||
roadNm: "",
|
||||
bldgNoMno: null,
|
||||
bldgNoSno: null,
|
||||
page: curPage,
|
||||
size: PAGE_SIZE
|
||||
});
|
||||
const [isResetPage, setIsResetPage] = useState<boolean>(false);
|
||||
const [isResetSelection, setIsResetSelection] = useState<boolean>(false);
|
||||
const [selectedRowIndex, setSelectedRowIndex] = useState<number | undefined>(undefined);
|
||||
const [selectedZip, setSelectedZip] = useState<Zip>();
|
||||
const [isSelectedZip, setIsSelectedZip] = useState<boolean>(false);
|
||||
|
||||
const handleCellClick = (index: any, headId: any) => {
|
||||
console.log('index', index);
|
||||
console.log('headId', headId);
|
||||
setSelectedZip(zipSearchResults[index]);
|
||||
setIsSelectedZip(true);
|
||||
console.log('selectedZip', zipSearchResults[index]);
|
||||
};
|
||||
|
||||
const formatPhoneNumber = (value: string) => {
|
||||
const input = value;
|
||||
@@ -262,6 +293,17 @@ export function SdmRegForm({
|
||||
[orgBznmNo, setIsDuplicate],
|
||||
);
|
||||
|
||||
// 우편번호 선택 함수
|
||||
const handleSelectAddress = () => {
|
||||
setZipId(selectedZip?.zipId);
|
||||
setAddress(selectedZip?.zipAddr || "");
|
||||
setDetailedAddress("");
|
||||
setIsZipModalOpen(false);
|
||||
setSelectedZip(undefined);
|
||||
setIsSelectedZip(false);
|
||||
setSelectedRowIndex(undefined);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (updateList?.dmdInfoId) {
|
||||
form.reset(updateList);
|
||||
@@ -283,199 +325,344 @@ export function SdmRegForm({
|
||||
console.log("form.formState.errors ", form.formState.errors);
|
||||
}, [form.formState.errors]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("curPage ", curPage);
|
||||
searchQuery.page = curPage - 1;
|
||||
const fetchAddress = async () => {
|
||||
const result = await findAddress(searchQuery);
|
||||
setZipSearchResults(result?.content);
|
||||
};
|
||||
fetchAddress();
|
||||
}, [curPage]);
|
||||
|
||||
// 폼 제출 전에 주소 합치기
|
||||
useEffect(() => {
|
||||
// address와 detailedAddress를 합쳐서 daddr에 설정
|
||||
if (address) {
|
||||
const fullAddress = `${address || ""} ${detailedAddress || ""}`.trim();
|
||||
form.setValue("daddr", fullAddress, {shouldValidate: true });
|
||||
}
|
||||
}, [address, detailedAddress, form]);
|
||||
|
||||
const renderBody = () => (
|
||||
<>
|
||||
<form
|
||||
onSubmit={async (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
const result = await findAddress(searchQuery);
|
||||
setZipSearchResults(result?.content);
|
||||
setZipTotalElements(result?.totalElements);
|
||||
}}
|
||||
className="mb-4 space-y-2"
|
||||
>
|
||||
{/* 검색 조건 부분 */}
|
||||
<div className="card card-border !m-0 flex flex-col gap-4 p-4">
|
||||
<div className="grid grid-cols-3 gap-4">
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 font-bold text-base">도로명</Label>
|
||||
<Input
|
||||
value={searchQuery.roadNm || ""}
|
||||
onChange={(e) =>
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
roadNm: e.target.value,
|
||||
})
|
||||
}
|
||||
placeholder="예: 테헤란로"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물본번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoMno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoMno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 123"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col">
|
||||
<Label className="mb-1 text-base">건물부번</Label>
|
||||
<Input
|
||||
type="number"
|
||||
value={searchQuery.bldgNoSno ?? ""}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value
|
||||
? parseInt(e.target.value)
|
||||
: null;
|
||||
setSearchQuery({
|
||||
...searchQuery,
|
||||
bldgNoSno: value,
|
||||
});
|
||||
}}
|
||||
placeholder="예: 45"
|
||||
className="!text-[1.3rem]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<Button className="rounded-md" type="submit">검색</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{/* 검색 결과 부분 */}
|
||||
{zipTotalElements > 0 && (
|
||||
<UiTable
|
||||
headName=''
|
||||
tableData={zipSearchResults}
|
||||
headlist={[{ id: 'zoneNo', title: '우편번호' }, { id: 'zipAddr', title: '주소' }]}
|
||||
pageSize={PAGE_SIZE}
|
||||
total={zipTotalElements}
|
||||
cellClick={handleCellClick}
|
||||
onPageChange={setCurPage}
|
||||
resetPageNo={isResetPage}
|
||||
resetSelection={isResetSelection}
|
||||
index={selectedRowIndex}
|
||||
/>
|
||||
)}
|
||||
{zipTotalElements === 0 && (
|
||||
<div className={cn("flex h-96 flex-col items-center justify-center gap-4")}>
|
||||
<i className="diveicon di-info-circle text-3xl" />
|
||||
조회된 데이터가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
|
||||
const formFields: Array<{
|
||||
name: keyof FormSchema;
|
||||
label: string;
|
||||
component: FieldComponent;
|
||||
}> = [
|
||||
{
|
||||
name: "ctpvCd",
|
||||
label: "시도",
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSidoData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={undefined}
|
||||
label=""
|
||||
selectArray={selectSidoData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "ctpvCd", field ?? "")
|
||||
}
|
||||
className=""
|
||||
value={sidoValue}
|
||||
{
|
||||
name: "ctpvCd",
|
||||
label: "시도",
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSidoData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={undefined}
|
||||
label=""
|
||||
selectArray={selectSidoData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "ctpvCd", field ?? "")
|
||||
}
|
||||
className=""
|
||||
value={sidoValue}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "sggCd",
|
||||
label: "시군구",
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSigunData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={"!text-xl text-gray-600"}
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "sggCd", field)
|
||||
}
|
||||
className=""
|
||||
value={sigunValue}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdCoNm",
|
||||
label: "회사명",
|
||||
component: (field) => (
|
||||
<SdmSearchForm
|
||||
rtnData={setRtnData}
|
||||
label="수요처명"
|
||||
initValue={updateCoNm}
|
||||
dataList={dataList}
|
||||
rtnValue={setRtnValue}
|
||||
rtnText={setRtnText}
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "sggCd",
|
||||
label: "시군구",
|
||||
component: (field) =>
|
||||
updateList?.dmdInfoId ? (
|
||||
},
|
||||
{
|
||||
name: "dmdInfoId",
|
||||
label: "사업자등록번호",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="시도"
|
||||
placeholder="사업자등록번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => {
|
||||
field.onChange(e.target.value);
|
||||
}}
|
||||
value={
|
||||
selectSigunData.find((item) => item.val === field.value?.trim())
|
||||
?.text ?? ""
|
||||
}
|
||||
onChange={(e) => bznNoChange(e, "dmdInfoId", field)}
|
||||
value={formatBusinessNumber(field.value ?? "")}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
) : (
|
||||
<SelectBox
|
||||
selectClass={"!text-xl text-gray-600"}
|
||||
label=""
|
||||
selectArray={filteredSigunData}
|
||||
onSelectValue={(val) =>
|
||||
onSelectValue(val.toString(), "sggCd", field)
|
||||
}
|
||||
className=""
|
||||
value={sigunValue}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdCoNm",
|
||||
label: "회사명",
|
||||
component: (field) => (
|
||||
<SdmSearchForm
|
||||
rtnData={setRtnData}
|
||||
label="수요처명"
|
||||
initValue={updateCoNm}
|
||||
dataList={dataList}
|
||||
rtnValue={setRtnValue}
|
||||
rtnText={setRtnText}
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdInfoId",
|
||||
label: "사업자등록번호",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="사업자등록번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
onChange={(e) => bznNoChange(e, "dmdInfoId", field)}
|
||||
value={formatBusinessNumber(field.value ?? "")}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "bznmTotNo",
|
||||
label: "",
|
||||
component: (field) => (
|
||||
<FormUi
|
||||
label="종사업자등록번호"
|
||||
onCheckboxChange={handleCheckboxChange}
|
||||
isDisabled={isBznmTotNoDisabled}
|
||||
>
|
||||
},
|
||||
{
|
||||
name: "bznmTotNo",
|
||||
label: "",
|
||||
component: (field) => (
|
||||
<FormUi
|
||||
label="종사업자등록번호"
|
||||
onCheckboxChange={handleCheckboxChange}
|
||||
isDisabled={isBznmTotNoDisabled}
|
||||
>
|
||||
<Input
|
||||
placeholder="여러사업장이 있을 경우 입력해주세요"
|
||||
type="text"
|
||||
className="!mt-5 !text-xl text-gray-600"
|
||||
disabled={isBznmTotNoDisabled}
|
||||
onChange={(e) => bznNoChange(e, "bznmTotNo", field)}
|
||||
// {...field}
|
||||
value={field.value ?? ""}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
</FormUi>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "daddr",
|
||||
label: "사업자주소",
|
||||
component: (field) =>
|
||||
openNetwork ? (
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 우편번호 */}
|
||||
<Input
|
||||
type="text"
|
||||
className="!text-xl text-gray-600 w-64"
|
||||
readOnly={true}
|
||||
value={zipId?.toString() ?? ""}
|
||||
placeholder="우편번호"
|
||||
/>
|
||||
<Button className="px-4 py-2 rounded-md" onClick={() => setIsZipModalOpen(true)}>우편번호 검색</Button>
|
||||
</div>
|
||||
{/* 주소 */}
|
||||
<Input
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={true}
|
||||
value={address ?? ""}
|
||||
placeholder="주소"
|
||||
/>
|
||||
{/* 상세 주소 */}
|
||||
<Input
|
||||
placeholder="상세 주소를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value;
|
||||
setDetailedAddress(value);
|
||||
}}
|
||||
value={detailedAddress ?? ""}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<Input
|
||||
placeholder="주소를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "telno",
|
||||
label: "전화번호",
|
||||
component: (field) => {
|
||||
const formattedValue = formatPhoneNumber(field.value ?? ""); // 초기 렌더링 시에도 포맷 적용
|
||||
|
||||
return (
|
||||
<Input
|
||||
placeholder="전화번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={formattedValue}
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value.replace(/\D/g, ""); // 숫자만 저장
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "dmdAplyPswd",
|
||||
label: "패스워드",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="여러사업장이 있을 경우 입력해주세요"
|
||||
type="text"
|
||||
className="!mt-5 !text-xl text-gray-600"
|
||||
disabled={isBznmTotNoDisabled}
|
||||
onChange={(e) => bznNoChange(e, "bznmTotNo", field)}
|
||||
// {...field}
|
||||
value={field.value ?? ""}
|
||||
readOnly={!!updateList?.dmdInfoId}
|
||||
/>
|
||||
</FormUi>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "daddr",
|
||||
label: "사업자주소",
|
||||
component: (field) =>
|
||||
openNetwork ? (
|
||||
<SearchInputAddress
|
||||
initValue={updateList?.daddr || ""}
|
||||
readonly={readOnly ?? false}
|
||||
setRtnData={(rtnData: addressType) => {
|
||||
field.onChange(rtnData.roadAddrPart1);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<Input
|
||||
placeholder="주소를 입력하세요"
|
||||
type="text"
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "telno",
|
||||
label: "전화번호",
|
||||
component: (field) => {
|
||||
const formattedValue = formatPhoneNumber(field.value ?? ""); // 초기 렌더링 시에도 포맷 적용
|
||||
|
||||
return (
|
||||
<Input
|
||||
placeholder="전화번호를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={formattedValue}
|
||||
readOnly={readOnly}
|
||||
onChange={(e) => {
|
||||
const value = e.target.value.replace(/\D/g, ""); // 숫자만 저장
|
||||
field.onChange(value);
|
||||
}}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "dmdAplyPswd",
|
||||
label: "패스워드",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "dmdAplyPswdConfirm",
|
||||
label: "패스워드확인",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
{
|
||||
name: "dmdAplyPswdConfirm",
|
||||
label: "패스워드확인",
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="패스워드를 입력하세요"
|
||||
type="password"
|
||||
className="!text-xl text-gray-600"
|
||||
readOnly={readOnly}
|
||||
{...field}
|
||||
value={field.value ?? ""}
|
||||
/>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -538,6 +725,36 @@ export function SdmRegForm({
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<UiModal
|
||||
headerTitle="주소 검색"
|
||||
headerTitleClass="text-2xl font-bold text-gray-900"
|
||||
open={isZipModalOpen}
|
||||
onOpenChange={setIsZipModalOpen}
|
||||
bodyClass={`
|
||||
${zipTotalElements > -1 ? 'h-[80vh]' : 'h-[30vh]'}
|
||||
w-[30vw]
|
||||
min-w-[500px]
|
||||
max-w-[90vw]
|
||||
max-h-[85vh]
|
||||
overflow-y-auto
|
||||
!fixed
|
||||
!top-[50%]
|
||||
!left-[50%]
|
||||
!-translate-x-1/2
|
||||
!-translate-y-1/2
|
||||
z-[101]
|
||||
flex
|
||||
flex-col
|
||||
`}
|
||||
body={renderBody()}
|
||||
footerContent={
|
||||
<div className="w-full flex justify-center items-center gap-4">
|
||||
<Button className="rounded-md" size="lg" onClick={handleSelectAddress} disabled={!isSelectedZip}>선택</Button>
|
||||
<Button className="rounded-md" size="lg" onClick={() => setIsZipModalOpen(false)}>취소</Button>
|
||||
</div>
|
||||
}
|
||||
useDirectRender={true}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ const createFormSchema = (isBznmTotNoDisabled: boolean, isDuplicate: boolean ,up
|
||||
.refine(() => !isDuplicate, "이미 등록된 사업자등록번호입니다"),
|
||||
daddr: z.string()
|
||||
.min(1, "주소를 입력해주세요")
|
||||
.min(6, "주소는 6자 이상 입력해주세요")
|
||||
// .min(6, "주소는 6자 이상 입력해주세요")
|
||||
.max(40, "주소는 40자 이내로 입력해주세요"),
|
||||
telno: z.string()
|
||||
.min(8, "전화번호는 8자 이상 입력해주세요")
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
// const Key = 'U01TX0FVVEgyMDI1MDgyODE0MTAxNzExNjEyMjA'
|
||||
// const addresssKey = 'devU01TX0FVVEgyMDI1MDgyNTEwMzkwNDExNjEwNTM='; //인증키 만료일은 2025-11-23
|
||||
|
||||
import type { Zip, ZipSearchParams } from "./zipService";
|
||||
|
||||
/**
|
||||
* 주소 API 응답 타입
|
||||
* https://business.juso.go.kr/addrlink/main.do 해당 사이트 참조
|
||||
*/
|
||||
export type AddressApiResponse ={
|
||||
export type AddressApiResponse = {
|
||||
results: {
|
||||
common: {
|
||||
errorMessage: string;
|
||||
@@ -19,7 +21,7 @@ export type AddressApiResponse ={
|
||||
};
|
||||
}
|
||||
|
||||
export type addressType ={
|
||||
export type addressType = {
|
||||
detBdNmList: string;
|
||||
engAddr: string;
|
||||
rn: string;
|
||||
@@ -46,79 +48,70 @@ export type addressType ={
|
||||
buldSlno: string;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 주소에 따른 검색
|
||||
* @param search : 검색어
|
||||
* @returns addressType[] 주소 배열
|
||||
*/
|
||||
export const findAddress = async (search: string) => {
|
||||
if (!search) {
|
||||
return [];
|
||||
}
|
||||
const params = new URLSearchParams({
|
||||
currentPage: "1", // 원하는 페이지
|
||||
countPerPage: "5", // 페이지당 결과 수
|
||||
keyword: search, // 검색어(주소)
|
||||
confmKey: '', // 인증키 인터넷용 패쇄망용은 따로 발급 필요 즉 middleware에서 치환해서 사용해야할듯
|
||||
resultType: "json", // 결과 형식 기본은 xml
|
||||
});
|
||||
// const url = `https://business.juso.go.kr/addrlink/addrLinkApi.do?${params.toString()}`;
|
||||
const url = `/bussiness-juso-service/addrlink/addrLinkApi.do?${params.toString()}`;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error('Network response was not ok');
|
||||
}
|
||||
const data = await response.json();
|
||||
if (data.results && data.results.juso) {
|
||||
return data.results.juso as addressType[];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
export const findAddress = async (searchQuery: ZipSearchParams): Promise<any> => {
|
||||
if (!searchQuery) return [];
|
||||
|
||||
// 쿼리 파라미터 생성
|
||||
const params = new URLSearchParams();
|
||||
if (searchQuery.roadNm) params.append('roadNm', searchQuery.roadNm);
|
||||
if (searchQuery.bldgNoMno != null) params.append('bldgNoMno', searchQuery.bldgNoMno.toString());
|
||||
if (searchQuery.bldgNoSno != null) params.append('bldgNoSno', searchQuery.bldgNoSno.toString());
|
||||
if (searchQuery.page != null) params.append('page', searchQuery.page.toString());
|
||||
if (searchQuery.size != null) params.append('size', searchQuery.size.toString());
|
||||
|
||||
const url = `/cms-service/api/v1/zips?${params.toString()}`;
|
||||
try {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) throw new Error('Network response was not ok');
|
||||
|
||||
const data = await response.json();
|
||||
if (data) return data
|
||||
else return [];
|
||||
} catch (error) {
|
||||
console.error('Error fetching address data:', error);
|
||||
return [];
|
||||
console.error('Error fetching address data:', error);
|
||||
return [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const searchFilter=(search:string)=>{
|
||||
export const searchFilter = (search: string) => {
|
||||
|
||||
|
||||
if(search.length >0){
|
||||
//특수문자 제거
|
||||
const expText = /[%=><]/ ;
|
||||
if(expText.test(search) == true){
|
||||
alert("특수문자를 입력 할수 없습니다.") ;
|
||||
search = search.split(expText).join("");
|
||||
return false;
|
||||
}
|
||||
|
||||
//특정문자열(sql예약어의 앞뒤공백포함) 제거
|
||||
const sqlArray = [
|
||||
//sql 예약어
|
||||
"OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE", "DROP", "EXEC",
|
||||
"UNION", "FETCH", "DECLARE", "TRUNCATE"
|
||||
if (search.length > 0) {
|
||||
//특수문자 제거
|
||||
const expText = /[%=><]/;
|
||||
if (expText.test(search) == true) {
|
||||
alert("특수문자를 입력 할수 없습니다.");
|
||||
search = search.split(expText).join("");
|
||||
return false;
|
||||
}
|
||||
|
||||
//특정문자열(sql예약어의 앞뒤공백포함) 제거
|
||||
const sqlArray = [
|
||||
//sql 예약어
|
||||
"OR", "SELECT", "INSERT", "DELETE", "UPDATE", "CREATE", "DROP", "EXEC",
|
||||
"UNION", "FETCH", "DECLARE", "TRUNCATE"
|
||||
]
|
||||
|
||||
let regex;
|
||||
for(let i=0; i<sqlArray.length; i++){
|
||||
regex = new RegExp( sqlArray[i] as string,"gi") ;
|
||||
|
||||
if (regex.test(search) ) {
|
||||
alert("\"" + sqlArray[i]+"\"와(과) 같은 특정문자로 검색할 수 없습니다.");
|
||||
search =search.replace(regex, "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true ;
|
||||
|
||||
let regex;
|
||||
for (let i = 0; i < sqlArray.length; i++) {
|
||||
regex = new RegExp(sqlArray[i] as string, "gi");
|
||||
|
||||
if (regex.test(search)) {
|
||||
alert("\"" + sqlArray[i] + "\"와(과) 같은 특정문자로 검색할 수 없습니다.");
|
||||
search = search.replace(regex, "");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,129 +1,129 @@
|
||||
import { Input } from "@common/components/ui";
|
||||
import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { findAddress, searchFilter, type addressType } from "./findAddress";
|
||||
// import { Input } from "@common/components/ui";
|
||||
// import React, { useCallback, useEffect, useRef, useState } from "react";
|
||||
// import { findAddress, searchFilter, type addressType } from "./findAddress";
|
||||
|
||||
type thisProps = {
|
||||
initValue: string | undefined;
|
||||
setRtnData: (rtnData: addressType) => void;
|
||||
readonly?: boolean;
|
||||
};
|
||||
// type thisProps = {
|
||||
// initValue: string | undefined;
|
||||
// setRtnData: (rtnData: addressType) => void;
|
||||
// readonly?: boolean;
|
||||
// };
|
||||
|
||||
/**
|
||||
*
|
||||
* @param initValue : 초기값 ?
|
||||
* @returns setRtnData => 선택된 주소 데이터 반환
|
||||
*/
|
||||
export default function SearchInputAddress({
|
||||
initValue,
|
||||
setRtnData = () => {},
|
||||
readonly = false,
|
||||
}: thisProps) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [textValue, setTextValue] = useState(initValue || "");
|
||||
const [searchList, setSearchList] = useState<addressType[]>([]);
|
||||
// /**
|
||||
// *
|
||||
// * @param initValue : 초기값 ?
|
||||
// * @returns setRtnData => 선택된 주소 데이터 반환
|
||||
// */
|
||||
// export default function SearchInputAddress({
|
||||
// initValue,
|
||||
// setRtnData = () => {},
|
||||
// readonly = false,
|
||||
// }: thisProps) {
|
||||
// const [isOpen, setIsOpen] = useState(false);
|
||||
// const [textValue, setTextValue] = useState(initValue || "");
|
||||
// const [searchList, setSearchList] = useState<addressType[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
initValue !== textValue &&
|
||||
initValue !== undefined &&
|
||||
initValue !== null &&
|
||||
initValue !== ""
|
||||
) {
|
||||
setTextValue(initValue);
|
||||
}
|
||||
}, [initValue]);
|
||||
const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
// useEffect(() => {
|
||||
// if (
|
||||
// initValue !== textValue &&
|
||||
// initValue !== undefined &&
|
||||
// initValue !== null &&
|
||||
// initValue !== ""
|
||||
// ) {
|
||||
// setTextValue(initValue);
|
||||
// }
|
||||
// }, [initValue]);
|
||||
// const wrapperRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const handleInputChange = useCallback(
|
||||
(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
// const handleInputChange = useCallback(
|
||||
// (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
// const value = e.target.value;
|
||||
|
||||
if (searchFilter(value)) {
|
||||
setTextValue(value);
|
||||
findAddress(value).then((data) => {
|
||||
setSearchList(data);
|
||||
});
|
||||
}else{
|
||||
setTextValue("");
|
||||
setSearchList([]);
|
||||
}
|
||||
if (value) {
|
||||
setIsOpen(true);
|
||||
} else {
|
||||
setIsOpen(false);
|
||||
}
|
||||
},
|
||||
[setSearchList],
|
||||
);
|
||||
// if (searchFilter(value)) {
|
||||
// setTextValue(value);
|
||||
// findAddress(value).then((data) => {
|
||||
// setSearchList(data);
|
||||
// });
|
||||
// }else{
|
||||
// setTextValue("");
|
||||
// setSearchList([]);
|
||||
// }
|
||||
// if (value) {
|
||||
// setIsOpen(true);
|
||||
// } else {
|
||||
// setIsOpen(false);
|
||||
// }
|
||||
// },
|
||||
// [setSearchList],
|
||||
// );
|
||||
|
||||
const handleSuggestionClick = useCallback(
|
||||
(roadAddrPart1: string) => {
|
||||
setTextValue(roadAddrPart1);
|
||||
setIsOpen(false);
|
||||
setRtnData(
|
||||
searchList?.find((item) => item.roadAddrPart1 === roadAddrPart1) ||
|
||||
({} as addressType),
|
||||
);
|
||||
},
|
||||
[searchList, setRtnData],
|
||||
);
|
||||
// const handleSuggestionClick = useCallback(
|
||||
// (roadAddrPart1: string) => {
|
||||
// setTextValue(roadAddrPart1);
|
||||
// setIsOpen(false);
|
||||
// setRtnData(
|
||||
// searchList?.find((item) => item.roadAddrPart1 === roadAddrPart1) ||
|
||||
// ({} as addressType),
|
||||
// );
|
||||
// },
|
||||
// [searchList, setRtnData],
|
||||
// );
|
||||
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (
|
||||
wrapperRef.current &&
|
||||
!wrapperRef.current.contains(event.target as Node)
|
||||
) {
|
||||
setIsOpen(false);
|
||||
}
|
||||
};
|
||||
// useEffect(() => {
|
||||
// const handleClickOutside = (event: MouseEvent) => {
|
||||
// if (
|
||||
// wrapperRef.current &&
|
||||
// !wrapperRef.current.contains(event.target as Node)
|
||||
// ) {
|
||||
// setIsOpen(false);
|
||||
// }
|
||||
// };
|
||||
|
||||
document.addEventListener("mousedown", handleClickOutside);
|
||||
return () => {
|
||||
document.removeEventListener("mousedown", handleClickOutside);
|
||||
};
|
||||
}, []);
|
||||
// document.addEventListener("mousedown", handleClickOutside);
|
||||
// return () => {
|
||||
// document.removeEventListener("mousedown", handleClickOutside);
|
||||
// };
|
||||
// }, []);
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className="relative">
|
||||
<Input
|
||||
type="text"
|
||||
value={textValue}
|
||||
onChange={handleInputChange}
|
||||
/* onFocus={() => setIsOpen(true)} */
|
||||
className="h-[3.2rem] w-full rounded-md border border-gray-300 pl-3 !text-xl text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
placeholder={`주소를 입력하세요`}
|
||||
readOnly={readonly}
|
||||
/>
|
||||
{isOpen && (
|
||||
<div className="absolute left-0 right-0 z-50 mt-2 max-h-72 overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
|
||||
<div className="max-h-72">
|
||||
{searchList && searchList.length > 0 ? (
|
||||
searchList.map((item: addressType, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
className="w-full cursor-pointer overflow-auto px-5 py-3 text-left !text-xl hover:bg-gray-100"
|
||||
onClick={() => handleSuggestionClick(item.roadAddrPart1)}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === "Enter" || e.key === " ") {
|
||||
handleSuggestionClick(item.roadAddrPart1);
|
||||
}
|
||||
}}
|
||||
>
|
||||
{item.zipNo}
|
||||
<span className="float-right">{item.roadAddrPart1}</span>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<div className="w-full cursor-pointer overflow-auto px-5 py-3 !text-xl hover:bg-gray-100">
|
||||
검색 결과가 없습니다.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
// return (
|
||||
// <div ref={wrapperRef} className="relative">
|
||||
// <Input
|
||||
// type="text"
|
||||
// value={textValue}
|
||||
// onChange={handleInputChange}
|
||||
// /* onFocus={() => setIsOpen(true)} */
|
||||
// className="h-[3.2rem] w-full rounded-md border border-gray-300 pl-3 !text-xl text-gray-600 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
// placeholder={`주소를 입력하세요`}
|
||||
// readOnly={readonly}
|
||||
// />
|
||||
// {isOpen && (
|
||||
// <div className="absolute left-0 right-0 z-50 mt-2 max-h-72 overflow-auto rounded-md border border-gray-300 bg-white shadow-lg">
|
||||
// <div className="max-h-72">
|
||||
// {searchList && searchList.length > 0 ? (
|
||||
// searchList.map((item: addressType, index: number) => (
|
||||
// <div
|
||||
// key={index}
|
||||
// className="w-full cursor-pointer overflow-auto px-5 py-3 text-left !text-xl hover:bg-gray-100"
|
||||
// onClick={() => handleSuggestionClick(item.roadAddrPart1)}
|
||||
// role="button"
|
||||
// tabIndex={0}
|
||||
// onKeyDown={(e) => {
|
||||
// if (e.key === "Enter" || e.key === " ") {
|
||||
// handleSuggestionClick(item.roadAddrPart1);
|
||||
// }
|
||||
// }}
|
||||
// >
|
||||
// {item.zipNo}
|
||||
// <span className="float-right">{item.roadAddrPart1}</span>
|
||||
// </div>
|
||||
// ))
|
||||
// ) : (
|
||||
// <div className="w-full cursor-pointer overflow-auto px-5 py-3 !text-xl hover:bg-gray-100">
|
||||
// 검색 결과가 없습니다.
|
||||
// </div>
|
||||
// )}
|
||||
// </div>
|
||||
// </div>
|
||||
// )}
|
||||
// </div>
|
||||
// );
|
||||
// }
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
interface SortConfig {
|
||||
empty: boolean;
|
||||
sorted: boolean;
|
||||
unsorted: boolean;
|
||||
}
|
||||
|
||||
interface PageableConfig {
|
||||
sort: SortConfig;
|
||||
offset: number;
|
||||
pageNumber: number;
|
||||
pageSize: number;
|
||||
paged: boolean;
|
||||
unpaged: boolean;
|
||||
}
|
||||
|
||||
export interface PageableList<T> {
|
||||
content: T[];
|
||||
pageable: PageableConfig;
|
||||
sort: SortConfig;
|
||||
totalPages: number;
|
||||
totalElements: number;
|
||||
number: number;
|
||||
numberOfElements: number;
|
||||
size: number;
|
||||
first: boolean;
|
||||
last: boolean;
|
||||
empty: boolean;
|
||||
}
|
||||
|
||||
export interface PageableParams {
|
||||
page?: number;
|
||||
size?: number;
|
||||
sort?: string;
|
||||
}
|
||||
|
||||
|
||||
export interface ZipSearchParams extends PageableParams {
|
||||
zoneNo?: string; // 구역번호
|
||||
ctpvNm?: string; // 시도명
|
||||
sggNm?: string; // 시군구명
|
||||
emdNm?: string; // 읍면동명
|
||||
roadNm?: string; // 도로명
|
||||
stdgNm?: string; // 법정동명
|
||||
dongNm?: string; // 행정동명
|
||||
bldgNoMno?: number | null; // 빌딩본번
|
||||
bldgNoSno?: number | null; // 빌딩딩부번
|
||||
lotnoMno?: number | null; // 지번본번
|
||||
lotnoSno?: number | null; // 지번부번
|
||||
}
|
||||
|
||||
export interface Zip {
|
||||
zipId: number;
|
||||
zoneNo: string;
|
||||
ctpvNm: string;
|
||||
sggNm: string;
|
||||
emdNm: string;
|
||||
roadNm: string;
|
||||
bldgNoMno: number;
|
||||
bldgNoSno: number;
|
||||
lotnoMno: number;
|
||||
lotnoSno: number;
|
||||
lotno: string;
|
||||
zipAddr: string;
|
||||
}
|
||||
|
||||
export type ZipList = PageableList<Zip>;
|
||||
Reference in New Issue
Block a user