Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7849f317c | ||
|
|
7cd1ae2625 | ||
|
|
19bee65195 | ||
|
|
26c01ede4e | ||
|
|
c4750d9652 | ||
|
|
142929510f |
@@ -1,19 +1,16 @@
|
||||
NEXT_PUBLIC_SITE_ID = DM
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
NEXT_PUBLIC_PROXY_HOST = http://localhost:3000
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
NEXT_PUBLIC_CLAIM_NAME = Authorization
|
||||
NEXT_PUBLIC_AUTH_USER_ID = token-id
|
||||
NEXT_PUBLIC_ACCESS_TOKEN = access-token
|
||||
NEXT_PUBLIC_REFRESH_TOKEN = refresh-token
|
||||
|
||||
|
||||
|
||||
NEXT_PUBLIC_PORT = 11035
|
||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://con.mind-one.co.kr:11080/api/v1
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://con.mind-one.co.kr:11082/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://dev.onasys.co.kr:8000
|
||||
NEXT_PUBLIC_CS_TUS_UPLOAD = /attach-service/api/v1/tus/upload
|
||||
NEXT_PUBLIC_SEWERAGE_API_URL=http://con.mind-one.co.kr:11083/sewerage-service/api # 개발 서버 API
|
||||
# NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.128:8883/sewerage-service/api # 최용성
|
||||
#NEXT_PUBLIC_SEWERAGE_API_URL=http://192.168.1.66:8883/sewerage-service/api # 박이정
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
NEXT_PUBLIC_SITE_ID = DM
|
||||
NEXT_PUBLIC_PORT = 3000
|
||||
NEXT_PUBLIC_PROXY_HOST = http://wr.hasuon.or.kr
|
||||
NEXT_PUBLIC_PORT = 11035
|
||||
NEXT_PUBLIC_PROXY_HOST = http://con.mind-one.co.kr:11035
|
||||
NEXT_PUBLIC_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/api/v1
|
||||
NEXT_PUBLIC_FO_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000/operation-service/api/v1
|
||||
NEXT_PUBLIC_CS_SERVER_API_URL = http://apigateway.iipbs-dev.svc.cluster.local:8000
|
||||
|
||||
@@ -30,6 +30,9 @@ export default function Home() {
|
||||
<Button className='ml-5 place-self-auto'>
|
||||
<Link href="/pages/sdmMng/sdmApplyList">수요처 신청 현황(개발중)</Link>
|
||||
</Button>
|
||||
<Button className='ml-5 place-self-auto'>
|
||||
<Link href="/pages/map/mainMap">지도팝업 (임시)</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
"use client";
|
||||
const Map = () => {
|
||||
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
|
||||
</>
|
||||
|
||||
);
|
||||
};
|
||||
|
||||
export default Map;
|
||||
@@ -0,0 +1,132 @@
|
||||
"use client";
|
||||
|
||||
import Gis from "@common/business_components/ui/map/Gis";
|
||||
import { useEffect, useRef, useState, useCallback } from "react";
|
||||
import { mapService } from "../service";
|
||||
import GisApp from "@common/business_components/ui/map/lib/gis.core";
|
||||
|
||||
const Map = () => {
|
||||
const [treeData, setTreeData] = useState([]); // 초기값을 객체 또는 null로 설정
|
||||
const gisMaps = useRef<any | null>(null);
|
||||
const [isOpen, setIsOpen] = useState(false); // 팝업 열기/닫기 상태
|
||||
const [isSearchModalOpen, setIsSearchModalOpen] = useState(true); // SearchModal 열림 상태
|
||||
const [featureData, setFeatureData] = useState(null); // 선택된 피쳐 데이터
|
||||
const [checkedLayers, setCheckedLayers] = useState<string[]>([]);
|
||||
const [checkedLayersData, setCheckedLayersData] = useState<any[]>([]);
|
||||
|
||||
const fetchData = async () => {
|
||||
try {
|
||||
const response = await mapService.getLyrStngs();
|
||||
setTreeData(response); // API 응답 저장
|
||||
} catch (error) {
|
||||
console.error("데이터 불러오기 실패:", error);
|
||||
}
|
||||
};
|
||||
|
||||
// 팝업 닫기 핸들러를 useCallback으로 메모이제이션
|
||||
const handlePopupClose = useCallback(() => {
|
||||
setIsOpen(false);
|
||||
setFeatureData(null);
|
||||
}, []);
|
||||
|
||||
// 컴포넌트 마운트 시 1회 실행
|
||||
useEffect(() => {
|
||||
fetchData();
|
||||
}, []);
|
||||
|
||||
// 체크된 레이어 정보를 받는 핸들러
|
||||
const handleCheckedLayersChange = (
|
||||
checkedIds: string[],
|
||||
checkedNodesData: any[]
|
||||
) => {
|
||||
setCheckedLayers(checkedIds);
|
||||
setCheckedLayersData(checkedNodesData);
|
||||
};
|
||||
|
||||
// SearchModal, GisContent 등에서 호출
|
||||
const onFeatureSelect = (data: any) => {
|
||||
const map = gisMaps.current;
|
||||
if (!map) {
|
||||
console.warn("지도가 초기화되지 않았습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 항상 같은 select 객체 사용
|
||||
const select = GisApp.Module.select as any;
|
||||
if (!select) return;
|
||||
|
||||
// 1. 기존 선택 초기화
|
||||
select.resetSelectedFeature();
|
||||
|
||||
// 2. data가 OpenLayers Feature 인스턴스인지 확인
|
||||
let foundFeature: any = null;
|
||||
if (
|
||||
data &&
|
||||
typeof data.getGeometry === "function" &&
|
||||
typeof data.setStyle === "function"
|
||||
) {
|
||||
// 이미 Feature 인스턴스라면 그대로 사용
|
||||
foundFeature = data;
|
||||
} else {
|
||||
// 아니면 featureId로 맵에서 Feature 인스턴스를 찾아서 사용
|
||||
const featureId = data.fid || data.ftrIdn || data.id;
|
||||
map
|
||||
.getLayers()
|
||||
.getArray()
|
||||
.forEach((layer: any) => {
|
||||
const source = layer.getSource?.();
|
||||
if (source?.getFeatureById) {
|
||||
const feature = source.getFeatureById(String(featureId).trim());
|
||||
if (feature) foundFeature = feature;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 3. 피처 선택
|
||||
if (foundFeature) {
|
||||
const geometry = foundFeature.getGeometry();
|
||||
if (geometry) {
|
||||
const extent = geometry.getExtent();
|
||||
|
||||
map.getView().fit(extent, {
|
||||
duration: 300,
|
||||
padding: [50, 50, 50, 50],
|
||||
maxZoom: 16,
|
||||
constrainResolution: true,
|
||||
nearest: true,
|
||||
});
|
||||
}
|
||||
select.selectFeature(foundFeature, true);
|
||||
} else {
|
||||
console.warn("OpenLayers Feature를 찾을 수 없습니다:", data);
|
||||
}
|
||||
|
||||
setFeatureData(data);
|
||||
setIsOpen(true);
|
||||
setIsSearchModalOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="bg-container">
|
||||
<Gis
|
||||
treeData={treeData}
|
||||
isSearch={false}
|
||||
gisMaps={gisMaps}
|
||||
isMiniMap={false}
|
||||
searchView={undefined}
|
||||
detailView={null}
|
||||
onFeatureSelect={onFeatureSelect}
|
||||
setIsOpen={setIsOpen}
|
||||
setFeatureData={setFeatureData}
|
||||
featureData={featureData}
|
||||
setIsSearchModalOpen={setIsSearchModalOpen}
|
||||
isOpen={isOpen}
|
||||
isSearchModalOpen={isSearchModalOpen}
|
||||
onCheckedLayersChange={handleCheckedLayersChange}
|
||||
imgVisble={true}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Map;
|
||||
@@ -0,0 +1,94 @@
|
||||
import React, { useState, useEffect, useRef, useCallback } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
|
||||
// 현재 문서의 스타일(CSS)을 새 창으로 복사하는 함수
|
||||
const copyStyles = (sourceDoc: Document, targetDoc: Document) => {
|
||||
Array.from(sourceDoc.styleSheets).forEach(styleSheet => {
|
||||
try {
|
||||
if (styleSheet.cssRules) { // <style> 태그로 주입된 CSS
|
||||
const newStyleEl = sourceDoc.createElement('style');
|
||||
Array.from(styleSheet.cssRules).forEach(cssRule => {
|
||||
newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
|
||||
});
|
||||
targetDoc.head.appendChild(newStyleEl);
|
||||
} else if (styleSheet.href) { // <link> 태그로 연결된 CSS 파일
|
||||
const newLinkEl = sourceDoc.createElement('link');
|
||||
newLinkEl.rel = 'stylesheet';
|
||||
newLinkEl.href = styleSheet.href;
|
||||
targetDoc.head.appendChild(newLinkEl);
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('스타일시트를 복사할 수 없습니다:', e);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
interface NewWindowPortalProps {
|
||||
children: React.ReactNode;
|
||||
onClose: () => void;
|
||||
title?: string;
|
||||
width?: number;
|
||||
height?: number;
|
||||
resizable?: string;
|
||||
scrollbars?: string;
|
||||
}
|
||||
|
||||
const NewWindowPortal: React.FC<NewWindowPortalProps> = ({ children, onClose, title = "" , width = 900, height = 800, resizable = "yes", scrollbars= "yes" }) => {
|
||||
const [container, setContainer] = useState<HTMLElement | null>(null);
|
||||
const newWindowRef = useRef<Window | null>(null);
|
||||
const onCloseRef = useRef(onClose);
|
||||
|
||||
// onClose 함수를 ref로 저장하여 의존성 문제 해결
|
||||
useEffect(() => {
|
||||
onCloseRef.current = onClose;
|
||||
}, [onClose]);
|
||||
|
||||
const handleUnload = useCallback(() => {
|
||||
onCloseRef.current();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
// 이미 창이 열려있으면 새로 열지 않음
|
||||
if (newWindowRef.current && !newWindowRef.current.closed) return;
|
||||
|
||||
// 1. 새 창을 열고 참조를 저장합니다.
|
||||
const popupOptions = `width=${width},height=${height},resizable=${resizable},scrollbars=${scrollbars}`;
|
||||
newWindowRef.current = window.open('', title, popupOptions);
|
||||
|
||||
if (newWindowRef.current) {
|
||||
newWindowRef.current.document.title = title;
|
||||
|
||||
// 2. React 컴포넌트를 마운트할 컨테이너 div를 생성하여 새 창의 body에 추가합니다.
|
||||
const div = newWindowRef.current.document.createElement('div');
|
||||
newWindowRef.current.document.body.appendChild(div);
|
||||
setContainer(div);
|
||||
|
||||
// 3. 메인 창의 스타일을 새 창으로 복사합니다. (매우 중요)
|
||||
copyStyles(document, newWindowRef.current.document);
|
||||
|
||||
// 4. 사용자가 창을 닫을 때 부모에게 알리기 위한 이벤트 리스너를 설정합니다.
|
||||
// const handleUnload = () => {
|
||||
// onClose();
|
||||
// };
|
||||
newWindowRef.current.addEventListener('unload', handleUnload);
|
||||
|
||||
// 5. 컴포넌트가 사라질 때 창을 닫는 클린업 함수를 반환합니다.
|
||||
return () => {
|
||||
if (newWindowRef.current) {
|
||||
newWindowRef.current.removeEventListener('unload', handleUnload);
|
||||
if (!newWindowRef.current.closed) {
|
||||
newWindowRef.current.close();
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
alert('팝업이 차단되었습니다. 팝업 차단을 해제하고 다시 시도해주세요.');
|
||||
onCloseRef.current();
|
||||
}
|
||||
}, [handleUnload, onClose, title]);
|
||||
|
||||
// `createPortal`을 사용해 children을 새 창의 container div에 렌더링합니다.
|
||||
return container ? createPortal(children, container) : null;
|
||||
};
|
||||
|
||||
export default NewWindowPortal;
|
||||
@@ -0,0 +1 @@
|
||||
export * from './map'
|
||||
@@ -0,0 +1,46 @@
|
||||
|
||||
/**
|
||||
* 관망도 API
|
||||
*/
|
||||
const API_URL = `${process.env.NEXT_PUBLIC_SEWERAGE_API_URL}/v1/map`
|
||||
|
||||
export type LyrStngProps = {
|
||||
lyr_sn: string
|
||||
lyr_nm: string
|
||||
upper_lyr_sn: string
|
||||
drawOrdr: string
|
||||
flterSql: string
|
||||
gobjTy: string
|
||||
lyrTpNm: string
|
||||
useYn: string
|
||||
minViewSize: string
|
||||
iconNm: string
|
||||
lblAtrbNm: string
|
||||
fontNm: string
|
||||
fontIntnColor: string
|
||||
fontExtnColor: string
|
||||
fontExtnWdth: string
|
||||
lnWdth: string
|
||||
lnColor: string
|
||||
polgnColor: string
|
||||
initEprssYn: string
|
||||
clickPsblYn: string
|
||||
}
|
||||
|
||||
export const mapService = {
|
||||
//레이어 설정 조회
|
||||
getLyrStngs: async () => {
|
||||
const response = await fetch(`${API_URL}/lyrStngs/WR_NETWORK`, {
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@ import { Toaster } from "react-hot-toast";
|
||||
import * as z from "zod";
|
||||
import SdmLogin from "../sdmLogin/page";
|
||||
|
||||
const createFormSchema = () => z.object({
|
||||
const sdmInfoFormSchema = z.object({
|
||||
sdmNm: z.string()
|
||||
.min(1, "수요처를 선택해주세요"),
|
||||
demandYmd: z.date().optional(),
|
||||
@@ -67,14 +67,14 @@ const createFormSchema = () => z.object({
|
||||
candidateTitle: z.string().optional(),
|
||||
});
|
||||
|
||||
export type FormData = z.infer<ReturnType<typeof createFormSchema>>;
|
||||
export type FormData = z.infer<typeof sdmInfoFormSchema>;
|
||||
|
||||
function SdmInfoInsertContent() {
|
||||
const searchParams = useSearchParams();
|
||||
const {insertSdmInfoData, Sdm} = useDmStore((state) => state);
|
||||
const {successLogin} = Sdm;
|
||||
const [ismoneyDisabled, setIsmoneyDisabled] = useState(false);
|
||||
const formSchema = createFormSchema();
|
||||
const formSchema = sdmInfoFormSchema;
|
||||
|
||||
const [isLogin, setIsLogin] = useState(false);
|
||||
const [facilityName, setFacilityName] = useState<string>('');
|
||||
|
||||
@@ -21,6 +21,7 @@ export default function MyForm() {
|
||||
useEffect(() => {
|
||||
if (successNextPage && formDataRef.current) {
|
||||
const data = formDataRef.current;
|
||||
console.log(data);
|
||||
const queryParams = new URLSearchParams({
|
||||
dmdCoNm: data.dmdCoNm || '',
|
||||
ctpvCd: data.ctpvCd || '',
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import ModalSimilarPage from "@/app/pages/sdmMng/sdmInfoInsert/modalSimilar/page";
|
||||
import type { FormData } from "@/app/pages/sdmMng/sdmInfoInsert/page";
|
||||
import { useDmStore } from "@/app/store";
|
||||
import { CANDIDATE, DatePicker, FormField, FormLabel, FormUi, SelectBox, UiModal } from "@common/business_components";
|
||||
import {
|
||||
CANDIDATE,
|
||||
DatePicker,
|
||||
FormField,
|
||||
FormLabel,
|
||||
FormUi,
|
||||
SelectBox,
|
||||
UiModal,
|
||||
} from "@common/business_components";
|
||||
import { Input } from "@common/components";
|
||||
import { Button } from "@common/components/ui";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
@@ -10,6 +18,8 @@ import { AccessibleFormField } from "./AccessibleFormField";
|
||||
import type { ControllerRenderProps, UseFormReturn } from "react-hook-form";
|
||||
import SearchInputText from "../common/searhDemandInput/component";
|
||||
import type { DemandCompType } from "@/app/store/sdmMng";
|
||||
import NewWindowPortal from "@/app/pages/map/popup/windowPotal";
|
||||
import Map from "@/app/pages/map/popup/sdmInfoMap";
|
||||
|
||||
export interface SdmInfoRegFormProps {
|
||||
form: UseFormReturn<FormData>;
|
||||
@@ -17,21 +27,31 @@ export interface SdmInfoRegFormProps {
|
||||
facilityName?: string;
|
||||
}
|
||||
|
||||
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
||||
type FieldComponent = (
|
||||
field: ControllerRenderProps<FormData, keyof FormData>
|
||||
) => JSX.Element;
|
||||
|
||||
export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfoRegFormProps) {
|
||||
export function SdmInfoRegForm({
|
||||
form,
|
||||
onCheckboxChange,
|
||||
facilityName,
|
||||
}: SdmInfoRegFormProps) {
|
||||
const { initializeCommonData, Sdm } = useDmStore((state) => state);
|
||||
const { useTypesData } = Sdm;
|
||||
const searchParams = useSearchParams();
|
||||
|
||||
const [sdmNmValue, setSdmNmValue] = useState<string>(searchParams.get('dmdCoNm') || '');
|
||||
|
||||
const [sdmNmValue, setSdmNmValue] = useState<string>(
|
||||
searchParams.get("dmdCoNm") || ""
|
||||
);
|
||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
||||
const [isSimilarCase, setIsSimilarCase] = useState(false);
|
||||
const [key, setKey] = useState(0);
|
||||
// 후보지 팝업 오픈 상태
|
||||
const [isCandidatePopup, setIsCandidatePopup] = useState(false);
|
||||
|
||||
//모달 조회에 필요한 데이터
|
||||
const [sply, setSply] = useState<number>(0);
|
||||
const [usageCd, setUsageCd] = useState<string>('청소');
|
||||
const [usageCd, setUsageCd] = useState<string>("청소");
|
||||
const [money, setMoney] = useState<number>(0);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -41,7 +61,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
useEffect(() => {
|
||||
if (useTypesData && useTypesData.length > 0) {
|
||||
setTimeout(() => {
|
||||
form.setValue('usePurpose', useTypesData[0]?.val?.toString() || '');
|
||||
form.setValue("usePurpose", useTypesData[0]?.val?.toString() || "");
|
||||
}, 500);
|
||||
}
|
||||
}, [useTypesData, form]);
|
||||
@@ -49,32 +69,45 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
useEffect(() => {
|
||||
if (facilityName) {
|
||||
setSdmNmValue(facilityName);
|
||||
form.setValue('sdmNm', facilityName);
|
||||
setKey(prev => prev + 1);
|
||||
form.setValue("sdmNm", facilityName);
|
||||
setKey((prev) => prev + 1);
|
||||
}
|
||||
}, [facilityName, form]);
|
||||
|
||||
useEffect(() => {
|
||||
if (searchParams.get("dmdCoNm")) {
|
||||
form.setValue("sdmNm", searchParams.get("dmdCoNm") || "");
|
||||
setSdmNmValue(searchParams.get("dmdCoNm") || "");
|
||||
setKey((prev) => prev + 1);
|
||||
}
|
||||
}, [searchParams, form]);
|
||||
|
||||
const searchCandidate = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
console.log(1);
|
||||
setIsCandidatePopup(true);
|
||||
};
|
||||
|
||||
const searchSimilarCase = (e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setIsSimilarCase(true);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
const handleCheckboxChange = (checked: boolean) => {
|
||||
setIsBznmTotNoDisabled(checked);
|
||||
onCheckboxChange?.(checked);
|
||||
};
|
||||
|
||||
// 시설 선택시 이벤트
|
||||
const selectComp = useCallback((rtnData: DemandCompType[]) => {
|
||||
const rtnCompData = rtnData?.[0];
|
||||
form.setValue('sdmNm', rtnCompData?.dmdCoNm || '');
|
||||
}, [form]);
|
||||
const selectComp = useCallback(
|
||||
(rtnData: DemandCompType[]) => {
|
||||
const rtnCompData = rtnData?.[0];
|
||||
form.setValue("sdmNm", rtnCompData?.dmdCoNm || "");
|
||||
},
|
||||
[form]
|
||||
);
|
||||
|
||||
const formFields: Array<{
|
||||
name: keyof FormData;
|
||||
@@ -93,15 +126,15 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
<SearchInputText
|
||||
label="수요처명"
|
||||
setValue={(val) => {
|
||||
setSdmNmValue(val || '');
|
||||
field.onChange(val || '');
|
||||
setSdmNmValue(val || "");
|
||||
field.onChange(val || "");
|
||||
}}
|
||||
setRtnData={selectComp}
|
||||
initValue={facilityName || sdmNmValue}
|
||||
{...field}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "demandYmd",
|
||||
@@ -110,7 +143,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<div className="w-full">
|
||||
<DatePicker
|
||||
<DatePicker
|
||||
mode="single"
|
||||
selected={field.value as Date}
|
||||
onSelect={(date) => {
|
||||
@@ -122,12 +155,12 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
value: field.value as Date,
|
||||
onChange: (date: Date | undefined) => {
|
||||
field.onChange(date as Date);
|
||||
}
|
||||
},
|
||||
}}
|
||||
selectClass={undefined}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "demandQnty",
|
||||
@@ -135,8 +168,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 0,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="요구수량(㎥/d)을 입력하세요"
|
||||
<Input
|
||||
placeholder="요구수량(㎥/d)을 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -148,7 +181,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "usePurpose",
|
||||
@@ -158,16 +191,16 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
component: (field) => (
|
||||
<SelectBox
|
||||
selectClass={undefined}
|
||||
label=""
|
||||
selectArray={useTypesData}
|
||||
label=""
|
||||
selectArray={useTypesData}
|
||||
onSelectValue={(val) => {
|
||||
field.onChange(val.toString());
|
||||
setUsageCd(val.toString());
|
||||
}}
|
||||
className=""
|
||||
className=""
|
||||
value={field.value as string}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "money",
|
||||
@@ -201,14 +234,14 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
</FormUi>
|
||||
}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "reqWaterQlty",
|
||||
label: "요구수질",
|
||||
formIndex: 0,
|
||||
required: true,
|
||||
component: undefined
|
||||
component: undefined,
|
||||
},
|
||||
{
|
||||
name: "grssClfg",
|
||||
@@ -216,8 +249,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="총대장균군수를 입력하세요"
|
||||
<Input
|
||||
placeholder="총대장균군수를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -226,7 +259,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "tn",
|
||||
@@ -234,8 +267,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="총질소를 입력하세요"
|
||||
<Input
|
||||
placeholder="총질소를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -244,7 +277,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "combResdch",
|
||||
@@ -252,8 +285,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="결합잔류염소를 입력하세요"
|
||||
<Input
|
||||
placeholder="결합잔류염소를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -262,7 +295,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "tph",
|
||||
@@ -270,8 +303,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="총인을 입력하세요"
|
||||
<Input
|
||||
placeholder="총인을 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -280,16 +313,16 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "trbt",
|
||||
label: "탁도(NTU)",
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="탁도를 입력하세요"
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="탁도를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -298,7 +331,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "ph",
|
||||
@@ -306,8 +339,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="수소이온농도를 입력하세요"
|
||||
<Input
|
||||
placeholder="수소이온농도를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -316,7 +349,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "bod",
|
||||
@@ -324,8 +357,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="생물학적 산소요구량을 입력하세요"
|
||||
<Input
|
||||
placeholder="생물학적 산소요구량을 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -334,7 +367,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "clIonQnt",
|
||||
@@ -342,8 +375,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="염화물을 입력하세요"
|
||||
<Input
|
||||
placeholder="염화물을 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -352,16 +385,16 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
},
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "smll",
|
||||
label: "냄새",
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="냄새를 입력하세요"
|
||||
<Input
|
||||
placeholder="냄새를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -370,7 +403,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "cdtnv",
|
||||
@@ -378,8 +411,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="전기전도도를 입력하세요"
|
||||
<Input
|
||||
placeholder="전기전도도를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -388,7 +421,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "crmty",
|
||||
@@ -396,8 +429,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="색도를 입력하세요"
|
||||
<Input
|
||||
placeholder="색도를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -406,7 +439,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "rmrk",
|
||||
@@ -414,8 +447,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
formIndex: 1,
|
||||
required: true,
|
||||
component: (field) => (
|
||||
<Input
|
||||
placeholder="비고를 입력하세요"
|
||||
<Input
|
||||
placeholder="비고를 입력하세요"
|
||||
type="text"
|
||||
className="!text-xl text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -424,7 +457,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
)
|
||||
),
|
||||
},
|
||||
{
|
||||
name: "candidateTitle",
|
||||
@@ -433,16 +466,16 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
component: (field) => (
|
||||
<div>
|
||||
<div className="-mt-14 float-right flex gap-10">
|
||||
<Button className={'bg-gray-200'} onClick={searchCandidate}>
|
||||
<Button className={"bg-gray-200"} onClick={searchCandidate}>
|
||||
후보지 조회
|
||||
</Button>
|
||||
<Button className={'bg-gray-200'} onClick={searchSimilarCase}>
|
||||
<Button className={"bg-gray-200"} onClick={searchSimilarCase}>
|
||||
유사사례
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex justify-center gap-10 mt-5">
|
||||
<Input
|
||||
placeholder="후보지1"
|
||||
<Input
|
||||
placeholder="후보지1"
|
||||
type="text"
|
||||
className="!text-xl w-[130px] text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -451,8 +484,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
<Input
|
||||
placeholder="후보지2"
|
||||
<Input
|
||||
placeholder="후보지2"
|
||||
type="text"
|
||||
className="!text-xl w-[130px] text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -461,8 +494,8 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
name={field.name}
|
||||
ref={field.ref}
|
||||
/>
|
||||
<Input
|
||||
placeholder="후보지3"
|
||||
<Input
|
||||
placeholder="후보지3"
|
||||
type="text"
|
||||
className="!text-xl w-[130px] text-gray-600"
|
||||
value={field.value as string}
|
||||
@@ -473,24 +506,32 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const normalFields = formFields.filter(f => f.formIndex === 0 && f.component);
|
||||
const groupFields = formFields.filter(f => f.formIndex === 1 && f.component);
|
||||
const candidateFields = formFields.filter(f => f.formIndex === 2 && f.component);
|
||||
const normalFields = formFields.filter(
|
||||
(f) => f.formIndex === 0 && f.component
|
||||
);
|
||||
const groupFields = formFields.filter(
|
||||
(f) => f.formIndex === 1 && f.component
|
||||
);
|
||||
const candidateFields = formFields.filter(
|
||||
(f) => f.formIndex === 2 && f.component
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{normalFields.map(({ name, label, component, required }) => (
|
||||
{normalFields.map(({ name, label, component, required }) =>
|
||||
component ? (
|
||||
<FormField
|
||||
key={name}
|
||||
control={form.control}
|
||||
name={name}
|
||||
render={({ field }) => (
|
||||
name === 'money' ? component(field) : (
|
||||
render={({ field }) =>
|
||||
name === "money" ? (
|
||||
component(field)
|
||||
) : (
|
||||
// <FormUi label={label}>
|
||||
// {component(field)}
|
||||
// </FormUi>
|
||||
@@ -502,10 +543,10 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
inputComponent={component(field)}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
}
|
||||
/>
|
||||
) : null
|
||||
))}
|
||||
)}
|
||||
|
||||
{groupFields.length > 0 && (
|
||||
<div className="mt-10">
|
||||
@@ -535,7 +576,7 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
</div>
|
||||
)}
|
||||
|
||||
{candidateFields.map(({ name, label, component, required }, index) => (
|
||||
{candidateFields.map(({ name, label, component, required }, index) =>
|
||||
component ? (
|
||||
<FormField
|
||||
key={name + index}
|
||||
@@ -555,11 +596,13 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
)}
|
||||
/>
|
||||
) : null
|
||||
))}
|
||||
)}
|
||||
|
||||
{isSimilarCase && (
|
||||
<UiModal
|
||||
body={<ModalSimilarPage sply={sply} usageCd={usageCd} money={money} />}
|
||||
body={
|
||||
<ModalSimilarPage sply={sply} usageCd={usageCd} money={money} />
|
||||
}
|
||||
bodyClass="sm:max-w-[100vw] w-[1400px] h-[900px]"
|
||||
open={isSimilarCase}
|
||||
onOpenChange={(open) => !open && setIsSimilarCase(false)}
|
||||
@@ -567,6 +610,20 @@ export function SdmInfoRegForm({ form, onCheckboxChange, facilityName }: SdmInfo
|
||||
noFooterYn="Y"
|
||||
/>
|
||||
)}
|
||||
|
||||
{/* 후보지 조회 새 창 포털 */}
|
||||
{isCandidatePopup && (
|
||||
<NewWindowPortal
|
||||
onClose={() => setIsCandidatePopup(false)}
|
||||
title="공급처 후보지 조회"
|
||||
width={window.screen.availWidth}
|
||||
height={window.screen.availHeight}
|
||||
resizable="no"
|
||||
scrollbars="yes"
|
||||
>
|
||||
<Map />
|
||||
</NewWindowPortal>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,16 @@ import { BZNM_TOT_NO, FormField, FormUi } from "@common/business_components";
|
||||
import { Button, Input } from "@common/components";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { sha512 } from 'js-sha512';
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useMemo } from "react";
|
||||
import { FormProvider, useForm, type ControllerRenderProps } from "react-hook-form";
|
||||
import * as z from "zod";
|
||||
|
||||
export function SdmLoginForm() {
|
||||
type FormData = z.infer<ReturnType<typeof createFormSchema>>;
|
||||
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
||||
const createFormSchema = () => z.object({
|
||||
const { actionLogin, initializeCommonData } = useDmStore((state) => state);
|
||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
||||
|
||||
// 스키마를 useMemo로 최적화
|
||||
const sdmLoginFormSchema = useMemo(() => z.object({
|
||||
dmdInfoId: z.string()
|
||||
.min(1, "사업자등록번호를 입력해주세요")
|
||||
.regex(/^\d{10}$/, "사업자등록번호는 10자리 숫자만 입력 가능합니다"),
|
||||
@@ -24,11 +26,12 @@ export function SdmLoginForm() {
|
||||
.max(16, "비밀번호는 16자 이내로 입력해주세요"),
|
||||
rgtr: z.string().optional(),
|
||||
dmdAplyPswd: z.string().optional(),
|
||||
});
|
||||
}), [isBznmTotNoDisabled]);
|
||||
|
||||
const { actionLogin, initializeCommonData } = useDmStore((state) => state);
|
||||
const [isBznmTotNoDisabled, setIsBznmTotNoDisabled] = useState(false);
|
||||
const formSchema = createFormSchema();
|
||||
type FormData = z.infer<typeof sdmLoginFormSchema>;
|
||||
type FieldComponent = (field: ControllerRenderProps<FormData, keyof FormData>) => JSX.Element;
|
||||
|
||||
const formSchema = sdmLoginFormSchema;
|
||||
|
||||
useEffect(() => {
|
||||
initializeCommonData();
|
||||
|
||||
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 961 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 970 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1016 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 468 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 757 B |
|
After Width: | Height: | Size: 785 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 791 B |
|
After Width: | Height: | Size: 455 B |
|
After Width: | Height: | Size: 782 B |
|
After Width: | Height: | Size: 782 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 217 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1009 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1017 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 259 B |
|
After Width: | Height: | Size: 167 B |
|
After Width: | Height: | Size: 164 B |
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 165 B |
|
After Width: | Height: | Size: 163 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 160 B |
|
After Width: | Height: | Size: 108 B |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 313 B |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.2 KiB |