From 0963b60daf1b05d11801c7c926822a8e36e9a055 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Thu, 12 Sep 2024 10:51:27 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=ED=8C=94=EC=9E=91=EC=A7=80=EB=B6=95=20offs?= =?UTF-8?q?et=20validation=20=EC=B6=94=EA=B0=80.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/qpolygon-utils.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 7a20a2b4..1599905d 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2732,6 +2732,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { if (ridge.direction === 'top') { if (ridge.y1 > y1 && ridge.y2 > y1) { offset = Math.abs(ridge.y1 - y1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1, @@ -2763,6 +2764,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { } if (ridge.y1 < y1 && ridge.y2 < y1) { offset = Math.abs(ridge.y2 - y1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1 - offset, @@ -2795,6 +2797,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { if (ridge.direction === 'bottom') { if (ridge.y1 > y1 && ridge.y2 > y1) { offset = Math.abs(ridge.y1 - y1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1 - offset, @@ -2825,6 +2828,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { } if (ridge.y1 < y1 && ridge.y2 < y1) { offset = Math.abs(ridge.y2 - y1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1, @@ -2858,6 +2862,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { if (ridge.direction === 'right') { if (ridge.x1 > x1 && ridge.x2 > x1) { offset = Math.abs(ridge.x1 - x1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1 - offset, y1: ridge.y1, @@ -2888,6 +2893,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { } if (ridge.x1 < x1 && ridge.x2 < x1) { offset = Math.abs(ridge.x2 - x1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1, @@ -2920,6 +2926,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { if (ridge.direction === 'left') { if (ridge.x1 > x1 && ridge.x2 > x1) { offset = Math.abs(ridge.x1 - x1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1, y1: ridge.y1, @@ -2950,6 +2957,7 @@ const setGableRoof = (polygon, ridge, hip1, hip2, offset, canvas) => { } if (ridge.x1 < x1 && ridge.x2 < x1) { offset = Math.abs(ridge.x2 - x1) - offset + offset = offset < 0 ? 0 : offset ridge.set({ x1: ridge.x1 - offset, y1: ridge.y1, From 166b60ca03c2c5f6246fd91ab62f007cf38e3f29 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 12 Sep 2024 11:55:29 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 274 ++++++++++++++-------- 1 file changed, 182 insertions(+), 92 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 0c0692c7..91cf5131 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -44,45 +44,39 @@ export default function StuffDetail() { const [prefCodeList, setPrefCodeList] = useState([]) //도도부현 코트 리스트 const [prefValue, setPrefValue] = useState('') + const [saleStoreList, setSaleStoreList] = useState([]) // 판매점 리스트 - const [receiveUser, setReceiveUser] = useState('') //담당자 - const [name2, setName2] = useState('') //물건명 - const [name3, setName3] = useState('') //물건명후리가나 - const [zipCode, setZipCode] = useState('') //우편번호 - const [name5, setName5] = useState('') //수직적설량 - const [gubun, setGubun] = useState('NEW') //신축 기축 - const [sel, setSel] = useState('') //경칭선택 - const [sel2, setSel2] = useState('') //발전량시뮬레이션지역 - const [sel3, setSel3] = useState('') //기준풍속 - const [sel4, setSel4] = useState('') //설치높이 + const [powerSimAreaList, setPowerSimAreaList] = useState([]) //발전시뮬레이션 리스트 - const [errors, setErrors] = useState({}) const [isFormValid, setIsFormValid] = useState(false) //임시저장, 진짜저장 버튼 컨트롤 - const [testSelOption, setTestSelOption] = useState([]) // 테스트용 - const [autoSelectValue, setAutoSelectValue] = useState('') //판매점명 자동완성 const [buttonValid, setButtonValid] = useState(false) //주소검색 활성화 컨트롤 - const [isSelected, setIsSelected] = useState(false) //한랭지대첵 체크박스 - const [isSelected2, setIsSelected2] = useState(false) //염해지역용아이템사용 체크박스 - const [gubun2, setGubun2] = useState('1') //면조도구분 라디오 - const [gubun3, setGubun3] = useState('A') //계약조건 라디오 - const [memo, setMemo] = useState('') //메모 const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set - // const [address1, setAddress1] = useState('') //우편API리턴 도도부현명 - // const [address2, setAddress2] = useState('') //우편API리턴 시구정촌명 - // const [address3, setAddress3] = useState('') //우편API리턴 마을 지역명 - // const [prefCode, setPrefCode] = useState(1) //우편API prefcode - const [editMode, setEditMode] = useState('NEW') const [detailData, setDetailData] = useState({}) useEffect(() => { + // 도도부현API get({ url: '/api/object/prefecture/list' }).then((res) => { if (!isEmptyArray(res)) { - console.log('도도부현API 결과:::', res) + //console.log('도도부현API 결과:::', res) setPrefCodeList(res) } }) + // 판매점목록 API /api/object/saleStore/판매점코드/list - 판매점 목록 조회 + // salesStoreLevel 추가되면 붙여서 보내기 + // 임시 1차점 판매점코드 saleStoreId=201TES01 + // T01 + get({ url: `/api/object/saleStore/201TES01/list` }).then((res) => { + if (!isEmptyArray(res)) { + console.log('판매점 결과:::::', res) + setSaleStoreList(res) + //1차 판매점 자동완성 값 셋팅 + form.setValue('saleStoreId', res[0].saleStoreId) + //1차 판매점 번호 셋팅 + form.setValue('saleStoreName', res[0].saleStoreId) + } + }) // console.log('상세화면진입:::::::::', searchParams.get('objectNo')) // console.log('물건번호::::', objectNo) @@ -100,10 +94,16 @@ export default function StuffDetail() { } }, [objectNo]) - useEffect(() => { - // validateForm() - }, [receiveUser, name2, name3, gubun, sel, autoSelectValue, zipCode, sel2, sel3, name5, sel4]) - + //1차점 변경 이벤트 + const onSelectionChange = (key) => { + if (key == null) { + form.setValue('saleStoreId', '') + form.setValue('saleStoreName', '') + } else { + form.setValue('saleStoreId', key) + form.setValue('saleStoreName', key) + } + } // 우편번호 숫자만 체크 const _zipNo = watch('zipNo') useEffect(() => { @@ -114,62 +114,82 @@ export default function StuffDetail() { } }, [_zipNo]) - // 수직적설량 숫자만 - const textTypeHandler2 = (e) => { - if (!e.target.value.match(/[^0-9]/g)) { - setName5(e.target.value) - } - } - const validateForm = () => { + //임시저장 저장 버튼 컨트롤 + // dispCompanyName: '', //담당자 + // objectName: '', //물건명 + // objectNameOmit: '', //경칭선택 + // saleStoreId: '', //판매점ID + // zipNo: '', //우편번호 + // prefId: '', //도도부현 + // address: '', //주소 + // powerSimArea: '', //발전량시뮬레이션지역 + // windSpeed: '', //기준풍속 + // snowCover: '', //수직적설량 + // coldAreaChk: false, //한랭지대책시행 + // surfaceType: 'Ⅲ・Ⅳ', //면조도구분(Ⅲ・Ⅳ / Ⅱ) + // saltAreaChk: false, //염해지역용아이템사용 + // installHeight: '', //설치높이 + // powerConTerms: '0', //계약조건(잉여 / 전량) + // remark: '', //메모 + // tempFlag: 'T', //임시저장(1) 저장(0) + const _dispCompanyName = watch('dispCompanyName') + const _objectName = watch('objectName') + const _objectNameOmit = watch('objectNameOmit') + const _saleStoreId = watch('saleStoreId') + const _prefId = watch('prefId') + const _address = watch('address') + const _powerSimArea = watch('powerSimArea') + const _windSpeed = watch('windSpeed') + const _snowCover = watch('snowCover') + const _installHeight = watch('installHeight') + useEffect(() => { + const formData = form.getValues() + console.log('폼::::::::::::', formData) let errors = {} - - if (!receiveUser || receiveUser.trim().length === 0) { - errors.receiveUser = '담당자 is required.' + if (!_dispCompanyName || _dispCompanyName.trim().length === 0) { + errors.dispCompanyName = true + } + if (!_objectName || _objectName.trim().length === 0) { + errors.objectName = true + } + if (!_objectNameOmit) { + errors.objectNameOmit = true + } + if (!_saleStoreId) { + errors.saleStoreId = true } - if (!name2 || name2.trim().length === 0) { - errors.name2 = '물건명 is required.' + if (!_zipNo || _zipNo.length != 7) { + errors.zipCode = true } - if (!name3 || name3.trim().length === 0) { - errors.name3 = '물건명후리가나 is required.' + if (!_prefId) { + errors.prefId = true } - if (!sel) { - errors.sel = '경칭선택 is required' + if (!_address.trim().length === 0) { + errors.address = true } - if (!sel2) { - errors.sel2 = '발전량시뮬레이션지역 is required' + if (!_powerSimArea) { + errors.powerSimArea = true } - if (!sel3) { - errors.sel3 = '기준풍속 is required' + if (!_windSpeed) { + errors.windSpeed = true } - if (!sel4) { - errors.sel4 = '설치높이 is required' + if (!_snowCover) { + errors.snowCover = true } - if (!autoSelectValue) { - errors.autoSelectValue = '판매점ID자동완성 is required' + if (!_installHeight) { + errors.installHeight = true } - if (!zipCode || zipCode.length != 7) { - errors.zipCode = '우편번호 is required.' - setButtonValid(true) - } else { - setButtonValid(false) - } - - if (!name5) { - errors.name5 = '수직적설량 is required.' - } - - console.log('errors::', errors) - setErrors(errors) + // console.log('errors::', errors) setIsFormValid(Object.keys(errors).length === 0) - } + }, [_dispCompanyName, _objectName, _objectNameOmit, _saleStoreId, _zipNo, _prefId, _address, _powerSimArea, _windSpeed, _snowCover, _installHeight]) // 주소검색 API const onSearchPostNumber = () => { @@ -179,9 +199,8 @@ export default function StuffDetail() { get({ url: `https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter(params)}` }).then((res) => { //7830060 if (res.status === 200) { - console.log('res.results::', res.results) if (res.results != null) { - console.log('res.results::', res.results) + console.log('주소검색::', res.results) // prefId: '', //도도부현 // address: '', //주소 console.log('prefcode::', res.results[0].prefcode) @@ -193,7 +212,10 @@ export default function StuffDetail() { alert('등록된 우편번호에서 주소를 찾을 수 없습니다. 다시 입력해주세요.') form.setValue('prefId', '') form.setValue('address', '') + form.setValue('zipNo', '') setPrefValue('') + setPowerSimAreaList([]) + form.setValue('powerSimArea', '') } } else { alert(res.message) @@ -201,6 +223,21 @@ export default function StuffDetail() { }) } + useEffect(() => { + if (prefValue !== '') { + console.log('우편번호 검색해서 도도부현골랐을때::::', prefValue) + // 발전시뮬레이션 지역 목록 + // /api/object/prefecture/도도부현코드/list + get({ url: `/api/object/prefecture/${prefValue}/list` }).then((res) => { + if (!isEmptyArray(res)) { + console.log('발전시뮬레이션::::::::', res) + setPowerSimAreaList(res) + // form.setValue('powerSimArea', res[0].prefId) + } + }) + } + }, [prefValue]) + const onTempSave = () => { console.log('임시저장::', isFormValid) } @@ -213,35 +250,33 @@ export default function StuffDetail() { router.push('/management/stuff') } - const changeAddress2 = (e) => { - console.log('e:::::::', e.target.value) - } - //필수값 다 입력했을때 const onValid = (data) => { + console.log('필수값 다 있고 저장') console.log('data::::::', data) const formData = form.getValues() - //console.log('formData::::', formData) - const _dispCompanyName = watch('dispCompanyName') - const _objectStatusId = watch('objectStatusId') - const _objectNameOmit = watch('objectNameOmit') - const _zipNo = watch('zipNo') - const _prefId = watch('prefId') - const _address = watch('address') - const _coldAreaChk = watch('coldAreaChk') - console.log(_dispCompanyName) - console.log(_objectStatusId) - console.log(_objectNameOmit) - console.log(_zipNo) - console.log(_prefId) - console.log('prefValue::', prefValue) - console.log(_address) - console.log('_coldAreaChk::', _coldAreaChk) + console.log('formData::::', formData) + // const _dispCompanyName = watch('dispCompanyName') + // const _objectStatusId = watch('objectStatusId') + // const _objectNameOmit = watch('objectNameOmit') + // const _zipNo = watch('zipNo') + // const _prefId = watch('prefId') + // const _address = watch('address') + // const _coldAreaChk = watch('coldAreaChk') + // console.log(_dispCompanyName) + // console.log(_objectStatusId) + // console.log(_objectNameOmit) + // console.log(_zipNo) + // console.log(_prefId) + // console.log('prefValue::', prefValue) + // console.log(_address) + // console.log('_coldAreaChk::', _coldAreaChk) } - //필수값 안넣었을때 + //필수값 안넣었을때 임시저장 const onInvalid = (errors) => { - console.log('실패', errors) + const formData = form.getValues() + console.log('임시저장formData::::', formData) } return ( @@ -276,6 +311,22 @@ export default function StuffDetail() {
+
+ {saleStoreList?.length > 0 && ( + + {(option) => {option.saleStoreName}} + + )} + +
@@ -313,9 +364,33 @@ export default function StuffDetail() {
+ {powerSimAreaList?.length > 0 && ( + + // + )}
+
+ +
@@ -354,7 +429,15 @@ export default function StuffDetail() {
- + +
+ +
@@ -379,7 +462,14 @@ export default function StuffDetail() { />
- + {!isFormValid ? ( + <> + + + + ) : ( + + )} )) ||
상세:::::::::::
} From 7fc84937cf59fc37be3a1de3fbb2d0c634531255 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 12 Sep 2024 12:03:13 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 91cf5131..611fd07c 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -464,14 +464,24 @@ export default function StuffDetail() { {!isFormValid ? ( <> - + {/* */} ) : ( )} + + + - )) ||
상세:::::::::::
} + )) || ( +
+ 상세::::::::::: + + + +
+ )} {/*
From c1fd6087cdf38dd0f16741657472b08da9a7e9a5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 12 Sep 2024 15:13:33 +0900 Subject: [PATCH 4/7] =?UTF-8?q?-=20=EC=99=B8=EB=B2=BD=EC=84=A0=20=EA=B7=B8?= =?UTF-8?q?=EB=A6=AC=EA=B8=B0=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/common.js | 5 +- src/components/floor-plan/CanvasLayout.jsx | 76 +++--- src/components/floor-plan/CanvasMenu.jsx | 52 ++-- .../floor-plan/RoofCoveringMenu.jsx | 54 +++++ .../modal/outerlinesetting/OuterLineWall.jsx | 227 +++++++++++++++--- src/hooks/useEvent.js | 112 ++++++--- src/store/canvasAtom.js | 7 +- src/store/outerLineAtom.js | 65 +++++ src/util/qpolygon-utils.js | 4 +- 9 files changed, 469 insertions(+), 133 deletions(-) create mode 100644 src/components/floor-plan/RoofCoveringMenu.jsx create mode 100644 src/store/outerLineAtom.js diff --git a/src/common/common.js b/src/common/common.js index aaba3f45..c78673ee 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -1,19 +1,22 @@ -export const STEP = { +export const MENU = { INITIAL_CANVAS_SETTING: 'initialCanvasSetting', // 배치면 초기설정 ROOF_COVERING: { EXTERIOR_WALL_LINE: 'exteriorWallLine', // 외벽선 그리기 ROOF_SHAPE_SETTINGS: 'roofShapeSettings', // 지붕형상 설정 ROOF_SHAPE_EDITING: 'roofShapeEditing', // 지붕형상 편집 HELP_LINE_DRAWING: 'helpLineDrawing', // 보조선 그리기 + DEFAULT: 'roofCoveringDefault', // 아무것도 선택 안할 경우 }, // 지붕덮개 BATCH_CANVAS: { BATCH_DRAWING: 'batchDrawing', // 배치면 그리기 SURFACE_SHAPE_BATCH: 'surfaceShapeBatch', // 면형상 배치 OBJECT_BATCH: 'objectBatch', // 오브젝트 배치 + DEFAULT: 'batchCanvasDefault', // default }, // 배치면 MODULE_CIRCUIT_SETTING: { BASIC_SETTING: 'basicSetting', // 기본설정 CIRCUIT_TRESTLE_SETTING: 'circuitTrestleSetting', // 회로가대설정 + DEFAULT: 'moduleCircuitSettingDefault', }, // 모듈회로구성 ESTIMATE: 'estimate', // todo 견적서 POWER_GENERATION_SIMULATION: 'powerGenerationSimulation', // todo 발전 시뮬레이션 diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 5be6a114..71c48845 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -1,45 +1,47 @@ 'use client' -import { useState } from "react" -import CanvasFrame from "./CanvasFrame"; +import { useState } from 'react' +import CanvasFrame from './CanvasFrame' +import { useRecoilState, useRecoilValue } from 'recoil' +import { currentMenuState, stepState } from '@/store/canvasAtom' -export default function CanvasLayout () { - const [plans, setPlans] = useState([{ id: 0, name: 'Plan 1' }, { id: 1, name: 'Plan 2' }, { id: 2, name: 'Plan 3' }]); - const [idxNum, setIdxNum] = useState(null); +export default function CanvasLayout() { + const [plans, setPlans] = useState([ + { id: 0, name: 'Plan 1' }, + { id: 1, name: 'Plan 2' }, + { id: 2, name: 'Plan 3' }, + ]) + const [idxNum, setIdxNum] = useState(null) - const onClickPlane = (num) => { - setIdxNum(num); - } + const onClickPlane = (num) => { + setIdxNum(num) + } - const handleDeletePlan = (e, id) => { - e.stopPropagation(); // 이벤트 버블링 방지 - setPlans(plans.filter(plan => plan.id !== id)); // 삭제할 아이디와 다른 아이템만 남김 - } + const handleDeletePlan = (e, id) => { + e.stopPropagation() // 이벤트 버블링 방지 + setPlans(plans.filter((plan) => plan.id !== id)) // 삭제할 아이디와 다른 아이템만 남김 + } - const addNewPlan = () => { - setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]); - } + const addNewPlan = () => { + setPlans([...plans, { id: plans.length, name: `Plan ${plans.length + 1}` }]) + } - return( -
-
-
- {plans.map((plan, idx) => ( - - ))} -
- -
- + return ( +
+
+
+ {plans.map((plan, idx) => ( + + ))}
- ) -} \ No newline at end of file + +
+ +
+ ) +} diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 45896d96..4cb14c5c 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -1,10 +1,12 @@ 'use client' import { useState } from 'react' -import MenuDepth01 from './MenuDepth01' import { useRecoilState } from 'recoil' import { modalState } from '@/store/modalAtom' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' +import { currentMenuState } from '@/store/canvasAtom' +import { MENU } from '@/common/common' +import RoofCoveringMenu from '@/components/floor-plan/RoofCoveringMenu' export default function CanvasMenu() { const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state @@ -12,34 +14,37 @@ export default function CanvasMenu() { const [vertical, setVertical] = useState(true) const { getMessage } = useMessage() const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] - const onClickNav = (number) => { - setMenuNumber(number) - if (menuNumber === number) { - setMenuNumber(null) - } + const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) + + const onClickNav = (menu) => { + setCurrentMenu(menu) } return ( -
+
    -
  • onClickNav(0)}> +
  • onClickNav(1)}>
  • -
  • onClickNav(1)}> - -
  • + { +
  • onClickNav(MENU.INITIAL_CANVAS_SETTING)} + > + +
  • + }
  • { - setModalOption({ ...modalOption, outerwall: true }) - onClickNav(2) - }} + className={`canvas-menu-item ${Object.values(MENU.ROOF_COVERING).includes(currentMenu) ? 'active' : ''}`} + onClick={() => onClickNav(MENU.ROOF_COVERING.DEFAULT)} >
-
- {menuNumber === 2 && } +
+ {Object.values(MENU.ROOF_COVERING).includes(currentMenu) && } + {/*{menuNumber === 2 && } {menuNumber === 3 && } - {menuNumber === 4 && } + {menuNumber === 4 && }*/}
) diff --git a/src/components/floor-plan/RoofCoveringMenu.jsx b/src/components/floor-plan/RoofCoveringMenu.jsx new file mode 100644 index 00000000..26da4bda --- /dev/null +++ b/src/components/floor-plan/RoofCoveringMenu.jsx @@ -0,0 +1,54 @@ +'use client' + +import { useMessage } from '@/hooks/useMessage' +import { useRecoilState, useSetRecoilState } from 'recoil' +import { currentMenuState } from '@/store/canvasAtom' +import { MENU } from '@/common/common' +import { modalState } from '@/store/modalAtom' +import { ToggleonMouse } from '@/components/header/Header' + +export default function RoofCoveringMenu() { + const { getMessage } = useMessage() + const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) + + const setModalState = useSetRecoilState(modalState) + + const onClickNav = (menu) => { + setCurrentMenu(menu) + if (menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) { + setModalState((prev) => ({ ...prev, outerwall: true })) + } else { + setModalState((prev) => ({ ...prev, outerwall: false })) + } + } + + return ( +
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
    +
  • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
  • +
  • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
  • +
  • ToggleonMouse(e, 'add', 'ul')} onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'ul')}> + +
  • +
+
+ ) +} diff --git a/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx index 1ba1c597..f3699a50 100644 --- a/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/OuterLineWall.jsx @@ -1,68 +1,239 @@ 'use client' -import { useState } from 'react' +import { useEffect, useRef } from 'react' import WithDraggable from '@/components/common/draggable/withDraggable' import { modalState } from '@/store/modalAtom' -import { useRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' +import { useEvent } from '@/hooks/useEvent' +import { canvasState } from '@/store/canvasAtom' +import { + OUTER_LINE_TYPE, + outerLineArrow1State, + outerLineArrow2State, + outerLineLength1State, + outerLineLength2State, + outerLinePointsState, + outerLineTypeState, +} from '@/store/outerLineAtom' +import { QLine } from '@/components/fabric/QLine' export default function OuterLineWall() { const [modalOption, setModalOption] = useRecoilState(modalState) //modal 열림닫힘 state - const [buttonAct, setButtonAct] = useState(1) - const [close, setClose] = useState(false) const { getMessage } = useMessage() - const HandleClickClose = () => { - setClose(true) - setTimeout(() => { - setModalOption({ ...modalOption, outerwall: false }) - setClose(false) - }, 180) + const { addCanvasMouseEventListener, addDocumentEventListener } = useEvent() + const length1Ref = useRef(null) + const length2Ref = useRef(null) + const [length1, setLength1] = useRecoilState(outerLineLength1State) + const [length2, setLength2] = useRecoilState(outerLineLength2State) + const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State) + const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State) + const [points, setPoints] = useRecoilState(outerLinePointsState) + const [type, setType] = useRecoilState(outerLineTypeState) + + const canvas = useRecoilValue(canvasState) + + useEffect(() => { + addCanvasMouseEventListener('mouse:down', mouseDown) + addDocumentEventListener('keydown', document, keydown) + }, []) + + useEffect(() => { + clear() + }, [type]) + + const clear = () => { + setLength1(0) + setArrow1('') } + + const mouseDown = (e) => { + const pointer = canvas.getPointer(e.e) + + setPoints((prev) => [...prev, pointer]) + } + + useEffect(() => { + canvas + ?.getObjects() + .filter((obj) => obj.name === 'outerLine') + .forEach((obj) => { + canvas?.remove(obj) + }) + canvas?.remove(canvas?.getObjects().find((obj) => obj.name === 'startPoint')) + if (points.length === 0) { + return + } + + if (points.length === 1) { + const point = new fabric.Circle({ + radius: 5, + fill: 'transparent', + stroke: 'red', + left: points[0].x - 5, + top: points[0].y - 5, + selectable: false, + name: 'startPoint', + }) + + canvas?.add(point) + } else { + points.forEach((point, idx) => { + if (idx === 0) { + return + } + drawLine(points[idx - 1], point) + }) + } + }, [points]) + + const drawLine = (point1, point2) => { + const line = new QLine([point1.x, point1.y, point2.x, point2.y], { + stroke: 'black', + strokeWidth: 1, + selectable: false, + name: 'outerLine', + }) + + line.setViewLengthText(true) + + canvas?.add(line) + } + + const keydown = (e) => { + const key = e.key + + const lengthNum = Number(length1Ref.current.value) + if (lengthNum === 0) { + return + } + switch (key) { + case 'Down': // IE/Edge에서 사용되는 값 + case 'ArrowDown': + setArrow1('↓') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y + lengthNum }] + }) + break + case 'Up': // IE/Edge에서 사용되는 값 + case 'ArrowUp': + setArrow1('↑') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x, y: prev[prev.length - 1].y - lengthNum }] + }) + break + case 'Left': // IE/Edge에서 사용되는 값 + case 'ArrowLeft': + setArrow1('←') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x - lengthNum, y: prev[prev.length - 1].y }] + }) + break + case 'Right': // IE/Edge에서 사용되는 값 + case 'ArrowRight': + setArrow1('→') + setPoints((prev) => { + if (prev.length === 0) { + return [] + } + return [...prev, { x: prev[prev.length - 1].x + lengthNum, y: prev[prev.length - 1].y }] + }) + break + } + } + + /** + * 일변전으로 돌아가기 + */ + const handleRollback = () => { + //points의 마지막 요소를 제거 + setPoints((prev) => prev.slice(0, prev.length - 1)) + } + + const handleClickClose = () => { + setModalOption({ ...modalOption, outerwall: false }) + } + + const handleFix = () => {} return ( -
+

{getMessage('modal.cover.outline.drawing')}

-
- - - - -

{getMessage('modal.cover.outline.setting')}

-
-
- - + {type === OUTER_LINE_TYPE.OUTER_LINE ? ( +
+
+ + { + setLength1(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
+
+ + +
-
- - -
-
+ ) : ( + <> + )}
- -
+ ) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? ( +
+
+ + { + setLength1(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
+
+ + +
+
+ + { + setLength2(e.target.value.replace(/[^-0-9]/g, '')) + }} + placeholder="3000" + /> +
+
+ + +
+
) : ( <> )} From b59bdd0645af5dc358da958ef892f3e78790658d Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 12 Sep 2024 17:45:40 +0900 Subject: [PATCH 7/7] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../[locale]/management/stuff/detail/page.jsx | 4 + .../management/stuff/tempdetail/page.jsx | 15 + src/components/management/Stuff.jsx | 150 ++++++---- src/components/management/StuffDetail.jsx | 272 +++++++++++------- .../management/StuffSearchCondition.jsx | 50 +++- src/locales/ko.json | 2 +- src/store/stuffAtom.js | 4 + 7 files changed, 340 insertions(+), 157 deletions(-) create mode 100644 src/app/[locale]/management/stuff/tempdetail/page.jsx diff --git a/src/app/[locale]/management/stuff/detail/page.jsx b/src/app/[locale]/management/stuff/detail/page.jsx index 8b84287a..6759b282 100644 --- a/src/app/[locale]/management/stuff/detail/page.jsx +++ b/src/app/[locale]/management/stuff/detail/page.jsx @@ -1,11 +1,15 @@ import React from 'react' import Hero from '@/components/Hero' import StuffDetail from '@/components/management/StuffDetail' +import Link from 'next/link' export default function ManagementStuffDetailPage() { return ( <>

물건정보

+ +

도면작성

+
diff --git a/src/app/[locale]/management/stuff/tempdetail/page.jsx b/src/app/[locale]/management/stuff/tempdetail/page.jsx new file mode 100644 index 00000000..8b84287a --- /dev/null +++ b/src/app/[locale]/management/stuff/tempdetail/page.jsx @@ -0,0 +1,15 @@ +import React from 'react' +import Hero from '@/components/Hero' +import StuffDetail from '@/components/management/StuffDetail' +export default function ManagementStuffDetailPage() { + return ( + <> +
+

물건정보

+
+
+ +
+ + ) +} diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index cf427814..e445fa1d 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -6,7 +6,7 @@ import { Button } from '@nextui-org/react' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import StuffQGrid from './StuffQGrid' -import { useRecoilValue } from 'recoil' +import { useRecoilValue, useRecoilState } from 'recoil' import { stuffSearchState } from '@/store/stuffAtom' import { queryStringFormatter, isEmptyArray } from '@/util/common-utils' import dayjs from 'dayjs' @@ -15,10 +15,12 @@ dayjs.extend(isLeapYear) export default function Stuff() { const stuffSearchParams = useRecoilValue(stuffSearchState) + const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const { getMessage } = useMessage() const [curPage, setCurPage] = useState(1) //현재 페이지 번호 - const [size, setSize] = useState(100) //페이지 당 게시물 수 - const { get, del } = useAxios() + const [defaultSize, setDefaultSize] = useState(100) //페이지 당 게시물 수 + const [defaultSortType, setDefaultSortType] = useState('R') + const { get } = useAxios() const gridRef = useRef() const [gridCount, setGridCount] = useState(0) @@ -38,13 +40,26 @@ export default function Stuff() { } } + //물건번호 복사버튼 옆에 영역 + const onDoubleClick = (e) => { + let objectNo = e.target.innerText + console.log(objectNo) + if (objectNo.substring(0, 1) === 'R') { + console.log('진짜') + router.push(`${pathname}/detail?objectNo=${objectNo.toString()}`) + } else { + console.log('임시') + router.push(`${pathname}/tempdetail?objectNo=${objectNo.toString()}`) + } + } + const [gridProps, setGridProps] = useState({ gridData: [], isPageable: false, // sets 10 rows per page (default is 100) - paginationPageSize: 100, + // paginationPageSize: 100, // allows the user to select the page size from a predefined list of page sizes - paginationPageSizeSelector: [100, 200, 300, 400], + // paginationPageSizeSelector: [100, 200, 300, 400], gridColumns: [ { field: 'lastEditDatetime', @@ -82,7 +97,6 @@ export default function Stuff() {
- {params.value} + {params.value}
) } @@ -148,8 +162,15 @@ export default function Stuff() { return } else { console.log(' 상세이동::::::::', event.data) + //T 면 임시 R은 진짜 if (event.data.objectNo) { - router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`) + if (event.data.objectNo.substring(0, 1) === 'R') { + console.log('진짜:::::::::') + router.push(`${pathname}/detail?objectNo=${event.data.objectNo.toString()}`) + } else { + console.log('임시:::::::::::::::::') + router.push(`${pathname}/tempdetail?objectNo=${event.data.objectNo.toString()}`) + } } } } @@ -175,45 +196,6 @@ export default function Stuff() { errCount++ } }) - - async function fetchDelete(data) { - console.log('물건삭제API호출!!!!!!!!!', data) - //행추가말고 api데이터만 보냄 - // let newData = data.filter((item) => item.company != null) - // console.log('삭제에 전송되는 데이타::', newData) - // await del({ url: '', data:newData }) - await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' }) - // try { - // const res = await del({url:'', data:newData}) - - // if(!res || res.length === 0) { - - // } else { - fetchData() - // } - // } catch (error) { - // console.error('Data Delete error:', error); - // } - } - - // 삭제API 완료 후 fetchData Api호출 - async function fetchData() { - console.log('물건삭제후 조회API호출!!!!!!!!!!!!!', stuffSearchParams) - const data = await get({ url: 'https://www.ag-grid.com/example-assets/space-mission-data.json' }) - setGridProps({ ...gridProps, gridData: data, count: data.length }) - setGridCount(data.length) - //data.length = 10 - //setGridProps({ ...gridProps, gridData: data, count: data.length-1}) - //setGridCount(data.length - 1 ) - } - - if (errCount === 0) { - // console.log('errCount::::::::', errCount) - fetchDelete(data) - // fetchData() - } else { - alert('물건정보가 있는 행만 선택해주세요') - } } //행추가 @@ -265,15 +247,14 @@ export default function Stuff() { schDateType: 'U', schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'), - startRow: (curPage - 1) * size + 1, - endRow: curPage * size, + startRow: (curPage - 1) * defaultSize + 1, + endRow: curPage * defaultSize, + schSelSaleStoreId: '', + schSortType: 'R', } async function fetchData() { console.log('화면진입:::::::::::::', params) - console.log('현재페이지::::::', curPage) - console.log('페이지당 게시물수::::::', size) - //api에 넘길값 startRow, endRow // let startRow // let endRow @@ -306,6 +287,9 @@ export default function Stuff() { useEffect(() => { if (stuffSearchParams?.code === 'E') { + stuffSearchParams.startRow = (curPage - 1) * defaultSize + 1 + stuffSearchParams.endRow = curPage * defaultSize + stuffSearchParams.schSortType = defaultSortType console.log('조회 눌럿을때 ::::::::::::::', stuffSearchParams) async function fetchData() { const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` @@ -314,6 +298,9 @@ export default function Stuff() { if (!isEmptyArray(res)) { setGridProps({ ...gridProps, gridData: res, count: res.length }) setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) } }) } @@ -321,6 +308,56 @@ export default function Stuff() { } }, [stuffSearchParams]) + //페이지 갯수 변경 이벤트 + const onChangePerPage = (e) => { + let startRow = (curPage - 1) * e.target.value + 1 + stuffSearchParams.startRow = startRow + stuffSearchParams.endRow = curPage * e.target.value + setDefaultSize(e.target.value) + setStuffSearch({ + ...stuffSearch, + code: 'S', + startRow: startRow, + endRow: curPage * e.target.value, + }) + console.log('셋팅된 검색조건:::', stuffSearchParams) + //조회API호출 + const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + get({ url: apiUrl }).then((res) => { + console.log('보여줄개수바꿨을때 조회 ::::::::::', res) + if (!isEmptyArray(res)) { + setGridProps({ ...gridProps, gridData: res, count: res.length }) + setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) + } + }) + } + + //최근 등록일 수정일 정렬 이벤트 + const onChangeSortType = (e) => { + stuffSearchParams.schSortType = e.target.value + console.log('셋팅된 검색조건:::', stuffSearchParams) + setDefaultSortType(e.target.value) + setStuffSearch({ + ...stuffSearch, + code: 'S', + schSortType: e.target.value, + }) + const apiUrl = `/api/object/list?saleStoreId=201TES01&${queryStringFormatter(stuffSearchParams)}` + // console.log('apiUrl::', apiUrl) + get({ url: apiUrl }).then((res) => { + console.log('정렬바꿨을때 조회 ::::::::::', res) + if (!isEmptyArray(res)) { + setGridProps({ ...gridProps, gridData: res, count: res.length }) + setGridCount(res.length) + } else { + setGridProps({ ...gridProps, gridData: [], count: 0 }) + setGridCount(0) + } + }) + } return ( <>
@@ -328,6 +365,15 @@ export default function Stuff() { 전체 : {gridCount} // 선택 : {selectedRowDataCount} + +
{/*
{!isFormValid ? ( <> - {/* */} - + ) : ( - + )} - + )) || ( -
- 상세::::::::::: - - - -
+ <> + {objectNo.substring(0, 1) === 'R' ? ( + <> + + + + + + + ) : ( + <> + + + + + + )} + + //
+ // EDIT모드 + + // {/* {objectNo.substring(0,1) ? 'R' ? <>RRRRRRR : <>TTTTTTTT} */} + // {/* + // + // + // + // */} + //
)} {/*
diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index f0d665d0..58aa4ce9 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -2,10 +2,12 @@ import React, { useEffect } from 'react' import { useState } from 'react' -import { Input, RadioGroup, Radio, Button } from '@nextui-org/react' +import { Input, RadioGroup, Radio, Button, Autocomplete, AutocompleteItem } from '@nextui-org/react' import RangeDatePicker from '@/components/common/datepicker/RangeDatePicker' import { useRecoilState, useResetRecoilState } from 'recoil' import { stuffSearchState } from '@/store/stuffAtom' +import { isEmptyArray } from '@/util/common-utils' +import { get } from '@/lib/Axios' import dayjs from 'dayjs' import isLeapYear from 'dayjs/plugin/isLeapYear' // 윤년 판단 플러그인 dayjs.extend(isLeapYear) @@ -33,13 +35,16 @@ export default function StuffSearchCondition() { const [receiveUser, setReceiveUser] = useState('') //담당자 const [dispCompanyName, setDispCompanyName] = useState('') //견적처 const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R) + const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //판매대리점 선택 + const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT // 조회 const onSubmit = () => { let diff = dayjs(endRangeDate).diff(startRangeDate, 'day') if (diff > 366) { return alert('최대1년 조회 가능합니다.') } + setStuffSearch({ schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo, schSaleStoreId: stuffSearch?.schSaleStoreId ? stuffSearch.schSaleStoreId : saleStoreId, @@ -53,6 +58,10 @@ export default function StuffSearchCondition() { schFromDt: dayjs(startRangeDate).format('YYYY-MM-DD'), schToDt: dayjs(endRangeDate).format('YYYY-MM-DD'), code: 'E', + schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : schSelSaleStoreId, + startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, + endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, + schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', }) } @@ -68,9 +77,31 @@ export default function StuffSearchCondition() { setDispCompanyName('') setDateType('U') setDateRange([dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), dayjs(new Date()).format('YYYY-MM-DD')]) + setSchSelSaleStoreId('') resetStuffRecoil() } + useEffect(() => { + get({ url: `/api/object/saleStore/201TES01/list` }).then((res) => { + if (!isEmptyArray(res)) { + // console.log('판매점 결과:::::', res) + setSchSelSaleStoreList(res) + } + }) + }, []) + + //판매대리점 자동완성 변경 + const onSelectionChange = (key) => { + // console.log('자동완성값변경', key) + if (key == null) { + setSchSelSaleStoreId('') + setStuffSearch({ ...stuffSearch, schSelSaleStoreId: '' }) + } else { + setSchSelSaleStoreId(key) + setStuffSearch({ ...stuffSearch, schSelSaleStoreId: key }) + } + } + //x로 날짜 비웠을때 기본값으로 셋팅 useEffect(() => { if (!startRangeDate && !endRangeDate) { @@ -88,7 +119,7 @@ export default function StuffSearchCondition() { return ( <>
- +
@@ -220,6 +251,17 @@ export default function StuffSearchCondition() { setStuffSearch({ ...stuffSearch, code: 'S', schDispCompanyName: e.target.value }) }} /> + {schSelSaleStoreList?.length > 0 && ( + + {(option) => {option.saleStoreName}} + + )}
) } else { diff --git a/src/locales/ko.json b/src/locales/ko.json index cf7d758f..82b187bc 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -118,7 +118,7 @@ "common.message.multi.insert": "Total {0} cases ({1} successes, {2} failures {3})", "common.message.error": "Error occurred, please contact site administrator.", "common.message.data.save": "Do you want to save it?", - "common.message.data.delete": "Do you want to delete it?", + "common.message.data.delete": "정말로 삭제하시겠습니까?", "common.message.data.exists": "{0} is data that already exists.", "common.message.data.no.exists": "{0} is data that does not exist.", "common.message.all": "All", diff --git a/src/store/stuffAtom.js b/src/store/stuffAtom.js index a122543c..5de2c04e 100644 --- a/src/store/stuffAtom.js +++ b/src/store/stuffAtom.js @@ -17,6 +17,10 @@ export const stuffSearchState = atom({ schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일 schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일 code: 'S', + schSelSaleStoreId: '', //판매대리점 선택 + startRow: 1, + endRow: 100, + schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일) }, dangerouslyAllowMutability: true, })