From 0f97344d0a701eb24ddfbb4f8a1fbeded1c4578b Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Fri, 18 Oct 2024 10:30:06 +0900 Subject: [PATCH 001/139] =?UTF-8?q?refactor:=20CanvasLayout=20=EC=BB=B4?= =?UTF-8?q?=ED=8F=AC=EB=84=8C=ED=8A=B8=20=EB=82=B4=20sesion=20=EC=88=98?= =?UTF-8?q?=EC=A0=95,=20=EC=8B=A0=EA=B7=9C=20plan=20id=EB=A5=BC=20uuid?= =?UTF-8?q?=EB=A1=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasLayout.jsx | 10 +++------- src/hooks/usePlan.js | 6 ++++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 7c84705c..405d5106 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -7,14 +7,11 @@ import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { usePlan } from '@/hooks/usePlan' import { globalLocaleStore } from '@/store/localeAtom' -import { sessionStore } from '@/store/commonAtom' import { SessionContext } from '@/app/SessionProvider' export default function CanvasLayout() { const { session } = useContext(SessionContext) - console.log('session >>> ', session) const [objectNo, setObjectNo] = useState('test123240822001') // 이후 삭제 필요 - const sessionState = useRecoilValue(sessionStore) const globalLocaleState = useRecoilValue(globalLocaleStore) const { getMessage } = useMessage() @@ -22,8 +19,7 @@ export default function CanvasLayout() { const { plans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() useEffect(() => { - console.log('loadCanvasPlanData 실행, sessionState.userId >>> ', sessionState.userId) - loadCanvasPlanData(sessionState.userId, objectNo) + loadCanvasPlanData(session.userId, objectNo) }, []) return ( @@ -34,7 +30,7 @@ export default function CanvasLayout() { )} diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 8afb2060..b1273d82 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react' import { useRecoilState } from 'recoil' +import { v4 as uuidv4 } from 'uuid' import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState } from '@/store/canvasAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' @@ -269,15 +270,16 @@ export function usePlan() { : addPlan(userId, objectNo) } const addPlan = (userId, objectNo, canvasStatus = '') => { + const id = uuidv4() const newPlan = { - id: planNum, + id: id, name: `Plan ${planNum + 1}`, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, } setPlans([...plans, newPlan]) - handleCurrentPlan(userId, planNum) + handleCurrentPlan(userId, id) setPlanNum(planNum + 1) } From 15af4655a3b76c8c6409aec21b5e1cfaf8eee94a Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 18 Oct 2024 13:36:32 +0900 Subject: [PATCH 002/139] =?UTF-8?q?popupManager=20=EA=B0=9C=EB=B0=9C=20?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/layout.js | 2 + src/components/Roof2.jsx | 2 +- .../common/color-picker/ColorPicker.jsx | 23 +- .../common/color-picker/ColorPickerModal.jsx | 44 +++ src/components/common/font/FontSetting.jsx | 69 +++++ .../common/popupManager/PopupManager.jsx | 8 + src/components/floor-plan/CanvasFrame.jsx | 21 +- src/components/floor-plan/CanvasMenu.jsx | 25 +- src/components/floor-plan/FloorPlan.jsx | 23 +- .../modal/auxiliary/AuxiliaryDrawing.jsx | 4 +- .../modal/grid/GridColorSetting.jsx | 39 --- .../floor-plan/modal/setting01/GridOption.jsx | 41 ++- .../modal/setting01/SecondOption.jsx | 32 ++- .../modal/setting01/SettingModal01.jsx | 56 ++-- .../dimensionLine/DimensionLineSetting.jsx | 51 ++++ src/hooks/useCanvasEvent.js | 15 +- src/hooks/useContextMenu.js | 128 ++++++++- src/hooks/usePopup.js | 26 ++ src/locales/ja.json | 2 + src/locales/ko.json | 2 + src/store/popupAtom.js | 13 + src/styles/_modal.scss | 265 +++++++++++++++++- 22 files changed, 784 insertions(+), 107 deletions(-) create mode 100644 src/components/common/color-picker/ColorPickerModal.jsx create mode 100644 src/components/common/font/FontSetting.jsx create mode 100644 src/components/common/popupManager/PopupManager.jsx delete mode 100644 src/components/floor-plan/modal/grid/GridColorSetting.jsx create mode 100644 src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx create mode 100644 src/hooks/usePopup.js create mode 100644 src/store/popupAtom.js diff --git a/src/app/layout.js b/src/app/layout.js index d27522fe..0e9a797c 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -15,6 +15,7 @@ import './globals.css' import '../styles/style.scss' import '../styles/contents.scss' import Dimmed from '@/components/ui/Dimmed' +import PopupManager from '@/components/common/popupManager/PopupManager' // const inter = Inter({ subsets: ['latin'] }) @@ -81,6 +82,7 @@ export default async function RootLayout({ children }) { )} + diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index fbe61038..cc690ba9 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,7 +39,7 @@ import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMen import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { changeAllHipAndGableRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' +import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' import ObjectPlacement from '@/components/ui/ObjectPlacement' import { globalLocaleStore } from '@/store/localeAtom' diff --git a/src/components/common/color-picker/ColorPicker.jsx b/src/components/common/color-picker/ColorPicker.jsx index 7e774259..fe48272b 100644 --- a/src/components/common/color-picker/ColorPicker.jsx +++ b/src/components/common/color-picker/ColorPicker.jsx @@ -1,11 +1,30 @@ import { HexColorPicker } from 'react-colorful' +import { useMessage } from '@/hooks/useMessage' export default function ColorPicker(props) { const { color, setColor } = props - + const { getMessage } = useMessage() + const defaultColors = ['#EA575D', '#F29955', '#F2C957', '#32975D', '#3D7FED', '#828282', '#ffffff', '#000000'] return ( <> - +
+ +
+
+
HEX
+
+ setColor(e.target.value)} /> +
+
+
+
+
{getMessage('modal.color.picker.default.color')}
+
+ {defaultColors.map((color, index) => ( + + ))} +
+
) } diff --git a/src/components/common/color-picker/ColorPickerModal.jsx b/src/components/common/color-picker/ColorPickerModal.jsx new file mode 100644 index 00000000..0f81d99f --- /dev/null +++ b/src/components/common/color-picker/ColorPickerModal.jsx @@ -0,0 +1,44 @@ +import WithDraggable from '@/components/common/draggable/WithDraggable' +import ColorPicker from '@/components/common/color-picker/ColorPicker' +import { useMessage } from '@/hooks/useMessage' +import { useEffect, useState } from 'react' + +export default function ColorPickerModal(props) { + const { isShow, setIsShow, pos = { x: 800, y: -950 }, color = '#ff0000', setColor } = props + const { getMessage } = useMessage() + const [originColor, setOriginColor] = useState(color) + useEffect(() => { + setOriginColor(color) + }, [isShow]) + return ( + +
+
+

{getMessage('modal.color.picker.title')}

+ +
+
+
+
COLOR PICKER
+
+ +
+
+
+ +
+
+
+
+ ) +} diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx new file mode 100644 index 00000000..aaeb7b02 --- /dev/null +++ b/src/components/common/font/FontSetting.jsx @@ -0,0 +1,69 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' +import QSelectBox from '@/components/common/select/QSelectBox' + +const SelectOption = [{ name: '原寸' }, { name: '原寸' }, { name: '原寸' }, { name: '原寸' }] +export default function FontSetting(props) { + const { setShowFontSettingModal } = props + console.log( + Array.from({ length: 10 }).map((_, index) => { + return { name: 5 + index } + }), + ) + return ( + +
+
+

フォント

+ +
+
+
+
+
+
文字(F)
+
+ +
+
+
+
フォントスタイル(Y)
+
+ +
+
+
+
サイズ(S)
+
+ { + return { id: index, name: 8 * (index + 1) } + })} + /> +
+
+
+
フォン
+
+ +
+
+
+
+
見る
+
+ Aaあぁアァ +
+
+
ントです。プリンタと画面 でも同じフォントを使用します.
+
+
+ +
+
+
+
+ ) +} diff --git a/src/components/common/popupManager/PopupManager.jsx b/src/components/common/popupManager/PopupManager.jsx new file mode 100644 index 00000000..cc6ce224 --- /dev/null +++ b/src/components/common/popupManager/PopupManager.jsx @@ -0,0 +1,8 @@ +'use client' +import { useRecoilState } from 'recoil' +import { popupState } from '@/store/popupAtom' + +export default function PopupManager() { + const [popup, setPopup] = useRecoilState(popupState) + return <>{popup.children?.map((child) => child.component)} +} diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index f34d1cb6..9b17b1f0 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -8,11 +8,18 @@ import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useContextMenu } from '@/hooks/useContextMenu' import { useRecoilValue } from 'recoil' import { currentObjectState } from '@/store/canvasAtom' +import { useCanvasEvent } from '@/hooks/useCanvasEvent' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) const { canvas } = useCanvas('canvas') - const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu() + const { handleZoomClear } = useCanvasEvent() + const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu({ + externalFn: { + handleZoomClear, + }, + }) + const currentObject = useRecoilValue(currentObjectState) useEffect(() => { @@ -44,7 +51,17 @@ export default function CanvasFrame({ plan }) { {contextMenu.map((menus, index) => (
    {menus.map((menu) => ( -
  • setCurrentContextMenu(menu)}>{menu.name}
  • +
  • { + if (menu.fn) { + menu.fn() + } + setCurrentContextMenu(menu) + }} + > + {menu.name} +
  • ))}
))} diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index ae8cc79d..61bfb0ae 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -19,6 +19,10 @@ import { MENU } from '@/common/common' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import { settingModalFirstOptionsState } from '@/store/settingAtom' +import { useCanvasEvent } from '@/hooks/useCanvasEvent' +import { popupState } from '@/store/popupAtom' +import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' +import { usePopup } from '@/hooks/usePopup' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -52,6 +56,7 @@ export default function CanvasMenu(props) { setShowPropertiesSettingModal, } = props + const { addPopup, closePopup } = usePopup() const [menuNumber, setMenuNumber] = useState(null) const [type, setType] = useState('') @@ -61,6 +66,7 @@ export default function CanvasMenu(props) { const setPoints = useSetRecoilState(outerLinePointsState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) + const { handleZoomClear } = useCanvasEvent() const globalLocale = useRecoilValue(globalLocaleStore) const canvas = useRecoilValue(canvasState) @@ -69,7 +75,7 @@ export default function CanvasMenu(props) { const { getMessage } = useMessage() const { saveCanvas } = usePlan() const { swalFire } = useSwal() - + const [popup, setPopup] = useRecoilState(popupState) const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const onClickNav = (menu) => { setMenuNumber(menu.index) @@ -143,13 +149,13 @@ export default function CanvasMenu(props) { setPoints([]) canvas?.clear() } - - const handleZoomClear = () => { - setCanvasZoom(100) - canvas.set({ zoom: 1 }) - canvas.viewportTransform = [1, 0, 0, 1, 0, 0] - canvas.renderAll() - } + // + // const handleZoomClear = () => { + // setCanvasZoom(100) + // canvas.set({ zoom: 1 }) + // canvas.viewportTransform = [1, 0, 0, 1, 0, 0] + // canvas.renderAll() + // } useEffect(() => { if (globalLocale === 'ko') { @@ -196,7 +202,8 @@ export default function CanvasMenu(props) {
- + {/**/} +
diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index b8ea7784..4d70ee0c 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -1,19 +1,17 @@ 'use client' import { useEffect, useState } from 'react' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' -import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { settingModalFirstOptionsState, settingModalGridOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import '@/styles/contents.scss' import CanvasMenu from '@/components/floor-plan/CanvasMenu' -import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' import CanvasLayout from '@/components/floor-plan/CanvasLayout' import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid' import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' -import GridColorSetting from './modal/grid/GridColorSetting' import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' import Slope from '@/components/floor-plan/modal/Slope' @@ -28,6 +26,8 @@ import MovementSetting from '@/components/floor-plan/modal/movement/MovementSett import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' +import FontSetting from '@/components/common/font/FontSetting' +import { gridColorState } from '@/store/gridAtom' export default function FloorPlan() { const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false) @@ -58,10 +58,15 @@ export default function FloorPlan() { const [showGridCopyModal, setShowGridCopyModal] = useState(false) const [showGridMoveModal, setShowGridMoveModal] = useState(false) const [showColorPickerModal, setShowColorPickerModal] = useState(false) + const [color, setColor] = useRecoilState(gridColorState) + const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) + const [showFontSettingModal, setShowFontSettingModal] = useState(false) + const canvasSettingProps = { setShowCanvasSettingModal, setShowDotLineGridModal, setShowColorPickerModal, + setShowFontSettingModal, } const outlineProps = { @@ -127,6 +132,9 @@ export default function FloorPlan() { const gridColorProps = { setShowColorPickerModal, + color, + setColor, + setSettingModalGridOptions, } const propertiesSettingProps = { @@ -141,12 +149,13 @@ export default function FloorPlan() {
- {showCanvasSettingModal && } + {/*{showCanvasSettingModal && }*/} {showOutlineModal && } {showDotLineGridModal && } - {showColorPickerModal && } + {/*{showColorPickerModal && }*/} + {showFontSettingModal && } {showPropertiesSettingModal && } - + {/**/} {showPlaceShapeModal && } {showRoofShapeSettingModal && } {showRoofShapePassivitySettingModal && ( diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx index d0f87114..2aa5cd84 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx @@ -1,4 +1,3 @@ -import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import RightAngle from '@/components/floor-plan/modal/lineTypes/RightAngle' @@ -6,7 +5,6 @@ import DoublePitch from '@/components/floor-plan/modal/lineTypes/DoublePitch' import Angle from '@/components/floor-plan/modal/lineTypes/Angle' import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' -import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' import { useAuxiliaryDrawing } from '@/hooks/roofcover/useAuxiliaryDrawing' @@ -152,7 +150,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { {getMessage('modal.cover.outline.rollback')}
diff --git a/src/components/floor-plan/modal/grid/GridColorSetting.jsx b/src/components/floor-plan/modal/grid/GridColorSetting.jsx deleted file mode 100644 index 5b7b2ff6..00000000 --- a/src/components/floor-plan/modal/grid/GridColorSetting.jsx +++ /dev/null @@ -1,39 +0,0 @@ -import WithDraggable from '@/components/common/draggable/WithDraggable' -import ColorPicker from '@/components/common/color-picker/ColorPicker' -import { useRecoilState, useSetRecoilState } from 'recoil' -import { gridColorState } from '@/store/gridAtom' -import { useMessage } from '@/hooks/useMessage' -import { useEffect } from 'react' -import { settingModalGridOptionsState } from '@/store/settingAtom' - -export default function GridColorSetting(props) { - const { setShowColorPickerModal } = props - const [color, setColor] = useRecoilState(gridColorState) - const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) - const { getMessage } = useMessage() - - useEffect(() => { - return () => { - setSettingModalGridOptions((prev) => { - const newSettingOptions = [...prev] - newSettingOptions[3].selected = false - return [...newSettingOptions] - }) - } - }, []) - return ( - -
-
-

{getMessage('modal.canvas.setting.grid.color.setting')}

- -
-
- -
-
-
- ) -} diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index 39af3a10..efa7d099 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -1,27 +1,45 @@ -import React, { useEffect } from 'react' -import { useRecoilState } from 'recoil' +import React, { useEffect, useState } from 'react' +import { useRecoilState, useSetRecoilState } from 'recoil' import { settingModalGridOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import { adsorptionPointAddModeState } from '@/store/canvasAtom' import { useTempGrid } from '@/hooks/useTempGrid' import { gridColorState } from '@/store/gridAtom' import { useColor } from 'react-color-palette' +import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' export default function GridOption(props) { - const { setShowDotLineGridModal, setShowColorPickerModal } = props + const { setShowDotLineGridModal } = props const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState) - const [gridColor, setGridColor] = useRecoilState(gridColorState) const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState) + const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) const { getMessage } = useMessage() const { tempGridMode, setTempGridMode } = useTempGrid() - + const [gridColor, setGridColor] = useRecoilState(gridColorState) const [color, setColor] = useColor(gridColor) + const [showColorPickerModal, setShowColorPickerModal] = useState(false) useEffect(() => { console.log('GridOption useEffect 실행') + console.log(color) setGridColor(color.hex) }, [color]) + useEffect(() => { + gridOptions[3].selected = showColorPickerModal + setGridOptions([...gridOptions]) + }, [showColorPickerModal]) + + useEffect(() => { + return () => { + setSettingModalGridOptions((prev) => { + const newSettingOptions = [...prev] + newSettingOptions[3].selected = false + return [...newSettingOptions] + }) + } + }, []) + const onClickOption = (option) => { const newGridOptions = [...gridOptions] newGridOptions.map((item) => { @@ -54,6 +72,7 @@ export default function GridOption(props) { if (option.id === 4) { // 그리드 색 설정 + console.log(option) if (option.selected) { setShowColorPickerModal(true) } else { @@ -64,6 +83,17 @@ export default function GridOption(props) { setGridOptions(newGridOptions) } + const colorPickerProps = { + color: gridColor, + setColor: setGridColor, + isShow: showColorPickerModal, + setIsShow: setShowColorPickerModal, + pos: { + x: -515, + y: -214, + }, + } + return ( <>
@@ -77,6 +107,7 @@ export default function GridOption(props) { ))}
+ ) } diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index f6cf6e30..05d20c11 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -5,8 +5,9 @@ import React, { useEffect, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' +import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting' -export default function SecondOption() { +export default function SecondOption({ setShowFontSettingModal }) { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) @@ -18,6 +19,15 @@ export default function SecondOption() { const { getMessage } = useMessage() const { get, post } = useAxios() const { swalFire } = useSwal() + const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) + const dimensionLineSettingProps = { + isShow: showDimensionLineSettingModal, + setIsShow: setShowDimensionLineSettingModal, + pos: { + x: -515, + y: -214, + }, + } // 데이터를 최초 한 번만 조회 useEffect(() => { @@ -31,7 +41,10 @@ export default function SecondOption() { const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) - const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] })) + const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ + ...item, + selected: res[item.column], + })) const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) @@ -51,7 +64,14 @@ export default function SecondOption() { const onClickOption = async (option) => { // option4에서 한 개만 선택 가능하도록 처리 - const updatedOption4 = option4.map((item) => (item.id === option.id ? { ...item, selected: true } : { ...item, selected: false })) + const updatedOption4 = option4.map((item) => + item.id === option.id + ? { ...item, selected: true } + : { + ...item, + selected: false, + }, + ) setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) setSettingModalSecondOptions({ option3, option4: updatedOption4 }) @@ -117,6 +137,7 @@ export default function SecondOption() { } setAdsorptionRange(option.range) } + return ( <>
@@ -124,7 +145,7 @@ export default function SecondOption() {
{settingModalSecondOptions && settingModalSecondOptions.option3.map((item) => ( - ))} @@ -142,7 +163,7 @@ export default function SecondOption() { ))}
-
+ ) } diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index 78511548..98542c36 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -10,7 +10,7 @@ import { canGridOptionSeletor } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' export default function SettingModal01(props) { - const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowColorPickerModal } = props + const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowFontSettingModal } = props const [buttonAct, setButtonAct] = useState(1) const { getMessage } = useMessage() const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor) @@ -20,34 +20,36 @@ export default function SettingModal01(props) { } return ( - -
-
-

{getMessage('modal.canvas.setting')}

- -
-
-
- - - - {canGridOptionSeletorValue && ( - - )}
- {buttonAct === 1 && } - {buttonAct === 2 && } - {buttonAct === 3 && } +
+
+ + + + {canGridOptionSeletorValue && ( + + )} +
+ {buttonAct === 1 && } + {buttonAct === 2 && } + {buttonAct === 3 && } +
-
-
+ + ) } diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx new file mode 100644 index 00000000..a17cc22e --- /dev/null +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -0,0 +1,51 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' + +export default function DimensionLineSetting(props) { + const { isShow, setIsShow, pos = { x: 800, y: -950 }, setShowFontSettingModal, setShowColorPickerModal } = props + return ( + +
+
+

寸法線 設定

+ +
+
+
+ +
+
+
+ 寸法線の線太さ +
+ +
+ pixel +
+
+ 寸法線の線の色 + +
+
+
+
見る
+
+
+
+ + 9,999 + + +
+
+
+
+
+ +
+
+
+
+ ) +} diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index cf3b6244..4f041e79 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,15 +1,17 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' -import { canvasSizeState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' // 캔버스에 필요한 이벤트 export function useCanvasEvent() { - const [canvas, setCanvasForEvent] = useState(null) + const canvas = useRecoilValue(canvasState) + const [canvasForEvent, setCanvasForEvent] = useState(null) const [currentObject, setCurrentObject] = useRecoilState(currentObjectState) const canvasSize = useRecoilValue(canvasSizeState) const fontSize = useRecoilValue(fontSizeState) const fontFamily = useRecoilValue(fontFamilyState) + const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { @@ -167,7 +169,6 @@ export function useCanvasEvent() { const whiteList = ['mouseLine', 'guideLine'] if (whiteList.includes(e.target.name)) { - return } }, } @@ -336,8 +337,16 @@ export function useCanvasEvent() { }) } + const handleZoomClear = () => { + setCanvasZoom(100) + canvas.set({ zoom: 1 }) + canvas.viewportTransform = [1, 0, 0, 1, 0, 0] + canvas.renderAll() + } + return { setCanvasForEvent, attachDefaultEventOnCanvas, + handleZoomClear, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 665617ef..3fb6f164 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -1,16 +1,18 @@ import { useRecoilValue } from 'recoil' -import { currentMenuState } from '@/store/canvasAtom' +import { currentMenuState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' import { MENU } from '@/common/common' import AuxiliaryMove from '@/components/floor-plan/modal/auxiliary/AuxiliaryMove' import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize' -export function useContextMenu() { +export function useContextMenu({ externalFn }) { const currentMenu = useRecoilValue(currentMenuState) const [contextMenu, setContextMenu] = useState([[]]) const [currentContextMenu, setCurrentContextMenu] = useState(null) + const currentObject = useRecoilValue(currentObjectState) - useEffect(() => { + const currentMenuSetting = () => { + console.log(currentMenu) switch (currentMenu) { case MENU.PLAN_DRAWING: setContextMenu([ @@ -50,6 +52,13 @@ export function useContextMenu() { case MENU.ROOF_COVERING.DEFAULT: setContextMenu([ [ + { + id: 'refresh', + name: '새로고침', + fn: () => { + externalFn.handleZoomClear() + }, + }, { id: 'roofMaterialPlacement', name: '지붕재 배치', @@ -150,8 +159,121 @@ export function useContextMenu() { setContextMenu([]) break } + } + useEffect(() => { + currentMenuSetting() }, [currentMenu]) + useEffect(() => { + console.log('currentObject', currentObject) + console.log('currentMenu', currentMenu) + if (currentObject?.name) { + console.log(currentObject) + switch (currentObject.name) { + case 'triangleDormer': + setContextMenu([ + [ + { + id: 'sizeEdit', + name: '사이즈 변경', + }, + { + id: 'dormerRemove', + name: '삭제(D)', + }, + { + id: 'dormerMove', + name: '이동(M)', + }, + { + id: 'dormerCopy', + name: '복사(C)', + }, + { + id: 'roofMaterialEdit', + name: '지붕재 변경', + }, + { + id: 'dormerOffset', + name: '도머 오프셋', + }, + ], + ]) + break + case 'roof': + setContextMenu([ + [ + { + id: 'sizeEdit', + name: '사이즈 변경', + }, + { + id: 'roofMaterialRemove', + name: '삭제(D)', + }, + { + id: 'roofMaterialMove', + name: '이동(M)', + }, + { + id: 'roofMaterialCopy', + name: '복사(C)', + }, + ], + [ + { + id: 'roofMaterialEdit', + name: '지붕재 변경', + }, + { + id: 'linePropertyEdit', + name: '각 변 속성 변경', + }, + { + id: 'flowDirectionEdit', + name: '흐름 뱡향 변경', + }, + ], + ]) + break + case 'opening': + setContextMenu([ + [ + { + id: 'sizeEdit', + name: '사이즈 변경', + }, + { + id: 'openingRemove', + name: '삭제(D)', + }, + { + id: 'openingMove', + name: '이동(M)', + }, + { + id: 'openingCopy', + name: '복사(C)', + }, + { + id: 'openingOffset', + name: '개구 오프셋', + }, + ], + ]) + break + default: + currentMenuSetting() + } + } else { + currentMenuSetting() + } + }, [currentObject]) + + useEffect(() => { + console.log(currentContextMenu) + }, [currentContextMenu]) + return { contextMenu, currentContextMenu, diff --git a/src/hooks/usePopup.js b/src/hooks/usePopup.js new file mode 100644 index 00000000..8a1fa876 --- /dev/null +++ b/src/hooks/usePopup.js @@ -0,0 +1,26 @@ +import { useRecoilState } from 'recoil' +import { popupState } from '@/store/popupAtom' +import { v4 as uuidv4 } from 'uuid' +import { useEffect } from 'react' + +export function usePopup() { + const [popup, setPopup] = useRecoilState(popupState) + useEffect(() => { + console.log(popup) + }, [popup]) + + const addPopup = (component) => { + setPopup({ children: [...popup.children, { id: uuidv4(), component: component }] }) + } + + const closePopup = (id) => { + setPopup({ children: popup.children.filter((child) => child.id !== id) }) + } + + return { + popup, + setPopup, + addPopup, + closePopup, + } +} diff --git a/src/locales/ja.json b/src/locales/ja.json index 980d1400..23e3b45c 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -247,6 +247,8 @@ "modal.object.setting.direction.select": "方向の選択", "modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。", "modal.placement.surface.setting.diagonal.length": "斜めの長さ", + "modal.color.picker.title": "色の設定", + "modal.color.picker.default.color": "基本色", "setting": "設定", "common.message.no.data": "No data", "common.message.no.dataDown": "ダウンロードするデータがありません", diff --git a/src/locales/ko.json b/src/locales/ko.json index 21aca2be..1ef504b2 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -252,6 +252,8 @@ "modal.object.setting.direction.select": "방향 선택", "modal.placement.surface.setting.info": "ⓘ ①의 길이 입력 후 대각선 길이를 입력하면 ②의 길이를 자동 계산합니다.", "modal.placement.surface.setting.diagonal.length": "대각선 길이", + "modal.color.picker.title": "색 설정", + "modal.color.picker.default.color": "기본색상", "setting": "설정", "common.message.no.data": "No data", "common.message.no.dataDown": "No data to download", diff --git a/src/store/popupAtom.js b/src/store/popupAtom.js new file mode 100644 index 00000000..78de8660 --- /dev/null +++ b/src/store/popupAtom.js @@ -0,0 +1,13 @@ +import { atom } from 'recoil' + +/* + * id: uuid + * component: Popup Component + * */ +export const popupState = atom({ + key: 'popupState', + default: { + children: [], + }, + dangerouslyAllowMutability: true, +}) diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 9bd59e3d..f0966b04 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -34,6 +34,9 @@ $alert-color: #101010; border-radius: 4px; background-color: #272727; z-index: 9999999; + &.xsm{ + width: 200px; + } &.xxxm{ width: 240px; } @@ -1505,7 +1508,7 @@ $alert-color: #101010; width: 16px; height: 16px; &.pink{ - border: 2px solid #EA10AC; + border: 2px solid #ce1c9c; background-color: #16417D; } &.white{ @@ -1514,4 +1517,264 @@ $alert-color: #101010; } } } +} + +// color setting +.color-setting-wrap{ + padding-bottom: 15px; + border-bottom: 1px solid #424242; + .color-tit{ + font-size: 13px; + font-weight: 500; + color: #ffffff; + margin-bottom: 10px; + } + .color-picker{ + .react-colorful{ + width: 100%; + height: auto; + gap: 20px; + .react-colorful__pointer{ + width: 15px; + height: 15px; + border: 4px solid #Fff; + } + .react-colorful__saturation{ + border-radius: 2px; + height: 200px; + border-bottom: 5px solid #000; + } + .react-colorful__last-control{ + border-radius: 2px; + height: 10px; + } + } + .hex-color-box{ + display: flex; + align-items: center; + margin-top: 15px; + .color-box-tit{ + font-size: 12px; + color: #fff; + font-weight: 500; + margin-right: 10px; + } + .color-hex-input{ + width: 150px; + margin-right: 5px; + input{ + width: 100%; + } + } + .color-box{ + display: block; + width: 30px; + height: 30px; + border-radius: 4px; + } + } + .default-color-wrap{ + margin-top: 25px; + .default-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .color-button-wrap{ + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 21px; + .default-color{ + display: block; + width: 100%; + height: 30px; + border-radius: 4px; + } + } + } + } +} + +// 글꼴 설정 팝업 +.font-option-warp{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 5px; + margin-bottom: 15px; + .font-option-item{ + .option-item-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + } +} +.font-ex-wrap{ + margin-bottom: 15px; + .font-ex-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .font-ex-box{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 80px; + background-color: #fff; + } + +} + +// 치수선 설정 +.font-btn-wrap{ + margin-bottom: 15px; + button{ + width: 100%; + height: 30px; + line-height: 28px; + } +} + +.line-color-wrap{ + margin-bottom: 15px; + .color-btn{ + display: block; + width: 100%; + height: 30px; + border-radius: 2px; + } +} + +.form-box{ + width: 100%; + background-color: #fff; + padding: 10px 0 20px; + .line-form{ + position: relative; + width: 102px; + height: 40px; + margin: 0 auto; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + .line-font-box{ + position: absolute; + bottom: -3px; + left: 0; + width: 100%; + text-align: center; + .font{ + display: block; + padding-bottom: 6px; + color: #101010; + } + .line{ + position: relative; + display: block; + width: 100%; + height: 1px; + border-radius: 30px; + &::before{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + left: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-top: none; + border-right: none; + } + &::after{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + right: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-bottom: none; + border-left: none; + } + } + } + } +} + +// 사이즈 변경 +.size-inner-warp{ + position: relative; +} +.size-check-wrap{ + position: relative; + display: block; + width: 132px; + height: 132px; + margin: 0 auto; + .size-btn{ + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background-color: #fff; + border-radius: 50%; + } + } + &:nth-child(1){ top: 0; left: 0; } + &:nth-child(2){ top: 0; right: 0; } + &:nth-child(3){ bottom: 0; left: 0; } + &:nth-child(4){ bottom: 0; right: 0; } + } + .size-box{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100px; + height: 100px; + background-color: #fff; + } +} + +.size-option-top{ + margin-bottom: 15px; +} +.size-option-side{ + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); +} +.size-option-wrap{ + width: 88px; + margin: 0 auto; + .size-option{ + display: flex; + align-items: center; + input{ + width: 100%; + flex: 1; + } + span{ + flex: none; + } + } } \ No newline at end of file From b909006f7ab61efb1316f546a55cb1406142be00 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 18 Oct 2024 13:56:28 +0900 Subject: [PATCH 003/139] chore: modify .env variable --- .env | 12 ------------ .env.development | 6 ------ .env.production | 4 ---- 3 files changed, 22 deletions(-) diff --git a/.env b/.env index 50ab0d74..e69de29b 100644 --- a/.env +++ b/.env @@ -1,12 +0,0 @@ -# Environment variables declared in this file are automatically made available to Prisma. -# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema - -# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB. -# See the documentation for all the connection string options: https://pris.ly/d/connection-strings - -# DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public" -# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority" -#DATABASE_URL = "mongodb%2Bsrv%3A%2F%2Fyoo32767%3AGuCtswjLGqUaNL0G%40cluster0.vsdtcnb.mongodb.net%2F%3FretryWrites%3Dtrue%26w%3Dmajority%26appName%3DCluster0" -# DATABASE_URL = "mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/Cluster0?retryWrites=true&w=majority" -# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority" -DATABASE_URL="mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/mytest" \ No newline at end of file diff --git a/.env.development b/.env.development index 933db5d3..bb0e9585 100644 --- a/.env.development +++ b/.env.development @@ -1,10 +1,4 @@ -NEXT_PUBLIC_TEST="테스트변수입니다. development" - NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" -# NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080" -# NEXT_PUBLIC_API_SERVER_PATH="http://172.30.1.60:8080" - -DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" diff --git a/.env.production b/.env.production index 9bad1719..bb0e9585 100644 --- a/.env.production +++ b/.env.production @@ -1,9 +1,5 @@ -NEXT_PUBLIC_TEST="테스트변수입니다. production" - NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" -DATABASE_URL="" - SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" From 4ac1e6ea9a7e81a2ee7621eefe90aabcbb9b6867 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 18 Oct 2024 14:01:19 +0900 Subject: [PATCH 004/139] =?UTF-8?q?=EC=98=A4=EA=B0=81=ED=98=95=20=EB=B0=B8?= =?UTF-8?q?=EB=A6=AC=EB=8D=B0=EC=9D=B4=EC=85=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/object/useObjectBatch.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 9ad8af5d..600dece7 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -471,32 +471,28 @@ export function useObjectBatch() { addCanvasMouseEventListener('mouse:up', (e) => { if (dormer) { - // const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer)) - // const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) + const pentagonPolygon = pointsToTurfPolygon(dormer.points) + const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) - // //지붕 밖으로 그렸을때 - // if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) { - // swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) - // //일단 지워 - // deleteTempObjects() - // return - // } + //지붕 밖으로 그렸을때 + if (!turf.booleanWithin(pentagonPolygon, selectedSurfacePolygon)) { + swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) + //일단 지워 + deleteTempObjects() + return + } //각도 추가 - let originAngle = 0 //기본 남쪽 - let direction = 'south' + let direction = 'south' if (directionRef === 'left') { //서 - originAngle = 90 direction = 'west' } else if (directionRef === 'right') { //동 - originAngle = 270 direction = 'east' } else if (directionRef === 'up') { //북 - originAngle = 180 direction = 'north' } From e186ca17748b36572ad78379c58d6c1c290100c9 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 18 Oct 2024 14:57:25 +0900 Subject: [PATCH 005/139] =?UTF-8?q?object=20=EB=B0=B0=EC=B9=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/object/ObjectSetting.jsx | 11 +++--- src/hooks/object/useObjectBatch.js | 34 ++++++++++++------- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/components/floor-plan/modal/object/ObjectSetting.jsx b/src/components/floor-plan/modal/object/ObjectSetting.jsx index 764535e3..cb1b0b45 100644 --- a/src/components/floor-plan/modal/object/ObjectSetting.jsx +++ b/src/components/floor-plan/modal/object/ObjectSetting.jsx @@ -51,15 +51,12 @@ export default function ObjectSetting({ setShowObjectSettingModal }) { } const applyObject = () => { - // if (surfaceShapePolygons.length === 0) { - // swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' }) - // return - // } + if (surfaceShapePolygons.length === 0) { + swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' }) + return + } //개구배치, 그림자배치 - - console.log(surfaceShapePolygons) - if (buttonAct === 1 || buttonAct === 2) { applyOpeningAndShadow(objectPlacement, buttonAct, surfaceShapePolygons) } else { diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 600dece7..e18b13e3 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -200,20 +200,34 @@ export function useObjectBatch() { } } + /** + * 오브젝트 도머 배치 + * @param {} dormerPlacement + * @param {*} buttonAct + * @param {*} surfaceShapePolygons + * @returns + */ const applyDormers = (dormerPlacement, buttonAct, surfaceShapePolygons) => { const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP - const height = dormerPlacement.heightRef.current.value / 10 - const width = dormerPlacement.widthRef.current.value / 10 - const pitch = dormerPlacement.pitchRef.current.value - const offsetRef = dormerPlacement.offsetRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetRef.current.value) / 10 - const offsetWidthRef = dormerPlacement.offsetWidthRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetWidthRef.current.value) / 10 + const height = dormerPlacement.heightRef.current !== null ? dormerPlacement.heightRef.current.value / 10 : 0 + const width = dormerPlacement.widthRef.current !== null ? dormerPlacement.widthRef.current.value / 10 : 0 //triangle일때는 없음 + const pitch = dormerPlacement.pitchRef.current !== null ? dormerPlacement.pitchRef.current.value : 0 + const offsetRef = + dormerPlacement.offsetRef.current !== null + ? dormerPlacement.offsetRef.current.value === '' + ? 0 + : parseInt(dormerPlacement.offsetRef.current.value) / 10 + : 0 + const offsetWidthRef = + dormerPlacement.offsetWidthRef.current !== null + ? dormerPlacement.offsetWidthRef.current.value === '' + ? 0 + : parseInt(dormerPlacement.offsetWidthRef.current.value) / 10 + : 0 const directionRef = dormerPlacement.directionRef.current - let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints - console.log('dormerPlacement', dormerPlacement) - if (height === '' || pitch === '' || height <= 0 || pitch <= 0) { swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' }) return @@ -636,8 +650,6 @@ export function useObjectBatch() { const splitDormerPentagon = (pentagon, direction, offsetMode) => { const points = pentagon.points - console.log(pentagon.points) - let leftPoints = [] let rightPoints = [] @@ -699,8 +711,6 @@ export function useObjectBatch() { ] } - console.log(leftPoints, rightPoints) - return [leftPoints, rightPoints] } From d6fbea705fecf0e0e52dff31b9e22ae9a7f9a5f8 Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 18 Oct 2024 15:28:59 +0900 Subject: [PATCH 006/139] =?UTF-8?q?popupManager=20canvasSetting=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/color-picker/ColorPickerModal.jsx | 17 +++++++-- src/components/common/font/FontSetting.jsx | 19 +++++----- src/components/floor-plan/CanvasMenu.jsx | 9 +++-- src/components/floor-plan/FloorPlan.jsx | 28 --------------- .../floor-plan/modal/grid/DotLineGrid.jsx | 16 +++++++-- .../floor-plan/modal/setting01/GridOption.jsx | 16 +++++---- .../modal/setting01/SecondOption.jsx | 36 ++++++++++++------- .../modal/setting01/SettingModal01.jsx | 12 ++++--- .../dimensionLine/DimensionLineSetting.jsx | 15 ++++---- src/hooks/usePopup.js | 21 ++++++++--- 10 files changed, 112 insertions(+), 77 deletions(-) diff --git a/src/components/common/color-picker/ColorPickerModal.jsx b/src/components/common/color-picker/ColorPickerModal.jsx index 0f81d99f..3e4997b6 100644 --- a/src/components/common/color-picker/ColorPickerModal.jsx +++ b/src/components/common/color-picker/ColorPickerModal.jsx @@ -2,20 +2,30 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import ColorPicker from '@/components/common/color-picker/ColorPicker' import { useMessage } from '@/hooks/useMessage' import { useEffect, useState } from 'react' +import { usePopup } from '@/hooks/usePopup' export default function ColorPickerModal(props) { - const { isShow, setIsShow, pos = { x: 800, y: -950 }, color = '#ff0000', setColor } = props + const { isShow, setIsShow, pos = { x: 770, y: -815 }, color = '#ff0000', setColor, id } = props const { getMessage } = useMessage() const [originColor, setOriginColor] = useState(color) + const { closePopup } = usePopup() + useEffect(() => { setOriginColor(color) }, [isShow]) + return ( - +

{getMessage('modal.color.picker.title')}

-
@@ -32,6 +42,7 @@ export default function ColorPickerModal(props) { onClick={() => { setColor(originColor) setIsShow(false) + closePopup(id) }} > {getMessage('common.message.save')} diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index aaeb7b02..a78bd97d 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,20 +1,23 @@ import WithDraggable from '@/components/common/draggable/withDraggable' import QSelectBox from '@/components/common/select/QSelectBox' +import { usePopup } from '@/hooks/usePopup' const SelectOption = [{ name: '原寸' }, { name: '原寸' }, { name: '原寸' }, { name: '原寸' }] export default function FontSetting(props) { - const { setShowFontSettingModal } = props - console.log( - Array.from({ length: 10 }).map((_, index) => { - return { name: 5 + index } - }), - ) + const { id, setShowFontSettingModal } = props + const { closePopup } = usePopup() return ( - +

フォント

-
diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 61bfb0ae..14d8ee14 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -6,7 +6,7 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import MenuDepth01 from './MenuDepth01' import QSelectBox from '@/components/common/select/QSelectBox' - +import { v4 as uuidv4 } from 'uuid' import { useMessage } from '@/hooks/useMessage' import { usePlan } from '@/hooks/usePlan' import { useSwal } from '@/hooks/useSwal' @@ -157,6 +157,11 @@ export default function CanvasMenu(props) { // canvas.renderAll() // } + const handlePopup = () => { + const id = uuidv4() + addPopup(id, 1, ) + } + useEffect(() => { if (globalLocale === 'ko') { setAppMessageState(KO) @@ -203,7 +208,7 @@ export default function CanvasMenu(props) {
{/**/} - +
diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 4d70ee0c..6f798f0a 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -8,7 +8,6 @@ import { settingModalFirstOptionsState, settingModalGridOptionsState, settingMod import '@/styles/contents.scss' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import CanvasLayout from '@/components/floor-plan/CanvasLayout' -import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid' import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' @@ -26,7 +25,6 @@ import MovementSetting from '@/components/floor-plan/modal/movement/MovementSett import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' -import FontSetting from '@/components/common/font/FontSetting' import { gridColorState } from '@/store/gridAtom' export default function FloorPlan() { @@ -54,20 +52,10 @@ export default function FloorPlan() { const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - const [showDotLineGridModal, setShowDotLineGridModal] = useState(false) const [showGridCopyModal, setShowGridCopyModal] = useState(false) const [showGridMoveModal, setShowGridMoveModal] = useState(false) - const [showColorPickerModal, setShowColorPickerModal] = useState(false) const [color, setColor] = useRecoilState(gridColorState) const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) - const [showFontSettingModal, setShowFontSettingModal] = useState(false) - - const canvasSettingProps = { - setShowCanvasSettingModal, - setShowDotLineGridModal, - setShowColorPickerModal, - setShowFontSettingModal, - } const outlineProps = { setShowOutlineModal, @@ -125,17 +113,6 @@ export default function FloorPlan() { console.error('Data fetching error:', error) } } - const dotLineProps = { - showDotLineGridModal, - setShowDotLineGridModal, - } - - const gridColorProps = { - setShowColorPickerModal, - color, - setColor, - setSettingModalGridOptions, - } const propertiesSettingProps = { setShowPropertiesSettingModal, @@ -149,13 +126,8 @@ export default function FloorPlan() {
- {/*{showCanvasSettingModal && }*/} {showOutlineModal && } - {showDotLineGridModal && } - {/*{showColorPickerModal && }*/} - {showFontSettingModal && } {showPropertiesSettingModal && } - {/**/} {showPlaceShapeModal && } {showRoofShapeSettingModal && } {showRoofShapePassivitySettingModal && ( diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index eb5a834e..4d839906 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -10,6 +10,7 @@ import { gridColorState } from '@/store/gridAtom' import { settingModalGridOptionsState } from '@/store/settingAtom' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' const TYPE = { DOT: 'DOT', @@ -20,7 +21,7 @@ export default function DotLineGrid(props) { // const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [close, setClose] = useState(false) - const { setShowDotLineGridModal } = props + const { id, setShowDotLineGridModal } = props const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) const gridColor = useRecoilValue(gridColorState) const canvas = useRecoilValue(canvasState) @@ -32,6 +33,7 @@ export default function DotLineGrid(props) { const { getMessage } = useMessage() const { get, post } = useAxios() const { swalFire } = useSwal() + const { closePopup } = usePopup() useEffect(() => { return () => { @@ -243,6 +245,8 @@ export default function DotLineGrid(props) { canvas.renderAll() }) + setShowDotLineGridModal(false) + closePopup(id) } catch (error) { swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) } @@ -303,11 +307,17 @@ export default function DotLineGrid(props) { } return ( - +

{getMessage('modal.canvas.setting.grid.dot.line.setting')}

-
diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index efa7d099..9b5e131e 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -7,9 +7,11 @@ import { useTempGrid } from '@/hooks/useTempGrid' import { gridColorState } from '@/store/gridAtom' import { useColor } from 'react-color-palette' import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' +import { usePopup } from '@/hooks/usePopup' +import { v4 as uuidv4 } from 'uuid' +import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid' export default function GridOption(props) { - const { setShowDotLineGridModal } = props const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState) const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState) const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) @@ -18,6 +20,8 @@ export default function GridOption(props) { const [gridColor, setGridColor] = useRecoilState(gridColorState) const [color, setColor] = useColor(gridColor) const [showColorPickerModal, setShowColorPickerModal] = useState(false) + const [showDotLineGridModal, setShowDotLineGridModal] = useState(false) + const { addPopup } = usePopup() useEffect(() => { console.log('GridOption useEffect 실행') @@ -26,6 +30,7 @@ export default function GridOption(props) { }, [color]) useEffect(() => { + console.log(showColorPickerModal) gridOptions[3].selected = showColorPickerModal setGridOptions([...gridOptions]) }, [showColorPickerModal]) @@ -42,6 +47,7 @@ export default function GridOption(props) { const onClickOption = (option) => { const newGridOptions = [...gridOptions] + const id = uuidv4() newGridOptions.map((item) => { if (item.id === option.id) { item.selected = !item.selected @@ -59,6 +65,7 @@ export default function GridOption(props) { // 점.선 그리드 if (option.selected) { setShowDotLineGridModal(true) + addPopup(id, 2, ) } else { setShowDotLineGridModal(false) } @@ -75,6 +82,7 @@ export default function GridOption(props) { console.log(option) if (option.selected) { setShowColorPickerModal(true) + addPopup(id, 2, ) } else { setShowColorPickerModal(false) } @@ -88,10 +96,6 @@ export default function GridOption(props) { setColor: setGridColor, isShow: showColorPickerModal, setIsShow: setShowColorPickerModal, - pos: { - x: -515, - y: -214, - }, } return ( @@ -107,7 +111,7 @@ export default function GridOption(props) { ))}
- + {/**/} ) } diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index 05d20c11..a4123fe3 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -6,8 +6,11 @@ import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting' +import { usePopup } from '@/hooks/usePopup' +import { v4 as uuidv4 } from 'uuid' +import FontSetting from '@/components/common/font/FontSetting' -export default function SecondOption({ setShowFontSettingModal }) { +export default function SecondOption() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) @@ -19,15 +22,9 @@ export default function SecondOption({ setShowFontSettingModal }) { const { getMessage } = useMessage() const { get, post } = useAxios() const { swalFire } = useSwal() + const { addPopup } = usePopup() + const [showFontSettingModal, setShowFontSettingModal] = useState(false) const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) - const dimensionLineSettingProps = { - isShow: showDimensionLineSettingModal, - setIsShow: setShowDimensionLineSettingModal, - pos: { - x: -515, - y: -214, - }, - } // 데이터를 최초 한 번만 조회 useEffect(() => { @@ -138,6 +135,21 @@ export default function SecondOption({ setShowFontSettingModal }) { setAdsorptionRange(option.range) } + const handlePopup = (type) => { + const id = uuidv4() + + switch (type) { + case 'dimensionLine': + addPopup(id, 2, ) + break + case 'font1': //문자 글꼴변경 + case 'font2': //흐름 방향 글꼴 변경 + case 'font3': //치수 글꼴변경 + case 'font4': //회로번호 글꼴변경 + addPopup(id, 2, ) + } + } + return ( <>
@@ -145,7 +157,7 @@ export default function SecondOption({ setShowFontSettingModal }) {
{settingModalSecondOptions && settingModalSecondOptions.option3.map((item) => ( - ))} @@ -163,7 +175,8 @@ export default function SecondOption({ setShowFontSettingModal }) { ))}
-
- ) } diff --git a/src/components/floor-plan/modal/setting01/SettingModal01.jsx b/src/components/floor-plan/modal/setting01/SettingModal01.jsx index 98542c36..c5496f45 100644 --- a/src/components/floor-plan/modal/setting01/SettingModal01.jsx +++ b/src/components/floor-plan/modal/setting01/SettingModal01.jsx @@ -8,24 +8,26 @@ import { useMessage } from '@/hooks/useMessage' import GridOption from '@/components/floor-plan/modal/setting01/GridOption' import { canGridOptionSeletor } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' +import { usePopup } from '@/hooks/usePopup' export default function SettingModal01(props) { - const { setShowCanvasSettingModal, setShowDotLineGridModal, setShowFontSettingModal } = props + const { setShowDotLineGridModal, setShowFontSettingModal, id } = props + console.log(props) const [buttonAct, setButtonAct] = useState(1) const { getMessage } = useMessage() const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor) - + const { addPopup, closePopup } = usePopup() const handleBtnClick = (num) => { setButtonAct(num) } return ( <> - +

{getMessage('modal.canvas.setting')}

-
@@ -45,7 +47,7 @@ export default function SettingModal01(props) { )}
{buttonAct === 1 && } - {buttonAct === 2 && } + {buttonAct === 2 && } {buttonAct === 3 && }
diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index a17cc22e..667e90c8 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -1,19 +1,22 @@ import WithDraggable from '@/components/common/draggable/withDraggable' +import { usePopup } from '@/hooks/usePopup' export default function DimensionLineSetting(props) { - const { isShow, setIsShow, pos = { x: 800, y: -950 }, setShowFontSettingModal, setShowColorPickerModal } = props + const { id, pos = { x: 970, y: -815 }, setShowColorPickerModal } = props + console.log(props) + const { closePopup } = usePopup() return ( - +

寸法線 設定

- +
- +
diff --git a/src/hooks/usePopup.js b/src/hooks/usePopup.js index 8a1fa876..f62fd6c5 100644 --- a/src/hooks/usePopup.js +++ b/src/hooks/usePopup.js @@ -1,20 +1,32 @@ import { useRecoilState } from 'recoil' import { popupState } from '@/store/popupAtom' -import { v4 as uuidv4 } from 'uuid' import { useEffect } from 'react' export function usePopup() { const [popup, setPopup] = useRecoilState(popupState) + useEffect(() => { console.log(popup) }, [popup]) - const addPopup = (component) => { - setPopup({ children: [...popup.children, { id: uuidv4(), component: component }] }) + const addPopup = (id, depth, component) => { + setPopup({ children: [...filterDepth(depth), { id: id, depth: depth, component: component }] }) } const closePopup = (id) => { - setPopup({ children: popup.children.filter((child) => child.id !== id) }) + setPopup({ children: [...popup.children.filter((child) => child.id !== id)] }) + } + + const closeAll = () => { + setPopup({ children: [] }) + } + + const closePrevPopup = () => { + setPopup({ children: [...popup.children.slice(popup.children.length - 1)] }) + } + + const filterDepth = (depth) => { + return [...popup.children.filter((child) => child.depth !== depth)] } return { @@ -22,5 +34,6 @@ export function usePopup() { setPopup, addPopup, closePopup, + closeAll, } } From e1a4ccaa08050d8776ac98fdebf94460d8298c42 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 18 Oct 2024 17:28:42 +0900 Subject: [PATCH 007/139] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20hooks=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/setting01/FirstOption.jsx | 3 ++- src/hooks/option/useFirstOption.js | 23 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 src/hooks/option/useFirstOption.js diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index c4e75ea4..bd24d738 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -5,10 +5,11 @@ import React, { useEffect, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' import { adsorptionPointAddModeState } from '@/store/canvasAtom' +import { useFirstOption } from '@/hooks/option/useFirstOption' export default function FirstOption() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const { settingModalFirstOptions, setSettingModalFirstOptions } = useFirstOption() const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const { option1, option2, dimensionDisplay } = settingModalFirstOptions const { option3, option4 } = settingModalSecondOptions diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js new file mode 100644 index 00000000..4010b69e --- /dev/null +++ b/src/hooks/option/useFirstOption.js @@ -0,0 +1,23 @@ +import { useRecoilState, useRecoilValue } from 'recoil' +import { canvasState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { settingModalFirstOptionsState } from '@/store/settingAtom' + +export function useFirstOption() { + const canvas = useRecoilValue(canvasState) + + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + + useEffect(() => { + const option1 = settingModalFirstOptions.option1 + + canvas + .getObjects() + .filter((obj) => obj.name === '') + .forEach((obj) => { + obj.set({ visible: !obj.visible }) + }) + }, [settingModalFirstOptions]) + + return { settingModalFirstOptions, setSettingModalFirstOptions } +} From 7d2d32f198ce821a0efc9ba481e5c301861a3a77 Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 18 Oct 2024 17:42:03 +0900 Subject: [PATCH 008/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/MainContents.jsx | 2 - src/components/management/StuffDetail.jsx | 71 ++++++++++++++++------- 2 files changed, 51 insertions(+), 22 deletions(-) diff --git a/src/components/main/MainContents.jsx b/src/components/main/MainContents.jsx index ba9a8d77..6dcca943 100644 --- a/src/components/main/MainContents.jsx +++ b/src/components/main/MainContents.jsx @@ -34,7 +34,6 @@ export default function MainContents({ objectList, businessCharger, businessChar startRow: 1, endRow: 1, } - // const noticeApiUrl = `api/board/list?schNoticeTpCd=QC&schNoticeClsCd=NOTICE&schTitle=&startRow=1&endRow=1` const noticeApiUrl = `api/board/list?${queryStringFormatter(param)}` const res = await get({ url: noticeApiUrl }) //console.log('공지res::', res) @@ -57,7 +56,6 @@ export default function MainContents({ objectList, businessCharger, businessChar startRow: 1, endRow: 3, } - // const faqApiUrl = `api/board/list?schNoticeTpCd=QC&schNoticeClsCd=FAQ&schTitle=&startRow=1&endRow=1` const faqApiUrl = `api/board/list?${queryStringFormatter(param)}` const res = await get({ url: faqApiUrl }) //console.log('FAQres::', res) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 3727555e..6800a5e8 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -102,7 +102,6 @@ export default function StuffDetail() { // 도도부현API get({ url: '/api/object/prefecture/list' }).then((res) => { if (!isEmptyArray(res)) { - // console.log('신규화면 도도부현API 결과:::', res) setPrefCodeList(res) } }) @@ -348,9 +347,8 @@ export default function StuffDetail() { // 발전량시뮬레이션 지역 목록 get({ url: `/api/object/prefecture/${prefValue}/list` }).then((res) => { if (!isEmptyArray(res)) { - // console.log('발전량 시뮬레이션::::::::', res) - form.setValue('areaId', res[0].areaId) - form.setValue('areaName', res[0].prefName) + // form.setValue('areaId', res[0].areaId) + // form.setValue('areaName', res[0].prefName) setAreaIdList(res) } }) @@ -359,7 +357,8 @@ export default function StuffDetail() { // 발전량 시뮬레이션 변경 const handleAreaIdOnChange = (e) => { - form.setValue('areaId', e.target.value) + form.setValue('areaId', e.areaId) + form.setValue('areaName', e.prefName) } //필수값 다 입력했을때 @@ -631,13 +630,28 @@ export default function StuffDetail() {
{prefCodeList?.length > 0 && ( - + // + 0 ? false : true} @@ -664,8 +678,25 @@ export default function StuffDetail() { {row.prefName} ) + })} + + */} + + isDisabled={areaIdList.length > 0 ? false : true} + />
@@ -794,9 +825,9 @@ export default function StuffDetail() { )} - +
@@ -911,9 +942,9 @@ export default function StuffDetail() { {objectNo.substring(0, 1) === 'R' ? ( <> - + )} - + )} From ee897ede4d03239bf99d7f6a5e297460a24e5ac9 Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 18 Oct 2024 17:45:59 +0900 Subject: [PATCH 009/139] =?UTF-8?q?=5Fmain.scss,=20=5Fcontents.scss=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 2390 +++++++++++++++++++------------------ src/styles/_main.scss | 4 +- 2 files changed, 1247 insertions(+), 1147 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 37233d13..9cd8bd32 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -1,1203 +1,1303 @@ // CanvasPage -.canvas-wrap{ - height: calc(100vh - 47px); - display: flex; - flex-direction: column; - .canvas-content{ - flex: 1 1 auto; - .canvas-layout{ - height: 100%; - } - } - &.sub-wrap{ - overflow: hidden; - .canvas-content{ - height: calc(100% - 47px); - } - } -} +// .canvas-wrap{ +// height: calc(100vh - 47px); +// display: flex; +// flex-direction: column; +// .canvas-content{ +// flex: 1 1 auto; +// .canvas-layout{ +// height: 100%; +// } +// } +// &.sub-wrap{ +// overflow: hidden; +// .canvas-content{ +// height: calc(100% - 47px); +// } +// } +// } // CanvasMenu -.canvas-menu-wrap{ +.canvas-menu-wrap { + position: fixed; + top: 46px; + left: 0; + display: block; + width: 100%; + padding-bottom: 0; + background-color: #383838; + transition: padding 0.17s ease-in-out; + z-index: 999; + .canvas-menu-inner { position: relative; - display: block; - width: 100%; - padding-bottom: 0; - background-color: #383838; - transition: padding .17s ease-in-out; - .canvas-menu-inner{ - position: relative; - display: flex; - align-items: center; - padding: 0 40px 0 20px; - background-color: #2C2C2C; - z-index: 999; - .canvas-menu-list{ - display: flex; - align-items: center; - height: 100%; - .canvas-menu-item{ - display: flex; - align-items: center; - height: 100%; - button{ - display: flex; - align-items: center; - font-size: 12px; - height: 100%; - color: #fff; - font-weight: 600; - padding: 15px 20px; - opacity: 0.55; - transition: all .17s ease-in-out; - .menu-icon{ - display: block; - width: 16px; - height: 16px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - margin-right: 10px; - &.con00{background-image: url(/static/images/canvas/menu_icon00.svg);} - &.con01{background-image: url(/static/images/canvas/menu_icon01.svg);} - &.con02{background-image: url(/static/images/canvas/menu_icon02.svg);} - &.con03{background-image: url(/static/images/canvas/menu_icon03.svg);} - &.con04{background-image: url(/static/images/canvas/menu_icon04.svg);} - &.con05{background-image: url(/static/images/canvas/menu_icon05.svg);} - &.con06{background-image: url(/static/images/canvas/menu_icon06.svg);} - } - } - &.active{ - background-color: #383838; - button{ - opacity: 1; - } - } - } - } - .canvas-side-btn-wrap{ - display: flex; - align-items: center; - margin-left: auto; - .select-box{ - width: 124px; - margin-right: 5px; - > div{ - width: 100%; - } - } - .btn-from{ - display: flex; - align-items: center; - gap: 5px; - button{ - display: block; - width: 30px; - height: 30px; - border-radius: 2px; - background-color: #3D3D3D; - background-position: center; - background-repeat: no-repeat; - background-size: 15px 15px; - transition: all .17s ease-in-out; - &.btn01{background-image: url(../../public/static/images/canvas/side_icon03.svg);} - &.btn02{background-image: url(../../public/static/images/canvas/side_icon02.svg);} - &.btn03{background-image: url(../../public/static/images/canvas/side_icon01.svg);} - &.btn04{background-image: url(../../public/static/images/canvas/side_icon04.svg);} - &.btn05{background-image: url(../../public/static/images/canvas/side_icon05.svg);} - &.btn06{background-image: url(../../public/static/images/canvas/side_icon06.svg);} - &.btn07{background-image: url(../../public/static/images/canvas/side_icon07.svg);} - &.btn08{background-image: url(../../public/static/images/canvas/side_icon08.svg);} - &.btn09{background-image: url(../../public/static/images/canvas/side_icon09.svg);} - &:hover{ - background-color: #1083E3; - } - &.active{ - background-color: #1083E3; - } - } - } - .ico-btn-from{ - display: flex; - align-items: center; - gap: 5px; - button{ - .ico{ - display: block; - width: 15px; - height: 15px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - &.ico01{background-image: url(../../public/static/images/canvas/ico-flx01.svg);} - &.ico02{background-image: url(../../public/static/images/canvas/ico-flx02.svg);} - &.ico03{background-image: url(../../public/static/images/canvas/ico-flx03.svg);} - &.ico04{background-image: url(../../public/static/images/canvas/ico-flx04.svg);} - } - .name{ - font-size: 12px; - color: #fff; - } - } - &.form06{ - .name{ - font-size: 13px; - } - } - } - .vertical-horizontal{ - display: flex; - min-width: 170px; - height: 28px; - margin: 0 5px; - border-radius: 2px; - background: #373737; - line-height: 28px; - overflow: hidden; - span{ - padding: 0 10px; - font-size: 13px; - color: #fff; - } - button{ - margin-left: auto; - height: 100%; - background-color: #4B4B4B; - font-size: 13px; - font-weight: 400; - color: #fff; - padding: 0 7.5px; - transition: all .17s ease-in-out; - } - &.on{ - button{ - background-color: #1083E3; - } - } - } - .size-control{ - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - background-color: #3D3D3D; - border-radius: 2px; - width: 100px; - height: 30px; - margin: 0 5px; - span{ - font-size: 13px; - color: #fff; - } - .control-btn{ - display: block; - width: 12px; - height: 12px; - background-repeat: no-repeat; - background-size: cover; - background-position: center; - &.minus{ - background-image: url(../../public/static/images/canvas/minus.svg); - } - &.plus{ - background-image: url(../../public/static/images/canvas/plus.svg); - } - } - } - } - } - .canvas-depth2-wrap{ - position: absolute; - top: -100%; - left: 0; - background-color: #383838; - width: 100%; - height: 50px; - transition: all .17s ease-in-out; - .canvas-depth2-inner{ - display: flex; - align-items: center; - padding: 0 40px; - height: 100%; - .canvas-depth2-list{ - display: flex; - align-items: center ; - height: 100%; - .canvas-depth2-item{ - display: flex; - align-items: center; - margin-right: 26px; - height: 100%; - button{ - position: relative; - opacity: 0.55; - color: #fff; - font-size: 12px; - font-weight: normal; - height: 100%; - padding-right: 12px; - } - &.active{ - button{ - opacity: 1; - font-weight: 600; - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } - } - } - } - } - .canvas-depth2-btn-list{ - display: flex; - align-items: center; - margin-left: auto; - height: 100%; - .depth2-btn-box{ - display: flex; - align-items: center; - margin-right: 34px; - height: 100%; - transition: all .17s ease-in-out; - button{ - position: relative; - font-size: 12px; - font-weight: 400; - height: 100%; - color: #fff; - padding-right: 12px; - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } - } - &:last-child{ - margin-right: 0; - } - &.mouse{ - opacity: 0.55; - } - } - } - } - &.active{ - top: 47px; - } - } - &.active{ - padding-bottom: 50px; - } -} - -// canvas-layout -.canvas-layout{ - .canvas-page-list{ - display: flex; - background-color: #1C1C1C; - border-top: 1px solid #000; - width: 100%; - .canvas-plane-wrap{ - display: flex; - align-items: center; - max-width: calc(100% - 45px); - .canvas-page-box{ - display: flex; - align-items: center; - background-color: #1c1c1c; - padding: 9.6px 20px; - border-right:1px solid #000; - min-width: 0; - transition: all .17s ease-in-out; - span{ - display: flex; - align-items: center; - width: 100%; - font-size: 12px; - font-family: 'Pretendard', sans-serif; - color: #AAA; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - .close{ - flex: none; - display: block; - width: 7px; - height: 8px; - margin-left: 15px; - background: url(../../public/static/images/canvas/plan_close_gray.svg)no-repeat center; - background-size: cover; - } - &.on{ - background-color: #fff; - span{ - font-weight: 600; - color: #101010; - } - .close{ - background: url(../../public/static/images/canvas/plan_close_black.svg)no-repeat center; - } - &:hover{ - background-color: #fff; - } - } - &:hover{ - background-color: #000; - } - } - } - .plane-add{ - display: flex; - align-items: center; - justify-content: center; - width: 45px; - padding: 13.5px 0; - background-color: #1C1C1C; - border-right: 1px solid #000; - transition: all .17s ease-in-out; - span{ - display: block; - width: 9px; - height: 9px; - background: url(../../public/static/images/canvas/plane_add.svg)no-repeat center; - background-size: cover; - } - &:hover{ - background-color: #000; - } - } - } -} - -.canvas-frame{ - position: relative; - height: calc(100% - 36.5px); - background-color: #fff; - canvas{ - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } -} - -// sub-page -.sub-header{ - position: fixed; - top: 46px; - left: 0; - width: 100%; - height: 46px; - border-bottom: 1px solid #000; - background: #2C2C2C; + display: flex; + align-items: center; + padding: 0 40px 0 20px; + background-color: #2c2c2c; z-index: 999; - .sub-header-inner{ + .canvas-menu-list { + display: flex; + align-items: center; + height: 100%; + .canvas-menu-item { display: flex; align-items: center; height: 100%; - padding: 0 100px; - .sub-header-title-wrap{ - display: flex; - align-items: center; - .title-item{ - position: relative; - padding: 0 24px; - a{ - display: flex; - align-items: center; - .icon{ - width: 22px; - height: 22px; - margin-right: 8px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.drawing{background-image: url(../../public/static/images/main/drawing_icon.svg);} - } - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 16px; - background-color: #D9D9D9; - } - &:first-child{ - padding-left: 0; - } - &:last-child{ - padding-right: 0; - &:after{ - display: none; - } - } + button { + display: flex; + align-items: center; + font-size: 12px; + height: 100%; + color: #fff; + font-weight: 600; + padding: 15px 20px; + opacity: 0.55; + transition: all 0.17s ease-in-out; + .menu-icon { + display: block; + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + margin-right: 10px; + &.con00 { + background-image: url(/static/images/canvas/menu_icon00.svg); } + &.con01 { + background-image: url(/static/images/canvas/menu_icon01.svg); + } + &.con02 { + background-image: url(/static/images/canvas/menu_icon02.svg); + } + &.con03 { + background-image: url(/static/images/canvas/menu_icon03.svg); + } + &.con04 { + background-image: url(/static/images/canvas/menu_icon04.svg); + } + &.con05 { + background-image: url(/static/images/canvas/menu_icon05.svg); + } + &.con06 { + background-image: url(/static/images/canvas/menu_icon06.svg); + } + } } - .sub-header-title{ - font-size: 16px; + &.active { + background-color: #383838; + button { + opacity: 1; + } + } + } + } + .canvas-side-btn-wrap { + display: flex; + align-items: center; + margin-left: auto; + .select-box { + width: 124px; + margin-right: 5px; + > div { + width: 100%; + } + } + .btn-from { + display: flex; + align-items: center; + gap: 5px; + button { + display: block; + width: 30px; + height: 30px; + border-radius: 2px; + background-color: #3d3d3d; + background-position: center; + background-repeat: no-repeat; + background-size: 15px 15px; + transition: all 0.17s ease-in-out; + &.btn01 { + background-image: url(../../public/static/images/canvas/side_icon03.svg); + } + &.btn02 { + background-image: url(../../public/static/images/canvas/side_icon02.svg); + } + &.btn03 { + background-image: url(../../public/static/images/canvas/side_icon01.svg); + } + &.btn04 { + background-image: url(../../public/static/images/canvas/side_icon04.svg); + } + &.btn05 { + background-image: url(../../public/static/images/canvas/side_icon05.svg); + } + &.btn06 { + background-image: url(../../public/static/images/canvas/side_icon06.svg); + } + &.btn07 { + background-image: url(../../public/static/images/canvas/side_icon07.svg); + } + &.btn08 { + background-image: url(../../public/static/images/canvas/side_icon08.svg); + } + &.btn09 { + background-image: url(../../public/static/images/canvas/side_icon09.svg); + } + &:hover { + background-color: #1083e3; + } + &.active { + background-color: #1083e3; + } + } + } + .ico-btn-from { + display: flex; + align-items: center; + gap: 5px; + button { + .ico { + display: block; + width: 15px; + height: 15px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + &.ico01 { + background-image: url(../../public/static/images/canvas/ico-flx01.svg); + } + &.ico02 { + background-image: url(../../public/static/images/canvas/ico-flx02.svg); + } + &.ico03 { + background-image: url(../../public/static/images/canvas/ico-flx03.svg); + } + &.ico04 { + background-image: url(../../public/static/images/canvas/ico-flx04.svg); + } + } + .name { + font-size: 12px; color: #fff; - font-weight: 600; + } } - .sub-header-location{ - margin-left: auto; - display: flex; - align-items: center; - .location-item{ - position: relative; - display: flex; - align-items: center; - padding: 0 10px; - span{ - display: flex; - font-size: 12px; - color: #AAA; - font-weight: normal; - cursor: default; - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 4px; - height: 6px; - background: url(../../public/static/images/main/loaction_arr.svg)no-repeat center; - } - &:first-child{ - padding-left: 0; - } - &:last-child{ - padding-right: 0; - span{ - color: #fff; - } - &:after{ - display: none; - } - } - } + &.form06 { + .name { + font-size: 13px; + } } - } -} - -// sub content -.sub-content{ - padding-top: 46px; - .sub-content-inner{ - max-width: 1720px; - margin: 0 auto; - padding-top: 20px; - .sub-content-box{ - margin-bottom: 20px; - &:last-child{ - margin-bottom: 0; - } - } - } - &.estimate{ + } + .vertical-horizontal { display: flex; - flex-direction: column; - height: calc(100% - 36.5px); - overflow-y: auto; - padding-top: 0; - .sub-content-inner{ - flex: 1; - width: 100%; + min-width: 170px; + height: 28px; + margin: 0 5px; + border-radius: 2px; + background: #373737; + line-height: 28px; + overflow: hidden; + span { + padding: 0 10px; + font-size: 13px; + color: #fff; } - } -} -.sub-table-box{ - padding: 20px; - border-radius: 6px; - border: 1px solid #E9EAED; - background: #FFF; - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - .table-box-title-wrap{ - display: flex; - align-items: center; - margin-bottom: 15px; - .title-wrap{ - display: flex; - align-items: center; - h3{ - display: block; - font-size: 15px; - color: #101010; - font-weight: 600; - margin-right: 14px; - &.product{ - margin-right: 10px; - } - } - .product_tit{ - position: relative; - font-size: 15px; - font-weight: 600; - color: #1083E3; - padding-left: 10px; - &::before{ - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #D9D9D9; - } - } - .option{ - padding-left: 5px; - font-size: 13px; - color: #101010; - font-weight: 400; - } - .info-wrap{ - display: flex; - align-items: center; - li{ - position: relative; - padding: 0 6px; - font-size: 12px; - color: #101010; - font-weight: normal; - span{ - font-weight: 600; - &.red{ - color: #E23D70; - } - } - &:after{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #D9D9D9; - } - &:first-child{padding-left: 0;} - &:last-child{padding-right: 0;&::after{display: none;}} - } - } + button { + margin-left: auto; + height: 100%; + background-color: #4b4b4b; + font-size: 13px; + font-weight: 400; + color: #fff; + padding: 0 7.5px; + transition: all 0.17s ease-in-out; } - } - .left-unit-box{ - margin-left: auto; - display: flex; - align-items: center; - } - .promise-gudie{ - display: block; - font-size: 13px; - font-weight: 700; - color: #101010; - margin-bottom: 20px; - } - .important{ - color: #f00; - } - .sub-center-footer{ + &.on { + button { + background-color: #1083e3; + } + } + } + .size-control { display: flex; align-items: center; justify-content: center; - margin-top: 20px; - } - .sub-right-footer{ - display: flex; - align-items: center; - justify-content: flex-end; - margin-top: 20px; - } -} -.pagination-wrap{ - margin-top: 24px; -} - -.infomation-wrap{ - margin-bottom: 30px; -} - -.infomation-box-wrap{ - display: flex; - align-items: center; - gap: 10px; - .sub-table-box{ - flex: 1 ; - } - .info-title{ - font-size: 14px; - font-weight: 500; - color: #344356; - margin-bottom: 10px; - } - .info-inner{ - position: relative; - font-size: 13px; - color: #344356; - .copy-ico{ - position: absolute; - bottom: 0; - right: 0; - width: 16px; - height: 16px; - background: url(../../public/static/images/sub/copy_ico.svg)no-repeat center; - background-size: cover; + gap: 10px; + background-color: #3d3d3d; + border-radius: 2px; + width: 100px; + height: 30px; + margin: 0 5px; + span { + font-size: 13px; + color: #fff; } + .control-btn { + display: block; + width: 12px; + height: 12px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + &.minus { + background-image: url(../../public/static/images/canvas/minus.svg); + } + &.plus { + background-image: url(../../public/static/images/canvas/plus.svg); + } + } + } } -} - -// 견적서 -.estimate-list-wrap{ - display: flex; - align-items: center; - margin-bottom: 10px; - &.one{ - .estimate-box{ - &:last-child{ - min-width: unset; - } - } - } - .estimate-box{ - flex: 1 ; - display: flex; - align-items: center; - &:last-child{ - flex: none; - min-width: 220px; - } - .estimate-tit{ - width: 105px; - height: 30px; - line-height: 30px; - background-color: #F4F4F7; - border-radius: 100px; - text-align: center; - font-size: 13px; - font-weight: 500; - color: #344356; - } - .estimate-name{ - font-size: 13px; - color: #344356; - margin-left: 14px; - font-weight: 400; - &.blue{ - font-size: 16px; - font-weight: 700; - color: #1083E3; - } - &.red{ - font-size: 16px; - font-weight: 700; - color: #D72A2A; - } - } - } - &:last-child{ - margin-bottom: 0; - } -} - -// file drag box -.drag-file-box{ - padding: 10px; - .btn-area{ - padding-bottom: 15px; - border-bottom: 1px solid #ECF0F4; - } - .drag-file-area{ - position: relative; - margin-top: 15px; - p{ - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 13px; - color: #ccc; - font-weight: 400; - cursor: default; - } - } - .file-list{ - .file-item{ - margin-bottom: 15px; - span{ - position: relative; - font-size: 13px; - color: #45576F; - font-weight: 400; - white-space: nowrap; - padding-right: 55px; - button{ - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 15px; - height: 15px; - background: url(../../public/static/images/sub/file_delete.svg)no-repeat center; - background-size: cover; - } - } - &:last-child{ - margin-bottom: 0; - } - } - } -} - -.special-note-check-wrap{ - display: grid; - grid-template-columns: repeat(5, 1fr); - border: 1px solid #ECF0F4; - border-radius: 3px; - margin-bottom: 30px; - .special-note-check-item{ - padding: 14px 10px; - border-right: 1px solid #ECF0F4; - border-top: 1px solid #ECF0F4; - &:nth-child(5n){ - border-right: none; - } - &:nth-child(-n+5){ - border-top: none; - } - &.act{ - background-color: #F7F9FA; - } - } -} - -.calculation-estimate{ - border: 1px solid #ECF0F4; - border-radius: 3px; - padding: 24px; - max-height: 350px; - overflow-y: auto; - margin-bottom: 30px; - dl{ - margin-bottom: 35px; - &:last-child{ - margin-bottom: 0; - } - dt{ - font-size: 13px; - font-weight: 600; - color: #1083E3; - margin-bottom: 15px; - } - dd{ - font-size: 12px; - font-weight: 400; - color: #45576F; - margin-bottom: 8px; - &:last-child{ - margin-bottom: 0; - } - } - } - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9dee2; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} -.esimate-wrap{ - margin-bottom: 20px; -} - -.estimate-product-option{ - display: flex; - align-items: center; - margin-bottom: 15px; - .product-price-wrap{ - display: flex; - align-items: center; - .product-price-tit{ - font-size: 13px; - font-weight: 400; - color: #45576F; - margin-right: 10px; - } - .select-wrap{ - width: 110px; - } - } - .product-edit-wrap{ - display: flex; - align-items: center; - margin-left: auto; - .product-edit-explane{ - display: flex; - align-items: center; - margin-right: 15px; - .attachment-required{ - position: relative; - display: flex; - align-items: center; - font-size: 12px; - font-weight: 400; - color: #45576F; - padding-right: 10px; - .ico{ - width: 23px; - height: 23px; - margin-right: 5px; - background: url(../../public/static/images/sub/attachment_ico.svg)no-repeat center; - background-size: cover; - } - &::before{ - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 12px; - background-color: #D9D9D9; - } - } - .click-check{ - display: flex; - align-items: center; - font-size: 12px; - font-weight: 400; - color: #F16A6A ; - padding-left: 10px; - .ico{ - width: 14px; - height: 14px; - margin-right: 5px; - background: url(../../public/static/images/sub/click_check_ico.svg)no-repeat center; - background-size: cover; - } - } - } - .product-edit-btn{ - display: flex; - align-items: center; - button{ - display: flex; - align-items: center; - span{ - width: 13px; - height: 13px; - margin-right: 5px; - background-size: cover; - &.plus{ - background: url(../../public/static/images/sub/plus_btn.svg)no-repeat center; - } - &.minus{ - background: url(../../public/static/images/sub/minus_btn.svg)no-repeat center; - } - } - } - } - } - -} - -// 발전시물레이션 -.chart-wrap{ - display: flex; - gap: 20px; + } + .canvas-depth2-wrap { + position: absolute; + top: -100%; + left: 0; + background-color: #383838; width: 100%; - .sub-table-box{ - height: 100%; - } - .chart-inner{ - flex: 1; - .chart-box{ - margin-bottom: 30px; - } - } - .chart-table-wrap{ + height: 50px; + transition: all 0.17s ease-in-out; + .canvas-depth2-inner { + display: flex; + align-items: center; + padding: 0 40px; + height: 100%; + .canvas-depth2-list { display: flex; - flex-direction: column; - flex: none; - width: 650px; - .sub-table-box{ - flex: 1; - &:first-child{ - margin-bottom: 20px; - } - } - } -} - -.chart-month-table{ - table{ - table-layout: fixed; - border-collapse:collapse; - border: 1px solid #ECF0F4; - border-radius: 4px; - thead{ - th{ - padding: 4.5px 0; - border-bottom: 1px solid #ECF0F4; - text-align: center; - font-size: 13px; - color: #45576F; - font-weight: 500; - background-color: #F8F9FA; - } - } - tbody{ - td{ - font-size: 13px; - color: #45576F; - text-align: center; - padding: 4.5px 0; - } - } - } -} - -.simulation-guide-wrap{ - display: flex; - padding: 20px; - .simulation-tit-wrap{ - padding-right: 40px; - border-right: 1px solid #EEEEEE; - span{ - display: block; + align-items: center; + height: 100%; + .canvas-depth2-item { + display: flex; + align-items: center; + margin-right: 26px; + height: 100%; + button { position: relative; - padding-left: 60px; - font-size: 15px; - color: #14324F; - font-weight: 600; - &::before{ + opacity: 0.55; + color: #fff; + font-size: 12px; + font-weight: normal; + height: 100%; + padding-right: 12px; + } + &.active { + button { + opacity: 1; + font-weight: 600; + &:after { content: ''; position: absolute; top: 50%; - left: 0; + right: 0; transform: translateY(-50%); - width: 40px; - height: 40px; - background: url(../../public/static/images/sub/simulation_guide.svg)no-repeat center; - background-size: cover; + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } } + } } - } - .simulation-guide-box{ - padding-left: 40px; - dl{ - margin-bottom: 25px; - dt{ - font-size: 13px; - color: #101010; - font-weight: 600; - margin-bottom: 5px; - } - dd{ - font-size: 12px; - color: #45576F; - font-weight: 400; - line-height: 24px; - } - &:last-child{ - margin-bottom: 0; + } + .canvas-depth2-btn-list { + display: flex; + align-items: center; + margin-left: auto; + height: 100%; + .depth2-btn-box { + display: flex; + align-items: center; + margin-right: 34px; + height: 100%; + transition: all 0.17s ease-in-out; + button { + position: relative; + font-size: 12px; + font-weight: 400; + height: 100%; + color: #fff; + padding-right: 12px; + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; } + } + &:last-child { + margin-right: 0; + } + &.mouse { + opacity: 0.55; + } } + } } + &.active { + top: 47px; + } + } + &.active { + padding-bottom: 50px; + } } -.module-total{ +// canvas-layout +.canvas-content { + padding-top: 46.8px; + transition: all 0.17s ease-in-out; + .canvas-frame { + height: 86.3vh; + } + &.active { + padding-top: calc(46.8px + 50px); + .canvas-frame { + height: 81vh; + } + } +} +.canvas-layout { + padding-top: 37px; + .canvas-page-list { + position: fixed; + top: 92.8px; + left: 0; + display: flex; + background-color: #1c1c1c; + border-top: 1px solid #000; + width: 100%; + transition: all 0.17s ease-in-out; + z-index: 999; + &.active { + top: calc(92.8px + 50px); + } + .canvas-plane-wrap { + display: flex; + align-items: center; + max-width: calc(100% - 45px); + .canvas-page-box { + display: flex; + align-items: center; + background-color: #1c1c1c; + padding: 9.6px 20px; + border-right: 1px solid #000; + min-width: 0; + transition: all 0.17s ease-in-out; + span { + display: flex; + align-items: center; + width: 100%; + font-size: 12px; + font-family: 'Pretendard', sans-serif; + color: #aaa; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .close { + flex: none; + display: block; + width: 7px; + height: 8px; + margin-left: 15px; + background: url(../../public/static/images/canvas/plan_close_gray.svg) no-repeat center; + background-size: cover; + } + &.on { + background-color: #fff; + span { + font-weight: 600; + color: #101010; + } + .close { + background: url(../../public/static/images/canvas/plan_close_black.svg) no-repeat center; + } + &:hover { + background-color: #fff; + } + } + &:hover { + background-color: #000; + } + } + } + .plane-add { + display: flex; + align-items: center; + justify-content: center; + width: 45px; + padding: 13.5px 0; + background-color: #1c1c1c; + border-right: 1px solid #000; + transition: all 0.17s ease-in-out; + span { + display: block; + width: 9px; + height: 9px; + background: url(../../public/static/images/canvas/plane_add.svg) no-repeat center; + background-size: cover; + } + &:hover { + background-color: #000; + } + } + } +} + +.canvas-frame { + position: relative; + // height: calc(100% - 36.5px); + background-color: #f4f4f7; + overflow: auto; + transition: all 0.17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } + canvas { + background-color: #fff; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +// sub-page +.sub-header { + position: fixed; + top: 46px; + left: 0; + width: 100%; + height: 46px; + border-bottom: 1px solid #000; + background: #2c2c2c; + z-index: 999; + .sub-header-inner { display: flex; align-items: center; - background-color: #F8F9FA; - padding: 9px 0; - margin-right: 4px; - border: 1px solid #ECF0F4; - border-top: none; - .total-title{ - flex: 1; + height: 100%; + padding: 0 100px; + .sub-header-title-wrap { + display: flex; + align-items: center; + .title-item { + position: relative; + padding: 0 24px; + a { + display: flex; + align-items: center; + .icon { + width: 22px; + height: 22px; + margin-right: 8px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.drawing { + background-image: url(../../public/static/images/main/drawing_icon.svg); + } + } + } + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 16px; + background-color: #d9d9d9; + } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + &:after { + display: none; + } + } + } + } + .sub-header-title { + font-size: 16px; + color: #fff; + font-weight: 600; + } + .sub-header-location { + margin-left: auto; + display: flex; + align-items: center; + .location-item { + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + span { + display: flex; + font-size: 12px; + color: #aaa; + font-weight: normal; + cursor: default; + } + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4px; + height: 6px; + background: url(../../public/static/images/main/loaction_arr.svg) no-repeat center; + } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + span { + color: #fff; + } + &:after { + display: none; + } + } + } + } + } +} + +// sub content +.sub-content { + padding-top: 46px; + .sub-content-inner { + max-width: 1720px; + margin: 0 auto; + padding-top: 20px; + .sub-content-box { + margin-bottom: 20px; + &:last-child { + margin-bottom: 0; + } + } + } + &.estimate { + display: flex; + flex-direction: column; + padding-top: 0; + .sub-content-inner { + flex: 1; + width: 100%; + } + } +} +.sub-table-box { + padding: 20px; + border-radius: 6px; + border: 1px solid #e9eaed; + background: #fff; + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + .table-box-title-wrap { + display: flex; + align-items: center; + margin-bottom: 15px; + .title-wrap { + display: flex; + align-items: center; + h3 { + display: block; + font-size: 15px; + color: #101010; + font-weight: 600; + margin-right: 14px; + &.product { + margin-right: 10px; + } + } + .product_tit { + position: relative; + font-size: 15px; + font-weight: 600; + color: #1083e3; + padding-left: 10px; + &::before { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #d9d9d9; + } + } + .option { + padding-left: 5px; + font-size: 13px; + color: #101010; + font-weight: 400; + } + .info-wrap { + display: flex; + align-items: center; + li { + position: relative; + padding: 0 6px; + font-size: 12px; + color: #101010; + font-weight: normal; + span { + font-weight: 600; + &.red { + color: #e23d70; + } + } + &:after { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #d9d9d9; + } + &:first-child { + padding-left: 0; + } + &:last-child { + padding-right: 0; + &::after { + display: none; + } + } + } + } + } + } + .left-unit-box { + margin-left: auto; + display: flex; + align-items: center; + } + .promise-gudie { + display: block; + font-size: 13px; + font-weight: 700; + color: #101010; + margin-bottom: 20px; + } + .important { + color: #f00; + } + .sub-center-footer { + display: flex; + align-items: center; + justify-content: center; + margin-top: 20px; + } + .sub-right-footer { + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: 20px; + } +} +.pagination-wrap { + margin-top: 24px; +} + +.infomation-wrap { + margin-bottom: 30px; +} + +.infomation-box-wrap { + display: flex; + align-items: center; + gap: 10px; + .sub-table-box { + flex: 1; + } + .info-title { + font-size: 14px; + font-weight: 500; + color: #344356; + margin-bottom: 10px; + } + .info-inner { + position: relative; + font-size: 13px; + color: #344356; + .copy-ico { + position: absolute; + bottom: 0; + right: 0; + width: 16px; + height: 16px; + background: url(../../public/static/images/sub/copy_ico.svg) no-repeat center; + background-size: cover; + } + } +} + +// 견적서 +.estimate-list-wrap { + display: flex; + align-items: center; + margin-bottom: 10px; + &.one { + .estimate-box { + &:last-child { + min-width: unset; + } + } + } + .estimate-box { + flex: 1; + display: flex; + align-items: center; + &:last-child { + flex: none; + min-width: 220px; + } + .estimate-tit { + width: 105px; + height: 30px; + line-height: 30px; + background-color: #f4f4f7; + border-radius: 100px; + text-align: center; + font-size: 13px; + font-weight: 500; + color: #344356; + } + .estimate-name { + font-size: 13px; + color: #344356; + margin-left: 14px; + font-weight: 400; + &.blue { + font-size: 16px; + font-weight: 700; + color: #1083e3; + } + &.red { + font-size: 16px; + font-weight: 700; + color: #d72a2a; + } + } + } + &:last-child { + margin-bottom: 0; + } +} + +// file drag box +.drag-file-box { + padding: 10px; + .btn-area { + padding-bottom: 15px; + border-bottom: 1px solid #ecf0f4; + } + .drag-file-area { + position: relative; + margin-top: 15px; + p { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 13px; + color: #ccc; + font-weight: 400; + cursor: default; + } + } + .file-list { + .file-item { + margin-bottom: 15px; + span { + position: relative; + font-size: 13px; + color: #45576f; + font-weight: 400; + white-space: nowrap; + padding-right: 55px; + button { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 15px; + height: 15px; + background: url(../../public/static/images/sub/file_delete.svg) no-repeat center; + background-size: cover; + } + } + &:last-child { + margin-bottom: 0; + } + } + } +} + +.special-note-check-wrap { + display: grid; + grid-template-columns: repeat(5, 1fr); + border: 1px solid #ecf0f4; + border-radius: 3px; + margin-bottom: 30px; + .special-note-check-item { + padding: 14px 10px; + border-right: 1px solid #ecf0f4; + border-top: 1px solid #ecf0f4; + &:nth-child(5n) { + border-right: none; + } + &:nth-child(-n + 5) { + border-top: none; + } + &.act { + background-color: #f7f9fa; + } + } +} + +.calculation-estimate { + border: 1px solid #ecf0f4; + border-radius: 3px; + padding: 24px; + max-height: 350px; + overflow-y: auto; + margin-bottom: 30px; + dl { + margin-bottom: 35px; + &:last-child { + margin-bottom: 0; + } + dt { + font-size: 13px; + font-weight: 600; + color: #1083e3; + margin-bottom: 15px; + } + dd { + font-size: 12px; + font-weight: 400; + color: #45576f; + margin-bottom: 8px; + &:last-child { + margin-bottom: 0; + } + } + } + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #d9dee2; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} +.esimate-wrap { + margin-bottom: 20px; +} + +.estimate-product-option { + display: flex; + align-items: center; + margin-bottom: 15px; + .product-price-wrap { + display: flex; + align-items: center; + .product-price-tit { + font-size: 13px; + font-weight: 400; + color: #45576f; + margin-right: 10px; + } + .select-wrap { + width: 110px; + } + } + .product-edit-wrap { + display: flex; + align-items: center; + margin-left: auto; + .product-edit-explane { + display: flex; + align-items: center; + margin-right: 15px; + .attachment-required { + position: relative; + display: flex; + align-items: center; + font-size: 12px; + font-weight: 400; + color: #45576f; + padding-right: 10px; + .ico { + width: 23px; + height: 23px; + margin-right: 5px; + background: url(../../public/static/images/sub/attachment_ico.svg) no-repeat center; + background-size: cover; + } + &::before { + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 12px; + background-color: #d9d9d9; + } + } + .click-check { + display: flex; + align-items: center; + font-size: 12px; + font-weight: 400; + color: #f16a6a; + padding-left: 10px; + .ico { + width: 14px; + height: 14px; + margin-right: 5px; + background: url(../../public/static/images/sub/click_check_ico.svg) no-repeat center; + background-size: cover; + } + } + } + .product-edit-btn { + display: flex; + align-items: center; + button { + display: flex; + align-items: center; + span { + width: 13px; + height: 13px; + margin-right: 5px; + background-size: cover; + &.plus { + background: url(../../public/static/images/sub/plus_btn.svg) no-repeat center; + } + &.minus { + background: url(../../public/static/images/sub/minus_btn.svg) no-repeat center; + } + } + } + } + } +} + +// 발전시물레이션 +.chart-wrap { + display: flex; + gap: 20px; + width: 100%; + .sub-table-box { + height: 100%; + } + .chart-inner { + flex: 1; + .chart-box { + margin-bottom: 30px; + } + } + .chart-table-wrap { + display: flex; + flex-direction: column; + flex: none; + width: 650px; + .sub-table-box { + flex: 1; + &:first-child { + margin-bottom: 20px; + } + } + } +} + +.chart-month-table { + table { + table-layout: fixed; + border-collapse: collapse; + border: 1px solid #ecf0f4; + border-radius: 4px; + thead { + th { + padding: 4.5px 0; + border-bottom: 1px solid #ecf0f4; text-align: center; font-size: 13px; - color: #344356; + color: #45576f; font-weight: 500; + background-color: #f8f9fa; + } } - .total-num{ - flex: none; - width: 121px; + tbody { + td { + font-size: 13px; + color: #45576f; text-align: center; - font-size: 15px; - color: #344356; - font-weight: 500; + padding: 4.5px 0; + } } + } +} + +.simulation-guide-wrap { + display: flex; + padding: 20px; + .simulation-tit-wrap { + padding-right: 40px; + border-right: 1px solid #eeeeee; + span { + display: block; + position: relative; + padding-left: 60px; + font-size: 15px; + color: #14324f; + font-weight: 600; + &::before { + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 40px; + height: 40px; + background: url(../../public/static/images/sub/simulation_guide.svg) no-repeat center; + background-size: cover; + } + } + } + .simulation-guide-box { + padding-left: 40px; + dl { + margin-bottom: 25px; + dt { + font-size: 13px; + color: #101010; + font-weight: 600; + margin-bottom: 5px; + } + dd { + font-size: 12px; + color: #45576f; + font-weight: 400; + line-height: 24px; + } + &:last-child { + margin-bottom: 0; + } + } + } +} + +.module-total { + display: flex; + align-items: center; + background-color: #f8f9fa; + padding: 9px 0; + margin-right: 4px; + border: 1px solid #ecf0f4; + border-top: none; + .total-title { + flex: 1; + text-align: center; + font-size: 13px; + color: #344356; + font-weight: 500; + } + .total-num { + flex: none; + width: 121px; + text-align: center; + font-size: 15px; + color: #344356; + font-weight: 500; + } } // 물건상세 -.information-help-wrap{ +.information-help-wrap { + display: flex; + padding: 24px; + background-color: #f4f4f4; + border-radius: 4px; + margin-bottom: 15px; + .information-help-tit-wrap { + position: relative; display: flex; - padding: 24px; - background-color: #F4F4F4; - border-radius: 4px; - margin-bottom: 15px; - .information-help-tit-wrap{ - position: relative; - display: flex; - align-items: center; - padding-right: 40px; - border-right: 1px solid #E0E0E3; - .help-tit-icon{ - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - background: #fff url(../../public/static/images/sub/information_help.svg)no-repeat center; - background-size: 20px 20px; - } - .help-tit{ - font-size: 13px; - font-weight: 600; - color: #45576F; - } + align-items: center; + padding-right: 40px; + border-right: 1px solid #e0e0e3; + .help-tit-icon { + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + background: #fff url(../../public/static/images/sub/information_help.svg) no-repeat center; + background-size: 20px 20px; } - .information-help-guide{ - padding-left: 40px; - span{ - display: block; - font-size: 12px; - font-weight: 400; - color: #45576F; - margin-bottom: 7px; - &:last-child{ - margin-bottom: 0; - } - } + .help-tit { + font-size: 13px; + font-weight: 600; + color: #45576f; } + } + .information-help-guide { + padding-left: 40px; + span { + display: block; + font-size: 12px; + font-weight: 400; + color: #45576f; + margin-bottom: 7px; + &:last-child { + margin-bottom: 0; + } + } + } } -.community-search-warp{ +.community-search-warp { + display: flex; + flex-direction: column; + align-items: center; + padding: 10px 0 30px 0; + border-bottom: 1px solid #e5e5e5; + margin-bottom: 24px; + .community-search-box { + position: relative; display: flex; - flex-direction: column; align-items: center; - padding: 10px 0 30px 0; - border-bottom: 1px solid #E5E5E5; - margin-bottom: 24px; - .community-search-box{ - position: relative; - display: flex; - align-items: center; - width: 580px; - height: 45px; - padding: 0 45px 0 20px; - margin-bottom: 20px; - border-radius: 2px; - border: 1px solid #101010; - .community-input{ - width: 100%; - height: 100%; - font-size: 13px; - font-weight: 400; - color: #101010; - &::placeholder{ - color: #C8C8C8; - } - } - .community-search-ico{ - position: absolute; - top: 50%; - right: 20px; - transform: translateY(-50%); - flex: none; - width: 21px; - height: 100%; - background: url(../../public/static/images/sub/community_search.svg)no-repeat center; - background-size: 21px 21px; - z-index: 3; - } + width: 580px; + height: 45px; + padding: 0 45px 0 20px; + margin-bottom: 20px; + border-radius: 2px; + border: 1px solid #101010; + .community-input { + width: 100%; + height: 100%; + font-size: 13px; + font-weight: 400; + color: #101010; + &::placeholder { + color: #c8c8c8; + } } - .community-search-keyword{ - font-size: 13px; - font-weight: 400; - color: #45576F; - span{ - font-weight: 600; - color: #F16A6A; - } + .community-search-ico { + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); + flex: none; + width: 21px; + height: 100%; + background: url(../../public/static/images/sub/community_search.svg) no-repeat center; + background-size: 21px 21px; + z-index: 3; } + } + .community-search-keyword { + font-size: 13px; + font-weight: 400; + color: #45576f; + span { + font-weight: 600; + color: #f16a6a; + } + } } // 자료 다운로드 -.file-down-list{ - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - .file-down-item{ - display: flex; - align-items: center; - padding: 24px; - border-radius: 4px; - border: 1px solid #E5E5E5; - background: #FFF; - transition: all .15s ease-in-out; - cursor: pointer; - .file-item-info{ - .item-num{ - display: inline-block; - padding: 6px 17.5px; - border-radius: 60px; - background-color: #F4F4F7; - font-size: 13px; - font-weight: 600; - color: #101010; - margin-bottom: 15px; - } - .item-name{ - font-size: 16px; - color: #101010; - font-weight: 500; - margin-bottom: 13px; - } - .item-date{ - font-size: 13px; - font-weight: 400; - color: #344356; - } - } - .file-down-box{ - display: flex; - align-items: center; - flex: none; - margin-left: auto; - height: 100%; - .file-down-btn{ - width: 36px; - height: 36px; - background: url(../../public/static/images/sub/file_down_btn.svg)no-repeat center; - background-size: cover; - } - } - &:hover{ - background-color: #F4F4F7; - } +.file-down-list { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + .file-down-item { + display: flex; + align-items: center; + padding: 24px; + border-radius: 4px; + border: 1px solid #e5e5e5; + background: #fff; + transition: all 0.15s ease-in-out; + cursor: pointer; + .file-item-info { + .item-num { + display: inline-block; + padding: 6px 17.5px; + border-radius: 60px; + background-color: #f4f4f7; + font-size: 13px; + font-weight: 600; + color: #101010; + margin-bottom: 15px; + } + .item-name { + font-size: 16px; + color: #101010; + font-weight: 500; + margin-bottom: 13px; + } + .item-date { + font-size: 13px; + font-weight: 400; + color: #344356; + } } -} \ No newline at end of file + .file-down-box { + display: flex; + align-items: center; + flex: none; + margin-left: auto; + height: 100%; + .file-down-btn { + width: 36px; + height: 36px; + background: url(../../public/static/images/sub/file_down_btn.svg) no-repeat center; + background-size: cover; + } + } + &:hover { + background-color: #f4f4f7; + } + } +} + +.file-down-nodata { + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #e5e5e5; + font-size: 16px; + font-weight: 500; + color: #344356; +} diff --git a/src/styles/_main.scss b/src/styles/_main.scss index 92c9f8c8..6a2a06e6 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -114,12 +114,12 @@ box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); &.item01 { flex: 1; - max-height: 400px; + height: 400px; } &.item02 { flex: none; width: 451px; - max-height: 400px; + height: 400px; } &.item03 { flex: 1; From 7e6b8ffff364aeafadfe2623638a171b14e20c4c Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 18 Oct 2024 18:09:48 +0900 Subject: [PATCH 010/139] =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EB=93=9C=20=ED=91=9C?= =?UTF-8?q?=EC=8B=9C,=20=EC=99=B8=EB=B2=BD=EC=84=A0=20=ED=91=9C=EC=8B=9C,?= =?UTF-8?q?=20=EC=A7=80=EB=B6=95=EC=84=A0=20=ED=91=9C=EC=8B=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/grid/DotLineGrid.jsx | 6 +- .../modal/setting01/FirstOption.jsx | 3 +- src/hooks/roofcover/useOuterLineWall.js | 7 ++ src/store/settingAtom.js | 103 +++++++++++++++++- 4 files changed, 114 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index eb5a834e..d9919351 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -7,7 +7,7 @@ import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState import { onlyNumberInputChange } from '@/util/input-utils' import { fabric } from 'fabric' import { gridColorState } from '@/store/gridAtom' -import { settingModalGridOptionsState } from '@/store/settingAtom' +import { gridDisplaySelector, settingModalGridOptionsState } from '@/store/settingAtom' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' @@ -24,6 +24,7 @@ export default function DotLineGrid(props) { const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) const gridColor = useRecoilValue(gridColorState) const canvas = useRecoilValue(canvasState) + const isGridDisplay = useRecoilValue(gridDisplaySelector) const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState) const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState) @@ -179,6 +180,7 @@ export default function DotLineGrid(props) { fill: pattern, selectable: false, name: 'dotGrid', + visible: isGridDisplay, }, ) @@ -209,6 +211,7 @@ export default function DotLineGrid(props) { strokeDashArray: [5, 2], opacity: 0.3, direction: 'horizontal', + visible: isGridDisplay, }, ) canvas.add(horizontalLine) @@ -235,6 +238,7 @@ export default function DotLineGrid(props) { strokeDashArray: [5, 2], opacity: 0.3, direction: 'vertical', + visible: isGridDisplay, }, ) canvas.add(verticalLine) diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index bd24d738..848596ba 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -1,10 +1,9 @@ import { useRecoilState } from 'recoil' -import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' -import { adsorptionPointAddModeState } from '@/store/canvasAtom' import { useFirstOption } from '@/hooks/option/useFirstOption' export default function FirstOption() { diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js index 85c37015..4b4987af 100644 --- a/src/hooks/roofcover/useOuterLineWall.js +++ b/src/hooks/roofcover/useOuterLineWall.js @@ -30,6 +30,7 @@ import { import { calculateAngle } from '@/util/qpolygon-utils' import { fabric } from 'fabric' import { QLine } from '@/components/fabric/QLine' +import { outlineDisplaySelector } from '@/store/settingAtom' //외벽선 그리기 export function useOuterLineWall(setShowOutlineModal) { @@ -53,6 +54,8 @@ export function useOuterLineWall(setShowOutlineModal) { const adsorptionRange = useRecoilValue(adsorptionRangeState) const interval = useRecoilValue(dotLineIntervalSelector) // 가로 세로 간격 + const isOutlineDisplay = useRecoilValue(outlineDisplaySelector) + const length1Ref = useRef(null) const length2Ref = useRef(null) const angle1Ref = useRef(null) @@ -253,6 +256,7 @@ export function useOuterLineWall(setShowOutlineModal) { strokeWidth: 1, selectable: false, name: 'helpGuideLine', + visible: isOutlineDisplay, }) } else { const guideLine1 = addLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], { @@ -260,6 +264,7 @@ export function useOuterLineWall(setShowOutlineModal) { strokeWidth: 1, strokeDashArray: [1, 1, 1], name: 'helpGuideLine', + visible: isOutlineDisplay, }) const guideLine2 = addLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], { @@ -267,6 +272,7 @@ export function useOuterLineWall(setShowOutlineModal) { strokeWidth: 1, strokeDashArray: [1, 1, 1], name: 'helpGuideLine', + visible: isOutlineDisplay, }) } } @@ -283,6 +289,7 @@ export function useOuterLineWall(setShowOutlineModal) { y1: point1.y, x2: point2.x, y2: point2.y, + visible: isOutlineDisplay, }) } diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 6ec454be..8560c700 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -15,12 +15,12 @@ export const settingModalFirstOptionsState = atom({ { id: 9, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: false }, ], dimensionDisplay: [ - { id: 1, column: 'corridorDimension', name: 'modal.canvas.setting.first.option.corridor.dimension', selected: false }, + { id: 1, column: 'corridorDimension', name: 'modal.canvas.setting.first.option.corridor.dimension', selected: true }, { id: 2, column: 'realDimension', name: 'modal.canvas.setting.first.option.real.dimension', selected: false }, { id: 3, column: 'noneDimension', name: 'modal.canvas.setting.first.option.none.dimension', selected: false }, ], option2: [ - { id: 1, column: 'onlyBorder', name: 'modal.canvas.setting.first.option.border', selected: false }, + { id: 1, column: 'onlyBorder', name: 'modal.canvas.setting.first.option.border', selected: true }, { id: 2, column: 'lineHatch', name: 'modal.canvas.setting.first.option.line', selected: false }, { id: 3, column: 'allPainted', name: 'modal.canvas.setting.first.option.all', selected: false }, ], @@ -57,3 +57,102 @@ export const settingModalGridOptionsState = atom({ ], dangerouslyAllowMutability: true, }) + +// 디스플레이 설정 - 할당 표시 +export const allocDisplaySelector = selector({ + key: 'allocDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'allocDisplay').selected + }, +}) + +// 디스플레이 설정 - 외벽선 표시 +export const outlineDisplaySelector = selector({ + key: 'outlineDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'outlineDisplay').selected + }, +}) + +// 디스플레이 설정 - 그리드 표시 +export const gridDisplaySelector = selector({ + key: 'gridDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'gridDisplay').selected + }, +}) + +// 디스플레이 설정 - 지붕선 표시 +export const roofLineDisplaySelector = selector({ + key: 'lineDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'lineDisplay').selected + }, +}) + +// 디스플레이 설정 - 문자 표시 +export const wordDisplaySelector = selector({ + key: 'wordDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'wordDisplay').selected + }, +}) + +// 디스플레이 설정 - 회로번호 표시 +export const circuitNumDisplaySelector = selector({ + key: 'circuitNumDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'circuitNumDisplay').selected + }, +}) + +// 디스플레이 설정 - 흐름 방향 표시 +export const flowDisplaySelector = selector({ + key: 'flowDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'flowDisplay').selected + }, +}) + +// 디스플레이 설정 - 가대 표시 +export const trestleDisplaySelector = selector({ + key: 'trestleDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'trestleDisplay').selected + }, +}) + +// 디스플레이 설정 - 집계표 표시 +export const totalDisplaySelector = selector({ + key: 'totalDisplaySelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.option1.find((option) => option.column === 'totalDisplay').selected + }, +}) + +// 디스플레이 설정 - 치수 표시 +export const corridorDimensionSelector = selector({ + key: 'corridorDimensionSelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.dimensionDisplay.find((option) => option.selected) + }, +}) + +// 디스플레이 설정 - 화면 표시 +export const realDimensionSelector = selector({ + key: 'realDimensionSelector', + get: ({ get }) => { + const settingModalFirstOptions = get(settingModalFirstOptionsState) + return settingModalFirstOptions.dimensionDisplay.find((option) => option.selected) + }, +}) From 5085134c685244204aba0968eff830bf7c308e30 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 18 Oct 2024 18:10:37 +0900 Subject: [PATCH 011/139] refactor: Modify getMessage function --- src/app/QcastProvider.js | 25 +++++++++++-------------- src/hooks/useMessage.js | 11 +++++++---- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/app/QcastProvider.js b/src/app/QcastProvider.js index 3ae0993d..84a5638e 100644 --- a/src/app/QcastProvider.js +++ b/src/app/QcastProvider.js @@ -1,27 +1,24 @@ 'use client' -import { useEffect } from 'react' -import { useRecoilState, useRecoilValue } from 'recoil' -import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { ErrorBoundary } from 'next/dist/client/components/error-boundary' import ServerError from './error' import '@/styles/common.scss' -import KO from '@/locales/ko.json' -import JA from '@/locales/ja.json' +// import KO from '@/locales/ko.json' +// import JA from '@/locales/ja.json' export const QcastProvider = ({ children }) => { - const globalLocale = useRecoilValue(globalLocaleStore) - const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) + // const globalLocale = useRecoilValue(globalLocaleStore) + // const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) - useEffect(() => { - if (globalLocale === 'ko') { - setAppMessageState(KO) - } else { - setAppMessageState(JA) - } - }, [globalLocale]) + // useEffect(() => { + // if (globalLocale === 'ko') { + // setAppMessageState(KO) + // } else { + // setAppMessageState(JA) + // } + // }, [globalLocale]) return ( <> diff --git a/src/hooks/useMessage.js b/src/hooks/useMessage.js index f336f0b7..3a2fc316 100644 --- a/src/hooks/useMessage.js +++ b/src/hooks/useMessage.js @@ -1,14 +1,17 @@ +import { useEffect } from 'react' import { useRecoilValue } from 'recoil' -import { appMessageStore } from '@/store/localeAtom' +import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -// import KO from '@/locales/ko.json' -// import JA from '@/locales/ja.json' +import KO from '@/locales/ko.json' +import JA from '@/locales/ja.json' const SESSION_STORAGE_MESSAGE_KEY = 'QCAST_MESSAGE_STORAGE' export const useMessage = () => { // const globalLocale = useRecoilValue(globalLocaleState) - const appMessageState = useRecoilValue(appMessageStore) + // const appMessageState = useRecoilValue(appMessageStore) + const globalLocale = useRecoilValue(globalLocaleStore) + const appMessageState = globalLocale === 'ko' ? KO : JA const getMessage = (key, args = []) => { // if (sessionStorage.getItem(SESSION_STORAGE_MESSAGE_KEY) === null) { From 0262e47dd32fd5394681c6c74987652ec09847ca Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 18 Oct 2024 18:20:04 +0900 Subject: [PATCH 012/139] =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EB=93=9C=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=9E=84=EC=9D=98=20=EA=B7=B8=EB=A6=AC=EB=93=9C=20?= =?UTF-8?q?=EB=B0=8F=20=ED=9D=A1=EC=B0=A9=EC=A0=90=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useAdsorptionPoint.js | 4 +++- src/hooks/useEvent.js | 1 + src/hooks/useTempGrid.js | 4 ++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/hooks/useAdsorptionPoint.js b/src/hooks/useAdsorptionPoint.js index 49d49714..396db98c 100644 --- a/src/hooks/useAdsorptionPoint.js +++ b/src/hooks/useAdsorptionPoint.js @@ -2,13 +2,14 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { adsorptionPointAddModeState, adsorptionPointModeState, adsorptionRangeState, canvasState } from '@/store/canvasAtom' import { fabric } from 'fabric' import { useMouse } from '@/hooks/useMouse' +import { gridDisplaySelector } from '@/store/settingAtom' export function useAdsorptionPoint() { const canvas = useRecoilValue(canvasState) const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState) const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) const [adsorptionRange, setAdsorptionRange] = useRecoilState(adsorptionRangeState) - + const isGridDisplay = useRecoilValue(gridDisplaySelector) const { getIntersectMousePoint } = useMouse() const getAdsorptionPoints = () => { @@ -28,6 +29,7 @@ export function useAdsorptionPoint() { y: pointer.y, selectable: true, name: 'adsorptionPoint', + visible: isGridDisplay, }) canvas.add(adsorptionPoint) diff --git a/src/hooks/useEvent.js b/src/hooks/useEvent.js index ee41988d..a84dea38 100644 --- a/src/hooks/useEvent.js +++ b/src/hooks/useEvent.js @@ -6,6 +6,7 @@ import { calculateDistance, calculateIntersection, distanceBetweenPoints, findCl import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useDotLineGrid } from '@/hooks/useDotLineGrid' import { useTempGrid } from '@/hooks/useTempGrid' +import { gridDisplaySelector } from '@/store/settingAtom' export function useEvent() { const canvas = useRecoilValue(canvasState) diff --git a/src/hooks/useTempGrid.js b/src/hooks/useTempGrid.js index 8d7bac42..30847a2f 100644 --- a/src/hooks/useTempGrid.js +++ b/src/hooks/useTempGrid.js @@ -1,11 +1,13 @@ import { canvasState, tempGridModeState } from '@/store/canvasAtom' import { useRecoilState, useRecoilValue } from 'recoil' import { gridColorState } from '@/store/gridAtom' +import { gridDisplaySelector } from '@/store/settingAtom' export function useTempGrid() { const canvas = useRecoilValue(canvasState) const gridColor = useRecoilValue(gridColorState) const [tempGridMode, setTempGridMode] = useRecoilState(tempGridModeState) + const isGridDisplay = useRecoilValue(gridDisplaySelector) const tempGridModeStateLeftClickEvent = (e) => { //임의 그리드 모드일 경우 let pointer = canvas.getPointer(e.e) @@ -22,6 +24,7 @@ export function useTempGrid() { strokeDashArray: [5, 2], opacity: 0.3, direction: 'vertical', + visible: isGridDisplay, name: 'tempGrid', }) @@ -48,6 +51,7 @@ export function useTempGrid() { strokeDashArray: [5, 2], opacity: 0.3, name: 'tempGrid', + visible: isGridDisplay, direction: 'horizontal', }) From 1b44edbac354a2de11380aee9a756188cf15858c Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 10:56:15 +0900 Subject: [PATCH 013/139] feat: Add locale switch --- src/app/layout.js | 4 +++- src/components/LocaleSwitch.jsx | 23 +++++++++++++++++++++++ src/styles/style.scss | 6 +++++- 3 files changed, 31 insertions(+), 2 deletions(-) create mode 100644 src/components/LocaleSwitch.jsx diff --git a/src/app/layout.js b/src/app/layout.js index e59e28d1..64b374e8 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -16,6 +16,7 @@ import '../styles/style.scss' import '../styles/contents.scss' import Dimmed from '@/components/ui/Dimmed' import SessionProvider from './SessionProvider' +import LocaleSwitch from '@/components/LocaleSwitch' // const inter = Inter({ subsets: ['latin'] }) @@ -76,8 +77,9 @@ export default async function RootLayout({ children }) {
-
+
COPYRIGHT©2024 Hanwha Japan All Rights Reserved. +
diff --git a/src/components/LocaleSwitch.jsx b/src/components/LocaleSwitch.jsx new file mode 100644 index 00000000..291f2043 --- /dev/null +++ b/src/components/LocaleSwitch.jsx @@ -0,0 +1,23 @@ +'use client' + +import { globalLocaleStore } from '@/store/localeAtom' +import { useRecoilState } from 'recoil' + +export default function LocaleSwitch() { + const [globalLocale, setGlobalLocale] = useRecoilState(globalLocaleStore) + + return ( + { + if (globalLocale === 'ko') { + setGlobalLocale('ja') + } else { + setGlobalLocale('ko') + } + }} + > + {globalLocale.toUpperCase()} + + ) +} diff --git a/src/styles/style.scss b/src/styles/style.scss index 1841ebb9..39343d54 100644 --- a/src/styles/style.scss +++ b/src/styles/style.scss @@ -1 +1,5 @@ -@import '_main.scss'; \ No newline at end of file +@import '_main.scss'; + +.locale-switch { + cursor: pointer; +} From 909adc63fc2ad50f90e7b0a4efaa29d721ea38b5 Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 21 Oct 2024 11:23:29 +0900 Subject: [PATCH 014/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=ED=99=94=EB=A9=B4=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 2 - .../management/StuffSearchCondition.jsx | 115 ++++++++++++------ 2 files changed, 78 insertions(+), 39 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 5ce7c8b3..58cd7bff 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -245,7 +245,6 @@ export default function Stuff() { } async function fetchData() { - // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(params)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` await get({ url: apiUrl, @@ -294,7 +293,6 @@ export default function Stuff() { useEffect(() => { if (stuffSearchParams?.code === 'E') { - //console.log('조회누름::::::::', stuffSearchParams, sessionState) stuffSearchParams.startRow = 1 stuffSearchParams.endRow = 1 * pageSize stuffSearchParams.schSortType = defaultSortType diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index ed84073c..0326f28e 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -24,6 +24,13 @@ export default function StuffSearchCondition() { const ref = useRef() const { get } = useAxios(globalLocaleState) + const objectNoRef = useRef(null) + const saleStoreNameRef = useRef(null) + const addressRef = useRef(null) + const objectNameRef = useRef(null) + const dispCompanyNameRef = useRef(null) + const receiveUserRef = useRef(null) + //달력 props 관련 날짜 셋팅 const [startDate, setStartDate] = useState(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')) const [endDate, setEndDate] = useState(dayjs(new Date()).format('YYYY-MM-DD')) @@ -42,13 +49,13 @@ export default function StuffSearchCondition() { const resetStuffRecoil = useResetRecoilState(stuffSearchState) const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const [objectNo, setObjectNo] = useState('') //물건번호 + const [saleStoreName, setSaleStoreName] = useState('') //판매대리점명 const [address, setAddress] = useState('') //물건주소 const [objectName, setobjectName] = useState('') //물건명 - const [saleStoreName, setSaleStoreName] = useState('') //판매대리점명 - const [receiveUser, setReceiveUser] = useState('') //담당자 const [dispCompanyName, setDispCompanyName] = useState('') //견적처 - const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R) const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //판매대리점 선택 + const [receiveUser, setReceiveUser] = useState('') //담당자 + const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R) const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT // 조회 @@ -58,26 +65,52 @@ export default function StuffSearchCondition() { return alert(getMessage('stuff.message.periodError')) } - setStuffSearch({ - schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo, - schAddress: stuffSearch?.schAddress ? stuffSearch.schAddress : address, - schObjectName: stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName, - schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName, - schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser, - schDispCompanyName: stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName, - schDateType: stuffSearch?.schDateType ? stuffSearch.schDateType : dateType, - schFromDt: dayjs(startDate).format('YYYY-MM-DD'), - schToDt: dayjs(endDate).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', - }) + if (stuffSearch.code === 'S') { + setStuffSearch({ + schObjectNo: objectNo ? objectNo : stuffSearch?.schObjectNo, + schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch?.schSaleStoreName : saleStoreName, + schAddress: address ? address : stuffSearch?.schAddress, + schObjectName: objectName ? objectName : stuffSearch?.schObjectName, + schDispCompanyName: dispCompanyName ? dispCompanyName : stuffSearch?.schDispCompanyName, + schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : schSelSaleStoreId, + schReceiveUser: receiveUser ? receiveUser : stuffSearch?.schReceiveUser, + schDateType: stuffSearch?.schDateType ? stuffSearch.schDateType : dateType, + schFromDt: dayjs(startDate).format('YYYY-MM-DD'), + schToDt: dayjs(endDate).format('YYYY-MM-DD'), + code: 'E', + startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, + endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, + schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', + }) + } else { + setStuffSearch({ + schObjectNo: objectNo ? objectNo : '', + schSaleStoreName: saleStoreName ? saleStoreName : '', + schAddress: address ? address : '', + schObjectName: objectName ? objectName : '', + schDispCompanyName: dispCompanyName ? dispCompanyName : '', + schSelSaleStoreId: schSelSaleStoreId ? schSelSaleStoreId : '', + schReceiveUser: receiveUser ? receiveUser : '', + schDateType: dateType, + schFromDt: dayjs(startDate).format('YYYY-MM-DD'), + schToDt: dayjs(endDate).format('YYYY-MM-DD'), + code: 'E', + startRow: 1, + endRow: 100, + schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', + }) + } } //초기화 const resetRecoil = () => { + objectNoRef.current.value = '' + saleStoreNameRef.current.value = '' + addressRef.current.value = '' + objectNameRef.current.value = '' + dispCompanyNameRef.current.value = '' + receiveUserRef.current.value = '' + setObjectNo('') setAddress('') setobjectName('') @@ -143,6 +176,13 @@ export default function StuffSearchCondition() { } }, [globalLocaleState]) + // 엔터 이벤트 + const handleByOnKeyUp = (e) => { + if (e.key === 'Enter') { + onSubmit() + } + } + return ( <> {/* 퍼블적용시작 */} @@ -182,12 +222,13 @@ export default function StuffSearchCondition() {
{ - setObjectNo(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schObjectNo: e.target.value }) + setObjectNo(objectNoRef.current.value) }} + onKeyUp={handleByOnKeyUp} />
@@ -196,11 +237,11 @@ export default function StuffSearchCondition() {
{ - setSaleStoreName(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schSaleStoreName: e.target.value }) + setSaleStoreName(saleStoreNameRef.current.value) }} />
@@ -210,11 +251,11 @@ export default function StuffSearchCondition() {
{ - setAddress(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schAddress: e.target.value }) + setAddress(addressRef.current.value) }} />
@@ -226,11 +267,11 @@ export default function StuffSearchCondition() {
{ - setobjectName(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schObjectName: e.target.value }) + setobjectName(objectNameRef.current.value) }} />
@@ -240,11 +281,11 @@ export default function StuffSearchCondition() {
{ - setDispCompanyName(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schDispCompanyName: e.target.value }) + setDispCompanyName(dispCompanyNameRef.current.value) }} />
@@ -293,10 +334,10 @@ export default function StuffSearchCondition() { { - setReceiveUser(e.target.value) - setStuffSearch({ ...stuffSearch, code: 'S', schReceiveUser: e.target.value }) + setReceiveUser(receiveUserRef.current.value) }} />
From 788c4b7eb553a244bbd2258f97bda1651316fa8d Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 11:29:18 +0900 Subject: [PATCH 015/139] chore: Delete unused files --- src/locales/client.js | 18 --------- src/locales/ja.js | 90 ------------------------------------------ src/locales/ko.js | 91 ------------------------------------------- src/locales/server.js | 14 ------- 4 files changed, 213 deletions(-) delete mode 100644 src/locales/client.js delete mode 100644 src/locales/ja.js delete mode 100644 src/locales/ko.js delete mode 100644 src/locales/server.js diff --git a/src/locales/client.js b/src/locales/client.js deleted file mode 100644 index c4679862..00000000 --- a/src/locales/client.js +++ /dev/null @@ -1,18 +0,0 @@ -'use client' - -import { createI18nClient } from 'next-international/client' - -export const { useI18n, useScopedI18n, I18nProviderClient, useChangeLocale, defineLocale, useCurrentLocale } = createI18nClient( - { - ko: () => import('./ko'), - ja: () => import('./ja'), - }, - { - // Uncomment to set base path - // basePath: '/base', - // Uncomment to use custom segment name - // segmentName: 'locale', - // Uncomment to set fallback locale - // fallbackLocale: en, - }, -) diff --git a/src/locales/ja.js b/src/locales/ja.js deleted file mode 100644 index 5ae1b171..00000000 --- a/src/locales/ja.js +++ /dev/null @@ -1,90 +0,0 @@ -console.log('Loaded JA') - -export default { - hello: 'こんにちは', - welcome: 'こんにちは {name}!', - locale: '現在のロケールは {locale} です。', - common: { - require: '필수', - }, - site: { - name: 'Q.CAST III', - sub_name: '태양광 발전 시스템 도면관리 사이트', - }, - login: { - login: 'Login', - init_password: { - btn: '비밀번호 초기화', - title: '비밀번호 초기화', - sub_title: '비밀번호를 초기화할 아이디와 이메일 주소를 입력해 주세요.', - }, - }, - join: { - title: 'Q.CAST3 로그인ID 발행 신청', - sub1: { - title: '판매대리점 정보', - comment: '※ 등록되는 리셀러의 회사 이름을 입력하십시오. (2차점은 「○○판매주식회사(2차점:××설비주식회사)」로 기입해 주세요.)', - storeQcastNm: '판매대리점명', - storeQcastNm_placeholder: '株式会社エネルギア・ソリューション・アンド・サービス(2次店:山口住機販売有限会社)', - storeQcastNmKana: '판매대리점명 후리가나', - storeQcastNmKana_placeholder: 'カブシキガイシャエネルギア・ソリューション・アン', - postCd: '우편번호', - postCd_placeholder: '숫자 7자리', - addr: '주소', - addr_placeholder: '전각50자이내', - telNo: '전화번호', - telNo_placeholder: '00-0000-0000', - fax: 'FAX 번호', - fax_placeholder: '00-0000-0000', - }, - sub2: { - title: '담당자 정보', - userNm: '담당자명', - userNmKana: '담당자명 후리가나', - userId: '신청 ID', - email: '이메일 주소', - telNo: '전화번호', - telNo_placeholder: '00-0000-0000', - fax: 'FAX 번호', - fax_placeholder: '00-0000-0000', - category: '부서명', - }, - sub3: { - title: '견적서 제출용 회사정보', - qtCompNm: '회사명', - qtPostCd: '우편번호', - qtPostCd_placeholder: '숫자 7자리', - qtAddr: '주소', - qtAddr_placeholder: '전각50자이내', - qtEmail: '이메일 주소', - qtTelNo: '전화번호', - qtTelNo_placeholder: '00-0000-0000', - qtFax: 'FAX 번호', - qtFax_placeholder: '00-0000-0000', - }, - btn: { - approval_request: 'ID 승인요청', - }, - complete: { - title: 'Q.CAST3 로그인ID 발행신청 완료', - contents: '※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.', - email_comment: '담당자 이메일 주소', - email: 'test@naver.com', - }, - }, - stuff: { - gridHeader: { - lastEditDatetime: '갱신일시', - objectNo: '물건번호', - planTotCnt: '플랜 수', - objectName: '물건명', - saleStoreId: '대리점ID', - saleStoreName: '대리점명', - address: '물건주소', - dispCompanyName: '견적처', - receiveUser: '담당자', - specDate: '사양확인', - createDatetime: '등록일', - }, - }, -} diff --git a/src/locales/ko.js b/src/locales/ko.js deleted file mode 100644 index c01b913c..00000000 --- a/src/locales/ko.js +++ /dev/null @@ -1,91 +0,0 @@ -console.log('Loaded KO') - -export default { - hello: '안녕', - welcome: '안녕 {name}!', - locale: '현재 로케일은 {locale}입니다.', - common: { - require: '필수', - }, - site: { - name: 'Q.CAST III', - sub_name: '태양광 발전 시스템 도면관리 사이트', - }, - login: { - login: '로그인', - init_password: { - btn: '비밀번호 초기화', - title: '비밀번호 초기화', - sub_title: '비밀번호를 초기화할 아이디와 이메일 주소를 입력해 주세요.', - complete_message: '비밀번호가 초기화 되었습니다. 초기화된 비밀번호는 아이디와 같습니다.', - }, - }, - join: { - title: 'Q.CAST3 로그인ID 발행 신청', - sub1: { - title: '판매대리점 정보', - comment: '※ 등록되는 리셀러의 회사 이름을 입력하십시오. (2차점은 「○○판매주식회사(2차점:××설비주식회사)」로 기입해 주세요.)', - storeQcastNm: '판매대리점명', - storeQcastNm_placeholder: '주식회사 에너지 기어 솔루션 앤 서비스 (2차점: 야마구치 주기 판매 유한회사)', - storeQcastNmKana: '판매대리점명 후리가나', - storeQcastNmKana_placeholder: '주식회사 에너지 기어 솔루션', - postCd: '우편번호', - postCd_placeholder: '숫자 7자리', - addr: '주소', - addr_placeholder: '전각50자이내', - telNo: '전화번호', - telNo_placeholder: '00-0000-0000', - fax: 'FAX 번호', - fax_placeholder: '00-0000-0000', - }, - sub2: { - title: '담당자 정보', - userNm: '담당자명', - userNmKana: '담당자명 후리가나', - userId: '신청 ID', - email: '이메일 주소', - telNo: '전화번호', - telNo_placeholder: '00-0000-0000', - fax: 'FAX 번호', - fax_placeholder: '00-0000-0000', - category: '부서명', - }, - sub3: { - title: '견적서 제출용 회사정보', - qtCompNm: '회사명', - qtPostCd: '우편번호', - qtPostCd_placeholder: '숫자 7자리', - qtAddr: '주소', - qtAddr_placeholder: '전각50자이내', - qtEmail: '이메일 주소', - qtTelNo: '전화번호', - qtTelNo_placeholder: '00-0000-0000', - qtFax: 'FAX 번호', - qtFax_placeholder: '00-0000-0000', - }, - btn: { - approval_request: 'ID 승인요청', - }, - complete: { - title: 'Q.CAST3 로그인ID 발행신청 완료', - contents: '※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.', - email_comment: '담당자 이메일 주소', - email: 'test@naver.com', - }, - }, - stuff: { - gridHeader: { - lastEditDatetime: '갱신일시', - objectNo: '물건번호', - planTotCnt: '플랜 수', - objectName: '물건명', - saleStoreId: '대리점ID', - saleStoreName: '대리점명', - address: '물건주소', - dispCompanyName: '견적처', - receiveUser: '담당자', - specDate: '사양확인', - createDatetime: '등록일', - }, - }, -} diff --git a/src/locales/server.js b/src/locales/server.js deleted file mode 100644 index 7bfe43f0..00000000 --- a/src/locales/server.js +++ /dev/null @@ -1,14 +0,0 @@ -import { createI18nServer } from 'next-international/server' - -export const { getI18n, getScopedI18n, getCurrentLocale, getStaticParams } = createI18nServer( - { - ko: () => import('./ko'), - ja: () => import('./ja'), - }, - { - // Uncomment to use custom segment name - // segmentName: 'locale', - // Uncomment to set fallback locale - // fallbackLocale: en, - }, -) From 49218ddc6109164c1d9a556f523d9075d19a8642 Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Mon, 21 Oct 2024 13:10:13 +0900 Subject: [PATCH 016/139] =?UTF-8?q?=EC=9E=90=EB=8F=99=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=20=ED=8E=98=EC=9D=B4=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/AutoLogin.jsx | 21 +++++++++++++++++++++ src/components/auth/Login.jsx | 8 +++++--- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 4 files changed, 28 insertions(+), 3 deletions(-) create mode 100644 src/components/auth/AutoLogin.jsx diff --git a/src/components/auth/AutoLogin.jsx b/src/components/auth/AutoLogin.jsx new file mode 100644 index 00000000..0d539cbb --- /dev/null +++ b/src/components/auth/AutoLogin.jsx @@ -0,0 +1,21 @@ +'use client' + +import { useMessage } from '@/hooks/useMessage' + +export default function AutoLoginPage() { + const { getMessage } = useMessage() + + return ( +
+
+ {getMessage('site.name')} + {getMessage('site.sub_name')} +
+
+
+ {getMessage('login.auto.page.text')} +
+
+
+ ) +} diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 28416284..d75d9b6e 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -15,6 +15,8 @@ import Cookies from 'js-cookie' import { useSearchParams } from 'next/navigation' +import AutoLogin from './AutoLogin' + export default function Login() { // 자동 로그인 const initParams = useSearchParams() @@ -180,8 +182,7 @@ export default function Login() { react - - {passwordReset === 1 && ( + {!autoLoginParam && passwordReset === 1 && ( <>
@@ -266,7 +267,7 @@ export default function Login() {
)} - {passwordReset === 2 && ( + {!autoLoginParam && passwordReset === 2 && ( <>
@@ -328,6 +329,7 @@ export default function Login() {
)} + {autoLoginParam && }
COPYRIGHT©2024 Hanwha Japan All Rights Reserved.
diff --git a/src/locales/ja.json b/src/locales/ja.json index 0545be6e..3ccbdf40 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -385,6 +385,7 @@ "myinfo.message.save": "パスワードが変更されました。", "myinfo.message.password.error": "パスワードが間違っています。", "login": "ログイン", + "login.auto.page.text": "自動ログイン中です。", "login.id.save": "ID保存", "login.id.placeholder": "IDを入力してください。", "login.password.placeholder": "パスワードを入力してください。", diff --git a/src/locales/ko.json b/src/locales/ko.json index d02eed19..d87551a5 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -390,6 +390,7 @@ "myinfo.message.save": "비밀번호가 변경되었습니다.", "myinfo.message.password.error": "비밀번호가 틀렸습니다.", "login": "로그인", + "login.auto.page.text": "자동로그인 중 입니다.", "login.id.save": "ID Save", "login.id.placeholder": "아이디를 입력해주세요.", "login.password.placeholder": "비밀번호를 입력해주세요.", From 93ee8c14d9cfd45bc8acbab328b6b68e220b7cd2 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 14:13:43 +0900 Subject: [PATCH 017/139] =?UTF-8?q?=EA=B8=80=EA=BC=B4=20=EB=B0=8F=20?= =?UTF-8?q?=EB=8F=84=EB=A9=B4=20=ED=81=AC=EA=B8=B0=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/static/images/common/select_del.svg | 4 + .../common/color-picker/ColorPickerModal.jsx | 5 +- src/components/common/font/FontSetting.jsx | 89 ++++++++-- .../common/popupManager/PopupManager.jsx | 3 +- .../floor-plan/modal/setting01/GridOption.jsx | 16 +- .../modal/setting01/SecondOption.jsx | 30 +++- .../modal/setting01/SettingModal01.jsx | 4 +- .../dimensionLine/DimensionLineSetting.jsx | 152 ++++++++++++++++-- src/locales/ja.json | 4 + src/locales/ko.json | 4 + 10 files changed, 265 insertions(+), 46 deletions(-) create mode 100644 public/static/images/common/select_del.svg diff --git a/public/static/images/common/select_del.svg b/public/static/images/common/select_del.svg new file mode 100644 index 00000000..2376f16b --- /dev/null +++ b/public/static/images/common/select_del.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/common/color-picker/ColorPickerModal.jsx b/src/components/common/color-picker/ColorPickerModal.jsx index 3e4997b6..fe16896f 100644 --- a/src/components/common/color-picker/ColorPickerModal.jsx +++ b/src/components/common/color-picker/ColorPickerModal.jsx @@ -10,13 +10,14 @@ export default function ColorPickerModal(props) { const [originColor, setOriginColor] = useState(color) const { closePopup } = usePopup() + console.log(props) useEffect(() => { setOriginColor(color) }, [isShow]) - + return ( -
+

{getMessage('modal.color.picker.title')}

見る
- Aaあぁアァ + + Aaあぁアァ +
ントです。プリンタと画面 でも同じフォントを使用します.
- +
diff --git a/src/components/common/popupManager/PopupManager.jsx b/src/components/common/popupManager/PopupManager.jsx index cc6ce224..aa4b6cae 100644 --- a/src/components/common/popupManager/PopupManager.jsx +++ b/src/components/common/popupManager/PopupManager.jsx @@ -1,8 +1,9 @@ 'use client' import { useRecoilState } from 'recoil' import { popupState } from '@/store/popupAtom' +import { Fragment } from 'react' export default function PopupManager() { const [popup, setPopup] = useRecoilState(popupState) - return <>{popup.children?.map((child) => child.component)} + return popup.children?.map((child) => {child.component}) } diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index 9b5e131e..ca8e4f92 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -11,7 +11,7 @@ import { usePopup } from '@/hooks/usePopup' import { v4 as uuidv4 } from 'uuid' import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid' -export default function GridOption(props) { +export default function GridOption() { const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState) const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState) const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) @@ -21,7 +21,8 @@ export default function GridOption(props) { const [color, setColor] = useColor(gridColor) const [showColorPickerModal, setShowColorPickerModal] = useState(false) const [showDotLineGridModal, setShowDotLineGridModal] = useState(false) - const { addPopup } = usePopup() + const { addPopup, closePopup } = usePopup() + let [colorId, dotLineId] = '' useEffect(() => { console.log('GridOption useEffect 실행') @@ -36,6 +37,8 @@ export default function GridOption(props) { }, [showColorPickerModal]) useEffect(() => { + colorId = uuidv4() + dotLineId = uuidv4() return () => { setSettingModalGridOptions((prev) => { const newSettingOptions = [...prev] @@ -47,7 +50,7 @@ export default function GridOption(props) { const onClickOption = (option) => { const newGridOptions = [...gridOptions] - const id = uuidv4() + newGridOptions.map((item) => { if (item.id === option.id) { item.selected = !item.selected @@ -65,9 +68,10 @@ export default function GridOption(props) { // 점.선 그리드 if (option.selected) { setShowDotLineGridModal(true) - addPopup(id, 2, ) + addPopup(dotLineId, 2, ) } else { setShowDotLineGridModal(false) + closePopup(dotLineId) } } @@ -79,12 +83,12 @@ export default function GridOption(props) { if (option.id === 4) { // 그리드 색 설정 - console.log(option) if (option.selected) { setShowColorPickerModal(true) - addPopup(id, 2, ) + addPopup(colorId, 2, ) } else { setShowColorPickerModal(false) + closePopup(colorId) } } diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index a4123fe3..0efb2aab 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -134,19 +134,43 @@ export default function SecondOption() { } setAdsorptionRange(option.range) } + const dimensionId = uuidv4() + const fontId = uuidv4() + const [pixel, setPixel] = useState(1) + const [color, setColor] = useState('#FF0000') + const [font, setFont] = useState(null) + const [fontSize, setFontSize] = useState('#FF0000') + const [fontColor, setFontColor] = useState('#FF0000') + + const dimensionProps = { + color, + setColor, + pixel, + setPixel, + font, + setFont, + fontSize, + setFontSize, + fontColor, + setFontColor, + id: dimensionId, + isShow: showDimensionLineSettingModal, + setIsShow: setShowDimensionLineSettingModal, + } const handlePopup = (type) => { const id = uuidv4() switch (type) { case 'dimensionLine': - addPopup(id, 2, ) + setShowDimensionLineSettingModal(true) + addPopup(dimensionId, 2, ) break case 'font1': //문자 글꼴변경 case 'font2': //흐름 방향 글꼴 변경 case 'font3': //치수 글꼴변경 case 'font4': //회로번호 글꼴변경 - addPopup(id, 2, ) + addPopup(fontId, 2, ) } } @@ -176,7 +200,7 @@ export default function SecondOption() {
{/*
diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index 667e90c8..0f532ae9 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -1,51 +1,171 @@ import WithDraggable from '@/components/common/draggable/withDraggable' import { usePopup } from '@/hooks/usePopup' - +import { v4 as uuidv4 } from 'uuid' +import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' +import { useEffect, useState } from 'react' +import FontSetting from '@/components/common/font/FontSetting' +import QSelectBox from '@/components/common/select/QSelectBox' +import { useMessage } from '@/hooks/useMessage' +/* + color: 치수선 색 + fontColor: 글꼴 색 + fontSize: 치수선 치수 색 + pixel: 치수선 두깨 +*/ export default function DimensionLineSetting(props) { - const { id, pos = { x: 970, y: -815 }, setShowColorPickerModal } = props - console.log(props) - const { closePopup } = usePopup() + const { + color, + setColor, + font, + setFont, + fontColor, + setFontColor, + fontSize, + setFontSize, + pixel, + setPixel, + setIsShow, + id, + pos = { x: 985, y: 180 }, + } = props + const { addPopup, closePopup } = usePopup() + const pixels = Array.from({ length: 5 }).map((_, index) => { + return { name: index + 1, value: index + 1 } + }) + const [originColor, setOriginColor] = useState(color) + const [originFont, setOriginFont] = useState(font) + const [originFontColor, setOriginFontColor] = useState(fontColor) + const [originFontSize, setOriginFontSize] = useState(fontSize) + const [originPixel, setOriginPixel] = useState(pixel) + const fontModalId = uuidv4() + const colorModalId = uuidv4() + const [showColorPickerModal, setShowColorPickerModal] = useState(false) + const [showFontModal, setShowFontModal] = useState(false) + const { getMessage } = useMessage() + const colorPickerProps = { + isShow: showColorPickerModal, + setIsShow: setShowColorPickerModal, + color: originColor, + setColor: setOriginColor, + id: colorModalId, + pos: { + x: 480, + y: -815, + }, + } + + const fontProps = { + isShow: showFontModal, + setIsShow: setShowFontModal, + color: originColor, + setColor: setOriginColor, + font: originFont, + setFont: setOriginFont, + fontColor: 'black', + setFontColor: setOriginFontColor, + fontSize: originFontSize, + setFontSize: setOriginFontSize, + id: fontModalId, + pos: { + x: 480, + y: -815, + }, + } + const popupHandle = (type) => { + switch (type) { + case 'color': + closePopup(fontModalId) + addPopup(colorModalId, 3, ) + break + case 'font': + closePopup(colorModalId) + addPopup(fontModalId, 3, ) + break + } + } + + useEffect(() => { + console.log(pixel) + if (pixel) { + setOriginPixel(pixels?.filter((data) => data.value === pixel)[0]) + } + }, []) + return (
-

寸法線 設定

-
- +
- 寸法線の線太さ -
- + {getMessage('modal.canvas.setting.font.plan.absorption.dimension.line.font.size')} +
+ setOriginPixel(e)} />
pixel
- 寸法線の線の色 - + {getMessage('modal.canvas.setting.font.plan.absorption.dimension.line.color')} +
-
見る
+
{getMessage('modal.canvas.setting.font.plan.absorption.dimension.display')}
- + 9,999 - +
- +
diff --git a/src/locales/ja.json b/src/locales/ja.json index 23e3b45c..92c592c8 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -156,6 +156,7 @@ "plan.menu.simulation.pdf": "PDF", "plan.mode.vertical.horizontal": "垂直水平モード", "plan.mode.free": "프리 모드(JA)", + "modal.font.setting": "フォント設定", "modal.canvas.setting": "Canvas設定", "modal.canvas.setting.display": "ディスプレイ設定", "modal.canvas.setting.font.plan": " フォントと図面サイズの設定", @@ -198,6 +199,9 @@ "modal.canvas.setting.font.plan.absorption.medium": "中", "modal.canvas.setting.font.plan.absorption.large": "ティーン", "modal.canvas.setting.font.plan.absorption.dimension.line": "寸法線の設定", + "modal.canvas.setting.font.plan.absorption.dimension.line.font.size": "寸法線の線太さ", + "modal.canvas.setting.font.plan.absorption.dimension.line.color": "寸法線の線の色", + "modal.canvas.setting.font.plan.absorption.dimension.display": "見る", "modal.canvas.setting.font.plan.absorption.plan.size.setting": "図面サイズの設定", "modal.canvas.setting.first.option.info": "※図面に表示する項目をクリックすると適用されます。", "modal.canvas.setting.first.option.alloc": "할당표시", diff --git a/src/locales/ko.json b/src/locales/ko.json index 1ef504b2..bcc618fb 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -160,6 +160,7 @@ "plan.menu.simulation.pdf": "PDF", "plan.mode.vertical.horizontal": "수직 수평 모드", "plan.mode.free": "프리 모드", + "modal.font.setting": "글꼴 설정", "modal.canvas.setting": "Canvas 설정", "modal.canvas.setting.display": "디스플레이 설정", "modal.canvas.setting.font.plan": "글꼴 및 도면 크기 설정", @@ -203,6 +204,9 @@ "modal.canvas.setting.font.plan.absorption.medium": "중", "modal.canvas.setting.font.plan.absorption.large": "대", "modal.canvas.setting.font.plan.absorption.dimension.line": "치수선 설정", + "modal.canvas.setting.font.plan.absorption.dimension.line.font.size": "치수선의 굵기", + "modal.canvas.setting.font.plan.absorption.dimension.line.color": "치수선의 색", + "modal.canvas.setting.font.plan.absorption.dimension.display": "보기", "modal.canvas.setting.font.plan.absorption.plan.size.setting": "도면크기 설정", "modal.canvas.setting.first.option.info": "※도면에 표시하는 항목을 클릭하면 적용됩니다.", "modal.canvas.setting.first.option.alloc": "할당표시", From 676a0bdc91640c7544ccfd24ed3ce53ef4c9998c Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 14:13:54 +0900 Subject: [PATCH 018/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 96 ++++++++++++++++++++++++++++++--------- src/styles/_main.scss | 26 +++++------ src/styles/_modal.scss | 6 ++- src/styles/_reset.scss | 84 ++++++++++++++++++++++++++++++++++ 4 files changed, 175 insertions(+), 37 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 37233d13..ee823bab 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -1,29 +1,32 @@ // CanvasPage -.canvas-wrap{ - height: calc(100vh - 47px); - display: flex; - flex-direction: column; - .canvas-content{ - flex: 1 1 auto; - .canvas-layout{ - height: 100%; - } - } - &.sub-wrap{ - overflow: hidden; - .canvas-content{ - height: calc(100% - 47px); - } - } -} +// .canvas-wrap{ +// height: calc(100vh - 47px); +// display: flex; +// flex-direction: column; +// .canvas-content{ +// flex: 1 1 auto; +// .canvas-layout{ +// height: 100%; +// } +// } +// &.sub-wrap{ +// overflow: hidden; +// .canvas-content{ +// height: calc(100% - 47px); +// } +// } +// } // CanvasMenu .canvas-menu-wrap{ - position: relative; + position: fixed; + top: 46px; + left: 0; display: block; width: 100%; padding-bottom: 0; background-color: #383838; transition: padding .17s ease-in-out; + z-index: 999; .canvas-menu-inner{ position: relative; display: flex; @@ -302,12 +305,34 @@ } // canvas-layout +.canvas-content{ + padding-top: 46.8px; + transition: all .17s ease-in-out; + .canvas-frame{ + height: 86.3vh; + } + &.active{ + padding-top: calc(46.8px + 50px); + .canvas-frame{ + height: 81vh; + } + } +} .canvas-layout{ + padding-top: 37px; .canvas-page-list{ + position: fixed; + top: 92.8px; + left: 0; display: flex; background-color: #1C1C1C; border-top: 1px solid #000; width: 100%; + transition: all .17s ease-in-out; + z-index: 999; + &.active{ + top: calc(92.8px + 50px); + } .canvas-plane-wrap{ display: flex; align-items: center; @@ -383,9 +408,24 @@ .canvas-frame{ position: relative; - height: calc(100% - 36.5px); - background-color: #fff; + // height: calc(100% - 36.5px); + background-color: #F4F4F7; + overflow: auto; + transition: all .17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } canvas{ + background-color: #fff; position: absolute; top: 0; left: 0; @@ -514,8 +554,6 @@ &.estimate{ display: flex; flex-direction: column; - height: calc(100% - 36.5px); - overflow-y: auto; padding-top: 0; .sub-content-inner{ flex: 1; @@ -1200,4 +1238,18 @@ background-color: #F4F4F7; } } +} + +.file-down-nodata{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + font-size: 16px; + font-weight: 500; + color: #344356; } \ No newline at end of file diff --git a/src/styles/_main.scss b/src/styles/_main.scss index 37170a8b..ea9b8833 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -112,8 +112,8 @@ border-radius: 6px; background: #FFF; box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - &.item01{flex: 1; max-height: 400px;} - &.item02{flex: none; width: 451px; max-height: 400px;} + &.item01{flex: 1; height: 400px;} + &.item02{flex: none; width: 451px; height: 400px;} &.item03{flex: 1;} &.item04{flex: none; width: 351px;} &.item05{flex: none; width: 451px;} @@ -566,17 +566,17 @@ transition: background .05s ease-in-out; } } - } - input[type=checkbox]:checked + label::before{ - border-color: #A8B6C7; - background-color: #A8B6C7; - } - input[type=checkbox]:checked + label::after{ - border-color: #fff; - width: 7px; - height: 11px; - top: -2px; - left: 1px; + input[type=checkbox]:checked + label::before{ + border-color: #A8B6C7; + background-color: #A8B6C7; + } + input[type=checkbox]:checked + label::after{ + border-color: #fff; + width: 7px; + height: 11px; + top: -2px; + left: 1px; + } } } diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index f0966b04..3901ba0f 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -26,6 +26,8 @@ $alert-color: #101010; .modal-pop-wrap{ position: fixed; + top: 0; + left: 0; width: 100%; height: -webkit-fit-content; height: -moz-fit-content; @@ -453,7 +455,7 @@ $alert-color: #101010; gap: 20px; } .select-wrap{ - div{ + .sort-select{ width: 100%; } } @@ -1624,7 +1626,7 @@ $alert-color: #101010; align-items: center; justify-content: center; width: 100%; - height: 80px; + min-height: 80px; background-color: #fff; } diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index d345f643..d483c7b7 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -804,4 +804,88 @@ input[type=text]{ background-size: 14px 15px; cursor: pointer; } +} + +// react select +.react-select-custom{ + width: 100%; + .custom__control{ + height: 30px; + min-height: unset; + border-radius: 2px; + border-color: #EEE; + background-color: #fff; + &:hover{ + border-color: #EEE; + } + } + .custom__control--is-focused{ + border-color: #EEE; + box-shadow: unset; + &:hover{ + border-color: #EEE; + + } + } + .custom__value-container { + height: 100%; + padding: 0 10px; + } + .custom__placeholder, + .custom__single-value{ + margin: 0; + } + .custom__single-value{ + font-size: 13px; + color: #45576F; + font-weight: 400; + } + .custom__placeholder{ + font-size: 13px; + color: #bbbbbb; + font-weight: 400; + } + .custom__indicator{ + padding: 0; + svg{ + display: none; + } + } + .custom__clear-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_del.svg) no-repeat center; + background-size: 8px 8px; + } + .custom__dropdown-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_light_arr.svg) no-repeat center; + } + + .custom__menu { + margin: 1px 0; + border-radius: 2px; + overflow: hidden; + } + .custom__menu-list { + padding: 0; + } + .custom__option{ + font-size: 13px; + padding: 7px 10px; + color: #45576F; + } + .custom__option--is-selected{ + color: #fff; + } + // disable + &.custom--is-disabled{ + .custom__control{ + background-color: #FAFAFA ; + } + .custom__single-value{ + color: #999999; + } + } } \ No newline at end of file From d864ccb792cde9cf80684deeb0c44c31d175e34f Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 14:15:41 +0900 Subject: [PATCH 019/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/static/images/common/select_del.svg | 4 + src/styles/_contents.scss | 96 ++++++-- src/styles/_main.scss | 26 +- src/styles/_modal.scss | 269 ++++++++++++++++++++- src/styles/_reset.scss | 84 +++++++ 5 files changed, 442 insertions(+), 37 deletions(-) create mode 100644 public/static/images/common/select_del.svg diff --git a/public/static/images/common/select_del.svg b/public/static/images/common/select_del.svg new file mode 100644 index 00000000..2376f16b --- /dev/null +++ b/public/static/images/common/select_del.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 37233d13..ee823bab 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -1,29 +1,32 @@ // CanvasPage -.canvas-wrap{ - height: calc(100vh - 47px); - display: flex; - flex-direction: column; - .canvas-content{ - flex: 1 1 auto; - .canvas-layout{ - height: 100%; - } - } - &.sub-wrap{ - overflow: hidden; - .canvas-content{ - height: calc(100% - 47px); - } - } -} +// .canvas-wrap{ +// height: calc(100vh - 47px); +// display: flex; +// flex-direction: column; +// .canvas-content{ +// flex: 1 1 auto; +// .canvas-layout{ +// height: 100%; +// } +// } +// &.sub-wrap{ +// overflow: hidden; +// .canvas-content{ +// height: calc(100% - 47px); +// } +// } +// } // CanvasMenu .canvas-menu-wrap{ - position: relative; + position: fixed; + top: 46px; + left: 0; display: block; width: 100%; padding-bottom: 0; background-color: #383838; transition: padding .17s ease-in-out; + z-index: 999; .canvas-menu-inner{ position: relative; display: flex; @@ -302,12 +305,34 @@ } // canvas-layout +.canvas-content{ + padding-top: 46.8px; + transition: all .17s ease-in-out; + .canvas-frame{ + height: 86.3vh; + } + &.active{ + padding-top: calc(46.8px + 50px); + .canvas-frame{ + height: 81vh; + } + } +} .canvas-layout{ + padding-top: 37px; .canvas-page-list{ + position: fixed; + top: 92.8px; + left: 0; display: flex; background-color: #1C1C1C; border-top: 1px solid #000; width: 100%; + transition: all .17s ease-in-out; + z-index: 999; + &.active{ + top: calc(92.8px + 50px); + } .canvas-plane-wrap{ display: flex; align-items: center; @@ -383,9 +408,24 @@ .canvas-frame{ position: relative; - height: calc(100% - 36.5px); - background-color: #fff; + // height: calc(100% - 36.5px); + background-color: #F4F4F7; + overflow: auto; + transition: all .17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } canvas{ + background-color: #fff; position: absolute; top: 0; left: 0; @@ -514,8 +554,6 @@ &.estimate{ display: flex; flex-direction: column; - height: calc(100% - 36.5px); - overflow-y: auto; padding-top: 0; .sub-content-inner{ flex: 1; @@ -1200,4 +1238,18 @@ background-color: #F4F4F7; } } +} + +.file-down-nodata{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + font-size: 16px; + font-weight: 500; + color: #344356; } \ No newline at end of file diff --git a/src/styles/_main.scss b/src/styles/_main.scss index 37170a8b..ea9b8833 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -112,8 +112,8 @@ border-radius: 6px; background: #FFF; box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - &.item01{flex: 1; max-height: 400px;} - &.item02{flex: none; width: 451px; max-height: 400px;} + &.item01{flex: 1; height: 400px;} + &.item02{flex: none; width: 451px; height: 400px;} &.item03{flex: 1;} &.item04{flex: none; width: 351px;} &.item05{flex: none; width: 451px;} @@ -566,17 +566,17 @@ transition: background .05s ease-in-out; } } - } - input[type=checkbox]:checked + label::before{ - border-color: #A8B6C7; - background-color: #A8B6C7; - } - input[type=checkbox]:checked + label::after{ - border-color: #fff; - width: 7px; - height: 11px; - top: -2px; - left: 1px; + input[type=checkbox]:checked + label::before{ + border-color: #A8B6C7; + background-color: #A8B6C7; + } + input[type=checkbox]:checked + label::after{ + border-color: #fff; + width: 7px; + height: 11px; + top: -2px; + left: 1px; + } } } diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 9bd59e3d..3901ba0f 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -26,6 +26,8 @@ $alert-color: #101010; .modal-pop-wrap{ position: fixed; + top: 0; + left: 0; width: 100%; height: -webkit-fit-content; height: -moz-fit-content; @@ -34,6 +36,9 @@ $alert-color: #101010; border-radius: 4px; background-color: #272727; z-index: 9999999; + &.xsm{ + width: 200px; + } &.xxxm{ width: 240px; } @@ -450,7 +455,7 @@ $alert-color: #101010; gap: 20px; } .select-wrap{ - div{ + .sort-select{ width: 100%; } } @@ -1505,7 +1510,7 @@ $alert-color: #101010; width: 16px; height: 16px; &.pink{ - border: 2px solid #EA10AC; + border: 2px solid #ce1c9c; background-color: #16417D; } &.white{ @@ -1514,4 +1519,264 @@ $alert-color: #101010; } } } +} + +// color setting +.color-setting-wrap{ + padding-bottom: 15px; + border-bottom: 1px solid #424242; + .color-tit{ + font-size: 13px; + font-weight: 500; + color: #ffffff; + margin-bottom: 10px; + } + .color-picker{ + .react-colorful{ + width: 100%; + height: auto; + gap: 20px; + .react-colorful__pointer{ + width: 15px; + height: 15px; + border: 4px solid #Fff; + } + .react-colorful__saturation{ + border-radius: 2px; + height: 200px; + border-bottom: 5px solid #000; + } + .react-colorful__last-control{ + border-radius: 2px; + height: 10px; + } + } + .hex-color-box{ + display: flex; + align-items: center; + margin-top: 15px; + .color-box-tit{ + font-size: 12px; + color: #fff; + font-weight: 500; + margin-right: 10px; + } + .color-hex-input{ + width: 150px; + margin-right: 5px; + input{ + width: 100%; + } + } + .color-box{ + display: block; + width: 30px; + height: 30px; + border-radius: 4px; + } + } + .default-color-wrap{ + margin-top: 25px; + .default-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .color-button-wrap{ + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 21px; + .default-color{ + display: block; + width: 100%; + height: 30px; + border-radius: 4px; + } + } + } + } +} + +// 글꼴 설정 팝업 +.font-option-warp{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 5px; + margin-bottom: 15px; + .font-option-item{ + .option-item-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + } +} +.font-ex-wrap{ + margin-bottom: 15px; + .font-ex-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .font-ex-box{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 80px; + background-color: #fff; + } + +} + +// 치수선 설정 +.font-btn-wrap{ + margin-bottom: 15px; + button{ + width: 100%; + height: 30px; + line-height: 28px; + } +} + +.line-color-wrap{ + margin-bottom: 15px; + .color-btn{ + display: block; + width: 100%; + height: 30px; + border-radius: 2px; + } +} + +.form-box{ + width: 100%; + background-color: #fff; + padding: 10px 0 20px; + .line-form{ + position: relative; + width: 102px; + height: 40px; + margin: 0 auto; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + .line-font-box{ + position: absolute; + bottom: -3px; + left: 0; + width: 100%; + text-align: center; + .font{ + display: block; + padding-bottom: 6px; + color: #101010; + } + .line{ + position: relative; + display: block; + width: 100%; + height: 1px; + border-radius: 30px; + &::before{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + left: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-top: none; + border-right: none; + } + &::after{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + right: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-bottom: none; + border-left: none; + } + } + } + } +} + +// 사이즈 변경 +.size-inner-warp{ + position: relative; +} +.size-check-wrap{ + position: relative; + display: block; + width: 132px; + height: 132px; + margin: 0 auto; + .size-btn{ + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background-color: #fff; + border-radius: 50%; + } + } + &:nth-child(1){ top: 0; left: 0; } + &:nth-child(2){ top: 0; right: 0; } + &:nth-child(3){ bottom: 0; left: 0; } + &:nth-child(4){ bottom: 0; right: 0; } + } + .size-box{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 100px; + height: 100px; + background-color: #fff; + } +} + +.size-option-top{ + margin-bottom: 15px; +} +.size-option-side{ + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); +} +.size-option-wrap{ + width: 88px; + margin: 0 auto; + .size-option{ + display: flex; + align-items: center; + input{ + width: 100%; + flex: 1; + } + span{ + flex: none; + } + } } \ No newline at end of file diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index d345f643..d483c7b7 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -804,4 +804,88 @@ input[type=text]{ background-size: 14px 15px; cursor: pointer; } +} + +// react select +.react-select-custom{ + width: 100%; + .custom__control{ + height: 30px; + min-height: unset; + border-radius: 2px; + border-color: #EEE; + background-color: #fff; + &:hover{ + border-color: #EEE; + } + } + .custom__control--is-focused{ + border-color: #EEE; + box-shadow: unset; + &:hover{ + border-color: #EEE; + + } + } + .custom__value-container { + height: 100%; + padding: 0 10px; + } + .custom__placeholder, + .custom__single-value{ + margin: 0; + } + .custom__single-value{ + font-size: 13px; + color: #45576F; + font-weight: 400; + } + .custom__placeholder{ + font-size: 13px; + color: #bbbbbb; + font-weight: 400; + } + .custom__indicator{ + padding: 0; + svg{ + display: none; + } + } + .custom__clear-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_del.svg) no-repeat center; + background-size: 8px 8px; + } + .custom__dropdown-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_light_arr.svg) no-repeat center; + } + + .custom__menu { + margin: 1px 0; + border-radius: 2px; + overflow: hidden; + } + .custom__menu-list { + padding: 0; + } + .custom__option{ + font-size: 13px; + padding: 7px 10px; + color: #45576F; + } + .custom__option--is-selected{ + color: #fff; + } + // disable + &.custom--is-disabled{ + .custom__control{ + background-color: #FAFAFA ; + } + .custom__single-value{ + color: #999999; + } + } } \ No newline at end of file From 2e7b1c941a7951a55e34cb05c3fa0dd2e217c5fe Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 14:21:47 +0900 Subject: [PATCH 020/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 2282 ++++++++++++------------- src/styles/_main.scss | 1273 +++++++------- src/styles/_modal.scss | 3353 +++++++++++++++++-------------------- src/styles/_reset.scss | 1688 +++++++++---------- src/styles/style.scss | 6 +- 5 files changed, 4092 insertions(+), 4510 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 9cd8bd32..ee823bab 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -17,1287 +17,1239 @@ // } // } // CanvasMenu -.canvas-menu-wrap { - position: fixed; - top: 46px; - left: 0; - display: block; - width: 100%; - padding-bottom: 0; - background-color: #383838; - transition: padding 0.17s ease-in-out; - z-index: 999; - .canvas-menu-inner { - position: relative; - display: flex; - align-items: center; - padding: 0 40px 0 20px; - background-color: #2c2c2c; - z-index: 999; - .canvas-menu-list { - display: flex; - align-items: center; - height: 100%; - .canvas-menu-item { - display: flex; - align-items: center; - height: 100%; - button { - display: flex; - align-items: center; - font-size: 12px; - height: 100%; - color: #fff; - font-weight: 600; - padding: 15px 20px; - opacity: 0.55; - transition: all 0.17s ease-in-out; - .menu-icon { - display: block; - width: 16px; - height: 16px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - margin-right: 10px; - &.con00 { - background-image: url(/static/images/canvas/menu_icon00.svg); - } - &.con01 { - background-image: url(/static/images/canvas/menu_icon01.svg); - } - &.con02 { - background-image: url(/static/images/canvas/menu_icon02.svg); - } - &.con03 { - background-image: url(/static/images/canvas/menu_icon03.svg); - } - &.con04 { - background-image: url(/static/images/canvas/menu_icon04.svg); - } - &.con05 { - background-image: url(/static/images/canvas/menu_icon05.svg); - } - &.con06 { - background-image: url(/static/images/canvas/menu_icon06.svg); - } - } - } - &.active { - background-color: #383838; - button { - opacity: 1; - } - } - } - } - .canvas-side-btn-wrap { - display: flex; - align-items: center; - margin-left: auto; - .select-box { - width: 124px; - margin-right: 5px; - > div { - width: 100%; - } - } - .btn-from { - display: flex; - align-items: center; - gap: 5px; - button { - display: block; - width: 30px; - height: 30px; - border-radius: 2px; - background-color: #3d3d3d; - background-position: center; - background-repeat: no-repeat; - background-size: 15px 15px; - transition: all 0.17s ease-in-out; - &.btn01 { - background-image: url(../../public/static/images/canvas/side_icon03.svg); - } - &.btn02 { - background-image: url(../../public/static/images/canvas/side_icon02.svg); - } - &.btn03 { - background-image: url(../../public/static/images/canvas/side_icon01.svg); - } - &.btn04 { - background-image: url(../../public/static/images/canvas/side_icon04.svg); - } - &.btn05 { - background-image: url(../../public/static/images/canvas/side_icon05.svg); - } - &.btn06 { - background-image: url(../../public/static/images/canvas/side_icon06.svg); - } - &.btn07 { - background-image: url(../../public/static/images/canvas/side_icon07.svg); - } - &.btn08 { - background-image: url(../../public/static/images/canvas/side_icon08.svg); - } - &.btn09 { - background-image: url(../../public/static/images/canvas/side_icon09.svg); - } - &:hover { - background-color: #1083e3; - } - &.active { - background-color: #1083e3; - } - } - } - .ico-btn-from { - display: flex; - align-items: center; - gap: 5px; - button { - .ico { - display: block; - width: 15px; - height: 15px; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - &.ico01 { - background-image: url(../../public/static/images/canvas/ico-flx01.svg); - } - &.ico02 { - background-image: url(../../public/static/images/canvas/ico-flx02.svg); - } - &.ico03 { - background-image: url(../../public/static/images/canvas/ico-flx03.svg); - } - &.ico04 { - background-image: url(../../public/static/images/canvas/ico-flx04.svg); - } - } - .name { - font-size: 12px; - color: #fff; - } - } - &.form06 { - .name { - font-size: 13px; - } - } - } - .vertical-horizontal { - display: flex; - min-width: 170px; - height: 28px; - margin: 0 5px; - border-radius: 2px; - background: #373737; - line-height: 28px; - overflow: hidden; - span { - padding: 0 10px; - font-size: 13px; - color: #fff; - } - button { - margin-left: auto; - height: 100%; - background-color: #4b4b4b; - font-size: 13px; - font-weight: 400; - color: #fff; - padding: 0 7.5px; - transition: all 0.17s ease-in-out; - } - &.on { - button { - background-color: #1083e3; - } - } - } - .size-control { - display: flex; - align-items: center; - justify-content: center; - gap: 10px; - background-color: #3d3d3d; - border-radius: 2px; - width: 100px; - height: 30px; - margin: 0 5px; - span { - font-size: 13px; - color: #fff; - } - .control-btn { - display: block; - width: 12px; - height: 12px; - background-repeat: no-repeat; - background-size: cover; - background-position: center; - &.minus { - background-image: url(../../public/static/images/canvas/minus.svg); - } - &.plus { - background-image: url(../../public/static/images/canvas/plus.svg); - } - } - } - } - } - .canvas-depth2-wrap { - position: absolute; - top: -100%; +.canvas-menu-wrap{ + position: fixed; + top: 46px; left: 0; - background-color: #383838; + display: block; width: 100%; - height: 50px; - transition: all 0.17s ease-in-out; - .canvas-depth2-inner { - display: flex; - align-items: center; - padding: 0 40px; - height: 100%; - .canvas-depth2-list { + padding-bottom: 0; + background-color: #383838; + transition: padding .17s ease-in-out; + z-index: 999; + .canvas-menu-inner{ + position: relative; display: flex; align-items: center; - height: 100%; - .canvas-depth2-item { - display: flex; - align-items: center; - margin-right: 26px; - height: 100%; - button { - position: relative; - opacity: 0.55; - color: #fff; - font-size: 12px; - font-weight: normal; + padding: 0 40px 0 20px; + background-color: #2C2C2C; + z-index: 999; + .canvas-menu-list{ + display: flex; + align-items: center; height: 100%; - padding-right: 12px; - } - &.active { - button { - opacity: 1; - font-weight: 600; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; - } + .canvas-menu-item{ + display: flex; + align-items: center; + height: 100%; + button{ + display: flex; + align-items: center; + font-size: 12px; + height: 100%; + color: #fff; + font-weight: 600; + padding: 15px 20px; + opacity: 0.55; + transition: all .17s ease-in-out; + .menu-icon{ + display: block; + width: 16px; + height: 16px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + margin-right: 10px; + &.con00{background-image: url(/static/images/canvas/menu_icon00.svg);} + &.con01{background-image: url(/static/images/canvas/menu_icon01.svg);} + &.con02{background-image: url(/static/images/canvas/menu_icon02.svg);} + &.con03{background-image: url(/static/images/canvas/menu_icon03.svg);} + &.con04{background-image: url(/static/images/canvas/menu_icon04.svg);} + &.con05{background-image: url(/static/images/canvas/menu_icon05.svg);} + &.con06{background-image: url(/static/images/canvas/menu_icon06.svg);} + } + } + &.active{ + background-color: #383838; + button{ + opacity: 1; + } + } } - } } - } - .canvas-depth2-btn-list { - display: flex; - align-items: center; - margin-left: auto; - height: 100%; - .depth2-btn-box { - display: flex; - align-items: center; - margin-right: 34px; - height: 100%; - transition: all 0.17s ease-in-out; - button { - position: relative; - font-size: 12px; - font-weight: 400; + .canvas-side-btn-wrap{ + display: flex; + align-items: center; + margin-left: auto; + .select-box{ + width: 124px; + margin-right: 5px; + > div{ + width: 100%; + } + } + .btn-from{ + display: flex; + align-items: center; + gap: 5px; + button{ + display: block; + width: 30px; + height: 30px; + border-radius: 2px; + background-color: #3D3D3D; + background-position: center; + background-repeat: no-repeat; + background-size: 15px 15px; + transition: all .17s ease-in-out; + &.btn01{background-image: url(../../public/static/images/canvas/side_icon03.svg);} + &.btn02{background-image: url(../../public/static/images/canvas/side_icon02.svg);} + &.btn03{background-image: url(../../public/static/images/canvas/side_icon01.svg);} + &.btn04{background-image: url(../../public/static/images/canvas/side_icon04.svg);} + &.btn05{background-image: url(../../public/static/images/canvas/side_icon05.svg);} + &.btn06{background-image: url(../../public/static/images/canvas/side_icon06.svg);} + &.btn07{background-image: url(../../public/static/images/canvas/side_icon07.svg);} + &.btn08{background-image: url(../../public/static/images/canvas/side_icon08.svg);} + &.btn09{background-image: url(../../public/static/images/canvas/side_icon09.svg);} + &:hover{ + background-color: #1083E3; + } + &.active{ + background-color: #1083E3; + } + } + } + .ico-btn-from{ + display: flex; + align-items: center; + gap: 5px; + button{ + .ico{ + display: block; + width: 15px; + height: 15px; + background-repeat: no-repeat; + background-position: center; + background-size: contain; + &.ico01{background-image: url(../../public/static/images/canvas/ico-flx01.svg);} + &.ico02{background-image: url(../../public/static/images/canvas/ico-flx02.svg);} + &.ico03{background-image: url(../../public/static/images/canvas/ico-flx03.svg);} + &.ico04{background-image: url(../../public/static/images/canvas/ico-flx04.svg);} + } + .name{ + font-size: 12px; + color: #fff; + } + } + &.form06{ + .name{ + font-size: 13px; + } + } + } + .vertical-horizontal{ + display: flex; + min-width: 170px; + height: 28px; + margin: 0 5px; + border-radius: 2px; + background: #373737; + line-height: 28px; + overflow: hidden; + span{ + padding: 0 10px; + font-size: 13px; + color: #fff; + } + button{ + margin-left: auto; + height: 100%; + background-color: #4B4B4B; + font-size: 13px; + font-weight: 400; + color: #fff; + padding: 0 7.5px; + transition: all .17s ease-in-out; + } + &.on{ + button{ + background-color: #1083E3; + } + } + } + .size-control{ + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + background-color: #3D3D3D; + border-radius: 2px; + width: 100px; + height: 30px; + margin: 0 5px; + span{ + font-size: 13px; + color: #fff; + } + .control-btn{ + display: block; + width: 12px; + height: 12px; + background-repeat: no-repeat; + background-size: cover; + background-position: center; + &.minus{ + background-image: url(../../public/static/images/canvas/minus.svg); + } + &.plus{ + background-image: url(../../public/static/images/canvas/plus.svg); + } + } + } + } + } + .canvas-depth2-wrap{ + position: absolute; + top: -100%; + left: 0; + background-color: #383838; + width: 100%; + height: 50px; + transition: all .17s ease-in-out; + .canvas-depth2-inner{ + display: flex; + align-items: center; + padding: 0 40px; height: 100%; - color: #fff; - padding-right: 12px; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + .canvas-depth2-list{ + display: flex; + align-items: center ; + height: 100%; + .canvas-depth2-item{ + display: flex; + align-items: center; + margin-right: 26px; + height: 100%; + button{ + position: relative; + opacity: 0.55; + color: #fff; + font-size: 12px; + font-weight: normal; + height: 100%; + padding-right: 12px; + } + &.active{ + button{ + opacity: 1; + font-weight: 600; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } + } + } + } + } + .canvas-depth2-btn-list{ + display: flex; + align-items: center; + margin-left: auto; + height: 100%; + .depth2-btn-box{ + display: flex; + align-items: center; + margin-right: 34px; + height: 100%; + transition: all .17s ease-in-out; + button{ + position: relative; + font-size: 12px; + font-weight: 400; + height: 100%; + color: #fff; + padding-right: 12px; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center; + } + } + &:last-child{ + margin-right: 0; + } + &.mouse{ + opacity: 0.55; + } + } } - } - &:last-child { - margin-right: 0; - } - &.mouse { - opacity: 0.55; - } } - } + &.active{ + top: 47px; + } } - &.active { - top: 47px; + &.active{ + padding-bottom: 50px; } - } - &.active { - padding-bottom: 50px; - } } // canvas-layout -.canvas-content { - padding-top: 46.8px; - transition: all 0.17s ease-in-out; - .canvas-frame { - height: 86.3vh; - } - &.active { - padding-top: calc(46.8px + 50px); - .canvas-frame { - height: 81vh; +.canvas-content{ + padding-top: 46.8px; + transition: all .17s ease-in-out; + .canvas-frame{ + height: 86.3vh; + } + &.active{ + padding-top: calc(46.8px + 50px); + .canvas-frame{ + height: 81vh; + } } - } } -.canvas-layout { - padding-top: 37px; - .canvas-page-list { - position: fixed; - top: 92.8px; - left: 0; - display: flex; - background-color: #1c1c1c; - border-top: 1px solid #000; - width: 100%; - transition: all 0.17s ease-in-out; - z-index: 999; - &.active { - top: calc(92.8px + 50px); - } - .canvas-plane-wrap { - display: flex; - align-items: center; - max-width: calc(100% - 45px); - .canvas-page-box { +.canvas-layout{ + padding-top: 37px; + .canvas-page-list{ + position: fixed; + top: 92.8px; + left: 0; display: flex; - align-items: center; - background-color: #1c1c1c; - padding: 9.6px 20px; - border-right: 1px solid #000; - min-width: 0; - transition: all 0.17s ease-in-out; - span { - display: flex; - align-items: center; - width: 100%; - font-size: 12px; - font-family: 'Pretendard', sans-serif; - color: #aaa; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; + background-color: #1C1C1C; + border-top: 1px solid #000; + width: 100%; + transition: all .17s ease-in-out; + z-index: 999; + &.active{ + top: calc(92.8px + 50px); } - .close { - flex: none; - display: block; - width: 7px; - height: 8px; - margin-left: 15px; - background: url(../../public/static/images/canvas/plan_close_gray.svg) no-repeat center; - background-size: cover; + .canvas-plane-wrap{ + display: flex; + align-items: center; + max-width: calc(100% - 45px); + .canvas-page-box{ + display: flex; + align-items: center; + background-color: #1c1c1c; + padding: 9.6px 20px; + border-right:1px solid #000; + min-width: 0; + transition: all .17s ease-in-out; + span{ + display: flex; + align-items: center; + width: 100%; + font-size: 12px; + font-family: 'Pretendard', sans-serif; + color: #AAA; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .close{ + flex: none; + display: block; + width: 7px; + height: 8px; + margin-left: 15px; + background: url(../../public/static/images/canvas/plan_close_gray.svg)no-repeat center; + background-size: cover; + } + &.on{ + background-color: #fff; + span{ + font-weight: 600; + color: #101010; + } + .close{ + background: url(../../public/static/images/canvas/plan_close_black.svg)no-repeat center; + } + &:hover{ + background-color: #fff; + } + } + &:hover{ + background-color: #000; + } + } } - &.on { - background-color: #fff; - span { - font-weight: 600; - color: #101010; - } - .close { - background: url(../../public/static/images/canvas/plan_close_black.svg) no-repeat center; - } - &:hover { - background-color: #fff; - } + .plane-add{ + display: flex; + align-items: center; + justify-content: center; + width: 45px; + padding: 13.5px 0; + background-color: #1C1C1C; + border-right: 1px solid #000; + transition: all .17s ease-in-out; + span{ + display: block; + width: 9px; + height: 9px; + background: url(../../public/static/images/canvas/plane_add.svg)no-repeat center; + background-size: cover; + } + &:hover{ + background-color: #000; + } } - &:hover { - background-color: #000; - } - } } - .plane-add { - display: flex; - align-items: center; - justify-content: center; - width: 45px; - padding: 13.5px 0; - background-color: #1c1c1c; - border-right: 1px solid #000; - transition: all 0.17s ease-in-out; - span { - display: block; - width: 9px; - height: 9px; - background: url(../../public/static/images/canvas/plane_add.svg) no-repeat center; - background-size: cover; - } - &:hover { - background-color: #000; - } - } - } } -.canvas-frame { - position: relative; - // height: calc(100% - 36.5px); - background-color: #f4f4f7; - overflow: auto; - transition: all 0.17s ease-in-out; - // &::-webkit-scrollbar { - // width: 10px; - // height: 10px; - // background-color: #fff; - // } - // &::-webkit-scrollbar-thumb { - // background-color: #C1CCD7; - // border-radius: 30px; - // } - // &::-webkit-scrollbar-track { - // background-color: #fff; - // } - canvas { - background-color: #fff; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - } +.canvas-frame{ + position: relative; + // height: calc(100% - 36.5px); + background-color: #F4F4F7; + overflow: auto; + transition: all .17s ease-in-out; + // &::-webkit-scrollbar { + // width: 10px; + // height: 10px; + // background-color: #fff; + // } + // &::-webkit-scrollbar-thumb { + // background-color: #C1CCD7; + // border-radius: 30px; + // } + // &::-webkit-scrollbar-track { + // background-color: #fff; + // } + canvas{ + background-color: #fff; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } } // sub-page -.sub-header { - position: fixed; - top: 46px; - left: 0; - width: 100%; - height: 46px; - border-bottom: 1px solid #000; - background: #2c2c2c; - z-index: 999; - .sub-header-inner { - display: flex; - align-items: center; - height: 100%; - padding: 0 100px; - .sub-header-title-wrap { - display: flex; - align-items: center; - .title-item { - position: relative; - padding: 0 24px; - a { - display: flex; - align-items: center; - .icon { - width: 22px; - height: 22px; - margin-right: 8px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - &.drawing { - background-image: url(../../public/static/images/main/drawing_icon.svg); - } - } - } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 16px; - background-color: #d9d9d9; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - &:after { - display: none; - } - } - } - } - .sub-header-title { - font-size: 16px; - color: #fff; - font-weight: 600; - } - .sub-header-location { - margin-left: auto; - display: flex; - align-items: center; - .location-item { - position: relative; +.sub-header{ + position: fixed; + top: 46px; + left: 0; + width: 100%; + height: 46px; + border-bottom: 1px solid #000; + background: #2C2C2C; + z-index: 999; + .sub-header-inner{ display: flex; align-items: center; - padding: 0 10px; - span { - display: flex; - font-size: 12px; - color: #aaa; - font-weight: normal; - cursor: default; + height: 100%; + padding: 0 100px; + .sub-header-title-wrap{ + display: flex; + align-items: center; + .title-item{ + position: relative; + padding: 0 24px; + a{ + display: flex; + align-items: center; + .icon{ + width: 22px; + height: 22px; + margin-right: 8px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + &.drawing{background-image: url(../../public/static/images/main/drawing_icon.svg);} + } + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 16px; + background-color: #D9D9D9; + } + &:first-child{ + padding-left: 0; + } + &:last-child{ + padding-right: 0; + &:after{ + display: none; + } + } + } } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 4px; - height: 6px; - background: url(../../public/static/images/main/loaction_arr.svg) no-repeat center; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - span { + .sub-header-title{ + font-size: 16px; color: #fff; - } - &:after { - display: none; - } + font-weight: 600; + } + .sub-header-location{ + margin-left: auto; + display: flex; + align-items: center; + .location-item{ + position: relative; + display: flex; + align-items: center; + padding: 0 10px; + span{ + display: flex; + font-size: 12px; + color: #AAA; + font-weight: normal; + cursor: default; + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 4px; + height: 6px; + background: url(../../public/static/images/main/loaction_arr.svg)no-repeat center; + } + &:first-child{ + padding-left: 0; + } + &:last-child{ + padding-right: 0; + span{ + color: #fff; + } + &:after{ + display: none; + } + } + } } - } } - } } // sub content -.sub-content { - padding-top: 46px; - .sub-content-inner { - max-width: 1720px; - margin: 0 auto; - padding-top: 20px; - .sub-content-box { - margin-bottom: 20px; - &:last-child { - margin-bottom: 0; - } +.sub-content{ + padding-top: 46px; + .sub-content-inner{ + max-width: 1720px; + margin: 0 auto; + padding-top: 20px; + .sub-content-box{ + margin-bottom: 20px; + &:last-child{ + margin-bottom: 0; + } + } } - } - &.estimate { - display: flex; - flex-direction: column; - padding-top: 0; - .sub-content-inner { - flex: 1; - width: 100%; + &.estimate{ + display: flex; + flex-direction: column; + padding-top: 0; + .sub-content-inner{ + flex: 1; + width: 100%; + } } - } } -.sub-table-box { - padding: 20px; - border-radius: 6px; - border: 1px solid #e9eaed; - background: #fff; - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - .table-box-title-wrap { - display: flex; - align-items: center; - margin-bottom: 15px; - .title-wrap { - display: flex; - align-items: center; - h3 { - display: block; - font-size: 15px; - color: #101010; - font-weight: 600; - margin-right: 14px; - &.product { - margin-right: 10px; - } - } - .product_tit { - position: relative; - font-size: 15px; - font-weight: 600; - color: #1083e3; - padding-left: 10px; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #d9d9d9; - } - } - .option { - padding-left: 5px; - font-size: 13px; - color: #101010; - font-weight: 400; - } - .info-wrap { +.sub-table-box{ + padding: 20px; + border-radius: 6px; + border: 1px solid #E9EAED; + background: #FFF; + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + .table-box-title-wrap{ display: flex; align-items: center; - li { - position: relative; - padding: 0 6px; - font-size: 12px; - color: #101010; - font-weight: normal; - span { - font-weight: 600; - &.red { - color: #e23d70; + margin-bottom: 15px; + .title-wrap{ + display: flex; + align-items: center; + h3{ + display: block; + font-size: 15px; + color: #101010; + font-weight: 600; + margin-right: 14px; + &.product{ + margin-right: 10px; + } } - } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 11px; - background-color: #d9d9d9; - } - &:first-child { - padding-left: 0; - } - &:last-child { - padding-right: 0; - &::after { - display: none; + .product_tit{ + position: relative; + font-size: 15px; + font-weight: 600; + color: #1083E3; + padding-left: 10px; + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #D9D9D9; + } + } + .option{ + padding-left: 5px; + font-size: 13px; + color: #101010; + font-weight: 400; + } + .info-wrap{ + display: flex; + align-items: center; + li{ + position: relative; + padding: 0 6px; + font-size: 12px; + color: #101010; + font-weight: normal; + span{ + font-weight: 600; + &.red{ + color: #E23D70; + } + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 11px; + background-color: #D9D9D9; + } + &:first-child{padding-left: 0;} + &:last-child{padding-right: 0;&::after{display: none;}} + } } - } } - } } - } - .left-unit-box { - margin-left: auto; - display: flex; - align-items: center; - } - .promise-gudie { - display: block; - font-size: 13px; - font-weight: 700; - color: #101010; - margin-bottom: 20px; - } - .important { - color: #f00; - } - .sub-center-footer { - display: flex; - align-items: center; - justify-content: center; - margin-top: 20px; - } - .sub-right-footer { - display: flex; - align-items: center; - justify-content: flex-end; - margin-top: 20px; - } + .left-unit-box{ + margin-left: auto; + display: flex; + align-items: center; + } + .promise-gudie{ + display: block; + font-size: 13px; + font-weight: 700; + color: #101010; + margin-bottom: 20px; + } + .important{ + color: #f00; + } + .sub-center-footer{ + display: flex; + align-items: center; + justify-content: center; + margin-top: 20px; + } + .sub-right-footer{ + display: flex; + align-items: center; + justify-content: flex-end; + margin-top: 20px; + } } -.pagination-wrap { - margin-top: 24px; +.pagination-wrap{ + margin-top: 24px; } -.infomation-wrap { - margin-bottom: 30px; +.infomation-wrap{ + margin-bottom: 30px; } -.infomation-box-wrap { - display: flex; - align-items: center; - gap: 10px; - .sub-table-box { - flex: 1; - } - .info-title { - font-size: 14px; - font-weight: 500; - color: #344356; - margin-bottom: 10px; - } - .info-inner { - position: relative; - font-size: 13px; - color: #344356; - .copy-ico { - position: absolute; - bottom: 0; - right: 0; - width: 16px; - height: 16px; - background: url(../../public/static/images/sub/copy_ico.svg) no-repeat center; - background-size: cover; +.infomation-box-wrap{ + display: flex; + align-items: center; + gap: 10px; + .sub-table-box{ + flex: 1 ; + } + .info-title{ + font-size: 14px; + font-weight: 500; + color: #344356; + margin-bottom: 10px; + } + .info-inner{ + position: relative; + font-size: 13px; + color: #344356; + .copy-ico{ + position: absolute; + bottom: 0; + right: 0; + width: 16px; + height: 16px; + background: url(../../public/static/images/sub/copy_ico.svg)no-repeat center; + background-size: cover; + } } - } } // 견적서 -.estimate-list-wrap { - display: flex; - align-items: center; - margin-bottom: 10px; - &.one { - .estimate-box { - &:last-child { - min-width: unset; - } - } - } - .estimate-box { - flex: 1; +.estimate-list-wrap{ display: flex; align-items: center; - &:last-child { - flex: none; - min-width: 220px; + margin-bottom: 10px; + &.one{ + .estimate-box{ + &:last-child{ + min-width: unset; + } + } } - .estimate-tit { - width: 105px; - height: 30px; - line-height: 30px; - background-color: #f4f4f7; - border-radius: 100px; - text-align: center; - font-size: 13px; - font-weight: 500; - color: #344356; + .estimate-box{ + flex: 1 ; + display: flex; + align-items: center; + &:last-child{ + flex: none; + min-width: 220px; + } + .estimate-tit{ + width: 105px; + height: 30px; + line-height: 30px; + background-color: #F4F4F7; + border-radius: 100px; + text-align: center; + font-size: 13px; + font-weight: 500; + color: #344356; + } + .estimate-name{ + font-size: 13px; + color: #344356; + margin-left: 14px; + font-weight: 400; + &.blue{ + font-size: 16px; + font-weight: 700; + color: #1083E3; + } + &.red{ + font-size: 16px; + font-weight: 700; + color: #D72A2A; + } + } } - .estimate-name { - font-size: 13px; - color: #344356; - margin-left: 14px; - font-weight: 400; - &.blue { - font-size: 16px; - font-weight: 700; - color: #1083e3; - } - &.red { - font-size: 16px; - font-weight: 700; - color: #d72a2a; - } + &:last-child{ + margin-bottom: 0; } - } - &:last-child { - margin-bottom: 0; - } } // file drag box -.drag-file-box { - padding: 10px; - .btn-area { - padding-bottom: 15px; - border-bottom: 1px solid #ecf0f4; - } - .drag-file-area { - position: relative; - margin-top: 15px; - p { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - font-size: 13px; - color: #ccc; - font-weight: 400; - cursor: default; +.drag-file-box{ + padding: 10px; + .btn-area{ + padding-bottom: 15px; + border-bottom: 1px solid #ECF0F4; } - } - .file-list { - .file-item { - margin-bottom: 15px; - span { + .drag-file-area{ position: relative; - font-size: 13px; - color: #45576f; - font-weight: 400; - white-space: nowrap; - padding-right: 55px; - button { - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 15px; - height: 15px; - background: url(../../public/static/images/sub/file_delete.svg) no-repeat center; - background-size: cover; + margin-top: 15px; + p{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + font-size: 13px; + color: #ccc; + font-weight: 400; + cursor: default; + } + } + .file-list{ + .file-item{ + margin-bottom: 15px; + span{ + position: relative; + font-size: 13px; + color: #45576F; + font-weight: 400; + white-space: nowrap; + padding-right: 55px; + button{ + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 15px; + height: 15px; + background: url(../../public/static/images/sub/file_delete.svg)no-repeat center; + background-size: cover; + } + } + &:last-child{ + margin-bottom: 0; + } } - } - &:last-child { - margin-bottom: 0; - } } - } } -.special-note-check-wrap { - display: grid; - grid-template-columns: repeat(5, 1fr); - border: 1px solid #ecf0f4; - border-radius: 3px; - margin-bottom: 30px; - .special-note-check-item { - padding: 14px 10px; - border-right: 1px solid #ecf0f4; - border-top: 1px solid #ecf0f4; - &:nth-child(5n) { - border-right: none; +.special-note-check-wrap{ + display: grid; + grid-template-columns: repeat(5, 1fr); + border: 1px solid #ECF0F4; + border-radius: 3px; + margin-bottom: 30px; + .special-note-check-item{ + padding: 14px 10px; + border-right: 1px solid #ECF0F4; + border-top: 1px solid #ECF0F4; + &:nth-child(5n){ + border-right: none; + } + &:nth-child(-n+5){ + border-top: none; + } + &.act{ + background-color: #F7F9FA; + } } - &:nth-child(-n + 5) { - border-top: none; - } - &.act { - background-color: #f7f9fa; - } - } } -.calculation-estimate { - border: 1px solid #ecf0f4; - border-radius: 3px; - padding: 24px; - max-height: 350px; - overflow-y: auto; - margin-bottom: 30px; - dl { - margin-bottom: 35px; - &:last-child { - margin-bottom: 0; +.calculation-estimate{ + border: 1px solid #ECF0F4; + border-radius: 3px; + padding: 24px; + max-height: 350px; + overflow-y: auto; + margin-bottom: 30px; + dl{ + margin-bottom: 35px; + &:last-child{ + margin-bottom: 0; + } + dt{ + font-size: 13px; + font-weight: 600; + color: #1083E3; + margin-bottom: 15px; + } + dd{ + font-size: 12px; + font-weight: 400; + color: #45576F; + margin-bottom: 8px; + &:last-child{ + margin-bottom: 0; + } + } } - dt { - font-size: 13px; - font-weight: 600; - color: #1083e3; - margin-bottom: 15px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; } - dd { - font-size: 12px; - font-weight: 400; - color: #45576f; - margin-bottom: 8px; - &:last-child { - margin-bottom: 0; - } + &::-webkit-scrollbar-thumb { + background-color: #d9dee2; + } + &::-webkit-scrollbar-track { + background-color: transparent; } - } - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9dee2; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } } -.esimate-wrap { - margin-bottom: 20px; +.esimate-wrap{ + margin-bottom: 20px; } -.estimate-product-option { - display: flex; - align-items: center; - margin-bottom: 15px; - .product-price-wrap { +.estimate-product-option{ display: flex; align-items: center; - .product-price-tit { - font-size: 13px; - font-weight: 400; - color: #45576f; - margin-right: 10px; - } - .select-wrap { - width: 110px; - } - } - .product-edit-wrap { - display: flex; - align-items: center; - margin-left: auto; - .product-edit-explane { - display: flex; - align-items: center; - margin-right: 15px; - .attachment-required { - position: relative; + margin-bottom: 15px; + .product-price-wrap{ display: flex; align-items: center; - font-size: 12px; - font-weight: 400; - color: #45576f; - padding-right: 10px; - .ico { - width: 23px; - height: 23px; - margin-right: 5px; - background: url(../../public/static/images/sub/attachment_ico.svg) no-repeat center; - background-size: cover; + .product-price-tit{ + font-size: 13px; + font-weight: 400; + color: #45576F; + margin-right: 10px; } - &::before { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 12px; - background-color: #d9d9d9; + .select-wrap{ + width: 110px; } - } - .click-check { + } + .product-edit-wrap{ display: flex; align-items: center; - font-size: 12px; - font-weight: 400; - color: #f16a6a; - padding-left: 10px; - .ico { - width: 14px; - height: 14px; - margin-right: 5px; - background: url(../../public/static/images/sub/click_check_ico.svg) no-repeat center; - background-size: cover; + margin-left: auto; + .product-edit-explane{ + display: flex; + align-items: center; + margin-right: 15px; + .attachment-required{ + position: relative; + display: flex; + align-items: center; + font-size: 12px; + font-weight: 400; + color: #45576F; + padding-right: 10px; + .ico{ + width: 23px; + height: 23px; + margin-right: 5px; + background: url(../../public/static/images/sub/attachment_ico.svg)no-repeat center; + background-size: cover; + } + &::before{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 12px; + background-color: #D9D9D9; + } + } + .click-check{ + display: flex; + align-items: center; + font-size: 12px; + font-weight: 400; + color: #F16A6A ; + padding-left: 10px; + .ico{ + width: 14px; + height: 14px; + margin-right: 5px; + background: url(../../public/static/images/sub/click_check_ico.svg)no-repeat center; + background-size: cover; + } + } } - } - } - .product-edit-btn { - display: flex; - align-items: center; - button { - display: flex; - align-items: center; - span { - width: 13px; - height: 13px; - margin-right: 5px; - background-size: cover; - &.plus { - background: url(../../public/static/images/sub/plus_btn.svg) no-repeat center; - } - &.minus { - background: url(../../public/static/images/sub/minus_btn.svg) no-repeat center; - } + .product-edit-btn{ + display: flex; + align-items: center; + button{ + display: flex; + align-items: center; + span{ + width: 13px; + height: 13px; + margin-right: 5px; + background-size: cover; + &.plus{ + background: url(../../public/static/images/sub/plus_btn.svg)no-repeat center; + } + &.minus{ + background: url(../../public/static/images/sub/minus_btn.svg)no-repeat center; + } + } + } } - } } - } + } // 발전시물레이션 -.chart-wrap { - display: flex; - gap: 20px; - width: 100%; - .sub-table-box { - height: 100%; - } - .chart-inner { - flex: 1; - .chart-box { - margin-bottom: 30px; - } - } - .chart-table-wrap { +.chart-wrap{ display: flex; - flex-direction: column; - flex: none; - width: 650px; - .sub-table-box { - flex: 1; - &:first-child { - margin-bottom: 20px; - } + gap: 20px; + width: 100%; + .sub-table-box{ + height: 100%; + } + .chart-inner{ + flex: 1; + .chart-box{ + margin-bottom: 30px; + } + } + .chart-table-wrap{ + display: flex; + flex-direction: column; + flex: none; + width: 650px; + .sub-table-box{ + flex: 1; + &:first-child{ + margin-bottom: 20px; + } + } } - } } -.chart-month-table { - table { - table-layout: fixed; - border-collapse: collapse; - border: 1px solid #ecf0f4; - border-radius: 4px; - thead { - th { - padding: 4.5px 0; - border-bottom: 1px solid #ecf0f4; +.chart-month-table{ + table{ + table-layout: fixed; + border-collapse:collapse; + border: 1px solid #ECF0F4; + border-radius: 4px; + thead{ + th{ + padding: 4.5px 0; + border-bottom: 1px solid #ECF0F4; + text-align: center; + font-size: 13px; + color: #45576F; + font-weight: 500; + background-color: #F8F9FA; + } + } + tbody{ + td{ + font-size: 13px; + color: #45576F; + text-align: center; + padding: 4.5px 0; + } + } + } +} + +.simulation-guide-wrap{ + display: flex; + padding: 20px; + .simulation-tit-wrap{ + padding-right: 40px; + border-right: 1px solid #EEEEEE; + span{ + display: block; + position: relative; + padding-left: 60px; + font-size: 15px; + color: #14324F; + font-weight: 600; + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 40px; + height: 40px; + background: url(../../public/static/images/sub/simulation_guide.svg)no-repeat center; + background-size: cover; + } + } + } + .simulation-guide-box{ + padding-left: 40px; + dl{ + margin-bottom: 25px; + dt{ + font-size: 13px; + color: #101010; + font-weight: 600; + margin-bottom: 5px; + } + dd{ + font-size: 12px; + color: #45576F; + font-weight: 400; + line-height: 24px; + } + &:last-child{ + margin-bottom: 0; + } + } + } +} + +.module-total{ + display: flex; + align-items: center; + background-color: #F8F9FA; + padding: 9px 0; + margin-right: 4px; + border: 1px solid #ECF0F4; + border-top: none; + .total-title{ + flex: 1; text-align: center; font-size: 13px; - color: #45576f; + color: #344356; font-weight: 500; - background-color: #f8f9fa; - } } - tbody { - td { - font-size: 13px; - color: #45576f; + .total-num{ + flex: none; + width: 121px; text-align: center; - padding: 4.5px 0; - } + font-size: 15px; + color: #344356; + font-weight: 500; } - } -} - -.simulation-guide-wrap { - display: flex; - padding: 20px; - .simulation-tit-wrap { - padding-right: 40px; - border-right: 1px solid #eeeeee; - span { - display: block; - position: relative; - padding-left: 60px; - font-size: 15px; - color: #14324f; - font-weight: 600; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 40px; - height: 40px; - background: url(../../public/static/images/sub/simulation_guide.svg) no-repeat center; - background-size: cover; - } - } - } - .simulation-guide-box { - padding-left: 40px; - dl { - margin-bottom: 25px; - dt { - font-size: 13px; - color: #101010; - font-weight: 600; - margin-bottom: 5px; - } - dd { - font-size: 12px; - color: #45576f; - font-weight: 400; - line-height: 24px; - } - &:last-child { - margin-bottom: 0; - } - } - } -} - -.module-total { - display: flex; - align-items: center; - background-color: #f8f9fa; - padding: 9px 0; - margin-right: 4px; - border: 1px solid #ecf0f4; - border-top: none; - .total-title { - flex: 1; - text-align: center; - font-size: 13px; - color: #344356; - font-weight: 500; - } - .total-num { - flex: none; - width: 121px; - text-align: center; - font-size: 15px; - color: #344356; - font-weight: 500; - } } // 물건상세 -.information-help-wrap { - display: flex; - padding: 24px; - background-color: #f4f4f4; - border-radius: 4px; - margin-bottom: 15px; - .information-help-tit-wrap { - position: relative; +.information-help-wrap{ display: flex; - align-items: center; - padding-right: 40px; - border-right: 1px solid #e0e0e3; - .help-tit-icon { - width: 40px; - height: 40px; - border-radius: 50%; - margin-right: 10px; - background: #fff url(../../public/static/images/sub/information_help.svg) no-repeat center; - background-size: 20px 20px; + padding: 24px; + background-color: #F4F4F4; + border-radius: 4px; + margin-bottom: 15px; + .information-help-tit-wrap{ + position: relative; + display: flex; + align-items: center; + padding-right: 40px; + border-right: 1px solid #E0E0E3; + .help-tit-icon{ + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 10px; + background: #fff url(../../public/static/images/sub/information_help.svg)no-repeat center; + background-size: 20px 20px; + } + .help-tit{ + font-size: 13px; + font-weight: 600; + color: #45576F; + } } - .help-tit { - font-size: 13px; - font-weight: 600; - color: #45576f; + .information-help-guide{ + padding-left: 40px; + span{ + display: block; + font-size: 12px; + font-weight: 400; + color: #45576F; + margin-bottom: 7px; + &:last-child{ + margin-bottom: 0; + } + } } - } - .information-help-guide { - padding-left: 40px; - span { - display: block; - font-size: 12px; - font-weight: 400; - color: #45576f; - margin-bottom: 7px; - &:last-child { - margin-bottom: 0; - } - } - } } -.community-search-warp { - display: flex; - flex-direction: column; - align-items: center; - padding: 10px 0 30px 0; - border-bottom: 1px solid #e5e5e5; - margin-bottom: 24px; - .community-search-box { - position: relative; +.community-search-warp{ display: flex; + flex-direction: column; align-items: center; - width: 580px; - height: 45px; - padding: 0 45px 0 20px; - margin-bottom: 20px; - border-radius: 2px; - border: 1px solid #101010; - .community-input { - width: 100%; - height: 100%; - font-size: 13px; - font-weight: 400; - color: #101010; - &::placeholder { - color: #c8c8c8; - } + padding: 10px 0 30px 0; + border-bottom: 1px solid #E5E5E5; + margin-bottom: 24px; + .community-search-box{ + position: relative; + display: flex; + align-items: center; + width: 580px; + height: 45px; + padding: 0 45px 0 20px; + margin-bottom: 20px; + border-radius: 2px; + border: 1px solid #101010; + .community-input{ + width: 100%; + height: 100%; + font-size: 13px; + font-weight: 400; + color: #101010; + &::placeholder{ + color: #C8C8C8; + } + } + .community-search-ico{ + position: absolute; + top: 50%; + right: 20px; + transform: translateY(-50%); + flex: none; + width: 21px; + height: 100%; + background: url(../../public/static/images/sub/community_search.svg)no-repeat center; + background-size: 21px 21px; + z-index: 3; + } } - .community-search-ico { - position: absolute; - top: 50%; - right: 20px; - transform: translateY(-50%); - flex: none; - width: 21px; - height: 100%; - background: url(../../public/static/images/sub/community_search.svg) no-repeat center; - background-size: 21px 21px; - z-index: 3; + .community-search-keyword{ + font-size: 13px; + font-weight: 400; + color: #45576F; + span{ + font-weight: 600; + color: #F16A6A; + } } - } - .community-search-keyword { - font-size: 13px; - font-weight: 400; - color: #45576f; - span { - font-weight: 600; - color: #f16a6a; - } - } } // 자료 다운로드 -.file-down-list { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 14px; - .file-down-item { - display: flex; - align-items: center; - padding: 24px; - border-radius: 4px; - border: 1px solid #e5e5e5; - background: #fff; - transition: all 0.15s ease-in-out; - cursor: pointer; - .file-item-info { - .item-num { - display: inline-block; - padding: 6px 17.5px; - border-radius: 60px; - background-color: #f4f4f7; - font-size: 13px; - font-weight: 600; - color: #101010; - margin-bottom: 15px; - } - .item-name { - font-size: 16px; - color: #101010; - font-weight: 500; - margin-bottom: 13px; - } - .item-date { - font-size: 13px; - font-weight: 400; - color: #344356; - } +.file-down-list{ + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + .file-down-item{ + display: flex; + align-items: center; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + background: #FFF; + transition: all .15s ease-in-out; + cursor: pointer; + .file-item-info{ + .item-num{ + display: inline-block; + padding: 6px 17.5px; + border-radius: 60px; + background-color: #F4F4F7; + font-size: 13px; + font-weight: 600; + color: #101010; + margin-bottom: 15px; + } + .item-name{ + font-size: 16px; + color: #101010; + font-weight: 500; + margin-bottom: 13px; + } + .item-date{ + font-size: 13px; + font-weight: 400; + color: #344356; + } + } + .file-down-box{ + display: flex; + align-items: center; + flex: none; + margin-left: auto; + height: 100%; + .file-down-btn{ + width: 36px; + height: 36px; + background: url(../../public/static/images/sub/file_down_btn.svg)no-repeat center; + background-size: cover; + } + } + &:hover{ + background-color: #F4F4F7; + } } - .file-down-box { - display: flex; - align-items: center; - flex: none; - margin-left: auto; - height: 100%; - .file-down-btn { - width: 36px; - height: 36px; - background: url(../../public/static/images/sub/file_down_btn.svg) no-repeat center; - background-size: cover; - } - } - &:hover { - background-color: #f4f4f7; - } - } } -.file-down-nodata { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 148px; - padding: 24px; - border-radius: 4px; - border: 1px solid #e5e5e5; - font-size: 16px; - font-weight: 500; - color: #344356; -} +.file-down-nodata{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 148px; + padding: 24px; + border-radius: 4px; + border: 1px solid #E5E5E5; + font-size: 16px; + font-weight: 500; + color: #344356; +} \ No newline at end of file diff --git a/src/styles/_main.scss b/src/styles/_main.scss index 6a2a06e6..ea9b8833 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -1,687 +1,652 @@ // background img -.background-bord { - position: absolute; - top: 46px; - left: 0; - width: 100%; - height: 280px; - background: url(../../public/static/images/main/main_background.png) no-repeat center; - background-size: cover; - z-index: 0; +.background-bord{ + position: absolute; + top: 46px; + left: 0; + width: 100%; + height: 280px; + background: url(../../public/static/images/main/main_background.png)no-repeat center; + background-size: cover; + z-index: 0; } // main-wrap -.main-contents { - position: relative; - z-index: 1; - padding-bottom: 15px; +.main-contents{ + position: relative; + z-index: 1; + padding-bottom: 15px; } // contents -.store-id-wrap { - display: flex; - align-items: center; - justify-content: center; - gap: 12px; - padding: 33.5px 0; - border-bottom: 1px solid rgba(255, 255, 255, 0.08); - background-color: rgba(255, 255, 255, 0.05); - .store-id-title { - position: relative; - padding-left: 32px; - font-size: 13px; - color: #fff; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 20px; - height: 20px; - background: url(../../public/static/images/main/id_icon.svg) no-repeat center; - } - } - .store-arr { - display: block; - width: 7px; - height: 10px; - background: url(../../public/static/images/main/store-arr.svg) no-repeat center; - } - .store-id-name { - font-size: 16px; - color: #fff; - font-weight: 600; - } -} - -// main-search-form -.main-search-wrap { - display: flex; - align-items: center; - justify-content: center; - padding: 45px 0; - .search-raido-wrap { +.store-id-wrap{ display: flex; align-items: center; - gap: 16px; - margin-right: 30px; - } -} -.search-input-box { - display: flex; - align-items: center; - width: 580px; - height: 45px; - border-radius: 100px; - padding: 0 20px; - border: 1px solid rgba(255, 255, 255, 0.3); - background: rgba(31, 31, 31, 0.3); - .main-search { - flex: 1; - height: 100%; - font-size: 13px; - color: #fff; - background-color: transparent; - outline: none; - border: none; - font-family: 'Noto Sans JP', sans-serif; - } - .search-icon { - width: 20px; - height: 100%; - background-image: url(../../public/static/images/main/main_search.svg); - background-repeat: no-repeat; - background-position: center; - background-size: 21px 21px; - } -} - -// main-contents-inner -.main-product-list-wrap { - max-width: 1400px; - margin: 0 auto; - .main-product-list { - display: flex; - gap: 24px; - margin-bottom: 24px; - .product-item { - display: flex; - flex-direction: column; - padding: 40px; - border-radius: 6px; - background: #fff; - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - &.item01 { - flex: 1; - height: 400px; - } - &.item02 { - flex: none; - width: 451px; - height: 400px; - } - &.item03 { - flex: 1; - } - &.item04 { - flex: none; - width: 351px; - } - &.item05 { - flex: none; - width: 451px; - } - .product-item-title-wrap { - display: flex; - align-items: center; - .product-item-title { - display: flex; - align-items: center; - font-size: 16px; - color: #101010; - font-weight: 600; - .item-logo { - display: block; - width: 40px; - height: 40px; - border-radius: 50px; - background: #14324f; - margin-right: 12px; - background-repeat: no-repeat; - background-size: 22px 22px; - background-position: center; - &.ico01 { - background-image: url(../../public/static/images/main/product_ico01.svg); - } - &.ico02 { - background-image: url(../../public/static/images/main/product_ico02.svg); - } - &.ico03 { - background-image: url(../../public/static/images/main/product_ico03.svg); - } - &.ico04 { - background-image: url(../../public/static/images/main/product_ico04.svg); - } - &.ico05 { - background-image: url(../../public/static/images/main/product_ico05.svg); - } - } - } - .more-btn { - display: block; - width: 20px; - height: 20px; - margin-left: auto; - background: url(../../public/static/images/main/more_btn.svg) no-repeat center; - } - } - .product-item-content { - margin-top: 30px; - overflow: hidden; - .recently-list { - .recently-item { - border: 1px solid #f2f2f2; - background-color: transparent; - padding: 29.9px 20px; - margin-bottom: 5px; - cursor: pointer; - .item-inner { - display: flex; - align-items: center; - span { - position: relative; - display: block; - font-size: 13px; - color: #101010; - font-weight: 400; - padding: 0 10px; - &.time { - padding-left: 22px; - &::before { - content: ''; - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); - width: 14px; - height: 14px; - background: url(../../public/static/images/main/clock.svg) no-repeat center; - background-size: cover; - } - } - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 1px; - height: 10px; - background-color: #bbb; - } - &:last-child { - &:after { - display: none; - } - } - } - } - &:last-child { - margin-bottom: 5px; - } - } - } - .notice-box { - height: 100%; - overflow-y: auto; - .notice-day { - font-size: 13px; - color: #666; - font-weight: 400; - margin-bottom: 7px; - } - .notice-title { - font-size: 14px; - color: #101010; - font-weight: 600; - margin-bottom: 25px; - line-height: 24px; - word-break: keep-all; - } - .notice-contents { - font-size: 12px; - color: #666; - font-weight: 400; - line-height: 22px; - span { - position: relative; - display: block; - padding-left: 10px; - &::before { - content: ''; - position: absolute; - top: 10px; - left: 3px; - width: 3px; - height: 3px; - border-radius: 100%; - background-color: #666; - } - } - } - &::-webkit-scrollbar { - width: 4px; /* 스크롤바의 너비 */ - } - &::-webkit-scrollbar-thumb { - background: #697c8f; /* 스크롤바의 색상 */ - } - &::-webkit-scrollbar-track { - background: transparent; /*스크롤바 뒷 배경 색상*/ - } - } - .faq-item { - position: relative; - margin-bottom: 10px; - cursor: pointer; - .faq-item-inner { - display: flex; - align-items: center; - - .faq-num { - flex: none; - padding: 7px 12.5px; - font-size: 13px; - color: #101010; - font-weight: 600; - border-radius: 110px; - border: 1px solid rgba(242, 242, 242, 0.95); - margin-right: 20px; - } - .faq-title { - width: 0; - flex: 1 1 auto; - font-size: 13px; - color: #101010; - font-weight: 500; - padding-right: 96px; - white-space: nowrap; - text-overflow: ellipsis; - overflow: hidden; - } - .faq-day { - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - font-size: 13px; - color: #101010; - font-weight: 400; - } - } - &:last-child { - margin-bottom: 0; - } - } - .data-download-wrap { - width: 100%; - .data-down { - display: block; - width: 100%; - padding: 20px; - text-align: left; - border-radius: 4px; - background-color: #697c8f; - margin-bottom: 5px; - transition: background 0.17s ease-in-out; - span { - position: relative; - display: block; - padding-right: 30px; - font-size: 13px; - color: #fff; - font-weight: 400; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 18px; - height: 16px; - background: url(../../public/static/images/main/download.svg) no-repeat center; - background-size: cover; - } - } - &:last-child { - margin-bottom: 0; - } - &:hover { - background-color: #859eb6; - } - } - } - .contact-info-list { - padding: 25px 30px; - border-radius: 4px; - background-color: #f4f4f7; - .info-item { - display: flex; - align-items: center; - padding: 15px 0; - border-bottom: 1px solid #fff; - &:first-child { - padding-top: 0; - } - &:last-child { - padding-bottom: 0; - border: none; - } - .icon-box { - display: flex; - margin-right: 12px; - } - .infor-data { - font-size: 13px; - color: #101010; - font-weight: 500; - } - } - } - } - } - &:last-child { - margin-bottom: 0; - } - } -} - -// loginpage -.login-wrap { - position: relative; - width: 100%; - min-height: 100vh; - display: flex; - flex-direction: column; - justify-content: center; - background: url(../../public/static/images/main/login_bg.png) no-repeat center; - background-size: cover; - .login-inner { - max-width: 500px; - width: 100%; - margin: 0 auto; - .login-logo { - display: block; - margin-bottom: 25px; - } - .login-input-frame { - padding: 40px 50px; - border-radius: 6px; - background: rgba(255, 255, 255, 0.97); - box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); - .login-frame-tit { - font-size: 18px; - color: #364864; - font-weight: 400; - padding-bottom: 30px; - border-bottom: 1px solid #e5e9ef; - span { - display: block; - font-weight: 600; - margin-bottom: 5px; - } - &.pw-reset { - font-size: 13px; - } - } - .login-input-wrap { - margin-top: 30px; - .login-area { - position: relative; - display: flex; - align-items: center; - border: 1px solid #e5e9ef; - height: 45px; - padding-left: 40px; - padding-right: 15px; - margin-bottom: 15px; - .login-input { - flex: 1; - height: 100%; - background-color: transparent; - font-size: 13px; - font-weight: 400; - color: #6c819c; - &::placeholder { - font-size: 13px; - font-weight: 400; - color: #d1d7e0; - } - } - &::before { + justify-content: center; + gap: 12px; + padding: 33.5px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.08); + background-color: rgba(255, 255, 255, 0.05); + .store-id-title{ + position: relative; + padding-left: 32px; + font-size: 13px; + color: #fff; + &::before{ content: ''; position: absolute; top: 50%; - left: 15px; + left: 0; transform: translateY(-50%); - width: 10px; - height: 12px; - background-size: cover; - } - button { width: 20px; - height: 100%; - background-repeat: no-repeat; - background-position: center; - } - &.id { - &::before { - background: url(../../public/static/images/main/login_id.svg) no-repeat center; - } - .id-delete { - background-image: url(../../public/static/images/main/id_delete.svg); - background-size: 17px 17px; - } - } - &.email { - &::before { - background: url(../../public/static/images/main/login_email.svg) no-repeat center; - width: 12px; - height: 9px; - } - .id-delete { - background-image: url(../../public/static/images/main/id_delete.svg); - background-size: 17px 17px; - } - } - &.password { - margin-bottom: 20px; - &::before { - background: url(../../public/static/images/main/login_password.svg) no-repeat center; - } - .password-hidden { - background-image: url(../../public/static/images/main/password_hidden.svg); - background-size: 19px 13px; - &.visible { - background-image: url(../../public/static/images/main/password_visible.svg); - } - } - } + height: 20px; + background: url(../../public/static/images/main/id_icon.svg)no-repeat center; } - .login-btn { - display: block; - width: 100%; - height: 45px; - background-color: #5c6773; - color: #fff; - font-size: 15px; - font-weight: 600; - border-radius: 4px; - transition: background 0.15s ease-in-out; - &:hover { - background-color: #717e8d; - } - &.light { - background-color: #fff; - border: 1px solid #5c6773; - color: #5c6773; - } - } - .login-btn-box { - margin-bottom: 20px; - } - .pwreset-btn-box { - display: flex; - } - .reset-password { - width: 100%; - text-align: center; - button { - position: relative; - font-size: 13px; - color: #364864; - font-weight: 400; - padding-right: 16px; - &::before { - content: ''; - position: absolute; - top: calc(50% + 1px); - right: 0; - transform: translateY(-50%); - width: 6px; - height: 8px; - background: url(../../public/static/images/main/login-arr.svg) no-repeat center; - } - } - } - } } - .login-guide-wrap { - position: relative; - margin-left: 10px; - margin-top: 30px; - padding-left: 15px; - font-size: 13px; - color: #fff; - line-height: 24px; - a { + .store-arr{ + display: block; + width: 7px; + height: 10px; + background: url(../../public/static/images/main/store-arr.svg) no-repeat center; + } + .store-id-name{ + font-size: 16px; color: #fff; font-weight: 600; - text-decoration: underline; - } - span { - position: absolute; - top: 0; - left: 0; - } } - } - .login-copyright { - position: absolute; - bottom: 40px; - left: 50%; - transform: translateX(-50%); - font-size: 11px; - color: #fff; - font-weight: 500; - } } -.d-check-box { - &.login { - margin-bottom: 25px; - label { - padding-left: 20px; - color: #364864; - &:before { - width: 22px; - height: 22px; - top: -1px; - border-color: #a8b6c7; - border-radius: 3px; - transition: background 0.05s ease-in-out; - } +// main-search-form +.main-search-wrap{ + display: flex; + align-items: center; + justify-content: center; + padding: 45px 0; + .search-raido-wrap{ + display: flex; + align-items: center; + gap: 16px; + margin-right: 30px; } - input[type='checkbox']:checked + label::before { - border-color: #a8b6c7; - background-color: #a8b6c7; +} +.search-input-box{ + display: flex; + align-items: center; + width: 580px; + height: 45px; + border-radius: 100px; + padding: 0 20px; + border: 1px solid rgba(255, 255, 255, 0.30); + background: rgba(31, 31, 31, 0.30); + .main-search{ + flex: 1; + height: 100%; + font-size: 13px; + color: #fff; + background-color: transparent; + outline: none; + border: none; + font-family: 'Noto Sans JP', sans-serif; } - input[type='checkbox']:checked + label::after { - border-color: #fff; - width: 7px; - height: 11px; - top: -2px; - left: 1px; + .search-icon{ + width: 20px; + height: 100%; + background-image: url(../../public/static/images/main/main_search.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 21px 21px; + } +} + +// main-contents-inner +.main-product-list-wrap{ + max-width: 1400px; + margin: 0 auto; + .main-product-list{ + display: flex; + gap: 24px; + margin-bottom: 24px; + .product-item{ + display: flex; + flex-direction: column; + padding: 40px; + border-radius: 6px; + background: #FFF; + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + &.item01{flex: 1; height: 400px;} + &.item02{flex: none; width: 451px; height: 400px;} + &.item03{flex: 1;} + &.item04{flex: none; width: 351px;} + &.item05{flex: none; width: 451px;} + .product-item-title-wrap{ + display: flex; + align-items: center; + .product-item-title{ + display: flex; + align-items: center; + font-size: 16px; + color: #101010; + font-weight: 600; + .item-logo{ + display: block; + width: 40px; + height: 40px; + border-radius: 50px; + background: #14324F; + margin-right: 12px; + background-repeat: no-repeat; + background-size: 22px 22px; + background-position: center; + &.ico01{background-image: url(../../public/static/images/main/product_ico01.svg);} + &.ico02{background-image: url(../../public/static/images/main/product_ico02.svg);} + &.ico03{background-image: url(../../public/static/images/main/product_ico03.svg);} + &.ico04{background-image: url(../../public/static/images/main/product_ico04.svg);} + &.ico05{background-image: url(../../public/static/images/main/product_ico05.svg);} + } + } + .more-btn{ + display: block; + width: 20px; + height: 20px; + margin-left: auto; + background: url(../../public/static/images/main/more_btn.svg)no-repeat center; + } + } + .product-item-content{ + margin-top: 30px; + overflow: hidden; + .recently-list{ + .recently-item{ + border: 1px solid #F2F2F2; + background-color: transparent; + padding: 29.9px 20px; + margin-bottom: 5px; + cursor: pointer; + .item-inner{ + display: flex; + align-items: center; + span{ + position: relative; + display: block; + font-size: 13px; + color: #101010; + font-weight: 400; + padding: 0 10px; + &.time{ + padding-left: 22px; + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); + width: 14px; + height: 14px; + background:url(../../public/static/images/main/clock.svg)no-repeat center; + background-size: cover; + } + } + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 1px; + height: 10px; + background-color: #BBB; + } + &:last-child{ + &:after{ + display: none; + } + } + } + } + &:last-child{ + margin-bottom: 5px; + } + } + } + .notice-box{ + height: 100%; + overflow-y: auto; + .notice-day{ + font-size: 13px; + color: #666; + font-weight: 400; + margin-bottom: 7px; + } + .notice-title{ + font-size: 14px; + color: #101010; + font-weight: 600; + margin-bottom: 25px; + line-height: 24px; + word-break: keep-all; + } + .notice-contents{ + font-size: 12px; + color: #666; + font-weight: 400; + line-height: 22px; + span{ + position: relative; + display: block; + padding-left: 10px; + &::before{ + content: ''; + position: absolute; + top: 10px; + left: 3px; + width: 3px; + height: 3px; + border-radius: 100%; + background-color: #666; + } + } + } + &::-webkit-scrollbar {width: 4px; /* 스크롤바의 너비 */} + &::-webkit-scrollbar-thumb {background: #697C8F; /* 스크롤바의 색상 */} + &::-webkit-scrollbar-track {background: transparent; /*스크롤바 뒷 배경 색상*/} + } + .faq-item{ + position: relative; + margin-bottom: 10px; + cursor: pointer; + .faq-item-inner{ + display: flex; + align-items: center; + + .faq-num{ + flex: none; + padding: 7px 12.5px; + font-size: 13px; + color: #101010; + font-weight: 600; + border-radius: 110px; + border: 1px solid rgba(242, 242, 242, 0.95); + margin-right: 20px; + } + .faq-title{ + width: 0; + flex: 1 1 auto; + font-size: 13px; + color: #101010; + font-weight: 500; + padding-right: 96px; + white-space: nowrap; + text-overflow: ellipsis; + overflow: hidden; + } + .faq-day{ + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + font-size: 13px; + color: #101010; + font-weight: 400; + } + } + &:last-child{ + margin-bottom: 0; + } + } + .data-download-wrap{ + width: 100%; + .data-down{ + display: block; + width: 100%; + padding: 20px; + text-align: left; + border-radius: 4px; + background-color: #697C8F; + margin-bottom: 5px; + transition: background .17s ease-in-out; + span{ + position: relative; + display: block; + padding-right: 30px; + font-size: 13px; + color: #fff; + font-weight: 400; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 18px; + height: 16px; + background: url(../../public/static/images/main/download.svg)no-repeat center; + background-size: cover; + } + } + &:last-child{ + margin-bottom: 0; + } + &:hover{ + background-color: #859eb6; + } + } + } + .contact-info-list{ + padding: 25px 30px; + border-radius: 4px; + background-color: #F4F4F7; + .info-item{ + display: flex; + align-items: center; + padding: 15px 0; + border-bottom: 1px solid #fff; + &:first-child{padding-top: 0;} + &:last-child{padding-bottom: 0; border: none;} + .icon-box{ + display: flex; + margin-right: 12px; + } + .infor-data{ + font-size: 13px; + color: #101010; + font-weight: 500; + } + } + } + } + } + &:last-child{ + margin-bottom: 0; + } + } +} + +// loginpage +.login-wrap{ + position: relative; + width: 100%; + min-height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + background: url(../../public/static/images/main/login_bg.png) no-repeat center; + background-size: cover; + .login-inner{ + max-width: 500px; + width: 100%; + margin: 0 auto; + .login-logo{ + display: block; + margin-bottom: 25px; + } + .login-input-frame{ + padding: 40px 50px; + border-radius: 6px; + background: rgba(255, 255, 255, 0.97); + box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); + .login-frame-tit{ + font-size: 18px; + color: #364864; + font-weight: 400; + padding-bottom: 30px; + border-bottom: 1px solid #E5E9EF; + span{ + display: block; + font-weight: 600; + margin-bottom: 5px; + } + &.pw-reset{ + font-size: 13px; + } + } + .login-input-wrap{ + margin-top: 30px; + .login-area{ + position: relative; + display: flex; + align-items: center; + border: 1px solid #E5E9EF; + height: 45px; + padding-left: 40px; + padding-right: 15px; + margin-bottom: 15px; + .login-input{ + flex: 1; + height: 100%; + background-color: transparent; + font-size: 13px; + font-weight: 400; + color: #6c819c; + &::placeholder{ + font-size: 13px; + font-weight: 400; + color: #D1D7E0; + } + } + &::before{ + content: ''; + position: absolute; + top: 50%; + left: 15px; + transform: translateY(-50%); + width: 10px; + height: 12px; + background-size: cover; + } + button{ + width: 20px; + height: 100%; + background-repeat: no-repeat; + background-position: center; + } + &.id{ + &::before{ + background: url(../../public/static/images/main/login_id.svg)no-repeat center; + } + .id-delete{ + background-image: url(../../public/static/images/main/id_delete.svg); + background-size: 17px 17px; + } + } + &.email{ + &::before{ + background: url(../../public/static/images/main/login_email.svg)no-repeat center; + width: 12px; + height: 9px; + } + .id-delete{ + background-image: url(../../public/static/images/main/id_delete.svg); + background-size: 17px 17px; + } + } + &.password{ + margin-bottom: 20px; + &::before{ + background: url(../../public/static/images/main/login_password.svg)no-repeat center; + } + .password-hidden{ + background-image: url(../../public/static/images/main/password_hidden.svg); + background-size: 19px 13px; + &.visible{ + background-image: url(../../public/static/images/main/password_visible.svg); + } + } + } + } + .login-btn{ + display: block; + width: 100%; + height: 45px; + background-color: #5C6773; + color: #fff; + font-size: 15px; + font-weight: 600; + border-radius: 4px; + transition: background .15s ease-in-out; + &:hover{ + background-color: #717e8d; + } + &.light{ + background-color: #fff; + border: 1px solid #5C6773; + color: #5C6773; + } + } + .login-btn-box{ + margin-bottom: 20px; + } + .pwreset-btn-box{ + display: flex; + } + .reset-password{ + width: 100%; + text-align: center; + button{ + position: relative; + font-size: 13px; + color: #364864; + font-weight: 400; + padding-right: 16px; + &::before{ + content: ''; + position: absolute; + top: calc(50% + 1px); + right: 0; + transform: translateY(-50%); + width: 6px; + height: 8px; + background: url(../../public/static/images/main/login-arr.svg)no-repeat center; + } + } + } + } + } + .login-guide-wrap{ + position: relative; + margin-left: 10px; + margin-top: 30px; + padding-left: 15px; + font-size: 13px; + color: #fff; + line-height: 24px; + a{ + color: #fff; + font-weight: 600; + text-decoration: underline; + } + span{ + position: absolute; + top: 0; + left: 0; + } + } + } + .login-copyright{ + position: absolute; + bottom: 40px; + left: 50%; + transform: translateX(-50%); + font-size: 11px; + color: #fff; + font-weight: 500; + } +} + +.d-check-box{ + &.login{ + margin-bottom: 25px; + label{ + padding-left: 20px; + color: #364864; + &:before{ + width: 22px; + height: 22px; + top: -1px; + border-color: #A8B6C7; + border-radius: 3px; + transition: background .05s ease-in-out; + } + } + input[type=checkbox]:checked + label::before{ + border-color: #A8B6C7; + background-color: #A8B6C7; + } + input[type=checkbox]:checked + label::after{ + border-color: #fff; + width: 7px; + height: 11px; + top: -2px; + left: 1px; + } } - } } // 회원가입 -.center-page-wrap { - display: flex; - flex-direction: column; - justify-content: center; - width: 100%; - min-height: 100vh; - background-color: #f4f4f7; - overflow-x: hidden; - .center-page-inner { +.center-page-wrap{ + display: flex; + flex-direction: column; + justify-content: center; width: 100%; - max-width: 1720px; - margin: 0 auto; - .center-page-tit { - font-size: 18px; - font-weight: 600; - color: #101010; - margin-bottom: 24px; + min-height: 100vh; + background-color: #F4F4F7; + overflow-x: hidden; + .center-page-inner{ + width: 100%; + max-width: 1720px; + margin: 0 auto; + .center-page-tit{ + font-size: 18px; + font-weight: 600; + color: #101010; + margin-bottom: 24px; + } + .sub-table-box{ + &.signup{ + margin-bottom: 20px; + } + } + .sign-up-btn-wrap{ + display: flex; + justify-content: flex-end; + } + &.complete{ + max-width: 1000px; + } } - .sub-table-box { - &.signup { - margin-bottom: 20px; - } - } - .sign-up-btn-wrap { - display: flex; - justify-content: flex-end; - } - &.complete { - max-width: 1000px; - } - } + } // 회원가입 완료 -.complete-box-wrap { - padding: 72px 80px; - .complete-tit { - font-size: 18px; - font-weight: 600; - color: #101010; - margin-bottom: 17px; - } - .complete-txt { - font-size: 13px; - font-weight: 400; - color: #101010; - margin-bottom: 27px; - } - .complete-email-wrap { - padding: 36px 30px; - border-radius: 2px; - background: #f4f4f7; - margin-bottom: 20px; - .email-info { - font-size: 13px; - font-weight: 400; - color: #000; - span { - color: #204af4; - font-weight: 500; - } +.complete-box-wrap{ + padding: 72px 80px; + .complete-tit{ + font-size: 18px; + font-weight: 600; + color: #101010; + margin-bottom: 17px; } - } - .complete-btn { - display: flex; - justify-content: flex-end; - } -} + .complete-txt{ + font-size: 13px; + font-weight: 400; + color: #101010; + margin-bottom: 27px; + } + .complete-email-wrap{ + padding: 36px 30px; + border-radius: 2px; + background: #F4F4F7; + margin-bottom: 20px; + .email-info{ + font-size: 13px; + font-weight: 400; + color: #000; + span{ + color: #204AF4; + font-weight: 500; + } + } + } + .complete-btn{ + display: flex; + justify-content: flex-end; + } +} \ No newline at end of file diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index f4d79550..3901ba0f 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -4,669 +4,647 @@ $pop-bold-weight: 500; $pop-normal-size: 12px; $alert-color: #101010; -@keyframes mountpop { - from { - opacity: 0; - scale: 0.95; - } - to { - opacity: 1; - scale: 1; - } +@keyframes mountpop{ + from{opacity: 0; scale: 0.95;} + to{opacity: 1; scale: 1;} } -@keyframes unmountpop { - from { - opacity: 1; - scale: 1; - } - to { - opacity: 0; - scale: 0.95; - } +@keyframes unmountpop{ + from{opacity: 1; scale: 1;} + to{opacity: 0; scale: 0.95;} } -.normal-font { - font-size: 12px; - font-weight: 400; - color: #fff; +.normal-font{ + font-size: 12px; + font-weight: 400; + color: #fff; } -.bold-font { - font-size: 12px; - font-weight: 500; - color: #fff; +.bold-font{ + font-size: 12px; + font-weight: 500; + color: #fff; } -.modal-pop-wrap { - position: fixed; - width: 100%; - height: -webkit-fit-content; - height: -moz-fit-content; - height: fit-content; - border: 1px solid #000; - border-radius: 4px; - background-color: #272727; - z-index: 9999999; - &.xsm { - width: 200px; - } - &.xxxm { - width: 240px; - } - &.xxm { - width: 270px; - } - &.xm { - width: 300px; - } - &.ssm { - width: 380px; - } - &.sm { - width: 580px; - } - &.r { - width: 400px; - } - &.lr { - width: 440px; - } - &.lrr { - width: 480px; - } - &.ml { - width: 530px; - } - &.l-2 { - width: 640px; - } - &.lx-2 { - width: 740px; - } - &.lx { - width: 770px; - } - &.l { - width: 800px; - } - &.mount { - animation: mountpop 0.17s ease-in-out forwards; - } - &.unmount { - animation: unmountpop 0.17s ease-in-out forwards; - } - &.alert { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - background-color: transparent; - border: none; - .modal-head { - background-color: transparent; - padding: 0 0 8px; - .modal-close { - width: 20px; - height: 20px; - background: url(../../public/static/images/canvas/alert_close.svg) no-repeat center; - } +.modal-pop-wrap{ + position: fixed; + top: 0; + left: 0; + width: 100%; + height: -webkit-fit-content; + height: -moz-fit-content; + height: fit-content; + border: 1px solid #000; + border-radius: 4px; + background-color: #272727; + z-index: 9999999; + &.xsm{ + width: 200px; } - .modal-body { - background-color: #fff; - padding: 22px; - border-radius: 4px; - border: 1px solid #101010; - color: $alert-color; - .alert-title { + &.xxxm{ + width: 240px; + } + &.xxm{ + width: 270px; + } + &.xm{ + width: 300px; + } + &.ssm{ + width: 380px; + } + &.sm{ + width: 580px; + } + &.r{ + width: 400px; + } + &.lr{ + width: 440px; + } + &.lrr{ + width: 480px; + } + &.ml{ + width: 530px; + } + &.l-2{ + width: 640px; + } + &.lx-2{ + width: 740px; + } + &.lx{ + width: 770px; + } + &.l{ + width: 800px; + } + &.mount{ + animation: mountpop .17s ease-in-out forwards; + } + &.unmount{ + animation: unmountpop .17s ease-in-out forwards; + } + &.alert{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + background-color: transparent; + border: none; + .modal-head{ + background-color: transparent; + padding: 0 0 8px; + .modal-close{ + width: 20px; + height: 20px; + background: url(../../public/static/images/canvas/alert_close.svg)no-repeat center; + } + } + .modal-body{ + background-color: #fff; + padding: 22px; + border-radius: 4px; + border: 1px solid #101010; + color: $alert-color; + .alert-title{ + font-size: 13px; + font-weight: 700; + color: $alert-color; + margin-bottom: 15px; + } + } + } +} +.modal-head{ + display: flex; + align-items: center; + padding: 10px 24px; + background-color: #000; + // overflow: hidden; + h1.title{ font-size: 13px; + color: $pop-color; font-weight: 700; - color: $alert-color; + } + .modal-close{ + margin-left: auto; + color: transparent; + font-size: 0; + width: 10px; + height: 10px; + background: url(../../public/static/images/canvas/modal_close.svg)no-repeat center; + } +} +.modal-body{ + padding: 24px; + .modal-btn-wrap{ + display: flex; + align-items: center; + gap: 5px; + button{ + flex: 1; + } + &.sub{ + button{ + flex: 1 1 auto; + padding: 0; + } + margin-bottom: 14px; + } + } + .modal-check-btn-wrap{ + margin-top: 15px; + .check-wrap-title{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: 600; + &.light{ + font-weight: $pop-normal-weight; + } + } + .flex-check-box{ + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 15px; + &.for2{ + justify-content: flex-end; + button{ + width: calc(50% - 5px); + } + &.btn{ + gap: 5px; + button{ + width: calc(50% - 2.5px); + } + } + } + &.for-line{ + button{ + flex: 1; + } + } + } + } + .outer-line-wrap{ + border-top: 1px solid #3C3C3C; + margin-top: 10px; + padding-top: 15px; margin-bottom: 15px; - } + > div{ + margin-bottom: 15px; + &:last-child{ + margin-bottom: 0; + } + } } - } -} -.modal-head { - display: flex; - align-items: center; - padding: 10px 24px; - background-color: #000; - // overflow: hidden; - h1.title { - font-size: 13px; - color: $pop-color; - font-weight: 700; - } - .modal-close { - margin-left: auto; - color: transparent; - font-size: 0; - width: 10px; - height: 10px; - background: url(../../public/static/images/canvas/modal_close.svg) no-repeat center; - } -} -.modal-body { - padding: 24px; - .modal-btn-wrap { - display: flex; - align-items: center; - gap: 5px; - button { - flex: 1; - } - &.sub { - button { - flex: 1 1 auto; - padding: 0; - } - margin-bottom: 14px; - } - } - .modal-check-btn-wrap { - margin-top: 15px; - .check-wrap-title { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: 600; - &.light { + .modal-guide{ + display: block; + font-size: $pop-normal-size; + color: $alert-color; font-weight: $pop-normal-weight; - } } - .flex-check-box { - display: flex; - flex-wrap: wrap; - gap: 10px; - margin-top: 15px; - &.for2 { - justify-content: flex-end; - button { - width: calc(50% - 5px); - } - &.btn { - gap: 5px; - button { - width: calc(50% - 2.5px); - } - } - } - &.for-line { - button { - flex: 1; - } - } - } - } - .outer-line-wrap { - border-top: 1px solid #3c3c3c; - margin-top: 10px; - padding-top: 15px; - margin-bottom: 15px; - > div { - margin-bottom: 15px; - &:last-child { - margin-bottom: 0; - } - } - } - .modal-guide { - display: block; - font-size: $pop-normal-size; - color: $alert-color; - font-weight: $pop-normal-weight; - } } -.adsorption-point { - display: flex; - align-items: center; - background-color: #3a3a3a; - border-radius: 3px; - padding-left: 11px; - overflow: hidden; - transition: all 0.17s ease-in-out; - span { - font-size: $pop-normal-size; - color: #898989; - } - i { +.adsorption-point{ display: flex; align-items: center; - padding: 0 7px; - margin-left: auto; - height: 100%; - font-size: 13px; - color: #898989; - } - &.act { - i { - color: $pop-color; - background-color: #1083e3; + background-color: #3A3A3A; + border-radius: 3px; + padding-left: 11px; + overflow: hidden; + transition: all 0.17s ease-in-out; + span{ + font-size: $pop-normal-size; + color: #898989; + } + i{ + display: flex; + align-items: center; + padding: 0 7px; + margin-left: auto; + height: 100%; + font-size: 13px; + color: #898989; + } + &.act{ + i{ + color: $pop-color; + background-color: #1083E3; + } } - } } // grid-option -.grid-check-form { - display: flex; - align-items: center; - gap: 15px; - padding-bottom: 15px; - &.border { - border-bottom: 1px solid #424242; - } -} -.grid-option-wrap { - .grid-option-box { +.grid-check-form{ display: flex; align-items: center; - background-color: transparent; - border: 1px solid #3d3d3d; - border-radius: 2px; - padding: 15px 10px; - gap: 20px; - margin-bottom: 10px; - .grid-input-form { - display: flex; - align-items: center; - span { - flex: none; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } - .input-grid { - width: 54px; - input { - width: 100%; + gap: 15px; + padding-bottom: 15px; + &.border{ + border-bottom: 1px solid #424242; + } +} +.grid-option-wrap{ + .grid-option-box{ + display: flex; + align-items: center; + background-color: transparent; + border: 1px solid #3D3D3D; + border-radius: 2px; + padding: 15px 10px; + gap: 20px; + margin-bottom: 10px; + .grid-input-form{ + display: flex; + align-items: center; + span{ + flex: none; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + } + .input-grid{ + width: 54px; + input{ + width: 100%; + } + } + } + &:last-child{ + margin-bottom: 0; } - } } - &:last-child { - margin-bottom: 0; - } - } } -.select-form { - .sort-select { - width: 100%; - } +.select-form{ + .sort-select{width: 100%;} } -.grid-select { - flex: 1; - &.no-flx { - flex: unset; - } - .sort-select { - width: 100%; - background-color: #313131; - min-width: auto; - font-size: 12px; - border: none; - p { - font-size: 12px; +.grid-select{ + flex: 1; + &.no-flx{ + flex: unset; } - > ul { - border: none; + .sort-select{ + width: 100%; + background-color: #313131; + min-width: auto; + font-size: 12px; + border: none; + p{ + font-size: 12px; + } + > ul{ + border: none; + } } - } - &.right { - p { - text-align: right; + &.right{ + p{ + text-align: right; + } + ul{ + li{ + justify-content: flex-end; + } + } } - ul { - li { - justify-content: flex-end; - } - } - } } -.grid-btn-wrap { - padding-top: 15px; - text-align: right; - button { - padding: 0 10px; - } +.grid-btn-wrap{ + padding-top: 15px; + text-align: right; + button{ + padding: 0 10px; + } } // grid copy -.grid-option-tit { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - padding-bottom: 15px; -} -.grid-direction { - display: flex; - align-items: center; - gap: 5px; - flex: 1; -} -.direction { - width: 22px; - height: 22px; - background-color: #757575; - background-image: url(../../public/static/images/canvas/grid_option_arr.svg); - background-repeat: no-repeat; - background-position: center; - background-size: 16px 15px; - border-radius: 50%; - transition: all 0.15s ease-in-out; - opacity: 0.6; - &.down { - transform: rotate(180deg); - } - &.left { - transform: rotate(-90deg); - } - &.right { - transform: rotate(90deg); - } - &:hover, - &.act { - opacity: 1; - } -} - -// grid-move -.move-form { - p { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - } -} -.input-move-wrap { - display: flex; - align-items: center; - gap: 5px; - span { - color: $pop-color; - font-size: $pop-normal-size; - } - .input-move { - width: 130px; - input { - width: 100%; - } - } -} -.direction-move-wrap { - flex: none; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; -} - -// 배치면 초기 설정 -.placement-table { - table { - table-layout: fixed; - tr { - th { - display: flex; - align-items: center; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - padding: 18px 0; - border-bottom: 1px solid #424242; - } - td { - font-size: $pop-normal-size; - color: $pop-color; - border-bottom: 1px solid #424242; - padding-left: 20px; - } - &:first-child { - td, - th { - padding-top: 0; - } - } - } - } - .tooltip { - position: relative; - display: block; - width: 15px; - height: 15px; - margin-left: 5px; - background: url(../../public/static/images/canvas/pop_tip.svg) no-repeat center; - background-size: cover; - } - &.light { - padding: 0; - th, - td { - color: $alert-color; - border-bottom: none; - border-top: 1px solid #efefef; - } - th { - padding: 14px 0; - } - tr { - &:first-child { - td, - th { - padding-top: 14px; - } - } - &:last-child { - td, - th { - padding-bottom: 0px; - } - } - } - } -} - -.pop-form-radio { - display: flex; - align-items: center; - gap: 10px; -} -.placement-option { - display: flex; - align-items: center; - gap: 20px; -} -.select-wrap { - .sort-select { - width: 100%; - } -} -.flex-ment { - display: flex; - align-items: center; - gap: 5px; - span { +.grid-option-tit{ font-size: $pop-normal-size; color: $pop-color; font-weight: $pop-normal-weight; - } + padding-bottom: 15px; + +} +.grid-direction{ + display: flex; + align-items: center; + gap: 5px; + flex: 1; +} +.direction{ + width: 22px; + height: 22px; + background-color: #757575; + background-image: url(../../public/static/images/canvas/grid_option_arr.svg); + background-repeat: no-repeat; + background-position: center; + background-size: 16px 15px; + border-radius: 50%; + transition: all .15s ease-in-out; + opacity: 0.6; + &.down{transform: rotate(180deg);} + &.left{transform: rotate(-90deg);} + &.right{transform: rotate(90deg);} + &:hover, + &.act{ + opacity: 1; + } +} + +// grid-move +.move-form{ + p{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + } +} +.input-move-wrap{ + display: flex; + align-items: center; + gap: 5px; + span{ + color: $pop-color; + font-size: $pop-normal-size; + } + .input-move{ + width: 130px; + input{ + width: 100%; + } + } +} +.direction-move-wrap{ + flex: none; + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + +// 배치면 초기 설정 +.placement-table{ + table{ + table-layout: fixed; + tr{ + th{ + display: flex; + align-items: center; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + padding: 18px 0; + border-bottom: 1px solid #424242; + } + td{ + font-size: $pop-normal-size; + color: $pop-color; + border-bottom: 1px solid #424242; + padding-left: 20px; + } + &:first-child{ + td, + th{ + padding-top: 0; + } + } + } + } + .tooltip{ + position: relative; + display: block; + width: 15px; + height: 15px; + margin-left: 5px; + background: url(../../public/static/images/canvas/pop_tip.svg)no-repeat center; + background-size: cover; + } + &.light{ + padding: 0; + th,td{ + color: $alert-color; + border-bottom: none; + border-top: 1px solid #EFEFEF; + } + th{ + padding: 14px 0; + } + tr{ + &:first-child{ + td, + th{ + padding-top: 14px; + } + } + &:last-child{ + td, + th{ + padding-bottom: 0px; + } + } + } + } +} + +.pop-form-radio{ + display: flex; + align-items: center; + gap: 10px; +} +.placement-option{ + display: flex; + align-items: center; + gap: 20px; +} +.select-wrap{ + .sort-select{ + width: 100%; + } +} +.flex-ment{ + display: flex; + align-items: center; + gap: 5px; + span{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + } } // 외벽선 그리기 -.outline-wrap { - padding: 24px 0; - border-top: 1px solid #424242; - - .outline-inner { +.outline-wrap{ + padding: 24px 0; + border-top: 1px solid #424242; + + .outline-inner{ + display: flex; + align-items: center; + margin-bottom: 14px; + &:last-child{ + margin-bottom: 0; + } + .outline-form{ + // width: 50%; + margin-right: 15px; + } + } + &:last-child{ + border-bottom: 1px solid #424242; + } +} +.outline-form{ display: flex; align-items: center; - margin-bottom: 14px; - &:last-child { - margin-bottom: 0; + + span{ + width: 60px; + flex: none; + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-right: 10px; + &.thin{ + width: auto; + font-weight: $pop-normal-weight; + margin-right: 0; + } } - .outline-form { - // width: 50%; - margin-right: 15px; - } - } - &:last-child { - border-bottom: 1px solid #424242; - } -} -.outline-form { - display: flex; - align-items: center; - span { - width: 60px; - flex: none; - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-right: 10px; - &.thin { - width: auto; - font-weight: $pop-normal-weight; - margin-right: 0; + .reset-btn{ + flex: none; + width: 30px; + height: 30px; + background: transparent; + border: 1px solid #484848; + border-radius: 2px; + margin-left: 5px; + background-image: url(../../public/static/images/canvas/reset_ico.svg); + background-repeat: no-repeat; + background-size: 12px 12px; + background-position: center; + } + &:last-child{ + margin-right: 0; } - } - - .reset-btn { - flex: none; - width: 30px; - height: 30px; - background: transparent; - border: 1px solid #484848; - border-radius: 2px; - margin-left: 5px; - background-image: url(../../public/static/images/canvas/reset_ico.svg); - background-repeat: no-repeat; - background-size: 12px 12px; - background-position: center; - } - &:last-child { - margin-right: 0; - } } -.cul-wrap { - display: flex; - .outline-box { - width: 50%; - margin-right: 15px; - .outline-form { - width: 100%; - margin-bottom: 14px; - margin-right: 0; - &:last-child { - margin-bottom: 0; - } - } - } - .cul-box { +.cul-wrap{ display: flex; - align-items: center; - justify-content: center; - width: 50%; - background-color: #3d3d3d; - border-radius: 2px; - } + .outline-box{ + width: 50%; + margin-right: 15px; + .outline-form{ + width: 100%; + margin-bottom: 14px; + margin-right: 0; + &:last-child{ + margin-bottom: 0; + } + } + } + .cul-box{ + display: flex; + align-items: center; + justify-content: center; + width: 50%; + background-color: #3D3D3D; + border-radius: 2px ; + } } // 외벽선 속성 설정 -.properties-guide { - font-size: $pop-normal-size; - color: #aaa; - font-weight: $pop-normal-weight; - margin-bottom: 14px; +.properties-guide{ + font-size: $pop-normal-size; + color: #AAA; + font-weight: $pop-normal-weight; + margin-bottom: 14px; } -.setting-tit { - font-size: 13px; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-bottom: 10px; +.setting-tit{ + font-size: 13px; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-bottom: 10px; } -.properties-setting-wrap { - &.outer { - margin-top: 24px; - } - .setting-btn-wrap { - display: flex; - align-items: center; - padding: 14px 0; - border-top: 1px solid #424242; - border-bottom: 1px solid #424242; - .setting-btn { - display: block; - width: 100%; - height: 40px; - font-size: 13px; - color: #fff; - font-weight: 700; - border-radius: 2px; - transition: all 0.15s ease-in-out; - &.green { - background-color: #305941; - border: 1px solid #45cd7d; - &:hover { - background-color: #3a6b4e; - } - } - &.blue { - background-color: #2e5360; - border: 1px solid #3fbae6; - &:hover { - background-color: #365f6e; - } - } +.properties-setting-wrap{ + &.outer{ + margin-top: 24px; + } + .setting-btn-wrap{ + display: flex; + align-items: center; + padding: 14px 0; + border-top: 1px solid #424242; + border-bottom: 1px solid #424242; + .setting-btn{ + display: block; + width: 100%; + height: 40px; + font-size: 13px; + color: #fff; + font-weight: 700; + border-radius: 2px; + transition: all .15s ease-in-out; + &.green{ + background-color: #305941; + border: 1px solid #45CD7D; + &:hover{ + background-color: #3a6b4e; + } + } + &.blue{ + background-color: #2E5360; + border: 1px solid #3FBAE6; + &:hover{ + background-color: #365f6e; + } + } + } } - } } // 지붕형상 설정 -.roof-shape-menu { - display: grid; - grid-template-columns: 1fr 1fr 1fr 1fr; - grid-template-rows: 1fr 1fr; - gap: 24px 10px; - margin-bottom: 24px; - .shape-box { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - padding: 13px; - background-color: #3d3d3d; - transition: background 0.15s ease-in-out; - img { - max-width: 100%; +.roof-shape-menu{ + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr; + grid-template-rows: 1fr 1fr; + gap: 24px 10px; + margin-bottom: 24px; + .shape-box{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding: 13px; + background-color: #3D3D3D; + transition: background .15s ease-in-out; + img{ + max-width: 100%; + } } - } - .shape-title { - font-size: $pop-normal-size; - font-weight: $pop-bold-weight; - color: $pop-color; - margin-top: 10px; - text-align: center; - transition: color 0.15s ease-in-out; - } - .shape-menu-box { - &.act, - &:hover { - .shape-box { - background-color: #008bff; - } - .shape-title { - color: #008bff; - } + .shape-title{ + font-size: $pop-normal-size; + font-weight: $pop-bold-weight; + color: $pop-color; + margin-top: 10px; + text-align: center; + transition: color .15s ease-in-out; + } + .shape-menu-box{ + &.act, + &:hover{ + .shape-box{background-color: #008BFF;} + .shape-title{color: #008BFF;} + } } - } } -.setting-box { - padding: 14px 0; - border-top: 1px solid #424242; - border-bottom: 1px solid #424242; +.setting-box{ + padding: 14px 0; + border-top: 1px solid #424242; + border-bottom: 1px solid #424242; } -.padding-form { - padding-left: 23px; +.padding-form{ + padding-left: 23px; } .discrimination-box{ padding: 16px 12px; @@ -674,1304 +652,1131 @@ $alert-color: #101010; border-radius: 2px; } -.modal-bottom-border-bx { - margin-top: 24px; - padding-bottom: 14px; - border-bottom: 1px solid #424242; +.modal-bottom-border-bx{ + margin-top: 24px; + padding-bottom: 14px; + border-bottom: 1px solid #424242; } // 처마∙케라바 변경 -.eaves-keraba-table { - display: table; - border-collapse: collapse; - .eaves-keraba-item { - display: table-row; - .eaves-keraba-th, - .eaves-keraba-td { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - display: table-cell; - vertical-align: middle; - padding-bottom: 14px; +.eaves-keraba-table{ + display: table; + border-collapse: collapse; + .eaves-keraba-item{ + display: table-row; + .eaves-keraba-th, + .eaves-keraba-td{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + display: table-cell; + vertical-align: middle; + padding-bottom: 14px; + } + .eaves-keraba-td{ + padding-left: 10px; + } + .eaves-keraba-ico{ + display: flex; + align-items: center; + justify-content: center; + padding: 5px; + background-color: #3D3D3D; + border: 1px solid #3D3D3D; + border-radius: 2px; + cursor: pointer; + &.act{ + border: 1px solid #ED0004; + } + } + &:last-child{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 0; + } + } } - .eaves-keraba-td { - padding-left: 10px; - } - .eaves-keraba-ico { - display: flex; - align-items: center; - justify-content: center; - padding: 5px; - background-color: #3d3d3d; - border: 1px solid #3d3d3d; - border-radius: 2px; - cursor: pointer; - &.act { - border: 1px solid #ed0004; - } - } - &:last-child { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 0; - } - } - } } -.guide { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - margin-bottom: 24px; - &.sm { - margin-bottom: 15px; - } - span { - display: block; - } +.guide{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-bottom: 24px; + &.sm{ + margin-bottom: 15px; + } + span{ + display: block; + } } // 지붕면 할당 -.allocation-select-wrap { - display: flex; - align-items: center; - padding-bottom: 14px; - border-bottom: 1px solid #424242; - margin-bottom: 14px; - span { - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-bold-weight; - margin-right: 10px; - } - .allocation-edit { +.allocation-select-wrap{ display: flex; align-items: center; - height: 30px; - padding: 0 10px; - margin-left: 5px; - font-size: $pop-normal-size; - color: $pop-color; - font-weight: $pop-normal-weight; - border: 1px solid #484848; - background-color: #323234; - i { - display: block; - width: 12px; - height: 12px; - margin-right: 5px; - background: url(../../public/static/images/canvas/allocation_edit.svg) no-repeat center; - background-size: cover; + padding-bottom: 14px; + border-bottom: 1px solid #424242; + margin-bottom: 14px; + span{ + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-bold-weight; + margin-right: 10px; } - } -} - -.block-box { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 10px; - .flex-ment { - gap: 10px; - .dec { - text-decoration: underline; - } - .delete { - display: block; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/allocation_delete.svg) no-repeat center; - background-size: cover; - } - } - &:last-child { - margin-bottom: 0; - } -} - -.icon-btn-wrap { - flex: 1; - display: flex; - align-items: center; - gap: 5px; - button { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 30px; - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - border: 1px solid #646464; - border-radius: 2px; - padding: 0 10px; - transition: all 0.15s ease-in-out; - i { - height: 15px; - display: block; - margin-left: 10px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - transition: all 0.15s ease-in-out; - &.allocation01 { - background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); - width: 15px; - } - &.allocation02 { - background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); - width: 18px; - } - } - &.act, - &:hover { - color: #101010; - border: 1px solid #101010; - background-color: #fff; - i { - &.allocation01 { - background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); - } - &.allocation02 { - background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); - } - } - } - } -} - -// 경사설정 -.slope-wrap { - padding-bottom: 24px; - border-bottom: 1px solid #424242; -} - -// 면형상 배치 -.plane-shape-menu { - display: grid; - grid-template-columns: repeat(6, 1fr); - grid-template-rows: repeat(3, 90px); - gap: 10px; - margin-bottom: 10px; - .shape-menu-box { - border-radius: 2px; - background-color: #3d3d3d; - padding: 8px; - transition: all 0.15s ease-in-out; - .shape-box { - display: flex; - justify-content: center; - align-items: center; - position: relative; - width: 100%; - height: 100%; - background-color: #313131; - border-radius: 2px; - } - &.act, - &:hover { - background-color: #008bff; - } - } -} - -.shape-library { - display: flex; - align-items: center; - justify-content: center; - gap: 5px; - padding: 5px; - background-color: #3d3d3d; - margin-bottom: 24px; - .library-btn { - width: 30px; - height: 30px; - border: 1px solid #6c6c6c; - border-radius: 2px; - background-color: transparent; - background-repeat: no-repeat; - background-position: center; - transition: all 0.15s ease-in-out; - &.ico01 { - background-image: url(../../public/static/images/canvas/shape_labrary01.svg); - background-size: 14px 14px; - } - &.ico02 { - background-image: url(../../public/static/images/canvas/shape_labrary02.svg); - background-size: 13px 17px; - } - &.ico03 { - background-image: url(../../public/static/images/canvas/shape_labrary03.svg); - background-size: 17px 13px; - } - &:hover { - border-color: #1083e3; - background-color: #1083e3; - } - } -} - -.plane-shape-wrapper { - display: flex; - gap: 10px; - .plane-box { - padding: 10px; - border-radius: 2px; - background-color: #3d3d3d; - .plane-box-tit { - font-size: $pop-normal-size; - font-weight: 600; - color: $pop-color; - margin-bottom: 10px; - } - &.shape-box { - flex: 1; - .shape-box-inner { + .allocation-edit{ display: flex; - gap: 10px; - min-height: 140px; - .shape-img { - position: relative; - flex: 1; - background-color: #fff; - border-radius: 2px; - img { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - } + align-items: center; + height: 30px; + padding: 0 10px; + margin-left: 5px; + font-size: $pop-normal-size; + color: $pop-color; + font-weight: $pop-normal-weight; + border: 1px solid #484848; + background-color: #323234; + i{ + display: block; + width: 12px; + height: 12px; + margin-right: 5px; + background: url(../../public/static/images/canvas/allocation_edit.svg)no-repeat center; + background-size: cover; } - .shape-data { - flex: none; - width: 190px; - background-color: #313131; - border-radius: 2px; - padding: 15px; - .eaves-keraba-table { - .eaves-keraba-item { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 10px; - } - &:last-child { - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 0px; - } - } - } - } - } - } } - &.direction-box { - display: flex; - flex-direction: column; - flex: none; - width: 180px; - .plane-direction-box { - flex: 1; +} + +.block-box{ + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 10px; + .flex-ment{ + gap: 10px; + .dec{ + text-decoration: underline; + } + .delete{ + display: block; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/allocation_delete.svg)no-repeat center; + background-size: cover; + } + } + &:last-child{ + margin-bottom: 0; + } +} + +.icon-btn-wrap{ + flex: 1; + display: flex; + align-items: center; + gap: 5px; + button{ display: flex; align-items: center; justify-content: center; width: 100%; - padding: 10px 5px; - } + height: 30px; + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + border: 1px solid #646464; + border-radius: 2px; + padding: 0 10px; + transition: all .15s ease-in-out; + i{ + height: 15px; + display: block; + margin-left: 10px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + transition: all .15s ease-in-out; + &.allocation01{ + background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); + width: 15px; + } + &.allocation02{ + background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); + width: 18px; + } + } + &.act, + &:hover{ + color: #101010; + border: 1px solid #101010; + background-color: #fff; + i{ + &.allocation01{ + background-image: url(../../public/static/images/canvas/allocation_icon01_black.svg); + } + &.allocation02{ + background-image: url(../../public/static/images/canvas/allocation_icon02_black.svg); + } + } + } } - } -} -.plane-direction { - width: 150px; - position: relative; - height: 120px; - span { - position: absolute; - font-size: 12px; - font-weight: 500; - color: #b1b1b1; - &.top { - top: 0; - left: 50%; - transform: translateX(-50%); - } - &.right { - top: 50%; - right: 0; - transform: translateY(-50%); - } - &.bottom { - bottom: 0; - left: 50%; - transform: translateX(-50%); - } - &.left { - top: 50%; - left: 0; - transform: translateY(-50%); - } - } - .plane-btn { - position: absolute; - width: 28px; - height: 28px; - background-color: #777777; - background-image: url(../../public/static/images/canvas/plane_arr.svg); - background-size: 12px 13px; - background-repeat: no-repeat; - background-position: center; - border-radius: 50%; - transition: all 0.15s ease-in-out; - &.up { - top: 22px; - left: 50%; - transform: translateX(-50%); - } - &.right { - top: 50%; - right: 32px; - transform: translateY(-50%) rotate(90deg); - } - &.down { - bottom: 22px; - left: 50%; - transform: translateX(-50%) rotate(180deg); - } - &.left { - top: 50%; - left: 32px; - transform: translateY(-50%) rotate(270deg); - } - &:hover, - &.act { - background-color: #fff; - background-image: url(../../public/static/images/canvas/plane_arr_act.svg); - } - } } -.plane-tab-guide { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: $pop-color; - margin-top: 24px; - padding-bottom: 14px; - border-bottom: 1px solid #424242; +// 경사설정 +.slope-wrap{ + padding-bottom: 24px; + border-bottom: 1px solid #424242; +} + +// 면형상 배치 +.plane-shape-menu{ + display: grid; + grid-template-columns: repeat(6, 1fr); + grid-template-rows: repeat(3, 90px); + gap: 10px; + margin-bottom: 10px; + .shape-menu-box{ + border-radius: 2px; + background-color: #3D3D3D; + padding: 8px; + transition: all .15s ease-in-out; + .shape-box{ + display: flex; + justify-content: center; + align-items: center; + position: relative; + width: 100%; + height: 100%; + background-color: #313131; + border-radius: 2px; + } + &.act, + &:hover{ + background-color: #008BFF; + } + } +} + +.shape-library{ + display: flex; + align-items: center; + justify-content: center; + gap: 5px; + padding: 5px; + background-color: #3D3D3D; + margin-bottom: 24px; + .library-btn{ + width: 30px; + height: 30px; + border: 1px solid #6C6C6C; + border-radius: 2px; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + transition: all .15s ease-in-out; + &.ico01{background-image: url(../../public/static/images/canvas/shape_labrary01.svg); background-size: 14px 14px;} + &.ico02{background-image: url(../../public/static/images/canvas/shape_labrary02.svg); background-size: 13px 17px;} + &.ico03{background-image: url(../../public/static/images/canvas/shape_labrary03.svg); background-size: 17px 13px;} + &:hover{ + border-color: #1083E3; + background-color: #1083E3; + } + } +} + +.plane-shape-wrapper{ + display: flex; + gap: 10px; + .plane-box{ + padding: 10px; + border-radius: 2px; + background-color: #3D3D3D; + .plane-box-tit{ + font-size: $pop-normal-size; + font-weight: 600; + color: $pop-color; + margin-bottom: 10px; + } + &.shape-box{ + flex: 1; + .shape-box-inner{ + display: flex; + gap:10px; + min-height: 140px; + .shape-img{ + position: relative; + flex: 1; + background-color: #fff; + border-radius: 2px; + img{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } + } + .shape-data{ + flex: none; + width: 190px; + background-color: #313131; + border-radius: 2px; + padding: 15px; + .eaves-keraba-table{ + .eaves-keraba-item{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 10px; + } + &:last-child{ + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 0px; + } + } + } + } + } + } + } + &.direction-box{ + display: flex; + flex-direction: column; + flex: none; + width: 180px; + .plane-direction-box{ + flex: 1; + display: flex; + align-items: center; + justify-content: center; + width: 100%; + padding: 10px 5px; + } + } + } +} +.plane-direction{ + width: 150px; + position: relative; + height: 120px; + span{ + position: absolute; + font-size: 12px; + font-weight: 500; + color: #B1B1B1; + &.top{top: 0; left: 50%; transform: translateX(-50%);} + &.right{top: 50%; right: 0; transform: translateY(-50%);} + &.bottom{bottom: 0; left: 50%; transform: translateX(-50%);} + &.left{top: 50%; left: 0; transform: translateY(-50%);} + } + .plane-btn{ + position: absolute; + width: 28px; + height: 28px; + background-color: #777777; + background-image: url(../../public/static/images/canvas/plane_arr.svg); + background-size: 12px 13px; + background-repeat: no-repeat; + background-position: center; + border-radius: 50%; + transition: all .15s ease-in-out; + &.up{top: 22px; left: 50%; transform: translateX(-50%);} + &.right{top: 50%; right: 32px; transform: translateY(-50%) rotate(90deg);} + &.down{bottom: 22px; left: 50%; transform: translateX(-50%) rotate(180deg);} + &.left{top: 50%; left: 32px; transform: translateY(-50%) rotate(270deg);} + &:hover, + &.act{ + background-color: #fff; + background-image: url(../../public/static/images/canvas/plane_arr_act.svg); + } + } +} + +.plane-tab-guide{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: $pop-color; + margin-top: 24px; + padding-bottom: 14px; + border-bottom: 1px solid #424242; } // 오브젝트 배치 -.mb-box { - margin-bottom: 24px; +.mb-box{ + margin-bottom: 24px; } -.object-direction-wrap { - display: flex; - align-items: center; - justify-content: center; +.object-direction-wrap{ + display: flex; + align-items: center; + justify-content: center; } -.discrimination-tit { - font-size: 13px; - color: #fff; - font-weight: 500; +.discrimination-tit{ + font-size: 13px; + color: #fff; + font-weight: 500; } -.object-size-wrap { - display: flex; - min-height: 206px; - gap: 24px; - margin-top: 14px; - .object-size-img { - position: relative; - flex: none; - width: 200px; - background-color: #fff; - img { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); +.object-size-wrap{ + display: flex; + min-height: 206px; + gap: 24px; + margin-top: 14px; + .object-size-img{ + position: relative; + flex: none; + width: 200px; + background-color: #fff; + img{ + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + } } - } } // 표시변경 .display-change-wrap{ margin: 24px 0; } -.warning { - font-size: $pop-normal-size; - font-weight: $pop-normal-weight; - color: #ffafaf; +.warning{ + font-size: $pop-normal-size; + font-weight: $pop-normal-weight; + color: #FFAFAF; } // 각 변 속성 변경 -.radio-grid-wrap { - display: grid; - grid-template-columns: repeat(3, 1fr); - gap: 24px 15px; +.radio-grid-wrap{ + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 24px 15px; } // 면 흐름 설정 -.drawing-flow-wrap { - display: flex; - gap: 10px; - .discrimination-box { - flex: 1; +.drawing-flow-wrap{ display: flex; - flex-direction: column; - .object-direction-wrap { - flex: 1; + gap: 10px; + .discrimination-box{ + flex: 1; + display: flex; + flex-direction: column; + .object-direction-wrap{ + flex: 1; + } } - } } -.compas-box { - display: flex; - align-items: center; - justify-content: center; +.compas-box{ + display: flex; + align-items: center; + justify-content: center; } .compas-box-inner { - position: relative; - width: 200px; - height: 200px; - border-radius: 50%; - - .circle { - position: absolute; - width: 12px; - height: 12px; - border: 1px solid #fff; + position: relative; + width: 200px; + height: 200px; border-radius: 50%; - top: 95%; - left: 50%; - transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ - cursor: pointer; - z-index: 3; - /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ - i { - position: absolute; - top: 12.5px; - left: 50%; - font-size: 11px; - color: #8b8b8b; - font-weight: 500; - -webkit-user-select: none; - -moz-user-select: none; - -ms-use-select: none; - user-select: none; + + .circle { + position: absolute; + width: 12px; + height: 12px; + border: 1px solid #fff; + border-radius: 50%; + top: 95%; + left: 50%; + transform-origin: 0 -90px; /* 중심에서 반지름 거리만큼 떨어져 위치 */ + cursor:pointer; + z-index: 3; + /* 0번을 180도 위치(아래)에, 13번을 0도 위치(위)에 배치 */ + i{ + position: absolute; + top: 12.5px; + left: 50%; + font-size: 11px; + color: #8B8B8B; + font-weight: 500; + -webkit-user-select: none; + -moz-user-select: none; + -ms-use-select: none; + user-select: none; + } + &:nth-child(1) { transform: rotate(180deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(180deg);}} + &:nth-child(2) { transform: rotate(195deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(165deg);}} + &:nth-child(3) { transform: rotate(210deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(150deg);}} + &:nth-child(4) { transform: rotate(225deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(135deg);}} + &:nth-child(5) { transform: rotate(240deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(120deg);}} + &:nth-child(6) { transform: rotate(255deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(105deg);}} + &:nth-child(7) { transform: rotate(270deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(90deg);}} + &:nth-child(8) { transform: rotate(285deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(75deg);}} + &:nth-child(9) { transform: rotate(300deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(60deg);}} + &:nth-child(10) { transform: rotate(315deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(45deg);}} + &:nth-child(11) { transform: rotate(330deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(30deg);}} + &:nth-child(12) { transform: rotate(345deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(15deg);}} + &:nth-child(13) { transform: rotate(0deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(0deg);}} + &:nth-child(14) { transform: rotate(15deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-15deg);}} + &:nth-child(15) { transform: rotate(30deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-30deg);}} + &:nth-child(16) { transform: rotate(45deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-45deg);}} + &:nth-child(17) { transform: rotate(60deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-60deg);}} + &:nth-child(18) { transform: rotate(75deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-75deg);}} + &:nth-child(19) { transform: rotate(90deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-90deg);}} + &:nth-child(20) { transform: rotate(105deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-105deg);}} + &:nth-child(21) { transform: rotate(120deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-120deg);}} + &:nth-child(22) { transform: rotate(135deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-135deg);}} + &:nth-child(23) { transform: rotate(150deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-150deg);}} + &:nth-child(24) { transform: rotate(165deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-165deg);}} + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 5px; + height: 5px; + background-color: #fff; + } + i{ + color: #fff; + } + } } - &:nth-child(1) { - transform: rotate(180deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(180deg); - } - } - &:nth-child(2) { - transform: rotate(195deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(165deg); - } - } - &:nth-child(3) { - transform: rotate(210deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(150deg); - } - } - &:nth-child(4) { - transform: rotate(225deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(135deg); - } - } - &:nth-child(5) { - transform: rotate(240deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(120deg); - } - } - &:nth-child(6) { - transform: rotate(255deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(105deg); - } - } - &:nth-child(7) { - transform: rotate(270deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(90deg); - } - } - &:nth-child(8) { - transform: rotate(285deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(75deg); - } - } - &:nth-child(9) { - transform: rotate(300deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(60deg); - } - } - &:nth-child(10) { - transform: rotate(315deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(45deg); - } - } - &:nth-child(11) { - transform: rotate(330deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(30deg); - } - } - &:nth-child(12) { - transform: rotate(345deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(15deg); - } - } - &:nth-child(13) { - transform: rotate(0deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(0deg); - } - } - &:nth-child(14) { - transform: rotate(15deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-15deg); - } - } - &:nth-child(15) { - transform: rotate(30deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-30deg); - } - } - &:nth-child(16) { - transform: rotate(45deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-45deg); - } - } - &:nth-child(17) { - transform: rotate(60deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-60deg); - } - } - &:nth-child(18) { - transform: rotate(75deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-75deg); - } - } - &:nth-child(19) { - transform: rotate(90deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-90deg); - } - } - &:nth-child(20) { - transform: rotate(105deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-105deg); - } - } - &:nth-child(21) { - transform: rotate(120deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-120deg); - } - } - &:nth-child(22) { - transform: rotate(135deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-135deg); - } - } - &:nth-child(23) { - transform: rotate(150deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-150deg); - } - } - &:nth-child(24) { - transform: rotate(165deg) translate(-50%, -50%); - i { - transform: translateX(-50%) rotate(-165deg); - } - } - &.act { - &::after { - content: ''; + .compas{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 5px; - height: 5px; - background-color: #fff; - } - i { - color: #fff; - } + width: 148px; + height: 148px; + border: 4px solid #fff; + border-radius: 50%; + .compas-arr{ + width: 100%; + height: 100%; + background: url(../../public/static/images/canvas/compas.svg)no-repeat center; + background-size: 122px 122px; + } } - } - .compas { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 148px; - height: 148px; - border: 4px solid #fff; - border-radius: 50%; - .compas-arr { - width: 100%; - height: 100%; - background: url(../../public/static/images/canvas/compas.svg) no-repeat center; - background-size: 122px 122px; - } - } } + // 지붕모듈선택 -.roof-module-tab { - display: flex; - align-items: center; - gap: 10px; - margin-bottom: 14px; - .module-tab-bx { +.roof-module-tab{ + display: flex; + align-items: center; + gap: 10px; + margin-bottom: 14px; + .module-tab-bx{ + flex: 1; + height: 34px; + line-height: 31px; + border: 1px solid #484848; + border-radius: 2px; + background-color: transparent; + font-size: 12px; + color: #AAA; + text-align: center; + cursor: default; + transition: all .15s ease-in-out; + &.act{ + background-color: #1083E3; + border: 1px solid #1083E3; + color: #fff; + font-weight: 500; + } + } + .tab-arr{ + display: block; + width: 9px; + height: 14px; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + background-image: url(../../public/static/images/canvas/module_tab_arr.svg); + transition: all .15s ease-in-out; + &.act{ + background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); + } + } +} + +.roof-module-compas{ + margin-bottom: 24px; + .compas-box-inner{ + width: 280px; + height: 253px; + .circle{ + top: 86%; + &:nth-child(1), + &:nth-child(7), + &:nth-child(13), + &:nth-child(19){ + &::before{ + content: ''; + position: absolute; + top: 20px; + left: 50%; + transform: translateX(-50%); + width: 1px; + height: 6px; + background-color: #8B8B8B; + } + } + i{ + top: 32px; + } + &.act{ + i{color: #8B8B8B;} + } + } + } +} +.center-wrap{ + display: flex; + flex-direction: column; + align-items: center; + gap: 20px; +} + +.module-table-flex-wrap{ + display: flex; + gap: 10px; + .outline-form{ + flex: 1; + } +} + +.module-box-tab{ + display: flex; + .module-btn{ + flex: 1; + border-top: 1px solid #505050; + border-bottom: 1px solid #505050; + border-right: 1px solid #505050; + background-color: #454545; + color: #fff; + height: 30px; + font-size: 12px; + font-weight: 400; + transition: all .15s ease-in-out; + &:first-child{ + border-left: 1px solid #505050; + } + &.act{ + border-color: #fff; + background-color: #fff; + color: #101010; + } + } +} + +.module-table-box{ flex: 1; - height: 34px; - line-height: 31px; - border: 1px solid #484848; + background-color: #3D3D3D; border-radius: 2px; - background-color: transparent; - font-size: 12px; - color: #aaa; - text-align: center; - cursor: default; - transition: all 0.15s ease-in-out; - &.act { - background-color: #1083e3; - border: 1px solid #1083e3; - color: #fff; - font-weight: 500; - } - } - .tab-arr { - display: block; - width: 9px; - height: 14px; - background-repeat: no-repeat; - background-position: center; - background-size: cover; - background-image: url(../../public/static/images/canvas/module_tab_arr.svg); - transition: all 0.15s ease-in-out; - &.act { - background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); - } - } -} - -.roof-module-compas { - margin-bottom: 24px; - .compas-box-inner { - width: 280px; - height: 253px; - .circle { - top: 86%; - &:nth-child(1), - &:nth-child(7), - &:nth-child(13), - &:nth-child(19) { - &::before { - content: ''; - position: absolute; - top: 20px; - left: 50%; - transform: translateX(-50%); - width: 1px; - height: 6px; - background-color: #8b8b8b; + .module-table-inner{ + padding: 10px; + .outline-form{ + span{ + width: auto; + } } - } - i { - top: 32px; - } - &.act { - i { - color: #8b8b8b; + .module-table-tit{ + padding: 10px 0; + font-size: 12px; + color: #fff; + border-bottom: 1px solid #4D4D4D; + } + .eaves-keraba-table{ + width: 100%; + margin-top: 15px; + .eaves-keraba-th{ + width: 72px; + } + .eaves-keraba-th, + .eaves-keraba-td{ + padding-bottom: 5px; + } + } + .self-table-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + padding-bottom: 15px; + } + } + .warning-guide{ + padding: 20px; + .warning{ + color: #FFCACA; + max-height: 55px; + overflow-y: auto; + padding-right: 30px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } } - } } - } -} -.center-wrap { - display: flex; - flex-direction: column; - align-items: center; - gap: 20px; } -.module-table-flex-wrap { - display: flex; - gap: 10px; - .outline-form { - flex: 1; - } +.module-self-table{ + display: table; + border-top: 1px solid #4D4D4D; + border-collapse: collapse; + width: 100%; + .self-table-item{ + display: table-row; + .self-item-td, + .self-item-th{ + display: table-cell; + vertical-align: middle; + border-bottom: 1px solid #4D4D4D; + } + .self-item-th{ + width: 60px; + font-size: 12px; + font-weight: 500; + color: #fff; + } + .self-item-td{ + font-size: 12px; + font-weight: 400; + color: #fff; + padding: 15px 20px; + } + } } -.module-box-tab { - display: flex; - .module-btn { - flex: 1; - border-top: 1px solid #505050; - border-bottom: 1px solid #505050; - border-right: 1px solid #505050; - background-color: #454545; - color: #fff; - height: 30px; - font-size: 12px; - font-weight: 400; - transition: all 0.15s ease-in-out; - &:first-child { - border-left: 1px solid #505050; - } - &.act { - border-color: #fff; - background-color: #fff; - color: #101010; - } - } -} - -.module-table-box { - flex: 1; - background-color: #3d3d3d; - border-radius: 2px; - .module-table-inner { - padding: 10px; - .outline-form { - span { - width: auto; - } - } - .module-table-tit { - padding: 10px 0; - font-size: 12px; - color: #fff; - border-bottom: 1px solid #4d4d4d; - } - .eaves-keraba-table { - width: 100%; - margin-top: 15px; - .eaves-keraba-th { - width: 72px; - } - .eaves-keraba-th, - .eaves-keraba-td { - padding-bottom: 5px; - } - } - .self-table-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - padding-bottom: 15px; - } - } - .warning-guide { - padding: 20px; - .warning { - color: #ffcaca; - max-height: 55px; - overflow-y: auto; - padding-right: 30px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } - } - } -} - -.module-self-table { - display: table; - border-top: 1px solid #4d4d4d; - border-collapse: collapse; - width: 100%; - .self-table-item { - display: table-row; - .self-item-td, - .self-item-th { - display: table-cell; - vertical-align: middle; - border-bottom: 1px solid #4d4d4d; - } - .self-item-th { - width: 60px; - font-size: 12px; - font-weight: 500; - color: #fff; - } - .self-item-td { - font-size: 12px; - font-weight: 400; - color: #fff; - padding: 15px 20px; - } - } -} - -.self-table-flx { - display: flex; - align-items: center; - margin-top: 15px; - button { - margin-left: auto; - } -} -.hexagonal-wrap { - .hexagonal-item { - padding: 15px 0; - border-bottom: 1px solid #4d4d4d; - &:first-child { - padding-top: 0; - } - &:last-child { - padding-bottom: 0; - border: none; - } - .hexagonal-flx-auto { - display: flex; - justify-content: space-between; - } - .hexagonal-flx { - display: flex; - align-items: center; - button { +.self-table-flx{ + display: flex; + align-items: center; + margin-top: 15px; + button{ margin-left: auto; - } } - } +} +.hexagonal-wrap{ + .hexagonal-item{ + padding: 15px 0; + border-bottom: 1px solid #4D4D4D; + &:first-child{ + padding-top: 0; + } + &:last-child{ + padding-bottom: 0; + border: none; + } + .hexagonal-flx-auto{ + display: flex; + justify-content: space-between; + } + .hexagonal-flx{ + display: flex; + align-items: center; + button{ + margin-left: auto; + } + } + } } // 회로 및 가대설정 -.circuit-check-inner { - padding: 5px 0; +.circuit-check-inner{ + padding: 5px 0; } -.x-scroll-table { - overflow-x: auto; - padding-bottom: 5px; - .roof-module-table { - min-width: 1200px; - } - &::-webkit-scrollbar { - height: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } -} - -.circuit-right-wrap { - display: flex; - justify-content: flex-end; -} - -.circuit-data-form { - display: flex; - flex-direction: column; - gap: 5px; - min-height: 60px; - padding: 12px; - border: 1px solid rgba(255, 255, 255, 0.2); - span { - display: inline-flex; - align-items: center; - .del { - display: block; - margin-left: 10px; - width: 15px; - height: 15px; - background: url(../../public/static/images/canvas/circuit_del.svg) no-repeat center; - background-size: cover; +.x-scroll-table{ + overflow-x: auto; + padding-bottom: 5px; + .roof-module-table{ + min-width: 1200px; + } + &::-webkit-scrollbar { + height: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; } - } -} -.circuit-table-tit { - color: #fff; - font-size: 12px; - font-weight: 600; - padding: 11px 10px; - background-color: #474747; - border: 1px solid #505050; - border-bottom: none; } -.circuit-overflow { - max-height: 400px; - overflow-y: auto; - margin-bottom: 15px; - &::-webkit-scrollbar { - width: 4px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #d9d9d9; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } +.circuit-right-wrap{ + display: flex; + justify-content: flex-end; } -.circuit-table-flx-wrap { - display: flex; - gap: 10px; - margin-bottom: 10px; - .circuit-table-flx-box { - flex: 1; +.circuit-data-form{ display: flex; flex-direction: column; - .bottom-wrap { - margin-top: auto; + gap: 5px; + min-height: 60px; + padding: 12px; + border: 1px solid rgba(255, 255, 255, 0.20); + span{ + display: inline-flex; + align-items: center; + .del{ + display: block; + margin-left: 10px; + width: 15px; + height: 15px; + background: url(../../public/static/images/canvas/circuit_del.svg)no-repeat center; + background-size: cover; + } } - .roof-module-table { - table { - table-layout: fixed; - } - } - } +} +.circuit-table-tit{ + color: #fff; + font-size: 12px; + font-weight: 600; + padding: 11px 10px; + background-color: #474747; + border: 1px solid #505050; + border-bottom: none; } -.circuit-count-input { - display: flex; - align-items: center; - gap: 10px; +.circuit-overflow{ + max-height: 400px; + overflow-y: auto; + margin-bottom: 15px; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #D9D9D9; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } +} + +.circuit-table-flx-wrap{ + display: flex; + gap: 10px; + margin-bottom: 10px; + .circuit-table-flx-box{ + flex: 1; + display: flex; + flex-direction: column; + .bottom-wrap{ + margin-top: auto; + } + .roof-module-table{ + table{ + table-layout: fixed; + } + } + } +} + +.circuit-count-input{ + display: flex; + align-items: center; + gap: 10px; } // 모듈부가기능 -.additional-radio-wrap { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 0; - margin-bottom: 24px; +.additional-radio-wrap{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 0; + margin-bottom: 24px; } -.additional-wrap { - padding: 24px 0; - border-top: 1px solid #424242; +.additional-wrap{ + padding: 24px 0; + border-top: 1px solid #424242; } -.additional-color-wrap { - display: flex; - align-items: center; - padding: 5px 0; - gap: 15px; - .additional-color-box { +.additional-color-wrap{ display: flex; align-items: center; - gap: 8px; - .additional-color { - display: block; - width: 16px; - height: 16px; - &.pink { - border: 2px solid #ce1c9c; - background-color: #16417d; - } - &.white { - border: 2px solid #fff; - background-color: #001027; - } + padding: 5px 0; + gap: 15px; + .additional-color-box{ + display: flex; + align-items: center; + gap: 8px; + .additional-color{ + display: block; + width: 16px; + height: 16px; + &.pink{ + border: 2px solid #ce1c9c; + background-color: #16417D; + } + &.white{ + border: 2px solid #FFF; + background-color: #001027; + } + } } - } } // color setting -.color-setting-wrap { - padding-bottom: 15px; - border-bottom: 1px solid #424242; - .color-tit { - font-size: 13px; - font-weight: 500; - color: #ffffff; - margin-bottom: 10px; - } - .color-picker { - .react-colorful { - width: 100%; - height: auto; - gap: 20px; - .react-colorful__pointer { - width: 15px; - height: 15px; - border: 4px solid #fff; - } - .react-colorful__saturation { - border-radius: 2px; - height: 200px; - border-bottom: 5px solid #000; - } - .react-colorful__last-control { - border-radius: 2px; - height: 10px; - } - } - .hex-color-box { - display: flex; - align-items: center; - margin-top: 15px; - .color-box-tit { - font-size: 12px; - color: #fff; +.color-setting-wrap{ + padding-bottom: 15px; + border-bottom: 1px solid #424242; + .color-tit{ + font-size: 13px; font-weight: 500; - margin-right: 10px; - } - .color-hex-input { - width: 150px; - margin-right: 5px; - input { - width: 100%; - } - } - .color-box { - display: block; - width: 30px; - height: 30px; - border-radius: 4px; - } + color: #ffffff; + margin-bottom: 10px; } - .default-color-wrap { - margin-top: 25px; - .default-tit { + .color-picker{ + .react-colorful{ + width: 100%; + height: auto; + gap: 20px; + .react-colorful__pointer{ + width: 15px; + height: 15px; + border: 4px solid #Fff; + } + .react-colorful__saturation{ + border-radius: 2px; + height: 200px; + border-bottom: 5px solid #000; + } + .react-colorful__last-control{ + border-radius: 2px; + height: 10px; + } + } + .hex-color-box{ + display: flex; + align-items: center; + margin-top: 15px; + .color-box-tit{ + font-size: 12px; + color: #fff; + font-weight: 500; + margin-right: 10px; + } + .color-hex-input{ + width: 150px; + margin-right: 5px; + input{ + width: 100%; + } + } + .color-box{ + display: block; + width: 30px; + height: 30px; + border-radius: 4px; + } + } + .default-color-wrap{ + margin-top: 25px; + .default-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + .color-button-wrap{ + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 21px; + .default-color{ + display: block; + width: 100%; + height: 30px; + border-radius: 4px; + } + } + } + } +} + +// 글꼴 설정 팝업 +.font-option-warp{ + display: grid; + grid-template-columns: repeat(2, 1fr); + gap: 15px 5px; + margin-bottom: 15px; + .font-option-item{ + .option-item-tit{ + font-size: 12px; + font-weight: 500; + color: #fff; + margin-bottom: 10px; + } + } +} +.font-ex-wrap{ + margin-bottom: 15px; + .font-ex-tit{ font-size: 12px; font-weight: 500; color: #fff; margin-bottom: 10px; - } - .color-button-wrap { - display: grid; - grid-template-columns: repeat(8, 1fr); - gap: 21px; - .default-color { - display: block; - width: 100%; - height: 30px; - border-radius: 4px; - } - } } - } -} - -// 글꼴 설정 팝업 -.font-option-warp { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 15px 5px; - margin-bottom: 15px; - .font-option-item { - .option-item-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; + .font-ex-box{ + display: flex; + align-items: center; + justify-content: center; + width: 100%; + min-height: 80px; + background-color: #fff; } - } -} -.font-ex-wrap { - margin-bottom: 15px; - .font-ex-tit { - font-size: 12px; - font-weight: 500; - color: #fff; - margin-bottom: 10px; - } - .font-ex-box { - display: flex; - align-items: center; - justify-content: center; - width: 100%; - height: 80px; - background-color: #fff; - } + } // 치수선 설정 -.font-btn-wrap { - margin-bottom: 15px; - button { - width: 100%; - height: 30px; - line-height: 28px; - } +.font-btn-wrap{ + margin-bottom: 15px; + button{ + width: 100%; + height: 30px; + line-height: 28px; + } } -.line-color-wrap { - margin-bottom: 15px; - .color-btn { - display: block; - width: 100%; - height: 30px; - border-radius: 2px; - } -} - -.form-box { - width: 100%; - background-color: #fff; - padding: 10px 0 20px; - .line-form { - position: relative; - width: 102px; - height: 40px; - margin: 0 auto; - border-left: 1px dashed #101010; - border-right: 1px dashed #101010; - .line-font-box { - position: absolute; - bottom: -3px; - left: 0; - width: 100%; - text-align: center; - .font { - display: block; - padding-bottom: 6px; - color: #101010; - } - .line { - position: relative; +.line-color-wrap{ + margin-bottom: 15px; + .color-btn{ display: block; width: 100%; - height: 1px; - border-radius: 30px; - &::before { - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - left: 1px; - width: 9px; - height: 9px; - border: 1px solid; - border-color: inherit; - border-top: none; - border-right: none; - } - &::after { - content: ''; - position: absolute; - top: 50%; - transform: translateY(-50%) rotate(45deg); - right: 1px; - width: 9px; - height: 9px; - border: 1px solid; - border-color: inherit; - border-bottom: none; - border-left: none; - } - } + height: 30px; + border-radius: 2px; + } +} + +.form-box{ + width: 100%; + background-color: #fff; + padding: 10px 0 20px; + .line-form{ + position: relative; + width: 102px; + height: 40px; + margin: 0 auto; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + .line-font-box{ + position: absolute; + bottom: -3px; + left: 0; + width: 100%; + text-align: center; + .font{ + display: block; + padding-bottom: 6px; + color: #101010; + } + .line{ + position: relative; + display: block; + width: 100%; + height: 1px; + border-radius: 30px; + &::before{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + left: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-top: none; + border-right: none; + } + &::after{ + content: ''; + position: absolute; + top: 50%; + transform: translateY(-50%) rotate(45deg); + right: 1px; + width: 9px; + height: 9px; + border: 1px solid; + border-color: inherit; + border-bottom: none; + border-left: none; + } + } + } } - } } // 사이즈 변경 -.size-inner-warp { - position: relative; +.size-inner-warp{ + position: relative; } -.size-check-wrap { - position: relative; - display: block; - width: 132px; - height: 132px; - margin: 0 auto; - .size-btn { - position: absolute; - width: 16px; - height: 16px; - border: 1px solid #fff; - border-radius: 50%; - &.act { - &::after { - content: ''; +.size-check-wrap{ + position: relative; + display: block; + width: 132px; + height: 132px; + margin: 0 auto; + .size-btn{ + position: absolute; + width: 16px; + height: 16px; + border: 1px solid #fff; + border-radius: 50%; + &.act{ + &::after{ + content: ''; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: 8px; + height: 8px; + background-color: #fff; + border-radius: 50%; + } + } + &:nth-child(1){ top: 0; left: 0; } + &:nth-child(2){ top: 0; right: 0; } + &:nth-child(3){ bottom: 0; left: 0; } + &:nth-child(4){ bottom: 0; right: 0; } + } + .size-box{ position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); - width: 8px; - height: 8px; + width: 100px; + height: 100px; background-color: #fff; - border-radius: 50%; - } } - &:nth-child(1) { - top: 0; - left: 0; - } - &:nth-child(2) { - top: 0; - right: 0; - } - &:nth-child(3) { - bottom: 0; - left: 0; - } - &:nth-child(4) { - bottom: 0; - right: 0; - } - } - .size-box { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - width: 100px; - height: 100px; - background-color: #fff; - } } -.size-option-top { - margin-bottom: 15px; +.size-option-top{ + margin-bottom: 15px; } -.size-option-side { - position: absolute; - top: 50%; - left: 0; - transform: translateY(-50%); +.size-option-side{ + position: absolute; + top: 50%; + left: 0; + transform: translateY(-50%); } -.size-option-wrap { - width: 88px; - margin: 0 auto; - .size-option { - display: flex; - align-items: center; - input { - width: 100%; - flex: 1; +.size-option-wrap{ + width: 88px; + margin: 0 auto; + .size-option{ + display: flex; + align-items: center; + input{ + width: 100%; + flex: 1; + } + span{ + flex: none; + } } - span { - flex: none; - } - } -} +} \ No newline at end of file diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index ef4cee0d..d483c7b7 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -1,1027 +1,891 @@ * { - -webkit-text-size-adjust: none; - -moz-text-size-adjust: none; - -ms-text-size-adjust: none; - text-size-adjust: none; - box-sizing: content-box; + -webkit-text-size-adjust:none; + -moz-text-size-adjust:none; + -ms-text-size-adjust:none; + text-size-adjust: none; + box-sizing: content-box } -*, -::after, -::before { - box-sizing: border-box; +*, ::after, ::before { + box-sizing: border-box; } -html, -body { - width: 100%; - height: 100%; - font-size: 16px; +html, body{ + width: 100%; + height: 100%; + font-size: 16px; } -html, -body, -div, -span, -applet, -object, -iframe, -h1, -h2, -h3, -h4, -h5, -h6, -p, -blockquote, -pre, -a, -abbr, -acronym, -address, -big, -cite, -code, -del, -dfn, -em, -img, -ins, -kbd, -q, -s, -samp, -small, -strike, -strong, -sub, -sup, -tt, -var, -b, -u, -i, -center, -dl, -dt, -dd, -ol, -ul, -li, -fieldset, -form, -label, -legend, -table, -caption, -tbody, -tfoot, -thead, -tr, -th, -td, -article, -aside, -canvas, -details, -embed, -figure, -figcaption, -footer, -header, -hgroup, -menu, -nav, -output, -ruby, -section, -summary, -time, -mark, -audio, -video { - margin: 0; - padding: 0; - border: 0; - font: inherit; - vertical-align: baseline; - font-family: 'Noto Sans JP', sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - font-smooth: never; +html, body, div, span, applet, object, iframe, +h1, h2, h3, h4, h5, h6, p, blockquote, pre, +a, abbr, acronym, address, big, cite, code, +del, dfn, em, img, ins, kbd, q, s, samp, +small, strike, strong, sub, sup, tt, var, +b, u, i, center, +dl, dt, dd, ol, ul, li, +fieldset, form, label, legend, +table, caption, tbody, tfoot, thead, tr, th, td, +article, aside, canvas, details, embed, +figure, figcaption, footer, header, hgroup, +menu, nav, output, ruby, section, summary, +time, mark, audio, video { + margin: 0; + padding: 0; + border: 0; + font: inherit; + vertical-align: baseline; + font-family: 'Noto Sans JP', sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + font-smooth: never; } /* HTML5 display-role reset for older browsers */ -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -menu, -nav, -section { - display: block; +article, aside, details, figcaption, figure, +footer, header, hgroup, menu, nav, section { + display: block; } body { - line-height: 1.4; -} -body:first-of-type caption { - display: none; + line-height: 1.4; } +body:first-of-type caption { display:none;} -ol, -ul { - list-style: none; +ol, ul { + list-style: none; } -blockquote, -q { - quotes: none; +blockquote, q { + quotes: none; } -blockquote:before, -blockquote:after, -q:before, -q:after { - content: ''; - content: none; +blockquote:before, blockquote:after, +q:before, q:after { + content: ''; + content: none; } table { - width: 100%; - border-collapse: separate; - border-spacing: 0; - border: 0 none; + width: 100%; + border-collapse: separate; + border-spacing:0; + border:0 none; } -caption, -th, -td { - text-align: left; - font-weight: normal; - border: 0; +caption, th, td { + text-align:left; + font-weight: normal; + border:0; } -a { - cursor: pointer; - color: #000; +a { + cursor:pointer; + color:#000; } -a, -a:hover, -a:active { - text-decoration: none; - -webkit-tap-highlight-color: transparent; +a, a:hover, a:active { + text-decoration:none; + -webkit-tap-highlight-color: transparent; } /*form_style*/ -input, -select, -textarea, -button, -a, -label { - -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +input, select, textarea, button, a, label { + -webkit-tap-highlight-color:rgba(0,0,0,0); } -button, -input[type='text'], -input[type='button'] { - -webkit-appearance: none; - -webkit-border-radius: 0; - -webkit-appearance: none; - appearance: none; - border-radius: 0; +button,input[type=text], input[type=button] { + -webkit-appearance: none; + -webkit-border-radius: 0; + -webkit-appearance:none; + appearance: none; + border-radius: 0 } -input[type='checkbox'], -input[type='radio'] { - box-sizing: border-box; - padding: 0; +input[type=checkbox], input[type=radio] { + box-sizing: border-box; + padding: 0; } -input, -select, -button { - border: 0 none; - outline: none; - margin: 0; +input, select, button { + border:0 none; + outline:none; + margin:0; } select { - -webkit-appearance: none; - -moz-appearance: none; - appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; } select::-ms-expand { - display: none; + display: none; } ::-webkit-input-placeholder { - line-height: 1; - font-weight: 300; - font-size: 0.938rem; - letter-spacing: -0.6px; - color: #8b8b8b; + line-height:1; + font-weight:300; + font-size:0.938rem; + letter-spacing:-0.6px; + color:#8b8b8b; } -.log-box ::-webkit-input-placeholder { - color: #8b8b8b; +.log-box ::-webkit-input-placeholder{ + color:#8b8b8b; } -button { - background: transparent; - font-family: 'Noto Sans JP', sans-serif; - border: none; - padding: 0; - margin: 0; - line-height: 1.4; - color: inherit; - outline: none; - cursor: pointer; +button{ + background: transparent; + font-family: 'Noto Sans JP', sans-serif; + border: none; + padding: 0; + margin: 0; + line-height: 1.4; + color: inherit; + outline: none; + cursor: pointer; } -.pre { - font-family: 'Pretendard', sans-serif !important; +.pre{ + font-family: 'Pretendard', sans-serif !important; } // margin -.mt5 { - margin-top: 5px !important; -} -.mt10 { - margin-top: 10px !important; -} -.mt15 { - margin-top: 15px !important; -} -.mb5 { - margin-bottom: 5px !important; -} -.mb10 { - margin-bottom: 10px !important; -} -.mb15 { - margin-bottom: 15px !important; -} -.mr5 { - margin-right: 5px !important; -} -.mr10 { - margin-right: 10px !important; -} -.mr15 { - margin-right: 15px !important; -} -.ml5 { - margin-left: 5px !important; -} -.ml10 { - margin-left: 10px !important; -} -.ml15 { - margin-left: 15px !important; -} +.mt5{margin-top: 5px !important;} +.mt10{margin-top: 10px !important;} +.mt15{margin-top: 15px !important;} +.mb5{margin-bottom: 5px !important;} +.mb10{margin-bottom: 10px !important;} +.mb15{margin-bottom: 15px !important;} +.mr5{margin-right: 5px !important;} +.mr10{margin-right: 10px !important;} +.mr15{margin-right: 15px !important;} +.ml5{margin-left: 5px !important;} +.ml10{margin-left: 10px !important;} +.ml15{margin-left: 15px !important;} // align -.al-l { - text-align: left !important; -} -.al-r { - text-align: right !important; -} -.al-c { - text-align: center !important; -} +.al-l{text-align: left !important;} +.al-r{text-align: right !important;} +.al-c{text-align: center !important;} + // button -.btn-frame { - display: inline-block; - padding: 0 7px; - height: 34px; - line-height: 34px; - border-radius: 2px; - color: #fff; - font-size: 12px; - font-weight: 400; - border: 1px solid #000; - text-align: center; - font-family: 'Pretendard', sans-serif; - transition: all 0.17s ease-in-out; - cursor: pointer; - &.block { - width: 100%; - } - &.small { - font-family: 'Noto Sans JP', sans-serif; - height: 30px; - line-height: 30px; - font-size: 13px; - } +.btn-frame{ + display: inline-block; + padding: 0 7px; + height: 34px; + line-height: 34px; + border-radius: 2px; + color: #fff; + font-size: 12px; + font-weight: 400; + border: 1px solid #000; + text-align: center; + font-family: 'Pretendard', sans-serif; + transition: all .17s ease-in-out; + cursor: pointer; + &.block{ + width: 100%; + } + &.small{ + font-family: 'Noto Sans JP', sans-serif; + height: 30px; + line-height: 30px; + font-size: 13px; + } - &.deepgray { - background-color: #2c2c2c; - border: 1px solid #484848; - } - &.gray { - background-color: #3c3c3c; - border: 1px solid #545454; - } - &.dark { - background-color: #1c1c1c; - border: 1px solid #484848; - } - &.modal { - font-family: 'Noto Sans JP', sans-serif; - background-color: #272727; - border: 1px solid #484848; - color: #aaa; - &:hover { - background-color: #1083e3; - border: 1px solid #1083e3; - color: #fff; - font-weight: 500; + &.deepgray{ + background-color: #2C2C2C; + border: 1px solid #484848; } - } - &.sub-tab { - height: 30px; - padding: 0 10px; - line-height: 28px; - font-family: 'Noto Sans JP', sans-serif; - background-color: #2d2d2d; - border: 1px solid #393939; - color: #aaa; - &.act, - &:hover { - background-color: #414e6c; - border: 1px solid #414e6c; - color: #fff; - font-weight: 500; + &.gray{ + background-color: #3C3C3C; + border: 1px solid #545454; } - } - &.roof { - height: 30px; - padding: 0 10px; - line-height: 28px; - font-family: 'Noto Sans JP', sans-serif; - background-color: transparent; - border: 1px solid #484848; - color: #fff; - &.blue { - background-color: #414e6c; - border: 1px solid #414e6c; - &:hover { - background-color: #414e6c; - border: 1px solid #414e6c; - } + &.dark{ + background-color: #1C1C1C; + border: 1px solid #484848; } - &.white { - background-color: #fff; - border: 1px solid #fff; - color: #101010; - &:hover { - background-color: #fff; - border: 1px solid #fff; - color: #101010; - } + &.modal{ + font-family: 'Noto Sans JP', sans-serif; + background-color: #272727; + border: 1px solid #484848; + color: #aaa; + &:hover{ + background-color: #1083E3; + border: 1px solid #1083E3; + color: #fff; + font-weight: 500; + } } - &:hover { - font-weight: 400; - background-color: transparent; - border: 1px solid #484848; - color: #fff; + &.sub-tab{ + height: 30px; + padding: 0 10px; + line-height: 28px; + font-family: 'Noto Sans JP', sans-serif; + background-color: #2D2D2D; + border: 1px solid #393939; + color: #aaa; + &.act, + &:hover{ + background-color: #414E6C; + border: 1px solid #414E6C; + color: #fff; + font-weight: 500; + } } - } - &.self { - height: 30px; - padding: 0 10px; - line-height: 28px; - font-family: 'Noto Sans JP', sans-serif; - background-color: transparent; - border: 1px solid #676767; - color: #aaaaaa; - &:hover { - background-color: #272727; - border-color: #676767; - font-weight: 400; + &.roof{ + height: 30px; + padding: 0 10px; + line-height: 28px; + font-family: 'Noto Sans JP', sans-serif; + background-color: transparent; + border: 1px solid #484848; + color: #fff; + &.blue{ + background-color: #414E6C; + border: 1px solid #414E6C; + &:hover{ + background-color: #414E6C; + border: 1px solid #414E6C; + } + } + &.white{ + background-color: #fff; + border: 1px solid #fff; + color: #101010; + &:hover{ + background-color: #fff; + border: 1px solid #fff; + color: #101010; + } + } + &:hover{ + font-weight: 400; + background-color: transparent; + border: 1px solid #484848; + color: #fff; + } } - } - &:hover, - &.act { - background-color: #1083e3; - border: 1px solid #1083e3; - color: #fff; - font-weight: 500; - } - &.block { - display: block; - width: 100%; - } - &.ico-flx { - display: flex; - align-items: center; - .ico { - margin-right: 10px; + &.self{ + height: 30px; + padding: 0 10px; + line-height: 28px; + font-family: 'Noto Sans JP', sans-serif; + background-color: transparent; + border: 1px solid #676767; + color: #AAAAAA; + &:hover{ + background-color: #272727; + border-color: #676767; + font-weight: 400; + } } &:hover, - &.act { - font-weight: 400; + &.act{ + background-color: #1083E3; + border: 1px solid #1083E3; + color: #fff; + font-weight: 500; } - } + &.block{ + display: block; + width: 100%; + } + &.ico-flx{ + display: flex; + align-items: center; + .ico{ + margin-right: 10px; + } + &:hover, + &.act{ + font-weight: 400; + } + } } -.btn-origin { - display: inline-block; - height: 30px; - padding: 0 10px; - border-radius: 2px; - background-color: #101010; - color: #fff; - font-size: 13px; - font-weight: 400; - transition: all 0.15s ease-in-out; - &.navy { - background-color: #304961; - &:hover { - background-color: #233546; +.btn-origin{ + display: inline-block; + height: 30px; + padding: 0 10px; + border-radius: 2px; + background-color: #101010; + color: #fff; + font-size: 13px; + font-weight: 400; + transition: all .15s ease-in-out; + &.navy{ + background-color: #304961; + &:hover{ + background-color: #233546; + } } - } - &.grey { - background-color: #94a0ad; - &:hover { - background-color: #607f9a; + &.grey{ + background-color: #94A0AD; + &:hover{ + background-color: #607F9A; + } } - } - &.green { - background-color: #a6bba8; - &:hover { - background-color: #98af9b; + &.green{ + background-color: #A6BBA8; + &:hover{ + background-color: #98af9b; + } } - } - &.white { - border: 1px solid #94a0ad; - background-color: #fff; - color: #94a0ad; - &:hover { - background-color: #fff; + &.white{ + border: 1px solid #94A0AD; + background-color: #fff; + color: #94A0AD; + &:hover{ + background-color: #fff; + } } - } } // select -.sort-select { - position: relative; - display: inline-block; - min-width: 100px; - height: 30px; - line-height: 30px; - padding: 0 25px 0 10px; - background-color: #373737; - border: 1px solid #3f3f3f; - border-radius: 2px; - border-top-left-radius: 2px; - color: #fff; - cursor: pointer; - p { - font-size: 13px; - color: #fff; - height: 100%; - } - .select-item-wrap { - position: absolute; - top: 100%; - left: -1px; - clip-path: inset(0 0 100% 0); - width: calc(100% + 2px); - padding: 8px 0; - max-height: 100px; - overflow-y: auto; - background-color: #373737; - border: 1px solid #3f3f3f; - border-radius: 2px; - transition: all 0.17s ease-in-out; - visibility: hidden; - z-index: 999; - .select-item { - display: flex; - align-items: center; - padding: 8px 20px; - line-height: 1.4; - transition: all 0.17s ease-in-out; - button { - font-size: 12px; - color: #fff; - line-height: 1.4; - } - &:hover { - background-color: #2c2c2c; - } - } - &::-webkit-scrollbar { - width: 2px; - background-color: transparent; - } - &::-webkit-scrollbar-thumb { - background-color: #5a5a5a; - border-radius: 10px; - } - &::-webkit-scrollbar-track { - background-color: transparent; - } - } - &::after { - content: ''; - position: absolute; - top: 50%; - right: 7px; - transform: translateY(-50%); - width: 10px; - height: 6px; - background: url(/static/images/common/select-arr.svg) no-repeat center; - background-size: cover; - transition: all 0.17s ease-in-out; - } - &.active { - .select-item-wrap { - clip-path: inset(0 0 0 0); - visibility: visible; - } - &:after { - transform: translateY(-50%) rotate(-180deg); - } - } -} - -.select-light { - position: relative; - display: block; - width: 100%; - height: 30px; - background: #fff url(../../public/static/images/common/select_light_arr.svg) calc(100% - 11px) center no-repeat; - background-size: 10px 6px; - border: 1px solid #eee; - padding: 0 30px 0 10px; - font-size: 13px; - color: #45576f; - font-family: 'Noto Sans JP', sans-serif; - cursor: pointer; - &:disabled { - opacity: 1; - background-color: #fafafa; - color: #999; - cursor: default; - } - &.black { - color: #101010; - } - &.dark { - background: #323234 url(../../public/static/images/common/select_dark_arr.svg) calc(100% - 11px) center no-repeat; - color: #898989; - font-size: 12px; - border-radius: 2px; - border: none; - } -} - -// input -.form-input { - label { - display: block; - color: #aaa; - font-size: 12px; - font-weight: 500; - margin-bottom: 10px; - } -} -input[type='password'], -input[type='number'], -input[type='text'] { - &.input-origin { +.sort-select{ + position: relative; display: inline-block; + min-width: 100px; height: 30px; line-height: 30px; + padding: 0 25px 0 10px; + background-color: #373737; + border: 1px solid #3F3F3F; border-radius: 2px; - background-color: #323234; + border-top-left-radius: 2px; color: #fff; - font-size: 12px; - font-weight: 500; - font-family: 'Pretendard', sans-serif; - padding: 0 10px; - letter-spacing: 0px; - text-align: right; - &::placeholder { - opacity: 1; - font-size: 12px; - letter-spacing: 0px; + cursor: pointer; + p{ + font-size: 13px; + color: #fff; + height: 100%; } - &.block { - width: 100%; + .select-item-wrap{ + position: absolute; + top: 100%; + left: -1px; + clip-path:inset(0 0 100% 0); + width: calc(100% + 2px); + padding: 8px 0; + max-height: 100px; + overflow-y: auto; + background-color: #373737; + border: 1px solid #3F3F3F; + border-radius: 2px; + transition: all 0.17s ease-in-out; + visibility: hidden; + z-index: 999; + .select-item{ + display: flex; + align-items: center; + padding: 8px 20px; + line-height: 1.4; + transition: all .17s ease-in-out; + button{ + font-size: 12px; + color: #fff; + line-height: 1.4; + } + &:hover{ + background-color: #2C2C2C; + } + } + &::-webkit-scrollbar { + width: 2px; + background-color: transparent; + + } + &::-webkit-scrollbar-thumb { + background-color: #5a5a5a; + border-radius: 10px; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } } - &:read-only { - color: #aaa; + &::after{ + content: ''; + position: absolute; + top: 50%; + right: 7px; + transform: translateY(-50%); + width: 10px; + height: 6px; + background: url(/static/images/common/select-arr.svg) no-repeat center; + background-size: cover; + transition: all .17s ease-in-out; } - &.plane { - font-family: 'Noto Sans JP', sans-serif; - border: 1px solid #525252; - background-color: transparent; + &.active{ + .select-item-wrap{ + clip-path: inset(0 0 0 0); + visibility: visible; + } + &:after{ + transform: translateY(-50%) rotate(-180deg); + } } - } - &.input-light { +} + +.select-light{ + position: relative; display: block; width: 100%; height: 30px; - padding: 0 10px; + background: #FFF url(../../public/static/images/common/select_light_arr.svg) calc(100% - 11px) center no-repeat; + background-size: 10px 6px; border: 1px solid #eee; - border-radius: 2px; - background-color: #fff; - font-family: 'Noto Sans JP', sans-serif; + padding: 0 30px 0 10px; font-size: 13px; - color: #45576f; - font-weight: normal; - transition: border-color 0.17s ease-in-out; - text-align: left; - &:read-only { - background-color: #fafafa; - color: #999999; + color: #45576F; + font-family: 'Noto Sans JP', sans-serif; + cursor: pointer; + &:disabled{ + opacity: 1; + background-color: #FAFAFA; + color: #999; + cursor: default; + } + &.black{ + color: #101010; + } + &.dark{ + background: #323234 url(../../public/static/images/common/select_dark_arr.svg) calc(100% - 11px) center no-repeat; + color: #898989; + font-size: 12px; + border-radius: 2px; + border: none; } - } } + +// input +.form-input{ + label{ + display: block; + color: #aaa; + font-size: 12px; + font-weight: 500; + margin-bottom: 10px; + } +} +input[type=password], +input[type=number], +input[type=text]{ + &.input-origin{ + display: inline-block; + height: 30px; + line-height: 30px; + border-radius: 2px; + background-color: #323234; + color: #fff; + font-size: 12px; + font-weight: 500; + font-family: 'Pretendard', sans-serif; + padding: 0 10px; + letter-spacing: 0px; + text-align: right; + &::placeholder{ + opacity: 1; + font-size: 12px; + letter-spacing: 0px; + } + &.block{ + width: 100%; + } + &:read-only{ + color: #AAA; + } + &.plane{ + font-family: 'Noto Sans JP', sans-serif; + border: 1px solid #525252; + background-color: transparent; + } + } + &.input-light{ + display: block; + width: 100%; + height: 30px; + padding: 0 10px; + border: 1px solid #eee; + border-radius: 2px; + background-color: #fff; + font-family: 'Noto Sans JP', sans-serif; + font-size: 13px; + color: #45576F; + font-weight: normal; + transition: border-color .17s ease-in-out; + text-align: left; + &:read-only{ + background-color: #FAFAFA; + color: #999999; + } + } +} + + + // check-btn -.check-btn { - display: flex; - align-items: center; - height: 30px; - background-color: #3a3a3a; - border-radius: 3px; - transition: all 0.17s ease-in-out; - .check-area { - flex: none; - width: 30px; - height: 100%; - border-right: 1px solid #272727; - background: url(../../public/static/images/canvas/check-grey.svg) no-repeat center; - background-size: 11px 9px; - } - .title-area { - padding: 0 10px; - font-size: 12px; - color: #898989; - font-weight: 400; - } - &.block { - width: 100%; - } - &:hover, - &.act { - background-color: #fff; - .check-area { - border-right: 1px solid #101010; - background: url(../../public/static/images/canvas/check-black.svg) no-repeat center; +.check-btn{ + display: flex; + align-items: center; + height: 30px; + background-color: #3A3A3A; + border-radius: 3px; + transition: all .17s ease-in-out; + .check-area{ + flex: none; + width: 30px; + height: 100%; + border-right: 1px solid #272727; + background: url(../../public/static/images/canvas/check-grey.svg)no-repeat center; + background-size: 11px 9px; } - .title-area { - color: #101010; - font-weight: 600; + .title-area{ + padding: 0 10px; + font-size: 12px; + color: #898989; + font-weight: 400; + } + &.block{ + width: 100%; + } + &:hover, + &.act{ + background-color: #fff; + .check-area{ + border-right: 1px solid #101010; + background: url(../../public/static/images/canvas/check-black.svg)no-repeat center; + } + .title-area{ + color: #101010; + font-weight: 600; + } } - } } // arr-btn -.arr-btn { - display: block; - height: 30px; - border-radius: 3px; - background-color: #3a3a3a; - padding: 0 11px; - text-align: left; - transition: all 0.17s ease-in-out; - span { - position: relative; - font-size: 12px; - color: #898989; - font-weight: 400; - padding-right: 15px; - &:after { - content: ''; - position: absolute; - top: 50%; - right: 0; - transform: translateY(-50%); - width: 5px; - height: 8px; - background: url(../../public/static/images/canvas/arr_btn_ico.svg) no-repeat center; - } - } - &:hover, - &.act { - background-color: #fff; - span { - color: #101010; - font-weight: 500; - &:after { - background: url(../../public/static/images/canvas/arr_btn_ico_black.svg) no-repeat center; - } - } - } - &.dark { - text-align: center; - background-color: #272727; - border: 1px solid #484848; - span { - color: #fff; - &:after { - background: url(../../public/static/images/canvas/arr_btn_ico_white.svg) no-repeat center; - } +.arr-btn{ + display: block; + height: 30px; + border-radius: 3px; + background-color: #3A3A3A; + padding: 0 11px; + text-align: left; + transition: all .17s ease-in-out; + span{ + position: relative; + font-size: 12px; + color: #898989; + font-weight: 400; + padding-right: 15px; + &:after{ + content: ''; + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + width: 5px; + height: 8px; + background: url(../../public/static/images/canvas/arr_btn_ico.svg)no-repeat center; + } } &:hover, - &.act { - background-color: #1083e3; - border: 1px solid #1083e3; + &.act{ + background-color: #fff; + span{ + color: #101010; + font-weight: 500; + &:after{ + background: url(../../public/static/images/canvas/arr_btn_ico_black.svg)no-repeat center; + } + } + } + &.dark{ + text-align: center; + background-color: #272727; + border: 1px solid #484848; + span{ + color: #Fff; + &:after{ + background: url(../../public/static/images/canvas/arr_btn_ico_white.svg)no-repeat center; + } + } + &:hover, + &.act{ + background-color: #1083E3; + border: 1px solid #1083E3; + } } - } } // radio .d-check-radio, -.d-check-box { - line-height: 1.1; - cursor: pointer; - input[type='checkbox'], - input[type='radio'] { - position: static; - margin-left: 0; +.d-check-box{ + line-height: 1.1; cursor: pointer; - opacity: 0; - z-index: 1; - flex: 0 0 auto; - } - label { - position: relative; - padding-left: 10px; - margin-bottom: 0; - word-break: break-all; - line-height: 1.2; - display: inline; - vertical-align: top; - color: #fff; - font-size: 13px; - font-weight: 400; - cursor: pointer; - } - &.light { - label { - color: #45576f; + input[type=checkbox], + input[type=radio]{ + position: static; + margin-left: 0; + cursor: pointer; + opacity: 0; + z-index: 1; + flex: 0 0 auto; } - } - &.no-text { - label { - padding-left: 0; + label{ + position: relative; + padding-left: 10px; + margin-bottom: 0; + word-break: break-all; + line-height: 1.2; + display: inline; + vertical-align: top; + color: #fff; + font-size: 13px; + font-weight: 400; + cursor: pointer; + } + &.light{ + label{ + color: #45576F; + } + } + &.no-text{ + label{ + padding-left: 0; + } } - } } .d-check-radio { - label { - &::before { - cursor: pointer; - content: ''; - display: inline-block; - position: absolute; - width: 17px; - height: 17px; - top: 2px; - left: 0; - margin-left: -12px; - border: 1px solid #999999; - border-radius: 100%; - background-color: transparent; - text-align: center; - font-size: 13px; - line-height: 1.4; - transition: - border 0.15s ease-in-out, - color 0.15s ease-in-out; + label{ + &::before{ + cursor: pointer; + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + top:2px; + left: 0; + margin-left: -12px; + border: 1px solid #999999; + border-radius: 100%; + background-color: transparent; + text-align:center; + font-size:13px; + line-height:1.4; + transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + } + &::after{ + cursor: pointer; + content: ""; + display: inline-block; + position: absolute; + width: 9px; + height: 9px; + top:6px; + left: 4px; + margin-left: -12px; + border: none; + border-radius: 100%; + background-color: #fff; + text-align:center; + font-size:13px; + line-height:1.4; + opacity: 0; + visibility: hidden; + transition: opacity 0.15s ease-in-out, color 0.15s ease-in-out; + } } - &::after { - cursor: pointer; - content: ''; - display: inline-block; - position: absolute; - width: 9px; - height: 9px; - top: 6px; - left: 4px; - margin-left: -12px; - border: none; - border-radius: 100%; - background-color: #fff; - text-align: center; - font-size: 13px; - line-height: 1.4; - opacity: 0; - visibility: hidden; - transition: - opacity 0.15s ease-in-out, - color 0.15s ease-in-out; + &.light{ + label{ + &:before{ + border-color: #D6D6D7; + } + &:after{ + background-color: #697C8F; + } + } } - } - &.light { - label { - &:before { - border-color: #d6d6d7; - } - &:after { - background-color: #697c8f; - } + input[type=radio]:checked + label::after{ + opacity: 1; + visibility: visible; } - } - input[type='radio']:checked + label::after { - opacity: 1; - visibility: visible; - } - &.pop { - label { - font-size: 12px; - &:before { - width: 16px; - height: 16px; - border-color: #fff; - } - &:after { - width: 8px; - height: 8px; - background-color: #fff; - } + &.pop{ + label{ + font-size: 12px; + &:before{ + width: 16px; + height: 16px; + border-color: #fff; + } + &:after{ + width: 8px; + height: 8px; + background-color: #fff; + } + } } - } } // check-box -.d-check-box { - label { - &.red { - color: #ffcaca; +.d-check-box{ + label{ + &.red{color: #FFCACA;} + &::before{ + cursor: pointer; + content: ""; + display: inline-block; + position: absolute; + width: 17px; + height: 17px; + top: 2px; + left: 0; + margin-left: -12px; + border: 1px solid #D6D6D7; + background-color: #fff; + transition: border 0.15s ease-in-out, color 0.15s ease-in-out; + } + &:after{ + cursor: pointer; + content: ""; + display: inline-block; + position: absolute; + width: 16px; + height: 16px; + top:0; + left: 0; + margin-left: -.8rem; + transition: border 0.05s ease-in-out, color 0.05s ease-in-out; + } } - &::before { - cursor: pointer; - content: ''; - display: inline-block; - position: absolute; - width: 17px; - height: 17px; - top: 2px; - left: 0; - margin-left: -12px; - border: 1px solid #d6d6d7; - background-color: #fff; - transition: - border 0.15s ease-in-out, - color 0.15s ease-in-out; + input[type=checkbox]:checked + label::after{ + content: ""; + display: inline-block; + position: absolute; + top: 1px; + left: -1px; + width: 5px; + height: 8px; + border: 2px solid #697C8F; + border-left: none; + border-top: none; + transform: translate(7.75px,4.5px) rotate(45deg); + -ms-transform: translate(7.75px,4.5px) rotate(45deg); } - &:after { - cursor: pointer; - content: ''; - display: inline-block; - position: absolute; - width: 16px; - height: 16px; - top: 0; - left: 0; - margin-left: -0.8rem; - transition: - border 0.05s ease-in-out, - color 0.05s ease-in-out; + &.pop{ + label{ + &:before{ + background-color: transparent; + } + } + input[type=checkbox]:checked + label::after{ + border-color: #fff; + } + &.no-text{ + label{ + padding-left: 0; + } + } } - } - input[type='checkbox']:checked + label::after { - content: ''; - display: inline-block; - position: absolute; - top: 1px; - left: -1px; - width: 5px; - height: 8px; - border: 2px solid #697c8f; - border-left: none; - border-top: none; - transform: translate(7.75px, 4.5px) rotate(45deg); - -ms-transform: translate(7.75px, 4.5px) rotate(45deg); - } - &.pop { - label { - &:before { - background-color: transparent; - } + &.sel{ + input[type=checkbox]:checked + label{ + color: #D7C863; + } + input[type=checkbox]:checked + label::before, + input[type=checkbox]:checked + label::after{ + border-color: #D7C863; + } } - input[type='checkbox']:checked + label::after { - border-color: #fff; - } - &.no-text { - label { - padding-left: 0; - } - } - } - &.sel { - input[type='checkbox']:checked + label { - color: #d7c863; - } - input[type='checkbox']:checked + label::before, - input[type='checkbox']:checked + label::after { - border-color: #d7c863; - } - } } // date-picker -.date-picker { - svg { - display: none; - } - .react-datepicker-wrapper { - width: 100%; - } - input[type='text'] { - display: block; - width: 100%; - height: 30px; - padding: 0 34px 0 10px; - border-radius: 2px; - border: 1px solid #eee; - font-size: 13px; - color: #45576f; - font-weight: normal; - font-family: 'Noto Sans JP', sans-serif; - background: #fff url(../../public/static/images/common/datepicker.svg) calc(100% - 11px) center no-repeat; - background-size: 14px 15px; - cursor: pointer; - } +.date-picker{ + svg{display: none;} + .react-datepicker-wrapper{ + width: 100%; + } + input[type=text]{ + display: block; + width: 100%; + height: 30px; + padding: 0 34px 0 10px; + border-radius: 2px; + border: 1px solid #eee; + font-size: 13px; + color: #45576F; + font-weight: normal; + font-family: 'Noto Sans JP', sans-serif; + background: #fff url(../../public/static/images/common/datepicker.svg) calc(100% - 11px) center no-repeat; + background-size: 14px 15px; + cursor: pointer; + } } // react select -.react-select-custom { - width: 100%; - .custom__control { - height: 30px; - min-height: unset; - border-radius: 2px; - border-color: #eee; - background-color: #fff; - &:hover { - border-color: #eee; +.react-select-custom{ + width: 100%; + .custom__control{ + height: 30px; + min-height: unset; + border-radius: 2px; + border-color: #EEE; + background-color: #fff; + &:hover{ + border-color: #EEE; + } } - } - .custom__control--is-focused { - border-color: #eee; - box-shadow: unset; - &:hover { - border-color: #eee; - } - } - .custom__value-container { - height: 100%; - padding: 0 10px; - } - .custom__placeholder, - .custom__single-value { - margin: 0; - } - .custom__single-value { - font-size: 13px; - color: #45576f; - font-weight: 400; - } - .custom__placeholder { - font-size: 13px; - color: #bbbbbb; - font-weight: 400; - } - .custom__indicator { - padding: 0; - svg { - display: none; - } - } - .custom__clear-indicator { - width: 30px; - height: 100%; - background: url(../../public/static/images/common/select_del.svg) no-repeat center; - background-size: 8px 8px; - } - .custom__dropdown-indicator { - width: 30px; - height: 100%; - background: url(../../public/static/images/common/select_light_arr.svg) no-repeat center; - } + .custom__control--is-focused{ + border-color: #EEE; + box-shadow: unset; + &:hover{ + border-color: #EEE; - .custom__menu { - margin: 1px 0; - border-radius: 2px; - overflow: hidden; - } - .custom__menu-list { - padding: 0; - } - .custom__option { - font-size: 13px; - padding: 7px 10px; - color: #45576f; - } - .custom__option--is-selected { - color: #fff; - } - // disable - &.custom--is-disabled { - .custom__control { - background-color: #fafafa; + } } - .custom__single-value { - color: #999999; + .custom__value-container { + height: 100%; + padding: 0 10px; } - } -} + .custom__placeholder, + .custom__single-value{ + margin: 0; + } + .custom__single-value{ + font-size: 13px; + color: #45576F; + font-weight: 400; + } + .custom__placeholder{ + font-size: 13px; + color: #bbbbbb; + font-weight: 400; + } + .custom__indicator{ + padding: 0; + svg{ + display: none; + } + } + .custom__clear-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_del.svg) no-repeat center; + background-size: 8px 8px; + } + .custom__dropdown-indicator{ + width: 30px; + height: 100%; + background: url(../../public/static/images/common/select_light_arr.svg) no-repeat center; + } + + .custom__menu { + margin: 1px 0; + border-radius: 2px; + overflow: hidden; + } + .custom__menu-list { + padding: 0; + } + .custom__option{ + font-size: 13px; + padding: 7px 10px; + color: #45576F; + } + .custom__option--is-selected{ + color: #fff; + } + // disable + &.custom--is-disabled{ + .custom__control{ + background-color: #FAFAFA ; + } + .custom__single-value{ + color: #999999; + } + } +} \ No newline at end of file diff --git a/src/styles/style.scss b/src/styles/style.scss index 39343d54..1841ebb9 100644 --- a/src/styles/style.scss +++ b/src/styles/style.scss @@ -1,5 +1 @@ -@import '_main.scss'; - -.locale-switch { - cursor: pointer; -} +@import '_main.scss'; \ No newline at end of file From 4f47eae1a4bbcdf5caa8b2e0ba154ff228d6a184 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 14:47:38 +0900 Subject: [PATCH 021/139] fix: add key prop map syntax --- src/components/floor-plan/CanvasFrame.jsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index d6a4e179..50e2e28c 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -39,8 +39,10 @@ export default function CanvasFrame({ plan }) { {contextMenu.map((menus, index) => (
    - {menus.map((menu) => ( -
  • setCurrentContextMenu(menu)}>{menu.name}
  • + {menus.map((menu, idx) => ( +
  • setCurrentContextMenu(menu)}> + {menu.name} +
  • ))}
))} From faf733da925ecf74473373850672c9586e045905 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 15:30:43 +0900 Subject: [PATCH 022/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_modal.scss | 29 +++++++++++++++++++---------- src/styles/_submodal.scss | 18 +++++++++++++----- 2 files changed, 32 insertions(+), 15 deletions(-) diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 3901ba0f..9dc39b65 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -1655,24 +1655,33 @@ $alert-color: #101010; .form-box{ width: 100%; background-color: #fff; - padding: 10px 0 20px; + padding: 10px 15px 20px; .line-form{ position: relative; - width: 102px; - height: 40px; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-width: 102px; + min-height: 40px; margin: 0 auto; - border-left: 1px dashed #101010; - border-right: 1px dashed #101010; - .line-font-box{ + + &::before{ + content: ''; position: absolute; - bottom: -3px; + bottom: 0px; left: 0; width: 100%; - text-align: center; + height: 40px; + border-left: 1px dashed #101010; + border-right: 1px dashed #101010; + } + .line-font-box{ .font{ display: block; - padding-bottom: 6px; + padding-bottom: 15px; color: #101010; + text-align: center; + line-height: 1; } .line{ position: relative; @@ -1687,7 +1696,7 @@ $alert-color: #101010; transform: translateY(-50%) rotate(45deg); left: 1px; width: 9px; - height: 9px; + height:+ 9px; border: 1px solid; border-color: inherit; border-top: none; diff --git a/src/styles/_submodal.scss b/src/styles/_submodal.scss index 5b18f74a..e5fae9fb 100644 --- a/src/styles/_submodal.scss +++ b/src/styles/_submodal.scss @@ -228,11 +228,19 @@ margin-bottom: 20px; } .design-request-grid{ - .design-request-grid-tit{ - font-size: 13px; - font-weight: 600; - color: #101010; - margin-bottom: 15px; + .design-request-count{ + display: flex; + align-items: center; + margin-bottom: 10px; + .design-request-grid-tit{ + font-size: 13px; + font-weight: 600; + color: #101010; + } + .select-wrap{ + margin-left: auto; + width: 80px; + } } } From fa2231d5b0dbbcc5e1a32033488b2b4bd6358eaf Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 21 Oct 2024 15:31:01 +0900 Subject: [PATCH 023/139] =?UTF-8?q?=EB=A7=88=ED=81=AC=EC=97=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasFrame.jsx | 7 +-- src/components/floor-plan/CanvasLayout.jsx | 5 +- src/components/floor-plan/CanvasMenu.jsx | 3 +- src/components/floor-plan/FloorPlan.jsx | 58 +++++++++++----------- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index d6a4e179..bbf6c4ea 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -6,8 +6,6 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEvent } from '@/hooks/useEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useContextMenu } from '@/hooks/useContextMenu' -import { useRecoilValue } from 'recoil' -import { currentObjectState } from '@/store/canvasAtom' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) @@ -35,7 +33,10 @@ export default function CanvasFrame({ plan }) { return (
- +
+ +
+ {contextMenu.map((menus, index) => (
    diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 405d5106..d10b103c 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -9,7 +9,8 @@ import { usePlan } from '@/hooks/usePlan' import { globalLocaleStore } from '@/store/localeAtom' import { SessionContext } from '@/app/SessionProvider' -export default function CanvasLayout() { +export default function CanvasLayout(props) { + const { menuNumber } = props const { session } = useContext(SessionContext) const [objectNo, setObjectNo] = useState('test123240822001') // 이후 삭제 필요 const globalLocaleState = useRecoilValue(globalLocaleStore) @@ -24,7 +25,7 @@ export default function CanvasLayout() { return (
    -
    +
    {plans.map((plan) => (
))}
diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 1836f4df..54c82ce8 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -23,6 +23,7 @@ import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { popupState } from '@/store/popupAtom' import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' import { usePopup } from '@/hooks/usePopup' +import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -79,6 +80,19 @@ export default function CanvasMenu(props) { const { swalFire } = useSwal() const [popup, setPopup] = useRecoilState(popupState) const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] + useEffect(() => { + console.log(canvas) + if (canvas) { + const circle = new fabric.Circle({ + left: 300, + top: 300, + radius: 5, + stroke: 'black', + }) + canvas.add(circle) + canvas.renderAll() + } + }, []) const onClickNav = (menu) => { setMenuNumber(menu.index) setCurrentMenu(menu.title) diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index b115ca48..21b90616 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -128,8 +128,8 @@ export default function FloorPlan() { <>
-
- +
+ {showOutlineModal && } {showPropertiesSettingModal && } {showPlaceShapeModal && } diff --git a/src/components/floor-plan/modal/Slope.jsx b/src/components/floor-plan/modal/Slope.jsx index ba9ede2a..4e6d63aa 100644 --- a/src/components/floor-plan/modal/Slope.jsx +++ b/src/components/floor-plan/modal/Slope.jsx @@ -9,7 +9,7 @@ export default function Slope({ setShowSlopeSettingModal }) { const [globalPitch, setGlobalPitch] = useRecoilState(globalPitchState) const inputRef = useRef() return ( - +

{getMessage('plan.menu.placement.surface.slope.setting')}

diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx index 2aa5cd84..8ce885c4 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx @@ -121,7 +121,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { setType(button.type) } return ( - +

{getMessage('modal.auxiliary.drawing')}

diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 555cdfcb..94ad7317 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -14,7 +14,7 @@ export default function BasicSetting({ setShowBasicSettingModal }) { const [tabNum, setTabNum] = useState(1) const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) return ( - +

{getMessage('plan.menu.module.circuit.setting.default')}

diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index f165bde0..6daf04b2 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -14,7 +14,7 @@ export default function CircuitTrestleSetting({ setShowCircuitTrestleSettingModa setCircuitAllocationType, } return ( - +

{getMessage('modal.circuit.trestle.setting')}

diff --git a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx index bab1e696..b19f435e 100644 --- a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx +++ b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx @@ -1,6 +1,5 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useState } from 'react' import Eaves from '@/components/floor-plan/modal/eavesGable/type/Eaves' import Gable from '@/components/floor-plan/modal/eavesGable/type/Gable' import WallMerge from '@/components/floor-plan/modal/eavesGable/type/WallMerge' @@ -35,7 +34,7 @@ export default function EavesGableEdit({ setShowEavesGableEditModal }) { } return ( - +

{getMessage('modal.eaves.gable.edit')}

diff --git a/src/components/floor-plan/modal/movement/MovementSetting.jsx b/src/components/floor-plan/modal/movement/MovementSetting.jsx index 569249d6..2e6bd7ec 100644 --- a/src/components/floor-plan/modal/movement/MovementSetting.jsx +++ b/src/components/floor-plan/modal/movement/MovementSetting.jsx @@ -13,7 +13,7 @@ export default function MovementSetting({ setShowMovementModal }) { ] return ( - +

{getMessage('plan.menu.roof.cover.movement.shape.updown')}

diff --git a/src/components/floor-plan/modal/object/ObjectSetting.jsx b/src/components/floor-plan/modal/object/ObjectSetting.jsx index 764535e3..d028e9a7 100644 --- a/src/components/floor-plan/modal/object/ObjectSetting.jsx +++ b/src/components/floor-plan/modal/object/ObjectSetting.jsx @@ -1,9 +1,8 @@ 'use client' -import { useState, useRef, useEffect } from 'react' +import { useEffect, useRef, useState } from 'react' import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' -import { useEvent } from '@/hooks/useEvent' import { canvasState } from '@/store/canvasAtom' import { useSwal } from '@/hooks/useSwal' import { useObjectBatch } from '@/hooks/object/useObjectBatch' @@ -74,7 +73,7 @@ export default function ObjectSetting({ setShowObjectSettingModal }) { { id: 4, name: getMessage('modal.object.setting.type.pentagon.dormer') }, ] return ( - +

{getMessage('plan.menu.placement.surface.object')}

diff --git a/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx b/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx index d26b2ef3..a1e848be 100644 --- a/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx @@ -9,7 +9,7 @@ export default function PropertiesSetting(props) { const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting(setShowPropertiesSettingModal) return ( - +

{getMessage('modal.canvas.setting.wallline.properties.setting')}

diff --git a/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx b/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx index 975a582a..84e59da4 100644 --- a/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx @@ -109,7 +109,7 @@ export default function WallLineSetting(props) { } return ( - +

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

diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx index 0d2c301c..9374dbf9 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx @@ -5,7 +5,6 @@ import RightAngle from '@/components/floor-plan/modal/lineTypes/RightAngle' import DoublePitch from '@/components/floor-plan/modal/lineTypes/DoublePitch' import Angle from '@/components/floor-plan/modal/lineTypes/Angle' import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' -import { useOuterLineWall } from '@/hooks/roofcover/useOuterLineWall' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' import { usePlacementShapeDrawing } from '@/hooks/surface/usePlacementShapeDrawing' @@ -120,7 +119,7 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) setType(button.type) } return ( - +

{getMessage('plan.menu.placement.surface.drawing')}

diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 55cfcb6b..bc7ba2b7 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -1,7 +1,6 @@ import SizeGuide from '@/components/floor-plan/modal/placementShape/SizeGuide' import MaterialGuide from '@/components/floor-plan/modal/placementShape/MaterialGuide' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react' import { useRecoilState } from 'recoil' import { Fragment, useEffect, useState } from 'react' import { canvasSettingState } from '@/store/canvasAtom' @@ -18,7 +17,18 @@ export default function PlacementShapeSetting({ setShowPlaceShapeModal }) { const [basicSetting, setBasicSettings] = useState({ roofSizeSet: 1, roofAngleSet: 'slope', - roofs: [{ roofApply: true, roofSeq: 1, roofType: 1, roofWidth: 200, roofHeight: 200, roofHajebichi: 200, roofGap: 0, roofLayout: 'parallel' }], + roofs: [ + { + roofApply: true, + roofSeq: 1, + roofType: 1, + roofWidth: 200, + roofHeight: 200, + roofHajebichi: 200, + roofGap: 0, + roofLayout: 'parallel', + }, + ], }) const { getMessage } = useMessage() @@ -159,7 +169,7 @@ export default function PlacementShapeSetting({ setShowPlaceShapeModal }) { } return ( - +

{getMessage('plan.menu.placement.surface.initial.setting')}

diff --git a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx index e667667e..90e05dbf 100644 --- a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx +++ b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx @@ -1,6 +1,6 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useEffect, useState, useRef } from 'react' +import { useEffect, useRef, useState } from 'react' import Image from 'next/image' import PlacementSurface from '@/components/floor-plan/modal/placementSurface/PlacementSurface' import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' @@ -239,7 +239,7 @@ export default function PlacementSurfaceSetting({ setShowPlacementSurfaceSetting }, []) return ( - +

{getMessage('plan.menu.placement.surface.arrangement')}

diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index 72599bbe..52ee2e3f 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -1,6 +1,5 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useState } from 'react' import QSelectBox from '@/components/common/select/QSelectBox' import { useRoofAllocationSetting } from '@/hooks/roofcover/useRoofAllocationSetting' @@ -10,7 +9,7 @@ export default function RoofAllocationSetting({ setShowRoofAllocationSettingModa useRoofAllocationSetting(setShowRoofAllocationSettingModal) return ( - +

{getMessage('plan.menu.estimate.roof.alloc')}

diff --git a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx index ec1684a6..9e9dc93f 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx @@ -25,7 +25,7 @@ export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySet } return ( - +

{getMessage('plan.menu.roof.cover.roof.shape.passivity.setting')}

diff --git a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx index 60355848..d92ed807 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx @@ -67,10 +67,19 @@ export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { handleRollBack, } - const directionProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, shedWidth, setShedWidth } + const directionProps = { + pitch, + setPitch, + eavesOffset, + setEavesOffset, + gableOffset, + setGableOffset, + shedWidth, + setShedWidth, + } return ( - +

{getMessage('modal.roof.shape.setting')}

diff --git a/src/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting.jsx b/src/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting.jsx index 7e5230b1..1e421440 100644 --- a/src/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting.jsx +++ b/src/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting.jsx @@ -1,6 +1,5 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useState } from 'react' import WallLine from '@/components/floor-plan/modal/wallLineOffset/type/WallLine' import Offset from '@/components/floor-plan/modal/wallLineOffset/type/Offset' import { useWallLineOffsetSetting } from '@/hooks/roofcover/useWallLineOffsetSetting' @@ -38,7 +37,7 @@ export default function WallLineOffsetSetting({ setShowWallLineOffsetSettingModa } return ( - +

{getMessage('modal.wallline.offset.setting')}

From 68aba5094d2ba6c238e281b35ba3148db716491c Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 16:30:22 +0900 Subject: [PATCH 026/139] fix: Modify commonCode hook --- src/hooks/common/useCommonCode.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/common/useCommonCode.js b/src/hooks/common/useCommonCode.js index 055572eb..17c2de8b 100644 --- a/src/hooks/common/useCommonCode.js +++ b/src/hooks/common/useCommonCode.js @@ -6,7 +6,7 @@ import { useAxios } from '../useAxios' export const useCommonCode = () => { const [commonCode, setCommonCode] = useRecoilState(commonCodeState) - const { get, promiseGet } = useAxios() + const { promiseGet } = useAxios() const findCommonCode = (key) => { // const arr = commonCode[key] From cc70bf1db51bfecde78a9c350d989b4856f1c16e Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 21 Oct 2024 16:53:00 +0900 Subject: [PATCH 027/139] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=84=B8?= =?UTF-8?q?=ED=8C=85=20=EC=88=98=EC=A0=95,=20arrow=20usePolygon=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 6 +- .../floor-plan/modal/setting01/GridOption.jsx | 61 ++-- src/hooks/object/useObjectBatch.js | 11 +- .../roofcover/useRoofAllocationSetting.js | 4 +- src/hooks/surface/usePlacementShapeDrawing.js | 4 +- src/hooks/usePolygon.js | 316 ++++++++++++++++++ src/util/qpolygon-utils.js | 311 ----------------- 7 files changed, 356 insertions(+), 357 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ad08e884..d982a49a 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -2,7 +2,7 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' -import { calculateAngle, drawDirectionArrow, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' +import { calculateAngle, drawHippedRoof, inPolygon, toGeoJSON } from '@/util/qpolygon-utils' import * as turf from '@turf/turf' export const QPolygon = fabric.util.createClass(fabric.Polygon, { @@ -121,13 +121,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.on('modified', (e) => { this.addLengthText() - // if (this.arrow) { - // drawDirectionArrow(this) - // } }) this.on('selected', () => { - // drawDirectionArrow(this) Object.keys(this.controls).forEach((controlKey) => { if (controlKey !== 'ml' && controlKey !== 'mr') { this.setControlVisible(controlKey, false) diff --git a/src/components/floor-plan/modal/setting01/GridOption.jsx b/src/components/floor-plan/modal/setting01/GridOption.jsx index 39af3a10..1bded7a0 100644 --- a/src/components/floor-plan/modal/setting01/GridOption.jsx +++ b/src/components/floor-plan/modal/setting01/GridOption.jsx @@ -1,5 +1,5 @@ import React, { useEffect } from 'react' -import { useRecoilState } from 'recoil' +import { useRecoilState, useResetRecoilState } from 'recoil' import { settingModalGridOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import { adsorptionPointAddModeState } from '@/store/canvasAtom' @@ -18,47 +18,42 @@ export default function GridOption(props) { const [color, setColor] = useColor(gridColor) useEffect(() => { - console.log('GridOption useEffect 실행') setGridColor(color.hex) }, [color]) const onClickOption = (option) => { + const { id, name, selected } = option + const newGridOptions = [...gridOptions] - newGridOptions.map((item) => { - if (item.id === option.id) { + + // 초기화 + setShowColorPickerModal(false) + setShowDotLineGridModal(false) + setTempGridMode(false) + setAdsorptionPointAddMode(false) + // + + newGridOptions.forEach((item) => { + if (item.id === id) { item.selected = !item.selected + } else { + item.selected = false } }) - if (option.id === 1) { - // 점 그리드 - setAdsorptionPointAddMode(false) - setTempGridMode(option.selected) - newGridOptions[2].selected = false - } - - if (option.id === 2) { - // 점.선 그리드 - if (option.selected) { - setShowDotLineGridModal(true) - } else { - setShowDotLineGridModal(false) - } - } - - if (option.name === 'modal.canvas.setting.grid.absorption.add') { - setAdsorptionPointAddMode(!adsorptionPointAddMode) - setTempGridMode(false) - newGridOptions[0].selected = false - } - - if (option.id === 4) { - // 그리드 색 설정 - if (option.selected) { - setShowColorPickerModal(true) - } else { - setShowColorPickerModal(false) - } + const selectedOption = newGridOptions.find((item) => item.id === option.id) + if (selectedOption.id === 1) { + // 임의 그리드 모드 + setTempGridMode(selectedOption.selected) + } else if (selectedOption.id === 2) { + // 점 선 그리드 설정 모달 + setShowDotLineGridModal(selectedOption.selected) + } else if (selectedOption.id === 3) { + // 흡착점 모드 + setAdsorptionPointAddMode(selectedOption.selected) + } else if (selectedOption.id === 4) { + // 그리드 색 설정 모달 + setShowColorPickerModal(selectedOption.selected) } setGridOptions(newGridOptions) diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 9ad8af5d..06976f05 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -1,14 +1,13 @@ 'use client' import { useMessage } from '@/hooks/useMessage' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' -import { INPUT_TYPE, BATCH_TYPE } from '@/common/common' +import { BATCH_TYPE, INPUT_TYPE } from '@/common/common' import { useEvent } from '@/hooks/useEvent' -import { polygonToTurfPolygon, rectToPolygon, triangleToPolygon, pointsToTurfPolygon, setSurfaceShapePattern } from '@/util/canvas-util' +import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util' import { useSwal } from '@/hooks/useSwal' import * as turf from '@turf/turf' -import { QPolygon } from '@/components/fabric/QPolygon' -import { drawDirectionArrow } from '@/util/qpolygon-utils' +import { usePolygon } from '@/hooks/usePolygon' export function useObjectBatch() { const { getMessage } = useMessage() @@ -16,6 +15,8 @@ export function useObjectBatch() { const { addCanvasMouseEventListener, initEvent } = useEvent() const { swalFire } = useSwal() + const { drawDirectionArrow } = usePolygon() + const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => { const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index bc55c921..6eba271f 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -2,12 +2,14 @@ import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' import { setSurfaceShapePattern } from '@/util/canvas-util' -import { drawDirectionArrow, splitPolygonWithLines } from '@/util/qpolygon-utils' +import { splitPolygonWithLines } from '@/util/qpolygon-utils' import { useSwal } from '@/hooks/useSwal' +import { usePolygon } from '@/hooks/usePolygon' // 지붕면 할당 export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { const canvas = useRecoilValue(canvasState) + const { drawDirectionArrow } = usePolygon() const { swalFire } = useSwal() diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index 123e991d..40d25bf0 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -14,7 +14,7 @@ import { useTempGrid } from '@/hooks/useTempGrid' import { useEffect, useRef } from 'react' import { distanceBetweenPoints, setSurfaceShapePattern } from '@/util/canvas-util' import { fabric } from 'fabric' -import { calculateAngle, drawDirectionArrow } from '@/util/qpolygon-utils' +import { calculateAngle } from '@/util/qpolygon-utils' import { placementShapeDrawingAngle1State, placementShapeDrawingAngle2State, @@ -37,7 +37,7 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { useEvent() const { getIntersectMousePoint } = useMouse() const { addLine, removeLine } = useLine() - const { addPolygonByLines } = usePolygon() + const { addPolygonByLines, drawDirectionArrow } = usePolygon() const { tempGridMode } = useTempGrid() const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 7289a0d3..514c6592 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -4,9 +4,11 @@ import { fabric } from 'fabric' import { getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint } from '@/util/qpolygon-utils' +import { flowDisplaySelector } from '@/store/settingAtom' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) + const isFlowDisplay = useRecoilValue(flowDisplaySelector) const fontSize = useRecoilValue(fontSizeState) const fontFamily = useRecoilValue(fontFamilyState) @@ -100,9 +102,323 @@ export const usePolygon = () => { canvas.renderAll() } + /** + * poolygon의 방향에 따라 화살표를 추가한다. + * @param polygon + */ + const drawDirectionArrow = (polygon) => { + const direction = polygon.direction + if (!direction) { + return + } + + polygon.canvas + .getObjects() + .filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow) + .forEach((obj) => polygon.canvas.remove(obj)) + + let arrow = null + let points = [] + + if (polygon.arrow) { + polygon.canvas.remove(polygon.arrow) + } + + let centerPoint = { x: polygon.left, y: polygon.top } + let stickeyPoint + + const polygonMaxX = Math.max(...polygon.getCurrentPoints().map((point) => point.x)) + const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x)) + const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y)) + const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y)) + + switch (direction) { + case 'north': + points = [ + { x: centerPoint.x, y: polygonMinY - 50 }, + { x: centerPoint.x + 20, y: polygonMinY - 50 }, + { x: centerPoint.x + 20, y: polygonMinY - 80 }, + { x: centerPoint.x + 50, y: polygonMinY - 80 }, + { x: centerPoint.x, y: polygonMinY - 110 }, + { x: centerPoint.x - 50, y: polygonMinY - 80 }, + { x: centerPoint.x - 20, y: polygonMinY - 80 }, + { x: centerPoint.x - 20, y: polygonMinY - 50 }, + ] + + stickeyPoint = { x: centerPoint.x, y: polygonMinY - 110 } + break + case 'south': + points = [ + { x: centerPoint.x, y: polygonMaxY + 50 }, + { x: centerPoint.x + 20, y: polygonMaxY + 50 }, + { x: centerPoint.x + 20, y: polygonMaxY + 80 }, + { x: centerPoint.x + 50, y: polygonMaxY + 80 }, + { x: centerPoint.x, y: polygonMaxY + 110 }, + { x: centerPoint.x - 50, y: polygonMaxY + 80 }, + { x: centerPoint.x - 20, y: polygonMaxY + 80 }, + { x: centerPoint.x - 20, y: polygonMaxY + 50 }, + ] + stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 110 } + break + case 'west': + points = [ + { x: polygonMinX - 50, y: centerPoint.y }, + { x: polygonMinX - 50, y: centerPoint.y + 20 }, + { x: polygonMinX - 80, y: centerPoint.y + 20 }, + { x: polygonMinX - 80, y: centerPoint.y + 50 }, + { x: polygonMinX - 110, y: centerPoint.y }, + { x: polygonMinX - 80, y: centerPoint.y - 50 }, + { x: polygonMinX - 80, y: centerPoint.y - 20 }, + { x: polygonMinX - 50, y: centerPoint.y - 20 }, + ] + + stickeyPoint = { x: polygonMinX - 110, y: centerPoint.y } + break + case 'east': + points = [ + { x: polygonMaxX + 50, y: centerPoint.y }, + { x: polygonMaxX + 50, y: centerPoint.y + 20 }, + { x: polygonMaxX + 80, y: centerPoint.y + 20 }, + { x: polygonMaxX + 80, y: centerPoint.y + 50 }, + { x: polygonMaxX + 110, y: centerPoint.y }, + { x: polygonMaxX + 80, y: centerPoint.y - 50 }, + { x: polygonMaxX + 80, y: centerPoint.y - 20 }, + { x: polygonMaxX + 50, y: centerPoint.y - 20 }, + ] + + stickeyPoint = { x: polygonMaxX + 110, y: centerPoint.y } + break + } + + arrow = new fabric.Polygon(points, { + selectable: false, + name: 'arrow', + fill: 'transparent', + stroke: 'black', + direction: direction, + parent: polygon, + stickeyPoint: stickeyPoint, + visible: isFlowDisplay, + }) + + polygon.arrow = arrow + polygon.canvas.add(arrow) + polygon.canvas.renderAll() + drawDirectionStringToArrow(polygon.canvas, 0) + } + + /** + * 방향을 나타낸 화살표에 각도에 따라 글씨 추가 + * @param canvas + * @param compass + */ + const drawDirectionStringToArrow = (canvas, compass = 0) => { + const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') + + if (arrows.length === 0) { + return + } + + const eastArrows = arrows.filter((arrow) => arrow.direction === 'east') + const westArrows = arrows.filter((arrow) => arrow.direction === 'west') + const northArrows = arrows.filter((arrow) => arrow.direction === 'north') + const southArrows = arrows.filter((arrow) => arrow.direction === 'south') + + let southText = '南' + let eastText = '東' + let westText = '西' + let northText = '北' + + if (compass === 0 || compass === 360) { + // 남,동,서 가능 + // 그대로 + } else if (compass < 45) { + //남(남남동),동(동북동),서(서남서) 가능 + //북(북북서) + southText = '南南東' + eastText = '東北東' + westText = '西南西' + northText = '北北西' + } else if (compass === 45) { + // 남, 서 가능 + // 남(남동) + // 서(남서) + // 북(북서) + // 동(북동) + southText = '南東' + westText = '南西' + northText = '北西' + eastText = '北東' + } else if (compass < 90) { + // 북(서북서) + // 동 (북북동) + // 남(동남동) + // 서(남남서) + northText = '北西北' + eastText = '北北東' + southText = '東南東' + westText = '南南西' + } else if (compass === 90) { + // 동(북) + // 서(남) + // 남(동) + // 북(서) + eastText = '北' + westText = '南' + southText = '東' + northText = '西' + } else if (compass < 135) { + // 남,서,북 가능 + // 동(북북서) + // 서(남남동) + // 남(동북동) + // 북(서남서) + eastText = '北北西' + westText = '南南東' + southText = '東北東' + northText = '西南西' + } else if (compass === 135) { + // 서,북 가능 + + // 서(남동) + // 북(남서) + // 남(북동) + // 동(북서) + + westText = '南東' + northText = '南西' + southText = '北東' + eastText = '北西' + } else if (compass < 180) { + // 북,동,서 가능 + // 북(남남서) + // 동(서북서) + // 남(북북동) + // 서(동남동) + + northText = '南南西' + eastText = '西北西' + southText = '北北東' + westText = '東南東' + } else if (compass === 180) { + // 북,동,서 가능 + // 북(남) + // 동(서) + // 남(북) + // 서(동) + northText = '南' + eastText = '西' + southText = '北' + westText = '東' + } else if (compass < 225) { + // 서,북,동 가능 + // 북(남남동) + // 동(서남서) + // 남(북북서) + // 서(동남동) + northText = '南南東' + eastText = '西南西' + southText = '北北西' + westText = '東南東' + } else if (compass === 225) { + // 북,동 가능 + // 북(남동) + // 동(남서) + // 남(북서) + // 서(북동) + northText = '南東' + eastText = '南西' + southText = '北西' + westText = '北東' + } else if (compass < 270) { + // 북동남 가능 + // 북(동남동) + // 동(남남서) + // 남(서북서) + // 서(북북동) + northText = '東南東' + eastText = '南南西' + southText = '西北西' + westText = '北北東' + } else if (compass === 270) { + // 북동남 가능 + // 북(동) + // 동(남) + // 남(서) + // 서(북) + northText = '東' + eastText = '南' + southText = '西' + westText = '北' + } else if (compass < 315) { + // 북,동,남 가능 + // 북(동북동) + // 동(남남동) + // 남(서남서) + // 서(북북서) + northText = '東北東' + eastText = '南南東' + southText = '西南西' + westText = '北北西' + } else if (compass === 315) { + // 동,남 가능 + // 북(북동) + // 동(남동) + // 남(남서) + // 서(북서) + northText = '北東' + eastText = '南東' + southText = '南西' + westText = '北西' + } else if (compass < 360) { + // 남,동,서 가능 + // 북(북북동) + // 동(동남동) + // 남(남남서) + // 서(서북서) + northText = '北北東' + eastText = '東南東' + southText = '南南西' + westText = '西北西' + } + + clearDirectionText(canvas) + + addTextByArrows(eastArrows, eastText, canvas) + addTextByArrows(westArrows, westText, canvas) + addTextByArrows(northArrows, northText, canvas) + addTextByArrows(southArrows, southText, canvas) + } + + const clearDirectionText = (canvas) => { + const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') + texts.forEach((text) => { + canvas.remove(text) + }) + } + + const addTextByArrows = (arrows, txt, canvas) => { + arrows.forEach((arrow, index) => { + const text = new fabric.Text(`${txt}${index + 1}`, { + fontSize: arrow.parent.fontSize, + fill: 'black', + originX: 'center', + originY: 'center', + name: 'directionText', + selectable: false, + left: arrow.stickeyPoint.x, + top: arrow.stickeyPoint.y, + parent: arrow, + visible: isFlowDisplay, + }) + canvas.add(text) + }) + } + return { addPolygon, addPolygonByLines, removePolygon, + drawDirectionArrow, } } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 07b46bc4..bfdf78a4 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -3038,314 +3038,3 @@ export const inPolygon = (polygonPoints, rectPoints) => { return allPointsInsidePolygon && noPolygonPointsInsideRect } - -/** - * poolygon의 방향에 따라 화살표를 추가한다. - * @param polygon - */ -export const drawDirectionArrow = (polygon) => { - const direction = polygon.direction - if (!direction) { - return - } - - polygon.canvas - .getObjects() - .filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow) - .forEach((obj) => polygon.canvas.remove(obj)) - - let arrow = null - let points = [] - - if (polygon.arrow) { - polygon.canvas.remove(polygon.arrow) - } - - let centerPoint = { x: polygon.left, y: polygon.top } - let stickeyPoint - - const polygonMaxX = Math.max(...polygon.getCurrentPoints().map((point) => point.x)) - const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x)) - const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y)) - const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y)) - - switch (direction) { - case 'north': - points = [ - { x: centerPoint.x, y: polygonMinY - 50 }, - { x: centerPoint.x + 20, y: polygonMinY - 50 }, - { x: centerPoint.x + 20, y: polygonMinY - 80 }, - { x: centerPoint.x + 50, y: polygonMinY - 80 }, - { x: centerPoint.x, y: polygonMinY - 110 }, - { x: centerPoint.x - 50, y: polygonMinY - 80 }, - { x: centerPoint.x - 20, y: polygonMinY - 80 }, - { x: centerPoint.x - 20, y: polygonMinY - 50 }, - ] - - stickeyPoint = { x: centerPoint.x, y: polygonMinY - 110 } - break - case 'south': - points = [ - { x: centerPoint.x, y: polygonMaxY + 50 }, - { x: centerPoint.x + 20, y: polygonMaxY + 50 }, - { x: centerPoint.x + 20, y: polygonMaxY + 80 }, - { x: centerPoint.x + 50, y: polygonMaxY + 80 }, - { x: centerPoint.x, y: polygonMaxY + 110 }, - { x: centerPoint.x - 50, y: polygonMaxY + 80 }, - { x: centerPoint.x - 20, y: polygonMaxY + 80 }, - { x: centerPoint.x - 20, y: polygonMaxY + 50 }, - ] - stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 110 } - break - case 'west': - points = [ - { x: polygonMinX - 50, y: centerPoint.y }, - { x: polygonMinX - 50, y: centerPoint.y + 20 }, - { x: polygonMinX - 80, y: centerPoint.y + 20 }, - { x: polygonMinX - 80, y: centerPoint.y + 50 }, - { x: polygonMinX - 110, y: centerPoint.y }, - { x: polygonMinX - 80, y: centerPoint.y - 50 }, - { x: polygonMinX - 80, y: centerPoint.y - 20 }, - { x: polygonMinX - 50, y: centerPoint.y - 20 }, - ] - - stickeyPoint = { x: polygonMinX - 110, y: centerPoint.y } - break - case 'east': - points = [ - { x: polygonMaxX + 50, y: centerPoint.y }, - { x: polygonMaxX + 50, y: centerPoint.y + 20 }, - { x: polygonMaxX + 80, y: centerPoint.y + 20 }, - { x: polygonMaxX + 80, y: centerPoint.y + 50 }, - { x: polygonMaxX + 110, y: centerPoint.y }, - { x: polygonMaxX + 80, y: centerPoint.y - 50 }, - { x: polygonMaxX + 80, y: centerPoint.y - 20 }, - { x: polygonMaxX + 50, y: centerPoint.y - 20 }, - ] - - stickeyPoint = { x: polygonMaxX + 110, y: centerPoint.y } - break - } - - arrow = new fabric.Polygon(points, { - selectable: false, - name: 'arrow', - fill: 'transparent', - stroke: 'black', - direction: direction, - parent: polygon, - stickeyPoint: stickeyPoint, - }) - - polygon.arrow = arrow - polygon.canvas.add(arrow) - polygon.canvas.renderAll() - drawDirectionStringToArrow(polygon.canvas, 0) -} - -/** - * 방향을 나타낸 화살표에 각도에 따라 글씨 추가 - * @param canvas - * @param compass - */ -export const drawDirectionStringToArrow = (canvas, compass = 0) => { - const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') - - if (arrows.length === 0) { - return - } - - const eastArrows = arrows.filter((arrow) => arrow.direction === 'east') - const westArrows = arrows.filter((arrow) => arrow.direction === 'west') - const northArrows = arrows.filter((arrow) => arrow.direction === 'north') - const southArrows = arrows.filter((arrow) => arrow.direction === 'south') - - let southText = '南' - let eastText = '東' - let westText = '西' - let northText = '北' - - if (compass === 0 || compass === 360) { - // 남,동,서 가능 - // 그대로 - } else if (compass < 45) { - //남(남남동),동(동북동),서(서남서) 가능 - //북(북북서) - southText = '南南東' - eastText = '東北東' - westText = '西南西' - northText = '北北西' - } else if (compass === 45) { - // 남, 서 가능 - // 남(남동) - // 서(남서) - // 북(북서) - // 동(북동) - southText = '南東' - westText = '南西' - northText = '北西' - eastText = '北東' - } else if (compass < 90) { - // 북(서북서) - // 동 (북북동) - // 남(동남동) - // 서(남남서) - northText = '北西北' - eastText = '北北東' - southText = '東南東' - westText = '南南西' - } else if (compass === 90) { - // 동(북) - // 서(남) - // 남(동) - // 북(서) - eastText = '北' - westText = '南' - southText = '東' - northText = '西' - } else if (compass < 135) { - // 남,서,북 가능 - // 동(북북서) - // 서(남남동) - // 남(동북동) - // 북(서남서) - eastText = '北北西' - westText = '南南東' - southText = '東北東' - northText = '西南西' - } else if (compass === 135) { - // 서,북 가능 - - // 서(남동) - // 북(남서) - // 남(북동) - // 동(북서) - - westText = '南東' - northText = '南西' - southText = '北東' - eastText = '北西' - } else if (compass < 180) { - // 북,동,서 가능 - // 북(남남서) - // 동(서북서) - // 남(북북동) - // 서(동남동) - - northText = '南南西' - eastText = '西北西' - southText = '北北東' - westText = '東南東' - } else if (compass === 180) { - // 북,동,서 가능 - // 북(남) - // 동(서) - // 남(북) - // 서(동) - northText = '南' - eastText = '西' - southText = '北' - westText = '東' - } else if (compass < 225) { - // 서,북,동 가능 - // 북(남남동) - // 동(서남서) - // 남(북북서) - // 서(동남동) - northText = '南南東' - eastText = '西南西' - southText = '北北西' - westText = '東南東' - } else if (compass === 225) { - // 북,동 가능 - // 북(남동) - // 동(남서) - // 남(북서) - // 서(북동) - northText = '南東' - eastText = '南西' - southText = '北西' - westText = '北東' - } else if (compass < 270) { - // 북동남 가능 - // 북(동남동) - // 동(남남서) - // 남(서북서) - // 서(북북동) - northText = '東南東' - eastText = '南南西' - southText = '西北西' - westText = '北北東' - } else if (compass === 270) { - // 북동남 가능 - // 북(동) - // 동(남) - // 남(서) - // 서(북) - northText = '東' - eastText = '南' - southText = '西' - westText = '北' - } else if (compass < 315) { - // 북,동,남 가능 - // 북(동북동) - // 동(남남동) - // 남(서남서) - // 서(북북서) - northText = '東北東' - eastText = '南南東' - southText = '西南西' - westText = '北北西' - } else if (compass === 315) { - // 동,남 가능 - // 북(북동) - // 동(남동) - // 남(남서) - // 서(북서) - northText = '北東' - eastText = '南東' - southText = '南西' - westText = '北西' - } else if (compass < 360) { - // 남,동,서 가능 - // 북(북북동) - // 동(동남동) - // 남(남남서) - // 서(서북서) - northText = '北北東' - eastText = '東南東' - southText = '南南西' - westText = '西北西' - } - - clearDirectionText(canvas) - - addTextByArrows(eastArrows, eastText, canvas) - addTextByArrows(westArrows, westText, canvas) - addTextByArrows(northArrows, northText, canvas) - addTextByArrows(southArrows, southText, canvas) -} - -const clearDirectionText = (canvas) => { - const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') - texts.forEach((text) => { - canvas.remove(text) - }) -} - -const addTextByArrows = (arrows, txt, canvas) => { - arrows.forEach((arrow, index) => { - const text = new fabric.Text(`${txt}${index + 1}`, { - fontSize: arrow.parent.fontSize, - fill: 'black', - originX: 'center', - originY: 'center', - name: 'directionText', - selectable: false, - left: arrow.stickeyPoint.x, - top: arrow.stickeyPoint.y, - parent: arrow, - }) - canvas.add(text) - }) -} From fc0a1fd00d64e8b02a211baf73c5ef277a15bff2 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 16:54:15 +0900 Subject: [PATCH 028/139] chore: check 3rd lib MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 안쓰는 라이브러리 제거 - 안쓰늩 컴포넌트 제거 - 코드 정리 --- package.json | 3 - src/app/[locale]/LocaleProvider.js | 11 -- src/app/[locale]/community/archive/page.jsx | 16 --- src/app/[locale]/community/faq/page.jsx | 16 --- src/app/[locale]/community/notice/page.jsx | 16 --- src/app/[locale]/error.jsx | 15 -- src/app/[locale]/floor-plan/page.jsx | 9 -- src/app/[locale]/initSettingsModal/page.jsx | 16 --- src/app/[locale]/intro/page.jsx | 14 -- src/app/[locale]/join/complete/page.jsx | 19 --- src/app/[locale]/join/page.jsx | 5 - src/app/[locale]/layout.js | 42 ------ src/app/[locale]/login/page.jsx | 16 --- src/app/[locale]/management/plan/page.jsx | 16 --- .../[locale]/management/stuff/detail/page.jsx | 19 --- src/app/[locale]/management/stuff/page.jsx | 21 --- .../management/stuff/tempdetail/page.jsx | 15 -- src/app/[locale]/master/company/page.jsx | 16 --- src/app/[locale]/master/price/page.jsx | 16 --- src/app/[locale]/not-found.jsx | 25 ---- src/app/[locale]/page.js | 18 --- src/app/[locale]/playground/page.jsx | 17 --- src/app/[locale]/roof/page.jsx | 16 --- src/app/[locale]/roof2/RoofSelect.jsx | 128 ------------------ src/app/[locale]/roof2/page.jsx | 26 ---- src/app/[locale]/settings/page.jsx | 16 --- src/app/layout.js | 15 +- src/hooks/useToast.js | 35 ----- src/lib/prisma.js | 14 -- yarn.lock | 55 -------- 30 files changed, 3 insertions(+), 663 deletions(-) delete mode 100644 src/app/[locale]/LocaleProvider.js delete mode 100644 src/app/[locale]/community/archive/page.jsx delete mode 100644 src/app/[locale]/community/faq/page.jsx delete mode 100644 src/app/[locale]/community/notice/page.jsx delete mode 100644 src/app/[locale]/error.jsx delete mode 100644 src/app/[locale]/floor-plan/page.jsx delete mode 100644 src/app/[locale]/initSettingsModal/page.jsx delete mode 100644 src/app/[locale]/intro/page.jsx delete mode 100644 src/app/[locale]/join/complete/page.jsx delete mode 100644 src/app/[locale]/join/page.jsx delete mode 100644 src/app/[locale]/layout.js delete mode 100644 src/app/[locale]/login/page.jsx delete mode 100644 src/app/[locale]/management/plan/page.jsx delete mode 100644 src/app/[locale]/management/stuff/detail/page.jsx delete mode 100644 src/app/[locale]/management/stuff/page.jsx delete mode 100644 src/app/[locale]/management/stuff/tempdetail/page.jsx delete mode 100644 src/app/[locale]/master/company/page.jsx delete mode 100644 src/app/[locale]/master/price/page.jsx delete mode 100644 src/app/[locale]/not-found.jsx delete mode 100644 src/app/[locale]/page.js delete mode 100644 src/app/[locale]/playground/page.jsx delete mode 100644 src/app/[locale]/roof/page.jsx delete mode 100644 src/app/[locale]/roof2/RoofSelect.jsx delete mode 100644 src/app/[locale]/roof2/page.jsx delete mode 100644 src/app/[locale]/settings/page.jsx delete mode 100644 src/hooks/useToast.js delete mode 100644 src/lib/prisma.js diff --git a/package.json b/package.json index 4dfef6dd..303e4864 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,6 @@ }, "dependencies": { "@nextui-org/react": "^2.4.2", - "@prisma/client": "^5.18.0", "ag-grid-react": "^32.0.2", "axios": "^1.7.3", "fabric": "^5.3.0", @@ -30,7 +29,6 @@ "react-hook-form": "^7.53.0", "react-icons": "^5.3.0", "react-responsive-modal": "^6.4.2", - "react-toastify": "^10.0.5", "recoil": "^0.7.7", "sweetalert2": "^11.14.1", "sweetalert2-react-content": "^5.0.7", @@ -42,7 +40,6 @@ "dayjs": "^1.11.13", "postcss": "^8", "prettier": "^3.3.3", - "prisma": "^5.18.0", "react-color-palette": "^7.2.2", "react-select": "^5.8.1", "sass": "^1.77.8", diff --git a/src/app/[locale]/LocaleProvider.js b/src/app/[locale]/LocaleProvider.js deleted file mode 100644 index cb4aa5d6..00000000 --- a/src/app/[locale]/LocaleProvider.js +++ /dev/null @@ -1,11 +0,0 @@ -'use client' - -import { I18nProviderClient } from '@/locales/client' - -export function LocaleProvider({ locale, children }) { - return ( - - {children} - - ) -} diff --git a/src/app/[locale]/community/archive/page.jsx b/src/app/[locale]/community/archive/page.jsx deleted file mode 100644 index 6917f228..00000000 --- a/src/app/[locale]/community/archive/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Archive from '@/components/community/Archive' -import { initCheck } from '@/util/session-util' - -export default async function CommunityArchivePage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/community/faq/page.jsx b/src/app/[locale]/community/faq/page.jsx deleted file mode 100644 index 2b9d5452..00000000 --- a/src/app/[locale]/community/faq/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Faq from '@/components/community/Faq' -import { initCheck } from '@/util/session-util' - -export default async function CommunityFaqPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/community/notice/page.jsx b/src/app/[locale]/community/notice/page.jsx deleted file mode 100644 index d2157b20..00000000 --- a/src/app/[locale]/community/notice/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Notice from '@/components/community/Notice' -import { initCheck } from '@/util/session-util' - -export default async function CommunityNoticePage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/error.jsx b/src/app/[locale]/error.jsx deleted file mode 100644 index 07d75e7e..00000000 --- a/src/app/[locale]/error.jsx +++ /dev/null @@ -1,15 +0,0 @@ -'use client' - -export default function ServerError() { - return ( -
-
-
-

500

-

Internal Server Error.

-

We are already working to solve the problem.

-
-
-
- ) -} diff --git a/src/app/[locale]/floor-plan/page.jsx b/src/app/[locale]/floor-plan/page.jsx deleted file mode 100644 index f503099e..00000000 --- a/src/app/[locale]/floor-plan/page.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import FloorPlan from '@/components/floor-plan/FloorPlan' - -export default function FloorPlanPage() { - return ( - <> - - - ) -} diff --git a/src/app/[locale]/initSettingsModal/page.jsx b/src/app/[locale]/initSettingsModal/page.jsx deleted file mode 100644 index a081ef47..00000000 --- a/src/app/[locale]/initSettingsModal/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import InitSettingsModal from '@/components/InitSettingsModal' -import { initCheck } from '@/util/session-util' - -export default async function InitSettingsModalPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/intro/page.jsx b/src/app/[locale]/intro/page.jsx deleted file mode 100644 index 8d560ce5..00000000 --- a/src/app/[locale]/intro/page.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import Intro from '@/components/Intro' -import { initCheck } from '@/util/session-util' - -export default async function IntroPage() { - await initCheck() - - return ( - <> -
- -
- - ) -} diff --git a/src/app/[locale]/join/complete/page.jsx b/src/app/[locale]/join/complete/page.jsx deleted file mode 100644 index 3f9fc462..00000000 --- a/src/app/[locale]/join/complete/page.jsx +++ /dev/null @@ -1,19 +0,0 @@ -'use client' - -import { useMessage } from '@/hooks/useMessage' - -export default function CompletePage() { - const { getMessage } = useMessage() - - return ( - <> -
-

{getMessage('join.complete.title')}

-
{getMessage('join.complete.contents')}
-
- {getMessage('join.complete.email_comment')} : {getMessage('join.complete.email')} -
-
- - ) -} diff --git a/src/app/[locale]/join/page.jsx b/src/app/[locale]/join/page.jsx deleted file mode 100644 index 118a25b4..00000000 --- a/src/app/[locale]/join/page.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import Join from '@/components/auth/Join' - -export default function JoinPage() { - return <>{} -} diff --git a/src/app/[locale]/layout.js b/src/app/[locale]/layout.js deleted file mode 100644 index 018f1ef5..00000000 --- a/src/app/[locale]/layout.js +++ /dev/null @@ -1,42 +0,0 @@ -'use client' - -import { useEffect } from 'react' -import { useRecoilState, useRecoilValue } from 'recoil' -import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { LocaleProvider } from './LocaleProvider' -import { useCurrentLocale } from '@/locales/client' -import ServerError from './error' -import { ErrorBoundary } from 'next/dist/client/components/error-boundary' -import '@/styles/common.scss' - -import KO from '@/locales/ko.json' -import JA from '@/locales/ja.json' - -export default function LocaleLayout({ children }) { - const locale = useCurrentLocale() - const globalLocale = useRecoilValue(globalLocaleStore) - const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) - - useEffect(() => { - console.log(globalLocale) - console.log(sessionStorage.getItem('hi')) - console.log(Object.keys(appMessageState).length) - // if (Object.keys(appMessageState).length === 0) { - if (globalLocale === 'ko') { - setAppMessageState(KO) - } else { - setAppMessageState(JA) - } - // } - }, [globalLocale]) - - return ( - <> - }> - }> - {children} - - - - ) -} diff --git a/src/app/[locale]/login/page.jsx b/src/app/[locale]/login/page.jsx deleted file mode 100644 index 47a23986..00000000 --- a/src/app/[locale]/login/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Login from '@/components/auth/Login' -import { getCurrentLocale } from '@/locales/server' - -export default function LoginPage() { - const currentLocale = getCurrentLocale() - - const loginPageProps = { - currentLocale, - } - - return ( - <> - - - ) -} diff --git a/src/app/[locale]/management/plan/page.jsx b/src/app/[locale]/management/plan/page.jsx deleted file mode 100644 index 5fefa62a..00000000 --- a/src/app/[locale]/management/plan/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Plan from '@/components/management/Plan' -import { initCheck } from '@/util/session-util' - -export default async function ManagementPlanPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/management/stuff/detail/page.jsx b/src/app/[locale]/management/stuff/detail/page.jsx deleted file mode 100644 index 6759b282..00000000 --- a/src/app/[locale]/management/stuff/detail/page.jsx +++ /dev/null @@ -1,19 +0,0 @@ -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/page.jsx b/src/app/[locale]/management/stuff/page.jsx deleted file mode 100644 index 7590a7cf..00000000 --- a/src/app/[locale]/management/stuff/page.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import StuffSearchCondition from '@/components/management/StuffSearchCondition' -import Stuff from '@/components/management/Stuff' -import { initCheck } from '@/util/session-util' -import Hero from '@/components/Hero' -export default async function ManagementStuffPage() { - await initCheck() - - return ( - <> - -
-
- -
-
-
- -
- - ) -} diff --git a/src/app/[locale]/management/stuff/tempdetail/page.jsx b/src/app/[locale]/management/stuff/tempdetail/page.jsx deleted file mode 100644 index 8b84287a..00000000 --- a/src/app/[locale]/management/stuff/tempdetail/page.jsx +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import Hero from '@/components/Hero' -import StuffDetail from '@/components/management/StuffDetail' -export default function ManagementStuffDetailPage() { - return ( - <> -
-

물건정보

-
-
- -
- - ) -} diff --git a/src/app/[locale]/master/company/page.jsx b/src/app/[locale]/master/company/page.jsx deleted file mode 100644 index 15eda41c..00000000 --- a/src/app/[locale]/master/company/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Company from '@/components/master/Company' -import { initCheck } from '@/util/session-util' - -export default async function MasterCompanyPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/master/price/page.jsx b/src/app/[locale]/master/price/page.jsx deleted file mode 100644 index a641d6bb..00000000 --- a/src/app/[locale]/master/price/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Price from '@/components/master/Price' -import { initCheck } from '@/util/session-util' - -export default async function MasterPricePage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/not-found.jsx b/src/app/[locale]/not-found.jsx deleted file mode 100644 index 8127943b..00000000 --- a/src/app/[locale]/not-found.jsx +++ /dev/null @@ -1,25 +0,0 @@ -'use client' - -import Link from 'next/link' - -export default function NotFound() { - return ( -
-
-
-

404

-

Something's missing.

-

- Sorry, we can't find that page. You'll find lots to explore on the home page.{' '} -

- - Back to Homepage - -
-
-
- ) -} diff --git a/src/app/[locale]/page.js b/src/app/[locale]/page.js deleted file mode 100644 index 1b8f2258..00000000 --- a/src/app/[locale]/page.js +++ /dev/null @@ -1,18 +0,0 @@ -import { getSession } from '@/lib/authActions' -import MainPage from '@/components/Main' - -export default async function page() { - const session = await getSession() - - const mainPageProps = { - isLoggedIn: session?.isLoggedIn, - } - - return ( - <> -
- -
- - ) -} diff --git a/src/app/[locale]/playground/page.jsx b/src/app/[locale]/playground/page.jsx deleted file mode 100644 index 66d83c34..00000000 --- a/src/app/[locale]/playground/page.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import Playground from '@/components/Playground' -import { initCheck } from '@/util/session-util' - -export default async function PlaygroundPage() { - // const { session } = await checkSession() - - // if (!session.isLoggedIn) { - // redirect('/login') - // } - await initCheck() - - return ( - <> - - - ) -} diff --git a/src/app/[locale]/roof/page.jsx b/src/app/[locale]/roof/page.jsx deleted file mode 100644 index f5b8e611..00000000 --- a/src/app/[locale]/roof/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Roof from '@/components/Roof' -import { initCheck } from '@/util/session-util' - -export default async function RoofPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/[locale]/roof2/RoofSelect.jsx b/src/app/[locale]/roof2/RoofSelect.jsx deleted file mode 100644 index d759398b..00000000 --- a/src/app/[locale]/roof2/RoofSelect.jsx +++ /dev/null @@ -1,128 +0,0 @@ -'use client' - -import { Select, SelectItem } from '@nextui-org/react' -import { useEffect, useState } from 'react' -import { useAxios } from '@/hooks/useAxios' - -export default function RoofSelect() { - const [roofMaterials, setRoofMaterials] = useState([]) - const [manufacturers, setManufacturers] = useState([]) - const [trestles, setTrestles] = useState([]) - const [modules, setModules] = useState([]) - const [originTrestles, setOriginTrestles] = useState([]) - - const [roofMaterialId, setRoofMaterialId] = useState(null) - const [manufacturerId, setManufacturerId] = useState(null) - const [trestleId, setTrestleId] = useState(null) - - const { get } = useAxios() - - useEffect(() => { - get({ url: '/api/roof-material/roof-material-infos' }).then((res) => { - //TODO: error handling - if (!res) return - - setRoofMaterials(res) - }) - }, []) - - useEffect(() => { - if (!roofMaterialId) { - return - } - - get({ url: `/api/roof-material/roof-material-infos/${roofMaterialId}/trestles` }).then((res) => { - if (res.length === 0) { - return - } - setOriginTrestles(res) - const manufactural = res.map((trestle) => { - return { id: trestle.manufacturerId, name: trestle.manufacturerName } - }) - // Remove duplicates - const uniqueManufactural = Array.from(new Set(manufactural.map((a) => a.id))).map((id) => { - return manufactural.find((a) => a.id === id) - }) - - setManufacturers(uniqueManufactural) - }) - }, [roofMaterialId]) - - useEffect(() => { - if (!manufacturerId) { - return - } - - const trestles = originTrestles.filter((trestle) => trestle.manufacturerId === manufacturerId) - setTrestles(trestles) - }, [manufacturerId]) - - useEffect(() => { - if (!trestleId) { - return - } - get({ url: `/api/module/module-infos?roofMaterialId=${roofMaterialId}&trestleId=${trestleId}` }).then((res) => { - if (res.length === 0) { - return - } - setModules(res) - }) - }, [trestleId]) - - const handleRoofMaterialOnChange = (e) => { - const roofMaterialId = e.target.value - setRoofMaterialId(roofMaterialId) - setManufacturers([]) - setManufacturerId(null) - setTrestleId(null) - setTrestles([]) - setModules([]) - } - - const handleManufacturersOnChange = (e) => { - const manufacturerId = Number(e.target.value) - setTrestles([]) - setManufacturerId(manufacturerId) - setTrestleId(null) - setModules([]) - } - - const handleTrestlesOnChange = (e) => { - const trestleId = Number(e.target.value) - setTrestleId(trestleId) - setModules([]) - } - - return ( -
- {roofMaterials.length > 0 && ( - - )} - {manufacturers.length > 0 && ( - - )} - {trestles.length > 0 && ( - - )} - {modules.length > 0 && ( - - )} -
- ) -} diff --git a/src/app/[locale]/roof2/page.jsx b/src/app/[locale]/roof2/page.jsx deleted file mode 100644 index 72881d11..00000000 --- a/src/app/[locale]/roof2/page.jsx +++ /dev/null @@ -1,26 +0,0 @@ -import Roof2 from '@/components/Roof2' -import RoofSelect from '@/app/[locale]/roof2/RoofSelect' -import { initCheck } from '@/util/session-util' - -export default async function Roof2Page() { - const session = await initCheck() - const roof2Props = { - name: session.name || '', - userId: session.userId || '', - email: session.email || '', - isLoggedIn: session.isLoggedIn, - } - - return ( - <> -
-
- -
-
-
- -
- - ) -} diff --git a/src/app/[locale]/settings/page.jsx b/src/app/[locale]/settings/page.jsx deleted file mode 100644 index 797c024c..00000000 --- a/src/app/[locale]/settings/page.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import Hero from '@/components/Hero' -import Settings from '@/components/Settings' -import { initCheck } from '@/util/session-util' - -export default async function SettingsPage() { - await initCheck() - - return ( - <> - -
- -
- - ) -} diff --git a/src/app/layout.js b/src/app/layout.js index 424c74ef..32803812 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -1,25 +1,19 @@ -// import { Inter } from 'next/font/google' - import { headers } from 'next/headers' import { redirect } from 'next/navigation' import { getSession } from '@/lib/authActions' import RecoilRootWrapper from './RecoilWrapper' -import { ToastContainer } from 'react-toastify' - import { QcastProvider } from './QcastProvider' import Header from '@/components/header/Header' import QModal from '@/components/common/modal/QModal' - -import './globals.css' -import '../styles/style.scss' -import '../styles/contents.scss' import Dimmed from '@/components/ui/Dimmed' import SessionProvider from './SessionProvider' import LocaleSwitch from '@/components/LocaleSwitch' import PopupManager from '@/components/common/popupManager/PopupManager' -// const inter = Inter({ subsets: ['latin'] }) +import './globals.css' +import '../styles/style.scss' +import '../styles/contents.scss' export const metadata = { title: 'Create Next App', @@ -30,8 +24,6 @@ export default async function RootLayout({ children }) { const headersList = headers() const headerPathname = headersList.get('x-pathname') || '' - // console.log('headerPathname:', headerPathname) - // const isLoggedIn = await checkSession() const session = await getSession() console.log('session[layout]:', session) @@ -85,7 +77,6 @@ export default async function RootLayout({ children }) {
)} - diff --git a/src/hooks/useToast.js b/src/hooks/useToast.js deleted file mode 100644 index d604c42d..00000000 --- a/src/hooks/useToast.js +++ /dev/null @@ -1,35 +0,0 @@ -import { toast } from 'react-toastify' - -const toastDefaultOptions = { - position: 'top-right', - autoClose: 3000, - draggable: false, - hideProgressBar: false, - rtl: false, - pauseOnFocusLoss: true, - pauseOnHover: true, - theme: 'light', - limit: 2, - closeOnClick: true, -} - -const toastUp = (props) => { - // type TypeOptions = 'info' | 'success' | 'warning' | 'error' | 'default' - const { message, type = 'info', options } = props - const customOptions = { ...toastDefaultOptions, ...options } - - switch (type) { - case 'info': - return toast.info(message, customOptions) - case 'success': - return toast.success(message, customOptions) - case 'warning': - return toast.warn(message, customOptions) - case 'error': - return toast.error(message, customOptions) - default: - return toast(message, customOptions) - } -} - -export { toastUp } diff --git a/src/lib/prisma.js b/src/lib/prisma.js deleted file mode 100644 index aa946098..00000000 --- a/src/lib/prisma.js +++ /dev/null @@ -1,14 +0,0 @@ -import { PrismaClient } from '@prisma/client' - -let prisma - -if (process.env.NODE_ENV === 'production') { - prisma = new PrismaClient() -} else { - if (!global.prisma) { - global.prisma = new PrismaClient() - } - prisma = global.prisma -} - -export default prisma diff --git a/yarn.lock b/yarn.lock index c8c53b57..bf4e65b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1538,47 +1538,6 @@ resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz" integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== -"@prisma/client@^5.18.0": - version "5.18.0" - resolved "https://registry.npmjs.org/@prisma/client/-/client-5.18.0.tgz" - integrity sha512-BWivkLh+af1kqC89zCJYkHsRcyWsM8/JHpsDMM76DjP3ZdEquJhXa4IeX+HkWPnwJ5FanxEJFZZDTWiDs/Kvyw== - -"@prisma/debug@5.18.0": - version "5.18.0" - resolved "https://registry.npmjs.org/@prisma/debug/-/debug-5.18.0.tgz" - integrity sha512-f+ZvpTLidSo3LMJxQPVgAxdAjzv5OpzAo/eF8qZqbwvgi2F5cTOI9XCpdRzJYA0iGfajjwjOKKrVq64vkxEfUw== - -"@prisma/engines-version@5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169": - version "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169" - resolved "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169.tgz" - integrity sha512-a/+LpJj8vYU3nmtkg+N3X51ddbt35yYrRe8wqHTJtYQt7l1f8kjIBcCs6sHJvodW/EK5XGvboOiwm47fmNrbgg== - -"@prisma/engines@5.18.0": - version "5.18.0" - resolved "https://registry.npmjs.org/@prisma/engines/-/engines-5.18.0.tgz" - integrity sha512-ofmpGLeJ2q2P0wa/XaEgTnX/IsLnvSp/gZts0zjgLNdBhfuj2lowOOPmDcfKljLQUXMvAek3lw5T01kHmCG8rg== - dependencies: - "@prisma/debug" "5.18.0" - "@prisma/engines-version" "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169" - "@prisma/fetch-engine" "5.18.0" - "@prisma/get-platform" "5.18.0" - -"@prisma/fetch-engine@5.18.0": - version "5.18.0" - resolved "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.18.0.tgz" - integrity sha512-I/3u0x2n31rGaAuBRx2YK4eB7R/1zCuayo2DGwSpGyrJWsZesrV7QVw7ND0/Suxeo/vLkJ5OwuBqHoCxvTHpOg== - dependencies: - "@prisma/debug" "5.18.0" - "@prisma/engines-version" "5.18.0-25.4c784e32044a8a016d99474bd02a3b6123742169" - "@prisma/get-platform" "5.18.0" - -"@prisma/get-platform@5.18.0": - version "5.18.0" - resolved "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.18.0.tgz" - integrity sha512-Tk+m7+uhqcKDgnMnFN0lRiH7Ewea0OEsZZs9pqXa7i3+7svS3FSCqDBCaM9x5fmhhkufiG0BtunJVDka+46DlA== - dependencies: - "@prisma/debug" "5.18.0" - "@react-aria/breadcrumbs@3.5.13": version "3.5.13" resolved "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.13.tgz" @@ -5810,13 +5769,6 @@ prettier@^3.3.3: resolved "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz" integrity sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew== -prisma@^5.18.0: - version "5.18.0" - resolved "https://registry.npmjs.org/prisma/-/prisma-5.18.0.tgz" - integrity sha512-+TrSIxZsh64OPOmaSgVPH7ALL9dfU0jceYaMJXsNrTkFHO7/3RANi5K2ZiPB1De9+KDxCWn7jvRq8y8pvk+o9g== - dependencies: - "@prisma/engines" "5.18.0" - process@^0.11.10: version "0.11.10" resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" @@ -5998,13 +5950,6 @@ react-textarea-autosize@^8.5.3: use-composed-ref "^1.3.0" use-latest "^1.2.1" -react-toastify@^10.0.5: - version "10.0.5" - resolved "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz" - integrity sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw== - dependencies: - clsx "^2.1.0" - react-transition-group@^4.3.0: version "4.4.5" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.5.tgz#e53d4e3f3344da8521489fbef8f2581d42becdd1" From 220e6fe8c26ed43ce8e89be399dd4e49eddd71dd Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 21 Oct 2024 16:59:02 +0900 Subject: [PATCH 029/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/management/stuff/detail/page.jsx | 28 +---- src/app/management/stuff/page.jsx | 22 +--- src/app/management/stuff/tempdetail/page.jsx | 28 +---- src/components/management/StuffDetail.jsx | 87 ++++++------- src/components/management/StuffSubHeader.jsx | 81 ++++++++++++ .../management/popup/PlanRequestPop.jsx | 116 ++++++++++-------- src/locales/ja.json | 1 + src/locales/ko.json | 1 + src/store/planReqAtom.js | 22 ---- 9 files changed, 195 insertions(+), 191 deletions(-) create mode 100644 src/components/management/StuffSubHeader.jsx delete mode 100644 src/store/planReqAtom.js diff --git a/src/app/management/stuff/detail/page.jsx b/src/app/management/stuff/detail/page.jsx index 8783e17e..8c7dd731 100644 --- a/src/app/management/stuff/detail/page.jsx +++ b/src/app/management/stuff/detail/page.jsx @@ -1,36 +1,12 @@ import React from 'react' -import Link from 'next/link' -import Image from 'next/image' import '@/styles/contents.scss' +import StuffSubHeader from '@/components/management/StuffSubHeader' import StuffHeader from '@/components/management/StuffHeader' import StuffDetail from '@/components/management/StuffDetail' export default function ManagementStuffDetailPage() { return ( <> -
-
-
    -
  • - - 商品情報 - -
  • -
-
    -
  • - - react - -
  • -
  • - 物品及び図面管理 -
  • -
  • - 商品情報 -
  • -
-
-
+
diff --git a/src/app/management/stuff/page.jsx b/src/app/management/stuff/page.jsx index 9c1abdfb..21c6bb78 100644 --- a/src/app/management/stuff/page.jsx +++ b/src/app/management/stuff/page.jsx @@ -1,31 +1,13 @@ import StuffSearchCondition from '@/components/management/StuffSearchCondition' import Stuff from '@/components/management/Stuff' +import StuffSubHeader from '@/components/management/StuffSubHeader' import { initCheck } from '@/util/session-util' -import Image from 'next/image' import '@/styles/contents.scss' export default async function ManagementStuffPage() { await initCheck() - return ( <> -
-
-

物品及び図面管理

-
    -
  • - - react - -
  • -
  • - 物品及び図面管理 -
  • -
  • - 新規物件登録 -
  • -
-
-
+
diff --git a/src/app/management/stuff/tempdetail/page.jsx b/src/app/management/stuff/tempdetail/page.jsx index d122d717..447194fc 100644 --- a/src/app/management/stuff/tempdetail/page.jsx +++ b/src/app/management/stuff/tempdetail/page.jsx @@ -1,35 +1,11 @@ import React from 'react' -import Link from 'next/link' -import Image from 'next/image' +import StuffSubHeader from '@/components/management/StuffSubHeader' import '@/styles/contents.scss' import StuffDetail from '@/components/management/StuffDetail' export default function ManagementStuffDetailPage() { return ( <> -
-
-
    -
  • - - 商品情報 - -
  • -
-
    -
  • - - react - -
  • -
  • - 物品及び図面管理 -
  • -
  • - 商品情報 -
  • -
-
-
+
diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 6800a5e8..04ba662a 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -30,6 +30,7 @@ export default function StuffDetail() { //form const formInitValue = { // 물건번호 T...(임시) R...(진짜) + planReqNo: '', //설계의뢰No dispCompanyName: '', //담당자 objectStatusId: '0', //물건구분(신축:0 기축 : 1) objectName: '', //물건명 @@ -70,7 +71,6 @@ export default function StuffDetail() { const [areaIdList, setAreaIdList] = useState([]) //발전시뮬레이션 리스트 - // const [windSpeedList, setWindSpeedList] = useState([]) //기준풍속 리스트 팝업으로이동 const [isFormValid, setIsFormValid] = useState(false) //임시저장, 진짜저장 버튼 컨트롤 const [showAddressButtonValid, setShowAddressButtonValid] = useState(false) //주소검색팝업 활성화 컨트롤 const [showDesignRequestButtonValid, setShowDesignRequestButtonValid] = useState(false) //설계의뢰팝업 활성화 컨트롤 @@ -109,7 +109,7 @@ export default function StuffDetail() { // 임시 1차점 판매점코드 saleStoreId=201TES01 // T01 //1차점 : X167 T01 - // get({ url: `/api/object/saleStore/TEMP02/list` }).then((res) => { + // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') @@ -142,8 +142,8 @@ export default function StuffDetail() { // 임시 1차점 판매점코드 saleStoreId=201TES01 // T01 //1차점 : X167 - get({ url: `/api/object/saleStore/T01/list` }).then((res) => { - // get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { + get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') @@ -208,7 +208,7 @@ export default function StuffDetail() { //팝업에서 넘어온 우편정보 const setZipInfo = (info) => { - // console.log('팝업에서 넘어온 데이타::::::::', info) + console.log('팝업에서 넘어온 우편 데이타::::::::', info) setPrefValue(info.prefId) form.setValue('prefId', info.prefId) form.setValue('prefName', info.address1) @@ -218,14 +218,33 @@ export default function StuffDetail() { //팝업에서 넘어온 설계의뢰 정보로 바꾸기 const setPlanReqInfo = (info) => { - console.log('팝업에서 넘어온 설계의뢰 정보::: ', info) - //building : 신축 기축 - //planReqName : 물건명 - //zipNo : 우편번호 - //도도부현 :address1 주소 : address2 미세팅 - //기준풍속 팝업열려면 setPrefValue(info.prefId) 필요 - //기준풍속 : - // form.setValue('dispCompanyName', info.planReqName) + form.setValue('planReqNo', info.planReqNo) + form.setValue('objectStatusId', info.building) + form.setValue('objectName', info.planReqName) + form.setValue('zipNo', info.zipNo) + form.setValue('address', info.address2) + // console.log('팝업에서 넘어온 설계의뢰 정보::: ', info) + + prefCodeList.map((row) => { + if (row.prefName == info.address1) { + setPrefValue(row.prefId) + form.setValue('prefId', row.prefId) + form.setValue('prefName', info.address1) + } + }) + + if (info.saleStoreLevel === '1') { + setSelOptions(info.saleStoreId) + form.setValue('saleStoreId', info.saleStoreName) + } else { + console.log('설계의뢰 정보가 2차점인경우::::::::::::', info) + } + form.setValue('windSpeed', info.windSpeed) + form.setValue('verticalSnowCover', info.verticalSnowCover) + form.setValue('surfaceType', info.surfaceType) + //설치 높이 installHeight + + form.setValue('remarks', info.remarks) } //팝업에서 넘어온 바람정보 @@ -475,7 +494,7 @@ export default function StuffDetail() {
- +
@@ -630,13 +654,6 @@ export default function StuffDetail() {
{prefCodeList?.length > 0 && ( - // 0 ? false : true} - onChange={handleAreaIdOnChange} - > - {areaIdList.map((row) => { - return ( - - ) - })} - - */}
- {/*
- -
*/} {getMessage('stuff.detail.windSpeedSpan')} )} - + diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx new file mode 100644 index 00000000..1b10a149 --- /dev/null +++ b/src/components/management/StuffSubHeader.jsx @@ -0,0 +1,81 @@ +'use client' + +import { useEffect } from 'react' +import Link from 'next/link' +import Image from 'next/image' +import { useMessage } from '@/hooks/useMessage' +import { useRouter, useSearchParams } from 'next/navigation' +import { stuffSearchState } from '@/store/stuffAtom' +import { useSetRecoilState } from 'recoil' + +export default function StuffSubHeader({ type }) { + const { getMessage } = useMessage() + const router = useRouter() + + const setSchObjectNo = useSetRecoilState(stuffSearchState) + useEffect(() => { + window.scrollTo(0, 0) + }, []) + + const searchParams = useSearchParams() + const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set + + // url에 물건번호로 도면작성화면으로 이동 + const moveFloorPlan = () => { + setSchObjectNo(objectNo) + + router.push('/floor-plan') + } + + return ( +
+
+ {type === 'list' && ( + +

{getMessage('header.menus.management')}

+ + )} + {type === 'temp' && ( +
    +
  • + + {getMessage('stuff.temp.subTitle')} + +
  • +
+ )} + {type === 'detail' && ( + + )} + + {type !== 'detail' && ( +
    +
  • + + react + +
  • +
  • + {getMessage('header.menus.management')} +
  • +
  • + {getMessage('header.menus.management.stuff')} +
  • +
+ )} +
+
+ ) +} diff --git a/src/components/management/popup/PlanRequestPop.jsx b/src/components/management/popup/PlanRequestPop.jsx index ab2a836c..53d30447 100644 --- a/src/components/management/popup/PlanRequestPop.jsx +++ b/src/components/management/popup/PlanRequestPop.jsx @@ -1,16 +1,12 @@ -import React, { useState, useRef, useEffect } from 'react' -import { useForm } from 'react-hook-form' +import React, { useState, useRef } from 'react' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' -import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' -import FindAddressPopQGrid from './FindAddressPopQGrid' +import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' import { isNotEmptyArray } from '@/util/common-utils' import SingleDatePicker from '@/components/common/datepicker/SingleDatePicker' import dayjs from 'dayjs' import PlanRequestPopQGrid from './PlanRequestPopQGrid' -import { sessionStore } from '@/store/commonAtom' -import { planReqSearchState } from '@/store/planReqAtom' import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' import Select from 'react-select' @@ -24,7 +20,7 @@ export default function PlanRequestPop(props) { const [planReqObject, setPlanReqObject] = useState({}) - const { get, promiseGet } = useAxios(globalLocaleState) + const { promiseGet } = useAxios(globalLocaleState) const { getMessage } = useMessage() //Select ref @@ -43,9 +39,6 @@ export default function PlanRequestPop(props) { setStartDate: setEndDate, } - const resetPlanReqRecoil = useResetRecoilState(planReqSearchState) - - const [planReqSearch, setPlanReqSearch] = useRecoilState(planReqSearchState) const [schPlanReqNo, setSchPlanReqNo] = useState('') //설계의뢰번호 const [schTitle, setSchTitle] = useState('') //안건명 const [schAddress, setSchAddress] = useState('') //도도부현 @@ -66,7 +59,6 @@ export default function PlanRequestPop(props) { setEndDate(dayjs(new Date()).format('YYYY-MM-DD')) setSchPlanStatCd('') handleClear() //셀렉트 자동완성 초기화 - resetPlanReqRecoil() } //셀렉트 자동완성 초기화 @@ -82,22 +74,12 @@ export default function PlanRequestPop(props) { // console.log('E::::::::', key) if (isObjectNotEmpty(key)) { setSchPlanStatCd(key.value) - setPlanReqSearch({ - ...planReqSearch, - schPlanStatCd: key.value, - }) } else { //X누름 setSchPlanStatCd('') - setPlanReqSearch({ ...planReqSearch, schPlanStatCd: '' }) } } - useEffect(() => { - setStartDate(planReqSearch?.schStartDt ? planReqSearch.schStartDt : dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD')) - setEndDate(planReqSearch?.schEndDt ? planReqSearch.schEndDt : dayjs(new Date()).format('YYYY-MM-DD')) - }, [planReqSearch]) - // 조회 const onSubmit = (page, type) => { const params = { @@ -105,13 +87,13 @@ export default function PlanRequestPop(props) { // saleStoreLevel: '1', saleStoreId: props?.otherSaleStoreId ? props.otherSaleStoreId : props.saleStoreId, saleStoreLevel: props?.otherSaleStoreLevel ? props.otherSaleStoreLevel : props.saleStoreLevel, - schPlanReqNo: planReqSearch?.schPlanReqNo ? planReqSearch.schPlanReqNo : schPlanReqNo, - schTitle: planReqSearch?.schTitle ? planReqSearch.schTitle : schTitle, - schAddress: planReqSearch?.schAddress ? planReqSearch.schAddress : schAddress, - schSaleStoreName: planReqSearch?.schSaleStoreName ? planReqSearch.schSaleStoreName : schSaleStoreName, - schPlanReqName: planReqSearch?.schPlanReqName ? planReqSearch.schPlanReqName : schPlanReqName, - schPlanStatCd: planReqSearch?.schPlanStatCd ? planReqSearch.schPlanStatCd : schPlanStatCd, - schDateGbn: planReqSearch?.schDateGbn ? planReqSearch.schDateGbn : schDateGbn, + schPlanReqNo: schPlanReqNo, + schTitle: schTitle, + schAddress: schAddress, + schSaleStoreName: schSaleStoreName, + schPlanReqName: schPlanReqName, + schPlanStatCd: schPlanStatCd, + schDateGbn: schDateGbn, schStartDt: dayjs(startDate).format('YYYY-MM-DD'), schEndDt: dayjs(endDate).format('YYYY-MM-DD'), startRow: type === 'S' ? (1 - 1) * pageSize + 1 : (page - 1) * pageSize + 1, @@ -122,7 +104,6 @@ export default function PlanRequestPop(props) { } else { setPageNo(page) } - // console.log(params) const apiUrl = `/api/object/planReq/list?${queryStringFormatter(params)}` promiseGet({ url: apiUrl }).then((res) => { @@ -142,16 +123,51 @@ export default function PlanRequestPop(props) { } // 페이징 현재페이지 변경 const handleChangePage = (page) => { - setPlanReqSearch({ - ...planReqSearch, - startRow: (page - 1) * pageSize + 1, - endRow: page * pageSize, - }) setPageNo(page) onSubmit(page, 'P') } + //페이지 갯수 변경 이벤트 + const onChangePerPage = (e) => { + const params = { + // saleStoreId: 'T100', + // saleStoreLevel: '1', + saleStoreId: props?.otherSaleStoreId ? props.otherSaleStoreId : props.saleStoreId, + saleStoreLevel: props?.otherSaleStoreLevel ? props.otherSaleStoreLevel : props.saleStoreLevel, + schTitle: schTitle, + schAddress: schAddress, + schPlanReqNo: schPlanReqNo, + schSaleStoreName: schSaleStoreName, + schPlanReqName: schPlanReqName, + schPlanStatCd: schPlanStatCd, + schDateGbn: schDateGbn, + schStartDt: dayjs(startDate).format('YYYY-MM-DD'), + schEndDt: dayjs(endDate).format('YYYY-MM-DD'), + startRow: (1 - 1) * e.target.value + 1, + endRow: 1 * e.target.value, + } + + setPageSize(e.target.value) + setPageNo(1) + + const apiUrl = `/api/object/planReq/list?${queryStringFormatter(params)}` + promiseGet({ url: apiUrl }).then((res) => { + if (res.status === 200) { + if (isNotEmptyArray(res.data.data)) { + setGridProps({ ...gridProps, gridData: res.data.data, gridCount: res.data.data[0].totCnt }) + setTotalCount(res.data.data[0].totCnt) + } else { + setGridProps({ ...gridProps, gridData: [], gridCount: 0 }) + setTotalCount(0) + } + } else { + setGridProps({ ...gridProps, gridData: [], gridCount: 0 }) + setTotalCount(0) + } + }) + } + const [gridProps, setGridProps] = useState({ gridData: [], isPageable: false, @@ -292,10 +308,9 @@ export default function PlanRequestPop(props) { { setSchPlanReqNo(e.target.value) - setPlanReqSearch({ ...planReqSearch, schPlanReqNo: e.target.value }) }} />
@@ -306,10 +321,9 @@ export default function PlanRequestPop(props) { { setSchTitle(e.target.value) - setPlanReqSearch({ ...planReqSearch, schTitle: e.target.value }) }} />
@@ -320,10 +334,9 @@ export default function PlanRequestPop(props) { { setSchAddress(e.target.value) - setPlanReqSearch({ ...planReqSearch, schAddress: e.target.value }) }} />
@@ -336,10 +349,9 @@ export default function PlanRequestPop(props) { { setSchSaleStoreName(e.target.value) - setPlanReqSearch({ ...planReqSearch, schSaleStoreName: e.target.value }) }} />
@@ -350,10 +362,9 @@ export default function PlanRequestPop(props) { { setSchPlanReqName(e.target.value) - setPlanReqSearch({ ...planReqSearch, schPlanReqName: e.target.value }) }} />
@@ -386,11 +397,10 @@ export default function PlanRequestPop(props) { type="radio" name="radio04" id="ra07" - checked={planReqSearch?.schDateGbn === 'S' ? true : false} + checked={schDateGbn === 'S' ? true : false} value={'S'} onChange={(e) => { setSchDateGbn(e.target.value) - setPlanReqSearch({ ...planReqSearch, schDateGbn: e.target.value }) }} /> @@ -400,11 +410,10 @@ export default function PlanRequestPop(props) { type="radio" name="radio04" id="ra08" - checked={planReqSearch?.schDateGbn === 'R' ? true : false} + checked={schDateGbn === 'R' ? true : false} value={'R'} onChange={(e) => { setSchDateGbn(e.target.value) - setPlanReqSearch({ ...planReqSearch, schDateGbn: e.target.value }) }} /> @@ -427,7 +436,16 @@ export default function PlanRequestPop(props) {
-
Plan List
+
+
Plan List
+
+ +
+
diff --git a/src/locales/ja.json b/src/locales/ja.json index b5d24361..20fea301 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -459,6 +459,7 @@ "stuff.addressPopup.btn1": "閉じる", "stuff.addressPopup.btn2": "住所適用", "stuff.planReqPopup.title": "設計依頼のインポート", + "stuff.temp.subTitle": "商品情報", "stuff.detail.required": "必須入力項目", "stuff.detail.planReqNo": "設計依頼No.", "stuff.detail.dispCompanyName": "担当者", diff --git a/src/locales/ko.json b/src/locales/ko.json index d46633ea..b853a3d0 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -464,6 +464,7 @@ "stuff.addressPopup.btn1": "닫기", "stuff.addressPopup.btn2": "주소적용", "stuff.planReqPopup.title": "설계의뢰 불러오기", + "stuff.temp.subTitle" : "물건정보", "stuff.detail.required": "필수 입력항목", "stuff.detail.planReqNo": "설계의뢰No.", "stuff.detail.dispCompanyName": "담당자", diff --git a/src/store/planReqAtom.js b/src/store/planReqAtom.js deleted file mode 100644 index fddf1374..00000000 --- a/src/store/planReqAtom.js +++ /dev/null @@ -1,22 +0,0 @@ -import { atom } from 'recoil' -import dayjs from 'dayjs' -import { v1 } from 'uuid' -export const planReqSearchState = atom({ - key: `planReqSearchState/${v1()}`, - default: { - saleStoreId: '', //판매점ID 세션 - saleStoreLevel: '', //판매점레벨 세션 - schPlanReqNo: '', //설계의뢰 번호 - schTitle: '', //안건명 - schAddress: '', //도도부현 - schSaleStoreName: '', //판매대리점명 - schPlanReqName: '', //의뢰자명 - schPlanStatCd: '', //상태코드 - schDateGbn: 'S', //기간구분코드(S/R) - schStartDt: dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD'), //시작일 - schEndDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일 - startRow: 1, - endRow: 20, - }, - dangerouslyAllowMutability: true, -}) From 5a043c057031a1d3e189ea6d3b4cc734c15e6990 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 17:09:23 +0900 Subject: [PATCH 030/139] Auto stash before merge of "dev" and "origin/dev" --- src/app/community/archive/page.jsx | 3 -- src/app/community/faq/page.jsx | 3 -- src/app/community/notice/page.jsx | 3 -- src/app/initSettingsModal/page.jsx | 3 -- src/app/intro/page.jsx | 2 - src/app/management/plan/page.jsx | 3 -- src/app/master/company/page.jsx | 3 -- src/app/master/price/page.jsx | 3 -- src/app/playground/page.jsx | 8 ---- src/app/roof/page.jsx | 3 -- src/app/settings/page.jsx | 3 -- src/lib/canvas.js | 60 +++++++++++++++--------------- 12 files changed, 30 insertions(+), 67 deletions(-) diff --git a/src/app/community/archive/page.jsx b/src/app/community/archive/page.jsx index 308e02f3..eee23c36 100644 --- a/src/app/community/archive/page.jsx +++ b/src/app/community/archive/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Archive from '@/components/community/Archive' -import { initCheck } from '@/util/session-util' export default async function CommunityArchivePage() { - await initCheck() - return ( <> diff --git a/src/app/community/faq/page.jsx b/src/app/community/faq/page.jsx index 054f9007..cf1c1941 100644 --- a/src/app/community/faq/page.jsx +++ b/src/app/community/faq/page.jsx @@ -1,9 +1,6 @@ import Faq from '@/components/community/Faq' -import { initCheck } from '@/util/session-util' export default async function CommunityFaqPage() { - await initCheck() - return ( <> diff --git a/src/app/community/notice/page.jsx b/src/app/community/notice/page.jsx index a3453e64..c6d407e2 100644 --- a/src/app/community/notice/page.jsx +++ b/src/app/community/notice/page.jsx @@ -1,9 +1,6 @@ import Notice from '@/components/community/Notice' -import { initCheck } from '@/util/session-util' export default async function CommunityNoticePage() { - await initCheck() - return ( <> diff --git a/src/app/initSettingsModal/page.jsx b/src/app/initSettingsModal/page.jsx index a081ef47..fc51b5cc 100644 --- a/src/app/initSettingsModal/page.jsx +++ b/src/app/initSettingsModal/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import InitSettingsModal from '@/components/InitSettingsModal' -import { initCheck } from '@/util/session-util' export default async function InitSettingsModalPage() { - await initCheck() - return ( <> diff --git a/src/app/intro/page.jsx b/src/app/intro/page.jsx index 8d560ce5..ebf1081b 100644 --- a/src/app/intro/page.jsx +++ b/src/app/intro/page.jsx @@ -2,8 +2,6 @@ import Intro from '@/components/Intro' import { initCheck } from '@/util/session-util' export default async function IntroPage() { - await initCheck() - return ( <>
diff --git a/src/app/management/plan/page.jsx b/src/app/management/plan/page.jsx index 5fefa62a..51d67116 100644 --- a/src/app/management/plan/page.jsx +++ b/src/app/management/plan/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Plan from '@/components/management/Plan' -import { initCheck } from '@/util/session-util' export default async function ManagementPlanPage() { - await initCheck() - return ( <> diff --git a/src/app/master/company/page.jsx b/src/app/master/company/page.jsx index 15eda41c..968452e8 100644 --- a/src/app/master/company/page.jsx +++ b/src/app/master/company/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Company from '@/components/master/Company' -import { initCheck } from '@/util/session-util' export default async function MasterCompanyPage() { - await initCheck() - return ( <> diff --git a/src/app/master/price/page.jsx b/src/app/master/price/page.jsx index a641d6bb..57fa0bd2 100644 --- a/src/app/master/price/page.jsx +++ b/src/app/master/price/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Price from '@/components/master/Price' -import { initCheck } from '@/util/session-util' export default async function MasterPricePage() { - await initCheck() - return ( <> diff --git a/src/app/playground/page.jsx b/src/app/playground/page.jsx index 66d83c34..3a3ad1d1 100644 --- a/src/app/playground/page.jsx +++ b/src/app/playground/page.jsx @@ -1,14 +1,6 @@ import Playground from '@/components/Playground' -import { initCheck } from '@/util/session-util' export default async function PlaygroundPage() { - // const { session } = await checkSession() - - // if (!session.isLoggedIn) { - // redirect('/login') - // } - await initCheck() - return ( <> diff --git a/src/app/roof/page.jsx b/src/app/roof/page.jsx index f5b8e611..960ffa89 100644 --- a/src/app/roof/page.jsx +++ b/src/app/roof/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Roof from '@/components/Roof' -import { initCheck } from '@/util/session-util' export default async function RoofPage() { - await initCheck() - return ( <> diff --git a/src/app/settings/page.jsx b/src/app/settings/page.jsx index 797c024c..ab714682 100644 --- a/src/app/settings/page.jsx +++ b/src/app/settings/page.jsx @@ -1,10 +1,7 @@ import Hero from '@/components/Hero' import Settings from '@/components/Settings' -import { initCheck } from '@/util/session-util' export default async function SettingsPage() { - await initCheck() - return ( <> diff --git a/src/lib/canvas.js b/src/lib/canvas.js index 5bd6b419..f8855e33 100644 --- a/src/lib/canvas.js +++ b/src/lib/canvas.js @@ -1,43 +1,43 @@ 'use server' -import { PrismaClient } from '@prisma/client' +// import { PrismaClient } from '@prisma/client' import fs from 'fs/promises' -const prisma = new PrismaClient() +// const prisma = new PrismaClient() const imagePath = 'public/canvasState' -export const getTests = () => { - return prisma.test.findMany() -} +// export const getTests = () => { +// return prisma.test.findMany() +// } -export const insertTest = async (param) => { - return prisma.test.create({ - data: { - content: param, - }, - }) -} +// export const insertTest = async (param) => { +// return prisma.test.create({ +// data: { +// content: param, +// }, +// }) +// } -export const getCanvasStateAll = () => { - return prisma.canvas.findMany() -} +// export const getCanvasStateAll = () => { +// return prisma.canvas.findMany() +// } -export const getCanvasState = () => { - return prisma.canvas.findFirst({ - where: { - loginId: 'test', - }, - orderBy: { - id: 'desc', - }, - }) -} +// export const getCanvasState = () => { +// return prisma.canvas.findFirst({ +// where: { +// loginId: 'test', +// }, +// orderBy: { +// id: 'desc', +// }, +// }) +// } -export const insertCanvasState = (param) => { - return prisma.canvas.create({ - data: param, - }) -} +// export const insertCanvasState = (param) => { +// return prisma.canvas.create({ +// data: param, +// }) +// } export const writeImage = async (title, data) => { // 해당 경로에 Directory 가 없다면 생성 From 3ea6eb2eaf46e274f5873b5e581930d86d59bb9e Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 21 Oct 2024 17:10:54 +0900 Subject: [PATCH 031/139] fix: Delete Old code --- src/app/management/stuff/page.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/app/management/stuff/page.jsx b/src/app/management/stuff/page.jsx index 21c6bb78..eb852712 100644 --- a/src/app/management/stuff/page.jsx +++ b/src/app/management/stuff/page.jsx @@ -1,10 +1,8 @@ import StuffSearchCondition from '@/components/management/StuffSearchCondition' import Stuff from '@/components/management/Stuff' import StuffSubHeader from '@/components/management/StuffSubHeader' -import { initCheck } from '@/util/session-util' import '@/styles/contents.scss' export default async function ManagementStuffPage() { - await initCheck() return ( <> From f42ef08b098c58e14b3a230107e8eb9b8f303519 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 21 Oct 2024 17:32:35 +0900 Subject: [PATCH 032/139] =?UTF-8?q?=EC=A0=90=EC=84=A0=20=EA=B7=B8=EB=A6=AC?= =?UTF-8?q?=EB=93=9C=20=EC=A1=B0=EA=B1=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/modal/grid/DotLineGrid.jsx | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index ed9ffa21..eacb1b34 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -108,6 +108,10 @@ export default function DotLineGrid(props) { } const handleSave = async () => { + if (!dotLineGridSetting.DOT && !dotLineGridSetting.LINE) { + swalFire({ text: '배치할 그리드를 설정해주세요.' }) + return + } try { const patternData = { objectNo, @@ -345,7 +349,8 @@ export default function DotLineGrid(props) { id="ra01" value={1} onChange={handleRadioChange} - checked={dotLineGridSetting.INTERVAL.type === 1} + checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 1} + readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} />
@@ -384,7 +389,8 @@ export default function DotLineGrid(props) { id="ra02" value={2} onChange={handleRadioChange} - checked={dotLineGridSetting.INTERVAL.type === 2} + checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 2} + readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} />
From 51096a150d987e83978b670eb6f83198c8bc511e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 21 Oct 2024 18:12:53 +0900 Subject: [PATCH 033/139] =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EA=B3=B5=ED=86=B5?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5(=ED=85=8D=EC=8A=A4=ED=8A=B8,=20=EC=B9=98?= =?UTF-8?q?=EC=88=98=EC=84=A0,=20=EA=B1=B0=EB=A6=AC=EC=B8=A1=EC=A0=95)=20?= =?UTF-8?q?=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 371 +++++++++++++++++++++- src/hooks/surface/useSurfaceShapeBatch.js | 3 +- src/util/canvas-util.js | 12 +- 3 files changed, 381 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index b14ff216..84cbdca2 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -10,16 +10,21 @@ import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' import { usePlan } from '@/hooks/usePlan' import { useSwal } from '@/hooks/useSwal' +import { useEvent } from '@/hooks/useEvent' import { canvasState, canvasZoomState, currentCanvasPlanState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' import { sessionStore } from '@/store/commonAtom' import { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' +import { wordDisplaySelector } from '@/store/settingAtom' import { MENU } from '@/common/common' +import { checkLineOrientation, getDistance } from '@/util/canvas-util' + import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import { settingModalFirstOptionsState } from '@/store/settingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' +import { lineSegment } from '@turf/turf' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -68,11 +73,20 @@ export default function CanvasMenu(props) { const globalLocale = useRecoilValue(globalLocaleStore) const canvas = useRecoilValue(canvasState) const sessionState = useRecoilValue(sessionStore) + const wordDisplay = useRecoilValue(wordDisplaySelector) const { getMessage } = useMessage() const { saveCanvas } = usePlan() const { swalFire } = useSwal() + const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent() + const [commonFunction, setCommonFunction] = useState(null) + const [commonFunctionState, setCommonFunctionState] = useState({ + text: false, + dimension: false, + distance: false, + }) + const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const onClickNav = (menu) => { setMenuNumber(menu.index) @@ -155,6 +169,328 @@ export default function CanvasMenu(props) { canvas.renderAll() } + const commonTextMode = () => { + let textbox + if (commonFunctionState.text) { + addCanvasMouseEventListener('mouse:down', (event) => { + const pointer = canvas?.getPointer(event.e) + textbox = new fabric.Textbox('', { + left: pointer.x, + top: pointer.y, + width: 200, + fontSize: 14, + editable: true, + name: 'commonText', + visible: wordDisplay, + }) + + canvas?.add(textbox) + canvas.setActiveObject(textbox) + textbox.enterEditing() + textbox.selectAll() + }) + + addDocumentEventListener('keydown', document, (e) => { + if (e.key === 'Enter') { + if (commonFunctionState.text) { + const activeObject = canvas.getActiveObject() + if (activeObject && activeObject.isEditing) { + if (activeObject.text === '') { + canvas?.remove(activeObject) + } else { + activeObject.exitEditing() + } + //정책 협의 + const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText') + texts.forEach((text) => { + text.set({ editable: false }) + }) + + canvas.renderAll() + } + } + } + }) + } + } + + const commonDimensionMode = () => { + if (commonFunctionState.dimension) { + let points = [] + let distanceText = null + let minX, minY, maxX, maxY + + // 화살표를 생성하는 함수 + function createArrow(x, y, angle) { + return new fabric.Triangle({ + left: x, + top: y, + originX: 'center', + originY: 'center', + angle: angle, + width: 15, + height: 15, + fill: 'black', + selectable: false, + }) + } + + const circleOptions = { + radius: 5, + strokeWidth: 2, + stroke: 'red', + fill: 'white', + selectable: false, + } + + const lineOptions = { + stroke: 'black', + strokeWidth: 2, + selectable: false, + } + + // 캔버스에 클릭 이벤트 추가 + addCanvasMouseEventListener('mouse:down', (e) => { + const pointer = canvas.getPointer(e.e) + let point + + if (points.length === 0) { + // 첫 번째 포인트는 그대로 클릭한 위치에 추가 + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + points.push(point) + canvas.add(point) + } else if (points.length === 1) { + // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 + const p1 = points[0] + const deltaX = Math.abs(pointer.x - (p1.left + p1.radius)) + const deltaY = Math.abs(pointer.y - (p1.top + p1.radius)) + + if (deltaX > deltaY) { + // 수평선 상에만 배치 (y 좌표 고정) + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: p1.top, // y 좌표 고정 + ...circleOptions, + }) + } else { + // 수직선 상에만 배치 (x 좌표 고정) + point = new fabric.Circle({ + left: p1.left, // x 좌표 고정 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + } + + points.push(point) + canvas.add(point) + + // 두 포인트의 중심 좌표 계산 + const p2 = points[1] + const p1CenterX = p1.left + p1.radius + const p1CenterY = p1.top + p1.radius + const p2CenterX = p2.left + p2.radius + const p2CenterY = p2.top + p2.radius + + points.forEach((point) => { + canvas?.remove(point) + }) + + // 두 포인트 간에 직선을 그림 (중심을 기준으로) + const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) + canvas.add(line) + + const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) + const lineDirection = checkLineOrientation(line) + let extendLine = [] + + if (lineDirection === 'horizontal') { + extendLine = [ + [line.x1, line.y1 - 20, line.x1, line.y1 + 20], + [line.x2, line.y2 - 20, line.x2, line.y2 + 20], + ] + } else { + extendLine = [ + [line.x1 - 20, line.y1, line.x1 + 20, line.y1], + [line.x2 - 20, line.y2, line.x2 + 20, line.y2], + ] + } + + extendLine.forEach((line) => { + const extendLine = new fabric.Line(line, lineOptions) + canvas.add(extendLine) + }) + + // 두 포인트 간의 각도를 계산하여 화살표 추가 + // const angle = calculateAngle({ x: p1CenterX, y: p1CenterY }, { x: p2CenterX, y: p2CenterY }) + + // 첫 번째 포인트에 화살표 추가 + const arrow1 = createArrow(p1CenterX + 7.5, p1CenterY + 1, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 + const arrow2 = createArrow(p2CenterX - 6.5, p2CenterY + 1, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 + canvas.add(arrow1) + canvas.add(arrow2) + + // 두 포인트 간의 거리 계산 + + // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 + distanceText = new fabric.Text(`${distance}`, { + left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), + top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), + fill: 'black', + fontSize: 16, + selectable: true, + textAlign: 'center', + originX: 'center', + originY: 'center', + angle: lineDirection === 'horizontal' ? 0 : 270, + // lockMovementX: false, + // lockMovementY: false, + }) + canvas.add(distanceText) + + // minX = p1CenterX + // maxX = p2CenterX + // minY = p1CenterY + // maxY = p2CenterY + + // 거리 계산 후, 다음 측정을 위해 초기화 + points = [] + } + + // 캔버스 다시 그리기 + canvas.renderAll() + }) + + // addCanvasMouseEventListener('object:moving', function (e) { + // const obj = e.target + + // if (obj.left < minX) { + // obj.left = minX + // } + // if (obj.left + obj.width > maxX) { + // obj.left = maxX - obj.width + // } + // if (obj.top < minY) { + // obj.top = minY + // } + // if (obj.top + obj.height > maxY) { + // obj.top = maxY - obj.height + // } + // }) + } + } + + const commonDistanceMode = () => { + if (commonFunctionState.distance) { + let points = [] + let distanceText = null + + const circleOptions = { + radius: 5, + strokeWidth: 2, + stroke: 'red', + fill: 'white', + selectable: false, + } + + const lineOptions = { + stroke: 'black', + strokeWidth: 2, + selectable: false, + strokeDashArray: [9, 5], + } + + const textOptions = { + fill: 'black', + fontSize: 16, + selectable: true, + textAlign: 'center', + originX: 'center', + originY: 'center', + } + + // 캔버스에 클릭 이벤트 추가 + addCanvasMouseEventListener('mouse:down', function (options) { + const pointer = canvas.getPointer(options.e) + let point + + if (points.length === 0) { + // 첫 번째 포인트는 그대로 클릭한 위치에 추가 + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + points.push(point) + canvas.add(point) + } else if (points.length === 1) { + // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 + const p1 = points[0] + + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + + points.push(point) + canvas.add(point) + + // 두 포인트의 중심 좌표 계산 + const p2 = points[1] + + const p1CenterX = p1.left + p1.radius + const p1CenterY = p1.top + p1.radius + const p2CenterX = p2.left + p2.radius + const p2CenterY = p2.top + p2.radius + + const p3 = new fabric.Point(p2CenterX, p1CenterY) + + // 두 포인트 간에 직선을 그림 (중심을 기준으로) + const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) + const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) + const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) + canvas.add(line) + canvas.add(line2) + canvas.add(line3) + + const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) + const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) + const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + + // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 + distanceText = new fabric.Text(`${distance1}`, { + left: (p1CenterX + p2CenterX) / 2, + top: (p1CenterY + p2CenterY) / 2, + ...textOptions, + }) + canvas.add(distanceText) + distanceText = new fabric.Text(`${distance2}`, { + left: (p2CenterX + p3.x) / 2, + top: (p2CenterY + p3.y) / 2, + ...textOptions, + }) + canvas.add(distanceText) + distanceText = new fabric.Text(`${distance3}`, { + left: (p3.x + p1CenterX) / 2, + top: (p3.y + p1CenterY) / 2, + ...textOptions, + }) + canvas.add(distanceText) + + // 거리 계산 후, 다음 측정을 위해 초기화 + points = [] + } + + // 캔버스 다시 그리기 + canvas.renderAll() + }) + } + } + useEffect(() => { if (globalLocale === 'ko') { setAppMessageState(KO) @@ -163,6 +499,35 @@ export default function CanvasMenu(props) { } }, [menuNumber, type, globalLocale]) + const commonFunctions = (mode) => { + let tempStates = { ...commonFunctionState } + + if (tempStates[mode]) { + tempStates[mode] = false + } else { + Object.keys(tempStates).forEach((key) => { + tempStates[key] = false + }) + + if (mode !== undefined) { + tempStates[mode] = true + } + } + + setCommonFunctionState(tempStates) + } + + useEffect(() => { + initEvent() + if (commonFunctionState.text) { + commonTextMode() + } else if (commonFunctionState.dimension) { + commonDimensionMode() + } else if (commonFunctionState.distance) { + commonDistanceMode() + } + }, [commonFunctionState]) + return (
@@ -192,9 +557,9 @@ export default function CanvasMenu(props) {
}
- - - + + +
diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 7eb421cc..be421c8e 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -575,7 +575,8 @@ export function useSurfaceShapeBatch() { obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW || obj.name === BATCH_TYPE.TRIANGLE_DORMER || - obj.name === BATCH_TYPE.PENTAGON_DORMER + obj.name === BATCH_TYPE.PENTAGON_DORMER || + obj.name === 'lengthText' ) { canvas?.remove(obj) } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 20b6ec66..0e49e67d 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -78,7 +78,7 @@ export const getCenterPoint = (point1, point2) => { * @returns */ export const getDistance = (x1, y1, x2, y2) => { - return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)) + return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2)).toFixed(0) } // polygon의 각 변에 해당 점과 점 사이의 거리를 나타내는 IText를 추가하는 함수 @@ -853,3 +853,13 @@ export function setSurfaceShapePattern(polygon) { polygon.set('fill', pattern) polygon.canvas?.renderAll() } + +export function checkLineOrientation(line) { + if (line.y1 === line.y2) { + return 'horizontal' // 수평 + } else if (line.x1 === line.x2) { + return 'vertical' // 수직 + } else { + return 'diagonal' // 대각선 + } +} From f372c9ae61a1d2af0d221435f13d14fd8c2c5c68 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 22 Oct 2024 09:50:51 +0900 Subject: [PATCH 034/139] =?UTF-8?q?fix:=20=EA=B3=B5=ED=86=B5=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=A1=B0=ED=9A=8C=EC=8B=9C=20=EB=A1=9C=EC=BC=80?= =?UTF-8?q?=EC=9D=BC=20=EC=B0=B8=EC=A1=B0=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/QcastProvider.js | 6 +++--- src/hooks/common/useCommonCode.js | 19 +++++++++++++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/app/QcastProvider.js b/src/app/QcastProvider.js index bdaa72c6..e03ad186 100644 --- a/src/app/QcastProvider.js +++ b/src/app/QcastProvider.js @@ -1,5 +1,6 @@ 'use client' +// import { useEffect } from 'react' import { ErrorBoundary } from 'next/dist/client/components/error-boundary' import { useCommonCode } from '@/hooks/common/useCommonCode' import ServerError from './error' @@ -11,9 +12,8 @@ export const QcastProvider = ({ children }) => { // useEffect(() => { // console.log('commonCode', commonCode) - // console.log(findCommonCode(100200)) - // console.log(findCommonCode(115800)) - // }, [commonCode]) + // console.log(findCommonCode(113600)) + // }, [commonCode, findCommonCode]) return ( <> diff --git a/src/hooks/common/useCommonCode.js b/src/hooks/common/useCommonCode.js index 17c2de8b..f912beb9 100644 --- a/src/hooks/common/useCommonCode.js +++ b/src/hooks/common/useCommonCode.js @@ -1,19 +1,34 @@ import { useEffect } from 'react' -import { useRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { commonCodeState } from '@/store/commonCodeAtom' +import { globalLocaleStore } from '@/store/localeAtom' import { isObjectNotEmpty } from '@/util/common-utils' import { useAxios } from '../useAxios' export const useCommonCode = () => { const [commonCode, setCommonCode] = useRecoilState(commonCodeState) + const globalLocale = useRecoilValue(globalLocaleStore) const { promiseGet } = useAxios() const findCommonCode = (key) => { // const arr = commonCode[key] // return arr.sort((a, b) => a.clPriority - b.clPriority) - return commonCode[key] + const resultCodes = commonCode[key]?.map((code) => { + const result = { + clHeadCd: code.clHeadCd, + clCode: code.clCode, + clCodeNm: globalLocale === 'ko' ? code.clCodeNm : code.clCodeJp, + clPriority: code.clPriority, + } + return result + }) + return resultCodes } + useEffect(() => { + findCommonCode() + }, [globalLocale]) + useEffect(() => { const getCommonCode = async () => { await promiseGet({ url: '/api/commcode/qc-comm-code' }).then((res) => { From d079fe5948e66dea7d6caedddde9b353ae9f3a13 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 22 Oct 2024 10:09:43 +0900 Subject: [PATCH 035/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 5 ++++- src/styles/_modal.scss | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index ee823bab..f70745b3 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -424,8 +424,11 @@ // &::-webkit-scrollbar-track { // background-color: #fff; // } - canvas{ + .canvas-container{ + margin: 0 auto; background-color: #fff; + } + canvas{ position: absolute; top: 0; left: 0; diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 5a8167eb..9dc39b65 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -1629,7 +1629,7 @@ $alert-color: #101010; min-height: 80px; background-color: #fff; } - + } // 치수선 설정 From 30267703e7a8956fc8047a444f422d91dc12c1f4 Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 22 Oct 2024 10:13:17 +0900 Subject: [PATCH 036/139] =?UTF-8?q?usePopup=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 24 +++++----- .../floor-plan/modal/grid/DotLineGrid.jsx | 6 +-- .../floor-plan/modal/setting01/GridOption.jsx | 43 ++++++++++++----- .../modal/setting01/SecondOption.jsx | 46 ++++++++++++++++--- .../dimensionLine/DimensionLineSetting.jsx | 29 ++++++++---- src/hooks/usePopup.js | 6 +++ src/locales/ja.json | 8 ++++ src/locales/ko.json | 8 ++++ 8 files changed, 128 insertions(+), 42 deletions(-) diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index 0e4754b0..d4896ab3 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -2,6 +2,7 @@ import WithDraggable from '@/components/common/draggable/withDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' import { useState } from 'react' +import { useMessage } from '@/hooks/useMessage' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, @@ -42,7 +43,8 @@ const fontColors = [ { name: '남색', value: 'darkblue' }, ] export default function FontSetting(props) { - const { id, setIsShow, font, setFont, fontSize, setFontSize } = props + const { id, setIsShow, font, setFont, fontSize, setFontSize, pos = { x: 455, y: 180 } } = props + const { getMessage } = useMessage() const { closePopup } = usePopup() const [originFont, setOriginFont] = useState(font) const [originFontSize, setOriginFontSize] = useState(fontSize) @@ -50,10 +52,10 @@ export default function FontSetting(props) { const [selectedFontSize, setSelectedFontSize] = useState(fontSize ? fontSize : fontSizes[0]) const [selectedFontColor, setSelectedFontColor] = useState(null) return ( - -
+ +
-

フォント

+

{getMessage('modal.font')}

diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index ed9ffa21..376cac03 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -21,7 +21,7 @@ export default function DotLineGrid(props) { // const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [close, setClose] = useState(false) - const { id, setShowDotLineGridModal } = props + const { id, setIsShow, pos = { x: 840, y: -815 } } = props const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) const gridColor = useRecoilValue(gridColorState) const canvas = useRecoilValue(canvasState) @@ -311,14 +311,14 @@ export default function DotLineGrid(props) { } return ( - +

{getMessage('modal.canvas.setting.grid.dot.line.setting')}

- +
+
+
+
+ {getMessage('common.horizon')} +
+ setOriginHorizon(Number(e.target.value))} /> +
+ mm +
+
+ {getMessage('common.vertical')} +
+ setOriginVertical(Number(e.target.value))} + /> +
+ mm +
+
+
+ +
+
+
+
+ ) +} From 9ca8d99555c9f9ad9e76daf61a2fe77dc20f4854 Mon Sep 17 00:00:00 2001 From: basssy Date: Tue, 22 Oct 2024 10:39:46 +0900 Subject: [PATCH 038/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=EC=8B=A0=EA=B7=9C=EB=93=B1=EB=A1=9D=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 201 +++++++++++++----- .../management/popup/PlanRequestPop.jsx | 41 ++-- 2 files changed, 168 insertions(+), 74 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 04ba662a..87159dee 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -15,7 +15,11 @@ import { sessionStore } from '@/store/commonAtom' import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' import WindSelectPop from './popup/WindSelectPop' +import { useCommonCode } from '@/hooks/common/useCommonCode' + export default function StuffDetail() { + //공통코드 + const { commonCode, findCommonCode } = useCommonCode() const [selOptions, setSelOptions] = useState('') const sessionState = useRecoilValue(sessionStore) @@ -26,7 +30,7 @@ export default function StuffDetail() { const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) const ref = useRef() - const { get, post, del, promisePost } = useAxios(globalLocaleState) + const { get, del, promisePost } = useAxios(globalLocaleState) //form const formInitValue = { // 물건번호 T...(임시) R...(진짜) @@ -63,6 +67,10 @@ export default function StuffDetail() { const form = { register, setValue, getValues, handleSubmit, resetField, control, watch } + const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드 리스트 + const [selHonorificCode, setSelHonorificCode] = useState('') //선택한 경칭코드 + const [objectStatusList, setObjectStatusList] = useState([]) //물건구분 공통코드 리스트 + const [windSpeedList, setWindSpeedList] = useState([]) //기준 풍속 공통코드 리스트 const [prefCodeList, setPrefCodeList] = useState([]) //도도부현 코트 리스트 const [prefValue, setPrefValue] = useState('') const [saleStoreList, setSaleStoreList] = useState([]) // 판매점 리스트 @@ -92,7 +100,6 @@ export default function StuffDetail() { setIsFormValid(true) } get({ url: `/api/object/${objectNo}/detail` }).then((res) => { - console.log('물건번호로 상세 API 호출') if (res != null) { setDetailData(res) } @@ -128,6 +135,24 @@ export default function StuffDetail() { } }, [objectNo, sessionState]) + useEffect(() => { + const code1 = findCommonCode(200800) //경칭 + const code2 = findCommonCode(201700) //신축/기축 + const code3 = findCommonCode(113600) //기준풍속 + if (code1 != null) { + // console.log('경칭공코::::::', code1) + setHonorificCodeList(code1) + } + if (code2 != null) { + // console.log('신축/기축공코::::', code2) + setObjectStatusList(code2) + } + if (code3 != null) { + // console.log('기준풍속::::', code3) + setWindSpeedList(code3) + } + }, [commonCode]) + useEffect(() => { if (isObjectNotEmpty(detailData)) { // 도도부현API @@ -159,6 +184,26 @@ export default function StuffDetail() { } }, [detailData]) + //경칭선택 변경 이벤트 + const onChangeHonorificCode = (key) => { + if (isObjectNotEmpty(key)) { + setSelHonorificCode(key.clCode) + form.setValue('objectNameOmit', key.clCode) + } else { + setSelHonorificCode('') + form.setValue('objectNameOmit', '') + } + } + + //기준풍속 변경 이벤트 + const onChangeWindSpeedCode = (key) => { + if (isObjectNotEmpty(key)) { + form.setValue('windSpeed', key.clCode) + } else { + form.setValue('windSpeed', '') + } + } + //1차점 변경 이벤트 const onSelectionChange = (key) => { if (isObjectNotEmpty(key)) { @@ -208,7 +253,7 @@ export default function StuffDetail() { //팝업에서 넘어온 우편정보 const setZipInfo = (info) => { - console.log('팝업에서 넘어온 우편 데이타::::::::', info) + // console.log('팝업에서 넘어온 우편 데이타::::::::', info) setPrefValue(info.prefId) form.setValue('prefId', info.prefId) form.setValue('prefName', info.address1) @@ -243,7 +288,7 @@ export default function StuffDetail() { form.setValue('verticalSnowCover', info.verticalSnowCover) form.setValue('surfaceType', info.surfaceType) //설치 높이 installHeight - + form.setValue('installHeight', info.installHeight) form.setValue('remarks', info.remarks) } @@ -285,7 +330,7 @@ export default function StuffDetail() { useEffect(() => { if (editMode === 'NEW') { const formData = form.getValues() - // console.log('임시저장폼::::::::::::', formData) + // console.log('임시저장폼error체크::::::::::::', formData) let errors = {} if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { errors.dispCompanyName = true @@ -415,10 +460,9 @@ export default function StuffDetail() { // 임시저장 const onTempSave = async () => { - console.log('임시저장:::::') - return const formData = form.getValues() - // console.log('formData::', formData) + console.log('임시저장누름:::::', formData) + return const params = { saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId, saleStoreName: formData.otherSaleStoreName ? formData.otherSaleStoreName : formData.saleStoreName, @@ -518,24 +562,43 @@ export default function StuffDetail() {
-
- - -
-
- - -
+ {/* 라디오시작 */} + {objectStatusList.map((row, index) => { + return ( +
+ + +
+ ) + })} + {/* 라디오끝 */}
- +
@@ -611,10 +674,10 @@ export default function StuffDetail() { getOptionValue={(x) => x.saleStoreId} isDisabled={form.watch('saleStoreId') !== '' ? false : true} isClearable={true} - value={otherSaleStoreList.filter(function (option) { - // console.log('2차점::::::', option) - // return option.saleStoreId === selOptions - })} + //value={otherSaleStoreList.filter(function (option) { + // console.log('2차점::::::', option) + // return option.saleStoreId === selOptions + //})} />
@@ -708,9 +771,30 @@ export default function StuffDetail() {
-
+ {/*
+
*/} + {/* 기준풍속sel시작 */} +
+
+ {/* 기준풍속sel끝 */} {getMessage('stuff.detail.windSpeedSpan')}
- +
)) || ( diff --git a/src/components/main/ChangePasswordPop.jsx b/src/components/main/ChangePasswordPop.jsx index e9355d24..b5a3f8da 100644 --- a/src/components/main/ChangePasswordPop.jsx +++ b/src/components/main/ChangePasswordPop.jsx @@ -70,8 +70,9 @@ export default function ChangePasswordPop() { chgType: 'I', chgPwd: _password1, } + await patch({ url: '/api/login/v1.0/user/change-password', data: param }).then((res) => { - if (res) { + if (res.result.code === 200) { if (res.result.resultCode === 'S') { alert(getMessage('main.popup.login.success')) setSessionState({ ...sessionState, pwdInitYn: 'Y' }) diff --git a/src/components/main/MainContents.jsx b/src/components/main/MainContents.jsx index 6dcca943..d2e38853 100644 --- a/src/components/main/MainContents.jsx +++ b/src/components/main/MainContents.jsx @@ -8,11 +8,18 @@ import { useRecoilValue } from 'recoil' import { useRouter } from 'next/navigation' import { globalLocaleStore } from '@/store/localeAtom' import { queryStringFormatter } from '@/util/common-utils' -export default function MainContents({ objectList, businessCharger, businessChargerMail, businessChargerTel }) { +import { sessionStore } from '@/store/commonAtom' + +export default function MainContents() { const { getMessage } = useMessage() const router = useRouter() const globalLocaleState = useRecoilValue(globalLocaleStore) - const { get } = useAxios(globalLocaleState) + const { promiseGet, get } = useAxios(globalLocaleState) + + const sessionState = useRecoilValue(sessionStore) + + //최근 물건 + const [objectList, setObjectList] = useState([]) //공지사항 const [recentNoticeList, setRecentNoticeList] = useState([]) @@ -20,10 +27,37 @@ export default function MainContents({ objectList, businessCharger, businessChar //FAQ const [recentFaqList, setRecentFaqList] = useState([]) + //Sales Contact info + const [businessCharger, setBusinessCharger] = useState(null) + const [businessChargerMail, setBusinessChargerMail] = useState(null) + useEffect(() => { + fetchObjectList() fetchNoticeList() fetchFaqList() - }, []) + }, [sessionState]) + + //최근 갱신 물건목록 / Sales Contact info 정보 + const fetchObjectList = async () => { + try { + const apiUrl = `/api/main-page/object/${sessionState?.storeId}/list` + await promiseGet({ + url: apiUrl, + }).then((res) => { + if (res.status === 200) { + setObjectList(res.data.objectList) + setBusinessCharger(res.data.businessCharger) + setBusinessChargerMail(res.data.businessChargerMail) + } else { + setObjectList([]) + setBusinessCharger(null) + setBusinessChargerMail(null) + } + }) + } catch (error) { + console.error('MAIN API fetching error:', error) + } + } //공지사항 호출 const fetchNoticeList = async () => { @@ -35,13 +69,13 @@ export default function MainContents({ objectList, businessCharger, businessChar endRow: 1, } const noticeApiUrl = `api/board/list?${queryStringFormatter(param)}` - const res = await get({ url: noticeApiUrl }) - //console.log('공지res::', res) - if (res) { - if (res.data.length > 0) { - setRecentNoticeList(res.data) + await promiseGet({ url: noticeApiUrl }).then((res) => { + if (res.status === 200) { + setRecentNoticeList(res.data.data) + } else { + setRecentNoticeList([]) } - } + }) } catch (error) { console.error('NOTICE fetching error:', error) } @@ -57,13 +91,15 @@ export default function MainContents({ objectList, businessCharger, businessChar endRow: 3, } const faqApiUrl = `api/board/list?${queryStringFormatter(param)}` - const res = await get({ url: faqApiUrl }) - //console.log('FAQres::', res) - if (res) { - if (res.data.length > 0) { - setRecentFaqList(res.data) + await promiseGet({ + url: faqApiUrl, + }).then((res) => { + if (res.status === 200) { + setRecentFaqList(res.data.data) + } else { + setRecentFaqList([]) } - } + }) } catch (error) { console.error('FAQ fetching error:', error) } @@ -74,38 +110,28 @@ export default function MainContents({ objectList, businessCharger, businessChar
    - {objectList?.length > 0 ? ( - <> - {objectList.map((row) => { - return ( -
  • { - if (row.objectNo.substring(0, 1) === 'R') { - router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`) - } else { - router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`) - } - }} - > -
    - {dayjs(row.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')} - {row.objectNo} - {row.objectName} - {row.saleStoreName} -
    -
  • - ) - })} - - ) : ( - <> -
  • -
    최근 갱신 물건이 없습니다
    + {objectList.map((row) => { + return ( +
  • { + if (row.objectNo.substring(0, 1) === 'R') { + router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`) + } else { + router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`) + } + }} + > +
    + {dayjs(row.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')} + {row.objectNo} + {row.objectName} + {row.saleStoreName} +
  • - - )} + ) + })}
@@ -156,13 +182,17 @@ export default function MainContents({ objectList, businessCharger, businessChar
react
-
{businessCharger}
+ {(businessCharger &&
{businessCharger}
) || ( +
{getMessage('main.content.noBusiness')}
+ )}
  • react
    -
    {businessChargerMail}
    + {(businessChargerMail &&
    {businessChargerMail}
    ) || ( +
    {getMessage('main.content.noBusiness')}
    + )}
  • diff --git a/src/locales/ja.json b/src/locales/ja.json index b6f41c05..c4c09341 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -588,6 +588,7 @@ "main.content.notice": "お知らせ", "main.content.download1": "操作マニュアル", "main.content.download2": "屋根の説明書", + "main.content.noBusiness": "Hanwha Japanにお問い合わせください", "main.popup.login.popupTitle": "パスワード変更", "main.popup.login.newPassword1": "新しいパスワードを入力", "main.popup.login.newPassword2": "新規パスワード再入力", diff --git a/src/locales/ko.json b/src/locales/ko.json index 525ae91c..f5394e2e 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -472,7 +472,7 @@ "stuff.addressPopup.btn1": "닫기", "stuff.addressPopup.btn2": "주소적용", "stuff.planReqPopup.title": "설계의뢰 불러오기", - "stuff.temp.subTitle" : "물건정보", + "stuff.temp.subTitle": "물건정보", "stuff.detail.required": "필수 입력항목", "stuff.detail.planReqNo": "설계의뢰No.", "stuff.detail.dispCompanyName": "담당자", @@ -593,12 +593,13 @@ "main.content.notice": "공지사항", "main.content.download1": "조작메뉴얼", "main.content.download2": "지붕설명서", + "main.content.noBusiness": "Hanwha Japan에 문의하세요", "main.popup.login.popupTitle": "비밀번호변경", "main.popup.login.newPassword1": "새 비밀번호 입력", "main.popup.login.newPassword2": "새 비밀번호 재입력", "main.popup.login.placeholder": "반각 10자 이내", - "main.popup.login.guide1": "초기화된 비밀번호로 로그인한 경우 비밀번호를 변경하지 않으면 사이트 이용이 가능합니다.", - "main.popup.login.guide2": "비밀번호를 변경하지 않으려면 로그인 화면으로 이동합니다.", + "main.popup.login.guide1": "초기화된 비밀번호로 로그인한 경우, 비밀번호를 변경해야 사이트 이용이 가능합니다.", + "main.popup.login.guide2": "비밀번호를 변경하지 않을 경우, 로그인 화면으로 이동합니다.", "main.popup.login.btn1": "변경", "main.popup.login.btn2": "변경안함", "main.popup.login.validate1": "입력한 패스워드가 다릅니다.", From bc2f18a9a01d689b6deadd257ff3e19362206246 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Oct 2024 16:48:45 +0900 Subject: [PATCH 043/139] =?UTF-8?q?=EC=98=A4=ED=94=84=EC=85=8B,=20?= =?UTF-8?q?=ED=99=94=EC=82=B4=ED=91=9C=20=EA=B5=AC=EB=B0=B0=20=EA=B0=92=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 3 +- .../floor-plan/modal/grid/DotLineGrid.jsx | 8 +- src/hooks/roofcover/useEavesGableEdit.js | 3 +- src/hooks/roofcover/usePropertiesSetting.js | 5 +- .../roofcover/useRoofShapePassivitySetting.js | 3 +- src/hooks/roofcover/useRoofShapeSetting.js | 256 +++++++++++++----- src/hooks/surface/usePlacementShapeDrawing.js | 5 + src/hooks/surface/useSurfaceShapeBatch.js | 4 +- src/hooks/useLine.js | 57 ++++ src/hooks/useMode.js | 2 +- src/hooks/usePolygon.js | 3 +- src/util/qpolygon-utils.js | 4 +- 12 files changed, 275 insertions(+), 78 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 616143fe..7700ae42 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -26,10 +26,9 @@ export const QLine = fabric.util.createClass(fabric.Line, { }) this.idx = options.idx ?? 0 - + this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) this.setLength() - this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) this.startPoint = { x: this.x1, y: this.y1 } this.endPoint = { x: this.x2, y: this.y2 } diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index 06a911f6..6b63f3d7 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -57,7 +57,7 @@ export default function DotLineGrid(props) { // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('DotLineGrid useEffect 실행') - fetchGridSettings() + // fetchGridSettings() }, [objectNo]) const HandleClickClose = () => { @@ -118,9 +118,9 @@ export default function DotLineGrid(props) { dotGridDisplay: dotLineGridSetting.DOT, lineGridDisplay: dotLineGridSetting.LINE, gridType: dotLineGridSetting.INTERVAL.type, - gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval, - gridVertical: dotLineGridSetting.INTERVAL.verticalInterval, - gridRatio: dotLineGridSetting.INTERVAL.ratioInterval, + gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10, + gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10, + gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, gridDimen: dotLineGridSetting.INTERVAL.dimension, } diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 083d8e03..c43e71f3 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -22,7 +22,7 @@ export function useEavesGableEdit(setShowEavesGableEditModal) { } const [type, setType] = useState(TYPES.EAVES) const typeRef = useRef(TYPES.EAVES) - const { removeLine } = useLine() + const { removeLine, addPitchTextsByOuterLines } = useLine() const { swalFire } = useSwal() const { drawRoofPolygon } = useMode() @@ -167,6 +167,7 @@ export function useEavesGableEdit(setShowEavesGableEditModal) { const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') wallLines.forEach((wallLine) => { + addPitchTextsByOuterLines() const roof = drawRoofPolygon(wallLine) canvas?.renderAll() diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index ad703356..315a6e8c 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -17,7 +17,7 @@ export function usePropertiesSetting(setShowPropertiesSettingModal) { const setPoints = useResetRecoilState(outerLinePointsState) const { addPolygonByLines } = usePolygon() - const { removeLine, hideLine } = useLine() + const { removeLine, hideLine, addPitchTextsByOuterLines } = useLine() useEffect(() => { const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') @@ -129,14 +129,13 @@ export function usePropertiesSetting(setShowPropertiesSettingModal) { stroke: '#000000', strokeWidth: 4, }) - - hideLine(line) }) const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) wall.lines = [...lines] + addPitchTextsByOuterLines() const roof = drawRoofPolygon(wall) setPoints([]) diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index f7b8b9fd..a04b6e0b 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -19,7 +19,7 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod } const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() - const { showLine, hideLine } = useLine() + const { showLine, hideLine, addPitchTextsByOuterLines } = useLine() const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() const { drawRoofPolygon } = useMode() @@ -212,6 +212,7 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod if (isFix.current) { // 완료 한 경우에는 지붕까지 그려줌 + addPitchTextsByOuterLines() const roof = drawRoofPolygon(wall) } diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 016cd365..05564c28 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -28,7 +28,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { const [hasSleeve, setHasSleeve] = useState('0') const currentObject = useRecoilValue(currentObjectState) const { drawRoofPolygon } = useMode() - const { hideLine, showLine } = useLine() + const { hideLine, showLine, removePitchText, addPitchText, addPitchTextsByOuterLines } = useLine() const setCurrentMenu = useSetRecoilState(currentMenuState) const outerLineFix = useRecoilValue(outerLineFixState) @@ -41,6 +41,36 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { swalFire({ text: '외벽선이 없습니다.' }) setShowRoofShapeSettingModal(false) } + + return () => { + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText') + canvas.remove(...pitchTexts) + outerLines.forEach((line) => { + let stroke, strokeWidth + if (line.attributes) { + if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES || line.attributes.type === LINE_TYPE.WALLLINE.HIPANDGABLE) { + stroke = '#45CD7D' + strokeWidth = 4 + } else if (line.attributes.type === LINE_TYPE.WALLLINE.GABLE || line.attributes.type === LINE_TYPE.WALLLINE.JERKINHEAD) { + stroke = '#3FBAE6' + strokeWidth = 4 + } else { + stroke = '#000000' + strokeWidth = 4 + } + + line.set({ + stroke, + strokeWidth, + }) + + addPitchText(line) + line.setViewLengthText(false) + } + }) + canvas.renderAll() + } }, []) useEffect(() => { @@ -54,13 +84,13 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { return } - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + /*const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines.forEach((line) => { line.set({ stroke: '#000000', strokeWidth: 4, }) - }) + })*/ currentObject.set({ stroke: '#EA10AC', @@ -132,7 +162,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { case 4: { outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines.forEach((line) => { - hideLine(line) + // hideLine(line) }) break } @@ -144,23 +174,41 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { outerLines.forEach((line) => { setWestAndEastRoof(line) - if (line.direction === 'bottom') { - line.attributes = { - offset: eavesOffset / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.EAVES, + if (outerLines[0].direction === 'bottom') { + if (line.direction === 'bottom') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'top') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + } else { + if (line.direction === 'top') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'bottom') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } } } - if (line.direction === 'top') { - line.attributes = { - offset: shedWidth / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.SHED, - } - } - - hideLine(line) + // hideLine(line) }) break } @@ -170,23 +218,42 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { outerLines.forEach((line) => { setWestAndEastRoof(line) - if (line.direction === 'top') { - line.attributes = { - offset: eavesOffset / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.EAVES, + + if (outerLines[0].direction === 'bottom') { + if (line.direction === 'top') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'bottom') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + } else { + if (line.direction === 'bottom') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'top') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } } } - if (line.direction === 'bottom') { - line.attributes = { - offset: shedWidth / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.SHED, - } - } - - hideLine(line) + // hideLine(line) }) break } @@ -196,22 +263,41 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { outerLines.forEach((line) => { setSouthAndNorthRoof(line) - if (line.direction === 'right') { - line.attributes = { - offset: eavesOffset / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.EAVES, + if (outerLines[0].direction === 'bottom') { + if (line.direction === 'right') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'left') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + } else { + if (line.direction === 'left') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'right') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } } } - if (line.direction === 'left') { - line.attributes = { - offset: shedWidth / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.SHED, - } - } - hideLine(line) + // hideLine(line) }) break } @@ -222,23 +308,41 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { outerLines.forEach((line) => { setSouthAndNorthRoof(line) - if (line.direction === 'left') { - line.attributes = { - offset: eavesOffset / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.EAVES, + if (outerLines[0].direction === 'bottom') { + if (line.direction === 'left') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'right') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } + } + } else { + if (line.direction === 'right') { + line.attributes = { + offset: eavesOffset / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.EAVES, + } + } + + if (line.direction === 'left') { + line.attributes = { + offset: shedWidth / 10, + pitch: pitch, + type: LINE_TYPE.WALLLINE.SHED, + } } } - if (line.direction === 'right') { - line.attributes = { - offset: shedWidth / 10, - pitch: pitch, - type: LINE_TYPE.WALLLINE.SHED, - } - } - - hideLine(line) + // hideLine(line) }) break } @@ -247,14 +351,23 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { // 기존 wallLine, roofBase 제거 canvas .getObjects() - .filter((obj) => obj.name === 'wallLine' || obj.name === 'roofBase') + .filter((obj) => obj.name === 'wallLine') .forEach((line) => { canvas.remove(line) }) + canvas + .getObjects() + .filter((obj) => obj.name === 'roofBase') + .forEach((obj) => { + canvas.remove(...obj.innerLines) + canvas.remove(obj) + }) + const polygon = addPolygonByLines(outerLines, { name: 'wallLine' }) polygon.lines = [...outerLines] + addPitchTextsByOuterLines() const roof = drawRoofPolygon(polygon) canvas?.renderAll() @@ -322,7 +435,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { pitch: pitch, type: LINE_TYPE.WALLLINE.EAVES, } - hideLine(line) + // hideLine(line) }) return outerLines @@ -345,7 +458,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { type: LINE_TYPE.WALLLINE.EAVES, } } - hideLine(line) + // hideLine(line) }) return outerLines @@ -368,7 +481,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { type: LINE_TYPE.WALLLINE.EAVES, } } - hideLine(line) + // hideLine(line) }) return outerLines @@ -390,6 +503,9 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { pitch: pitch, offset: eavesOffset / 10, } + addPitchText(currentObject) + selectedLine.set({ strokeWidth: 4 }) + selectedLine.set({ stroke: '#45CD7D' }) break } case 2: { @@ -398,6 +514,8 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { type: LINE_TYPE.WALLLINE.GABLE, offset: gableOffset / 10, } + selectedLine.set({ strokeWidth: 4 }) + selectedLine.set({ stroke: '#3FBAE6' }) break } case 3: { @@ -417,6 +535,9 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { offset: eavesOffset / 10, width: hipAndGableWidth / 10, } + addPitchText(currentObject) + selectedLine.set({ strokeWidth: 4 }) + selectedLine.set({ stroke: '#45CD7D' }) break } case 5: { @@ -427,6 +548,9 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { width: jerkinHeadWidth / 10, pitch: jerkinHeadPitch, } + addPitchText(currentObject) + selectedLine.set({ strokeWidth: 4 }) + selectedLine.set({ stroke: '#3FBAE6' }) break } case 6: { @@ -440,6 +564,7 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { } selectedLine.attributes = attributes history.current.push(selectedLine) + canvas.renderAll() nextLineFocus(selectedLine) } @@ -458,6 +583,11 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { } const lastLine = history.current.pop() + currentObject.set({ + stroke: '#000000', + strokeWidth: 4, + }) + lastLine.set({ stroke: '#000000', strokeWidth: 4, diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index 40d25bf0..91725a1c 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -5,6 +5,7 @@ import { adsorptionRangeState, canvasState, dotLineIntervalSelector, + globalPitchState, verticalHorizontalModeState, } from '@/store/canvasAtom' import { useEvent } from '@/hooks/useEvent' @@ -67,6 +68,8 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { const isFix = useRef(false) + const globalPitch = useRecoilValue(globalPitchState) + useEffect(() => { if (adsorptionPointAddMode || tempGridMode) { return @@ -215,6 +218,7 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { originX: 'center', originY: 'center', direction: 'south', + pitch: globalPitch, }) setSurfaceShapePattern(roof) @@ -224,6 +228,7 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { removeLine(line) }) + setPoints([]) canvas?.renderAll() setShowPlaceShapeDrawingModal(false) } diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index be421c8e..23e017bd 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -1,7 +1,7 @@ 'use client' import { useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, globalPitchState } from '@/store/canvasAtom' import { MENU, BATCH_TYPE, POLYGON_TYPE } from '@/common/common' import { getIntersectionPoint, setSurfaceShapePattern } from '@/util/canvas-util' import { degreesToRadians } from '@turf/turf' @@ -14,6 +14,7 @@ export function useSurfaceShapeBatch() { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) + const globalPitch = useRecoilValue(globalPitchState) const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() @@ -83,6 +84,7 @@ export function useSurfaceShapeBatch() { angle: surfaceRefs.rotate, originX: 'center', originY: 'center', + pitch: globalPitch, } obj = new QPolygon(points, options) diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index a313d127..210c1ac6 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -71,10 +71,67 @@ export const useLine = () => { return Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10 } + const addPitchText = (line) => { + removePitchText(line) + const { startPoint, endPoint, direction, attributes } = line + + let left, top + + if (direction === 'top') { + left = (startPoint.x + endPoint.x) / 2 + top = (startPoint.y + endPoint.y) / 2 - 50 + } else if (direction === 'bottom') { + left = (startPoint.x + endPoint.x) / 2 + top = (startPoint.y + endPoint.y) / 2 - 50 + } else if (direction === 'left') { + left = (startPoint.x + endPoint.x) / 2 + 50 + top = (startPoint.y + endPoint.y) / 2 - 30 + } else if (direction === 'right') { + left = (startPoint.x + endPoint.x) / 2 + 50 + top = (startPoint.y + endPoint.y) / 2 - 30 + } + + const text = new fabric.Text( + `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + attributes.pitch : ''}`, + { + left, + top, + fontSize: 20, + fill: 'black', + name: 'pitchText', + parentId: line.id, + }, + ) + + canvas.add(text) + } + + const removePitchText = (line) => { + const { id } = line + const pitchText = canvas.getObjects().filter((obj) => obj.name === 'pitchText' && obj.parentId === id) + + // 기존 pitchText가 있으면 삭제 + if (pitchText.length > 0) { + canvas.remove(pitchText) + } + } + + const addPitchTextsByOuterLines = () => { + canvas + .getObjects() + .filter((obj) => obj.name === 'outerLine') + .forEach((line) => { + addPitchText(line) + }) + } + return { addLine, removeLine, hideLine, showLine, + addPitchText, + removePitchText, + addPitchTextsByOuterLines, } } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 858c13f7..be42ef52 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1715,7 +1715,7 @@ export function useMode() { roof.setWall(wall) roof.lines.forEach((line, index) => { - line.attributes = { type: wall.lines[index].attributes.type } + line.attributes = wall.lines[index].attributes }) setRoof(roof) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 514c6592..3fbf1388 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -199,6 +199,7 @@ export const usePolygon = () => { parent: polygon, stickeyPoint: stickeyPoint, visible: isFlowDisplay, + pitch: polygon.pitch, }) polygon.arrow = arrow @@ -399,7 +400,7 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { - const text = new fabric.Text(`${txt}${index + 1}`, { + const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, { fontSize: arrow.parent.fontSize, fill: 'black', originX: 'center', diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index bfdf78a4..c5ddc9cb 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1127,7 +1127,7 @@ export const splitPolygonWithLines = (polygon) => { }) roofs.forEach((roofPoint, index) => { - let defense + let defense, pitch const direction = getDirectionByPoint(roofPoint[0], roofPoint[roofPoint.length - 1]) switch (direction) { @@ -1144,6 +1144,7 @@ export const splitPolygonWithLines = (polygon) => { defense = 'north' break } + pitch = polygon.lines[index].attributes?.pitch ?? 0 const roof = new QPolygon(roofPoint, { fontSize: polygon.fontSize, @@ -1156,6 +1157,7 @@ export const splitPolygonWithLines = (polygon) => { selectable: true, defense: defense, direction: defense, + pitch: pitch, }) polygon.canvas.add(roof) From 67cabab44d68529d60580186a1650482daa64a01 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 22 Oct 2024 16:51:43 +0900 Subject: [PATCH 044/139] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=20=ED=85=8C=EB=91=90=EB=A6=AC=EB=A7=8C,=20=EB=9D=BC?= =?UTF-8?q?=EC=9D=B8=ED=95=B4=EC=B9=98,=20=EC=98=AC=ED=8E=98=EC=9D=B8?= =?UTF-8?q?=ED=8A=B8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dictionary.txt | 3 +- .../modal/setting01/FirstOption.jsx | 12 ++++- src/hooks/surface/useSurfaceShapeBatch.js | 6 ++- src/util/canvas-util.js | 52 +++++++++++++++++-- 4 files changed, 66 insertions(+), 7 deletions(-) diff --git a/docs/dictionary.txt b/docs/dictionary.txt index cef0921e..0864da77 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -10,7 +10,8 @@ 복도치수(입력치수): inputSize 실제치수: actualSize 테두리만: borderOnly -라인해치: lineHatching +라인해치: lineHatch +Allpainted : allPainted 문자글꼴: textFont 흐름방향글꼴 : flowDirectionFont 회로번호글꼴: circuitNumberFont diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index 848596ba..6373d8a8 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -1,10 +1,13 @@ -import { useRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' import { useFirstOption } from '@/hooks/option/useFirstOption' +import { setSurfaceShapePattern } from '@/util/canvas-util' +import { canvasState } from '@/store/canvasAtom' +import { POLYGON_TYPE } from '@/common/common' export default function FirstOption() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 @@ -15,6 +18,7 @@ export default function FirstOption() { const { getMessage } = useMessage() const { get, post } = useAxios() const { swalFire } = useSwal() + const canvas = useRecoilValue(canvasState) // 데이터를 최초 한 번만 조회 useEffect(() => { @@ -124,6 +128,12 @@ export default function FirstOption() { return option2 }) + const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + + polygons.forEach((polygon) => { + setSurfaceShapePattern(polygon, item.column) + }) + //치수 표시 } else { const options = settingModalFirstOptions?.dimensionDisplay.map((option) => { diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 23e017bd..ac28d8ed 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -9,6 +9,7 @@ import { QPolygon } from '@/components/fabric/QPolygon' import { useSwal } from '@/hooks/useSwal' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' +import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() @@ -17,6 +18,8 @@ export function useSurfaceShapeBatch() { const globalPitch = useRecoilValue(globalPitchState) const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() + const firstSettings = useRecoilValue(settingModalFirstOptionsState) + const secondSettings = useRecoilValue(settingModalSecondOptionsState) const applySurfaceShape = (surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) => { let length1, length2, length3, length4, length5 @@ -119,7 +122,8 @@ export function useSurfaceShapeBatch() { isDrawing = false obj.set('name', POLYGON_TYPE.ROOF) initEvent() - setSurfaceShapePattern(obj) + const displayMode = firstSettings.option2.filter((item) => item.selected)[0].column + setSurfaceShapePattern(obj, displayMode) setShowPlacementSurfaceSettingModal(true) }) } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 0e49e67d..7e26e460 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -1,5 +1,6 @@ import { intersect } from 'mathjs' import * as turf from '@turf/turf' + /** * Collection of function to use on canvas */ @@ -773,7 +774,7 @@ export const rectToPolygon = (rect) => { } //면형상 선택 클릭시 지붕 패턴 입히기 -export function setSurfaceShapePattern(polygon) { +export function setSurfaceShapePattern(polygon, mode = 'onlyBorder') { const ratio = window.devicePixelRatio || 1 let width = 265 / 10 @@ -797,8 +798,9 @@ export function setSurfaceShapePattern(polygon) { const rows = Math.floor(patternSourceCanvas.height / patternSize.height) const cols = Math.floor(patternSourceCanvas.width / patternSize.width) - ctx.strokeStyle = 'green' - ctx.lineWidth = 0.4 + ctx.strokeStyle = mode === 'allPainted' ? 'black' : 'green' + ctx.lineWidth = mode === 'allPainted' ? 1 : 0.4 + ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white' if (polygon.direction === 'east' || polygon.direction === 'west') { offset = roofStyle === 1 ? 0 : patternSize.height / 2 @@ -810,6 +812,9 @@ export function setSurfaceShapePattern(polygon) { ctx.moveTo(x, yStart) // 선 시작점 ctx.lineTo(x, yEnd) // 선 끝점 ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) + } for (let row = 0; row <= rows; row++) { const y = row * patternSize.height + (col % 2 === 0 ? 0 : offset) @@ -819,6 +824,9 @@ export function setSurfaceShapePattern(polygon) { ctx.moveTo(xStart, y) // 선 시작점 ctx.lineTo(xEnd, y) // 선 끝점 ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height) + } } } } else { @@ -829,6 +837,9 @@ export function setSurfaceShapePattern(polygon) { ctx.moveTo(0, y) // 선 시작점 ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점 ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height) + } for (let col = 0; col <= cols; col++) { const x = col * patternSize.width + (row % 2 === 0 ? 0 : offset) @@ -839,13 +850,46 @@ export function setSurfaceShapePattern(polygon) { ctx.moveTo(x, yStart) // 선 시작점 ctx.lineTo(x, yEnd) // 선 끝점 ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) + } } } } + const hachingPatternSourceCanvas = document.createElement('canvas') + + if (mode === 'lineHatch') { + hachingPatternSourceCanvas.width = polygon.width * ratio + hachingPatternSourceCanvas.height = polygon.height * ratio + + const ctx1 = hachingPatternSourceCanvas.getContext('2d') + + const gap = 10 + + ctx1.strokeStyle = 'green' // 선 색상 + ctx1.lineWidth = 0.3 // 선 두께 + + for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) { + ctx1.beginPath() + ctx1.moveTo(x, 0) // 선 시작점 + ctx1.lineTo(0, x) // 선 끝점 + ctx1.stroke() + } + } + + const combinedPatternCanvas = document.createElement('canvas') + combinedPatternCanvas.width = polygon.width * ratio + combinedPatternCanvas.height = polygon.height * ratio + const combinedCtx = combinedPatternCanvas.getContext('2d') + + // 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘 + combinedCtx.drawImage(patternSourceCanvas, 0, 0) + combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0) + // 패턴 생성 const pattern = new fabric.Pattern({ - source: patternSourceCanvas, + source: combinedPatternCanvas, repeat: 'repeat', }) From 6c37af9ef3f384faac6f516f8729fdc06f78d81f Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 22 Oct 2024 17:11:16 +0900 Subject: [PATCH 045/139] =?UTF-8?q?=EB=B0=B0=EC=B9=98=EB=A9=B4=20=EA=B7=B8?= =?UTF-8?q?=EB=A6=AC=EA=B8=B0=20=ED=8C=A8=ED=84=B4=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/surface/usePlacementShapeDrawing.js | 6 ++++-- src/hooks/surface/useSurfaceShapeBatch.js | 8 +++----- src/store/settingAtom.js | 7 ++++--- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index 91725a1c..b3e207dc 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -30,15 +30,17 @@ import { } from '@/store/placementShapeDrawingAtom' import { usePolygon } from '@/hooks/usePolygon' import { POLYGON_TYPE } from '@/common/common' - +import { roofDisplaySelector } from '@/store/settingAtom' // 면형상 배치 export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { const canvas = useRecoilValue(canvasState) + const roofDisplay = useRecoilValue(roofDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } = useEvent() const { getIntersectMousePoint } = useMouse() const { addLine, removeLine } = useLine() const { addPolygonByLines, drawDirectionArrow } = usePolygon() + const { tempGridMode } = useTempGrid() const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) @@ -221,7 +223,7 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { pitch: globalPitch, }) - setSurfaceShapePattern(roof) + setSurfaceShapePattern(roof, roofDisplay.column) drawDirectionArrow(roof) lines.forEach((line) => { diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index ac28d8ed..d0c58944 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -9,17 +9,16 @@ import { QPolygon } from '@/components/fabric/QPolygon' import { useSwal } from '@/hooks/useSwal' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' -import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { roofDisplaySelector } from '@/store/settingAtom' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) const globalPitch = useRecoilValue(globalPitchState) + const roofDisplay = useRecoilValue(roofDisplaySelector) const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() - const firstSettings = useRecoilValue(settingModalFirstOptionsState) - const secondSettings = useRecoilValue(settingModalSecondOptionsState) const applySurfaceShape = (surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) => { let length1, length2, length3, length4, length5 @@ -122,8 +121,7 @@ export function useSurfaceShapeBatch() { isDrawing = false obj.set('name', POLYGON_TYPE.ROOF) initEvent() - const displayMode = firstSettings.option2.filter((item) => item.selected)[0].column - setSurfaceShapePattern(obj, displayMode) + setSurfaceShapePattern(obj, roofDisplay.column) setShowPlacementSurfaceSettingModal(true) }) } diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 8560c700..c6e94029 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -149,10 +149,11 @@ export const corridorDimensionSelector = selector({ }) // 디스플레이 설정 - 화면 표시 -export const realDimensionSelector = selector({ - key: 'realDimensionSelector', +export const roofDisplaySelector = selector({ + key: 'roofDisplaySelector', get: ({ get }) => { const settingModalFirstOptions = get(settingModalFirstOptionsState) - return settingModalFirstOptions.dimensionDisplay.find((option) => option.selected) + return settingModalFirstOptions.option2.find((option) => option.selected) }, + dangerouslyAllowMutability: true, }) From 442d8e56a2d9edb09c4bddeb789a9174fcf5407e Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 22 Oct 2024 17:15:57 +0900 Subject: [PATCH 046/139] =?UTF-8?q?=EB=A9=94=EB=89=B4=20=EB=AA=A8=EB=8B=AC?= =?UTF-8?q?=20=EC=8B=A0=EA=B7=9C=20=EB=AA=A8=EB=8B=AC=20=EC=BB=B4=ED=8F=AC?= =?UTF-8?q?=EB=84=8C=ED=8A=B8=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../{withDraggable.jsx => WithDraggable.jsx} | 0 src/components/common/font/FontSetting.jsx | 2 +- src/components/floor-plan/CanvasMenu.jsx | 58 ++------ src/components/floor-plan/FloorPlan.jsx | 93 +----------- src/components/floor-plan/MenuDepth01.jsx | 133 +++++++++--------- src/components/floor-plan/modal/Slope.jsx | 11 +- .../modal/auxiliary/AuxiliaryDrawing.jsx | 12 +- .../floor-plan/modal/basic/BasicSetting.jsx | 8 +- .../circuitTrestle/CircuitTrestleSetting.jsx | 6 +- .../modal/eavesGable/EavesGableEdit.jsx | 10 +- .../modal/movement/MovementSetting.jsx | 8 +- .../floor-plan/modal/object/ObjectSetting.jsx | 8 +- .../outerlinesetting/PropertiesSetting.jsx | 22 +-- .../outerlinesetting/WallLineSetting.jsx | 18 ++- .../placementShape/PlacementShapeDrawing.jsx | 10 +- .../placementShape/PlacementShapeSetting.jsx | 8 +- .../PlacementSurfaceSetting.jsx | 9 +- .../roofAllocation/RoofAllocationSetting.jsx | 10 +- .../roofShape/RoofShapePassivitySetting.jsx | 13 +- .../modal/roofShape/RoofShapeSetting.jsx | 12 +- .../modal/setting01/SecondOption.jsx | 18 ++- .../dimensionLine/DimensionLineSetting.jsx | 25 ++-- .../setting01/planSize/PlanSizeSetting.jsx | 2 +- .../wallLineOffset/WallLineOffsetSetting.jsx | 10 +- src/hooks/roofcover/useAuxiliaryDrawing.js | 22 ++- src/hooks/roofcover/useEavesGableEdit.js | 6 +- src/hooks/roofcover/useOuterLineWall.js | 116 ++++++++++++--- src/hooks/roofcover/usePropertiesSetting.js | 9 +- .../roofcover/useRoofAllocationSetting.js | 8 +- .../roofcover/useRoofShapePassivitySetting.js | 13 +- src/hooks/roofcover/useRoofShapeSetting.js | 12 +- .../roofcover/useWallLineOffsetSetting.js | 6 +- src/hooks/surface/usePlacementShapeDrawing.js | 113 ++++++++++++--- src/hooks/surface/useSurfaceShapeBatch.js | 85 ++++++++--- src/hooks/useContextMenu.js | 3 - src/hooks/usePopup.js | 16 ++- 36 files changed, 527 insertions(+), 388 deletions(-) rename src/components/common/draggable/{withDraggable.jsx => WithDraggable.jsx} (100%) diff --git a/src/components/common/draggable/withDraggable.jsx b/src/components/common/draggable/WithDraggable.jsx similarity index 100% rename from src/components/common/draggable/withDraggable.jsx rename to src/components/common/draggable/WithDraggable.jsx diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index d4896ab3..d738d016 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,4 +1,4 @@ -import WithDraggable from '@/components/common/draggable/withDraggable' +import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' import { useState } from 'react' diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 5846a8ff..1478ab13 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -27,6 +27,7 @@ import { popupState } from '@/store/popupAtom' import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' import { usePopup } from '@/hooks/usePopup' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' +import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -39,28 +40,7 @@ const canvasMenus = [ ] export default function CanvasMenu(props) { - const { - menuNumber, - setMenuNumber, - setShowCanvasSettingModal, - showOutlineModal, - setShowOutlineModal, - setShowPlaceShapeModal, - setShowSlopeSettingModal, - setShowPlacementSurfaceSettingModal, - setShowPlaceShapeDrawingModal, - setShowRoofShapeSettingModal, - setShowObjectSettingModal, - setShowRoofShapePassivitySettingModal, - setShowAuxiliaryModal, - setShowEavesGableEditModal, - setShowMovementModal, - setShowWallLineOffsetSettingModal, - setShowRoofAllocationSettingModal, - setShowBasicSettingModal, - setShowCircuitTrestleSettingModal, - setShowPropertiesSettingModal, - } = props + const { menuNumber, setMenuNumber } = props const { addPopup, closePopup } = usePopup() const [type, setType] = useState('') @@ -115,22 +95,6 @@ export default function CanvasMenu(props) { } } const menuProps = { - setShowOutlineModal, - setShowPlaceShapeModal, - setShowRoofShapeSettingModal, - setShowRoofShapePassivitySettingModal, - setShowAuxiliaryModal, - setShowEavesGableEditModal, - setShowMovementModal, - setShowSlopeSettingModal, - setShowPlacementSurfaceSettingModal, - setShowPlaceShapeDrawingModal, - setShowWallLineOffsetSettingModal, - setShowRoofAllocationSettingModal, - setShowObjectSettingModal, - setShowBasicSettingModal, - setShowCircuitTrestleSettingModal, - setShowPropertiesSettingModal, type, } @@ -140,7 +104,6 @@ export default function CanvasMenu(props) { if (menuNumber === 1) { onClickPlacementInitialMenu() } - if (menuNumber !== 2 && showOutlineModal) setShowOutlineModal(false) }, [menuNumber, type]) // 저장버튼(btn08) 클릭 시 호출되는 함수 @@ -154,12 +117,17 @@ export default function CanvasMenu(props) { // }) } + const [placementInitialId, setPlacementInitialId] = useState(uuidv4()) + const placementInitialProps = { + id: placementInitialId, + pos: { + x: 50, + y: 180, + }, + } const onClickPlacementInitialMenu = () => { - setShowOutlineModal(false) - setShowCanvasSettingModal(false) - setShowEavesGableEditModal(false) - setShowMovementModal(false) - setShowPlaceShapeModal(true) + addPopup(placementInitialId, 1, ) + // setShowPlaceShapeModal(true) } const handleClear = () => { @@ -177,7 +145,7 @@ export default function CanvasMenu(props) { const handlePopup = () => { const id = uuidv4() - addPopup(id, 1, ) + addPopup(id, 0, ) } const commonTextMode = () => { diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 21b90616..655c7340 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -1,50 +1,15 @@ 'use client' import { useEffect, useState } from 'react' -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' -import { settingModalFirstOptionsState, settingModalGridOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import '@/styles/contents.scss' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import CanvasLayout from '@/components/floor-plan/CanvasLayout' -import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' -import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' -import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' -import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' -import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' -import Slope from '@/components/floor-plan/modal/Slope' - -import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing' -import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit' -import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting' -import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting' -import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting' -import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting' -import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting' -import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' -import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' -import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' -import { gridColorState } from '@/store/gridAtom' export default function FloorPlan() { - const [showCanvasSettingModal, setShowCanvasSettingModal] = useState(false) - const [showOutlineModal, setShowOutlineModal] = useState(false) - const [showPlaceShapeModal, setShowPlaceShapeModal] = useState(false) - const [showPropertiesSettingModal, setShowPropertiesSettingModal] = useState(false) - const [showRoofShapeSettingModal, setShowRoofShapeSettingModal] = useState(false) - const [showRoofShapePassivitySettingModal, setShowRoofShapePassivitySettingModal] = useState(false) - const [showAuxiliaryModal, setShowAuxiliaryModal] = useState(false) - const [showSlopeSettingModal, setShowSlopeSettingModal] = useState(false) - const [showPlacementSurfaceSettingModal, setShowPlacementSurfaceSettingModal] = useState(false) - const [showPlaceShapeDrawingModal, setShowPlaceShapeDrawingModal] = useState(false) - const [showObjectSettingModal, setShowObjectSettingModal] = useState(false) - const [showEavesGableEditModal, setShowEavesGableEditModal] = useState(false) - const [showMovementModal, setShowMovementModal] = useState(false) - const [showWallLineOffsetSettingModal, setShowWallLineOffsetSettingModal] = useState(false) - const [showRoofAllocationSettingModal, setShowRoofAllocationSettingModal] = useState(false) - const [showBasicSettingModal, setShowBasicSettingModal] = useState(false) - const [showCircuitTrestleSettingModal, setShowCircuitTrestleSettingModal] = useState(false) const globalLocaleState = useRecoilValue(globalLocaleStore) const { get } = useAxios(globalLocaleState) @@ -53,44 +18,16 @@ export default function FloorPlan() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [menuNumber, setMenuNumber] = useState(null) - const [showDotLineGridModal, setShowDotLineGridModal] = useState(false) - const [showGridCopyModal, setShowGridCopyModal] = useState(false) - const [showGridMoveModal, setShowGridMoveModal] = useState(false) - const [color, setColor] = useRecoilState(gridColorState) - const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) - - const outlineProps = { - setShowOutlineModal, - setShowPropertiesSettingModal, - } const modalProps = { menuNumber, setMenuNumber, - setShowCanvasSettingModal, - showOutlineModal, - setShowOutlineModal, - setShowPlaceShapeModal, - setShowSlopeSettingModal, - setShowPlacementSurfaceSettingModal, - setShowPlaceShapeDrawingModal, - setShowRoofShapeSettingModal, - setShowObjectSettingModal, - setShowRoofShapePassivitySettingModal, - setShowAuxiliaryModal, - setShowEavesGableEditModal, - setShowMovementModal, - setShowWallLineOffsetSettingModal, - setShowRoofAllocationSettingModal, - setShowBasicSettingModal, - setShowCircuitTrestleSettingModal, - setShowPropertiesSettingModal, } useEffect(() => { console.log('FloorPlan useEffect 실행') fetchSettings() - }, [showOutlineModal, objectNo]) + }, [objectNo]) // Canvas Setting 조회 const fetchSettings = async () => { @@ -118,36 +55,12 @@ export default function FloorPlan() { } } - const propertiesSettingProps = { - setShowPropertiesSettingModal, - } - - useEffect(() => {}, [showOutlineModal]) - return ( <>
    - {showOutlineModal && } - {showPropertiesSettingModal && } - {showPlaceShapeModal && } - {showRoofShapeSettingModal && } - {showRoofShapePassivitySettingModal && ( - - )} - {showAuxiliaryModal && } - {showSlopeSettingModal && } - {showPlaceShapeDrawingModal && } - {showEavesGableEditModal && } - {showMovementModal && } - {showRoofAllocationSettingModal && } - {showWallLineOffsetSettingModal && } - {showObjectSettingModal && } - {showPlacementSurfaceSettingModal && } - {showBasicSettingModal && } - {showCircuitTrestleSettingModal && }
    diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index 763dc92b..113a1f0e 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -6,85 +6,92 @@ import { MENU } from '@/common/common' import { currentMenuState } from '@/store/canvasAtom' import { useSetRecoilState } from 'recoil' import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' +import { usePopup } from '@/hooks/usePopup' +import { v4 as uuidv4 } from 'uuid' +import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' +import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' +import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting' +import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing' +import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit' +import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting' +import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting' +import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' +import Slope from '@/components/floor-plan/modal/Slope' +import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting' +import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' +import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting' +import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' +import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' + export default function MenuDepth01(props) { - const { - setShowOutlineModal, - type, - setShowPlaceShapeModal, - setShowRoofShapeSettingModal, - setShowRoofShapePassivitySettingModal, - setShowAuxiliaryModal, - setShowEavesGableEditModal, - setShowMovementModal, - setShowSlopeSettingModal, - setShowPlacementSurfaceSettingModal, - setShowPlaceShapeDrawingModal, - setShowWallLineOffsetSettingModal, - setShowRoofAllocationSettingModal, - setShowObjectSettingModal, - setShowBasicSettingModal, - setShowCircuitTrestleSettingModal, - setShowPropertiesSettingModal, - } = props + const { type } = props const { getMessage } = useMessage() const [activeMenu, setActiveMenu] = useState() const setCurrentMenu = useSetRecoilState(currentMenuState) - const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch() - + const { addPopup } = usePopup() + const [outlineId, setOutlineId] = useState(uuidv4()) const onClickMenu = ({ id, menu, name }) => { setActiveMenu(menu) - setShowOutlineModal(menu === MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) setCurrentMenu(menu) - setShowPlaceShapeModal(false) if (type === 'outline') { - setShowOutlineModal(id === 0) - setShowRoofShapeSettingModal(id === 1) - setShowRoofShapePassivitySettingModal(id === 2) - setShowAuxiliaryModal(id === 3) - setShowEavesGableEditModal(id === 4) - setShowMovementModal(id === 5) - setShowWallLineOffsetSettingModal(id === 6) - setShowRoofAllocationSettingModal(id === 7) - setShowPlaceShapeDrawingModal(false) - setShowPropertiesSettingModal(false) - setShowCircuitTrestleSettingModal(false) + switch (id) { + case 0: + addPopup(outlineId, 1, ) + break + case 1: + addPopup(outlineId, 1, ) + break + case 2: + addPopup(outlineId, 1, ) + break + case 3: + addPopup(outlineId, 1, ) + break + case 4: + addPopup(outlineId, 1, ) + break + case 5: + addPopup(outlineId, 1, ) + break + case 6: + addPopup(outlineId, 1, ) + break + case 7: + addPopup(outlineId, 1, ) + break + } } if (type === 'surface') { - setShowOutlineModal(false) - setShowRoofShapeSettingModal(false) - setShowRoofShapePassivitySettingModal(false) - setShowAuxiliaryModal(false) - setShowEavesGableEditModal(false) - setShowMovementModal(false) - setShowWallLineOffsetSettingModal(false) - setShowRoofAllocationSettingModal(false) - setShowPropertiesSettingModal(false) - setShowCircuitTrestleSettingModal(false) - setShowSlopeSettingModal(id === 0) - setShowPlaceShapeDrawingModal(id === 1) - setShowPlacementSurfaceSettingModal(id === 2) - setShowObjectSettingModal(id === 3) - - //배치면 전체 삭제 - if (id === 4) { - deleteAllSurfacesAndObjects() + switch (id) { + case 0: + addPopup(outlineId, 1, ) + break + case 1: + addPopup(outlineId, 1, ) + break + case 2: + addPopup(outlineId, 1, ) + break + case 3: + addPopup(outlineId, 1, ) + break + case 4: + deleteAllSurfacesAndObjects() + break } } if (type === 'module') { - setShowOutlineModal(false) - setShowRoofShapeSettingModal(false) - setShowRoofShapePassivitySettingModal(false) - setShowAuxiliaryModal(false) - setShowEavesGableEditModal(false) - setShowMovementModal(false) - setShowWallLineOffsetSettingModal(false) - setShowRoofAllocationSettingModal(false) - setShowPropertiesSettingModal(false) - setShowBasicSettingModal(id === 0) - setShowCircuitTrestleSettingModal(id === 1) + switch (id) { + case 0: + addPopup(outlineId, 1, ) + break + case 1: + addPopup(outlineId, 1, ) + break + } } } diff --git a/src/components/floor-plan/modal/Slope.jsx b/src/components/floor-plan/modal/Slope.jsx index 4e6d63aa..ffe32af6 100644 --- a/src/components/floor-plan/modal/Slope.jsx +++ b/src/components/floor-plan/modal/Slope.jsx @@ -3,17 +3,20 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { globalPitchState } from '@/store/canvasAtom' import { useRecoilState } from 'recoil' import { useRef } from 'react' +import { usePopup } from '@/hooks/usePopup' -export default function Slope({ setShowSlopeSettingModal }) { +export default function Slope({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const [globalPitch, setGlobalPitch] = useRecoilState(globalPitchState) const inputRef = useRef() + return ( - +

    {getMessage('plan.menu.placement.surface.slope.setting')}

    -
    @@ -34,7 +37,7 @@ export default function Slope({ setShowSlopeSettingModal }) { className="btn-frame modal act" onClick={() => { setGlobalPitch(inputRef.current.value) - setShowSlopeSettingModal(false) + closePopup(id) }} > {getMessage('modal.common.save')} diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx index 8ce885c4..84e7ab91 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryDrawing.jsx @@ -7,9 +7,11 @@ import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' import { useAuxiliaryDrawing } from '@/hooks/roofcover/useAuxiliaryDrawing' +import { usePopup } from '@/hooks/usePopup' -export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { +export default function AuxiliaryDrawing({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const types = [ { id: 1, name: getMessage('straight.line'), type: OUTER_LINE_TYPE.OUTER_LINE }, @@ -47,7 +49,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { handleFix, buttonAct, setButtonAct, - } = useAuxiliaryDrawing(setShowAuxiliaryModal) + } = useAuxiliaryDrawing(id) const outerLineProps = { length1, @@ -121,11 +123,11 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { setType(button.type) } return ( - +

    {getMessage('modal.auxiliary.drawing')}

    -
    @@ -149,7 +151,7 @@ export default function AuxiliaryDrawing({ setShowAuxiliaryModal }) { -
    diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 94ad7317..6a7a1d0e 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -8,17 +8,19 @@ import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/Pitch import Placement from '@/components/floor-plan/modal/basic/step/Placement' import { useRecoilState } from 'recoil' import { canvasSettingState } from '@/store/canvasAtom' +import { usePopup } from '@/hooks/usePopup' -export default function BasicSetting({ setShowBasicSettingModal }) { +export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const [tabNum, setTabNum] = useState(1) const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) return ( - +

    {getMessage('plan.menu.module.circuit.setting.default')}

    -
    diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 6daf04b2..36082642 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -4,9 +4,11 @@ import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle import CircuitAllocation from '@/components/floor-plan/modal/circuitTrestle/step/CircuitAllocation' import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' -export default function CircuitTrestleSetting({ setShowCircuitTrestleSettingModal }) { +export default function CircuitTrestleSetting({ id }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const [tabNum, setTabNum] = useState(1) const [circuitAllocationType, setCircuitAllocationType] = useState(1) const circuitProps = { @@ -18,7 +20,7 @@ export default function CircuitTrestleSetting({ setShowCircuitTrestleSettingModa

    {getMessage('modal.circuit.trestle.setting')}

    -
    diff --git a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx index b19f435e..ab8553a2 100644 --- a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx +++ b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx @@ -5,11 +5,13 @@ import Gable from '@/components/floor-plan/modal/eavesGable/type/Gable' import WallMerge from '@/components/floor-plan/modal/eavesGable/type/WallMerge' import Shed from '@/components/floor-plan/modal/eavesGable/type/Shed' import { useEavesGableEdit } from '@/hooks/roofcover/useEavesGableEdit' +import { usePopup } from '@/hooks/usePopup' -export default function EavesGableEdit({ setShowEavesGableEditModal }) { +export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() - const { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef } = useEavesGableEdit(setShowEavesGableEditModal) + const { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef } = useEavesGableEdit(id) const eavesProps = { pitchRef, offsetRef, @@ -34,11 +36,11 @@ export default function EavesGableEdit({ setShowEavesGableEditModal }) { } return ( - +

    {getMessage('modal.eaves.gable.edit')}

    -
    diff --git a/src/components/floor-plan/modal/movement/MovementSetting.jsx b/src/components/floor-plan/modal/movement/MovementSetting.jsx index 2e6bd7ec..fabf813c 100644 --- a/src/components/floor-plan/modal/movement/MovementSetting.jsx +++ b/src/components/floor-plan/modal/movement/MovementSetting.jsx @@ -3,9 +3,11 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { useState } from 'react' import FlowLine from '@/components/floor-plan/modal/movement/type/FlowLine' import Updown from '@/components/floor-plan/modal/movement/type/Updown' +import { usePopup } from '@/hooks/usePopup' -export default function MovementSetting({ setShowMovementModal }) { +export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const [buttonAct, setButtonAct] = useState(1) const buttonMenu = [ { id: 1, name: getMessage('modal.movement.flow.line.move') }, @@ -13,11 +15,11 @@ export default function MovementSetting({ setShowMovementModal }) { ] return ( - +

    {getMessage('plan.menu.roof.cover.movement.shape.updown')}

    -
    diff --git a/src/components/floor-plan/modal/object/ObjectSetting.jsx b/src/components/floor-plan/modal/object/ObjectSetting.jsx index d98b76b0..86a4f3a0 100644 --- a/src/components/floor-plan/modal/object/ObjectSetting.jsx +++ b/src/components/floor-plan/modal/object/ObjectSetting.jsx @@ -12,13 +12,15 @@ import OpenSpace from '@/components/floor-plan/modal/object/type/OpenSpace' import Shadow from '@/components/floor-plan/modal/object/type/Shadow' import TriangleDormer from '@/components/floor-plan/modal/object/type/TriangleDormer' import PentagonDormer from '@/components/floor-plan/modal/object/type/PentagonDormer' +import { usePopup } from '@/hooks/usePopup' -export default function ObjectSetting({ setShowObjectSettingModal }) { +export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) const [buttonAct, setButtonAct] = useState(1) const { swalFire } = useSwal() const { applyOpeningAndShadow, applyDormers } = useObjectBatch() + const { closePopup } = usePopup() const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) @@ -70,11 +72,11 @@ export default function ObjectSetting({ setShowObjectSettingModal }) { { id: 4, name: getMessage('modal.object.setting.type.pentagon.dormer') }, ] return ( - +

    {getMessage('plan.menu.placement.surface.object')}

    -
    diff --git a/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx b/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx index a1e848be..6c2c8d3f 100644 --- a/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/PropertiesSetting.jsx @@ -4,21 +4,15 @@ import { usePropertiesSetting } from '@/hooks/roofcover/usePropertiesSetting' export default function PropertiesSetting(props) { const { getMessage } = useMessage() - const { setShowPropertiesSettingModal } = props - - const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting(setShowPropertiesSettingModal) + const { id, pos = { x: 50, y: 230 } } = props + const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting(id) return ( - +

    {getMessage('modal.canvas.setting.wallline.properties.setting')}

    -
    @@ -39,13 +33,7 @@ export default function PropertiesSetting(props) { -
    diff --git a/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx b/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx index 84e59da4..a98c937a 100644 --- a/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx +++ b/src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx @@ -9,10 +9,15 @@ import RightAngle from '@/components/floor-plan/modal/lineTypes/RightAngle' import Angle from '@/components/floor-plan/modal/lineTypes/Angle' import DoublePitch from '@/components/floor-plan/modal/lineTypes/DoublePitch' import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' +import { usePopup } from '@/hooks/usePopup' +import { useState } from 'react' +import { v4 as uuidv4 } from 'uuid' export default function WallLineSetting(props) { - const { setShowOutlineModal, setShowPropertiesSettingModal } = props + const { id } = props + const { addPopup, closePopup } = usePopup() const { getMessage } = useMessage() + const [propertiesId, setPropertiesId] = useState(uuidv4()) const { length1, setLength1, @@ -39,7 +44,7 @@ export default function WallLineSetting(props) { outerLineDiagonalLengthRef, handleRollback, handleFix, - } = useOuterLineWall(setShowOutlineModal) + } = useOuterLineWall(id, propertiesId) const outerLineProps = { length1, @@ -113,9 +118,8 @@ export default function WallLineSetting(props) {

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

    - + {/*
    @@ -172,7 +176,9 @@ export default function WallLineSetting(props) { className="btn-frame modal act" onClick={() => { handleFix() - setShowPropertiesSettingModal(true) + // closePopup(id) + + // setShowPropertiesSettingModal(true) }} > {getMessage('modal.cover.outline.fix')} diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx index 9374dbf9..304d0169 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeDrawing.jsx @@ -8,9 +8,11 @@ import Diagonal from '@/components/floor-plan/modal/lineTypes/Diagonal' import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' import OuterLineWall from '@/components/floor-plan/modal/lineTypes/OuterLineWall' import { usePlacementShapeDrawing } from '@/hooks/surface/usePlacementShapeDrawing' +import { usePopup } from '@/hooks/usePopup' -export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) { +export default function PlacementShapeDrawing({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const [buttonAct, setButtonAct] = useState(1) const types = [ { id: 1, name: getMessage('straight.line'), type: OUTER_LINE_TYPE.OUTER_LINE }, @@ -45,7 +47,7 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) outerLineDiagonalLengthRef, handleRollback, handleFix, - } = usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) + } = usePlacementShapeDrawing(id) const outerLineProps = { length1, @@ -119,11 +121,11 @@ export default function PlacementShapeDrawing({ setShowPlaceShapeDrawingModal }) setType(button.type) } return ( - +

    {getMessage('plan.menu.placement.surface.drawing')}

    -
    diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index bc7ba2b7..79a89b88 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -7,13 +7,15 @@ import { canvasSettingState } from '@/store/canvasAtom' import { useMessage } from '@/hooks/useMessage' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' -export default function PlacementShapeSetting({ setShowPlaceShapeModal }) { +export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) { const [objectNo, setObjectNo] = useState('test123241008001') // 후에 삭제 필요 const [showSizeGuideModal, setShowSizeGuidModal] = useState(false) const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false) const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(1) const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) + const { closePopup } = usePopup() const [basicSetting, setBasicSettings] = useState({ roofSizeSet: 1, roofAngleSet: 'slope', @@ -169,11 +171,11 @@ export default function PlacementShapeSetting({ setShowPlaceShapeModal }) { } return ( - +

    {getMessage('plan.menu.placement.surface.initial.setting')}

    -
    diff --git a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx index 90e05dbf..d6666d5c 100644 --- a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx +++ b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx @@ -7,15 +7,16 @@ import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' +import { usePopup } from '@/hooks/usePopup' -export default function PlacementSurfaceSetting({ setShowPlacementSurfaceSettingModal }) { +export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const [selectedType, setSelectedType] = useState() const [rotate, setRotate] = useState(0) const [xInversion, setXInversion] = useState(false) const [yInversion, setYInversion] = useState(false) const canvas = useRecoilValue(canvasState) - + const { closePopup } = usePopup() const { applySurfaceShape } = useSurfaceShapeBatch() const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) @@ -231,7 +232,7 @@ export default function PlacementSurfaceSetting({ setShowPlacementSurfaceSetting surfaceRefs.xInversion = xInversion //좌우반전 surfaceRefs.yInversion = yInversion //상하반전 surfaceRefs.rotate = rotate * 90 //앵글 - applySurfaceShape(surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) + applySurfaceShape(surfaceRefs, selectedType, id) } useEffect(() => { @@ -243,7 +244,7 @@ export default function PlacementSurfaceSetting({ setShowPlacementSurfaceSetting

    {getMessage('plan.menu.placement.surface.arrangement')}

    -
    diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index 52ee2e3f..934f2f9d 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -2,18 +2,20 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { useRoofAllocationSetting } from '@/hooks/roofcover/useRoofAllocationSetting' +import { usePopup } from '@/hooks/usePopup' -export default function RoofAllocationSetting({ setShowRoofAllocationSettingModal }) { +export default function RoofAllocationSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() + const { closePopup } = usePopup() const { handleSave, onAddRoofMaterial, onDeleteRoofMaterial, values, roofMaterials, selectedRoofMaterial, setSelectedRoofMaterial } = - useRoofAllocationSetting(setShowRoofAllocationSettingModal) + useRoofAllocationSetting(id) return ( - +

    {getMessage('plan.menu.estimate.roof.alloc')}

    -
    diff --git a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx index 9e9dc93f..b9ddd97d 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx @@ -4,11 +4,12 @@ import Gable from '@/components/floor-plan/modal/roofShape/passivity/Gable' import Shed from '@/components/floor-plan/modal/roofShape/passivity/Shed' import { useMessage } from '@/hooks/useMessage' import { useRoofShapePassivitySetting } from '@/hooks/roofcover/useRoofShapePassivitySetting' +import { usePopup } from '@/hooks/usePopup' -export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySettingModal }) { - const { handleSave, handleConfirm, handleRollback, buttons, type, setType, TYPES, offsetRef, pitchRef } = - useRoofShapePassivitySetting(setShowRoofShapePassivitySettingModal) +export default function RoofShapePassivitySetting({ id, pos = { x: 50, y: 230 } }) { + const { handleSave, handleConfirm, handleRollback, buttons, type, setType, TYPES, offsetRef, pitchRef } = useRoofShapePassivitySetting(id) const { getMessage } = useMessage() + const { closePopup } = usePopup() const eavesProps = { offsetRef, @@ -25,11 +26,11 @@ export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySet } return ( - +

    {getMessage('plan.menu.roof.cover.roof.shape.passivity.setting')}

    -
    @@ -58,7 +59,7 @@ export default function RoofShapePassivitySetting({ setShowRoofShapePassivitySet
    -
    diff --git a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx index d92ed807..48058b1b 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx @@ -6,8 +6,9 @@ import Image from 'next/image' import Direction from '@/components/floor-plan/modal/roofShape/type/Direction' import { useRoofShapeSetting } from '@/hooks/roofcover/useRoofShapeSetting' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' -export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { +export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const { shapeNum, @@ -37,7 +38,8 @@ export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { buttonMenu, handleConfirm, handleRollBack, - } = useRoofShapeSetting(setShowRoofShapeSettingModal) + } = useRoofShapeSetting(id) + const { closePopup } = usePopup() const ridgeProps = { pitch, setPitch, eavesOffset, setEavesOffset } const patternProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset } @@ -79,11 +81,11 @@ export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { } return ( - +

    {getMessage('modal.roof.shape.setting')}

    -
    @@ -106,7 +108,7 @@ export default function RoofShapeSetting({ setShowRoofShapeSettingModal }) { {(shapeNum === 5 || shapeNum === 6 || shapeNum === 7 || shapeNum === 8) && }
    -
    diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index ca5edc32..987f521c 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -169,6 +169,12 @@ export default function SecondOption() { const [horizon, setHorizon] = useState(1600) const [vertical, setVertical] = useState(1600) + + const fontProps = { + id: fontId, + pos: { x: 745, y: 180 }, + setIsShow: setShowFontSettingModal, + } const planSizeProps = { id: planSizeId, horizon, @@ -176,11 +182,12 @@ export default function SecondOption() { vertical, setVertical, setIsShow: setShowPlanSizeSettingModal, - pos: { x: 1020, y: 180 }, + pos: { x: 1025, y: 180 }, } const handlePopup = (type) => { - const id = uuidv4() + setShowPlanSizeSettingModal(false) + setShowFontSettingModal(false) switch (type) { case 'dimensionLine': @@ -189,7 +196,7 @@ export default function SecondOption() { addPopup(dimensionId, 2, ) } else { setShowDimensionLineSettingModal(false) - closePopups([dimensionId, fontId]) + closePopup(dimensionId) } break @@ -197,10 +204,13 @@ export default function SecondOption() { case 'font2': //흐름 방향 글꼴 변경 case 'font3': //치수 글꼴변경 case 'font4': //회로번호 글꼴변경 - addPopup(fontId, 2, ) + setShowFontSettingModal(true) + + addPopup(fontId, 2, ) break case 'planSize': setShowPlanSizeSettingModal(true) + addPopup(planSizeId, 2, ) break } diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index d9b3059c..569a47d8 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -1,4 +1,4 @@ -import WithDraggable from '@/components/common/draggable/withDraggable' +import WithDraggable from '@/components/common/draggable/WithDraggable' import { usePopup } from '@/hooks/usePopup' import { v4 as uuidv4 } from 'uuid' import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' @@ -44,7 +44,17 @@ export default function DimensionLineSetting(props) { const [showColorPickerModal, setShowColorPickerModal] = useState(false) const [showFontModal, setShowFontModal] = useState(false) const { getMessage } = useMessage() + useEffect(() => { + console.log(2, isShow) + if (pixel) { + setOriginPixel(pixels?.filter((data) => data.value === pixel)[0]) + } + setIsShow(true) + }, []) + + useEffect(() => { + console.log(1, isShow) if (!isShow) { closePopups([fontModalId, colorModalId]) } @@ -81,23 +91,14 @@ export default function DimensionLineSetting(props) { const popupHandle = (type) => { switch (type) { case 'color': - closePopup(fontModalId) addPopup(colorModalId, 3, ) break case 'font': - closePopup(colorModalId) addPopup(fontModalId, 3, ) break } } - useEffect(() => { - console.log(pixel) - if (pixel) { - setOriginPixel(pixels?.filter((data) => data.value === pixel)[0]) - } - }, []) - return (
    @@ -106,10 +107,8 @@ export default function DimensionLineSetting(props) {
    diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index e5e79740..7d18c5a2 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -1,19 +1,11 @@ import { useEffect, useRef, useState } from 'react' -import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { - adsorptionPointAddModeState, - adsorptionPointModeState, - adsorptionRangeState, - canvasState, - dotLineIntervalSelector, - verticalHorizontalModeState, -} from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { adsorptionRangeState, canvasState } from '@/store/canvasAtom' import { useEvent } from '@/hooks/useEvent' import { useMouse } from '@/hooks/useMouse' import { useLine } from '@/hooks/useLine' import { useTempGrid } from '@/hooks/useTempGrid' import { - OUTER_LINE_TYPE, outerLineAngle1State, outerLineAngle2State, outerLineArrow1State, @@ -23,14 +15,15 @@ import { outerLineLength2State, outerLineTypeState, } from '@/store/outerLineAtom' -import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util' +import { calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util' import { fabric } from 'fabric' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useSwal } from '@/hooks/useSwal' import { booleanPointInPolygon } from '@turf/turf' +import { usePopup } from '@/hooks/usePopup' // 보조선 작성 -export function useAuxiliaryDrawing(setShowAuxiliaryModal) { +export function useAuxiliaryDrawing(id) { const canvas = useRecoilValue(canvasState) const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useEvent() const { getIntersectMousePoint } = useMouse() @@ -38,6 +31,7 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) { const { tempGridMode } = useTempGrid() const { swalFire } = useSwal() const { getAdsorptionPoints } = useAdsorptionPoint() + const { closePopup } = usePopup() const adsorptionRange = useRecoilValue(adsorptionRangeState) @@ -86,7 +80,7 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) { const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roofBase') if (roofs.length === 0) { swalFire({ text: '지붕형상이 없습니다.' }) - setShowAuxiliaryModal(false) + closePopup(id) return } @@ -653,7 +647,7 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) { roofBase.innerLines = [...roofInnerLines] }) - setShowAuxiliaryModal(false) + closePopup(id) } return { diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 083d8e03..66a7cb1a 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -8,12 +8,14 @@ import { useLine } from '@/hooks/useLine' import { useMode } from '@/hooks/useMode' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' // 처마.케라바 변경 -export function useEavesGableEdit(setShowEavesGableEditModal) { +export function useEavesGableEdit(id) { const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() const { addCanvasMouseEventListener, initEvent } = useEvent() + const { closePopup } = usePopup() const TYPES = { EAVES: 'eaves', GABLE: 'gable', @@ -44,7 +46,7 @@ export function useEavesGableEdit(setShowEavesGableEditModal) { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') if (!outerLineFix || outerLines.length === 0) { swalFire({ text: '외벽선이 없습니다.' }) - setShowEavesGableEditModal(false) + closePopup(id) } }, []) diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js index 4b4987af..531aab48 100644 --- a/src/hooks/roofcover/useOuterLineWall.js +++ b/src/hooks/roofcover/useOuterLineWall.js @@ -1,12 +1,11 @@ import { useEffect, useRef } from 'react' -import { distanceBetweenPoints, getDegreeByChon } from '@/util/canvas-util' +import { distanceBetweenPoints } from '@/util/canvas-util' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { adsorptionPointAddModeState, adsorptionPointModeState, adsorptionRangeState, canvasState, - currentCanvasPlanState, dotLineIntervalSelector, verticalHorizontalModeState, } from '@/store/canvasAtom' @@ -29,11 +28,12 @@ import { } from '@/store/outerLineAtom' import { calculateAngle } from '@/util/qpolygon-utils' import { fabric } from 'fabric' -import { QLine } from '@/components/fabric/QLine' import { outlineDisplaySelector } from '@/store/settingAtom' +import { usePopup } from '@/hooks/usePopup' +import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting' //외벽선 그리기 -export function useOuterLineWall(setShowOutlineModal) { +export function useOuterLineWall(id, propertiesId) { const canvas = useRecoilValue(canvasState) const { initEvent, @@ -71,6 +71,7 @@ export function useOuterLineWall(setShowOutlineModal) { const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(outerLineDiagonalState) const arrow1Ref = useRef(arrow1) const arrow2Ref = useRef(arrow2) + const { addPopup, closePopup } = usePopup() const setOuterLineFix = useSetRecoilState(outerLineFixState) @@ -221,7 +222,8 @@ export function useOuterLineWall(setShowOutlineModal) { removeAllDocumentEventListeners() canvas?.renderAll() setOuterLineFix(true) - setShowOutlineModal(false) + closePopup(id) + addPopup(propertiesId, 1, ) } if (points.length < 3) { @@ -419,56 +421,104 @@ export function useOuterLineWall(setShowOutlineModal) { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '↓' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '→') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y - length2Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length1Value / 10, + y: prev[prev.length - 1].y - length2Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↑') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '←' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '←' && arrow2Value === '↑') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } @@ -524,35 +574,65 @@ export function useOuterLineWall(setShowOutlineModal) { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '↓' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '→') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↑') { setPoints((prev) => { diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index ad703356..df4267ff 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -1,14 +1,15 @@ import { useEffect, useRef } from 'react' import { LINE_TYPE } from '@/common/common' -import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' +import { useRecoilValue, useResetRecoilState } from 'recoil' import { canvasState, currentObjectState } from '@/store/canvasAtom' import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' import { useLine } from '@/hooks/useLine' import { outerLinePointsState } from '@/store/outerLineAtom' +import { usePopup } from '@/hooks/usePopup' // 외벽선 속성 설정 -export function usePropertiesSetting(setShowPropertiesSettingModal) { +export function usePropertiesSetting(id) { const canvas = useRecoilValue(canvasState) const currentObject = useRecoilValue(currentObjectState) @@ -18,6 +19,7 @@ export function usePropertiesSetting(setShowPropertiesSettingModal) { const { addPolygonByLines } = usePolygon() const { removeLine, hideLine } = useLine() + const { closePopup } = usePopup() useEffect(() => { const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') @@ -142,6 +144,7 @@ export function usePropertiesSetting(setShowPropertiesSettingModal) { setPoints([]) canvas.renderAll() roof.drawHelpLine() + closePopup(id) } const closeModal = (fn) => { @@ -161,7 +164,7 @@ export function usePropertiesSetting(setShowPropertiesSettingModal) { canvas.renderAll() setPoints([]) - setShowPropertiesSettingModal(false) + closePopup(id) } return { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 6eba271f..95f991d9 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -5,11 +5,13 @@ import { setSurfaceShapePattern } from '@/util/canvas-util' import { splitPolygonWithLines } from '@/util/qpolygon-utils' import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' +import { usePopup } from '@/hooks/usePopup' // 지붕면 할당 -export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { +export function useRoofAllocationSetting(id) { const canvas = useRecoilValue(canvasState) const { drawDirectionArrow } = usePolygon() + const { closePopup } = usePopup() const { swalFire } = useSwal() @@ -80,7 +82,7 @@ export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') if (roofBases.length === 0) { swalFire({ text: '할당할 지붕이 없습니다.' }) - setShowRoofAllocationSettingModal(false) + closePopup(id) } }, []) @@ -120,7 +122,7 @@ export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { setSurfaceShapePattern(roof) drawDirectionArrow(roof) }) - setShowRoofAllocationSettingModal(false) + closePopup(id) } const handleRadioOnChange = (e) => { diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index f7b8b9fd..d80774ab 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -9,9 +9,10 @@ import { useMode } from '@/hooks/useMode' import { usePolygon } from '@/hooks/usePolygon' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' //지붕형상 수동 설정 -export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingModal) { +export function useRoofShapePassivitySetting(id) { const TYPES = { EAVES: 'eaves', GABLE: 'gable', @@ -28,16 +29,12 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod const offsetRef = useRef(null) const pitchRef = useRef(null) const currentLineRef = useRef(null) - const history = useRef([]) - const [type, setType] = useState(TYPES.EAVES) - const isFix = useRef(false) const initLines = useRef([]) - const [isLoading, setIsLoading] = useState(false) - + const { closePopup } = usePopup() const buttons = [ { id: 1, name: getMessage('eaves'), type: TYPES.EAVES }, { id: 2, name: getMessage('gable'), type: TYPES.GABLE }, @@ -50,7 +47,7 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') if (!outerLineFix || outerLines.length === 0) { swalFire({ text: '외벽선이 없습니다.' }) - setShowRoofShapePassivitySettingModal(false) + closePopup(id) return } setIsLoading(true) @@ -180,7 +177,7 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod isFix.current = true handleLineToPolygon() - setShowRoofShapePassivitySettingModal(false) + closePopup(id) } const handleLineToPolygon = () => { diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 016cd365..bc7992cc 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -2,15 +2,16 @@ import { useEffect, useRef, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilValue, useSetRecoilState } from 'recoil' import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom' -import { LINE_TYPE, MENU } from '@/common/common' +import { LINE_TYPE } from '@/common/common' import { usePolygon } from '@/hooks/usePolygon' import { useMode } from '@/hooks/useMode' import { useLine } from '@/hooks/useLine' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' // 지붕형상 설정 -export function useRoofShapeSetting(setShowRoofShapeSettingModal) { +export function useRoofShapeSetting(id) { const [shapeNum, setShapeNum] = useState(1) const [buttonAct, setButtonAct] = useState(1) const { swalFire } = useSwal() @@ -34,12 +35,14 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { const outerLineFix = useRecoilValue(outerLineFixState) const history = useRef([]) + const { closePopup } = usePopup() useEffect(() => { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') if (!outerLineFix || outerLines.length === 0) { swalFire({ text: '외벽선이 없습니다.' }) - setShowRoofShapeSettingModal(false) + // setShowRoofShapeSettingModal(false) + closePopup(id) } }, []) @@ -259,7 +262,8 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) { canvas?.renderAll() roof.drawHelpLine() - setShowRoofShapeSettingModal(false) + // setShowRoofShapeSettingModal(false) + closePopup(id) } const initLineSetting = () => { diff --git a/src/hooks/roofcover/useWallLineOffsetSetting.js b/src/hooks/roofcover/useWallLineOffsetSetting.js index b84e9ef4..ba6453ef 100644 --- a/src/hooks/roofcover/useWallLineOffsetSetting.js +++ b/src/hooks/roofcover/useWallLineOffsetSetting.js @@ -5,12 +5,14 @@ import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' import { useLine } from '@/hooks/useLine' import { useSwal } from '@/hooks/useSwal' +import { usePopup } from '@/hooks/usePopup' // 외벽선 편집 및 오프셋 -export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) { +export function useWallLineOffsetSetting(id) { const canvas = useRecoilValue(canvasState) const { showLine, addLine } = useLine() const { getMessage } = useMessage() + const { closePopup } = usePopup() const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() const wallLineEditRef = useRef(null) @@ -58,7 +60,7 @@ export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') if (outerLines.length === 0) { swalFire({ text: '외벽선이 없습니다.' }) - setShowWallLineOffsetSettingModal(false) + closePopup(id) return } outerLines.forEach((outerLine) => { diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index 40d25bf0..fe578365 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -29,9 +29,10 @@ import { } from '@/store/placementShapeDrawingAtom' import { usePolygon } from '@/hooks/usePolygon' import { POLYGON_TYPE } from '@/common/common' +import { usePopup } from '@/hooks/usePopup' // 면형상 배치 -export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { +export function usePlacementShapeDrawing(id) { const canvas = useRecoilValue(canvasState) const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } = useEvent() @@ -62,11 +63,11 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { const setOuterLineFix = useSetRecoilState(placementShapeDrawingFixState) const arrow1Ref = useRef(arrow1) const arrow2Ref = useRef(arrow2) - const outerLineDiagonalLengthRef = useRef(null) - const isFix = useRef(false) + const { closePopup } = usePopup() + useEffect(() => { if (adsorptionPointAddMode || tempGridMode) { return @@ -225,7 +226,7 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { }) canvas?.renderAll() - setShowPlaceShapeDrawingModal(false) + closePopup(id) } if (points.length < 3) { @@ -419,56 +420,104 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '↓' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '→') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y - length2Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length1Value / 10, y: prev[prev.length - 1].y - length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length1Value / 10, + y: prev[prev.length - 1].y - length2Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↑') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '←' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '←' && arrow2Value === '↑') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } @@ -524,35 +573,65 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '↓' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y + length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y + length1Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '→') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '↑' && arrow2Value === '←') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x - length2Value / 10, y: prev[prev.length - 1].y - length1Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x - length2Value / 10, + y: prev[prev.length - 1].y - length1Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↓') { setPoints((prev) => { if (prev.length === 0) { return [] } - return [...prev, { x: prev[prev.length - 1].x + length1Value / 10, y: prev[prev.length - 1].y + length2Value / 10 }] + return [ + ...prev, + { + x: prev[prev.length - 1].x + length1Value / 10, + y: prev[prev.length - 1].y + length2Value / 10, + }, + ] }) } else if (arrow1Value === '→' && arrow2Value === '↑') { setPoints((prev) => { diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index be421c8e..98e2b985 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -2,13 +2,14 @@ import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' -import { MENU, BATCH_TYPE, POLYGON_TYPE } from '@/common/common' +import { BATCH_TYPE, MENU, POLYGON_TYPE } from '@/common/common' import { getIntersectionPoint, setSurfaceShapePattern } from '@/util/canvas-util' import { degreesToRadians } from '@turf/turf' import { QPolygon } from '@/components/fabric/QPolygon' import { useSwal } from '@/hooks/useSwal' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' +import { usePopup } from '@/hooks/usePopup' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() @@ -16,8 +17,9 @@ export function useSurfaceShapeBatch() { const canvas = useRecoilValue(canvasState) const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() + const { closePopup } = usePopup() - const applySurfaceShape = (surfaceRefs, selectedType, setShowPlacementSurfaceSettingModal) => { + const applySurfaceShape = (surfaceRefs, selectedType, id) => { let length1, length2, length3, length4, length5 const surfaceId = selectedType?.id const azimuth = surfaceRefs.azimuth.current @@ -56,7 +58,6 @@ export function useSurfaceShapeBatch() { let obj = null let points = [] if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) { - setShowPlacementSurfaceSettingModal(false) addCanvasMouseEventListener('mouse:move', (e) => { if (!isDrawing) { return @@ -111,6 +112,7 @@ export function useSurfaceShapeBatch() { obj.set({ originAngle: originAngle }) canvas?.renderAll() + closePopup(id) }) addCanvasMouseEventListener('mouse:down', (e) => { @@ -118,7 +120,7 @@ export function useSurfaceShapeBatch() { obj.set('name', POLYGON_TYPE.ROOF) initEvent() setSurfaceShapePattern(obj) - setShowPlacementSurfaceSettingModal(true) + closePopup(id) }) } } @@ -292,8 +294,14 @@ export function useSurfaceShapeBatch() { const angleInRadians = Math.asin(length2 / length3) points = [ { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, - { x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { + x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), + y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians), + }, + { + x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), + y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians), + }, { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, ] @@ -304,9 +312,18 @@ export function useSurfaceShapeBatch() { { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1, + y: pointer.y + (length4 + length5) / 2 - length5, + }, + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, + y: pointer.y + (length4 + length5) / 2 - length5, + }, + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, + y: pointer.y + (length4 + length5) / 2 - length5 + length5, + }, { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, y: pointer.y + (length4 + length5) / 2 - length5 + length5, @@ -325,8 +342,14 @@ export function useSurfaceShapeBatch() { { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 }, { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, + { + x: pointer.x - length1 / 2 + length1 - (length1 - length2), + y: pointer.y + length4 / 2 - length3 + (length3 - length4), + }, + { + x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, + y: pointer.y + length4 / 2 - length3 + (length3 - length4), + }, ] break @@ -337,8 +360,14 @@ export function useSurfaceShapeBatch() { { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + { + x: pointer.x - length1 / 2 + length1 - length3, + y: pointer.y + length4 / 2 - length4 + (length4 - length5), + }, + { + x: pointer.x - length1 / 2 + length1 - length3 - length2, + y: pointer.y + length4 / 2 - length4 + (length4 - length5), + }, ] break } @@ -348,8 +377,14 @@ export function useSurfaceShapeBatch() { { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { + x: pointer.x + length1 / 2 - length1 + length2, + y: pointer.y + length4 / 2 - length5 - (length4 - length5), + }, + { + x: pointer.x + length1 / 2 - length1 + length2 + length3, + y: pointer.y + length4 / 2 - length5 - (length4 - length5), + }, ] break } @@ -359,8 +394,14 @@ export function useSurfaceShapeBatch() { { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { + x: pointer.x - length1 / 2 + length1 - length2, + y: pointer.y + length4 / 2 - length5 - (length4 - length5), + }, + { + x: pointer.x - length1 / 2 + length1 - length2 - length3, + y: pointer.y + length4 / 2 - length5 - (length4 - length5), + }, ] break } @@ -371,7 +412,10 @@ export function useSurfaceShapeBatch() { const leftAngle = Math.acos((length1 - length2) / 2 / leftHypotenuse) points = [ - { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle) }, + { + x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle), + y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle), + }, { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, { @@ -459,7 +503,10 @@ export function useSurfaceShapeBatch() { { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 }, { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 }, - { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 }, + { + x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, + y: pointer.y + length4 / 2 - length4 + length5, + }, ] break } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 3fb6f164..4451c259 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -165,10 +165,7 @@ export function useContextMenu({ externalFn }) { }, [currentMenu]) useEffect(() => { - console.log('currentObject', currentObject) - console.log('currentMenu', currentMenu) if (currentObject?.name) { - console.log(currentObject) switch (currentObject.name) { case 'triangleDormer': setContextMenu([ diff --git a/src/hooks/usePopup.js b/src/hooks/usePopup.js index 4a8e3cfb..b54492b9 100644 --- a/src/hooks/usePopup.js +++ b/src/hooks/usePopup.js @@ -14,7 +14,21 @@ export function usePopup() { } const closePopup = (id) => { - setPopup({ children: [...popup.children.filter((child) => child.id !== id)] }) + console.log(id) + setPopup({ children: [...filterChildrenPopup(id).filter((child) => child.id !== id)] }) + } + + const filterPopup = (depth) => { + setPopup({ children: [...filterDepth(depth)] }) + } + + const filterChildrenPopup = (id) => { + const target = popup.children.filter((child) => child.id === id) + if (target.length !== 0) { + return popup.children.filter((child) => child.depth <= target[0].depth) + } + + return popup.children } const closePopups = (ids) => { From 7ab481ec368334189b76fe32b9388a3749f07753 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Oct 2024 17:24:51 +0900 Subject: [PATCH 047/139] =?UTF-8?q?canvas=20=EC=A0=80=EC=9E=A5=20=EC=8B=9C?= =?UTF-8?q?=20=EA=B0=92=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useRoofAllocationSetting.js | 4 +++- src/hooks/usePlan.js | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 6eba271f..d219cf24 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -5,10 +5,12 @@ import { setSurfaceShapePattern } from '@/util/canvas-util' import { splitPolygonWithLines } from '@/util/qpolygon-utils' import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' +import { roofDisplaySelector } from '@/store/settingAtom' // 지붕면 할당 export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { const canvas = useRecoilValue(canvasState) + const roofDisplay = useRecoilValue(roofDisplaySelector) const { drawDirectionArrow } = usePolygon() const { swalFire } = useSwal() @@ -117,7 +119,7 @@ export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) { const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') roofs.forEach((roof) => { - setSurfaceShapePattern(roof) + setSurfaceShapePattern(roof, roofDisplay.column) drawDirectionArrow(roof) }) setShowRoofAllocationSettingModal(false) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index b1273d82..dc5286d4 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -60,6 +60,7 @@ export function usePlan() { 'attributes', 'stickeyPoint', 'text', + 'pitch', ]) const str = JSON.stringify(objs) From 4d859d1530b893474ed357b4e1453c34b9f9e2cb Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 22 Oct 2024 17:47:17 +0900 Subject: [PATCH 048/139] =?UTF-8?q?escape=20=EC=B2=98=EB=A6=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/usePlan.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index dc5286d4..63eeb59c 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -115,7 +115,7 @@ export function usePlan() { * DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화 */ const dbToCanvasFormat = (cs) => { - return cs.replace(/##/g, '"') + return cs.replace(/##/g, '"').replace(/∠/g, '∠') } /** From cc9eee731b322b867fd33ede87ae824bede348ea Mon Sep 17 00:00:00 2001 From: basssy Date: Tue, 22 Oct 2024 17:55:47 +0900 Subject: [PATCH 049/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=82=AC=EC=96=91=ED=99=95?= =?UTF-8?q?=EC=A0=95=EC=9D=BC=20=ED=95=84=EB=93=9C=EB=AA=85=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20&=20=EC=9E=84=EC=8B=9C=EC=A0=80=EC=9E=A5=20&=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=ED=99=94=EB=A9=B4=20...?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 4 +- src/components/management/StuffDetail.jsx | 463 ++++++++++++++++------ src/locales/ja.json | 4 +- src/locales/ko.json | 4 +- 4 files changed, 350 insertions(+), 125 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 58cd7bff..07119205 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -123,8 +123,8 @@ export default function Stuff() { { field: 'dispCompanyName', headerName: getMessage('stuff.gridHeader.dispCompanyName'), cellStyle: { textAlign: 'left' } }, { field: 'receiveUser', headerName: getMessage('stuff.gridHeader.receiveUser'), cellStyle: { textAlign: 'left' } }, { - field: 'specDate', - headerName: getMessage('stuff.gridHeader.specDate'), + field: 'specificationConfirmDate', + headerName: getMessage('stuff.gridHeader.specificationConfirmDate'), valueFormatter: function (params) { if (params.value) { return dayjs(params?.value).format('YYYY.MM.DD') diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 928d2234..46353f08 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -31,7 +31,7 @@ export default function StuffDetail() { const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) const ref = useRef() - const { get, del, promisePost } = useAxios(globalLocaleState) + const { get, del, promisePost, promisePut } = useAxios(globalLocaleState) //form const formInitValue = { // 물건번호 T...(임시) R...(진짜) @@ -71,6 +71,8 @@ export default function StuffDetail() { const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드 리스트 const [selHonorificCode, setSelHonorificCode] = useState('') //선택한 경칭코드 const [objectStatusList, setObjectStatusList] = useState([]) //물건구분 공통코드 리스트 + + const [selectObjectStatusId, setSelectObjectStatusId] = useState('0') //신축기축 선택값 const [windSpeedList, setWindSpeedList] = useState([]) //기준 풍속 공통코드 리스트 const [prefCodeList, setPrefCodeList] = useState([]) //도도부현 코트 리스트 const [prefValue, setPrefValue] = useState('') @@ -93,7 +95,6 @@ export default function StuffDetail() { // console.log('objectNo::', objectNo) if (objectNo) { - console.log('수정화면') setEditMode('EDIT') if (objectNo.substring(0, 1) === 'R') { @@ -116,7 +117,6 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 - // get({ url: `/api/object/saleStore/T100/list` }).then((res) => { get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') @@ -171,11 +171,8 @@ export default function StuffDetail() { } }) - //상세정보로 1차점 목록등 셋팅?? - // 임시 1차점 판매점코드 saleStoreId=201TES01 - // T01 - //1차점 : X167 - // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { + //1차점 : X167 T01 + //2차점 : 10X22, 201X112 get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') @@ -186,11 +183,44 @@ export default function StuffDetail() { setOriginOtherSaleStoreList(otherList) setOtherSaleStoreList(otherList) } - }) + console.log('상세데이타::세팅:::::', detailData) + //설계의뢰No. + form.setValue('planReqNo', detailData.planReqNo) + //담당자 + form.setValue('dispCompanyName', detailData.dispCompanyName) - console.log('상세데이타::세팅:::::', detailData) + //물건구분objectStatusId + setSelectObjectStatusId(detailData.objectStatusId) + form.setValue('objectStatusId', detailData.objectStatusId) + + //물건명 + form.setValue('objectName', detailData.objectName) + + //경칭코드 + + setSelHonorificCode(detailData.objectNameOmit) + form.setValue('objectNameOmit', detailData.objectNameOmit) + + //물건명 후리가나 + form.setValue('objectNameKana', detailData.objectNameKana) + + // console.log('1차점리스트::', firstList) + // console.log('2차점리스트::', otherList) + setSelOptions(detailData.saleStoreId) + form.setValue('saleStoreId', detailData.saleStoreId) + form.setValue('saleStoreLevel', sessionState?.storeLvl) + + //2차점까지 고른경우 확인필요 + console.log('2차점까지 고른경우 확인필요') + // setOtherSelOptions(sessionState?.storeId) + // form.setValue('saleStoreId', firstList[0].saleStoreId) + // form.setValue('otherSaleStoreId', sessionState?.storeId) + // form.setValue('otherSaleStoreLevel', sessionState?.storeLvl) + + form.setValue('zipNo', detailData.zipNo) + }) } - }, [detailData]) + }, [detailData, sessionState]) //경칭선택 변경 이벤트 const onChangeHonorificCode = (key) => { @@ -212,45 +242,117 @@ export default function StuffDetail() { } } + //물건구분 변경 이벤트 + const onRadioChange = (key) => { + setSelectObjectStatusId(key.target.value) + } //1차점 변경 이벤트 const onSelectionChange = (key) => { - if (isObjectNotEmpty(key)) { - setOtherSaleStoreList(otherSaleStoreList) - form.setValue('saleStoreId', key.saleStoreId) - form.setValue('saleStoreName', key.saleStoreName) - form.setValue('saleStoreLevel', key.saleStoreLevel) - setSelOptions(key.saleStoreId) - //선택한 1차점 정보로 2차점 list 추리기 - //長府工産株式会社 大阪支社 - let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) - setOtherSaleStoreList(newOtherSaleStoreList) + const planReqNo = form.watch('planReqNo') + + let delFlg = false + if (planReqNo !== '') { + if (confirm('stuff.detail.confirm.message1')) { + delFlg = true + } else { + delFlg = false + } + } + + if (planReqNo !== '') { + if (delFlg) { + form.setValue('planReqNo', '') + if (isObjectNotEmpty(key)) { + setOtherSaleStoreList(otherSaleStoreList) + form.setValue('saleStoreId', key.saleStoreId) + form.setValue('saleStoreName', key.saleStoreName) + form.setValue('saleStoreLevel', key.saleStoreLevel) + setSelOptions(key.saleStoreId) + //선택한 1차점 정보로 2차점 list 추리기 + //長府工産株式会社 大阪支社 + let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) + setOtherSaleStoreList(newOtherSaleStoreList) + } else { + //X누름 + setSelOptions('') + form.setValue('saleStoreId', '') + form.setValue('saleStoreName', '') + form.setValue('saleStoreLevel', '') + form.setValue('otherSaleStoreId', '') + form.setValue('otherSaleStoreName', '') + form.setValue('otherSaleStoreLevel', '') + //1차점 지웠을때 2차점 자동완성 초기화 + setOtherSaleStoreList(originOtherSaleStoreList) + handleClear() + } + } } else { - //X누름 - setSelOptions('') - form.setValue('saleStoreId', '') - form.setValue('saleStoreName', '') - form.setValue('saleStoreLevel', '') - form.setValue('otherSaleStoreId', '') - form.setValue('otherSaleStoreName', '') - form.setValue('otherSaleStoreLevel', '') - setOtherSaleStoreList(originOtherSaleStoreList) - //1차점 지웠을때 2차점 자동완성 초기화 - handleClear() + if (isObjectNotEmpty(key)) { + setOtherSaleStoreList(otherSaleStoreList) + form.setValue('saleStoreId', key.saleStoreId) + form.setValue('saleStoreName', key.saleStoreName) + form.setValue('saleStoreLevel', key.saleStoreLevel) + setSelOptions(key.saleStoreId) + //선택한 1차점 정보로 2차점 list 추리기 + //長府工産株式会社 大阪支社 + let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) + setOtherSaleStoreList(newOtherSaleStoreList) + } else { + //X누름 + setSelOptions('') + form.setValue('saleStoreId', '') + form.setValue('saleStoreName', '') + form.setValue('saleStoreLevel', '') + form.setValue('otherSaleStoreId', '') + form.setValue('otherSaleStoreName', '') + form.setValue('otherSaleStoreLevel', '') + //1차점 지웠을때 2차점 자동완성 초기화 + setOtherSaleStoreList(originOtherSaleStoreList) + handleClear() + } } } //2차점 변경 이벤트 const onSelectionChange2 = (key) => { - if (isObjectNotEmpty(key)) { - setOtherSelOptions(key.saleStoreId) - form.setValue('otherSaleStoreId', key.saleStoreId) - form.setValue('otherSaleStoreName', key.saleStoreName) - form.setValue('otherSaleStoreLevel', key.saleStoreLevel) + const planReqNo = form.watch('planReqNo') + + let delFlg = false + if (planReqNo !== '') { + if (confirm('stuff.detail.confirm.message1')) { + delFlg = true + } else { + delFlg = false + } + } + + if (planReqNo !== '') { + if (delFlg) { + form.setValue('planReqNo', '') + if (isObjectNotEmpty(key)) { + setOtherSelOptions(key.saleStoreId) + form.setValue('otherSaleStoreId', key.saleStoreId) + form.setValue('otherSaleStoreName', key.saleStoreName) + form.setValue('otherSaleStoreLevel', key.saleStoreLevel) + } else { + setOtherSelOptions('') + form.setValue('otherSaleStoreId', '') + form.setValue('otherSaleStoreName', '') + form.setValue('otherSaleStoreLevel', '') + } + } } else { - setOtherSelOptions('') - form.setValue('otherSaleStoreId', '') - form.setValue('otherSaleStoreName', '') - form.setValue('otherSaleStoreLevel', '') + if (isObjectNotEmpty(key)) { + setOtherSelOptions(key.saleStoreId) + form.setValue('otherSaleStoreId', key.saleStoreId) + form.setValue('otherSaleStoreName', key.saleStoreName) + form.setValue('otherSaleStoreLevel', key.saleStoreLevel) + } else { + setOtherSelOptions('') + form.setValue('otherSaleStoreId', '') + form.setValue('otherSaleStoreName', '') + form.setValue('otherSaleStoreLevel', '') + } } } @@ -295,8 +397,8 @@ export default function StuffDetail() { if (info.saleStoreLevel === '1') { setSelOptions(info.saleStoreId) form.setValue('saleStoreId', info.saleStoreId) - form.setValue('saleStoreName', key.saleStoreName) - form.setValue('saleStoreLevel', key.saleStoreLevel) + form.setValue('saleStoreName', info.saleStoreName) + form.setValue('saleStoreLevel', info.saleStoreLevel) } else { setOtherSelOptions(info.saleStoreId) form.setValue('otherSaleStoreId', info.saleStoreId) @@ -310,40 +412,32 @@ export default function StuffDetail() { form.setValue('windSpeed', info.windSpeed) } - //임시저장 저장 버튼 컨트롤 - // dispCompanyName: '', //담당자 - // objectName: '', //물건명 - // objectNameOmit: '', //경칭선택 - // saleStoreId: '', //판매점ID - // zipNo: '', //우편번호 - // prefId: '', //도도부현 - // address: '', //주소 - // areaId: '', //발전량시뮬레이션지역new - // windSpeed: '', //기준풍속 - // verticalSnowCover: '', //수직적설량 - // coldRegionFlg: false, //한랭지대책시행 - // surfaceType: 'Ⅲ・Ⅳ', //면조도구분(Ⅲ・Ⅳ / Ⅱ) - // saltAreaFlg: false, //염해지역용아이템사용 - // installHeight: '', //설치높이 - // conType : '0' //계약조건(잉여 / 전량) - // remarks: '', //메모 - // tempFlag: 'T', //임시저장(1) 저장(0) + //dispCompanyName: '', //담당자 const _dispCompanyName = watch('dispCompanyName') + //objectName: '', //물건명 const _objectName = watch('objectName') + // objectNameOmit: '', //경칭선택 const _objectNameOmit = watch('objectNameOmit') + // saleStoreId: '', //1차 판매점ID const _saleStoreId = watch('saleStoreId') - const _saleStoreLevel = watch('saleStoreLevel') + // zipNo: '', //우편번호 + const _zipNo = watch('zipNo') + // prefId: '', //도도부현 const _prefId = watch('prefId') + // address: '', //주소 const _address = watch('address') - const _areaId = watch('areaId') //new + // areaId: '', //발전량시뮬레이션지역 + const _areaId = watch('areaId') + // windSpeed: '', //기준풍속 const _windSpeed = watch('windSpeed') + // verticalSnowCover: '', //수직적설량 const _verticalSnowCover = watch('verticalSnowCover') + // installHeight: '', //설치높이 const _installHeight = watch('installHeight') useEffect(() => { if (editMode === 'NEW') { const formData = form.getValues() - // console.log('임시저장폼error체크::::::::::::', formData) let errors = {} if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { errors.dispCompanyName = true @@ -358,6 +452,10 @@ export default function StuffDetail() { errors.saleStoreId = true } + if (!formData.zipNo) { + errors.zipNo = true + } + if (!formData.prefId) { errors.prefId = true } @@ -378,19 +476,57 @@ export default function StuffDetail() { errors.installHeight = true } - // console.log('임시저장용::', errors) setIsFormValid(Object.keys(errors).length === 0 ? true : false) } else { console.log('상세일때 폼체크') + const formData = form.getValues() + let errors = {} + if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { + errors.dispCompanyName = true + } + if (!formData.objectName || formData.objectName.trim().length === 0) { + errors.objectName = true + } + if (!formData.objectNameOmit) { + errors.objectNameOmit = true + } + if (!formData.saleStoreId) { + errors.saleStoreId = true + } + + if (!formData.zipNo) { + errors.zipNo = true + } + + if (!formData.prefId) { + errors.prefId = true + } + + if (!formData.areaId) { + errors.areaId = true + } + + if (!formData.windSpeed) { + errors.windSpeed = true + } + + if (!formData.verticalSnowCover) { + errors.verticalSnowCover = true + } + + if (!formData.installHeight) { + errors.installHeight = true + } + + console.log('상세 저장용 에러결과?????::', errors) + setIsFormValid(Object.keys(errors).length === 0 ? true : false) } }, [ _dispCompanyName, _objectName, _objectNameOmit, _saleStoreId, - _saleStoreLevel, - // _otherSaleStoreId, - // _otherSaleStoreLevel, + _zipNo, _prefId, _address, _areaId, @@ -424,8 +560,6 @@ export default function StuffDetail() { // 발전량시뮬레이션 지역 목록 get({ url: `/api/object/prefecture/${prefValue}/list` }).then((res) => { if (!isEmptyArray(res)) { - // form.setValue('areaId', res[0].areaId) - // form.setValue('areaName', res[0].prefName) setAreaIdList(res) } }) @@ -439,29 +573,52 @@ export default function StuffDetail() { } //필수값 다 입력했을때 - const onValid = (data, e) => { + const onValid = async () => { const formData = form.getValues() - console.log('필수값 통과:::', data, formData) - // console.log('필수값 formData:::', formData) - // 수정모드일때는 PUT - // console.log('필수값 다 있고 저장') - // console.log('data::::::', data) - // 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 _coldRegionFlg = watch('coldRegionFlg') - // console.log(_dispCompanyName) - // console.log(_objectStatusId) - // console.log(_objectNameOmit) - // console.log(_zipNo) - // console.log(_prefId) - // console.log('prefValue::', prefValue) - // console.log(_address) - // console.log('_coldRegionFlg::', _coldRegionFlg) + console.log('필수값 통과:::', formData) + const apiUrl = '/api/object/save-object' + const params = { + saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId, + saleStoreName: formData.otherSaleStoreName ? formData.otherSaleStoreName : formData.saleStoreName, + saleStoreLevel: formData.otherSaleStoreLevel ? formData.otherSaleStoreLevel : formData.saleStoreLevel, + objectStatusId: formData.objectStatusId, + objectName: formData.objectName, + objectNameOmit: formData.objectNameOmit, + objectNameKana: formData.objectNameKana, + zipNo: formData.zipNo, + prefId: formData.prefId, + prefName: formData.prefName, + address: formData.address, + areaId: formData.areaId, + receiveUser: formData.dispCompanyName, + installHeight: formData.installHeight, + windSpeed: formData.windSpeed, + verticalSnowCover: formData.verticalSnowCover, + surfaceType: formData.surfaceType, + conType: formData.conType, + coldRegionFlg: formData.coldRegionFlg, + saltAreaFlg: formData.saltAreaFlg, + tempFlg: '0', + workNo: null, + workName: null, + } + console.log('params::', params) + alert('작업중') + return + if (editMode === 'NEW') { + await promisePost({ url: apiUrl, data: params }).then((res) => { + console.log('진짜저장결과::::', pathname, res) + + //상세화면으로 전환 + //router.push(`${pathname}?objectNo=${res.data.objectNo.toString()}`) + }) + } else { + // 수정모드일때는 PUT + await promisePut({ url: apiUrl, data: params }).then((res) => { + console.log('진짜데이터 수정 결과::::::::::', pathname, res) + //새로고침??? + }) + } } //필수값 안넣었을때 임시저장 form required사용시 @@ -474,8 +631,6 @@ export default function StuffDetail() { // 임시저장 const onTempSave = async () => { const formData = form.getValues() - console.log('임시저장누름:::::', formData) - return const params = { saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId, saleStoreName: formData.otherSaleStoreName ? formData.otherSaleStoreName : formData.saleStoreName, @@ -501,15 +656,17 @@ export default function StuffDetail() { workNo: null, workName: null, } + //1차점 or 2차점 안고르고 임시저장하면 if (params.saleStoreId == '') { params.saleStoreId = sessionState.storeId params.saleStoreLevel = sessionState.storeLvl } - + alert('작업중') + return await promisePost({ url: '/api/object/save-object', data: params }).then((res) => { if (res.status === 201) { - alert('임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.') + getMessage('stuff.detail.tempSave.message1') router.push(`${pathname}?objectNo=${res.data.objectNo.toString()}`) } }) @@ -576,7 +733,7 @@ export default function StuffDetail() {
    {/* 라디오시작 */} - {objectStatusList.map((row, index) => { + {objectStatusList.map((row) => { return (
    @@ -597,7 +756,7 @@ export default function StuffDetail() {
    -
    */} {/* 기준풍속sel시작 */}
    - - - - -
    */}
    @@ -905,7 +1054,7 @@ export default function StuffDetail() { ) : ( )} @@ -935,11 +1084,15 @@ export default function StuffDetail() {
    - +
    - + {objectNo.substring(0, 1) === 'T' ? ( + <> + + + ) : null}
    @@ -969,6 +1122,8 @@ export default function StuffDetail() { value={row.clCode} id={`objectStatus${row.clCode}`} {...register('objectStatusId')} + onChange={onRadioChange} + checked={row.clCode === selectObjectStatusId} />
    @@ -981,7 +1136,7 @@ export default function StuffDetail() {
    @@ -1021,15 +1178,21 @@ export default function StuffDetail() {
    - {/* */} + getOptionLabel={(x) => x.saleStoreName} + getOptionValue={(x) => x.saleStoreId} + isClearable={sessionState?.storeLvl === '1' ? true : false} + value={saleStoreList.filter(function (option) { + return option.saleStoreId === selOptions + })} + />
    @@ -1037,6 +1200,64 @@ export default function StuffDetail() {
    + + +
    +
    {getMessage('stuff.detail.otherSaleStoreId')}
    +
    + {getMessage('stuff.detail.tooltip.saleStoreId')} +
    +
    + + +
    +
    + +
    +
    + + + + + {getMessage('stuff.detail.zipNo')} * + + +
    +
    + +
    + +
    {getMessage('stuff.detail.btn.addressPop.guide')}
    +
    + +
    diff --git a/src/locales/ja.json b/src/locales/ja.json index c4c09341..2b743e4a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -454,7 +454,7 @@ "stuff.gridHeader.address": "商品アドレス", "stuff.gridHeader.dispCompanyName": "見積もり", "stuff.gridHeader.receiveUser": "担当者", - "stuff.gridHeader.specDate": "仕様確認日", + "stuff.gridHeader.specificationConfirmDate": "仕様確認日", "stuff.gridHeader.createDatetime": "登録日", "stuff.message.periodError": "最大1年間閲覧可能.", "stuff.addressPopup.title": "郵便番号", @@ -495,6 +495,8 @@ "stuff.detail.conType1": "全量", "stuff.detail.remarks": "メモ", "stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください", + "stuff.detail.tempSave.message1": "一時保存されました。商品番号を取得するには、必須項目をすべて入力してください。", + "stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?", "stuff.planReqPopup.popTitle": "設計依頼検索", "stuff.planReqPopup.btn1": "検索", "stuff.planReqPopup.btn2": "初期化", diff --git a/src/locales/ko.json b/src/locales/ko.json index f5394e2e..61f3ba9e 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -459,7 +459,7 @@ "stuff.gridHeader.address": "물건주소", "stuff.gridHeader.dispCompanyName": "견적처", "stuff.gridHeader.receiveUser": "담당자", - "stuff.gridHeader.specDate": "사양확인일", + "stuff.gridHeader.specificationConfirmDate": "사양확인일", "stuff.gridHeader.createDatetime": "등록일", "stuff.message.periodError": "최대1년 조회 가능합니다.", "stuff.addressPopup.title": "우편번호", @@ -500,6 +500,8 @@ "stuff.detail.conType1": "전량", "stuff.detail.remarks": "메모", "stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요", + "stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.", + "stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", "stuff.planReqPopup.popTitle": "설계 요청 검색", "stuff.planReqPopup.btn1": "검색", "stuff.planReqPopup.btn2": "초기화", From 0ce703a39246974ef6245abafa179b4f5fa8f11a Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Tue, 22 Oct 2024 18:14:37 +0900 Subject: [PATCH 050/139] =?UTF-8?q?refactor:=20=EC=BA=94=EB=B2=84=EC=8A=A4?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=A9=EB=B2=95=EC=9D=84=20=EC=8B=A4=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EC=98=A4=EB=B8=8C=EC=A0=9D=ED=8A=B8=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EA=B0=90=EC=A7=80=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasFrame.jsx | 36 ++++++++++ src/components/floor-plan/CanvasLayout.jsx | 7 +- src/hooks/usePlan.js | 77 +++++++++++++++------- src/store/canvasAtom.js | 6 ++ 4 files changed, 101 insertions(+), 25 deletions(-) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index ef01987a..8dcd341f 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -4,6 +4,7 @@ import { useEffect, useRef } from 'react' import { useCanvas } from '@/hooks/useCanvas' import { useEvent } from '@/hooks/useEvent' +import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' import { useRecoilValue } from 'recoil' import { currentObjectState } from '@/store/canvasAtom' @@ -19,6 +20,7 @@ export default function CanvasFrame({ plan }) { handleZoomClear, }, }) + const { checkCanvasObjectEvent, checkUnsavedCanvasPlan } = usePlan() const currentObject = useRecoilValue(currentObjectState) @@ -36,7 +38,41 @@ export default function CanvasFrame({ plan }) { } useEffect(() => { + // const checkEventName = [ + // 'object:modified', + // 'object:moving', + // 'object:scaling', + // 'object:rotating', + // 'object:skewing', + // 'object:resizing', + // 'object:selected', + // 'object:added', + // 'object:removed', + // ] + + canvas?.off('object:added') + canvas?.off('object:modified') + canvas?.off('object:removed') + loadCanvas() + + if (plan) { + canvas?.on('object:added', (e) => { + if (e?.target.name !== 'mouseLine') { + checkCanvasObjectEvent(e, plan.id) + } + }) + canvas?.on('object:modified', (e) => { + if (e?.target.name !== 'mouseLine') { + checkCanvasObjectEvent(e, plan.id) + } + }) + canvas?.on('object:removed', (e) => { + if (e?.target.name !== 'mouseLine') { + checkCanvasObjectEvent(e, plan.id) + } + }) + } }, [plan, canvas]) const onClickContextMenu = (index) => {} diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index d10b103c..63722a64 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -17,7 +17,7 @@ export default function CanvasLayout(props) { const { getMessage } = useMessage() const { swalFire } = useSwal() - const { plans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() + const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() useEffect(() => { loadCanvasPlanData(session.userId, objectNo) @@ -33,7 +33,10 @@ export default function CanvasLayout(props) { className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`} onClick={() => handleCurrentPlan(session.userId, plan.id)} > - {plan.name} + + {plan.name} + {modifiedPlans.some((modifiedPlan) => modifiedPlan === plan.id) && ' [ M ]'} + diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 63eeb59c..166ff738 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useRecoilState } from 'recoil' import { v4 as uuidv4 } from 'uuid' -import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState } from '@/store/canvasAtom' +import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState, modifiedPlansState } from '@/store/canvasAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' @@ -13,6 +13,7 @@ export function usePlan() { const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) // DB에 저장된 plan const [plans, setPlans] = useRecoilState(plansState) // 전체 plan (DB에 저장된 plan + 저장 안된 새로운 plan) + const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan const { swalFire } = useSwal() const { getMessage } = useMessage() @@ -87,11 +88,20 @@ export function usePlan() { } /** - * 실시간 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 + * 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 판단 */ - const checkModifiedCanvasPlan = () => { + const checkCanvasObjectEvent = (e, planId) => { + if (!modifiedPlans.some((modifiedPlan) => modifiedPlan === planId) && checkModifiedCanvasPlan(planId)) { + setModifiedPlans([...modifiedPlans, planId]) + } + } + + /** + * 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 + */ + const checkModifiedCanvasPlan = (planId) => { const canvasStatus = currentCanvasData() - const initPlanData = initCanvasPlans.find((plan) => plan.id === currentCanvasPlan.id) + const initPlanData = initCanvasPlans.find((plan) => plan.id === planId) if (!initPlanData) { // 새로운 캔버스 @@ -110,6 +120,21 @@ export function usePlan() { .map((obj) => obj.id) .sort() } + /** + * 캔버스에 저장되지 않은 변경사항이 있는 경우 저장 여부를 확인 후 저장 + */ + const checkUnsavedCanvasPlan = async () => { + if (modifiedPlans.length > 0) { + swalFire({ + text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'), + type: 'confirm', + confirmFn: async () => { + await saveCanvas(userId) + }, + }) + setModifiedPlans([]) + } + } /** * DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화 @@ -139,7 +164,6 @@ export function usePlan() { * objectNo에 해당하는 canvas 목록을 조회 */ const getCanvasByObjectNo = async (userId, objectNo) => { - // console.log(`[GET] objectNo: ${objectNo} / userId: ${userId}`) return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) => res.map((item) => ({ id: item.id, @@ -163,7 +187,6 @@ export function usePlan() { } await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData }) .then((res) => { - swalFire({ text: getMessage('plan.message.save') }) setInitCanvasPlans((initCanvasPlans) => [...initCanvasPlans, { id: res.data, canvasStatus: canvasStatus }]) setPlans((plans) => plans.map((plan) => @@ -177,6 +200,8 @@ export function usePlan() { : plan, ), ) + setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) + swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) @@ -193,11 +218,12 @@ export function usePlan() { } await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData }) .then((res) => { - swalFire({ text: getMessage('plan.message.save') }) setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)), ) setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) + setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) + swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) @@ -222,23 +248,23 @@ export function usePlan() { * plan 이동 * 현재 plan의 작업상태를 확인, 저장 후 이동 */ - const handleCurrentPlan = (userId, newCurrentId) => { + const handleCurrentPlan = async (userId, newCurrentId) => { if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) { - if (currentCanvasPlan?.id && checkModifiedCanvasPlan()) { - swalFire({ - text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'), - type: 'confirm', - confirmFn: async () => { - await saveCanvas(userId) - updateCurrentPlan(newCurrentId) - }, - denyFn: () => { - updateCurrentPlan(newCurrentId) - }, - }) - } else { - updateCurrentPlan(newCurrentId) + if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) { + // swalFire({ + // text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'), + // type: 'confirm', + // confirmFn: async () => { + // await saveCanvas(userId) + // updateCurrentPlan(newCurrentId) + // }, + // denyFn: () => { + // updateCurrentPlan(newCurrentId) + // }, + // }) + await saveCanvas(userId) } + updateCurrentPlan(newCurrentId) } } const updateCurrentPlan = (newCurrentId) => { @@ -293,15 +319,17 @@ export function usePlan() { if (initCanvasPlans.some((plan) => plan.id === id)) { delCanvasById(id) .then((res) => { - swalFire({ text: getMessage('plan.message.delete') }) setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id)) setPlans((plans) => plans.filter((plan) => plan.id !== id)) + setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) + swalFire({ text: getMessage('plan.message.delete') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) }) } else { setPlans((plans) => plans.filter((plan) => plan.id !== id)) + setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) swalFire({ text: getMessage('plan.message.delete') }) } @@ -335,6 +363,9 @@ export function usePlan() { return { canvas, plans, + modifiedPlans, + checkCanvasObjectEvent, + checkUnsavedCanvasPlan, saveCanvas, handleCurrentPlan, handleAddPlan, diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index f3a81661..d9878f2f 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -270,6 +270,12 @@ export const plansState = atom({ default: [], }) +// 변경된 canvas plan 목록 +export const modifiedPlansState = atom({ + key: 'modifiedPlansState', + default: [], +}) + export const tempGridModeState = atom({ key: 'tempGridModeState', default: false, From bbd0e365be86620bd96ab583cf9089071192aeb1 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Oct 2024 09:21:22 +0900 Subject: [PATCH 051/139] =?UTF-8?q?=EC=98=A4=EB=B8=8C=EC=A0=9D=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=ED=94=BC=EC=B9=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 13 ++++++++++--- src/hooks/common/useCommonUtils.js | 0 src/hooks/object/useObjectBatch.js | 8 ++++++-- src/hooks/surface/useSurfaceShapeBatch.js | 4 ++++ 4 files changed, 20 insertions(+), 5 deletions(-) create mode 100644 src/hooks/common/useCommonUtils.js diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 1478ab13..06169e43 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -307,15 +307,21 @@ export default function CanvasMenu(props) { // const angle = calculateAngle({ x: p1CenterX, y: p1CenterY }, { x: p2CenterX, y: p2CenterY }) // 첫 번째 포인트에 화살표 추가 - const arrow1 = createArrow(p1CenterX + 7.5, p1CenterY + 1, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 - const arrow2 = createArrow(p2CenterX - 6.5, p2CenterY + 1, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 + + const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1 + const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1 + const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8 + const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 8 + + const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 + const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 canvas.add(arrow1) canvas.add(arrow2) // 두 포인트 간의 거리 계산 // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 - distanceText = new fabric.Text(`${distance}`, { + distanceText = new fabric.Text(`${distance * 10}`, { left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), fill: 'black', @@ -325,6 +331,7 @@ export default function CanvasMenu(props) { originX: 'center', originY: 'center', angle: lineDirection === 'horizontal' ? 0 : 270, + name: 'lengthText', // lockMovementX: false, // lockMovementY: false, }) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js new file mode 100644 index 00000000..e69de29b diff --git a/src/hooks/object/useObjectBatch.js b/src/hooks/object/useObjectBatch.js index 24e4bf07..3dba8436 100644 --- a/src/hooks/object/useObjectBatch.js +++ b/src/hooks/object/useObjectBatch.js @@ -4,17 +4,17 @@ import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { BATCH_TYPE, INPUT_TYPE } from '@/common/common' import { useEvent } from '@/hooks/useEvent' -import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util' +import { pointsToTurfPolygon, polygonToTurfPolygon, rectToPolygon, triangleToPolygon, setSurfaceShapePattern } from '@/util/canvas-util' import { useSwal } from '@/hooks/useSwal' import * as turf from '@turf/turf' import { usePolygon } from '@/hooks/usePolygon' +import { QPolygon } from '@/components/fabric/QPolygon' export function useObjectBatch() { const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) const { addCanvasMouseEventListener, initEvent } = useEvent() const { swalFire } = useSwal() - const { drawDirectionArrow } = usePolygon() const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => { @@ -367,6 +367,7 @@ export function useObjectBatch() { originX: 'center', originY: 'center', name: dormerName, + pitch: pitch, }) const rightTriangle = new QPolygon(splitedTriangle[1], { @@ -383,6 +384,7 @@ export function useObjectBatch() { originX: 'center', originY: 'center', name: dormerName, + pitch: pitch, }) canvas?.add(leftTriangle) @@ -540,6 +542,7 @@ export function useObjectBatch() { originX: 'center', originY: 'center', name: dormerName, + pitch: pitch, }) const rightPentagon = new QPolygon(splitedPentagon[1], { @@ -556,6 +559,7 @@ export function useObjectBatch() { originX: 'center', originY: 'center', name: dormerName, + pitch: pitch, }) canvas?.add(leftPentagon) diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 8207e5b8..d6c799ac 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -11,9 +11,11 @@ import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' import { usePopup } from '@/hooks/usePopup' import { roofDisplaySelector } from '@/store/settingAtom' +import { usePolygon } from '@/hooks/usePolygon' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() + const { drawDirectionArrow } = usePolygon() const canvas = useRecoilValue(canvasState) const globalPitch = useRecoilValue(globalPitchState) @@ -125,6 +127,8 @@ export function useSurfaceShapeBatch() { initEvent() setSurfaceShapePattern(obj, roofDisplay.column) closePopup(id) + drawDirectionArrow(obj) + setShowPlacementSurfaceSettingModal(true) }) } } From 1df9facaea23609b5cfa30902faa43a10c46de24 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Oct 2024 10:19:37 +0900 Subject: [PATCH 052/139] =?UTF-8?q?useCommon.js=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=ED=9B=84=20=EC=9E=A1=20=EA=B8=B0=EB=8A=A5=20=EC=9D=B4=EA=B4=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 370 +---------------------- src/hooks/common/useCommonUtils.js | 367 ++++++++++++++++++++++ 2 files changed, 375 insertions(+), 362 deletions(-) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 06169e43..5f73efa1 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -18,8 +18,6 @@ import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, wordDisplaySelector } from '@/store/settingAtom' import { MENU } from '@/common/common' -import { checkLineOrientation, getDistance } from '@/util/canvas-util' - import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import { useCanvasEvent } from '@/hooks/useCanvasEvent' @@ -28,6 +26,7 @@ import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal import { usePopup } from '@/hooks/usePopup' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' +import { useCommonUtils } from '@/hooks/common/useCommonUtils' const canvasMenus = [ { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, @@ -57,12 +56,11 @@ export default function CanvasMenu(props) { const globalLocale = useRecoilValue(globalLocaleStore) const canvas = useRecoilValue(canvasState) const sessionState = useRecoilValue(sessionStore) - const wordDisplay = useRecoilValue(wordDisplaySelector) const { getMessage } = useMessage() const { saveCanvas } = usePlan() const { swalFire } = useSwal() - const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent() + const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent() const [commonFunctionState, setCommonFunctionState] = useState({ text: false, @@ -70,6 +68,12 @@ export default function CanvasMenu(props) { distance: false, }) + const { commonFunctions } = useCommonUtils({ + canvas, + commonFunctionState, + setCommonFunctionState, + }) + const [popup, setPopup] = useRecoilState(popupState) const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] @@ -148,335 +152,6 @@ export default function CanvasMenu(props) { addPopup(id, 0, ) } - const commonTextMode = () => { - let textbox - if (commonFunctionState.text) { - addCanvasMouseEventListener('mouse:down', (event) => { - const pointer = canvas?.getPointer(event.e) - textbox = new fabric.Textbox('', { - left: pointer.x, - top: pointer.y, - width: 200, - fontSize: 14, - editable: true, - name: 'commonText', - visible: wordDisplay, - }) - - canvas?.add(textbox) - canvas.setActiveObject(textbox) - textbox.enterEditing() - textbox.selectAll() - }) - - addDocumentEventListener('keydown', document, (e) => { - if (e.key === 'Enter') { - if (commonFunctionState.text) { - const activeObject = canvas.getActiveObject() - if (activeObject && activeObject.isEditing) { - if (activeObject.text === '') { - canvas?.remove(activeObject) - } else { - activeObject.exitEditing() - } - //정책 협의 - const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText') - texts.forEach((text) => { - text.set({ editable: false }) - }) - - canvas.renderAll() - } - } - } - }) - } - } - - const commonDimensionMode = () => { - if (commonFunctionState.dimension) { - let points = [] - let distanceText = null - let minX, minY, maxX, maxY - - // 화살표를 생성하는 함수 - function createArrow(x, y, angle) { - return new fabric.Triangle({ - left: x, - top: y, - originX: 'center', - originY: 'center', - angle: angle, - width: 15, - height: 15, - fill: 'black', - selectable: false, - }) - } - - const circleOptions = { - radius: 5, - strokeWidth: 2, - stroke: 'red', - fill: 'white', - selectable: false, - } - - const lineOptions = { - stroke: 'black', - strokeWidth: 2, - selectable: false, - } - - // 캔버스에 클릭 이벤트 추가 - addCanvasMouseEventListener('mouse:down', (e) => { - const pointer = canvas.getPointer(e.e) - let point - - if (points.length === 0) { - // 첫 번째 포인트는 그대로 클릭한 위치에 추가 - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, - }) - points.push(point) - canvas.add(point) - } else if (points.length === 1) { - // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 - const p1 = points[0] - const deltaX = Math.abs(pointer.x - (p1.left + p1.radius)) - const deltaY = Math.abs(pointer.y - (p1.top + p1.radius)) - - if (deltaX > deltaY) { - // 수평선 상에만 배치 (y 좌표 고정) - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: p1.top, // y 좌표 고정 - ...circleOptions, - }) - } else { - // 수직선 상에만 배치 (x 좌표 고정) - point = new fabric.Circle({ - left: p1.left, // x 좌표 고정 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, - }) - } - - points.push(point) - canvas.add(point) - - // 두 포인트의 중심 좌표 계산 - const p2 = points[1] - const p1CenterX = p1.left + p1.radius - const p1CenterY = p1.top + p1.radius - const p2CenterX = p2.left + p2.radius - const p2CenterY = p2.top + p2.radius - - points.forEach((point) => { - canvas?.remove(point) - }) - - // 두 포인트 간에 직선을 그림 (중심을 기준으로) - const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) - canvas.add(line) - - const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) - const lineDirection = checkLineOrientation(line) - let extendLine = [] - - if (lineDirection === 'horizontal') { - extendLine = [ - [line.x1, line.y1 - 20, line.x1, line.y1 + 20], - [line.x2, line.y2 - 20, line.x2, line.y2 + 20], - ] - } else { - extendLine = [ - [line.x1 - 20, line.y1, line.x1 + 20, line.y1], - [line.x2 - 20, line.y2, line.x2 + 20, line.y2], - ] - } - - extendLine.forEach((line) => { - const extendLine = new fabric.Line(line, lineOptions) - canvas.add(extendLine) - }) - - // 두 포인트 간의 각도를 계산하여 화살표 추가 - // const angle = calculateAngle({ x: p1CenterX, y: p1CenterY }, { x: p2CenterX, y: p2CenterY }) - - // 첫 번째 포인트에 화살표 추가 - - const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1 - const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1 - const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8 - const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 8 - - const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 - const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 - canvas.add(arrow1) - canvas.add(arrow2) - - // 두 포인트 간의 거리 계산 - - // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 - distanceText = new fabric.Text(`${distance * 10}`, { - left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), - top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), - fill: 'black', - fontSize: 16, - selectable: true, - textAlign: 'center', - originX: 'center', - originY: 'center', - angle: lineDirection === 'horizontal' ? 0 : 270, - name: 'lengthText', - // lockMovementX: false, - // lockMovementY: false, - }) - canvas.add(distanceText) - - // minX = p1CenterX - // maxX = p2CenterX - // minY = p1CenterY - // maxY = p2CenterY - - // 거리 계산 후, 다음 측정을 위해 초기화 - points = [] - } - - // 캔버스 다시 그리기 - canvas.renderAll() - }) - - // addCanvasMouseEventListener('object:moving', function (e) { - // const obj = e.target - - // if (obj.left < minX) { - // obj.left = minX - // } - // if (obj.left + obj.width > maxX) { - // obj.left = maxX - obj.width - // } - // if (obj.top < minY) { - // obj.top = minY - // } - // if (obj.top + obj.height > maxY) { - // obj.top = maxY - obj.height - // } - // }) - } - } - - const commonDistanceMode = () => { - if (commonFunctionState.distance) { - let points = [] - let distanceText = null - - const circleOptions = { - radius: 5, - strokeWidth: 2, - stroke: 'red', - fill: 'white', - selectable: false, - } - - const lineOptions = { - stroke: 'black', - strokeWidth: 2, - selectable: false, - strokeDashArray: [9, 5], - } - - const textOptions = { - fill: 'black', - fontSize: 16, - selectable: true, - textAlign: 'center', - originX: 'center', - originY: 'center', - } - - // 캔버스에 클릭 이벤트 추가 - addCanvasMouseEventListener('mouse:down', function (options) { - const pointer = canvas.getPointer(options.e) - let point - - if (points.length === 0) { - // 첫 번째 포인트는 그대로 클릭한 위치에 추가 - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, - }) - points.push(point) - canvas.add(point) - } else if (points.length === 1) { - // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 - const p1 = points[0] - - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, - }) - - points.push(point) - canvas.add(point) - - // 두 포인트의 중심 좌표 계산 - const p2 = points[1] - - const p1CenterX = p1.left + p1.radius - const p1CenterY = p1.top + p1.radius - const p2CenterX = p2.left + p2.radius - const p2CenterY = p2.top + p2.radius - - const p3 = new fabric.Point(p2CenterX, p1CenterY) - - // 두 포인트 간에 직선을 그림 (중심을 기준으로) - const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) - const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) - const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) - canvas.add(line) - canvas.add(line2) - canvas.add(line3) - - const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) - const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) - const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) - - // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 - distanceText = new fabric.Text(`${distance1}`, { - left: (p1CenterX + p2CenterX) / 2, - top: (p1CenterY + p2CenterY) / 2, - ...textOptions, - }) - canvas.add(distanceText) - distanceText = new fabric.Text(`${distance2}`, { - left: (p2CenterX + p3.x) / 2, - top: (p2CenterY + p3.y) / 2, - ...textOptions, - }) - canvas.add(distanceText) - distanceText = new fabric.Text(`${distance3}`, { - left: (p3.x + p1CenterX) / 2, - top: (p3.y + p1CenterY) / 2, - ...textOptions, - }) - canvas.add(distanceText) - - // 거리 계산 후, 다음 측정을 위해 초기화 - points = [] - } - - // 캔버스 다시 그리기 - canvas.renderAll() - }) - } - } - useEffect(() => { if (globalLocale === 'ko') { setAppMessageState(KO) @@ -485,35 +160,6 @@ export default function CanvasMenu(props) { } }, [menuNumber, type, globalLocale]) - const commonFunctions = (mode) => { - let tempStates = { ...commonFunctionState } - - if (tempStates[mode]) { - tempStates[mode] = false - } else { - Object.keys(tempStates).forEach((key) => { - tempStates[key] = false - }) - - if (mode !== undefined) { - tempStates[mode] = true - } - } - - setCommonFunctionState(tempStates) - } - - useEffect(() => { - initEvent() - if (commonFunctionState.text) { - commonTextMode() - } else if (commonFunctionState.dimension) { - commonDimensionMode() - } else if (commonFunctionState.distance) { - commonDistanceMode() - } - }, [commonFunctionState]) - return (
    diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index e69de29b..52106e3e 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -0,0 +1,367 @@ +import { useEffect } from 'react' +import { useRecoilValue } from 'recoil' +import { wordDisplaySelector } from '@/store/settingAtom' +import { checkLineOrientation, getDistance } from '@/util/canvas-util' +import { useEvent } from '@/hooks/useEvent' + +export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { + const wordDisplay = useRecoilValue(wordDisplaySelector) + const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() + + useEffect(() => { + initEvent() + if (commonFunctionState.text) { + commonTextMode() + } else if (commonFunctionState.dimension) { + commonDimensionMode() + } else if (commonFunctionState.distance) { + commonDistanceMode() + } + }, [commonFunctionState]) + + const commonTextMode = () => { + let textbox + if (commonFunctionState.text) { + addCanvasMouseEventListener('mouse:down', (event) => { + const pointer = canvas?.getPointer(event.e) + textbox = new fabric.Textbox('', { + left: pointer.x, + top: pointer.y, + width: 200, + fontSize: 14, + editable: true, + name: 'commonText', + visible: wordDisplay, + }) + + canvas?.add(textbox) + canvas.setActiveObject(textbox) + textbox.enterEditing() + textbox.selectAll() + }) + + addDocumentEventListener('keydown', document, (e) => { + if (e.key === 'Enter') { + if (commonFunctionState.text) { + const activeObject = canvas.getActiveObject() + if (activeObject && activeObject.isEditing) { + if (activeObject.text === '') { + canvas?.remove(activeObject) + } else { + activeObject.exitEditing() + } + //정책 협의 + const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText') + texts.forEach((text) => { + text.set({ editable: false }) + }) + + canvas.renderAll() + } + } + } + }) + } + } + + const commonDimensionMode = () => { + if (commonFunctionState.dimension) { + let points = [] + let distanceText = null + let minX, minY, maxX, maxY + + // 화살표를 생성하는 함수 + function createArrow(x, y, angle) { + return new fabric.Triangle({ + left: x, + top: y, + originX: 'center', + originY: 'center', + angle: angle, + width: 15, + height: 15, + fill: 'black', + selectable: false, + }) + } + + const circleOptions = { + radius: 5, + strokeWidth: 2, + stroke: 'red', + fill: 'white', + selectable: false, + } + + const lineOptions = { + stroke: 'black', + strokeWidth: 2, + selectable: false, + } + + // 캔버스에 클릭 이벤트 추가 + addCanvasMouseEventListener('mouse:down', (e) => { + const pointer = canvas.getPointer(e.e) + let point + + if (points.length === 0) { + // 첫 번째 포인트는 그대로 클릭한 위치에 추가 + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + points.push(point) + canvas.add(point) + } else if (points.length === 1) { + // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 + const p1 = points[0] + const deltaX = Math.abs(pointer.x - (p1.left + p1.radius)) + const deltaY = Math.abs(pointer.y - (p1.top + p1.radius)) + + if (deltaX > deltaY) { + // 수평선 상에만 배치 (y 좌표 고정) + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: p1.top, // y 좌표 고정 + ...circleOptions, + }) + } else { + // 수직선 상에만 배치 (x 좌표 고정) + point = new fabric.Circle({ + left: p1.left, // x 좌표 고정 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + } + + points.push(point) + canvas.add(point) + + // 두 포인트의 중심 좌표 계산 + const p2 = points[1] + const p1CenterX = p1.left + p1.radius + const p1CenterY = p1.top + p1.radius + const p2CenterX = p2.left + p2.radius + const p2CenterY = p2.top + p2.radius + + points.forEach((point) => { + canvas?.remove(point) + }) + + // 두 포인트 간에 직선을 그림 (중심을 기준으로) + const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) + canvas.add(line) + + const distance = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) + const lineDirection = checkLineOrientation(line) + let extendLine = [] + + if (lineDirection === 'horizontal') { + extendLine = [ + [line.x1, line.y1 - 20, line.x1, line.y1 + 20], + [line.x2, line.y2 - 20, line.x2, line.y2 + 20], + ] + } else { + extendLine = [ + [line.x1 - 20, line.y1, line.x1 + 20, line.y1], + [line.x2 - 20, line.y2, line.x2 + 20, line.y2], + ] + } + + extendLine.forEach((line) => { + const extendLine = new fabric.Line(line, lineOptions) + canvas.add(extendLine) + }) + + // 첫 번째 포인트에 화살표 추가 + const paddingX = lineDirection === 'horizontal' ? p1CenterX + 7.5 : p1CenterX + 1 + const paddingX2 = lineDirection === 'horizontal' ? p2CenterX - 6.5 : p2CenterX + 1 + const paddingY = lineDirection === 'horizontal' ? p1CenterY + 1 : p1CenterY + 8 + const paddingY2 = lineDirection === 'horizontal' ? p2CenterY + 1 : p2CenterY - 8 + + const arrow1 = createArrow(paddingX, paddingY, lineDirection === 'horizontal' ? -90 : 0) // 반대 방향 화살표 + const arrow2 = createArrow(paddingX2, paddingY2, lineDirection === 'horizontal' ? 90 : 180) // 정방향 화살표 + canvas.add(arrow1) + canvas.add(arrow2) + + // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 + distanceText = new fabric.Text(`${distance}`, { + left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), + top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), + fill: 'black', + fontSize: 16, + selectable: true, + textAlign: 'center', + originX: 'center', + originY: 'center', + angle: lineDirection === 'horizontal' ? 0 : 270, + // lockMovementX: false, + // lockMovementY: false, + }) + canvas.add(distanceText) + + // minX = p1CenterX + // maxX = p2CenterX + // minY = p1CenterY + // maxY = p2CenterY + + // 거리 계산 후, 다음 측정을 위해 초기화 + points = [] + } + + // 캔버스 다시 그리기 + canvas.renderAll() + }) + + // addCanvasMouseEventListener('object:moving', function (e) { + // const obj = e.target + + // if (obj.left < minX) { + // obj.left = minX + // } + // if (obj.left + obj.width > maxX) { + // obj.left = maxX - obj.width + // } + // if (obj.top < minY) { + // obj.top = minY + // } + // if (obj.top + obj.height > maxY) { + // obj.top = maxY - obj.height + // } + // }) + } + } + + const commonDistanceMode = () => { + if (commonFunctionState.distance) { + let points = [] + let distanceText = null + + const circleOptions = { + radius: 5, + strokeWidth: 2, + stroke: 'red', + fill: 'white', + selectable: false, + } + + const lineOptions = { + stroke: 'black', + strokeWidth: 2, + selectable: false, + strokeDashArray: [9, 5], + } + + const textOptions = { + fill: 'black', + fontSize: 16, + selectable: true, + textAlign: 'center', + originX: 'center', + originY: 'center', + } + + // 캔버스에 클릭 이벤트 추가 + addCanvasMouseEventListener('mouse:down', function (options) { + const pointer = canvas.getPointer(options.e) + let point + + if (points.length === 0) { + // 첫 번째 포인트는 그대로 클릭한 위치에 추가 + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + points.push(point) + canvas.add(point) + } else if (points.length === 1) { + // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 + const p1 = points[0] + + point = new fabric.Circle({ + left: pointer.x - 5, // 반지름 반영 + top: pointer.y - 5, // 반지름 반영 + ...circleOptions, + }) + + points.push(point) + canvas.add(point) + + // 두 포인트의 중심 좌표 계산 + const p2 = points[1] + + const p1CenterX = p1.left + p1.radius + const p1CenterY = p1.top + p1.radius + const p2CenterX = p2.left + p2.radius + const p2CenterY = p2.top + p2.radius + + const p3 = new fabric.Point(p2CenterX, p1CenterY) + + // 두 포인트 간에 직선을 그림 (중심을 기준으로) + const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) + const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) + const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) + canvas.add(line) + canvas.add(line2) + canvas.add(line3) + + const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) + const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) + const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + + // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 + distanceText = new fabric.Text(`${distance1}`, { + left: (p1CenterX + p2CenterX) / 2, + top: (p1CenterY + p2CenterY) / 2, + ...textOptions, + }) + canvas.add(distanceText) + distanceText = new fabric.Text(`${distance2}`, { + left: (p2CenterX + p3.x) / 2, + top: (p2CenterY + p3.y) / 2, + ...textOptions, + }) + canvas.add(distanceText) + distanceText = new fabric.Text(`${distance3}`, { + left: (p3.x + p1CenterX) / 2, + top: (p3.y + p1CenterY) / 2, + ...textOptions, + }) + canvas.add(distanceText) + + // 거리 계산 후, 다음 측정을 위해 초기화 + points = [] + } + + // 캔버스 다시 그리기 + canvas.renderAll() + }) + } + } + const commonFunctions = (mode) => { + let tempStates = { ...commonFunctionState } + + if (tempStates[mode]) { + tempStates[mode] = false + } else { + Object.keys(tempStates).forEach((key) => { + tempStates[key] = false + }) + + if (mode !== undefined) { + tempStates[mode] = true + } + } + + setCommonFunctionState(tempStates) + } + + return { + commonTextMode, + commonDimensionMode, + commonDistanceMode, + commonFunctions, + } +} From 1493f9b9d3162f87d4b6f015b4e7c915825bc362 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Oct 2024 10:24:40 +0900 Subject: [PATCH 053/139] =?UTF-8?q?=EC=B9=98=EC=88=98=20=ED=91=9C=EA=B8=B0?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCommonUtils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 52106e3e..b4fb4fc8 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -1,8 +1,8 @@ import { useEffect } from 'react' import { useRecoilValue } from 'recoil' import { wordDisplaySelector } from '@/store/settingAtom' -import { checkLineOrientation, getDistance } from '@/util/canvas-util' import { useEvent } from '@/hooks/useEvent' +import { checkLineOrientation, getDistance } from '@/util/canvas-util' export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { const wordDisplay = useRecoilValue(wordDisplaySelector) @@ -186,7 +186,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS canvas.add(arrow2) // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 - distanceText = new fabric.Text(`${distance}`, { + distanceText = new fabric.Text(`${distance * 10} `, { left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), fill: 'black', @@ -312,19 +312,19 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 - distanceText = new fabric.Text(`${distance1}`, { + distanceText = new fabric.Text(`${distance1 * 10}`, { left: (p1CenterX + p2CenterX) / 2, top: (p1CenterY + p2CenterY) / 2, ...textOptions, }) canvas.add(distanceText) - distanceText = new fabric.Text(`${distance2}`, { + distanceText = new fabric.Text(`${distance2 * 10}`, { left: (p2CenterX + p3.x) / 2, top: (p2CenterY + p3.y) / 2, ...textOptions, }) canvas.add(distanceText) - distanceText = new fabric.Text(`${distance3}`, { + distanceText = new fabric.Text(`${distance3 * 10}`, { left: (p3.x + p1CenterX) / 2, top: (p3.y + p1CenterY) / 2, ...textOptions, From 543657bcd4b34f46bb2f2ef840c98d2a6109fa5e Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 23 Oct 2024 10:34:18 +0900 Subject: [PATCH 054/139] =?UTF-8?q?mouseline=20intersectionPoint=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useAuxiliaryDrawing.js | 1 - src/hooks/useMouse.js | 4 ++-- src/util/canvas-util.js | 9 ++++++++- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 7d18c5a2..610db186 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -454,7 +454,6 @@ export function useAuxiliaryDrawing(id) { const mouseDown = (e) => { canvas.renderAll() const pointer = getIntersectMousePoint(e) - console.log(pointer) mousePointerArr.current.push(pointer) if (mousePointerArr.current.length === 2) { diff --git a/src/hooks/useMouse.js b/src/hooks/useMouse.js index d484930a..033fea59 100644 --- a/src/hooks/useMouse.js +++ b/src/hooks/useMouse.js @@ -1,6 +1,6 @@ import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' -import { calculateIntersection } from '@/util/canvas-util' +import { calculateIntersection, getInterSectionLineNotOverCoordinate } from '@/util/canvas-util' export function useMouse() { const canvas = useRecoilValue(canvasState) @@ -14,7 +14,7 @@ export function useMouse() { return pointer } - return calculateIntersection(mouseLines[0], mouseLines[1]) || pointer + return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || pointer } return { diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 7e26e460..8ed918ca 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -333,7 +333,6 @@ export const findIntersection1 = (line1, line2) => { export const calculateIntersection = (line1, line2) => { const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2]) - if (!result) { return null } @@ -366,6 +365,14 @@ export const calculateIntersection = (line1, line2) => { } } +export const getInterSectionLineNotOverCoordinate = (line1, line2) => { + const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2]) + if (result) { + return { x: Math.round(result[0]), y: Math.round(result[1]) } + } + return null +} + export function findOrthogonalPoint(line1, line2) { // Calculate the intersection point of two lines const intersectionX = From 743c90fdaacad13e7e432a4c46ebb099ea9af8ca Mon Sep 17 00:00:00 2001 From: minsik Date: Wed, 23 Oct 2024 10:53:02 +0900 Subject: [PATCH 055/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/static/images/sub/product-del.svg | 5 ++++ src/styles/_contents.scss | 29 +++++++++++++++++++++++- src/styles/_reset.scss | 8 +++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 public/static/images/sub/product-del.svg diff --git a/public/static/images/sub/product-del.svg b/public/static/images/sub/product-del.svg new file mode 100644 index 00000000..dab3463a --- /dev/null +++ b/public/static/images/sub/product-del.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index f70745b3..70bd9f40 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -1200,7 +1200,6 @@ border: 1px solid #E5E5E5; background: #FFF; transition: all .15s ease-in-out; - cursor: pointer; .file-item-info{ .item-num{ display: inline-block; @@ -1255,4 +1254,32 @@ font-size: 16px; font-weight: 500; color: #344356; +} + +//신규물건 등록 +.product-input-wrap{ + display: flex; + align-items: center; + width: 200px; + height: 30px; + background-color: #FAFAFA; + border: 1px solid #EEE; + padding: 0 10px; + input{ + font-size: 13px; + font-weight: 400; + color: #999999; + padding: 0; + height: 100%; + flex: 1 ; + background-color: inherit; + } + .product-delete{ + flex: none; + display: block; + width: 15px; + height: 100%; + background: url(../../public/static/images/sub/product-del.svg)no-repeat center; + background-size: 15px 15px; + } } \ No newline at end of file diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index d483c7b7..b623dbff 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -460,6 +460,7 @@ input[type=text]{ line-height: 30px; border-radius: 2px; background-color: #323234; + border: 1px solid #323234; color: #fff; font-size: 12px; font-weight: 500; @@ -467,6 +468,10 @@ input[type=text]{ padding: 0 10px; letter-spacing: 0px; text-align: right; + transition: border .15s ease-in-out; + &:focus{ + border: 1px solid #1083E3; + } &::placeholder{ opacity: 1; font-size: 12px; @@ -498,6 +503,9 @@ input[type=text]{ font-weight: normal; transition: border-color .17s ease-in-out; text-align: left; + &:focus{ + border-color: #94A0AD; + } &:read-only{ background-color: #FAFAFA; color: #999999; From d6fc1134c1f188ee433073d95007812703f17927 Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 23 Oct 2024 11:01:04 +0900 Subject: [PATCH 056/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=8B=A0=EA=B7=9C=EB=93=B1=EB=A1=9D&=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 538 +++++++++++++--------- src/components/management/StuffHeader.jsx | 33 +- src/locales/ja.json | 18 + src/locales/ko.json | 18 + 4 files changed, 371 insertions(+), 236 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 46353f08..ec67e5c4 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -674,19 +674,27 @@ export default function StuffDetail() { // 물건삭제 const onDelete = () => { - //http://localhost:8080/api/object/R201TES01240910023 // console.log('물건번호::::::::', objectNo) - alert('사양확정일이 있으면 삭제 불가') - if (confirm(getMessage('common.message.data.delete'))) { - let testobj = '10' - - del({ url: `/api/object/${testobj}` }).then((res) => { - console.log('삭제 결과:::', res) - router.push('/management/stuff') - }) + // console.log('detailData:::::::::', detailData) + const specificationConfirmDate = detailData.specificationConfirmDate + if (specificationConfirmDate != null) { + alert(getMessage('stuff.detail.delete.message1')) + } else { + if (confirm(getMessage('common.message.data.delete'))) { + del({ url: `/api/object/${objectNo}` }).then((res) => { + console.log('삭제결과:::::::', res) + router.push('/management/stuff') + }) + } } } + // 숫자만 입력 가능 + const handleKeyUp = (e) => { + let input = e.target + input.value = input.value.replace(/[^0-9]/g, '') + } + return ( <> {(editMode === 'NEW' && ( @@ -707,8 +715,18 @@ export default function StuffDetail() { {getMessage('stuff.detail.planReqNo')}
    -
    - +
    + + {(form.watch('planReqNo') !== '' && ( + + )) || + null}
    ) : ( )}
    @@ -1072,229 +1102,281 @@ export default function StuffDetail() {
    * {getMessage('stuff.detail.required')}
    -
    - - - - - - - - - + + +
    {getMessage('stuff.detail.planReqNo')} -
    -
    - +
    +
    + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - + + + + + + + - - - + + - + + + + - - - - - - -
    {getMessage('stuff.detail.planReqNo')} +
    +
    + + {objectNo.substring(0, 1) === 'T' && form.watch('planReqNo') !== '' ? ( + + ) : null} +
    + {objectNo.substring(0, 1) === 'T' ? ( + <> + + + ) : null}
    - {objectNo.substring(0, 1) === 'T' ? ( - <> - - - ) : null} - -
    - {getMessage('stuff.detail.dispCompanyName')} * - -
    - -
    -
    - {getMessage('stuff.detail.objectStatusId')} * - -
    - {/* 상세라디오시작 */} - {objectStatusList.map((row) => { - return ( -
    - - -
    - ) - })} - {/* 상세라디오끝 */} -
    - +
    + {getMessage('stuff.detail.dispCompanyName')} * + +
    +
    -
    - +
    + {getMessage('stuff.detail.objectStatusId')} * + +
    + {/* 상세라디오시작 */} + {objectStatusList.map((row) => { + return ( +
    + + +
    + ) + })} + {/* 상세라디오끝 */} +
    + +
    +
    + +
    - -
    {getMessage('stuff.detail.objectNameKana')} -
    - -
    -
    -
    -
    - {getMessage('stuff.detail.saleStoreId')} - * + +
    {getMessage('stuff.detail.objectNameKana')} +
    +
    -
    - - -
    -
    -
    -
    +
    +
    + {getMessage('stuff.detail.saleStoreId')} + * +
    +
    -
    - +
    +
    +
    + +
    - -
    -
    -
    {getMessage('stuff.detail.otherSaleStoreId')}
    -
    - {getMessage('stuff.detail.tooltip.saleStoreId')} + +
    +
    +
    {getMessage('stuff.detail.otherSaleStoreId')}
    +
    + {getMessage('stuff.detail.tooltip.saleStoreId')} +
    - -
    -
    -
    -
    +
    +
    + +
    -
    - +
    + {getMessage('stuff.detail.zipNo')} * + +
    +
    + +
    + +
    {getMessage('stuff.detail.btn.addressPop.guide')}
    - -
    - {getMessage('stuff.detail.zipNo')} * - -
    -
    - -
    - -
    {getMessage('stuff.detail.btn.addressPop.guide')}
    -
    -
    +
    +
    + + {objectNo.substring(0, 1) === 'R' ? ( + <> + {/* 진짜R 플랜시작 */} +
    +
    +

    {getMessage('stuff.detail.planList.title')}

    +
      +
    • + {getMessage('stuff.detail.planList.cnt')} + 플랜갯수 +
    • +
    +
    +
    +
    +
    +
    +
    {getMessage('stuff.detail.planList.help')}
    +
    +
    + {getMessage('stuff.detail.planList.guide1')} + {getMessage('stuff.detail.planList.guide2')} + {getMessage('stuff.detail.planList.guide3')} +
    +
    +
    +
    + 그리드영역 +
    페이징영역
    +
    +
    + {/* 진짜R 플랜끝 */} +
    + + + + + +
    + + ) : ( + <> +
    + {!isFormValid ? ( + + ) : ( + + )} + + + +
    + + )}
    - {objectNo.substring(0, 1) === 'R' ? ( - <> - - - - - - - ) : ( - <> - {!isFormValid ? ( - - ) : ( - - )} - - - - - )} )} {showAddressButtonValid && } diff --git a/src/components/management/StuffHeader.jsx b/src/components/management/StuffHeader.jsx index fb4d831c..d8cade80 100644 --- a/src/components/management/StuffHeader.jsx +++ b/src/components/management/StuffHeader.jsx @@ -5,7 +5,10 @@ import { useAxios } from '@/hooks/useAxios' import { useRouter, useSearchParams } from 'next/navigation' import { globalLocaleStore } from '@/store/localeAtom' import { useRecoilValue } from 'recoil' +import { useMessage } from '@/hooks/useMessage' + export default function StuffHeader() { + const { getMessage } = useMessage() const router = useRouter() const searchParams = useSearchParams() const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set @@ -15,35 +18,49 @@ export default function StuffHeader() { useEffect(() => { get({ url: `/api/object/${objectNo}/detail` }).then((res) => { - //console.log('res::', res) if (res != null && res != '') { - console.log('헤더상세::::::::::', res) setHeaderData(res) } else { - alert('삭제된 물건입니다') + alert(getMessage('stuff.detail.header.message1')) router.push('/management/stuff') } }) }, [objectNo]) + //물건번호 복사 + const copyObjectNo = async (objectNo) => { + await navigator.clipboard.writeText(objectNo) + alert(getMessage('stuff.detail.header.message2')) + try { + } catch (error) { + alert(getMessage('stuff.detail.header.message3')) + } + } + return (
    -
    물건번호
    +
    {getMessage('stuff.detail.header.objectNo')}
    - {headerData.objectNo} + {headerData.objectNo}{' '} +
    -
    사양확정일
    +
    {getMessage('stuff.detail.header.specificationConfirmDate')}
    {headerData.specificationConfirmDate}
    -
    갱신일시
    +
    {getMessage('stuff.detail.header.lastEditDatetime')}
    {headerData.lastEditDatetime}
    -
    등록일
    +
    {getMessage('stuff.detail.header.createDatetime')}
    {headerData.createDatetime}
    diff --git a/src/locales/ja.json b/src/locales/ja.json index 2b743e4a..359d313e 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -468,6 +468,13 @@ "stuff.addressPopup.btn2": "住所適用", "stuff.planReqPopup.title": "設計依頼のインポート", "stuff.temp.subTitle": "商品情報", + "stuff.detail.header.message1": "存在しないものです。", + "stuff.detail.header.message2": "商品番号がコピーされました。", + "stuff.detail.header.message3": "存在しないものです。", + "stuff.detail.header.objectNo": "商品番号のコピーに失敗しました。", + "stuff.detail.header.specificationConfirmDate": "仕様拡張日", + "stuff.detail.header.lastEditDatetime": "更新日時", + "stuff.detail.header.createDatetime": "登録日", "stuff.detail.required": "必須入力項目", "stuff.detail.planReqNo": "設計依頼No.", "stuff.detail.dispCompanyName": "担当者", @@ -497,6 +504,17 @@ "stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください", "stuff.detail.tempSave.message1": "一時保存されました。商品番号を取得するには、必須項目をすべて入力してください。", "stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?", + "stuff.detail.delete.message1": "仕様が確定したものは削除できません。", + "stuff.detail.planList.title": "プランリスト", + "stuff.detail.planList.cnt": "全体", + "stuff.detail.planList.help": "ヘルプ", + "stuff.detail.planList.guide1": "1.発注は同一品番基準1件のみ可能です。", + "stuff.detail.planList.guide2": "2.[Excelダウンロード]は見積書、図面、シミュレーション結果をExcelファイルで一度にダウンロードします。", + "stuff.detail.planList.guide3": "3. プラン情報をダブルクリックすると図面作成画面に移動します。", + "stuff.detail.btn.delete": "物の削除", + "stuff.detail.btn.moveList": "商品リスト", + "stuff.detail.btn.save": "保存", + "stuff.detail.btn.tempSave": "一時保存", "stuff.planReqPopup.popTitle": "設計依頼検索", "stuff.planReqPopup.btn1": "検索", "stuff.planReqPopup.btn2": "初期化", diff --git a/src/locales/ko.json b/src/locales/ko.json index 61f3ba9e..fe228f22 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -473,6 +473,13 @@ "stuff.addressPopup.btn2": "주소적용", "stuff.planReqPopup.title": "설계의뢰 불러오기", "stuff.temp.subTitle": "물건정보", + "stuff.detail.header.message1": "존재하지 않는 물건입니다.", + "stuff.detail.header.message2": "물건번호가 복사되었습니다.", + "stuff.detail.header.message3": "물건번호 복사에 실패했습니다.", + "stuff.detail.header.objectNo": "물건번호", + "stuff.detail.header.specificationConfirmDate": "사양확장일", + "stuff.detail.header.lastEditDatetime": "갱신일시", + "stuff.detail.header.createDatetime": "등록일", "stuff.detail.required": "필수 입력항목", "stuff.detail.planReqNo": "설계의뢰No.", "stuff.detail.dispCompanyName": "담당자", @@ -502,6 +509,17 @@ "stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요", "stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.", "stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", + "stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.", + "stuff.detail.planList.title": "플랜리스트", + "stuff.detail.planList.cnt": "전체", + "stuff.detail.planList.help": "도움말", + "stuff.detail.planList.guide1": "1.발주는 동일 물건번호 기준 1건만 가능합니다.", + "stuff.detail.planList.guide2": "2.[Excel 다운로드]는 견적서, 도면, 시뮬레이션 결과를 엑셀파일로 한번에 다운로드 합니다.", + "stuff.detail.planList.guide3": "3.플랜정보를 더블 클릭하면 도면작성 화면으로 이동합니다.", + "stuff.detail.btn.delete": "물건삭제", + "stuff.detail.btn.moveList": "물건목록", + "stuff.detail.btn.save": "저장", + "stuff.detail.btn.tempSave": "임시저장", "stuff.planReqPopup.popTitle": "설계 요청 검색", "stuff.planReqPopup.btn1": "검색", "stuff.planReqPopup.btn2": "초기화", From bf35c1182d2a5821787da15fde59e47899ac8aac Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 23 Oct 2024 12:38:06 +0900 Subject: [PATCH 057/139] =?UTF-8?q?=ED=92=8D=EC=86=8D=ED=8C=9D=EC=97=85=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=EB=AA=85=20=EB=B3=80=EA=B2=BD=20=EB=B0=98?= =?UTF-8?q?=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 99 ++++++++++++------- .../management/popup/WindSelectPop.jsx | 13 ++- 2 files changed, 74 insertions(+), 38 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index ec67e5c4..fd01fc41 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -52,7 +52,7 @@ export default function StuffDetail() { prefName: '', address: '', //주소 areaId: '', //발전량시뮬레이션지역id - windSpeed: '', //기준풍속 + standardWindSpeedId: '', //기준풍속 verticalSnowCover: '', //수직적설량NEW coldRegionFlg: false, //한랭지대책시행(true : 1 / false : 0) surfaceType: 'III・IV', //면조도구분(III・IV / Ⅱ) @@ -147,7 +147,7 @@ export default function StuffDetail() { useEffect(() => { const code1 = findCommonCode(200800) //경칭 const code2 = findCommonCode(201700) //신축/기축 - const code3 = findCommonCode(113600) //기준풍속 + const code3 = findCommonCode(202000) //기준풍속 202000 if (code1 != null) { // console.log('경칭공코::::::', code1) setHonorificCodeList(code1) @@ -225,8 +225,8 @@ export default function StuffDetail() { //경칭선택 변경 이벤트 const onChangeHonorificCode = (key) => { if (isObjectNotEmpty(key)) { - setSelHonorificCode(key.clCode) - form.setValue('objectNameOmit', key.clCode) + setSelHonorificCode(key.clCodeNm) + form.setValue('objectNameOmit', key.clCodeNm) } else { setSelHonorificCode('') form.setValue('objectNameOmit', '') @@ -236,9 +236,9 @@ export default function StuffDetail() { //기준풍속 변경 이벤트 const onChangeWindSpeedCode = (key) => { if (isObjectNotEmpty(key)) { - form.setValue('windSpeed', key.clCode) + form.setValue('standardWindSpeedId', key.clCode) } else { - form.setValue('windSpeed', '') + form.setValue('standardWindSpeedId', '') } } @@ -388,7 +388,9 @@ export default function StuffDetail() { form.setValue('prefName', info.address1) } }) - form.setValue('windSpeed', info.windSpeed) + + //설계의뢰 팝업에선 WL_안붙어서 옴 + form.setValue('standardWindSpeedId', `WL_${info.windSpeed}`) form.setValue('verticalSnowCover', info.verticalSnowCover) form.setValue('surfaceType', info.surfaceType) form.setValue('installHeight', info.installHeight) @@ -407,9 +409,9 @@ export default function StuffDetail() { } } - //팝업에서 넘어온 바람정보 + //풍속선택 팝업에서 넘어온 바람정보 const setWindSppedInfo = (info) => { - form.setValue('windSpeed', info.windSpeed) + form.setValue('standardWindSpeedId', info.windSpeed) } //dispCompanyName: '', //담당자 @@ -428,8 +430,8 @@ export default function StuffDetail() { const _address = watch('address') // areaId: '', //발전량시뮬레이션지역 const _areaId = watch('areaId') - // windSpeed: '', //기준풍속 - const _windSpeed = watch('windSpeed') + // standardWindSpeedId: '', //기준풍속 + const _standardWindSpeedId = watch('standardWindSpeedId') // verticalSnowCover: '', //수직적설량 const _verticalSnowCover = watch('verticalSnowCover') // installHeight: '', //설치높이 @@ -464,8 +466,8 @@ export default function StuffDetail() { errors.areaId = true } - if (!formData.windSpeed) { - errors.windSpeed = true + if (!formData.standardWindSpeedId) { + errors.standardWindSpeedId = true } if (!formData.verticalSnowCover) { @@ -506,8 +508,8 @@ export default function StuffDetail() { errors.areaId = true } - if (!formData.windSpeed) { - errors.windSpeed = true + if (!formData.standardWindSpeedId) { + errors.standardWindSpeedId = true } if (!formData.verticalSnowCover) { @@ -530,7 +532,7 @@ export default function StuffDetail() { _prefId, _address, _areaId, - _windSpeed, + _standardWindSpeedId, _verticalSnowCover, _installHeight, ]) @@ -575,7 +577,7 @@ export default function StuffDetail() { //필수값 다 입력했을때 const onValid = async () => { const formData = form.getValues() - console.log('필수값 통과:::', formData) + // console.log('필수값 통과:::', formData) const apiUrl = '/api/object/save-object' const params = { saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId, @@ -592,7 +594,7 @@ export default function StuffDetail() { areaId: formData.areaId, receiveUser: formData.dispCompanyName, installHeight: formData.installHeight, - windSpeed: formData.windSpeed, + standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, @@ -602,7 +604,7 @@ export default function StuffDetail() { workNo: null, workName: null, } - console.log('params::', params) + // console.log('params::', params) alert('작업중') return if (editMode === 'NEW') { @@ -646,7 +648,7 @@ export default function StuffDetail() { areaId: formData.areaId, receiveUser: formData.dispCompanyName, installHeight: formData.installHeight, - windSpeed: formData.windSpeed, + standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, @@ -662,6 +664,7 @@ export default function StuffDetail() { params.saleStoreId = sessionState.storeId params.saleStoreLevel = sessionState.storeLvl } + console.log('임시저장파람:::', params) alert('작업중') return await promisePost({ url: '/api/object/save-object', data: params }).then((res) => { @@ -716,7 +719,7 @@ export default function StuffDetail() {
    - + {(form.watch('planReqNo') !== '' && (
    @@ -833,7 +836,13 @@ export default function StuffDetail() { />
    - +
    @@ -887,7 +896,7 @@ export default function StuffDetail() {
    - +
    - +
    @@ -962,7 +971,7 @@ export default function StuffDetail() { {/* 기준풍속sel시작 */}
    @@ -1115,7 +1124,7 @@ export default function StuffDetail() {
    - + {objectNo.substring(0, 1) === 'T' && form.watch('planReqNo') !== '' ? (
    @@ -1295,7 +1307,7 @@ export default function StuffDetail() {
    - +
    + {/* 도도부현 /주소 시작*/} + {/* 도도부현 /주소 끝 */} + {/* 발전량시뮬레이션지역시작 */} + {/* 발전량시뮬레이션지역끝 */} + {/* 기준풍속시작 */} + {/* 기준풍속끝 */} + {/* 수직적설량시작 */} + {/* 수직적설량끝 */} + {/* 면조도구분시작 */} + {/* 면조도구분끝 */} + {/* 설치높이싲가 */} + {/* 설치높이끝 */} + {/* 계약조건시작 */} + {/* 계약조건끝 */} + {/* 메모시작 */} + {/* 메모끝 */} + + +
    @@ -1318,7 +1349,7 @@ export default function StuffDetail() {
    • {getMessage('stuff.detail.planList.cnt')} - 플랜갯수 + 플랜갯수찍어주기
    diff --git a/src/components/management/popup/WindSelectPop.jsx b/src/components/management/popup/WindSelectPop.jsx index db1795f8..b135aa20 100644 --- a/src/components/management/popup/WindSelectPop.jsx +++ b/src/components/management/popup/WindSelectPop.jsx @@ -81,16 +81,21 @@ export default function WindSelectPop(props) { {windSpeedList.map((row, index) => { - // console.log('row:::', row) return (
    - - + +
    - {row.windSpeed} + {row.standardWindSpeedId.slice(3)} {row.remarks} ) From 9e2e4bff581fc2a63aa6b790fd4589b1f909d34e Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Wed, 23 Oct 2024 13:33:55 +0900 Subject: [PATCH 058/139] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=A7=80=20focus=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Login.jsx | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index d75d9b6e..66d149ac 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -71,6 +71,10 @@ export default function Login() { const { promisePost, promisePatch, post } = useAxios(globalLocaleState) + // focus state + const [idFocus, setIdFocus] = useState(false) + const [secFocus, setSecFocus] = useState(false) + // login process const loginProcess = async (e) => { e.preventDefault() @@ -191,7 +195,7 @@ export default function Login() { {getMessage('site.sub_name')}
    -
    +
    { setUserId(e.target.value) }} + onFocus={() => setIdFocus(true)} + onBlur={() => setIdFocus(false)} />
    -
    +
    { setPasswordVisible(passwordVisible) }} + onFocus={() => setSecFocus(true)} + onBlur={() => setSecFocus(false)} />
    -
    +
    setSecFocus(true)} + onBlur={() => setSecFocus(false)} /> +
    diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 610db186..5ab18a40 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' -import { adsorptionRangeState, canvasState } from '@/store/canvasAtom' +import { adsorptionRangeState, canvasState, verticalHorizontalModeState } from '@/store/canvasAtom' import { useEvent } from '@/hooks/useEvent' import { useMouse } from '@/hooks/useMouse' import { useLine } from '@/hooks/useLine' @@ -21,6 +21,7 @@ import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useSwal } from '@/hooks/useSwal' import { booleanPointInPolygon } from '@turf/turf' import { usePopup } from '@/hooks/usePopup' +import { calculateAngle } from '@/util/qpolygon-utils' // 보조선 작성 export function useAuxiliaryDrawing(id) { @@ -60,6 +61,7 @@ export function useAuxiliaryDrawing(id) { const outerLineDiagonalLengthRef = useRef(0) const intersectionPoints = useRef([]) + const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) useEffect(() => { arrow1Ref.current = arrow1 @@ -100,6 +102,10 @@ export function useAuxiliaryDrawing(id) { } }, []) + useEffect(() => { + addCanvasMouseEventListener('mouse:down', mouseDown) + }, [verticalHorizontalMode]) + const clear = () => { addCanvasMouseEventListener('mouse:move', mouseMove) setLength1(0) @@ -453,11 +459,26 @@ export function useAuxiliaryDrawing(id) { const mouseDown = (e) => { canvas.renderAll() - const pointer = getIntersectMousePoint(e) + let pointer = getIntersectMousePoint(e) - mousePointerArr.current.push(pointer) - if (mousePointerArr.current.length === 2) { - drawLine(mousePointerArr.current[0], mousePointerArr.current[1]) + if (mousePointerArr.current.length === 1) { + const currentPoint = canvas.getPointer(e.e) + const prevPoint = mousePointerArr.current[0] + + const degreeByTwoPoints = calculateAngle(prevPoint, currentPoint) + + const degree = Math.round(degreeByTwoPoints / 45) * 45 + + if (verticalHorizontalMode) { + pointer = { + x: prevPoint.x + distanceBetweenPoints(currentPoint, prevPoint) * Math.cos((degree * Math.PI) / 180), + y: prevPoint.y + distanceBetweenPoints(currentPoint, prevPoint) * Math.sin((degree * Math.PI) / 180), + } + } + + mousePointerArr.current.push(pointer) + + drawLine() } else { const circle = new fabric.Circle({ radius: 3, @@ -471,6 +492,7 @@ export function useAuxiliaryDrawing(id) { }) canvas.add(circle) canvas.renderAll() + mousePointerArr.current.push(pointer) } } diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 3fbf1388..a976c0aa 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -401,7 +401,7 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, { - fontSize: arrow.parent.fontSize, + fontSize: fontSize, fill: 'black', originX: 'center', originY: 'center', From 065c17cc17076a672ba3fbe5023b8aa3658bea20 Mon Sep 17 00:00:00 2001 From: minsik Date: Wed, 23 Oct 2024 14:49:13 +0900 Subject: [PATCH 060/139] =?UTF-8?q?FloorPlan=20=ED=99=94=EB=A9=B4=EC=97=90?= =?UTF-8?q?=EC=84=9C=20footer=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/layout.js | 9 ++------- src/components/footer/Footer.jsx | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+), 7 deletions(-) create mode 100644 src/components/footer/Footer.jsx diff --git a/src/app/layout.js b/src/app/layout.js index 32803812..b41172c9 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -8,12 +8,12 @@ import Header from '@/components/header/Header' import QModal from '@/components/common/modal/QModal' import Dimmed from '@/components/ui/Dimmed' import SessionProvider from './SessionProvider' -import LocaleSwitch from '@/components/LocaleSwitch' import PopupManager from '@/components/common/popupManager/PopupManager' import './globals.css' import '../styles/style.scss' import '../styles/contents.scss' +import Footer from '@/components/footer/Footer' export const metadata = { title: 'Create Next App', @@ -69,12 +69,7 @@ export default async function RootLayout({ children }) { {children}
    -
    -
    - COPYRIGHT©2024 Hanwha Japan All Rights Reserved. - -
    -
    +
    )} diff --git a/src/components/footer/Footer.jsx b/src/components/footer/Footer.jsx new file mode 100644 index 00000000..c62fcf7a --- /dev/null +++ b/src/components/footer/Footer.jsx @@ -0,0 +1,18 @@ +'use client' +import LocaleSwitch from '@/components/LocaleSwitch' +import { usePathname } from 'next/navigation' + +export default function Footer() { + return ( + <> + {usePathname() !== '/floor-plan' && ( +
    +
    + COPYRIGHT©2024 Hanwha Japan All Rights Reserved. + +
    +
    + )} + + ) +} From 3d6c021c4b95c387e18e48426badf3771187acca Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Oct 2024 15:04:35 +0900 Subject: [PATCH 061/139] =?UTF-8?q?=EC=98=B5=EC=85=982=20->=20=EC=B9=98?= =?UTF-8?q?=EC=88=98=EC=84=A0=20=EC=84=A4=EC=A0=95=20(=ED=8F=B0=ED=8A=B8?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=A0=9C=EC=99=B8)=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/setting01/SecondOption.jsx | 13 ++++++----- .../dimensionLine/DimensionLineSetting.jsx | 15 +++++++++++++ src/hooks/common/useCommonUtils.js | 22 +++++++++++-------- src/hooks/surface/useSurfaceShapeBatch.js | 1 - src/store/commonUtilsAtom.js | 13 +++++++++++ 5 files changed, 49 insertions(+), 15 deletions(-) create mode 100644 src/store/commonUtilsAtom.js diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index 987f521c..40463296 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,4 +1,4 @@ -import { useRecoilState, useSetRecoilState } from 'recoil' +import { useRecoilState, useSetRecoilState, useRecoilValue } from 'recoil' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' @@ -10,6 +10,7 @@ import { usePopup } from '@/hooks/usePopup' import { v4 as uuidv4 } from 'uuid' import FontSetting from '@/components/common/font/FontSetting' import PlanSizeSetting from '@/components/floor-plan/modal/setting01/planSize/PlanSizeSetting' +import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' export default function SecondOption() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 @@ -28,6 +29,8 @@ export default function SecondOption() { const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) const [showPlanSizeSettingModal, setShowPlanSizeSettingModal] = useState(false) + const dimensionSettings = useRecoilValue(dimensionLineSettingsState) + // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('SecondOption useEffect 실행') @@ -139,11 +142,11 @@ export default function SecondOption() { let dimensionId = null let fontId = null let planSizeId = null - const [pixel, setPixel] = useState(1) - const [color, setColor] = useState('#FF0000') + const [pixel, setPixel] = useState(dimensionSettings.pixel) + const [color, setColor] = useState(dimensionSettings.color) const [font, setFont] = useState(null) - const [fontSize, setFontSize] = useState('#FF0000') - const [fontColor, setFontColor] = useState('#FF0000') + const [fontSize, setFontSize] = useState(dimensionSettings.fontSize) + const [fontColor, setFontColor] = useState(dimensionSettings.fontColor) useEffect(() => { dimensionId = uuidv4() diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index 569a47d8..aae246dc 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -6,6 +6,9 @@ import { useEffect, useState } from 'react' import FontSetting from '@/components/common/font/FontSetting' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' +import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' +import { useRecoilState } from 'recoil' + /* color: 치수선 색 fontColor: 글꼴 색 @@ -44,6 +47,7 @@ export default function DimensionLineSetting(props) { const [showColorPickerModal, setShowColorPickerModal] = useState(false) const [showFontModal, setShowFontModal] = useState(false) const { getMessage } = useMessage() + const [dimensionLineSettings, setDimensionLineSettings] = useRecoilState(dimensionLineSettingsState) useEffect(() => { console.log(2, isShow) @@ -59,6 +63,7 @@ export default function DimensionLineSetting(props) { closePopups([fontModalId, colorModalId]) } }, [isShow]) + const colorPickerProps = { isShow: showColorPickerModal, setIsShow: setShowColorPickerModal, @@ -168,6 +173,16 @@ export default function DimensionLineSetting(props) { setPixel(originPixel.value) setColor(originColor) setFont(originFont) + setDimensionLineSettings((prev) => { + return { + ...prev, + pixel: originPixel.value, + color: originColor, + font: originFont, + fontColor: originFontColor, + fontSize: originFontSize, + } + }) setIsShow(false) closePopups([fontModalId, colorModalId, id]) }} diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index b4fb4fc8..dd92253d 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -3,10 +3,12 @@ import { useRecoilValue } from 'recoil' import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' import { checkLineOrientation, getDistance } from '@/util/canvas-util' +import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() + const dimensionSettings = useRecoilValue(dimensionLineSettingsState) useEffect(() => { initEvent() @@ -17,7 +19,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } else if (commonFunctionState.distance) { commonDistanceMode() } - }, [commonFunctionState]) + }, [commonFunctionState, dimensionSettings]) const commonTextMode = () => { let textbox @@ -80,7 +82,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS angle: angle, width: 15, height: 15, - fill: 'black', + fill: dimensionSettings.color, selectable: false, }) } @@ -94,8 +96,8 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } const lineOptions = { - stroke: 'black', - strokeWidth: 2, + stroke: dimensionSettings.color, + strokeWidth: dimensionSettings.pixel, selectable: false, } @@ -185,12 +187,16 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS canvas.add(arrow1) canvas.add(arrow2) + console.log(dimensionSettings) + // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 distanceText = new fabric.Text(`${distance * 10} `, { left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), - fill: 'black', - fontSize: 16, + fill: dimensionSettings.fontColor, + fontSize: dimensionSettings.fontSize, + // fontFamily : dimensionSettings.font, //폰트 + // fontStyle : dimensionSettings.fontStyle, //폰트스타일 selectable: true, textAlign: 'center', originX: 'center', @@ -359,9 +365,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } return { - commonTextMode, - commonDimensionMode, - commonDistanceMode, commonFunctions, + dimensionSettings, } } diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index d6c799ac..2bfefb98 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -128,7 +128,6 @@ export function useSurfaceShapeBatch() { setSurfaceShapePattern(obj, roofDisplay.column) closePopup(id) drawDirectionArrow(obj) - setShowPlacementSurfaceSettingModal(true) }) } } diff --git a/src/store/commonUtilsAtom.js b/src/store/commonUtilsAtom.js new file mode 100644 index 00000000..3fe8dbb7 --- /dev/null +++ b/src/store/commonUtilsAtom.js @@ -0,0 +1,13 @@ +import { atom } from 'recoil' + +export const dimensionLineSettingsState = atom({ + key: 'dimensionLineSettingsState', + default: { + pixel: 1, + color: '#000000', + font: 'Arial', + fontColor: '#000000', + fontSize: 15, + fontStyle: 'normal', + }, +}) From c71468851d5509b855fe71626333953b11bc8c8c Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Oct 2024 15:30:30 +0900 Subject: [PATCH 062/139] =?UTF-8?q?=EC=98=B5=EC=85=982=20-=20=EC=BA=94?= =?UTF-8?q?=EB=B2=84=EC=8A=A4=20=EC=82=AC=EC=9D=B4=EC=A6=88=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/setting01/planSize/PlanSizeSetting.jsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx b/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx index 8802127e..18a92bf9 100644 --- a/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx +++ b/src/components/floor-plan/modal/setting01/planSize/PlanSizeSetting.jsx @@ -1,7 +1,9 @@ -import WithDraggable from '@/components/common/draggable/WithDraggable' -import { usePopup } from '@/hooks/usePopup' -import { useMessage } from '@/hooks/useMessage' import { useState } from 'react' +import { useRecoilValue } from 'recoil' +import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { canvasState } from '@/store/canvasAtom' export default function PlanSizeSetting(props) { const { horizon, setHorizon, vertical, setVertical, id, pos = { x: 985, y: 180 }, setIsShow } = props @@ -9,6 +11,7 @@ export default function PlanSizeSetting(props) { const { getMessage } = useMessage() const [originHorizon, setOriginHorizon] = useState(horizon) const [originVertical, setOriginVertical] = useState(vertical) + const canvas = useRecoilValue(canvasState) return ( @@ -55,6 +58,9 @@ export default function PlanSizeSetting(props) { setVertical(originVertical) setIsShow(false) closePopup(id) + canvas.setWidth(originHorizon) + canvas.setHeight(originVertical) + canvas.renderAll() }} > {getMessage('modal.common.save')} From 914bf93197f771287cf1cd95cfc66674015faf74 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Wed, 23 Oct 2024 16:20:25 +0900 Subject: [PATCH 063/139] =?UTF-8?q?refactor:=20canvas=20plan=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=20=EC=8B=9C=20=EC=84=B1=EA=B3=B5=EB=A9=94=EC=84=B8?= =?UTF-8?q?=EC=A7=80=20=ED=91=9C=EC=B6=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/usePlan.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 166ff738..87d43021 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -201,7 +201,6 @@ export function usePlan() { ), ) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) - swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) @@ -223,7 +222,6 @@ export function usePlan() { ) setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) - swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) From 0de81807bd41c40df83dbd1438797148b6c97f7f Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 23 Oct 2024 17:01:06 +0900 Subject: [PATCH 064/139] =?UTF-8?q?=ED=8F=B0=ED=8A=B8=20=EC=85=8B=ED=8C=85?= =?UTF-8?q?=20=EB=B0=8F=20uuid=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 49 ++++++++++++------- src/components/fabric/QLine.js | 9 ++-- src/components/fabric/QPolygon.js | 18 ++----- .../modal/setting01/SecondOption.jsx | 30 ++++++++++-- .../dimensionLine/DimensionLineSetting.jsx | 1 + src/hooks/roofcover/useAuxiliaryDrawing.js | 3 +- src/hooks/useCanvas.js | 1 + src/hooks/usePolygon.js | 5 +- src/store/fontAtom.js | 29 +++++++++++ 9 files changed, 101 insertions(+), 44 deletions(-) create mode 100644 src/store/fontAtom.js diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index d738d016..413e6cc0 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,8 +1,10 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' +import { useRecoilState, useRecoilValue } from 'recoil' +import { fontSelector, globalFontAtom } from '@/store/fontAtom' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, @@ -43,19 +45,38 @@ const fontColors = [ { name: '남색', value: 'darkblue' }, ] export default function FontSetting(props) { - const { id, setIsShow, font, setFont, fontSize, setFontSize, pos = { x: 455, y: 180 } } = props + const { id, setIsShow, pos = { x: 455, y: 180 }, type } = props const { getMessage } = useMessage() const { closePopup } = usePopup() - const [originFont, setOriginFont] = useState(font) - const [originFontSize, setOriginFontSize] = useState(fontSize) - const [selectedFont, setSelectedFont] = useState(font ? font : fonts[0]) - const [selectedFontSize, setSelectedFontSize] = useState(fontSize ? fontSize : fontSizes[0]) - const [selectedFontColor, setSelectedFontColor] = useState(null) + const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom) + const currentFont = useRecoilValue(fontSelector(type)) + + const [selectedFont, setSelectedFont] = useState(currentFont.fontFamily) + const [selectedFontWeight, setSelectedFontWeight] = useState(currentFont.fontWeight) + const [selectedFontSize, setSelectedFontSize] = useState(currentFont.fontSize) + const [selectedFontColor, setSelectedFontColor] = useState(currentFont.fontColor) + + const handleSaveBtn = () => { + setGlobalFont((prev) => { + return { + ...prev, + [type]: { + fontFamily: selectedFont, + fontSize: selectedFontSize, + fontColor: selectedFontColor, + fontWeight: selectedFontWeight, + }, + } + }) + setIsShow(false) + closePopup(id) + } + return (
    -

    {getMessage('modal.font')}

    +

    {getMessage('modal.font')}

    diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 7700ae42..7b4e2196 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -57,11 +57,10 @@ export const QLine = fabric.util.createClass(fabric.Line, { }) this.on('removed', () => { - const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id) - if (thisText) { - this.canvas.remove(thisText) - } - this.text = null + const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id) + children.forEach((child) => { + this.canvas.remove(child) + }) }) }, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index d982a49a..76c8dd6c 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -132,22 +132,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) this.on('removed', () => { - const thisText = this.canvas.getObjects().filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id) - thisText.forEach((text) => { - this.canvas.remove(text) + const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id) + children.forEach((child) => { + this.canvas.remove(child) }) - this.texts = null - - if (this.arrow) { - this.canvas.remove(this.arrow) - this.canvas - .getObjects() - .filter((obj) => obj.name === 'directionText' && obj.parent === this.arrow) - .forEach((text) => { - this.canvas.remove(text) - }) - this.arrow = null - } }) // polygon.fillCell({ width: 50, height: 30, padding: 10 }) diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index 40463296..799892d8 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -203,12 +203,34 @@ export default function SecondOption() { } break - case 'font1': //문자 글꼴변경 - case 'font2': //흐름 방향 글꼴 변경 - case 'font3': //치수 글꼴변경 + case 'font1': { + //문자 글꼴변경 + setShowFontSettingModal(true) + fontProps.type = 'commonText' + fontProps.id = fontId + 1 + addPopup(fontId + 1, 2, ) + break + } + case 'font2': { + //흐름 방향 글꼴 변경 + setShowFontSettingModal(true) + fontProps.type = 'flowText' + fontProps.id = fontId + 2 + addPopup(fontId + 2, 2, ) + break + } + case 'font3': { + //치수 글꼴변경 + setShowFontSettingModal(true) + fontProps.type = 'lengthText' + fontProps.id = fontId + 3 + addPopup(fontId + 3, 2, ) + break + } case 'font4': //회로번호 글꼴변경 setShowFontSettingModal(true) - + fontProps.type = 'circuitNumberText' + fontProps.id = fontId addPopup(fontId, 2, ) break case 'planSize': diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index aae246dc..2afbd184 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -92,6 +92,7 @@ export default function DimensionLineSetting(props) { x: 455, y: 180, }, + type: 'dimensionLineText', } const popupHandle = (type) => { switch (type) { diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 5ab18a40..39294260 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -241,7 +241,8 @@ export function useAuxiliaryDrawing(id) { const x = lastPoint.x + length * Math.cos(radian) const y = lastPoint.y - length * Math.sin(radian) - return [...prev, { x, y }] + mousePointerArr.current.push({ x, y }) + drawLine() } } }, diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index a33c0de2..d8bf840f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -92,6 +92,7 @@ export function useCanvas(id) { // settings for all canvas in the app fabric.Object.prototype.transparentCorners = false fabric.Object.prototype.id = uuidv4() + fabric.Object.prototype.uuid = uuidv4() fabric.Object.prototype.selectable = true fabric.Object.prototype.lockMovementX = true fabric.Object.prototype.lockMovementY = true diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index a976c0aa..bf6ac7e6 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -190,7 +190,7 @@ export const usePolygon = () => { break } - arrow = new fabric.Polygon(points, { + arrow = new QPolygon(points, { selectable: false, name: 'arrow', fill: 'transparent', @@ -200,8 +200,10 @@ export const usePolygon = () => { stickeyPoint: stickeyPoint, visible: isFlowDisplay, pitch: polygon.pitch, + parentId: polygon.id, }) + arrow.setViewLengthText(false) polygon.arrow = arrow polygon.canvas.add(arrow) polygon.canvas.renderAll() @@ -410,6 +412,7 @@ export const usePolygon = () => { left: arrow.stickeyPoint.x, top: arrow.stickeyPoint.y, parent: arrow, + parentId: arrow.id, visible: isFlowDisplay, }) canvas.add(text) diff --git a/src/store/fontAtom.js b/src/store/fontAtom.js new file mode 100644 index 00000000..1bf0df80 --- /dev/null +++ b/src/store/fontAtom.js @@ -0,0 +1,29 @@ +import { atom, selectorFamily } from 'recoil' + +const defaultFont = { + fontFamily: { name: 'MS PGothic', value: 'MS PGothic' }, + fontWeight: { name: '보통', value: 'normal' }, + fontSize: { name: '16', value: '16' }, + fontColor: { name: '검정색', value: 'black' }, +} + +export const globalFontAtom = atom({ + key: 'fontAtom', + default: { + commonText: defaultFont, + dimensionLineText: defaultFont, + flowText: defaultFont, + lengthText: defaultFont, + circuitNumberText: defaultFont, + }, +}) + +export const fontSelector = selectorFamily({ + key: 'fontSelector', + get: + (type) => + ({ get }) => { + const fontAtom = get(globalFontAtom) + return fontAtom[type] + }, +}) From 365722f09629c26eadbd9c2f59619b698cce9275 Mon Sep 17 00:00:00 2001 From: changkyu choi Date: Wed, 23 Oct 2024 17:07:20 +0900 Subject: [PATCH 065/139] =?UTF-8?q?Canvas=20=EC=84=A4=EC=A0=95(=EB=94=94?= =?UTF-8?q?=EC=8A=A4=ED=94=8C=EB=A0=88=EC=9D=B4)=20=EC=9D=BC=EB=B6=80=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/option/useFirstOption.js | 67 +++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 6 deletions(-) diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js index 4010b69e..5a4605e9 100644 --- a/src/hooks/option/useFirstOption.js +++ b/src/hooks/option/useFirstOption.js @@ -11,12 +11,67 @@ export function useFirstOption() { useEffect(() => { const option1 = settingModalFirstOptions.option1 - canvas - .getObjects() - .filter((obj) => obj.name === '') - .forEach((obj) => { - obj.set({ visible: !obj.visible }) - }) + // 'allocDisplay' 할당 표시 + // 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine' + // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid' + // 'lineDisplay' 지붕선 표시 'roof', 'roofBase' + // 'wordDisplay' 문자 표시 + // 'circuitNumDisplay' 회로번호 표시 + // 'flowDisplay' 흐름방향 표시 'arrow' + // 'trestleDisplay' 가대 표시 + // 'totalDisplay' 집계표 표시 + + let optionName //옵션명 + let optionSelected //옵션상태 + + for (let i = 0; i < option1.length; i++) { + switch (option1[i].column) { + case 'allocDisplay': //할당 표시 + optionName = ['1'] + break + case 'outlineDisplay': //외벽선 표시 + optionName = ['outerLine', 'wallLine'] + break + case 'gridDisplay': //그리드 표시 + optionName = ['lindGrid', 'dotGrid'] + break + case 'lineDisplay': //지붕선 표시 + optionName = ['roof', 'roofBase'] + break + case 'wordDisplay': //문자 표시 + optionName = ['6'] + break + case 'circuitNumDisplay': //회로번호 표시 + optionName = ['7'] + break + case 'flowDisplay': //흐름방향 표시 + optionName = ['arrow'] + break + case 'trestleDisplay': //가대 표시 + optionName = ['8'] + break + case 'totalDisplay': //집계표 표시 + optionName = ['9'] + break + } + // 표시 선택 상태(true/false) + optionSelected = option1[i].selected + + canvas + .getObjects() + .filter((obj) => optionName.includes(obj.name)) + //.filter((obj) => obj.name === optionName) + .forEach((obj) => { + obj.set({ visible: optionSelected }) + //obj.set({ visible: !obj.visible }) + }) + + // console.log( + // 'optionName', + // optionName, + // canvas.getObjects().filter((obj) => optionName.includes(obj.name)), + // ) + } }, [settingModalFirstOptions]) return { settingModalFirstOptions, setSettingModalFirstOptions } From a95b7ebe4cce21643ed17a56e0ea9ff838ebc7c2 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 23 Oct 2024 17:08:50 +0900 Subject: [PATCH 066/139] =?UTF-8?q?object=20=EC=88=98=EC=A0=95=20=EC=8B=9C?= =?UTF-8?q?=20uuid=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useCanvasEvent.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 4f041e79..bf878c7b 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,5 +1,6 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' +import { v4 as uuidv4 } from 'uuid' import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' @@ -32,7 +33,9 @@ export function useCanvasEvent() { const objectEvent = { onChange: (e) => { const target = e.target + if (target) { + target.uuid = uuidv4() // settleDown(target) } }, From 045a9b2f39c50e565873447ace9ea8eba195a53e Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Wed, 23 Oct 2024 17:17:43 +0900 Subject: [PATCH 067/139] =?UTF-8?q?refactor:=20canvas=20plan=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD=20=EC=97=AC=EB=B6=80=20=ED=99=95=EC=9D=B8=EC=9D=84=20?= =?UTF-8?q?id->uuid=EB=A1=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/usePlan.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 87d43021..26d26339 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -62,6 +62,7 @@ export function usePlan() { 'stickeyPoint', 'text', 'pitch', + 'uuid', ]) const str = JSON.stringify(objs) @@ -108,16 +109,16 @@ export function usePlan() { return JSON.parse(canvasStatus).objects.length > 0 } else { // 저장된 캔버스 - // 각각 object들의 id 목록을 추출하여 비교 - const canvasObjsIds = getObjectIds(JSON.parse(canvasStatus).objects) - const dbObjsIds = getObjectIds(JSON.parse(initPlanData.canvasStatus).objects) - return canvasObjsIds.length !== dbObjsIds.length || !canvasObjsIds.every((id, index) => id === dbObjsIds[index]) + // 각각 object들의 uuid 목록을 추출하여 비교 + const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects) + const dbObjsUuids = getObjectUuids(JSON.parse(initPlanData.canvasStatus).objects) + return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((id, index) => id === dbObjsUuids[index]) } } - const getObjectIds = (objects) => { + const getObjectUuids = (objects) => { return objects - .filter((obj) => obj.hasOwnProperty('id')) - .map((obj) => obj.id) + .filter((obj) => obj.hasOwnProperty('uuid')) + .map((obj) => obj.uuid) .sort() } /** From 9d328413407183cd2814096042fef6de5af115b7 Mon Sep 17 00:00:00 2001 From: basssy Date: Wed, 23 Oct 2024 17:52:25 +0900 Subject: [PATCH 068/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=99=94=EB=A9=B4=20=ED=94=8C=EB=9E=9C=EB=AA=A9=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/management/stuff/detail/page.jsx | 2 + src/app/management/stuff/page.jsx | 2 +- src/components/management/Stuff.jsx | 1 - src/components/management/StuffDetail.jsx | 473 +++++++++++++++++-- src/components/management/StuffPlanQGrid.jsx | 51 ++ src/locales/ja.json | 12 + src/locales/ko.json | 12 + 7 files changed, 499 insertions(+), 54 deletions(-) create mode 100644 src/components/management/StuffPlanQGrid.jsx diff --git a/src/app/management/stuff/detail/page.jsx b/src/app/management/stuff/detail/page.jsx index 8c7dd731..7c5b0b0e 100644 --- a/src/app/management/stuff/detail/page.jsx +++ b/src/app/management/stuff/detail/page.jsx @@ -3,6 +3,8 @@ import '@/styles/contents.scss' import StuffSubHeader from '@/components/management/StuffSubHeader' import StuffHeader from '@/components/management/StuffHeader' import StuffDetail from '@/components/management/StuffDetail' +import '@/styles/contents.scss' +import '@/styles/grid.scss' export default function ManagementStuffDetailPage() { return ( <> diff --git a/src/app/management/stuff/page.jsx b/src/app/management/stuff/page.jsx index eb852712..414f377b 100644 --- a/src/app/management/stuff/page.jsx +++ b/src/app/management/stuff/page.jsx @@ -1,7 +1,7 @@ import StuffSearchCondition from '@/components/management/StuffSearchCondition' import Stuff from '@/components/management/Stuff' import StuffSubHeader from '@/components/management/StuffSubHeader' -import '@/styles/contents.scss' +import '@/styles/grid.scss' export default async function ManagementStuffPage() { return ( <> diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 07119205..b5297420 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -16,7 +16,6 @@ import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import QPagination from '../common/pagination/QPagination' -import '@/styles/grid.scss' import { sessionStore } from '@/store/commonAtom' export default function Stuff() { diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index fd01fc41..5d49bc06 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -16,6 +16,7 @@ import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' import WindSelectPop from './popup/WindSelectPop' import { useCommonCode } from '@/hooks/common/useCommonCode' +import StuffPlanQGrid from './StuffPlanQGrid' export default function StuffDetail() { //공통코드 @@ -31,12 +32,12 @@ export default function StuffDetail() { const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) const ref = useRef() - const { get, del, promisePost, promisePut } = useAxios(globalLocaleState) + const { get, promiseGet, del, promisePost, promisePut } = useAxios(globalLocaleState) //form const formInitValue = { // 물건번호 T...(임시) R...(진짜) planReqNo: '', //설계의뢰No - dispCompanyName: '', //담당자 + receiveUser: '', //담당자 objectStatusId: '0', //물건구분(신축:0 기축 : 1) objectName: '', //물건명 objectNameOmit: '', //경칭선택 @@ -91,6 +92,173 @@ export default function StuffDetail() { const [editMode, setEditMode] = useState('NEW') const [detailData, setDetailData] = useState({}) + const [planGridProps, setPlanGridProps] = useState({ + planGridData: [], + isPageable: false, + planGridColumns: [ + { + field: 'planNo', + headerName: getMessage('stuff.detail.planGridHeader.planNo'), + width: 100, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'orderFlg', + headerName: getMessage('stuff.detail.planGridHeader.orderFlg'), + width: 80, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + //1일때만 동그라미 + let orderFlg + orderFlg = params.value === '1' ? 'O' : 'X' + return orderFlg + }, + }, + { + field: 'moduleModel', + headerName: getMessage('stuff.detail.planGridHeader.moduleModel'), + flex: 1, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'capacity', + headerName: getMessage('stuff.detail.planGridHeader.capacity'), + width: 120, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'roofMaterialIdMulti', + headerName: getMessage('stuff.detail.planGridHeader.roofMaterialIdMulti'), + width: 140, + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
    + + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'constructSpecification', + headerName: getMessage('stuff.detail.planGridHeader.constructSpecification'), + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
    + + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'supportMethodIdMulti', + headerName: getMessage('stuff.detail.planGridHeader.supportMethodIdMulti'), + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
    + + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'pcTypeNo', + headerName: getMessage('stuff.detail.planGridHeader.pcTypeNo'), + flex: 1, + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
    + + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'management', + headerName: getMessage('stuff.detail.planGridHeader.management'), + width: 200, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: () => { + return ( +
    + + +
    + ) + }, + }, + ], + }) + useEffect(() => { // console.log('objectNo::', objectNo) @@ -101,9 +269,22 @@ export default function StuffDetail() { //진짜 setIsFormValid(true) } - get({ url: `/api/object/${objectNo}/detail` }).then((res) => { - if (res != null) { - setDetailData(res) + promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { + if (res.status === 200) { + if (res.data != null) { + setDetailData(res.data) + } else { + setDetailData({}) + } + if (isNotEmptyArray(res.data.planList)) { + // console.log('플랜RES::::::::', res.data.planList) + setPlanGridProps({ ...planGridProps, planGridData: res.data.planList }) + } else { + setPlanGridProps({ ...planGridProps, planGridData: [] }) + } + } else { + setDetailData({}) + setPlanGridProps({ ...planGridProps, planGridData: [] }) } }) } else { @@ -187,7 +368,7 @@ export default function StuffDetail() { //설계의뢰No. form.setValue('planReqNo', detailData.planReqNo) //담당자 - form.setValue('dispCompanyName', detailData.dispCompanyName) + form.setValue('receiveUser', detailData.receiveUser) //물건구분objectStatusId setSelectObjectStatusId(detailData.objectStatusId) @@ -197,7 +378,6 @@ export default function StuffDetail() { form.setValue('objectName', detailData.objectName) //경칭코드 - setSelHonorificCode(detailData.objectNameOmit) form.setValue('objectNameOmit', detailData.objectNameOmit) @@ -217,7 +397,32 @@ export default function StuffDetail() { // form.setValue('otherSaleStoreId', sessionState?.storeId) // form.setValue('otherSaleStoreLevel', sessionState?.storeLvl) + //우편번호 form.setValue('zipNo', detailData.zipNo) + + //도도부현 / 주소 + setPrefValue(detailData.prefId) + form.setValue('prefId', detailData.prefId) + //prefName ??? + form.setValue('address', detailData.address) + + //수직적설량 + form.setValue('verticalSnowCover', detailData.verticalSnowCover) + //한랭지대책시행 coldRegionFlg 1이면 true + form.setValue('coldRegionFlg', detailData.coldRegionFlg === '1' ? true : false) + + //면조도구분surfaceType + // form.setValue('surfaceType', 'Ⅱ') + // form.setValue('surfaceType', 'III・IV') + form.setValue('surfaceType', detailData.surfaceType) + //염해지역용아이템사용 saltAreaFlg 1이면 true + form.setValue('saltAreaFlg', detailData.saltAreaFlg === '1' ? true : false) + //설치높이 + form.setValue('installHeight', detailData.installHeight) + //계약조건 + form.setValue('conType', detailData.conType) + //메모 + form.setValue('remarks', detailData.remarks) }) } }, [detailData, sessionState]) @@ -414,8 +619,8 @@ export default function StuffDetail() { form.setValue('standardWindSpeedId', info.windSpeed) } - //dispCompanyName: '', //담당자 - const _dispCompanyName = watch('dispCompanyName') + //receiveUser: '', //담당자 + const _receiveUser = watch('receiveUser') //objectName: '', //물건명 const _objectName = watch('objectName') // objectNameOmit: '', //경칭선택 @@ -441,8 +646,8 @@ export default function StuffDetail() { if (editMode === 'NEW') { const formData = form.getValues() let errors = {} - if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { - errors.dispCompanyName = true + if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { + errors.receiveUser = true } if (!formData.objectName || formData.objectName.trim().length === 0) { errors.objectName = true @@ -483,8 +688,8 @@ export default function StuffDetail() { console.log('상세일때 폼체크') const formData = form.getValues() let errors = {} - if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { - errors.dispCompanyName = true + if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { + errors.receiveUser = true } if (!formData.objectName || formData.objectName.trim().length === 0) { errors.objectName = true @@ -524,7 +729,7 @@ export default function StuffDetail() { setIsFormValid(Object.keys(errors).length === 0 ? true : false) } }, [ - _dispCompanyName, + _receiveUser, _objectName, _objectNameOmit, _saleStoreId, @@ -592,14 +797,14 @@ export default function StuffDetail() { prefName: formData.prefName, address: formData.address, areaId: formData.areaId, - receiveUser: formData.dispCompanyName, + receiveUser: formData.receiveUser, installHeight: formData.installHeight, standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, - coldRegionFlg: formData.coldRegionFlg, - saltAreaFlg: formData.saltAreaFlg, + coldRegionFlg: formData.coldRegionFlg === true ? '1' : '0', + saltAreaFlg: formData.saltAreaFlg === true ? '1' : '0', tempFlg: '0', workNo: null, workName: null, @@ -623,13 +828,6 @@ export default function StuffDetail() { } } - //필수값 안넣었을때 임시저장 form required사용시 - // const onInvalid = (errors) => { - // console.log('22222222222222222222222') - // const formData = form.getValues() - // console.log('임시저장formData::::', formData) - // } - // 임시저장 const onTempSave = async () => { const formData = form.getValues() @@ -646,14 +844,14 @@ export default function StuffDetail() { prefName: formData.prefName, address: formData.address, areaId: formData.areaId, - receiveUser: formData.dispCompanyName, + receiveUser: formData.receiveUser, installHeight: formData.installHeight, standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, - coldRegionFlg: formData.coldRegionFlg, - saltAreaFlg: formData.saltAreaFlg, + coldRegionFlg: formData.coldRegionFlg === true ? '1' : '0', + saltAreaFlg: formData.saltAreaFlg === true ? '1' : '0', tempFlg: '1', workNo: null, workName: null, @@ -685,7 +883,7 @@ export default function StuffDetail() { } else { if (confirm(getMessage('common.message.data.delete'))) { del({ url: `/api/object/${objectNo}` }).then((res) => { - console.log('삭제결과:::::::', res) + // console.log('삭제결과:::::::', res) router.push('/management/stuff') }) } @@ -743,7 +941,7 @@ export default function StuffDetail() {
    - +
    @@ -881,7 +1079,7 @@ export default function StuffDetail() { @@ -968,7 +1166,6 @@ export default function StuffDetail() {
    - {/* 기준풍속sel시작 */}
    - {/* 기준풍속sel끝 */} {getMessage('stuff.detail.windSpeedSpan')} -
    @@ -1007,7 +1203,7 @@ export default function StuffDetail() { type="text" className="input-light" onKeyUp={handleKeyUp} - value={form.watch('verticalSnowCover')} + value={form.watch('verticalSnowCover') || ''} {...register('verticalSnowCover')} />
    @@ -1037,7 +1233,9 @@ export default function StuffDetail() {
    -
    +
    + {getMessage('stuff.detail.tooltip.surfaceType')} +
    @@ -1052,7 +1250,7 @@ export default function StuffDetail() { type="text" className="input-light" onKeyUp={handleKeyUp} - value={form.watch('installHeight')} + value={form.watch('installHeight') || ''} {...register('installHeight')} />
    @@ -1151,12 +1349,7 @@ export default function StuffDetail() {
    - +
    @@ -1224,7 +1417,9 @@ export default function StuffDetail() { {getMessage('stuff.detail.saleStoreId')} *
    -
    +
    + {getMessage('stuff.detail.tooltip.saleStoreId')} +
    @@ -1250,7 +1445,7 @@ export default function StuffDetail() { @@ -1292,7 +1487,7 @@ export default function StuffDetail() { @@ -1317,29 +1512,203 @@ export default function StuffDetail() { {/* 도도부현 /주소 시작*/} + + + {getMessage('stuff.detail.prefId')} + * + + +
    +
    + {prefCodeList?.length > 0 && ( + +
    +
    + + {/* 도도부현 /주소 끝 */} {/* 발전량시뮬레이션지역시작 */} + + + {getMessage('stuff.detail.areaId')} * + + +
    + x.clCodeNm} + getOptionValue={(x) => x.clCode} + isClearable={true} + isSearchable={false} + value={windSpeedList.filter(function (option) { + return option.clCode === watch('standardWindSpeedId') + })} + > +
    + {getMessage('stuff.detail.windSpeedSpan')} + +
    + + {/* 기준풍속끝 */} {/* 수직적설량시작 */} + + + {getMessage('stuff.detail.verticalSnowCover')} * + + +
    +
    + +
    + cm +
    + + +
    +
    + + {/* 수직적설량끝 */} {/* 면조도구분시작 */} + + + {getMessage('stuff.detail.surfaceType')} * + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + {getMessage('stuff.detail.tooltip.surfaceType')} +
    +
    + + {/* 면조도구분끝 */} - {/* 설치높이싲가 */} + {/* 설치높이시작 */} + + + {getMessage('stuff.detail.installHeight')} * + + +
    +
    + +
    + m +
    + + {/* 설치높이끝 */} {/* 계약조건시작 */} + + {getMessage('stuff.detail.conType')} + +
    +
    + + +
    +
    + + +
    +
    + + {/* 계약조건끝 */} {/* 메모시작 */} - {/* 메모끝 */} - + {getMessage('stuff.detail.remarks')} + +
    + +
    + + {/* 메모끝 */}
    - {objectNo.substring(0, 1) === 'R' ? ( <> {/* 진짜R 플랜시작 */} @@ -1349,7 +1718,7 @@ export default function StuffDetail() {
    • {getMessage('stuff.detail.planList.cnt')} - 플랜갯수찍어주기 + {detailData.planList?.length}
    @@ -1367,8 +1736,8 @@ export default function StuffDetail() {
    - 그리드영역 -
    페이징영역
    + + {/*
    페이징영역
    */}
    {/* 진짜R 플랜끝 */} diff --git a/src/components/management/StuffPlanQGrid.jsx b/src/components/management/StuffPlanQGrid.jsx new file mode 100644 index 00000000..b4108342 --- /dev/null +++ b/src/components/management/StuffPlanQGrid.jsx @@ -0,0 +1,51 @@ +import { useState, useMemo, useCallback, useEffect } from 'react' +import { AgGridReact } from 'ag-grid-react' +import 'ag-grid-community/styles/ag-grid.css' +import 'ag-grid-community/styles/ag-theme-quartz.css' +export default function StuffPlanQGrid(props) { + const { planGridData, planGridColumns, isPageable = true } = props + + const [rowData, setRowData] = useState(null) + const [gridApi, setGridApi] = useState(null) + const [colDefs, setColDefs] = useState(planGridColumns) + + const defaultColDef = useMemo(() => { + return { + flex: 1, + minWidth: 100, + sortable: false, + suppressMovable: false, + resizable: false, + suppressSizeToFit: false, + } + }, []) + + const rowBuffer = 100 + + useEffect(() => { + planGridData ? setRowData(planGridData) : '' + }, [planGridData]) + + const onGridReady = useCallback( + (params) => { + setGridApi(params.api) + planGridData ? setRowData(planGridData) : '' + }, + [planGridData], + ) + + return ( +
    + +
    + ) +} diff --git a/src/locales/ja.json b/src/locales/ja.json index 359d313e..521f4ac6 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -502,6 +502,7 @@ "stuff.detail.conType1": "全量", "stuff.detail.remarks": "メモ", "stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください", + "stuff.detail.tooltip.surfaceType": "塩害地域の定義は各メーカーの設置マニュアルをご確認ください", "stuff.detail.tempSave.message1": "一時保存されました。商品番号を取得するには、必須項目をすべて入力してください。", "stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?", "stuff.detail.delete.message1": "仕様が確定したものは削除できません。", @@ -566,6 +567,17 @@ "stuff.windSelectPopup.search.address1": "県", "stuff.windSelectPopup.btn1": "閉じる", "stuff.windSelectPopup.btn2": "選択", + "stuff.detail.planGridHeader.planNo": "プラン番号", + "stuff.detail.planGridHeader.orderFlg": "発注可", + "stuff.detail.planGridHeader.moduleModel": "モジュール", + "stuff.detail.planGridHeader.capacity": "システム容量", + "stuff.detail.planGridHeader.roofMaterialIdMulti": "屋根材", + "stuff.detail.planGridHeader.constructSpecification": "施工方法", + "stuff.detail.planGridHeader.supportMethodIdMulti": "架台", + "stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー", + "stuff.detail.planGridHeader.management": "管理", + "stuff.detail.planGrid.btn1": "見積書の照会", + "stuff.detail.planGrid.btn2": "Excel", "length": "長さ", "height": "高さ", "output": "出力", diff --git a/src/locales/ko.json b/src/locales/ko.json index fe228f22..693d94b4 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -507,6 +507,7 @@ "stuff.detail.conType1": "전량", "stuff.detail.remarks": "메모", "stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요", + "stuff.detail.tooltip.surfaceType": "염해지역 정의는 각 메이커의 설치 메뉴얼을 확인해주십시오", "stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.", "stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", "stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.", @@ -571,6 +572,17 @@ "stuff.windSelectPopup.search.address1": "현", "stuff.windSelectPopup.btn1": "닫기", "stuff.windSelectPopup.btn2": "선택", + "stuff.detail.planGridHeader.planNo": "플랜번호", + "stuff.detail.planGridHeader.orderFlg": "발주여부", + "stuff.detail.planGridHeader.moduleModel": "모듈", + "stuff.detail.planGridHeader.capacity": "시스템용량", + "stuff.detail.planGridHeader.roofMaterialIdMulti": "지붕재", + "stuff.detail.planGridHeader.constructSpecification": "시공방법", + "stuff.detail.planGridHeader.supportMethodIdMulti": "가대", + "stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너", + "stuff.detail.planGridHeader.management": "관리", + "stuff.detail.planGrid.btn1": "견적서 조회", + "stuff.detail.planGrid.btn2": "Excel", "length": "길이", "height": "높이", "output": "출력", From 7dded33338b1a73733efc51619ce71c149b1af5b Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 23 Oct 2024 18:09:31 +0900 Subject: [PATCH 069/139] =?UTF-8?q?useFont=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/font/FontSetting.jsx | 1 + .../modal/setting01/SecondOption.jsx | 3 +- src/hooks/common/useFont.js | 51 +++++++++++++++++++ src/hooks/useCanvas.js | 2 + src/hooks/usePolygon.js | 10 ++-- 5 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 src/hooks/common/useFont.js diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index 413e6cc0..cbb2de00 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -5,6 +5,7 @@ import { useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilState, useRecoilValue } from 'recoil' import { fontSelector, globalFontAtom } from '@/store/fontAtom' +import { useFont } from '@/hooks/common/useFont' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index 799892d8..ceccce5e 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,4 +1,4 @@ -import { useRecoilState, useSetRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' @@ -28,7 +28,6 @@ export default function SecondOption() { const [showFontSettingModal, setShowFontSettingModal] = useState(false) const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) const [showPlanSizeSettingModal, setShowPlanSizeSettingModal] = useState(false) - const dimensionSettings = useRecoilValue(dimensionLineSettingsState) // 데이터를 최초 한 번만 조회 diff --git a/src/hooks/common/useFont.js b/src/hooks/common/useFont.js new file mode 100644 index 00000000..383997a0 --- /dev/null +++ b/src/hooks/common/useFont.js @@ -0,0 +1,51 @@ +import { useRecoilValue } from 'recoil' +import { canvasState } from '@/store/canvasAtom' +import { fontSelector, globalFontAtom } from '@/store/fontAtom' +import { useEffect } from 'react' + +export function useFont() { + const canvas = useRecoilValue(canvasState) + const commonText = useRecoilValue(fontSelector('commonText')) + const dimensionLineText = useRecoilValue(fontSelector('dimensionLineText')) + const flowText = useRecoilValue(fontSelector('flowText')) + const lengthText = useRecoilValue(fontSelector('lengthText')) + const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText')) + + useEffect(() => {}, [commonText]) + + useEffect(() => {}, [dimensionLineText]) + + useEffect(() => { + if (canvas) { + const textObjs = canvas.getObjects().filter((obj) => obj.name === 'flowText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: flowText.fontFamily.value, + fontWeight: flowText.fontWeight.value, + fontSize: flowText.fontSize.value, + fill: flowText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [flowText]) + + useEffect(() => { + if (canvas) { + const textObjs = canvas.getObjects().filter((obj) => obj.name === 'lengthText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: lengthText.fontFamily.value, + fontWeight: lengthText.fontWeight.value, + fontSize: lengthText.fontSize.value, + fill: lengthText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [lengthText]) + + useEffect(() => {}, [circuitNumberText]) + + return {} +} diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index d8bf840f..17f00eea 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -13,6 +13,7 @@ import { writeImage } from '@/lib/canvas' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { useAxios } from '@/hooks/useAxios' import { v4 as uuidv4 } from 'uuid' +import { useFont } from '@/hooks/common/useFont' export function useCanvas(id) { const [canvas, setCanvas] = useRecoilState(canvasState) @@ -23,6 +24,7 @@ export function useCanvas(id) { const [fontSize] = useRecoilState(fontSizeState) const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() const { post } = useAxios() + const {} = useFont() /** * 처음 셋팅 diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index bf6ac7e6..71e49408 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -114,7 +114,7 @@ export const usePolygon = () => { polygon.canvas .getObjects() - .filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow) + .filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow) .forEach((obj) => polygon.canvas.remove(obj)) let arrow = null @@ -385,7 +385,7 @@ export const usePolygon = () => { westText = '西北西' } - clearDirectionText(canvas) + clearFlowText(canvas) addTextByArrows(eastArrows, eastText, canvas) addTextByArrows(westArrows, westText, canvas) @@ -393,8 +393,8 @@ export const usePolygon = () => { addTextByArrows(southArrows, southText, canvas) } - const clearDirectionText = (canvas) => { - const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') + const clearFlowText = (canvas) => { + const texts = canvas.getObjects().filter((obj) => obj.name === 'flowText') texts.forEach((text) => { canvas.remove(text) }) @@ -407,7 +407,7 @@ export const usePolygon = () => { fill: 'black', originX: 'center', originY: 'center', - name: 'directionText', + name: 'flowText', selectable: false, left: arrow.stickeyPoint.x, top: arrow.stickeyPoint.y, From 83640cc89b678fb5a657eb5dea251e20cdec54db Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 24 Oct 2024 09:48:55 +0900 Subject: [PATCH 070/139] =?UTF-8?q?=EC=B9=98=EC=88=98=EC=84=A0,=20?= =?UTF-8?q?=EB=AC=B8=EC=9E=90=20=ED=8F=B0=ED=8A=B8=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCommonUtils.js | 34 ++++++++++++++++++++---------- src/hooks/common/useFont.js | 30 ++++++++++++++++++++++++-- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index dd92253d..d4ab9cbf 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -2,13 +2,16 @@ import { useEffect } from 'react' import { useRecoilValue } from 'recoil' import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' -import { checkLineOrientation, getDistance } from '@/util/canvas-util' +import { checkLineOrientation, getDistance, setSurfaceShapePattern } from '@/util/canvas-util' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' +import { fontSelector } from '@/store/fontAtom' export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const dimensionSettings = useRecoilValue(dimensionLineSettingsState) + const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) + const commonTextFont = useRecoilValue(fontSelector('commonText')) useEffect(() => { initEvent() @@ -19,21 +22,31 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } else if (commonFunctionState.distance) { commonDistanceMode() } - }, [commonFunctionState, dimensionSettings]) + }, [commonFunctionState, dimensionSettings, commonTextFont, dimensionLineTextFont]) + + const loadDataInitialize = () => { + const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') + roofs.forEach((roof) => {}) + } const commonTextMode = () => { let textbox if (commonFunctionState.text) { + console.log(commonTextFont) + addCanvasMouseEventListener('mouse:down', (event) => { const pointer = canvas?.getPointer(event.e) textbox = new fabric.Textbox('', { left: pointer.x, top: pointer.y, width: 200, - fontSize: 14, editable: true, name: 'commonText', visible: wordDisplay, + fill: commonTextFont.fontColor.value, + fontFamily: commonTextFont.fontFamily.value, + fontSize: commonTextFont.fontSize.value, + fontStyle: commonTextFont.fontWeight.value, }) canvas?.add(textbox) @@ -187,21 +200,19 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS canvas.add(arrow1) canvas.add(arrow2) - console.log(dimensionSettings) - - // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 distanceText = new fabric.Text(`${distance * 10} `, { left: (p1CenterX + p2CenterX) / 2 + (lineDirection === 'horizontal' ? 0 : -15), top: (p1CenterY + p2CenterY) / 2 + (lineDirection === 'horizontal' ? +15 : 0), - fill: dimensionSettings.fontColor, - fontSize: dimensionSettings.fontSize, - // fontFamily : dimensionSettings.font, //폰트 - // fontStyle : dimensionSettings.fontStyle, //폰트스타일 + fill: dimensionLineTextFont.fontColor.value, + fontSize: dimensionLineTextFont.fontSize.value, + fontFamily: dimensionLineTextFont.fontFamily.value, + fontStyle: dimensionLineTextFont.fontWeight.value, selectable: true, textAlign: 'center', originX: 'center', originY: 'center', angle: lineDirection === 'horizontal' ? 0 : 270, + name: 'dimensionLineText', // lockMovementX: false, // lockMovementY: false, }) @@ -361,11 +372,12 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } } - setCommonFunctionState(tempStates) + if (setCommonFunctionState) setCommonFunctionState(tempStates) } return { commonFunctions, dimensionSettings, + loadDataInitialize, } } diff --git a/src/hooks/common/useFont.js b/src/hooks/common/useFont.js index 383997a0..28c78f14 100644 --- a/src/hooks/common/useFont.js +++ b/src/hooks/common/useFont.js @@ -11,9 +11,35 @@ export function useFont() { const lengthText = useRecoilValue(fontSelector('lengthText')) const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText')) - useEffect(() => {}, [commonText]) + useEffect(() => { + if (canvas) { + const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'commonText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: commonText.fontFamily.value, + fontWeight: commonText.fontWeight.value, + fontSize: commonText.fontSize.value, + fill: commonText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [commonText]) - useEffect(() => {}, [dimensionLineText]) + useEffect(() => { + if (canvas) { + const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'dimensionLineText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: dimensionLineText.fontFamily.value, + fontWeight: dimensionLineText.fontWeight.value, + fontSize: dimensionLineText.fontSize.value, + fill: dimensionLineText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [dimensionLineText]) useEffect(() => { if (canvas) { From 46dab98801f7d8fdfd43baf8d9426e286930c407 Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Thu, 24 Oct 2024 10:39:01 +0900 Subject: [PATCH 071/139] =?UTF-8?q?[=EB=A1=9C=EA=B7=B8=EC=9D=B8]=20?= =?UTF-8?q?=ED=8C=A8=EC=8A=A4=EC=9B=8C=EB=93=9C=20=ED=91=9C=EC=8B=9C=20?= =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Login.jsx | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 66d149ac..80b34f9f 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -234,6 +234,7 @@ export default function Login() { onBlur={() => setSecFocus(false)} /> @@ -1767,7 +1868,7 @@ export default function StuffDetail() { TEMP상세:{getMessage('stuff.detail.btn.save')} )} - + diff --git a/src/locales/ja.json b/src/locales/ja.json index 521f4ac6..5a93188a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -516,6 +516,8 @@ "stuff.detail.btn.moveList": "商品リスト", "stuff.detail.btn.save": "保存", "stuff.detail.btn.tempSave": "一時保存", + "stuff.detail.save.valierror1": "垂直説説は0より大きい値を入力してください", + "stuff.detail.save.valierror2": "設置高さ0より大きい値を入力してください", "stuff.planReqPopup.popTitle": "設計依頼検索", "stuff.planReqPopup.btn1": "検索", "stuff.planReqPopup.btn2": "初期化", diff --git a/src/locales/ko.json b/src/locales/ko.json index 693d94b4..97d04755 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -521,6 +521,8 @@ "stuff.detail.btn.moveList": "물건목록", "stuff.detail.btn.save": "저장", "stuff.detail.btn.tempSave": "임시저장", + "stuff.detail.save.valierror1": "수직적설량은 0보다 큰 값을 입력하세요", + "stuff.detail.save.valierror2": "설치높이 0보다 큰 값을 입력하세요", "stuff.planReqPopup.popTitle": "설계 요청 검색", "stuff.planReqPopup.btn1": "검색", "stuff.planReqPopup.btn2": "초기화", From e86519211aebde771b137c68cb8b23e6991a8b96 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 24 Oct 2024 11:29:36 +0900 Subject: [PATCH 074/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 4 ++-- src/components/management/StuffDetail.jsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 98659701..162a64a6 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -244,8 +244,8 @@ export default function Stuff() { } async function fetchData() { - // const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` - const apiUrl = `/api/object/list?saleStoreId=T100&${queryStringFormatter(params)}` + const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` + // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(params)}` await get({ url: apiUrl, }).then((res) => { diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 4aa54583..1e35a0a2 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -299,8 +299,8 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 - // get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { - get({ url: `/api/object/saleStore/T100/list` }).then((res) => { + get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') @@ -356,8 +356,8 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 - // get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { - get({ url: `/api/object/saleStore/T100/list` }).then((res) => { + get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') From 0845259945bbe178c02ea20526d213c992ba9242 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 24 Oct 2024 12:23:45 +0900 Subject: [PATCH 075/139] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EB=A1=9C?= =?UTF-8?q?=EB=94=A9=20=ED=9B=84=20=EC=B4=88=EA=B8=B0=ED=99=94=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasFrame.jsx | 4 ++- src/components/floor-plan/CanvasMenu.jsx | 1 - src/hooks/common/useCanvasConfigInitialize.js | 32 +++++++++++++++++++ src/hooks/common/useCommonUtils.js | 10 ++---- 4 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 src/hooks/common/useCanvasConfigInitialize.js diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index ebb3ece7..6887d07a 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -10,6 +10,7 @@ import { useRecoilValue } from 'recoil' import { currentObjectState } from '@/store/canvasAtom' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' +import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) @@ -21,7 +22,7 @@ export default function CanvasFrame({ plan }) { }, }) const { checkCanvasObjectEvent, checkUnsavedCanvasPlan } = usePlan() - + const { canvasLoadInit } = useCanvasConfigInitialize() const currentObject = useRecoilValue(currentObjectState) useEvent() @@ -32,6 +33,7 @@ export default function CanvasFrame({ plan }) { if (plan?.canvasStatus) { canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () { canvas?.renderAll() // 캔버스를 다시 그립니다. + canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 }) } } diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 5f73efa1..07411efb 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -69,7 +69,6 @@ export default function CanvasMenu(props) { }) const { commonFunctions } = useCommonUtils({ - canvas, commonFunctionState, setCommonFunctionState, }) diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js new file mode 100644 index 00000000..7421c53f --- /dev/null +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -0,0 +1,32 @@ +import { use, useEffect } from 'react' +import { useRecoilValue } from 'recoil' +import { settingModalFirstOptionsState } from '@/store/settingAtom' +import { canvasState } from '@/store/canvasAtom' +import { setSurfaceShapePattern } from '@/util/canvas-util' + +export function useCanvasConfigInitialize() { + const canvas = useRecoilValue(canvasState) + const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState) + + const canvasLoadInit = () => { + roofInit() //화면표시 초기화 + } + + //치수표시, 화면표시, 글꼴등 초기화 + const roofInit = () => { + if (canvas) { + const roofDisplay = settingModalFirstOptions.option2.filter((item) => item.selected) + + canvas + .getObjects() + .filter((polygon) => polygon.name === 'roof') + .forEach((polygon) => { + setSurfaceShapePattern(polygon, roofDisplay[0].column) + }) + + canvas.renderAll() + } + } + + return { canvasLoadInit } +} diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index d4ab9cbf..8af18fa0 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -5,8 +5,10 @@ import { useEvent } from '@/hooks/useEvent' import { checkLineOrientation, getDistance, setSurfaceShapePattern } from '@/util/canvas-util' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' import { fontSelector } from '@/store/fontAtom' +import { canvasState } from '@/store/canvasAtom' -export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { +export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) { + const canvas = useRecoilValue(canvasState) const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const dimensionSettings = useRecoilValue(dimensionLineSettingsState) @@ -24,11 +26,6 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } }, [commonFunctionState, dimensionSettings, commonTextFont, dimensionLineTextFont]) - const loadDataInitialize = () => { - const roofs = canvas.getObjects().filter((obj) => obj.name === 'roof') - roofs.forEach((roof) => {}) - } - const commonTextMode = () => { let textbox if (commonFunctionState.text) { @@ -378,6 +375,5 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS return { commonFunctions, dimensionSettings, - loadDataInitialize, } } From 20e9a4894b61f2471bb1774c5a224b91cb5f64b7 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 24 Oct 2024 12:36:06 +0900 Subject: [PATCH 076/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 13 +++++-------- src/components/management/StuffDetail.jsx | 10 ++++++---- src/components/management/StuffSearchCondition.jsx | 1 - src/locales/ko.json | 2 +- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 162a64a6..df057d8f 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -228,6 +228,7 @@ export default function Stuff() { //물건 메뉴 눌러서 최초 진입 sessionState if (stuffSearchParams?.code === 'S') { const params = { + saleStoreId: sessionState?.storeId, schObjectNo: stuffSearchParams?.schObjectNo, schAddress: stuffSearchParams?.schAddress, schObjectName: stuffSearchParams?.schObjectName, @@ -244,8 +245,7 @@ export default function Stuff() { } async function fetchData() { - const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` - // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(params)}` + const apiUrl = `/api/object/list?${queryStringFormatter(params)}` await get({ url: apiUrl, }).then((res) => { @@ -259,6 +259,7 @@ export default function Stuff() { } else { //메인화면에서 진입 const params = { + saleStoreId: sessionState?.storeId, schObjectNo: stuffSearchParams.schObjectNo, schAddress: '', schObjectName: '', @@ -275,8 +276,7 @@ export default function Stuff() { } async function fetchData() { - const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` - + const apiUrl = `/api/object/list?${queryStringFormatter(params)}` await get({ url: apiUrl, }).then((res) => { @@ -298,9 +298,8 @@ export default function Stuff() { stuffSearchParams.schSortType = defaultSortType setPageNo(1) - + //조회를 눌렀을때 async function fetchData() { - // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` await get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { @@ -330,7 +329,6 @@ export default function Stuff() { }) setPageNo(1) - // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { @@ -361,7 +359,6 @@ export default function Stuff() { setPageNo(1) - // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` get({ url: apiUrl }).then((res) => { if (!isEmptyArray(res)) { diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 1e35a0a2..a68771fa 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -893,10 +893,10 @@ export default function StuffDetail() { let height = params.installHeight if (snow === '0') { - alert(getMessage('stuff.detail.save.valierror1')) + return alert(getMessage('stuff.detail.save.valierror1')) } if (height === '0') { - alert(getMessage('stuff.detail.save.valierror2')) + return alert(getMessage('stuff.detail.save.valierror2')) } alert('작업중') @@ -958,10 +958,10 @@ export default function StuffDetail() { let height = params.installHeight if (snow === '0') { - alert(getMessage('stuff.detail.save.valierror1')) + return alert(getMessage('stuff.detail.save.valierror1')) } if (height === '0') { - alert(getMessage('stuff.detail.save.valierror2')) + return alert(getMessage('stuff.detail.save.valierror2')) } alert('작업중') @@ -1129,6 +1129,7 @@ export default function StuffDetail() { getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} isClearable={sessionState?.storeLvl === '1' ? true : false} + isDisabled={sessionState?.storeLel !== '1' ? true : false} value={saleStoreList.filter(function (option) { return option.saleStoreId === selOptions })} @@ -1537,6 +1538,7 @@ export default function StuffDetail() { getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} isClearable={sessionState?.storeLvl === '1' ? true : false} + isDisabled={sessionState?.storeLel !== '1' ? true : false} value={saleStoreList.filter(function (option) { return option.saleStoreId === selOptions })} diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index 0326f28e..1822140e 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -128,7 +128,6 @@ export default function StuffSearchCondition() { useEffect(() => { if (isObjectNotEmpty(sessionState)) { // storeId가 T01 이거나 1차점일때만 판매대리점 선택 활성화 - // get({ url: `/api/object/saleStore/TEMP02/list` }).then((res) => { get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { if (!isEmptyArray(res)) { res.map((row) => { diff --git a/src/locales/ko.json b/src/locales/ko.json index 97d04755..651e8473 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -522,7 +522,7 @@ "stuff.detail.btn.save": "저장", "stuff.detail.btn.tempSave": "임시저장", "stuff.detail.save.valierror1": "수직적설량은 0보다 큰 값을 입력하세요", - "stuff.detail.save.valierror2": "설치높이 0보다 큰 값을 입력하세요", + "stuff.detail.save.valierror2": "설치높이는 0보다 큰 값을 입력하세요", "stuff.planReqPopup.popTitle": "설계 요청 검색", "stuff.planReqPopup.btn1": "검색", "stuff.planReqPopup.btn2": "초기화", From 7aa2e6194d8ed28a9af5e2c02271ca1477d75822 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 24 Oct 2024 13:46:55 +0900 Subject: [PATCH 077/139] =?UTF-8?q?=EA=B1=B0=EB=A6=AC=EC=9E=AC=EA=B8=B0=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCommonUtils.js | 106 ++++++++++++++++++----------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 8af18fa0..8d0412c1 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -29,8 +29,6 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) const commonTextMode = () => { let textbox if (commonFunctionState.text) { - console.log(commonTextFont) - addCanvasMouseEventListener('mouse:down', (event) => { const pointer = canvas?.getPointer(event.e) textbox = new fabric.Textbox('', { @@ -280,50 +278,70 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) addCanvasMouseEventListener('mouse:down', function (options) { const pointer = canvas.getPointer(options.e) let point + let cross = {} if (points.length === 0) { - // 첫 번째 포인트는 그대로 클릭한 위치에 추가 - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, + point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], { + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', }) - points.push(point) canvas.add(point) + cross['x'] = parseInt(point.left.toFixed(0)) + + // 세로 선 생성 (십자 모양의 다른 축) + point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], { + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', + }) + cross['y'] = parseInt(point.top.toFixed(0)) + + canvas.add(point) + points.push(cross) } else if (points.length === 1) { // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 const p1 = points[0] - point = new fabric.Circle({ - left: pointer.x - 5, // 반지름 반영 - top: pointer.y - 5, // 반지름 반영 - ...circleOptions, + point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], { + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', }) - - points.push(point) canvas.add(point) + cross['x'] = parseInt(point.left.toFixed(0)) + // 세로 선 생성 (십자 모양의 다른 축) + point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], { + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', + }) + canvas.add(point) + cross['y'] = parseInt(point.top.toFixed(0)) + points.push(cross) + + let isParallel = false + + if (points[0].x === points[1].x || points[0].y === points[1].y) { + isParallel = true + } // 두 포인트의 중심 좌표 계산 const p2 = points[1] - const p1CenterX = p1.left + p1.radius - const p1CenterY = p1.top + p1.radius - const p2CenterX = p2.left + p2.radius - const p2CenterY = p2.top + p2.radius - - const p3 = new fabric.Point(p2CenterX, p1CenterY) + const p1CenterX = p1.x + const p1CenterY = p1.y + const p2CenterX = p2.x + const p2CenterY = p2.y // 두 포인트 간에 직선을 그림 (중심을 기준으로) const line = new fabric.Line([p1CenterX, p1CenterY, p2CenterX, p2CenterY], lineOptions) - const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) - const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) canvas.add(line) - canvas.add(line2) - canvas.add(line3) - const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) - const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) - const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 distanceText = new fabric.Text(`${distance1 * 10}`, { @@ -332,18 +350,28 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) ...textOptions, }) canvas.add(distanceText) - distanceText = new fabric.Text(`${distance2 * 10}`, { - left: (p2CenterX + p3.x) / 2, - top: (p2CenterY + p3.y) / 2, - ...textOptions, - }) - canvas.add(distanceText) - distanceText = new fabric.Text(`${distance3 * 10}`, { - left: (p3.x + p1CenterX) / 2, - top: (p3.y + p1CenterY) / 2, - ...textOptions, - }) - canvas.add(distanceText) + + if (!isParallel) { + const p3 = new fabric.Point(p2CenterX, p1CenterY) + const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) + const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) + canvas.add(line2) + canvas.add(line3) + const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) + const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + distanceText = new fabric.Text(`${distance2 * 10}`, { + left: (p2CenterX + p3.x) / 2, + top: (p2CenterY + p3.y) / 2, + ...textOptions, + }) + canvas.add(distanceText) + distanceText = new fabric.Text(`${distance3 * 10}`, { + left: (p3.x + p1CenterX) / 2, + top: (p3.y + p1CenterY) / 2, + ...textOptions, + }) + canvas.add(distanceText) + } // 거리 계산 후, 다음 측정을 위해 초기화 points = [] From b11cfb28f2ff273530897e56518e1f8ee91c83ff Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 24 Oct 2024 17:30:33 +0900 Subject: [PATCH 078/139] feat: add hook sample --- .../option/useCanvasSettingController.js | 126 ++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/hooks/option/useCanvasSettingController.js diff --git a/src/hooks/option/useCanvasSettingController.js b/src/hooks/option/useCanvasSettingController.js new file mode 100644 index 00000000..72a590eb --- /dev/null +++ b/src/hooks/option/useCanvasSettingController.js @@ -0,0 +1,126 @@ +import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { useEffect, useState } from 'react' +import { useRecoilState } from 'recoil' + +export const useCanvasSettingController = () => { + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) + const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 + const { get } = useAxios() + + useEffect(() => { + fetchSettings() + }, [objectNo]) + + useEffect(() => { + fetchSettings() + }, []) + + useEffect(() => { + onClickOnlyOne() + fetchSettings() + }, [settingModalFirstOptions, settingModalSecondOptions]) + + const fetchSettings = async () => { + try { + const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) + const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) + const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) + const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) + const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) + const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ + ...item, + })) + // 데이터 설정 + setSettingModalFirstOptions({ + option1: optionData1, + option2: optionData2, + dimensionDisplay: optionData5, + }) + setSettingModalSecondOptions({ + option3: optionData3, + option4: optionData4, + }) + } catch (error) { + console.error('Data fetching error:', error) + } + } + + const onClickOption = async (option) => { + option.selected = !option.selected + + setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) + setSettingModalSecondOptions({ option3, option4 }) + + try { + // 서버에 전송할 데이터 + const dataToSend = { + firstOption1: option1.map((item) => ({ + column: item.column, + selected: item.selected, + })), + firstOption2: option2.map((item) => ({ + column: item.column, + selected: item.selected, + })), + firstOption3: dimensionDisplay.map((item) => ({ + column: item.column, + selected: item.selected, + })), + // secondOption1: secondOptions[0].option1.map((item) => ({ + // name: item.id, + // name: item.name, + // // 필요한 경우 데이터 항목 추가 + // })), + secondOption2: option4.map((item) => ({ + column: item.column, + selected: item.selected, + })), + } + + const patternData = { + objectNo, + //디스플레이 설정(다중) + allocDisplay: dataToSend.firstOption1[0].selected, + outlineDisplay: dataToSend.firstOption1[1].selected, + gridDisplay: dataToSend.firstOption1[2].selected, + lineDisplay: dataToSend.firstOption1[3].selected, + wordDisplay: dataToSend.firstOption1[4].selected, + circuitNumDisplay: dataToSend.firstOption1[5].selected, + flowDisplay: dataToSend.firstOption1[6].selected, + trestleDisplay: dataToSend.firstOption1[7].selected, + totalDisplay: dataToSend.firstOption1[8].selected, + //차수 표시(다건) + corridorDimension: dataToSend.firstOption3[0].selected, + realDimension: dataToSend.firstOption3[1].selected, + noneDimension: dataToSend.firstOption3[2].selected, + //화면 표시(다중) + onlyBorder: dataToSend.firstOption2[0].selected, + lineHatch: dataToSend.firstOption2[1].selected, + allPainted: dataToSend.firstOption2[2].selected, + //흡착범위 설정(단건) + adsorpRangeSmall: dataToSend.secondOption2[0].selected, + adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + adsorpRangeMedium: dataToSend.secondOption2[2].selected, + adsorpRangeLarge: dataToSend.secondOption2[3].selected, + } + + // HTTP POST 요청 보내기 + await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { + swalFire({ text: getMessage(res.returnMessage) }) + }) + } catch (error) { + swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) + } + } + + return { + fetchSettings, + settingModalFirstOptions, + setSettingModalFirstOptions, + settingModalSecondOptions, + setSettingModalSecondOptions, + onClickOption, + ß, + } +} From b5eefeca7e29dfaed76d2051b889f7c7192c0f69 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 24 Oct 2024 17:41:36 +0900 Subject: [PATCH 079/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EC=83=81=EC=84=B8=20=EB=AA=A9=EB=A1=9D=20=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 98 +++---- src/components/management/StuffDetail.jsx | 267 ++++++++++++++----- src/components/management/StuffPlanQGrid.jsx | 1 + src/locales/ja.json | 10 +- src/locales/ko.json | 10 +- 5 files changed, 262 insertions(+), 124 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index df057d8f..4a7e3052 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -25,7 +25,7 @@ export default function Stuff() { const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const { getMessage } = useMessage() const [pageNo, setPageNo] = useState(1) //현재 페이지 번호 - const [pageSize, setPageSize] = useState(100) //페이지 당 게시물 수 + const [pageSize, setPageSize] = useState(5) //페이지 당 게시물 수 const [totalCount, setTotalCount] = useState(0) //총 갯수 const [defaultSortType, setDefaultSortType] = useState('R') @@ -172,55 +172,54 @@ export default function Stuff() { } //물건삭제 - const fnDeleteRowData = (data) => { - console.log('물건삭제:::::::::::') - if (data.length === 0) { - return alert('삭제할 데이터를 선택하세요') - } - let errCount = 0 - data.forEach((cell) => { - if (!cell.objectNo) { - if (errCount === 0) { - alert('물건정보가 있는 행만 삭제 됩니다') - } - errCount++ - } - }) - } + // const fnDeleteRowData = (data) => { + // if (data.length === 0) { + // return alert('삭제할 데이터를 선택하세요') + // } + // let errCount = 0 + // data.forEach((cell) => { + // if (!cell.objectNo) { + // if (errCount === 0) { + // alert('물건정보가 있는 행만 삭제 됩니다') + // } + // errCount++ + // } + // }) + // } //행추가 - let newCount = 0 - const addRowItems = () => { - // console.log('girdRef::::::', gridRef.current.api) - const newItems = [ - { - mission: newCount + 1, - successful: true, - }, - ] - gridRef.current.api.applyTransaction({ - add: newItems, - addIndex: newCount, - }) - newCount++ - } + // let newCount = 0 + // const addRowItems = () => { + // // console.log('girdRef::::::', gridRef.current.api) + // const newItems = [ + // { + // mission: newCount + 1, + // successful: true, + // }, + // ] + // gridRef.current.api.applyTransaction({ + // add: newItems, + // addIndex: newCount, + // }) + // newCount++ + // } //행삭제 - const removeRowItems = () => { - // console.log('selectedRowData::', selectedRowData) - let errCount = 0 - selectedRowData.forEach((cell) => { - if (!cell.company) { - let newSelectedRowData = selectedRowData.filter((item) => item.company == null) - gridRef.current.api.applyTransaction({ remove: newSelectedRowData }) - } else { - if (errCount === 0) { - alert('행추가로 추가 한 행만 삭제됩니다.') - } - errCount++ - } - }) - } + // const removeRowItems = () => { + // // console.log('selectedRowData::', selectedRowData) + // let errCount = 0 + // selectedRowData.forEach((cell) => { + // if (!cell.company) { + // let newSelectedRowData = selectedRowData.filter((item) => item.company == null) + // gridRef.current.api.applyTransaction({ remove: newSelectedRowData }) + // } else { + // if (errCount === 0) { + // alert('행추가로 추가 한 행만 삭제됩니다.') + // } + // errCount++ + // } + // }) + // } // 진입시 그리드 데이터 조회 useEffect(() => { @@ -381,6 +380,7 @@ export default function Stuff() { // 페이징 현재페이지 변경 const handleChangePage = (page) => { + console.log('page:::', page) stuffSearchParams.code = 'S' setStuffSearch({ @@ -390,9 +390,13 @@ export default function Stuff() { endRow: page * pageSize, }) + // console.log('여기::::::::::::', page) setPageNo(page) } + // console.log('pageNo:::', pageNo) + // console.log('pageSize:::', pageSize) + // console.log('totalCount:::', totalCount) return ( <> {/* 퍼블시작 */} @@ -420,7 +424,7 @@ export default function Stuff() {
    diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index a68771fa..3ecd471f 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -261,24 +261,21 @@ export default function StuffDetail() { }) useEffect(() => { - // console.log('objectNo::', objectNo) - if (objectNo) { setEditMode('EDIT') - - if (objectNo.substring(0, 1) === 'R') { + if (objectNo.substring(0, 1) !== 'T') { //벨리데이션 체크용.. setIsFormValid(true) } promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { if (res.status === 200) { + console.log('플랜데이타:::', res.data.planList) if (res.data != null) { setDetailData(res.data) } else { setDetailData({}) } if (isNotEmptyArray(res.data.planList)) { - // console.log('플랜RES::::::::', res.data.planList) setPlanGridProps({ ...planGridProps, planGridData: res.data.planList }) } else { setPlanGridProps({ ...planGridProps, planGridData: [] }) @@ -300,16 +297,23 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { - // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') //1차점 셀렉트박스 setSaleStoreList(firstList) - //1차점 아닌 판매점 셀렉트박스 - setOriginOtherSaleStoreList(otherList) - setOtherSaleStoreList(otherList) + + let filterOtherList + if (sessionState?.storeId === 'T01') { + filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01') + setOriginOtherSaleStoreList(filterOtherList) + setOtherSaleStoreList(filterOtherList) + } else { + //1차점 아닌 판매점 셀렉트박스 + setOriginOtherSaleStoreList(otherList) + setOtherSaleStoreList(otherList) + } if (sessionState?.storeLvl === '1') { setSelOptions(sessionState?.storeId) @@ -332,21 +336,19 @@ export default function StuffDetail() { const code2 = findCommonCode(201700) //신축/기축 const code3 = findCommonCode(202000) //기준풍속 202000 if (code1 != null) { - // console.log('경칭공코::::::', code1) setHonorificCodeList(code1) } if (code2 != null) { - // console.log('신축/기축공코::::', code2) setObjectStatusList(code2) } if (code3 != null) { - // console.log('기준풍속::::', code3) setWindSpeedList(code3) } }, [commonCode]) useEffect(() => { if (isObjectNotEmpty(detailData)) { + // console.log('상세데이타세팅:::::', detailData) // 도도부현API get({ url: '/api/object/prefecture/list' }).then((res) => { if (!isEmptyArray(res)) { @@ -357,19 +359,40 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { - // get({ url: `/api/object/saleStore/T01/list` }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') + //1차점 셀렉트박스 setSaleStoreList(firstList) - //1차점 아닌 판매점 셀렉트박스 - setOriginOtherSaleStoreList(otherList) - setOtherSaleStoreList(otherList) - // console.log('1차점리스트::', firstList) - // console.log('2차점리스트::', otherList) + let filterOtherList + if (sessionState?.storeId === 'T01') { + filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01') + setOriginOtherSaleStoreList(filterOtherList) + setOtherSaleStoreList(filterOtherList) + } else { + //1차점 아닌 판매점 셀렉트박스 + setOriginOtherSaleStoreList(otherList) + setOtherSaleStoreList(otherList) + } } + + //상세데이터가 1차점이면 1차점에 세팅 + //상세데이터가 2차점이면 2차점에 세팅하고 세션으로 1차점 세팅 + if (detailData.saleStoreLevel === '1') { + setSelOptions(detailData.saleStoreId) + form.setValue('saleStoreId', detailData.saleStoreId) + form.setValue('saleStoreLevel', detailData.saleStoreLevel) + } else { + setSelOptions(sessionState?.storeId) + form.setValue('saleStoreId', sessionState?.storeId) + form.setValue('saleStoreLevel', sessionState?.storeLvl) + setOtherSelOptions(detailData.saleStoreId) + form.setValue('otherSaleStoreId', detailData.saleStoreId) + form.setValue('otherSaleStoreLevel', detailData.saleStoreLevel) + } + //설계의뢰No. form.setValue('planReqNo', detailData.planReqNo) //담당자 @@ -389,21 +412,6 @@ export default function StuffDetail() { //물건명 후리가나 form.setValue('objectNameKana', detailData.objectNameKana) - console.log('상세데이타::세팅:::::', detailData) - //상세데이터에는 2차점까지 골랐으면 2차점 정보만 내려옴 - //로그인세션이 1차점이면 1차점은 본인으로 디폴트 셋팅하고 2차점에 상세데이터 넣어줌 - //1차점 - // setSelOptions(detailData.saleStoreId) - // form.setValue('saleStoreId', detailData.saleStoreId) - // form.setValue('saleStoreLevel', sessionState?.storeLvl) - - //2차점까지 고른경우 확인필요 - // console.log('2차점까지 고른경우 확인필요') - // setOtherSelOptions(sessionState?.storeId) - // form.setValue('saleStoreId', firstList[0].saleStoreId) - // form.setValue('otherSaleStoreId', sessionState?.storeId) - // form.setValue('otherSaleStoreLevel', sessionState?.storeLvl) - //우편번호 form.setValue('zipNo', detailData.zipNo) @@ -412,7 +420,11 @@ export default function StuffDetail() { form.setValue('prefId', detailData.prefId) //prefName ??? form.setValue('address', detailData.address) + //발전시뮬 + form.setValue('areaId', detailData.areaId) + //기준풍속 + form.setValue('standardWindSpeedId', detailData.standardWindSpeedId) //수직적설량 form.setValue('verticalSnowCover', detailData.verticalSnowCover) //한랭지대책시행 coldRegionFlg 1이면 true @@ -460,6 +472,10 @@ export default function StuffDetail() { } //1차점 변경 이벤트 const onSelectionChange = (key) => { + if (key.saleStoreId === selOptions) { + return + } + const planReqNo = form.watch('planReqNo') let delFlg = false @@ -486,7 +502,7 @@ export default function StuffDetail() { if (objectNo) { tempObjectNo = objectNo.substring(0, 1) } - if (tempObjectNo !== 'R') { + if (tempObjectNo === 'T') { if (planReqNo) { if (delFlg) { form.setValue('planReqNo', '') @@ -568,6 +584,10 @@ export default function StuffDetail() { //2차점 변경 이벤트 const onSelectionChange2 = (key) => { + if (key.saleStoreId === otherSelOptions) { + return + } + const planReqNo = form.watch('planReqNo') let delFlg = false if (editMode === 'NEW') { @@ -593,7 +613,7 @@ export default function StuffDetail() { if (objectNo) { tempObjectNo = objectNo.substring(0, 1) } - if (tempObjectNo !== 'R') { + if (tempObjectNo === 'T') { if (planReqNo) { if (delFlg) { form.setValue('planReqNo', '') @@ -646,7 +666,6 @@ export default function StuffDetail() { //팝업에서 넘어온 우편정보 const setZipInfo = (info) => { - // console.log('팝업에서 넘어온 우편 데이타::::::::', info) setPrefValue(info.prefId) form.setValue('prefId', info.prefId) form.setValue('prefName', info.address1) @@ -761,7 +780,7 @@ export default function StuffDetail() { setIsFormValid(Object.keys(errors).length === 0 ? true : false) } else { - console.log('상세일때 폼체크') + //상세일떄 폼체크 const formData = form.getValues() let errors = {} if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { @@ -781,7 +800,7 @@ export default function StuffDetail() { errors.zipNo = true } - if (!formData.prefId) { + if (!formData.prefId || formData.prefId === '0') { errors.prefId = true } @@ -801,7 +820,7 @@ export default function StuffDetail() { errors.installHeight = true } - console.log('상세 저장용 에러결과?????::', errors) + // console.log('상세에러필드:::::', errors) setIsFormValid(Object.keys(errors).length === 0 ? true : false) } }, [ @@ -839,7 +858,7 @@ export default function StuffDetail() { } useEffect(() => { - if (prefValue !== '') { + if (prefValue) { // 발전량시뮬레이션 지역 목록 get({ url: `/api/object/prefecture/${prefValue}/list` }).then((res) => { if (!isEmptyArray(res)) { @@ -855,11 +874,66 @@ export default function StuffDetail() { form.setValue('areaName', e.prefName) } - //필수값 다 입력했을때 const onValid = async () => { const formData = form.getValues() + + let errors = {} + let fieldNm + if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { + fieldNm = getMessage('stuff.detail.receiveUser') + errors = fieldNm + } + if (!formData.objectName || formData.objectName.trim().length === 0) { + fieldNm = getMessage('stuff.detail.objectStatusId') + errors = fieldNm + } + if (!formData.objectNameOmit) { + fieldNm = getMessage('stuff.detail.objectNameOmit') + errors = fieldNm + } + if (!formData.saleStoreId) { + fieldNm = getMessage('stuff.detail.saleStoreId') + errors = fieldNm + } + + if (!formData.zipNo) { + fieldNm = getMessage('stuff.detail.zipNo') + errors = fieldNm + } + + if (!formData.prefId || formData.prefId === '0') { + fieldNm = getMessage('stuff.detail.prefId') + errors = fieldNm + } + + if (!formData.areaId) { + fieldNm = getMessage('stuff.detail.areaId') + errors = fieldNm + } + + if (!formData.standardWindSpeedId) { + fieldNm = getMessage('stuff.detail.standardWindSpeedId') + errors = fieldNm + } + + if (!formData.verticalSnowCover) { + fieldNm = getMessage('stuff.detail.verticalSnowCover') + errors = fieldNm + } + + if (!formData.installHeight) { + fieldNm = getMessage('stuff.detail.installHeight') + errors = fieldNm + } + + if (Object.keys(errors).length > 0) { + return alert(getMessage('stuff.detail.save.valierror3', [errors])) + } + const apiUrl = '/api/object/save-object' + const params = { + objectNo: objectNo, planReqNo: formData.planReqNo, saleStoreId: formData.otherSaleStoreId ? formData.otherSaleStoreId : formData.saleStoreId, saleStoreName: formData.otherSaleStoreName ? formData.otherSaleStoreName : formData.saleStoreName, @@ -886,7 +960,6 @@ export default function StuffDetail() { workNo: null, workName: null, } - console.log('REAL저장::', params) //수직적설량, 설치높이 0인지 체크 let snow = params.verticalSnowCover @@ -899,20 +972,76 @@ export default function StuffDetail() { return alert(getMessage('stuff.detail.save.valierror2')) } - alert('작업중') - return + let detail_sort = Object.keys(detailData) + .sort() + .reduce((obj, key) => ((obj[key] = detailData[key]), obj), {}) + let params_sort = Object.keys(params) + .sort() + .reduce((obj, key) => ((obj[key] = params[key]), obj), {}) + + delete detail_sort.areaName + delete detail_sort.contentsPath + delete detail_sort.createDatetime + delete detail_sort.createUserName + delete detail_sort.dispCompanyName + delete detail_sort.firstAgentId + delete detail_sort.lastEditDatetime + delete detail_sort.lastEditUserName + delete detail_sort.planList + delete detail_sort.planNo + delete detail_sort.planTotCnt + delete detail_sort.receiveCompanyName + delete detail_sort.saleStoreName + delete detail_sort.rowNumber + delete detail_sort.prefName + delete detail_sort.sameObjectInfo + delete detail_sort.specificationConfirmDate + delete detail_sort.totCnt + delete detail_sort.workNo + delete detail_sort.workName + + delete params_sort.areaName + delete params_sort.contentsPath + delete params_sort.createDatetime + delete params_sort.createUserName + delete params_sort.dispCompanyName + delete params_sort.firstAgentId + delete params_sort.lastEditDatetime + delete params_sort.lastEditUserName + delete params_sort.planList + delete params_sort.planNo + delete params_sort.planTotCnt + delete params_sort.receiveCompanyName + delete params_sort.saleStoreName + delete params_sort.rowNumber + delete params_sort.prefName + delete params_sort.sameObjectInfo + delete params_sort.specificationConfirmDate + delete params_sort.totCnt + delete params_sort.workNo + delete params_sort.workName + + // console.log(JSON.stringify(detail_sort) === JSON.stringify(params_sort)) + // console.log(Object.entries(detail_sort).toString() === Object.entries(params_sort).toString()) + if (Object.entries(detail_sort).toString() === Object.entries(params_sort).toString()) { + return alert(getMessage('stuff.detail.noChgData')) + } + if (editMode === 'NEW') { await promisePost({ url: apiUrl, data: params }).then((res) => { - console.log('진짜저장결과::::', pathname, res) - //상세화면으로 전환 - //router.push(`${pathname}?objectNo=${res.data.objectNo.toString()}`) + if (res.status === 201) { + alert(getMessage('stuff.detail.save')) + router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`) + } }) } else { // 수정모드일때는 PUT await promisePut({ url: apiUrl, data: params }).then((res) => { - console.log('진짜데이터 수정 결과::::::::::', pathname, res) - //새로고침??? + if (res.status === 201) { + alert(getMessage('stuff.detail.save')) + router.refresh() + } }) } } @@ -963,12 +1092,9 @@ export default function StuffDetail() { if (height === '0') { return alert(getMessage('stuff.detail.save.valierror2')) } - - alert('작업중') - return await promisePost({ url: '/api/object/save-object', data: params }).then((res) => { if (res.status === 201) { - getMessage('stuff.detail.tempSave.message1') + alert(getMessage('stuff.detail.tempSave.message1')) router.push(`${pathname}?objectNo=${res.data.objectNo.toString()}`) } }) @@ -976,15 +1102,12 @@ export default function StuffDetail() { // 물건삭제 const onDelete = () => { - // console.log('물건번호::::::::', objectNo) - // console.log('detailData:::::::::', detailData) const specificationConfirmDate = detailData.specificationConfirmDate if (specificationConfirmDate != null) { alert(getMessage('stuff.detail.delete.message1')) } else { if (confirm(getMessage('common.message.data.delete'))) { del({ url: `/api/object/${objectNo}` }).then((res) => { - // console.log('삭제결과:::::::', res) router.push('/management/stuff') }) } @@ -1038,7 +1161,7 @@ export default function StuffDetail() { - {getMessage('stuff.detail.dispCompanyName')} * + {getMessage('stuff.detail.receiveUser')} *
    @@ -1129,7 +1252,7 @@ export default function StuffDetail() { getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} isClearable={sessionState?.storeLvl === '1' ? true : false} - isDisabled={sessionState?.storeLel !== '1' ? true : false} + isDisabled={sessionState?.storeLvl !== '1' ? true : false} value={saleStoreList.filter(function (option) { return option.saleStoreId === selOptions })} @@ -1264,7 +1387,7 @@ export default function StuffDetail() { - {getMessage('stuff.detail.windSpeed')} * + {getMessage('stuff.detail.standardWindSpeedId')} *
    @@ -1287,7 +1410,7 @@ export default function StuffDetail() { })} >
    - {getMessage('stuff.detail.windSpeedSpan')} + {getMessage('stuff.detail.standardWindSpeedIdSpan')} @@ -1389,16 +1512,16 @@ export default function StuffDetail() {
    {!isFormValid ? ( ) : ( )}
    @@ -1425,6 +1548,7 @@ export default function StuffDetail() {
    + {/* {detailData?.tempFlg === '1' && form.watch('planReqNo') ? ( */} {objectNo.substring(0, 1) === 'T' && form.watch('planReqNo') ? ( ) : null}
    + {/* {detailData?.tempFlg === '1' ? ( */} {objectNo.substring(0, 1) === 'T' ? ( <> @@ -1812,7 +1937,8 @@ export default function StuffDetail() {
    - {objectNo.substring(0, 1) === 'R' ? ( + {/* {detailData?.tempFlg === '0' ? ( */} + {objectNo.substring(0, 1) !== 'T' ? ( <> {/* 진짜R 플랜시작 */}
    @@ -1840,7 +1966,6 @@ export default function StuffDetail() {
    - {/*
    페이징영역
    */}
    {/* 진짜R 플랜끝 */} @@ -1862,7 +1987,7 @@ export default function StuffDetail() { <>
    {!isFormValid ? ( - ) : ( diff --git a/src/components/management/StuffPlanQGrid.jsx b/src/components/management/StuffPlanQGrid.jsx index b4108342..108e17a2 100644 --- a/src/components/management/StuffPlanQGrid.jsx +++ b/src/components/management/StuffPlanQGrid.jsx @@ -45,6 +45,7 @@ export default function StuffPlanQGrid(props) { rowSelection={'singleRow'} pagination={isPageable} domLayout="autoHeight" + suppressCellFocus={true} />
    ) diff --git a/src/locales/ja.json b/src/locales/ja.json index 5a93188a..c5522fe2 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -477,10 +477,11 @@ "stuff.detail.header.createDatetime": "登録日", "stuff.detail.required": "必須入力項目", "stuff.detail.planReqNo": "設計依頼No.", - "stuff.detail.dispCompanyName": "担当者", + "stuff.detail.receiveUser": "担当者", "stuff.detail.objectStatusId": "物品区分/物件名", "stuff.detail.objectStatus0": "新築", "stuff.detail.objectStatus1": "基軸", + "stuff.detail.objectNameOmit": "敬称", "stuff.detail.objectNameKana": "商品名 ふりがな", "stuff.detail.saleStoreId": "一次販売店名/ID", "stuff.detail.otherSaleStoreId": "二次販売店名/ID", @@ -489,8 +490,8 @@ "stuff.detail.btn.addressPop.guide": "※ 郵便番号7桁を入力した後、アドレス検索ボタンをクリックしてください", "stuff.detail.prefId": "都道府県 / 住所 ", "stuff.detail.areaId": "発電量シミュレーション地域 ", - "stuff.detail.windSpeed": "基準風速", - "stuff.detail.windSpeedSpan": "m/s以下", + "stuff.detail.standardWindSpeedId": "基準風速", + "stuff.detail.standardWindSpeedIdSpan": "m/s以下", "stuff.detail.btn.windSpeedPop": "風速選択", "stuff.detail.verticalSnowCover": "垂直説説", "stuff.detail.coldRegionFlg": "寒冷地対策施行", @@ -516,8 +517,11 @@ "stuff.detail.btn.moveList": "商品リスト", "stuff.detail.btn.save": "保存", "stuff.detail.btn.tempSave": "一時保存", + "stuff.detail.save": "保存しました", + "stuff.detail.noChgData": "変更内容はありません", "stuff.detail.save.valierror1": "垂直説説は0より大きい値を入力してください", "stuff.detail.save.valierror2": "設置高さ0より大きい値を入力してください", + "stuff.detail.save.valierror3": "{0} 必須入力項目です.", "stuff.planReqPopup.popTitle": "設計依頼検索", "stuff.planReqPopup.btn1": "検索", "stuff.planReqPopup.btn2": "初期化", diff --git a/src/locales/ko.json b/src/locales/ko.json index 651e8473..529dc494 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -482,10 +482,11 @@ "stuff.detail.header.createDatetime": "등록일", "stuff.detail.required": "필수 입력항목", "stuff.detail.planReqNo": "설계의뢰No.", - "stuff.detail.dispCompanyName": "담당자", + "stuff.detail.receiveUser": "담당자", "stuff.detail.objectStatusId": "물건구분/물건명", "stuff.detail.objectStatus0": "신축", "stuff.detail.objectStatus1": "기축", + "stuff.detail.objectNameOmit": "경칭", "stuff.detail.objectNameKana": "물건명 후리가나", "stuff.detail.saleStoreId": "1차 판매점명 / ID", "stuff.detail.otherSaleStoreId": "2차 판매점명 / ID", @@ -494,8 +495,8 @@ "stuff.detail.btn.addressPop.guide": "※ 주소검색 버튼을 클릭한 후, 도도부현 정보를 선택해주십시오.", "stuff.detail.prefId": "도도부현 / 주소", "stuff.detail.areaId": "발전량시뮬레이션지역", - "stuff.detail.windSpeed": "기준풍속", - "stuff.detail.windSpeedSpan": "m/s이하", + "stuff.detail.standardWindSpeedId": "기준풍속", + "stuff.detail.standardWindSpeedIdSpan": "m/s이하", "stuff.detail.btn.windSpeedPop": "풍속선택", "stuff.detail.verticalSnowCover": "수직적설량", "stuff.detail.coldRegionFlg": "한랭지대책시행", @@ -521,8 +522,11 @@ "stuff.detail.btn.moveList": "물건목록", "stuff.detail.btn.save": "저장", "stuff.detail.btn.tempSave": "임시저장", + "stuff.detail.save": "저장되었습니다", + "stuff.detail.noChgData": "변경된 내용이 없습니다", "stuff.detail.save.valierror1": "수직적설량은 0보다 큰 값을 입력하세요", "stuff.detail.save.valierror2": "설치높이는 0보다 큰 값을 입력하세요", + "stuff.detail.save.valierror3": "{0} 필수 입력 항목입니다.", "stuff.planReqPopup.popTitle": "설계 요청 검색", "stuff.planReqPopup.btn1": "검색", "stuff.planReqPopup.btn2": "초기화", From 2d0d96d0cd72bd199ab7d58acc80e8e435fd0d45 Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:54:24 +0900 Subject: [PATCH 080/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 9 +++++++-- src/styles/_main.scss | 5 +++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index 70bd9f40..c242a96b 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -309,12 +309,12 @@ padding-top: 46.8px; transition: all .17s ease-in-out; .canvas-frame{ - height: 86.3vh; + height: calc(100vh - 129.3px); } &.active{ padding-top: calc(46.8px + 50px); .canvas-frame{ - height: 81vh; + height: calc(100vh - 179.4px); } } } @@ -1024,6 +1024,7 @@ display: flex; padding: 20px; .simulation-tit-wrap{ + flex: none; padding-right: 40px; border-right: 1px solid #EEEEEE; span{ @@ -1047,6 +1048,7 @@ } } .simulation-guide-box{ + flex: 1; padding-left: 40px; dl{ margin-bottom: 25px; @@ -1066,6 +1068,9 @@ margin-bottom: 0; } } + ul, ol{ + list-style: unset; + } } } diff --git a/src/styles/_main.scss b/src/styles/_main.scss index ea9b8833..b8783c3b 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -405,10 +405,15 @@ display: flex; align-items: center; border: 1px solid #E5E9EF; + border-radius: 4px; height: 45px; padding-left: 40px; padding-right: 15px; margin-bottom: 15px; + transition: border .15s ease-in-out; + &.focus{ + border-color: #A8B6C7; + } .login-input{ flex: 1; height: 100%; From 6f75e25fb98fd1134a1e089c97eaeb5a22180798 Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:55:58 +0900 Subject: [PATCH 081/139] =?UTF-8?q?-=20=EB=B3=B4=EC=A1=B0=EC=84=A0=20?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EC=B6=94=EA=B0=80=20-=20=EC=B9=98?= =?UTF-8?q?=EC=88=98=EC=84=A0=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?-=20=EA=B1=B0=EB=A6=AC=20=EC=B8=A1=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20=EB=8F=84=EB=A8=B8=20=EC=98=A4=ED=94=84?= =?UTF-8?q?=EC=85=8B=20=EC=B6=94=EA=B0=80=20-=20=ED=9D=90=EB=A6=84=20?= =?UTF-8?q?=EB=B0=A9=ED=96=A5=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20?= =?UTF-8?q?-=20=EC=84=A0=20=EC=86=8D=EC=84=B1=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80=20-=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80=20-=20=EB=8F=84?= =?UTF-8?q?=EB=A8=B8=20=ED=81=AC=EA=B8=B0=20=EB=B3=80=EA=B2=BD=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/auxiliary/AuxiliaryCopy.jsx | 55 +++++++ .../dimensionLine/DimensionLineSetting.jsx | 74 +++++++++ .../floor-plan/modal/distance/Distance.jsx | 67 ++++++++ .../flowDirection/FlowDirectionSetting.jsx | 150 ++++++++++++++++++ .../lineProperty/LinePropertySetting.jsx | 104 ++++++++++++ .../floor-plan/modal/object/DormerOffset.jsx | 55 +++++++ .../modal/object/RoofMaterialSetting.jsx | 45 ++++++ .../floor-plan/modal/object/SizeSetting.jsx | 71 +++++++++ 8 files changed, 621 insertions(+) create mode 100644 src/components/floor-plan/modal/auxiliary/AuxiliaryCopy.jsx create mode 100644 src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx create mode 100644 src/components/floor-plan/modal/distance/Distance.jsx create mode 100644 src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx create mode 100644 src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx create mode 100644 src/components/floor-plan/modal/object/DormerOffset.jsx create mode 100644 src/components/floor-plan/modal/object/RoofMaterialSetting.jsx create mode 100644 src/components/floor-plan/modal/object/SizeSetting.jsx diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryCopy.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryCopy.jsx new file mode 100644 index 00000000..b88d7a3b --- /dev/null +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryCopy.jsx @@ -0,0 +1,55 @@ +import { useMessage } from '@/hooks/useMessage' +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' + +export default function AuxiliaryCopy(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + return ( + +
    +
    +

    補助線のコピー

    + +
    +
    +
    コピーする方向を入力してください
    +
    +
    +
    +

    長さ

    +
    +
    + +
    + mm +
    +
    +
    + +
    + mm +
    +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx new file mode 100644 index 00000000..57fe3364 --- /dev/null +++ b/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx @@ -0,0 +1,74 @@ +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { useMessage } from '@/hooks/useMessage' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import QSelectBox from '@/components/common/select/QSelectBox' + +export default function DimensionLineSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, setIsShow, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] + return ( + +
    +
    +

    表示の変更

    + +
    +
    +
    寸法線に表示する数値を入力してください
    +
    +
    +
    + 既存の長さ +
    + +
    +
    +
    +
    + 変更の長さ +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    傾斜を着せてください。
    +
    +
    + 傾斜 +
    + +
    + 寸法 +
    +
    + 傾斜 +
    + +
    + 寸法 +
    +
    +
    傾き設定されている場合、入力した数値に傾き計算をした数値が表示されます。
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/distance/Distance.jsx b/src/components/floor-plan/modal/distance/Distance.jsx new file mode 100644 index 00000000..06a7a483 --- /dev/null +++ b/src/components/floor-plan/modal/distance/Distance.jsx @@ -0,0 +1,67 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' +import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' + +export default function Distance(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition, distance } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + + return ( + +
    +
    +

    距離測定

    + +
    +
    +
    +
    +
    +
    2点間距離
    +
    +
    +
    + +
    + mm +
    +
    +
    +
    +
    水平距離
    +
    +
    +
    + +
    + mm +
    +
    +
    +
    +
    垂直距離
    +
    +
    +
    + +
    + mm +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx new file mode 100644 index 00000000..ff749a6f --- /dev/null +++ b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx @@ -0,0 +1,150 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' +import { useState } from 'react' +import QSelectBox from '@/components/common/select/QSelectBox' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' + +const SelectOption01 = [{ name: 'M' }, { name: 'M' }, { name: 'M' }, { name: 'M' }] + +export default function FlowDirectionSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + const [compasDeg, setCompasDeg] = useState(0) + return ( + +
    +
    +

    面フローの設定

    + +
    +
    +
    +
    +
    流れ方向の設定
    +
    流れ方向を選択してください。
    +
    +
    + + ドン + + 立つ + + + + +
    +
    +
    +
    +
    方位設定
    +
    シミュレーション計算の方向を指定します。面が向いている方位を選択してください。
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + + +
    +
    +
    +
    +
    setCompasDeg(180)}> + 13 +
    +
    setCompasDeg(195)}> + 12 +
    +
    setCompasDeg(210)}> + 11 +
    +
    setCompasDeg(225)}> + 10 +
    +
    setCompasDeg(240)}> + 9 +
    +
    setCompasDeg(255)}> + 8 +
    +
    setCompasDeg(270)}> + 7 +
    +
    setCompasDeg(285)}> + 6 +
    +
    setCompasDeg(300)}> + 5 +
    +
    setCompasDeg(315)}> + 4 +
    +
    setCompasDeg(330)}> + 3 +
    +
    setCompasDeg(345)}> + 2 +
    +
    setCompasDeg(0)}> + 1 +
    +
    setCompasDeg(15)}> + 24 +
    +
    setCompasDeg(30)}> + 23 +
    +
    setCompasDeg(45)}> + 22 +
    +
    setCompasDeg(60)}> + 21 +
    +
    setCompasDeg(75)}> + 20 +
    +
    setCompasDeg(90)}> + 19 +
    +
    setCompasDeg(105)}> + 18 +
    +
    setCompasDeg(120)}> + 17 +
    +
    setCompasDeg(135)}> + 16 +
    +
    setCompasDeg(150)}> + 15 +
    +
    setCompasDeg(165)}> + 14 +
    +
    +
    +
    +
    +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx b/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx new file mode 100644 index 00000000..16871a19 --- /dev/null +++ b/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx @@ -0,0 +1,104 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' + +export default function LinePropertySetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + return ( + +
    +
    +

    各辺属性の変更

    + +
    +
    +
    + 属性を変更する辺を選択してください。 + 選択した値 [龍丸] +
    +
    +
    設定
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/object/DormerOffset.jsx b/src/components/floor-plan/modal/object/DormerOffset.jsx new file mode 100644 index 00000000..442e92df --- /dev/null +++ b/src/components/floor-plan/modal/object/DormerOffset.jsx @@ -0,0 +1,55 @@ +import { useMessage } from '@/hooks/useMessage' +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { usePopup } from '@/hooks/usePopup' + +export default function DormerOffset(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + return ( + +
    +
    +

    도머 오프셋

    + +
    +
    +
    移動する方向を入力してください
    +
    +
    +
    +

    長さ

    +
    +
    + +
    + mm +
    +
    +
    + +
    + mm +
    +
    +
    + + + + +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/object/RoofMaterialSetting.jsx b/src/components/floor-plan/modal/object/RoofMaterialSetting.jsx new file mode 100644 index 00000000..01d6f773 --- /dev/null +++ b/src/components/floor-plan/modal/object/RoofMaterialSetting.jsx @@ -0,0 +1,45 @@ +'use client' + +import { useRecoilValue } from 'recoil' +import { useMessage } from '@/hooks/useMessage' +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { contextPopupPositionState } from '@/store/popupAtom' +import QSelectBox from '@/components/common/select/QSelectBox' + +export default function RoofMaterialSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const { closePopup } = usePopup() + const roofMaterials = [ + { name: '기와1', value: 'material1' }, + { name: '기와2', value: 'material2' }, + { name: '기와3', value: 'material3' }, + { name: '기와4', value: 'material4' }, + { name: '기와5', value: 'material5' }, + ] + + return ( + +
    +
    +

    変更

    + +
    +
    +
    +
    + +
    +
    +
    + +
    +
    +
    +
    + ) +} diff --git a/src/components/floor-plan/modal/object/SizeSetting.jsx b/src/components/floor-plan/modal/object/SizeSetting.jsx new file mode 100644 index 00000000..ca7d4773 --- /dev/null +++ b/src/components/floor-plan/modal/object/SizeSetting.jsx @@ -0,0 +1,71 @@ +'use client' + +import { useRecoilValue } from 'recoil' +import { useMessage } from '@/hooks/useMessage' +import { canvasState } from '@/store/canvasAtom' +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { contextPopupPositionState } from '@/store/popupAtom' +import { useState } from 'react' + +export default function SizeSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const [settingTarget, setSettingTarget] = useState(1) + const { id, pos = contextPopupPosition } = props + const { getMessage } = useMessage() + const canvas = useRecoilValue(canvasState) + const { closePopup } = usePopup() + + return ( + +
    +
    +

    サイズ変更

    + +
    +
    +
    +
    +
    +
    + + mm +
    +
    + + mm +
    +
    +
    +
    +
    +
    +
    + + mm +
    +
    + + mm +
    +
    +
    +
    + + + + +
    +
    +
    +
    +
    + +
    +
    +
    +
    + ) +} From 4eb24971392a71a90d52bd45d0294d1dd09986d2 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 24 Oct 2024 17:57:38 +0900 Subject: [PATCH 082/139] =?UTF-8?q?fix:=20=ED=8E=98=EC=9D=B4=EC=A7=95=20?= =?UTF-8?q?=EB=8B=A8=EC=9C=84=20=EB=84=98=EA=B8=B0=EA=B8=B0=20=EB=B2=84?= =?UTF-8?q?=ED=8A=BC=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 다음 단위 없는데도 넘어가는 현상 수정 --- src/components/Playground.jsx | 2 +- src/components/common/pagination/QPagination.jsx | 2 +- src/hooks/usePagination.js | 9 +++++++++ 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 3bdb7ccb..d1061306 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -138,7 +138,7 @@ export default function Playground() { pageNo: 1, pageSize: 10, pagePerBlock: 10, - totalCount: 501, + totalCount: 26, handleChangePage: (page) => { console.log('page', page) }, diff --git a/src/components/common/pagination/QPagination.jsx b/src/components/common/pagination/QPagination.jsx index 7eb6638a..c6cab52d 100644 --- a/src/components/common/pagination/QPagination.jsx +++ b/src/components/common/pagination/QPagination.jsx @@ -31,7 +31,7 @@ export default function QPagination(props) { diff --git a/src/hooks/usePagination.js b/src/hooks/usePagination.js index 7d76d293..c0a9ea50 100644 --- a/src/hooks/usePagination.js +++ b/src/hooks/usePagination.js @@ -28,6 +28,15 @@ const usePagination = ({ pageNo = 1, pageSize = 10, pagePerBlock = 10, totalCoun return i + startPage }) + // console.log('pageRange', pageRange) + // console.log('startPage', startPage) + // console.log('endPage', endPage) + // console.log('totalPages', totalPages) + // console.log('pageGroup', pageGroup) + // console.log('pagePerBlock', pagePerBlock) + // console.log('currentPage', currentPage) + // console.log('pageNo', pageNo) + return { currentPage, changePage, pageGroup, totalPages, pages, startPage, endPage, pageRange } } From 4aac7c650f6f6ab2d675e032de0e895934076d7a Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:57:40 +0900 Subject: [PATCH 083/139] =?UTF-8?q?context=20menu=20=EC=9C=84=EC=B9=98=20?= =?UTF-8?q?=EC=A1=B0=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/color-picker/ColorPickerModal.jsx | 17 +- src/components/common/font/FontSetting.jsx | 11 +- src/components/floor-plan/CanvasFrame.jsx | 7 +- src/components/floor-plan/FloorPlan.jsx | 4 +- .../modal/auxiliary/AuxiliaryMove.jsx | 12 +- .../modal/auxiliary/AuxiliarySize.jsx | 12 +- .../floor-plan/modal/grid/GridCopy.jsx | 11 +- .../floor-plan/modal/grid/GridMove.jsx | 11 +- .../roofAllocation/RoofAllocationSetting.jsx | 6 +- src/hooks/common/useCommonUtils.js | 28 ++- .../roofcover/useRoofAllocationSetting.js | 6 + src/hooks/useContextMenu.js | 194 ++++++++++++++++-- src/hooks/usePopup.js | 6 - src/store/popupAtom.js | 9 + 14 files changed, 277 insertions(+), 57 deletions(-) diff --git a/src/components/common/color-picker/ColorPickerModal.jsx b/src/components/common/color-picker/ColorPickerModal.jsx index 22a3c5c4..add20a7e 100644 --- a/src/components/common/color-picker/ColorPickerModal.jsx +++ b/src/components/common/color-picker/ColorPickerModal.jsx @@ -3,9 +3,12 @@ import ColorPicker from '@/components/common/color-picker/ColorPicker' import { useMessage } from '@/hooks/useMessage' import { useEffect, useState } from 'react' import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function ColorPickerModal(props) { - const { isShow, setIsShow, pos = { x: 770, y: -815 }, color = '#ff0000', setColor, id } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) // 현재 메뉴 + const { isShow, setIsShow, pos = contextPopupPosition, color = '#ff0000', setColor, id } = props const { getMessage } = useMessage() const [originColor, setOriginColor] = useState(color) const { closePopup } = usePopup() @@ -15,14 +18,17 @@ export default function ColorPickerModal(props) { }, [isShow]) return ( - +

    {getMessage('modal.color.picker.title')}

    ) } diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 655c7340..bc95d9b3 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -5,14 +5,13 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' -import '@/styles/contents.scss' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import CanvasLayout from '@/components/floor-plan/CanvasLayout' +import '@/styles/contents.scss' export default function FloorPlan() { const globalLocaleState = useRecoilValue(globalLocaleStore) const { get } = useAxios(globalLocaleState) - const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 @@ -23,7 +22,6 @@ export default function FloorPlan() { menuNumber, setMenuNumber, } - useEffect(() => { console.log('FloorPlan useEffect 실행') fetchSettings() diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx index 28674c07..9b4beb8f 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx @@ -1,14 +1,20 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { usePopup } from '@/hooks/usePopup' -export default function AuxiliaryMove({ setCurrentContextMenu }) { +export default function AuxiliaryMove(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

    補助線の移動

    -
    diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx index c562e8dd..49cd2570 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliarySize.jsx @@ -1,14 +1,20 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' -export default function AuxiliarySize({ setCurrentContextMenu }) { +export default function AuxiliarySize(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

    補助線サイズ変更

    -
    diff --git a/src/components/floor-plan/modal/grid/GridCopy.jsx b/src/components/floor-plan/modal/grid/GridCopy.jsx index a6709d09..0f2bfc22 100644 --- a/src/components/floor-plan/modal/grid/GridCopy.jsx +++ b/src/components/floor-plan/modal/grid/GridCopy.jsx @@ -1,16 +1,21 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function GridCopy(props) { - const { setShowGridMoveModal, setShowGridCopyModal } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

    {getMessage('modal.grid.copy')}

    -
    diff --git a/src/components/floor-plan/modal/grid/GridMove.jsx b/src/components/floor-plan/modal/grid/GridMove.jsx index db226872..6d901fe3 100644 --- a/src/components/floor-plan/modal/grid/GridMove.jsx +++ b/src/components/floor-plan/modal/grid/GridMove.jsx @@ -1,16 +1,21 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { useMessage } from '@/hooks/useMessage' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' export default function GridMove(props) { - const { setShowGridMoveModal, setShowGridCopyModal } = props + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() + const { closePopup } = usePopup() return ( - +

    {getMessage('modal.grid.move')}

    -
    diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index 934f2f9d..c6afa44d 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -3,8 +3,12 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { useRoofAllocationSetting } from '@/hooks/roofcover/useRoofAllocationSetting' import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' -export default function RoofAllocationSetting({ id, pos = { x: 50, y: 230 } }) { +export default function RoofAllocationSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() const { closePopup } = usePopup() const { handleSave, onAddRoofMaterial, onDeleteRoofMaterial, values, roofMaterials, selectedRoofMaterial, setSelectedRoofMaterial } = diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index dd92253d..7cb605bd 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -4,11 +4,15 @@ import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' import { checkLineOrientation, getDistance } from '@/util/canvas-util' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' +import { v4 as uuidv4 } from 'uuid' +import { usePopup } from '@/hooks/usePopup' +import Distance from '@/components/floor-plan/modal/distance/Distance' export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionState }) { const wordDisplay = useRecoilValue(wordDisplaySelector) const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const dimensionSettings = useRecoilValue(dimensionLineSettingsState) + const { addPopup } = usePopup() useEffect(() => { initEvent() @@ -98,7 +102,8 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS const lineOptions = { stroke: dimensionSettings.color, strokeWidth: dimensionSettings.pixel, - selectable: false, + name: 'dimensionLine', + selectable: true, } // 캔버스에 클릭 이벤트 추가 @@ -273,6 +278,7 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS const pointer = canvas.getPointer(options.e) let point + console.log(options) if (points.length === 0) { // 첫 번째 포인트는 그대로 클릭한 위치에 추가 point = new fabric.Circle({ @@ -285,7 +291,6 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS } else if (points.length === 1) { // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 const p1 = points[0] - point = new fabric.Circle({ left: pointer.x - 5, // 반지름 반영 top: pointer.y - 5, // 반지름 반영 @@ -313,9 +318,9 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS canvas.add(line2) canvas.add(line3) - const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) - const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) - const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + const distance1 = getDistance(p1CenterX, p1CenterY, p2CenterX, p2CenterY) // 대각선 + const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) // 수직거리 + const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) // 수평거리 // 거리 텍스트가 이미 있으면 업데이트하고, 없으면 새로 생성 distanceText = new fabric.Text(`${distance1 * 10}`, { @@ -339,6 +344,19 @@ export function useCommonUtils({ canvas, commonFunctionState, setCommonFunctionS // 거리 계산 후, 다음 측정을 위해 초기화 points = [] + const id = uuidv4() + addPopup( + id, + 1, + , + ) } // 캔버스 다시 그리기 diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 9ac4c2aa..3f355111 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -86,6 +86,12 @@ export function useRoofAllocationSetting(id) { swalFire({ text: '할당할 지붕이 없습니다.' }) closePopup(id) } + // if (type === 'roofBase') { + // // 지붕면 할당 + // + // } else if ('roof') { + // // 지붕재 변경 + // } }, []) const onAddRoofMaterial = () => { diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 4451c259..bbd5115b 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -1,18 +1,36 @@ -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { currentMenuState, currentObjectState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' import { MENU } from '@/common/common' import AuxiliaryMove from '@/components/floor-plan/modal/auxiliary/AuxiliaryMove' import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize' +import { usePopup } from '@/hooks/usePopup' +import { v4 as uuidv4 } from 'uuid' +import GridMove from '@/components/floor-plan/modal/grid/GridMove' +import GridCopy from '@/components/floor-plan/modal/grid/GridCopy' +import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal' +import { gridColorState } from '@/store/gridAtom' +import { contextPopupPositionState } from '@/store/popupAtom' +import AuxiliaryCopy from '@/components/floor-plan/modal/auxiliary/AuxiliaryCopy' +import SizeSetting from '@/components/floor-plan/modal/object/SizeSetting' +import RoofMaterialSetting from '@/components/floor-plan/modal/object/RoofMaterialSetting' +import DormerOffset from '@/components/floor-plan/modal/object/DormerOffset' +import FontSetting from '@/components/common/font/FontSetting' +import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/DimensionLineSetting' +import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' +import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting' +import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' export function useContextMenu({ externalFn }) { - const currentMenu = useRecoilValue(currentMenuState) - const [contextMenu, setContextMenu] = useState([[]]) - const [currentContextMenu, setCurrentContextMenu] = useState(null) + const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 + const setContextPopupPosition = useSetRecoilState(contextPopupPositionState) // 현재 메뉴 + const [contextMenu, setContextMenu] = useState([[]]) // 메뉴.object 별 context menu + const [currentContextMenu, setCurrentContextMenu] = useState(null) // 선택한 contextMenu const currentObject = useRecoilValue(currentObjectState) - - const currentMenuSetting = () => { - console.log(currentMenu) + const { addPopup } = usePopup() + const [popupId, setPopupId] = useState(uuidv4()) + const [gridColor, setGridColor] = useRecoilState(gridColorState) + const currentMenuSetting = (position) => { switch (currentMenu) { case MENU.PLAN_DRAWING: setContextMenu([ @@ -20,14 +38,17 @@ export function useContextMenu({ externalFn }) { { id: 'gridMove', name: '그리드 이동', + component: , }, { id: 'gridCopy', name: '그리드 복사', + component: , }, { id: 'gridColorEdit', name: '그리드 색 변경', + component: , }, { id: 'remove', @@ -84,16 +105,17 @@ export function useContextMenu({ externalFn }) { { id: 'sizeEdit', name: '사이즈 변경', - component: , + component: , }, { id: 'auxiliaryMove', name: '보조선 이동(M)', - component: , + component: , }, { id: 'auxiliaryCopy', name: '보조선 복사(C)', + component: , }, { id: 'auxiliaryRemove', @@ -160,19 +182,35 @@ export function useContextMenu({ externalFn }) { break } } - useEffect(() => { - currentMenuSetting() - }, [currentMenu]) + + const handleClick = (e, menu) => { + setContextPopupPosition({ + x: e.clientX, + y: e.clientY, + }) + setCurrentContextMenu(menu) + } useEffect(() => { + currentMenuSetting() + }, [gridColor, currentMenu]) + + useEffect(() => { + if (currentContextMenu?.component) addPopup(popupId, 1, currentContextMenu?.component) + }, [currentContextMenu]) + + useEffect(() => { + console.log('object name', currentObject?.name) if (currentObject?.name) { switch (currentObject.name) { case 'triangleDormer': + case 'pentagonDormer': setContextMenu([ [ { id: 'sizeEdit', name: '사이즈 변경', + component: , }, { id: 'dormerRemove', @@ -189,10 +227,12 @@ export function useContextMenu({ externalFn }) { { id: 'roofMaterialEdit', name: '지붕재 변경', + component: , }, { id: 'dormerOffset', name: '도머 오프셋', + component: , }, ], ]) @@ -203,6 +243,7 @@ export function useContextMenu({ externalFn }) { { id: 'sizeEdit', name: '사이즈 변경', + component: , }, { id: 'roofMaterialRemove', @@ -221,14 +262,17 @@ export function useContextMenu({ externalFn }) { { id: 'roofMaterialEdit', name: '지붕재 변경', + component: , }, { id: 'linePropertyEdit', name: '각 변 속성 변경', + component: , }, { id: 'flowDirectionEdit', name: '흐름 뱡향 변경', + component: , }, ], ]) @@ -259,6 +303,127 @@ export function useContextMenu({ externalFn }) { ], ]) break + case 'lengthText': + setContextMenu([ + [ + { + id: 'lengthTextRemove', + name: '삭제', + }, + { + id: 'lengthTextMove', + name: '이동', + }, + { + id: 'lengthTextAuxiliaryLineEdit', + name: '치수 보조선 변경', + }, + { + id: 'displayEdit', + name: '표시 변경', + }, + ], + ]) + break + case 'commonText': + setContextMenu([ + [ + { + id: 'commonTextRemove', + name: '삭제', + }, + { + id: 'commonTextMove', + name: '이동', + }, + { + id: 'commonTextCopy', + name: '복사', + }, + { + id: 'commonTextFontSetting', + name: '폰트 설정', + component: , + }, + { + id: 'commonTextEdit', + name: '편집', + }, + ], + ]) + break + case 'lineGrid': + setContextMenu([ + [ + { + id: 'gridMove', + name: '그리드 이동', + }, + { + id: 'gridCopy', + name: '그리드 복사', + }, + { + id: 'gridColorEdit', + name: '그리드 색 변경', + }, + { + id: 'remove', + name: '삭제', + }, + { + id: 'removeAll', + name: '전체 삭제', + }, + ], + ]) + break + case 'dimensionLine': + setContextMenu([ + [ + { + id: 'dimensionLineRemove', + name: '삭제', + }, + { + id: 'dimensionLineMove', + name: '이동', + }, + { + id: 'dimensionAuxiliaryLineEdit', + name: '치수 보조선 변경', + }, + { + id: 'dimensionLineDisplayEdit', + name: '표시 변경', + component: , + }, + ], + ]) + break + case 'shadow': + setContextMenu([ + [ + { + id: 'sizeEdit', + name: '사이즈 변경', + component: , + }, + { + id: 'remove', + name: '삭제(D)', + }, + { + id: 'move', + name: '이동(M)', + }, + { + id: 'copy', + name: '복사(C)', + }, + ], + ]) + break default: currentMenuSetting() } @@ -267,13 +432,10 @@ export function useContextMenu({ externalFn }) { } }, [currentObject]) - useEffect(() => { - console.log(currentContextMenu) - }, [currentContextMenu]) - return { contextMenu, currentContextMenu, setCurrentContextMenu, + handleClick, } } diff --git a/src/hooks/usePopup.js b/src/hooks/usePopup.js index b54492b9..37730ec5 100644 --- a/src/hooks/usePopup.js +++ b/src/hooks/usePopup.js @@ -1,20 +1,14 @@ import { useRecoilState } from 'recoil' import { popupState } from '@/store/popupAtom' -import { useEffect } from 'react' export function usePopup() { const [popup, setPopup] = useRecoilState(popupState) - useEffect(() => { - console.log(popup) - }, [popup]) - const addPopup = (id, depth, component) => { setPopup({ children: [...filterDepth(depth), { id: id, depth: depth, component: component }] }) } const closePopup = (id) => { - console.log(id) setPopup({ children: [...filterChildrenPopup(id).filter((child) => child.id !== id)] }) } diff --git a/src/store/popupAtom.js b/src/store/popupAtom.js index 78de8660..498f4eed 100644 --- a/src/store/popupAtom.js +++ b/src/store/popupAtom.js @@ -11,3 +11,12 @@ export const popupState = atom({ }, dangerouslyAllowMutability: true, }) + +export const contextPopupPositionState = atom({ + key: 'contextPopupPositionState', + default: { + x: 50, + y: 180, + }, + dangerouslyAllowMutability: true, +}) From e9c558fdf9c5968620a5b4f7da295fadd6855b70 Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:57:53 +0900 Subject: [PATCH 084/139] =?UTF-8?q?=EC=B9=98=EC=88=98=EC=84=A0=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/dictionary.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/dictionary.txt b/docs/dictionary.txt index 0864da77..6e81da01 100644 --- a/docs/dictionary.txt +++ b/docs/dictionary.txt @@ -24,4 +24,4 @@ Allpainted : allPainted 개구: openSpace 도머: dormer 그림자: shadow - +치수선: dimensionLine \ No newline at end of file From a250507ab951a6650793f17215f69b6a9e654e47 Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:58:13 +0900 Subject: [PATCH 085/139] =?UTF-8?q?selectbox=20key=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/select/QSelectBox.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index d0538f1d..ee101898 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -20,7 +20,7 @@ export default function QSelectBox({ title = '', options, onChange, value }) {
      {options?.map((option) => (
    • handleClickSelectOption(option)}> - +
    • ))}
    From a41fe47387cdc476faeaa70666d29939eb1cd54c Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 17:58:36 +0900 Subject: [PATCH 086/139] =?UTF-8?q?=EB=B0=A9=EC=9C=84=20=EB=B2=94=EC=9C=84?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/basic/step/Orientation.jsx | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx index 3ef15a21..98e10c0c 100644 --- a/src/components/floor-plan/modal/basic/step/Orientation.jsx +++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx @@ -6,6 +6,19 @@ export default function Orientation({ setTabNum }) { const [compasDeg, setCompasDeg] = useState(0) const [hasAnglePassivity, setHasAnglePassivity] = useState(false) + const getDegree = (degree) => { + if (degree % 15 === 0) return degree + + let value = Math.floor(degree / 15) + const remain = ((degree / 15) % 1).toFixed(5) + + if (remain > 0.4) { + value++ + } + + return value * 15 + } + return ( <>
    @@ -18,7 +31,7 @@ export default function Orientation({ setTabNum }) { {Array.from({ length: 180 / 15 }).map((dot, index) => (
    setCompasDeg(15 * (12 + index))} > {index === 0 && 180°} @@ -26,13 +39,13 @@ export default function Orientation({ setTabNum }) {
    ))} {Array.from({ length: 180 / 15 }).map((dot, index) => ( -
    setCompasDeg(15 * index)}> +
    setCompasDeg(15 * index)}> {index === 0 && } {index === 6 && 90°}
    ))}
    -
    +
    From d7651ce68efd2abecf4eb85183574a0a58c0af7e Mon Sep 17 00:00:00 2001 From: minsik Date: Thu, 24 Oct 2024 18:04:49 +0900 Subject: [PATCH 087/139] =?UTF-8?q?=EA=B1=B0=EB=A6=AC=20=EC=B8=A1=EC=A0=95?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCommonUtils.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 9384a354..ec6f3fc7 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -2,7 +2,7 @@ import { useEffect } from 'react' import { useRecoilValue } from 'recoil' import { wordDisplaySelector } from '@/store/settingAtom' import { useEvent } from '@/hooks/useEvent' -import { checkLineOrientation, getDistance, setSurfaceShapePattern } from '@/util/canvas-util' +import { checkLineOrientation, getDistance } from '@/util/canvas-util' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' import { fontSelector } from '@/store/fontAtom' import { canvasState } from '@/store/canvasAtom' @@ -376,23 +376,23 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) ...textOptions, }) canvas.add(distanceText) + const id = uuidv4() + addPopup( + id, + 1, + , + ) } // 거리 계산 후, 다음 측정을 위해 초기화 points = [] - const id = uuidv4() - addPopup( - id, - 1, - , - ) } // 캔버스 다시 그리기 From f69a473102f760c37043890a491d3da4d9748481 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 24 Oct 2024 18:24:56 +0900 Subject: [PATCH 088/139] =?UTF-8?q?=EC=BA=94=EB=B2=84=EC=8A=A4=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95=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/components/common/font/FontSetting.jsx | 3 +- .../floor-plan/modal/grid/DotLineGrid.jsx | 192 ++++-------------- src/hooks/common/useCanvasConfigInitialize.js | 63 ++++-- src/hooks/common/useGrid.js | 145 +++++++++++++ src/hooks/usePolygon.js | 17 +- 5 files changed, 244 insertions(+), 176 deletions(-) create mode 100644 src/hooks/common/useGrid.js diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index cbb2de00..48efa316 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,11 +1,10 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' -import { useEffect, useState } from 'react' +import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilState, useRecoilValue } from 'recoil' import { fontSelector, globalFontAtom } from '@/store/fontAtom' -import { useFont } from '@/hooks/common/useFont' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, diff --git a/src/components/floor-plan/modal/grid/DotLineGrid.jsx b/src/components/floor-plan/modal/grid/DotLineGrid.jsx index 6b63f3d7..4cd63b1f 100644 --- a/src/components/floor-plan/modal/grid/DotLineGrid.jsx +++ b/src/components/floor-plan/modal/grid/DotLineGrid.jsx @@ -17,17 +17,31 @@ const TYPE = { LINE: 'LINE', } +const defaultDotLineGridSetting = { + INTERVAL: { + type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격 + ratioInterval: 910, + verticalInterval: 910, + horizontalInterval: 910, + dimension: 1, // 치수 + }, + DOT: false, + LINE: false, +} + export default function DotLineGrid(props) { // const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 const [close, setClose] = useState(false) const { id, setIsShow, pos = { x: 840, y: -815 } } = props const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState) - const gridColor = useRecoilValue(gridColorState) + const canvas = useRecoilValue(canvasState) - const isGridDisplay = useRecoilValue(gridDisplaySelector) const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState) + const [currentSetting, setCurrentSetting] = useState( + JSON.stringify(dotLineGridSetting) === JSON.stringify(defaultDotLineGridSetting) ? { ...defaultDotLineGridSetting } : { ...dotLineGridSetting }, + ) const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState) const interval = useRecoilValue(dotLineIntervalSelector) @@ -70,7 +84,7 @@ export default function DotLineGrid(props) { const handleCheckBoxChange = (e) => { const { value, checked } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, [value]: checked, @@ -101,160 +115,35 @@ export default function DotLineGrid(props) { setSelectOption(matchedOption) // 서버에서 받은 데이터로 상태 업데이트 - setDotLineGridSettingState(patternData) + setCurrentSetting(patternData) } catch (error) { console.error('Data fetching error:', error) } } const handleSave = async () => { - if (!dotLineGridSetting.DOT && !dotLineGridSetting.LINE) { + if (!currentSetting.DOT && !currentSetting.LINE) { swalFire({ text: '배치할 그리드를 설정해주세요.' }) return } try { const patternData = { objectNo, - dotGridDisplay: dotLineGridSetting.DOT, - lineGridDisplay: dotLineGridSetting.LINE, - gridType: dotLineGridSetting.INTERVAL.type, - gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10, - gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10, - gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, - gridDimen: dotLineGridSetting.INTERVAL.dimension, + dotGridDisplay: currentSetting.DOT, + lineGridDisplay: currentSetting.LINE, + gridType: currentSetting.INTERVAL.type, + gridHorizon: currentSetting.INTERVAL.horizontalInterval / 10, + gridVertical: currentSetting.INTERVAL.verticalInterval / 10, + gridRatio: currentSetting.INTERVAL.ratioInterval / 10, + gridDimen: currentSetting.INTERVAL.dimension, } // HTTP POST 요청 보내기 await post({ url: `/api/canvas-management/canvas-grid-settings`, data: patternData }).then((res) => { swalFire({ text: getMessage(res.returnMessage) }) - - // 1. 점.선 그리드 설정으로 만들어진 기존 오브젝트 제거 - canvas - ?.getObjects() - .filter((obj) => obj.name === 'lineGrid') - .forEach((obj) => canvas?.remove(obj)) - canvas - ?.getObjects() - .filter((obj) => obj.name === 'dotGrid') - .forEach((obj) => canvas?.remove(obj)) - - //const horizontalInterval = interval.horizontalInterval - //const verticalInterval = interval.verticalInterval - - if (patternData.dotGridDisplay) { - const circle = new fabric.Circle({ - radius: 2, - fill: 'red', - strokeWidth: 0.7, - originX: 'center', - originY: 'center', - selectable: false, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - }) - - const patternSourceCanvas = new fabric.StaticCanvas(null, { - width: patternData.gridHorizon, - height: patternData.gridVertical, - }) - - patternSourceCanvas.add(circle) - - circle.set({ - left: patternSourceCanvas.width / 2, - top: patternSourceCanvas.height / 2, - }) - - patternSourceCanvas.renderAll() - - const pattern = new fabric.Pattern({ - source: patternSourceCanvas.getElement(), - repeat: 'repeat', - }) - - const backgroundPolygon = new fabric.Polygon( - [ - { x: 0, y: 0 }, - { x: canvas.width, y: 0 }, - { x: canvas.width, y: canvas.height }, - { x: 0, y: canvas.height }, - ], - { - fill: pattern, - selectable: false, - name: 'dotGrid', - visible: isGridDisplay, - }, - ) - - canvas.add(backgroundPolygon) - backgroundPolygon.sendToBack() - canvas.renderAll() - } - - if (patternData.lineGridDisplay) { - for (let i = 0; i < canvas.height / patternData.gridVertical + 1; i++) { - const horizontalLine = new fabric.Line( - [ - 0, - i * patternData.gridVertical - patternData.gridVertical / 2, - canvas.width, - i * patternData.gridVertical - patternData.gridVertical / 2, - ], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'lineGrid', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'horizontal', - visible: isGridDisplay, - }, - ) - canvas.add(horizontalLine) - } - - for (let i = 0; i < canvas.width / patternData.gridHorizon + 1; i++) { - const verticalLine = new fabric.Line( - [ - i * patternData.gridHorizon - patternData.gridHorizon / 2, - 0, - i * patternData.gridHorizon - patternData.gridHorizon / 2, - canvas.height, - ], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'lineGrid', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'vertical', - visible: isGridDisplay, - }, - ) - canvas.add(verticalLine) - } - } - - canvas.renderAll() + setDotLineGridSettingState({ ...currentSetting }) + closePopup(id) }) - setShowDotLineGridModal(false) - closePopup(id) } catch (error) { swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) } @@ -263,7 +152,7 @@ export default function DotLineGrid(props) { const handleRadioChange = (e) => { const { value, name, checked, selected } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -276,7 +165,7 @@ export default function DotLineGrid(props) { const changeInput = (value, e) => { const { name } = e.target - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -289,7 +178,7 @@ export default function DotLineGrid(props) { const changeDimension = (result) => { const { value } = result - setDotLineGridSettingState((prev) => { + setCurrentSetting((prev) => { return { ...prev, INTERVAL: { @@ -310,6 +199,7 @@ export default function DotLineGrid(props) { ?.getObjects() .filter((obj) => obj.name === 'dotGrid') .forEach((obj) => canvas?.remove(obj)) + resetDotLineGridSetting() setSelectOption(SelectOption[0]) } @@ -332,11 +222,11 @@ export default function DotLineGrid(props) {
    - +
    - +
    @@ -349,8 +239,8 @@ export default function DotLineGrid(props) { id="ra01" value={1} onChange={handleRadioChange} - checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 1} - readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} + checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 1} + readOnly={!currentSetting.DOT && !currentSetting.LINE} />
    @@ -361,7 +251,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`horizontalInterval`} - value={dotLineGridSetting.INTERVAL.horizontalInterval} + value={currentSetting.INTERVAL.horizontalInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} />
    @@ -374,7 +264,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`verticalInterval`} - value={dotLineGridSetting.INTERVAL.verticalInterval} + value={currentSetting.INTERVAL.verticalInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} />
    @@ -389,8 +279,8 @@ export default function DotLineGrid(props) { id="ra02" value={2} onChange={handleRadioChange} - checked={(dotLineGridSetting.DOT || dotLineGridSetting.LINE) && dotLineGridSetting.INTERVAL.type === 2} - readOnly={!dotLineGridSetting.DOT && !dotLineGridSetting.LINE} + checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 2} + readOnly={!currentSetting.DOT && !currentSetting.LINE} />
    @@ -401,7 +291,7 @@ export default function DotLineGrid(props) { type="text" className="input-origin" name={`ratioInterval`} - value={dotLineGridSetting.INTERVAL.ratioInterval} + value={currentSetting.INTERVAL.ratioInterval} onChange={(e) => onlyNumberInputChange(e, changeInput)} />
    diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index 7421c53f..fd5d4542 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -1,12 +1,31 @@ -import { use, useEffect } from 'react' -import { useRecoilValue } from 'recoil' -import { settingModalFirstOptionsState } from '@/store/settingAtom' -import { canvasState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { roofDisplaySelector, settingModalFirstOptionsState } from '@/store/settingAtom' +import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' import { setSurfaceShapePattern } from '@/util/canvas-util' +import { useFont } from '@/hooks/common/useFont' +import { useGrid } from '@/hooks/common/useGrid' +import { globalFontAtom } from '@/store/fontAtom' export function useCanvasConfigInitialize() { const canvas = useRecoilValue(canvasState) - const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState) + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const roofDisplay = useRecoilValue(roofDisplaySelector) + const setGlobalFonts = useSetRecoilState(globalFontAtom) + const setDotLineGridSetting = useSetRecoilState(dotLineGridSettingState) + const {} = useFont() + const {} = useGrid() + + useEffect(() => { + if (!canvas) return + canvas + .getObjects() + .filter((polygon) => polygon.name === 'roof') + .forEach((polygon) => { + setSurfaceShapePattern(polygon, roofDisplay.column) + }) + canvas.renderAll() + }, [roofDisplay]) const canvasLoadInit = () => { roofInit() //화면표시 초기화 @@ -14,18 +33,32 @@ export function useCanvasConfigInitialize() { //치수표시, 화면표시, 글꼴등 초기화 const roofInit = () => { - if (canvas) { - const roofDisplay = settingModalFirstOptions.option2.filter((item) => item.selected) + setSettingModalFirstOptions((prev) => { + // ...prev에서 내부에 있는 option2 객체의 주소값도 다르게 만들어줘 + const option1 = prev.option1.map((option) => { + return { ...option } + }) + const option2 = prev.option2.map((option) => { + return { ...option } + }) + const dimensionDisplay = prev.dimensionDisplay.map((option) => { + return { ...option } + }) + return { ...prev, option1, option2, dimensionDisplay } + }) - canvas - .getObjects() - .filter((polygon) => polygon.name === 'roof') - .forEach((polygon) => { - setSurfaceShapePattern(polygon, roofDisplay[0].column) - }) + setDotLineGridSetting((prev) => { + return { ...prev } + }) - canvas.renderAll() - } + setGlobalFonts((prev) => { + const commonText = { ...prev.commonText } + const dimensionLineText = { ...prev.dimensionLineText } + const flowText = { ...prev.flowText } + const lengthText = { ...prev.lengthText } + const circuitNumberText = { ...prev.circuitNumberText } + return { commonText, dimensionLineText, flowText, lengthText, circuitNumberText } + }) } return { canvasLoadInit } diff --git a/src/hooks/common/useGrid.js b/src/hooks/common/useGrid.js new file mode 100644 index 00000000..0c6159dd --- /dev/null +++ b/src/hooks/common/useGrid.js @@ -0,0 +1,145 @@ +import { useRecoilValue } from 'recoil' +import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' +import { useEffect } from 'react' +import { gridColorState } from '@/store/gridAtom' +import { gridDisplaySelector } from '@/store/settingAtom' + +export function useGrid() { + const canvas = useRecoilValue(canvasState) + + const dotLineGridSetting = useRecoilValue(dotLineGridSettingState) + const gridColor = useRecoilValue(gridColorState) + const isGridDisplay = useRecoilValue(gridDisplaySelector) + + useEffect(() => { + if (!canvas) { + return + } + const patternData = { + dotGridDisplay: dotLineGridSetting.DOT, + lineGridDisplay: dotLineGridSetting.LINE, + gridType: dotLineGridSetting.INTERVAL.type, + gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10, + gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10, + gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, + gridDimen: dotLineGridSetting.INTERVAL.dimension, + } + + // 1. 점.선 그리드 설정으로 만들어진 기존 오브젝트 제거 + canvas + ?.getObjects() + .filter((obj) => obj.name === 'lineGrid') + .forEach((obj) => canvas?.remove(obj)) + canvas + ?.getObjects() + .filter((obj) => obj.name === 'dotGrid') + .forEach((obj) => canvas?.remove(obj)) + + //const horizontalInterval = interval.horizontalInterval + //const verticalInterval = interval.verticalInterval + + if (patternData.dotGridDisplay) { + const circle = new fabric.Circle({ + radius: 2, + fill: 'red', + strokeWidth: 0.7, + originX: 'center', + originY: 'center', + selectable: false, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + }) + + const patternSourceCanvas = new fabric.StaticCanvas(null, { + width: patternData.gridHorizon, + height: patternData.gridVertical, + }) + + patternSourceCanvas.add(circle) + + circle.set({ + left: patternSourceCanvas.width / 2, + top: patternSourceCanvas.height / 2, + }) + + patternSourceCanvas.renderAll() + + const pattern = new fabric.Pattern({ + source: patternSourceCanvas.getElement(), + repeat: 'repeat', + }) + + const backgroundPolygon = new fabric.Polygon( + [ + { x: 0, y: 0 }, + { x: canvas.width, y: 0 }, + { x: canvas.width, y: canvas.height }, + { x: 0, y: canvas.height }, + ], + { + fill: pattern, + selectable: false, + name: 'dotGrid', + visible: isGridDisplay, + }, + ) + + canvas.add(backgroundPolygon) + backgroundPolygon.sendToBack() + canvas.renderAll() + } + + if (patternData.lineGridDisplay) { + for (let i = 0; i < canvas.height / patternData.gridVertical + 1; i++) { + const horizontalLine = new fabric.Line( + [0, i * patternData.gridVertical - patternData.gridVertical / 2, canvas.width, i * patternData.gridVertical - patternData.gridVertical / 2], + { + stroke: gridColor, + strokeWidth: 1, + selectable: true, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'lineGrid', + strokeDashArray: [5, 2], + opacity: 0.3, + direction: 'horizontal', + visible: isGridDisplay, + }, + ) + canvas.add(horizontalLine) + } + + for (let i = 0; i < canvas.width / patternData.gridHorizon + 1; i++) { + const verticalLine = new fabric.Line( + [i * patternData.gridHorizon - patternData.gridHorizon / 2, 0, i * patternData.gridHorizon - patternData.gridHorizon / 2, canvas.height], + { + stroke: gridColor, + strokeWidth: 1, + selectable: true, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'lineGrid', + strokeDashArray: [5, 2], + opacity: 0.3, + direction: 'vertical', + visible: isGridDisplay, + }, + ) + canvas.add(verticalLine) + } + } + + canvas.renderAll() + }, [dotLineGridSetting]) + + return {} +} diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 71e49408..71ec1549 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -5,20 +5,20 @@ import { getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' +import { fontSelector } from '@/store/fontAtom' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) const isFlowDisplay = useRecoilValue(flowDisplaySelector) - const fontSize = useRecoilValue(fontSizeState) - const fontFamily = useRecoilValue(fontFamilyState) + const flowFontOptions = useRecoilValue(fontSelector('flowText')) + const lengthTextFontOptions = useRecoilValue(fontSelector('lengthText')) const addPolygon = (points, options) => { const polygon = new QPolygon(points, { ...options, + fontSize: lengthTextFontOptions.fontSize.value, fill: options.fill || 'transparent', stroke: options.stroke || '#000000', - fontSize: fontSize, - fontFamily: fontFamily, selectable: true, }) @@ -53,9 +53,8 @@ export const usePolygon = () => { const text = new fabric.Text(length.toString(), { left: midPoint.x, top: midPoint.y, - fontSize: fontSize, - fontFamily: fontFamily, parentId: polygon.id, + fontSize: lengthTextFontOptions.fontSize.value, minX: Math.min(start.x, end.x), maxX: Math.max(start.x, end.x), minY: Math.min(start.y, end.y), @@ -403,8 +402,10 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, { - fontSize: fontSize, - fill: 'black', + fontSize: flowFontOptions.fontSize.value, + fill: flowFontOptions.fontColor.value, + fontFamily: flowFontOptions.fontFamily.value, + fontWeight: flowFontOptions.fontWeight.value, originX: 'center', originY: 'center', name: 'flowText', From cc34dd78ee4c94811cdad4ae9bbede229eba6450 Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 08:44:55 +0900 Subject: [PATCH 089/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=95=20=EA=B0=AF=EC=88=98=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 9 ++------- src/components/management/StuffDetail.jsx | 6 +++--- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 4a7e3052..5771543f 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -25,7 +25,7 @@ export default function Stuff() { const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const { getMessage } = useMessage() const [pageNo, setPageNo] = useState(1) //현재 페이지 번호 - const [pageSize, setPageSize] = useState(5) //페이지 당 게시물 수 + const [pageSize, setPageSize] = useState(100) //페이지 당 게시물 수 const [totalCount, setTotalCount] = useState(0) //총 갯수 const [defaultSortType, setDefaultSortType] = useState('R') @@ -380,7 +380,6 @@ export default function Stuff() { // 페이징 현재페이지 변경 const handleChangePage = (page) => { - console.log('page:::', page) stuffSearchParams.code = 'S' setStuffSearch({ @@ -390,13 +389,9 @@ export default function Stuff() { endRow: page * pageSize, }) - // console.log('여기::::::::::::', page) setPageNo(page) } - // console.log('pageNo:::', pageNo) - // console.log('pageSize:::', pageSize) - // console.log('totalCount:::', totalCount) return ( <> {/* 퍼블시작 */} @@ -424,7 +419,7 @@ export default function Stuff() {
    diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 3ecd471f..d947da2b 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -226,12 +226,13 @@ export default function StuffDetail() { }, }, { - field: 'management', + field: 'estimateDate', headerName: getMessage('stuff.detail.planGridHeader.management'), width: 200, autoHeight: true, cellStyle: { justifyContent: 'center' }, - cellRenderer: () => { + cellRenderer: (params) => { + console.log('params::', params.value) return (
    - -
    + <> +
    + + +
    + ) }, }, From fc13c39fa456c69e53b4b6b7c61c795d64a1abfe Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 25 Oct 2024 09:10:41 +0900 Subject: [PATCH 091/139] =?UTF-8?q?=EC=B9=98=EC=88=98=EC=84=A0=20=EB=AA=A8?= =?UTF-8?q?=EB=8B=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCommonUtils.js | 83 +++++++++++++----------------- 1 file changed, 35 insertions(+), 48 deletions(-) diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index ec6f3fc7..70447ae8 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -254,13 +254,13 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) if (commonFunctionState.distance) { let points = [] let distanceText = null + let drawPoints = [] - const circleOptions = { - radius: 5, - strokeWidth: 2, - stroke: 'red', - fill: 'white', - selectable: false, + const crossOptions = { + stroke: 'black', + strokeWidth: 1, + originX: 'center', + originY: 'center', } const lineOptions = { @@ -286,23 +286,15 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) let cross = {} if (points.length === 0) { - point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], { - stroke: 'black', - strokeWidth: 1, - originX: 'center', - originY: 'center', - }) + point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], crossOptions) canvas.add(point) cross['x'] = parseInt(point.left.toFixed(0)) + drawPoints.push(point) // 세로 선 생성 (십자 모양의 다른 축) - point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], { - stroke: 'black', - strokeWidth: 1, - originX: 'center', - originY: 'center', - }) + point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], crossOptions) cross['y'] = parseInt(point.top.toFixed(0)) + drawPoints.push(point) canvas.add(point) points.push(cross) @@ -310,23 +302,15 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) // 두 번째 포인트는 첫 번째 포인트를 기준으로 수평 또는 수직으로만 배치 const p1 = points[0] - point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], { - stroke: 'black', - strokeWidth: 1, - originX: 'center', - originY: 'center', - }) + point = new fabric.Line([pointer.x - 10, pointer.y, pointer.x + 10, pointer.y], crossOptions) canvas.add(point) cross['x'] = parseInt(point.left.toFixed(0)) + drawPoints.push(point) // 세로 선 생성 (십자 모양의 다른 축) - point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], { - stroke: 'black', - strokeWidth: 1, - originX: 'center', - originY: 'center', - }) + point = new fabric.Line([pointer.x, pointer.y - 10, pointer.x, pointer.y + 10], crossOptions) canvas.add(point) cross['y'] = parseInt(point.top.toFixed(0)) + drawPoints.push(point) points.push(cross) let isParallel = false @@ -354,43 +338,46 @@ export function useCommonUtils({ commonFunctionState, setCommonFunctionState }) top: (p1CenterY + p2CenterY) / 2, ...textOptions, }) - canvas.add(distanceText) + // canvas.add(distanceText) + let distance2 = 0 + let distance3 = 0 if (!isParallel) { const p3 = new fabric.Point(p2CenterX, p1CenterY) const line2 = new fabric.Line([p2CenterX, p2CenterY, p3.x, p3.y], lineOptions) const line3 = new fabric.Line([p3.x, p3.y, p1CenterX, p1CenterY], lineOptions) canvas.add(line2) canvas.add(line3) - const distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) - const distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) + distance2 = getDistance(p2CenterX, p2CenterY, p3.x, p3.y) + distance3 = getDistance(p3.x, p3.y, p1CenterX, p1CenterY) distanceText = new fabric.Text(`${distance2 * 10}`, { left: (p2CenterX + p3.x) / 2, top: (p2CenterY + p3.y) / 2, ...textOptions, }) - canvas.add(distanceText) + // canvas.add(distanceText) distanceText = new fabric.Text(`${distance3 * 10}`, { left: (p3.x + p1CenterX) / 2, top: (p3.y + p1CenterY) / 2, ...textOptions, }) - canvas.add(distanceText) - const id = uuidv4() - addPopup( - id, - 1, - , - ) + // canvas.add(distanceText) } + const id = uuidv4() + addPopup( + id, + 1, + , + ) + // 거리 계산 후, 다음 측정을 위해 초기화 points = [] } From 7cc3537709f4035527f86013ee62c7cf5839be3e Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 09:12:38 +0900 Subject: [PATCH 092/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=AA=A9=EB=A1=9D=20?= =?UTF-8?q?=EB=A6=AC=EC=8A=A4=ED=8A=B8=20=EC=B2=B4=ED=81=AC=EB=B0=95?= =?UTF-8?q?=EC=8A=A4=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 5771543f..64cd7f33 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -67,10 +67,10 @@ export default function Stuff() { field: 'lastEditDatetime', minWidth: 200, headerName: getMessage('stuff.gridHeader.lastEditDatetime'), - headerCheckboxSelection: true, - headerCheckboxSelectionCurrentPageOnly: true, //페이징시 현재 페이지만 체크되도록 - checkboxSelection: true, - showDisabledCheckboxes: true, + // headerCheckboxSelection: true, + // headerCheckboxSelectionCurrentPageOnly: true, //페이징시 현재 페이지만 체크되도록 + // checkboxSelection: true, + // showDisabledCheckboxes: true, cellStyle: { textAlign: 'center' }, valueFormatter: function (params) { if (params.value) { From 4d6c1f3b08b483427fee9f70e9609b1eefdaf61b Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 25 Oct 2024 10:27:21 +0900 Subject: [PATCH 093/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_grid-detail.scss | 11 ++++++++++- src/styles/_main.scss | 1 - src/styles/_submodal.scss | 17 +++++++++++++++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/styles/_grid-detail.scss b/src/styles/_grid-detail.scss index 048a1946..0392bae8 100644 --- a/src/styles/_grid-detail.scss +++ b/src/styles/_grid-detail.scss @@ -8,6 +8,8 @@ --ag-header-height: 40px; --ag-header-foreground-color: white; --ag-header-background-color: #5D6A76; + --ag-row-hover-color: #ECF0F4; + // --ag-header-cell-hover-background-color: rgb(80, 40, 140); --ag-header-cell-moving-background-color: #5D6A76; .ag-root-wrapper{ @@ -41,8 +43,16 @@ } } .ag-cell{ + display: flex; + align-items: center; font-size: 13px; color: #45576F; + line-height: 1.4 !important; + padding-top: 10px; + padding-bottom: 10px; + .block{ + display: block; + } } .ag-icon-desc::before, .ag-icon-asc::before, @@ -94,7 +104,6 @@ justify-content: center; background-color: #fff; border: 1px solid #94A0AD; - background-color: transparent; border-radius: 2px; font-size: 13px; color: #94A0AD; diff --git a/src/styles/_main.scss b/src/styles/_main.scss index b8783c3b..ea1535b1 100644 --- a/src/styles/_main.scss +++ b/src/styles/_main.scss @@ -252,7 +252,6 @@ .faq-item{ position: relative; margin-bottom: 10px; - cursor: pointer; .faq-item-inner{ display: flex; align-items: center; diff --git a/src/styles/_submodal.scss b/src/styles/_submodal.scss index e5fae9fb..de01ee36 100644 --- a/src/styles/_submodal.scss +++ b/src/styles/_submodal.scss @@ -316,11 +316,24 @@ } } .community_detail-inner{ - padding-top: 20px; - padding-bottom: 20px; + max-height: 300px; + overflow-y: auto; + margin-top: 20px; + margin-bottom: 20px; font-size: 13px; font-weight: 400; color: #45576F; line-height: 26px; + word-break: keep-all; + &::-webkit-scrollbar { + width: 4px; + background-color: transparent; + } + &::-webkit-scrollbar-thumb { + background-color: #C1CCD7; + } + &::-webkit-scrollbar-track { + background-color: transparent; + } } } \ No newline at end of file From 451a3c8ccec0c9107c2b4ce2777220bf9daa0cfa Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 10:29:40 +0900 Subject: [PATCH 094/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=ED=99=94=EB=A9=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 38 +++++++++++++++++------ src/components/management/StuffHeader.jsx | 9 ++++-- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 4 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index b96818dc..44b053a6 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -427,7 +427,6 @@ export default function StuffDetail() { //도도부현 / 주소 setPrefValue(detailData.prefId) form.setValue('prefId', detailData.prefId) - //prefName ??? form.setValue('address', detailData.address) //발전시뮬 form.setValue('areaId', detailData.areaId) @@ -439,7 +438,7 @@ export default function StuffDetail() { //한랭지대책시행 coldRegionFlg 1이면 true form.setValue('coldRegionFlg', detailData.coldRegionFlg === '1' ? true : false) - //면조도구분surfaceType + //면조도구분 surfaceType null로 내려오면 셋팅 안하고 저장할때 필수값 체크하도록 // form.setValue('surfaceType', 'Ⅱ') // form.setValue('surfaceType', 'III・IV') form.setValue('surfaceType', detailData.surfaceType) @@ -447,8 +446,12 @@ export default function StuffDetail() { form.setValue('saltAreaFlg', detailData.saltAreaFlg === '1' ? true : false) //설치높이 form.setValue('installHeight', detailData.installHeight) - //계약조건 - form.setValue('conType', detailData.conType) + //계약조건 null로 내려오면 0으로 디폴트셋팅 + if (detailData.conType === null) { + form.setValue('conType', '0') + } else { + form.setValue('conType', detailData.conType) + } //메모 form.setValue('remarks', detailData.remarks) }) @@ -888,53 +891,70 @@ export default function StuffDetail() { let errors = {} let fieldNm + //담당자 if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { fieldNm = getMessage('stuff.detail.receiveUser') errors = fieldNm } + //물건명 if (!formData.objectName || formData.objectName.trim().length === 0) { fieldNm = getMessage('stuff.detail.objectStatusId') errors = fieldNm } + //경칭 if (!formData.objectNameOmit) { fieldNm = getMessage('stuff.detail.objectNameOmit') errors = fieldNm } + //1차판매점명 if (!formData.saleStoreId) { fieldNm = getMessage('stuff.detail.saleStoreId') errors = fieldNm } - + //우편번호 if (!formData.zipNo) { fieldNm = getMessage('stuff.detail.zipNo') errors = fieldNm } - + //주소 + if (!formData.address) { + fieldNm = getMessage('stuff.detail.address') + errors = fieldNm + } + //도도부현 if (!formData.prefId || formData.prefId === '0') { fieldNm = getMessage('stuff.detail.prefId') errors = fieldNm } - + //발전시뮬레이션지역 if (!formData.areaId) { fieldNm = getMessage('stuff.detail.areaId') errors = fieldNm } - + //기준풍속 if (!formData.standardWindSpeedId) { fieldNm = getMessage('stuff.detail.standardWindSpeedId') errors = fieldNm } - + //수직적설량 if (!formData.verticalSnowCover) { fieldNm = getMessage('stuff.detail.verticalSnowCover') errors = fieldNm } + //면조도구분 + if (!formData.surfaceType) { + fieldNm = getMessage('stuff.detail.surfaceType') + errors = fieldNm + } + //설치높이 if (!formData.installHeight) { fieldNm = getMessage('stuff.detail.installHeight') errors = fieldNm } + //계약조건 + if (Object.keys(errors).length > 0) { return alert(getMessage('stuff.detail.save.valierror3', [errors])) } diff --git a/src/components/management/StuffHeader.jsx b/src/components/management/StuffHeader.jsx index d8cade80..0ed58b34 100644 --- a/src/components/management/StuffHeader.jsx +++ b/src/components/management/StuffHeader.jsx @@ -6,6 +6,7 @@ import { useRouter, useSearchParams } from 'next/navigation' import { globalLocaleStore } from '@/store/localeAtom' import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' +import dayjs from 'dayjs' export default function StuffHeader() { const { getMessage } = useMessage() @@ -57,11 +58,15 @@ export default function StuffHeader() {
    {getMessage('stuff.detail.header.lastEditDatetime')}
    -
    {headerData.lastEditDatetime}
    +
    + {dayjs(headerData.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')} ({headerData.lastEditUserName}) +
    {getMessage('stuff.detail.header.createDatetime')}
    -
    {headerData.createDatetime}
    +
    + {dayjs(headerData.createDatetime).format('YYYY.MM.DD')} ({headerData.createUserName}) +
    ) diff --git a/src/locales/ja.json b/src/locales/ja.json index c5522fe2..3b886602 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -486,6 +486,7 @@ "stuff.detail.saleStoreId": "一次販売店名/ID", "stuff.detail.otherSaleStoreId": "二次販売店名/ID", "stuff.detail.zipNo": "郵便番号 ", + "stuff.detail.address": "住所 ", "stuff.detail.btn.addressPop": "住所検索", "stuff.detail.btn.addressPop.guide": "※ 郵便番号7桁を入力した後、アドレス検索ボタンをクリックしてください", "stuff.detail.prefId": "都道府県 / 住所 ", diff --git a/src/locales/ko.json b/src/locales/ko.json index 529dc494..25f7998f 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -491,6 +491,7 @@ "stuff.detail.saleStoreId": "1차 판매점명 / ID", "stuff.detail.otherSaleStoreId": "2차 판매점명 / ID", "stuff.detail.zipNo": "우편번호", + "stuff.detail.address": "주소", "stuff.detail.btn.addressPop": "주소검색", "stuff.detail.btn.addressPop.guide": "※ 주소검색 버튼을 클릭한 후, 도도부현 정보를 선택해주십시오.", "stuff.detail.prefId": "도도부현 / 주소", From a10d999cc8e7363c4cecba2d862fbd842b69c0ea Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 11:37:39 +0900 Subject: [PATCH 095/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=ED=99=94=EB=A9=B4=201=EC=B0=A8=EC=A0=90=20=EB=A1=9C=EA=B7=B8?= =?UTF-8?q?=EC=9D=B8=EC=8B=9C=201&2=EC=B0=A8=EC=A0=90=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=EC=99=84=EC=84=B1=20Select=20X=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 44b053a6..e8a25251 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -484,8 +484,10 @@ export default function StuffDetail() { } //1차점 변경 이벤트 const onSelectionChange = (key) => { - if (key.saleStoreId === selOptions) { - return + if (isObjectNotEmpty(key)) { + if (key.saleStoreId === selOptions) { + return + } } const planReqNo = form.watch('planReqNo') @@ -596,8 +598,10 @@ export default function StuffDetail() { //2차점 변경 이벤트 const onSelectionChange2 = (key) => { - if (key.saleStoreId === otherSelOptions) { - return + if (isObjectNotEmpty(key)) { + if (key.saleStoreId === otherSelOptions) { + return + } } const planReqNo = form.watch('planReqNo') From c4861f95a37d752f12187d64e9b47e6751083e47 Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 12:27:52 +0900 Subject: [PATCH 096/139] =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=8C=9D=EC=97=85=20validation=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/ChangePasswordPop.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/main/ChangePasswordPop.jsx b/src/components/main/ChangePasswordPop.jsx index b5a3f8da..42ab6ef6 100644 --- a/src/components/main/ChangePasswordPop.jsx +++ b/src/components/main/ChangePasswordPop.jsx @@ -62,7 +62,7 @@ export default function ChangePasswordPop() { //패스워드 길이수 체크 if (checkLength(_password1) > 10) { - alert(getMessage('main.popup.login.validate2')) + return alert(getMessage('main.popup.login.validate2')) } const param = { @@ -81,6 +81,8 @@ export default function ChangePasswordPop() { } else { alert(res.result.resultMsg) } + } else { + console.log('error') } }) } From 5f9e3a15b978d6e0345361d9a4a5f63bd7563082 Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Fri, 25 Oct 2024 13:14:22 +0900 Subject: [PATCH 097/139] =?UTF-8?q?[=ED=9A=8C=EC=9B=90]=20=EA=B0=80?= =?UTF-8?q?=EC=9E=85=EC=8B=A0=EC=B2=AD=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20?= =?UTF-8?q?=EA=B2=80=EC=82=AC=20=EC=B6=94=EA=B0=80=20=EB=B0=8F=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=99=94=EB=A9=B4=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Join.jsx | 238 +++++++++++++++++++++++++++------- src/components/auth/Login.jsx | 10 +- src/locales/ja.json | 1 + src/locales/ko.json | 1 + src/util/common-utils.js | 20 +++ 5 files changed, 222 insertions(+), 48 deletions(-) diff --git a/src/components/auth/Join.jsx b/src/components/auth/Join.jsx index 3412efdb..3f4c1097 100644 --- a/src/components/auth/Join.jsx +++ b/src/components/auth/Join.jsx @@ -1,53 +1,171 @@ 'use client' +import { useRef } from 'react' import { useAxios } from '@/hooks/useAxios' import { useRouter } from 'next/navigation' import { useMessage } from '@/hooks/useMessage' import Cookies from 'js-cookie' +import { isObjectNotEmpty, inputTelNumberCheck, inputNumberCheck } from '@/util/common-utils' + export default function Join() { const { getMessage } = useMessage() const { promisePost } = useAxios() const router = useRouter() + const storeQcastNmRef = useRef() + const storeQcastNmKanaRef = useRef() + const postCdRef = useRef() + const addrRef = useRef() + const telNoRef = useRef() + const faxRef = useRef() + const userNmRef = useRef() + const userIdRef = useRef() + const emailRef = useRef() + const userTelNoRef = useRef() + const userFaxRef = useRef() + + // 가입 신청 유효성 검사 + const joinValidation = (formData) => { + // 판매대리점 정보 - 판매대리점명 + const storeQcastNm = formData.get('storeQcastNm') + if (!isObjectNotEmpty(storeQcastNm)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.storeQcastNm')])) + storeQcastNmRef.current.focus() + return false + } + + // 판매대리점 정보 - 판매대리점명 후리가나 + const storeQcastNmKana = formData.get('storeQcastNmKana') + if (!isObjectNotEmpty(storeQcastNmKana)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.storeQcastNmKana')])) + storeQcastNmKanaRef.current.focus() + return false + } + + // 판매대리점 정보 - 우편번호 + const postCd = formData.get('postCd') + if (!isObjectNotEmpty(postCd)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.postCd')])) + postCdRef.current.focus() + return false + } + + // 판매대리점 정보 - 주소 + const addr = formData.get('addr') + if (!isObjectNotEmpty(addr)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.addr')])) + addrRef.current.focus() + return false + } + + // 판매대리점 정보 - 전화번호 + const telNo = formData.get('telNo') + if (!isObjectNotEmpty(telNo)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.telNo')])) + telNoRef.current.focus() + return false + } + + // 판매대리점 정보 - FAX 번호 + const fax = formData.get('fax') + if (!isObjectNotEmpty(fax)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub1.fax')])) + faxRef.current.focus() + return false + } + + // 담당자 정보 - 담당자명 + const userNm = formData.get('userNm') + if (!isObjectNotEmpty(userNm)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub2.userNm')])) + userNmRef.current.focus() + return false + } + + // 담당자 정보 - 신청 ID + const userId = formData.get('userId') + if (!isObjectNotEmpty(userId)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub2.userId')])) + userIdRef.current.focus() + return false + } + + // 담당자 정보 - 이메일 주소 + const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ + + const email = formData.get('email') + if (!isObjectNotEmpty(email)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub2.email')])) + emailRef.current.focus() + return false + } else { + // 이메일 정규식 검사 + if (!emailRegex.test(email)) { + alert(getMessage('join.validation.check1', [getMessage('join.sub2.email')])) + emailRef.current.focus() + return false + } + } + + // 담당자 정보 - 전화번호 + const userTelNo = formData.get('userTelNo') + if (!isObjectNotEmpty(userTelNo)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub2.telNo')])) + userTelNoRef.current.focus() + return false + } + + // 담당자 정보 - FAX 번호 + const userFax = formData.get('userFax') + if (!isObjectNotEmpty(userFax)) { + alert(getMessage('common.message.required.data', [getMessage('join.sub2.fax')])) + userFaxRef.current.focus() + return false + } + return true + } + // 가입 신청 const joinProcess = async (e) => { e.preventDefault() const formData = new FormData(e.target) - const param = { - storeQcastNm: formData.get('storeQcastNm'), - storeQcastNmKana: formData.get('storeQcastNmKana'), - postCd: formData.get('postCd'), - addr: formData.get('addr'), - telNo: formData.get('telNo'), - fax: formData.get('fax'), - bizNo: formData.get('bizNo'), - userInfo: { - userId: formData.get('userId'), - userNm: formData.get('userNm'), - userNmKana: formData.get('userNmKana'), - telNo: formData.get('userTelNo'), - fax: formData.get('userFax'), - email: formData.get('email'), - category: formData.get('category'), - }, - } + if (joinValidation(formData)) { + const param = { + storeQcastNm: formData.get('storeQcastNm'), + storeQcastNmKana: formData.get('storeQcastNmKana'), + postCd: formData.get('postCd'), + addr: formData.get('addr'), + telNo: formData.get('telNo'), + fax: formData.get('fax'), + bizNo: formData.get('bizNo'), + userInfo: { + userId: formData.get('userId'), + userNm: formData.get('userNm'), + userNmKana: formData.get('userNmKana'), + telNo: formData.get('userTelNo'), + fax: formData.get('userFax'), + email: formData.get('email'), + category: formData.get('category'), + }, + } - await promisePost({ url: '/api/login/v1.0/user/join', data: param }) - .then((res) => { - if (res) { - if (res.data.result.resultCode == 'S') { - Cookies.set('joinEmail', formData.get('email'), { expires: 1 }) - router.push('/join/complete') - } else { - alert(res.data.result.resultMsg) + await promisePost({ url: '/api/login/v1.0/user/join', data: param }) + .then((res) => { + if (res) { + if (res.data.result.resultCode == 'S') { + Cookies.set('joinEmail', formData.get('email'), { expires: 1 }) + router.push('/join/complete') + } else { + alert(res.data.result.resultMsg) + } } - } - }) - .catch((error) => { - alert(error.response.data.message) - }) + }) + .catch((error) => { + alert(error.response.data.message) + }) + } } return ( @@ -71,6 +189,7 @@ export default function Join() { + {/* 판매대리점명 */} {getMessage('join.sub1.storeQcastNm')} * @@ -81,14 +200,16 @@ export default function Join() { type="text" id="storeQcastNm" name="storeQcastNm" - required alt={getMessage('join.sub1.storeQcastNm')} className="input-light" placeholder={getMessage('join.sub1.storeQcastNm_placeholder')} + maxLength={30} + ref={storeQcastNmRef} />
    + {/* 판매대리점명 후리가나 */} {getMessage('join.sub1.storeQcastNmKana')} * @@ -99,13 +220,15 @@ export default function Join() { type="text" id="storeQcastNmKana" name="storeQcastNmKana" - required className="input-light" placeholder={getMessage('join.sub1.storeQcastNmKana_placeholder')} + maxLength={30} + ref={storeQcastNmKanaRef} />
    + {/* 우편번호/주소 */} {getMessage('join.sub1.postCd')}/{getMessage('join.sub1.addr')} * @@ -117,9 +240,11 @@ export default function Join() { type="text" id="postCd" name="postCd" - required className="input-light" placeholder={getMessage('join.sub1.postCd_placeholder')} + onChange={inputNumberCheck} + maxLength={7} + ref={postCdRef} />
    @@ -127,14 +252,16 @@ export default function Join() { type="text" id="addr" name="addr" - required className="input-light" placeholder={getMessage('join.sub1.addr_placeholder')} + maxLength={50} + ref={addrRef} />
    + {/* 전화번호 */} {getMessage('join.sub1.telNo')} * @@ -145,13 +272,16 @@ export default function Join() { type="text" id="telNo" name="telNo" - required className="input-light" placeholder={getMessage('join.sub1.telNo_placeholder')} - > + maxLength={15} + onChange={inputTelNumberCheck} + ref={telNoRef} + />
    + {/* FAX 번호 */} {getMessage('join.sub1.fax')} * @@ -162,18 +292,21 @@ export default function Join() { type="text" id="fax" name="fax" - required className="input-light" placeholder={getMessage('join.sub1.fax_placeholder')} - > + maxLength={15} + onChange={inputTelNumberCheck} + ref={faxRef} + />
    + {/* 법인번호 */} {getMessage('join.sub1.bizNo')}
    - +
    @@ -196,44 +329,49 @@ export default function Join() { + {/* 담당자명 */} {getMessage('join.sub2.userNm')} *
    - +
    + {/* 담당자명 후리가나 */} {getMessage('join.sub2.userNmKana')}
    - +
    + {/* 신청 ID */} {getMessage('join.sub2.userId')} *
    - +
    + {/* 이메일 주소 */} {getMessage('join.sub2.email')} *
    - +
    + {/* 전화번호 */} {getMessage('join.sub2.telNo')} * @@ -246,11 +384,14 @@ export default function Join() { name="userTelNo" className="input-light" placeholder={getMessage('join.sub2.telNo_placeholder')} - required + maxLength={15} + onChange={inputTelNumberCheck} + ref={userTelNoRef} />
    + {/* FAX 번호 */} {getMessage('join.sub2.fax')} * @@ -263,16 +404,19 @@ export default function Join() { name="userFax" className="input-light" placeholder={getMessage('join.sub1.fax_placeholder')} - required + maxLength={15} + onChange={inputTelNumberCheck} + ref={userFaxRef} />
    + {/* 부서명 */} {getMessage('join.sub2.category')}
    - +
    diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index 80b34f9f..ef4f92a3 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -331,7 +331,15 @@ export default function Login() { >
    -
    -
    @@ -1198,7 +1223,7 @@ export default function StuffDetail() {
    - +
    @@ -1227,7 +1252,7 @@ export default function StuffDetail() { })} {/* 라디오끝 */}
    - +
    - +
    -
    {getMessage('stuff.detail.btn.addressPop.guide')}
    @@ -1368,7 +1394,7 @@ export default function StuffDetail() {
    -
    +
    {prefCodeList?.length > 0 && ( +
    @@ -1444,7 +1476,7 @@ export default function StuffDetail() { >
    {getMessage('stuff.detail.standardWindSpeedIdSpan')} -
    @@ -1463,6 +1495,7 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('verticalSnowCover') || ''} {...register('verticalSnowCover')} + ref={inputVerticalSnowCoverEl} />
    cm @@ -1510,6 +1543,7 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('installHeight') || ''} {...register('installHeight')} + ref={inputInstallHeightEl} />
    m @@ -1544,7 +1578,7 @@ export default function StuffDetail() {
    {!isFormValid ? ( - ) : ( @@ -1595,7 +1629,7 @@ export default function StuffDetail() { {/* {detailData?.tempFlg === '1' ? ( */} {objectNo.substring(0, 1) === 'T' ? ( <> - @@ -1609,7 +1643,13 @@ export default function StuffDetail() {
    - +
    @@ -1638,7 +1678,7 @@ export default function StuffDetail() { })} {/* 상세라디오끝 */}
    - +
    +
    -
    {getMessage('stuff.detail.btn.addressPop.guide')}
    @@ -1780,7 +1820,7 @@ export default function StuffDetail() {
    -
    +
    {prefCodeList?.length > 0 && ( +
    @@ -1860,7 +1906,7 @@ export default function StuffDetail() { >
    {getMessage('stuff.detail.standardWindSpeedIdSpan')} -
    @@ -1881,6 +1927,7 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('verticalSnowCover') || ''} {...register('verticalSnowCover')} + ref={inputVerticalSnowCoverEl} />
    cm @@ -1932,6 +1979,7 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('installHeight') || ''} {...register('installHeight')} + ref={inputInstallHeightEl} />
    m @@ -2005,13 +2053,13 @@ export default function StuffDetail() {
    -
    @@ -2020,17 +2068,17 @@ export default function StuffDetail() { <>
    {!isFormValid ? ( - ) : ( )}
    From 49bb5e436289bedf2c597f3cd32305a31cd71908 Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Fri, 25 Oct 2024 14:53:49 +0900 Subject: [PATCH 100/139] =?UTF-8?q?=EA=B0=80=EC=9E=85=EC=8B=A0=EC=B2=AD=20?= =?UTF-8?q?=EC=8B=9C,=20confirm=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/auth/Join.jsx | 64 +++++++++++++++++++----------------- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 3 files changed, 35 insertions(+), 31 deletions(-) diff --git a/src/components/auth/Join.jsx b/src/components/auth/Join.jsx index 3f4c1097..a9e79750 100644 --- a/src/components/auth/Join.jsx +++ b/src/components/auth/Join.jsx @@ -132,39 +132,41 @@ export default function Join() { const formData = new FormData(e.target) if (joinValidation(formData)) { - const param = { - storeQcastNm: formData.get('storeQcastNm'), - storeQcastNmKana: formData.get('storeQcastNmKana'), - postCd: formData.get('postCd'), - addr: formData.get('addr'), - telNo: formData.get('telNo'), - fax: formData.get('fax'), - bizNo: formData.get('bizNo'), - userInfo: { - userId: formData.get('userId'), - userNm: formData.get('userNm'), - userNmKana: formData.get('userNmKana'), - telNo: formData.get('userTelNo'), - fax: formData.get('userFax'), - email: formData.get('email'), - category: formData.get('category'), - }, - } + if (confirm(getMessage('join.complete.save.confirm'))) { + const param = { + storeQcastNm: formData.get('storeQcastNm'), + storeQcastNmKana: formData.get('storeQcastNmKana'), + postCd: formData.get('postCd'), + addr: formData.get('addr'), + telNo: formData.get('telNo'), + fax: formData.get('fax'), + bizNo: formData.get('bizNo'), + userInfo: { + userId: formData.get('userId'), + userNm: formData.get('userNm'), + userNmKana: formData.get('userNmKana'), + telNo: formData.get('userTelNo'), + fax: formData.get('userFax'), + email: formData.get('email'), + category: formData.get('category'), + }, + } - await promisePost({ url: '/api/login/v1.0/user/join', data: param }) - .then((res) => { - if (res) { - if (res.data.result.resultCode == 'S') { - Cookies.set('joinEmail', formData.get('email'), { expires: 1 }) - router.push('/join/complete') - } else { - alert(res.data.result.resultMsg) + await promisePost({ url: '/api/login/v1.0/user/join', data: param }) + .then((res) => { + if (res) { + if (res.data.result.resultCode == 'S') { + Cookies.set('joinEmail', formData.get('email'), { expires: 1 }) + router.push('/join/complete') + } else { + alert(res.data.result.resultMsg) + } } - } - }) - .catch((error) => { - alert(error.response.data.message) - }) + }) + .catch((error) => { + alert(error.response.data.message) + }) + } } } diff --git a/src/locales/ja.json b/src/locales/ja.json index 688cae4c..baa74f41 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -446,6 +446,7 @@ "join.complete.contents": "※ 申請したIDが承認されると、担当者情報に入力されたメールアドレスにログイン案内メールが送信されます。", "join.complete.email_comment": "担当者メールアドレス", "join.validation.check1": "{0} の形式を確認してください。", + "join.complete.save.confirm": "Hanwha Japan担当者にID承認を要請されると、これ以上情報を修正できません。 本当にリクエストしますか?", "stuff.gridHeader.lastEditDatetime": "更新日時", "stuff.gridHeader.objectNo": "品番", "stuff.gridHeader.planTotCnt": "プラン数", diff --git a/src/locales/ko.json b/src/locales/ko.json index 7daef05c..d46e7726 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -451,6 +451,7 @@ "join.complete.contents": "※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.", "join.complete.email_comment": "담당자 이메일 주소", "join.validation.check1": "{0} 형식을 확인해주세요.", + "join.complete.save.confirm": "Hanwha Japan 담당자에게 ID승인이 요청되면 더 이상 정보를 수정할 수 없습니다. 정말로 요청하시겠습니까?", "stuff.gridHeader.lastEditDatetime": "갱신일시", "stuff.gridHeader.objectNo": "물건번호", "stuff.gridHeader.planTotCnt": "플랜 수", From f3f7daf9d698a0f71f5e31eb28053e9a274a0c4f Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 25 Oct 2024 15:01:25 +0900 Subject: [PATCH 101/139] feat: Add MainSkeleton --- package.json | 1 + src/components/main/MainContents.jsx | 53 +++++++++++++++------------- src/components/ui/Loading.jsx | 5 --- src/components/ui/Loading.module.css | 35 ------------------ src/components/ui/MainSkeleton.jsx | 13 +++++++ yarn.lock | 5 +++ 6 files changed, 48 insertions(+), 64 deletions(-) delete mode 100644 src/components/ui/Loading.jsx delete mode 100644 src/components/ui/Loading.module.css create mode 100644 src/components/ui/MainSkeleton.jsx diff --git a/package.json b/package.json index 303e4864..6c94a282 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "react-draggable": "^4.4.6", "react-hook-form": "^7.53.0", "react-icons": "^5.3.0", + "react-loading-skeleton": "^3.5.0", "react-responsive-modal": "^6.4.2", "recoil": "^0.7.7", "sweetalert2": "^11.14.1", diff --git a/src/components/main/MainContents.jsx b/src/components/main/MainContents.jsx index d2e38853..fa61b676 100644 --- a/src/components/main/MainContents.jsx +++ b/src/components/main/MainContents.jsx @@ -9,6 +9,7 @@ import { useRouter } from 'next/navigation' import { globalLocaleStore } from '@/store/localeAtom' import { queryStringFormatter } from '@/util/common-utils' import { sessionStore } from '@/store/commonAtom' +import MainSkeleton from '../ui/MainSkeleton' export default function MainContents() { const { getMessage } = useMessage() @@ -109,30 +110,34 @@ export default function MainContents() {
    -
      - {objectList.map((row) => { - return ( -
    • { - if (row.objectNo.substring(0, 1) === 'R') { - router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`) - } else { - router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`) - } - }} - > -
      - {dayjs(row.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')} - {row.objectNo} - {row.objectName} - {row.saleStoreName} -
      -
    • - ) - })} -
    + {objectList.length > 0 ? ( +
      + {objectList.map((row) => { + return ( +
    • { + if (row.objectNo.substring(0, 1) === 'R') { + router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`) + } else { + router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`) + } + }} + > +
      + {dayjs(row.lastEditDatetime).format('YYYY.MM.DD HH:mm:ss')} + {row.objectNo} + {row.objectName} + {row.saleStoreName} +
      +
    • + ) + })} +
    + ) : ( + + )}
    diff --git a/src/components/ui/Loading.jsx b/src/components/ui/Loading.jsx deleted file mode 100644 index 59d2170b..00000000 --- a/src/components/ui/Loading.jsx +++ /dev/null @@ -1,5 +0,0 @@ -import style from '@/components/ui/Loading.module.css' - -export default function Loading() { - return -} diff --git a/src/components/ui/Loading.module.css b/src/components/ui/Loading.module.css deleted file mode 100644 index 7b3001f8..00000000 --- a/src/components/ui/Loading.module.css +++ /dev/null @@ -1,35 +0,0 @@ -.loader { - position: relative; - font-size: 48px; - letter-spacing: 6px; -} -.loader:before { - content: 'Loading'; - color: #fff; -} -.loader:after { - content: ''; - width: 20px; - height: 20px; - background-color: #ff3d00; - background-image: radial-gradient(circle 2px, #fff4 100%, transparent 0), radial-gradient(circle 1px, #fff3 100%, transparent 0); - background-position: - 14px -4px, - 12px -1px; - border-radius: 50%; - position: absolute; - margin: auto; - top: -5px; - right: 66px; - transform-origin: center bottom; - animation: fillBaloon 1s ease-in-out infinite alternate; -} - -@keyframes fillBaloon { - 0% { - transform: scale(1); - } - 100% { - transform: scale(3); - } -} diff --git a/src/components/ui/MainSkeleton.jsx b/src/components/ui/MainSkeleton.jsx new file mode 100644 index 00000000..fa0a48c2 --- /dev/null +++ b/src/components/ui/MainSkeleton.jsx @@ -0,0 +1,13 @@ +import Skeleton from 'react-loading-skeleton' +import 'react-loading-skeleton/dist/skeleton.css' + +export default function MainSkeleton() { + return ( + <> +
    + +
    + + + ) +} diff --git a/yarn.lock b/yarn.lock index bf4e65b8..6e7b5f2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5884,6 +5884,11 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-loading-skeleton@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/react-loading-skeleton/-/react-loading-skeleton-3.5.0.tgz#da2090355b4dedcad5c53cb3f0ed364e3a76d6ca" + integrity sha512-gxxSyLbrEAdXTKgfbpBEFZCO/P153DnqSCQau2+o6lNy1jgMRr2MmRmOzMmyrwSaSYLRB8g7b0waYPmUjz7IhQ== + react-onclickoutside@^6.13.0: version "6.13.1" resolved "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.13.1.tgz" From 32691e4da9d9ab6dbcd00c2749227279b035fac2 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 25 Oct 2024 15:22:30 +0900 Subject: [PATCH 102/139] =?UTF-8?q?1=EB=8B=A8=EC=9C=84=EB=8F=84=20?= =?UTF-8?q?=EB=82=98=EC=98=A4=EB=8F=84=EB=A1=9D=20=EC=88=98=EC=A0=95,=20?= =?UTF-8?q?=EC=A7=80=EB=B6=95=EB=A9=B4=20=ED=95=A0=EB=8B=B9=ED=91=9C?= =?UTF-8?q?=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 2 +- src/components/fabric/QPolygon.js | 2 +- src/hooks/common/useCanvasConfigInitialize.js | 2 + src/hooks/common/useRoof.js | 151 ++++++++++++++++++ src/hooks/usePlan.js | 1 + 5 files changed, 156 insertions(+), 2 deletions(-) create mode 100644 src/hooks/common/useRoof.js diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 7b4e2196..a1d56b08 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -148,7 +148,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { getLength() { //10배 곱해진 값 return - return Number(this.length.toFixed(0) * 10) + return Number(this.length.toFixed(2) * 10) }, setViewLengthText(bool) { diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 76c8dd6c..b28a3b47 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -183,7 +183,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const end = points[(i + 1) % points.length] const dx = end.x - start.x const dy = end.y - start.y - const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) * 10 + const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(2)) * 10 let midPoint diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index 2e91fad1..c2775376 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -6,6 +6,7 @@ import { setSurfaceShapePattern } from '@/util/canvas-util' import { useFont } from '@/hooks/common/useFont' import { useGrid } from '@/hooks/common/useGrid' import { globalFontAtom } from '@/store/fontAtom' +import { useRoof } from '@/hooks/common/useRoof' export function useCanvasConfigInitialize() { const canvas = useRecoilValue(canvasState) @@ -15,6 +16,7 @@ export function useCanvasConfigInitialize() { const setDotLineGridSetting = useSetRecoilState(dotLineGridSettingState) const {} = useFont() const {} = useGrid() + const {} = useRoof() useEffect(() => { if (!canvas) return diff --git a/src/hooks/common/useRoof.js b/src/hooks/common/useRoof.js new file mode 100644 index 00000000..8aee0344 --- /dev/null +++ b/src/hooks/common/useRoof.js @@ -0,0 +1,151 @@ +import { canvasState } from '@/store/canvasAtom' +import { allocDisplaySelector, roofDisplaySelector } from '@/store/settingAtom' +import { useRecoilValue } from 'recoil' +import { useEffect } from 'react' + +export function useRoof() { + const canvas = useRecoilValue(canvasState) + const allocDisplay = useRecoilValue(allocDisplaySelector) + const roofDisplay = useRecoilValue(roofDisplaySelector) + + useEffect(() => { + if (!canvas) return + canvas + .getObjects() + .filter((polygon) => polygon.name === 'roof') + .forEach((polygon) => { + if (allocDisplay) { + setSurfaceShapePattern(polygon, roofDisplay.column) + } else { + polygon.set('fill', null) + } + }) + canvas.renderAll() + }, [allocDisplay]) + + const setSurfaceShapePattern = (polygon, mode = 'onlyBorder') => { + const ratio = window.devicePixelRatio || 1 + + let width = 265 / 10 + let height = 150 / 10 + let roofStyle = 2 + const inputPatternSize = { width: width, height: height } //임시 사이즈 + const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해 + + if (polygon.direction === 'east' || polygon.direction === 'west') { + //세로형이면 width height를 바꿈 + ;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width] + } + + // 패턴 소스를 위한 임시 캔버스 생성 + const patternSourceCanvas = document.createElement('canvas') + patternSourceCanvas.width = polygon.width * ratio + patternSourceCanvas.height = polygon.height * ratio + const ctx = patternSourceCanvas.getContext('2d') + let offset = roofStyle === 1 ? 0 : patternSize.width / 2 + + const rows = Math.floor(patternSourceCanvas.height / patternSize.height) + const cols = Math.floor(patternSourceCanvas.width / patternSize.width) + + ctx.strokeStyle = mode === 'allPainted' ? 'black' : 'green' + ctx.lineWidth = mode === 'allPainted' ? 1 : 0.4 + ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white' + + if (polygon.direction === 'east' || polygon.direction === 'west') { + offset = roofStyle === 1 ? 0 : patternSize.height / 2 + for (let col = 0; col <= cols; col++) { + const x = col * patternSize.width + const yStart = 0 + const yEnd = patternSourceCanvas.height + ctx.beginPath() + ctx.moveTo(x, yStart) // 선 시작점 + ctx.lineTo(x, yEnd) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) + } + + for (let row = 0; row <= rows; row++) { + const y = row * patternSize.height + (col % 2 === 0 ? 0 : offset) + const xStart = col * patternSize.width + const xEnd = xStart + patternSize.width + ctx.beginPath() + ctx.moveTo(xStart, y) // 선 시작점 + ctx.lineTo(xEnd, y) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height) + } + } + } + } else { + for (let row = 0; row <= rows; row++) { + const y = row * patternSize.height + + ctx.beginPath() + ctx.moveTo(0, y) // 선 시작점 + ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height) + } + + for (let col = 0; col <= cols; col++) { + const x = col * patternSize.width + (row % 2 === 0 ? 0 : offset) + const yStart = row * patternSize.height + const yEnd = yStart + patternSize.height + + ctx.beginPath() + ctx.moveTo(x, yStart) // 선 시작점 + ctx.lineTo(x, yEnd) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted') { + ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) + } + } + } + } + + const hachingPatternSourceCanvas = document.createElement('canvas') + + if (mode === 'lineHatch') { + hachingPatternSourceCanvas.width = polygon.width * ratio + hachingPatternSourceCanvas.height = polygon.height * ratio + + const ctx1 = hachingPatternSourceCanvas.getContext('2d') + + const gap = 10 + + ctx1.strokeStyle = 'green' // 선 색상 + ctx1.lineWidth = 0.3 // 선 두께 + + for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) { + ctx1.beginPath() + ctx1.moveTo(x, 0) // 선 시작점 + ctx1.lineTo(0, x) // 선 끝점 + ctx1.stroke() + } + } + + const combinedPatternCanvas = document.createElement('canvas') + combinedPatternCanvas.width = polygon.width * ratio + combinedPatternCanvas.height = polygon.height * ratio + const combinedCtx = combinedPatternCanvas.getContext('2d') + + // 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘 + combinedCtx.drawImage(patternSourceCanvas, 0, 0) + combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0) + + // 패턴 생성 + const pattern = new fabric.Pattern({ + source: combinedPatternCanvas, + repeat: 'repeat', + }) + + polygon.set('fill', null) + polygon.set('fill', pattern) + polygon.canvas?.renderAll() + } + + return {} +} diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 19b9a879..e00c78e8 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -39,6 +39,7 @@ export function usePlan() { 'length', 'idx', 'direction', + 'parentDirection', 'lines', 'points', 'lockMovementX', From 1387c8aa0bc9fc9aa824fce33f5653feb8473718 Mon Sep 17 00:00:00 2001 From: Daseul Kim Date: Fri, 25 Oct 2024 16:19:20 +0900 Subject: [PATCH 103/139] =?UTF-8?q?refactor:=20=EC=BA=94=EB=B2=84=EC=8A=A4?= =?UTF-8?q?=20=EB=B3=80=EA=B2=BD=EC=82=AC=ED=95=AD=20=ED=99=95=EC=9D=B8=20?= =?UTF-8?q?=EB=B0=A9=EB=B2=95=EC=9D=84=20=EC=8B=A4=EC=8B=9C=EA=B0=84=20?= =?UTF-8?q?=EC=98=A4=EB=B8=8C=EC=A0=9D=ED=8A=B8=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=EB=A5=BC=20=EA=B0=90=EC=A7=80=ED=95=98=EB=8F=84?= =?UTF-8?q?=EB=A1=9D=20=EC=88=98=EC=A0=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 2 +- src/components/floor-plan/CanvasFrame.jsx | 15 ++++++++-- src/components/floor-plan/CanvasLayout.jsx | 6 ++-- src/hooks/useCanvasEvent.js | 34 ++++++++++++++++++++-- src/hooks/usePlan.js | 32 ++++++++++---------- src/store/canvasAtom.js | 5 ++++ 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index b28a3b47..31076b69 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -172,7 +172,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { addLengthText() { this.canvas ?.getObjects() - .filter((obj) => obj.name === 'lengthText' && obj.parent === this) + .filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id) .forEach((text) => { this.canvas.remove(text) }) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index 086e9441..4cc08372 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -2,18 +2,20 @@ import { useEffect, useRef } from 'react' +import { useRecoilState, useRecoilValue } from 'recoil' + import { useCanvas } from '@/hooks/useCanvas' import { useEvent } from '@/hooks/useEvent' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' -import { useRecoilValue } from 'recoil' -import { currentObjectState } from '@/store/canvasAtom' +import { currentObjectState, modifiedPlanFlagState } from '@/store/canvasAtom' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) + const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) const { canvas } = useCanvas('canvas') const { handleZoomClear } = useCanvasEvent() const { contextMenu, currentContextMenu, setCurrentContextMenu, handleClick } = useContextMenu({ @@ -21,7 +23,7 @@ export default function CanvasFrame({ plan }) { handleZoomClear, }, }) - const { checkCanvasObjectEvent, checkUnsavedCanvasPlan } = usePlan() + const { checkCanvasObjectEvent, resetModifiedPlans } = usePlan() const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() const currentObject = useRecoilValue(currentObjectState) @@ -40,8 +42,15 @@ export default function CanvasFrame({ plan }) { } } + useEffect(() => { + if (modifiedPlanFlag && plan?.id) { + checkCanvasObjectEvent(plan.id) + } + }, [modifiedPlanFlag]) + useEffect(() => { loadCanvas() + resetModifiedPlans() }, [plan, canvas]) const onClickContextMenu = (index) => {} diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 63722a64..ac247f6b 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -1,11 +1,12 @@ 'use client' import { useContext, useEffect, useState } from 'react' -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import CanvasFrame from './CanvasFrame' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { usePlan } from '@/hooks/usePlan' +import { modifiedPlansState } from '@/store/canvasAtom' import { globalLocaleStore } from '@/store/localeAtom' import { SessionContext } from '@/app/SessionProvider' @@ -13,11 +14,12 @@ export default function CanvasLayout(props) { const { menuNumber } = props const { session } = useContext(SessionContext) const [objectNo, setObjectNo] = useState('test123240822001') // 이후 삭제 필요 + const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan const globalLocaleState = useRecoilValue(globalLocaleStore) const { getMessage } = useMessage() const { swalFire } = useSwal() - const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() + const { plans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() useEffect(() => { loadCanvasPlanData(session.userId, objectNo) diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index bf878c7b..0df650c0 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,7 +1,15 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' -import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { + canvasSizeState, + canvasState, + canvasZoomState, + currentObjectState, + fontFamilyState, + fontSizeState, + modifiedPlanFlagState, +} from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' // 캔버스에 필요한 이벤트 @@ -13,6 +21,7 @@ export function useCanvasEvent() { const fontSize = useRecoilValue(fontSizeState) const fontFamily = useRecoilValue(fontFamilyState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) + const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { @@ -34,14 +43,32 @@ export function useCanvasEvent() { onChange: (e) => { const target = e.target + if (target.name !== 'mouseLine') { + if (!modifiedPlanFlag) { + setModifiedPlanFlag((prev) => !prev) + } + } + if (target) { - target.uuid = uuidv4() // settleDown(target) } }, addEvent: (e) => { const target = e.target + if (!target.id) { + target.id = uuidv4() + } + if (!target.uuid) { + target.uuid = uuidv4() + } + + if (target.name !== 'mouseLine') { + if (!modifiedPlanFlag) { + setModifiedPlanFlag((prev) => !prev) + } + } + if (target.type === 'QPolygon' || target.type === 'QLine') { const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') textObjs.forEach((obj) => { @@ -141,6 +168,9 @@ export function useCanvasEvent() { })*/ target.on('moving', (e) => { + target.uuid = uuidv4() + setModifiedPlanFlag((prev) => !prev) + if (target.parentDirection === 'left' || target.parentDirection === 'right') { const minX = target.minX const maxX = target.maxX diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index e00c78e8..8ed84af4 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useRecoilState } from 'recoil' -import { v4 as uuidv4 } from 'uuid' -import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState, modifiedPlansState } from '@/store/canvasAtom' +import { v4 as uuidv4, validate as isValidUUID } from 'uuid' +import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' @@ -14,6 +14,7 @@ export function usePlan() { const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) // DB에 저장된 plan const [plans, setPlans] = useRecoilState(plansState) // 전체 plan (DB에 저장된 plan + 저장 안된 새로운 plan) const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan + const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag const { swalFire } = useSwal() const { getMessage } = useMessage() @@ -90,30 +91,29 @@ export function usePlan() { } /** - * 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 판단 + * 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 확인 후 관리 */ - const checkCanvasObjectEvent = (e, planId) => { + const checkCanvasObjectEvent = (planId) => { if (!modifiedPlans.some((modifiedPlan) => modifiedPlan === planId) && checkModifiedCanvasPlan(planId)) { - setModifiedPlans([...modifiedPlans, planId]) + setModifiedPlans((prev) => [...prev, planId]) + setModifiedPlanFlag(false) } } - /** * 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 */ const checkModifiedCanvasPlan = (planId) => { const canvasStatus = currentCanvasData() - const initPlanData = initCanvasPlans.find((plan) => plan.id === planId) - - if (!initPlanData) { + if (isValidUUID(planId)) { // 새로운 캔버스 return JSON.parse(canvasStatus).objects.length > 0 } else { // 저장된 캔버스 // 각각 object들의 uuid 목록을 추출하여 비교 const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects) + const initPlanData = initCanvasPlans.find((plan) => plan.id === planId) const dbObjsUuids = getObjectUuids(JSON.parse(initPlanData.canvasStatus).objects) - return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((id, index) => id === dbObjsUuids[index]) + return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index]) } } const getObjectUuids = (objects) => { @@ -122,10 +122,12 @@ export function usePlan() { .map((obj) => obj.uuid) .sort() } - /** - * 캔버스에 저장되지 않은 변경사항이 있는 경우 저장 여부를 확인 후 저장 - */ - const checkUnsavedCanvasPlan = async () => { + + const resetModifiedPlans = () => { + setModifiedPlans([]) + setModifiedPlanFlag(false) + } + const checkUnsavedCanvasPlan = (str) => { if (modifiedPlans.length > 0) { swalFire({ text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'), @@ -365,7 +367,7 @@ export function usePlan() { plans, modifiedPlans, checkCanvasObjectEvent, - checkUnsavedCanvasPlan, + resetModifiedPlans, saveCanvas, handleCurrentPlan, handleAddPlan, diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index d9878f2f..0f2428ee 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -275,6 +275,11 @@ export const modifiedPlansState = atom({ key: 'modifiedPlansState', default: [], }) +// 변경감지 flag +export const modifiedPlanFlagState = atom({ + key: 'modifiedPlanFlagState', + default: false, +}) export const tempGridModeState = atom({ key: 'tempGridModeState', From 45b0063b8b2befba7142116386a85a5f6c5c847c Mon Sep 17 00:00:00 2001 From: basssy Date: Fri, 25 Oct 2024 16:26:07 +0900 Subject: [PATCH 104/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=99=94=EB=A9=B4=20?= =?UTF-8?q?,=20=EB=A9=94=EC=9D=B8=ED=99=94=EB=A9=B4=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/MainContents.jsx | 10 +++++++--- src/components/management/StuffQGrid.jsx | 5 ++++- .../management/popup/FindAddressPopQGrid.jsx | 6 +++++- src/components/management/popup/PlanRequestPop.jsx | 7 +++++++ .../management/popup/PlanRequestPopQGrid.jsx | 4 ++++ src/components/ui/MainSkeleton.jsx | 4 ++-- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 8 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/components/main/MainContents.jsx b/src/components/main/MainContents.jsx index fa61b676..9490a868 100644 --- a/src/components/main/MainContents.jsx +++ b/src/components/main/MainContents.jsx @@ -136,7 +136,7 @@ export default function MainContents() { })} ) : ( - + )} @@ -147,7 +147,9 @@ export default function MainContents() {
    {recentNoticeList[0]?.title}
    {recentNoticeList[0]?.contents}
    - ) : null} + ) : ( + + )}
    @@ -168,7 +170,9 @@ export default function MainContents() { ) })} - ) : null} + ) : ( + + )} diff --git a/src/components/management/StuffQGrid.jsx b/src/components/management/StuffQGrid.jsx index 33836e79..abbafca4 100644 --- a/src/components/management/StuffQGrid.jsx +++ b/src/components/management/StuffQGrid.jsx @@ -1,11 +1,14 @@ import React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' import { AgGridReact } from 'ag-grid-react' +import { useMessage } from '@/hooks/useMessage' import 'ag-grid-community/styles/ag-grid.css' import 'ag-grid-community/styles/ag-theme-quartz.css' export default function StuffQGrid(props) { + const { getMessage } = useMessage() + const { gridData, gridColumns, isPageable = true, count, gridRef } = props /** * 행 데이터를 설정할 때 useState을 사용하여 렌더링 전반에 걸쳐 일관된 배열 참조를 유지하는 것이 좋습니다 @@ -95,7 +98,7 @@ export default function StuffQGrid(props) { onSelectionChanged={onSelectionChanged} onCellDoubleClicked={onCellDoubleClicked} pagination={isPageable} - overlayNoRowsTemplate={'물건 목록이 없습니다.'} + overlayNoRowsTemplate={`${getMessage('stuff.grid.noData')}`} getRowClass={getRowClass} autoSizeAllColumns={true} /> diff --git a/src/components/management/popup/FindAddressPopQGrid.jsx b/src/components/management/popup/FindAddressPopQGrid.jsx index b9d1bb90..383e1cc7 100644 --- a/src/components/management/popup/FindAddressPopQGrid.jsx +++ b/src/components/management/popup/FindAddressPopQGrid.jsx @@ -1,11 +1,14 @@ import React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' import { AgGridReact } from 'ag-grid-react' +import { useMessage } from '@/hooks/useMessage' import 'ag-grid-community/styles/ag-grid.css' import 'ag-grid-community/styles/ag-theme-quartz.css' export default function FindAddressPopGrid(props) { + const { getMessage } = useMessage() + const { gridData, gridColumns, isPageable = true } = props const [rowData, setRowData] = useState(null) @@ -46,7 +49,7 @@ export default function FindAddressPopGrid(props) { } return ( -
    +
    ${getMessage('stuff.grid.noData')}`} />
    ) diff --git a/src/components/management/popup/PlanRequestPop.jsx b/src/components/management/popup/PlanRequestPop.jsx index cde86d6b..bbe0f6c9 100644 --- a/src/components/management/popup/PlanRequestPop.jsx +++ b/src/components/management/popup/PlanRequestPop.jsx @@ -253,6 +253,12 @@ export default function PlanRequestPop(props) { } }, [commonCode]) + // 숫자만 입력 가능 + const handleKeyUp = (e) => { + let input = e.target + input.value = input.value.replace(/[^0-9]/g, '') + } + return (
    @@ -301,6 +307,7 @@ export default function PlanRequestPop(props) { type="text" className="input-light" value={schPlanReqNo} + onKeyUp={handleKeyUp} onChange={(e) => { setSchPlanReqNo(e.target.value) }} diff --git a/src/components/management/popup/PlanRequestPopQGrid.jsx b/src/components/management/popup/PlanRequestPopQGrid.jsx index e610a138..6e3a8467 100644 --- a/src/components/management/popup/PlanRequestPopQGrid.jsx +++ b/src/components/management/popup/PlanRequestPopQGrid.jsx @@ -1,11 +1,14 @@ import React from 'react' import { useCallback, useEffect, useMemo, useState } from 'react' import { AgGridReact } from 'ag-grid-react' +import { useMessage } from '@/hooks/useMessage' import 'ag-grid-community/styles/ag-grid.css' import 'ag-grid-community/styles/ag-theme-quartz.css' export default function PlanRequestPopQGrid(props) { + const { getMessage } = useMessage() + const { gridData, gridColumns, isPageable = true } = props const [rowData, setRowData] = useState(null) @@ -56,6 +59,7 @@ export default function PlanRequestPopQGrid(props) { rowSelection={'singleRow'} pagination={isPageable} onSelectionChanged={onSelectionChanged} + overlayNoRowsTemplate={`${getMessage('stuff.grid.noData')}`} />
    ) diff --git a/src/components/ui/MainSkeleton.jsx b/src/components/ui/MainSkeleton.jsx index fa0a48c2..e8b64e17 100644 --- a/src/components/ui/MainSkeleton.jsx +++ b/src/components/ui/MainSkeleton.jsx @@ -1,13 +1,13 @@ import Skeleton from 'react-loading-skeleton' import 'react-loading-skeleton/dist/skeleton.css' -export default function MainSkeleton() { +export default function MainSkeleton({ count }) { return ( <>
    - + ) } diff --git a/src/locales/ja.json b/src/locales/ja.json index baa74f41..91b6df42 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -587,6 +587,7 @@ "stuff.detail.planGridHeader.management": "管理", "stuff.detail.planGrid.btn1": "見積書の照会", "stuff.detail.planGrid.btn2": "Excel", + "stuff.grid.noData": "照会されたデータがありません", "length": "長さ", "height": "高さ", "output": "出力", diff --git a/src/locales/ko.json b/src/locales/ko.json index d46e7726..f21c282e 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -592,6 +592,7 @@ "stuff.detail.planGridHeader.management": "관리", "stuff.detail.planGrid.btn1": "견적서 조회", "stuff.detail.planGrid.btn2": "Excel", + "stuff.grid.noData": "조회된 데이터가 없습니다", "length": "길이", "height": "높이", "output": "출력", From c8a27c5f019f2d51de8d03b4e95d73d957a1a7ee Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Fri, 25 Oct 2024 16:32:18 +0900 Subject: [PATCH 105/139] =?UTF-8?q?=EA=B2=8C=EC=8B=9C=EA=B8=80=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20=ED=8C=9D=EC=97=85=20=EB=8B=A4=EA=B5=AD=EC=96=B4=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/community/modal/BoardDetailModal.jsx | 7 +++++-- src/locales/ja.json | 1 + src/locales/ko.json | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/community/modal/BoardDetailModal.jsx b/src/components/community/modal/BoardDetailModal.jsx index ec324966..c1ba4213 100644 --- a/src/components/community/modal/BoardDetailModal.jsx +++ b/src/components/community/modal/BoardDetailModal.jsx @@ -3,8 +3,11 @@ import { useEffect, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { handleFileDown } from '@/util/board-utils' +import { useMessage } from '@/hooks/useMessage' export default function BoardDetailModal({ noticeNo, setOpen }) { + const { getMessage } = useMessage() + // api 조회 관련 const { get } = useAxios() const [boardDetail, setBoardDetail] = useState({}) @@ -46,7 +49,7 @@ export default function BoardDetailModal({ noticeNo, setOpen }) { setOpen(false) }} > - 닫기 + {getMessage('board.sub.btn.close')}
    @@ -55,7 +58,7 @@ export default function BoardDetailModal({ noticeNo, setOpen }) { {boardDetail.listFile && (
    -
    첨부파일 목록
    +
    {getMessage('board.sub.fileList')}
    {boardDetail.listFile.map((boardFile) => (
    From eaa388204536ac7104144f671d7f7d108767606e Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 25 Oct 2024 17:30:01 +0900 Subject: [PATCH 110/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_canvasside.scss | 20 +++++++++----------- src/styles/_contents.scss | 1 - src/styles/_reset.scss | 6 ++++++ 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/styles/_canvasside.scss b/src/styles/_canvasside.scss index 66bba83d..efb79f02 100644 --- a/src/styles/_canvasside.scss +++ b/src/styles/_canvasside.scss @@ -4,30 +4,28 @@ top: 200px; left: 50px; z-index: 999999; + display: flex; width: 237px; height: 40px; line-height: 40px; background-color: #fff; border: 1px solid #DFDFDF; - padding: 0 34px 0 10px; + padding: 0 10px 0 10px; border-radius: 2px; box-shadow: 0px 7px 14px 0px rgba(0, 0, 0, 0.05); cursor: pointer; - &::before{ - content: ''; - position: absolute; - top: 50%; - right: 12px; - transform: translateY(-50%); - width: 10px; - height: 6px; + .penal-arr{ + flex: none; + width: 24px; + height: 100%; background: url(../../public/static/images/canvas/penal_arr.svg)no-repeat center; - background-size: cover; + background-size: 10px 6px; } h2{ font-size: 12px; font-weight: 500; color: #3D3D3D; + flex: 1; } .penal-table-wrap{ display: none; @@ -69,7 +67,7 @@ h2{ color: #fff; } - &::before{ + .penal-arr{ background: url(../../public/static/images/canvas/penal_arr_white.svg)no-repeat center; } .penal-table-wrap{ diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index c242a96b..e3d8d1ee 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -679,7 +679,6 @@ .infomation-box-wrap{ display: flex; - align-items: center; gap: 10px; .sub-table-box{ flex: 1 ; diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index b623dbff..525c0488 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -482,6 +482,9 @@ input[type=text]{ } &:read-only{ color: #AAA; + &:focus{ + border: 1px solid #323234; + } } &.plane{ font-family: 'Noto Sans JP', sans-serif; @@ -509,6 +512,9 @@ input[type=text]{ &:read-only{ background-color: #FAFAFA; color: #999999; + &:focus{ + border-color: #eee; + } } } } From 9f30b2e88f4b5cf0f8fc13cf566c49ea208af953 Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 25 Oct 2024 17:30:43 +0900 Subject: [PATCH 111/139] =?UTF-8?q?=EB=8B=A4=EA=B5=AD=EC=96=B4=20=EC=A0=81?= =?UTF-8?q?=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasFrame.jsx | 26 ++- .../flowDirection/FlowDirectionSetting.jsx | 174 +++++++++--------- .../lineProperty/LinePropertySetting.jsx | 111 +++++------ .../floor-plan/modal/object/DormerOffset.jsx | 12 +- .../floor-plan/modal/object/SizeSetting.jsx | 16 +- src/hooks/useContextMenu.js | 144 ++++++++------- src/locales/ja.json | 60 +++++- src/locales/ko.json | 58 ++++++ 8 files changed, 337 insertions(+), 264 deletions(-) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index e6261edc..7de221f2 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -1,32 +1,25 @@ 'use client' import { useEffect, useRef } from 'react' - import { useCanvas } from '@/hooks/useCanvas' import { useEvent } from '@/hooks/useEvent' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' -import { useRecoilValue } from 'recoil' -import { currentObjectState } from '@/store/canvasAtom' -import { useCanvasEvent } from '@/hooks/useCanvasEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' +import { useRecoilValue } from 'recoil' +import { currentMenuState } from '@/store/canvasAtom' +import { MENU } from '@/common/common' +import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' export default function CanvasFrame({ plan }) { const canvasRef = useRef(null) const { canvas } = useCanvas('canvas') - const { handleZoomClear } = useCanvasEvent() - const { contextMenu, currentContextMenu, setCurrentContextMenu, handleClick } = useContextMenu({ - externalFn: { - handleZoomClear, - }, - }) + const { contextMenu, handleClick } = useContextMenu() const { checkCanvasObjectEvent, checkUnsavedCanvasPlan } = usePlan() const { canvasLoadInit } = useCanvasConfigInitialize() - const currentObject = useRecoilValue(currentObjectState) - + const currentMenu = useRecoilValue(currentMenuState) useEvent() - const loadCanvas = () => { if (canvas) { canvas?.clear() // 캔버스를 초기화합니다. @@ -43,8 +36,6 @@ export default function CanvasFrame({ plan }) { loadCanvas() }, [plan, canvas]) - const onClickContextMenu = (index) => {} - return (
    @@ -68,6 +59,11 @@ export default function CanvasFrame({ plan }) { ))} + {[ + MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING, + MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING, + MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION, + ].includes(currentMenu) && }
    ) } diff --git a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx index ff749a6f..9fa412f9 100644 --- a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx +++ b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx @@ -1,24 +1,68 @@ import WithDraggable from '@/components/common/draggable/withDraggable' -import { useState } from 'react' +import { useEffect, useState } from 'react' import QSelectBox from '@/components/common/select/QSelectBox' import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' -const SelectOption01 = [{ name: 'M' }, { name: 'M' }, { name: 'M' }, { name: 'M' }] - export default function FlowDirectionSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, pos = contextPopupPosition } = props + const { id, pos = contextPopupPosition, target } = props const { getMessage } = useMessage() const { closePopup } = usePopup() - const [compasDeg, setCompasDeg] = useState(0) + const [compasDeg, setCompasDeg] = useState(360) + const orientations = [ + { name: `${getMessage('commons.south')}`, value: 360 }, + { name: `${getMessage('commons.south')}${getMessage('commons.east')}`, value: 315 }, + { name: `${getMessage('commons.south')}${getMessage('commons.west')}`, value: 45 }, + { name: `${getMessage('commons.east')}`, value: 270 }, + { name: `${getMessage('commons.west')}`, value: 90 }, + { name: `${getMessage('commons.north')}${getMessage('commons.east')}`, value: 225 }, + { name: `${getMessage('commons.north')}${getMessage('commons.west')}`, value: 135 }, + { name: `${getMessage('commons.north')}`, value: 180 }, + ] + const [selectedOrientation, setSelectedOrientation] = useState(orientations[0]) + const [type, setType] = useState('0') + useEffect(() => { + if (target?.angle === 0) { + setCompasDeg(360) + } else { + setCompasDeg(target?.angle ?? 360) + } + }, []) + useEffect(() => { + if (type === '0') { + setCompasDeg(selectedOrientation.value) + } + }, [selectedOrientation]) + + useEffect(() => { + if (type === '1') { + if ([15, 345, 360].includes(compasDeg)) { + setSelectedOrientation(orientations[0]) + } else if ([30, 45, 60].includes(compasDeg)) { + setSelectedOrientation(orientations[2]) + } else if ([75, 90, 105].includes(compasDeg)) { + setSelectedOrientation(orientations[4]) + } else if ([120, 135, 150].includes(compasDeg)) { + setSelectedOrientation(orientations[6]) + } else if ([165, 180, 195].includes(compasDeg)) { + setSelectedOrientation(orientations[7]) + } else if ([210, 225, 240].includes(compasDeg)) { + setSelectedOrientation(orientations[5]) + } else if ([255, 270, 285].includes(compasDeg)) { + setSelectedOrientation(orientations[3]) + } else if ([300, 315, 330].includes(compasDeg)) { + setSelectedOrientation(orientations[1]) + } + } + }, [compasDeg]) return (
    -

    面フローの設定

    +

    {getMessage('modal.shape.flow.direction.setting')}

    @@ -26,113 +70,59 @@ export default function FlowDirectionSetting(props) {
    -
    流れ方向の設定
    -
    流れ方向を選択してください。
    +
    {getMessage('modal.flow.direction.setting')}
    +
    {getMessage('modal.flow.direction.setting.info')}
    - - ドン - - 立つ + {getMessage('commons.north')} + {getMessage('commons.east')} + {getMessage('commons.south')} + {getMessage('commons.west')}
    -
    方位設定
    -
    シミュレーション計算の方向を指定します。面が向いている方位を選択してください。
    +
    {getMessage('modal.module.basic.setting.orientation.setting')}
    +
    {getMessage('modal.shape.flow.direction.setting.orientation.setting.info')}
    - - + setType(e.target.value)} /> +
    - + setSelectedOrientation(e)} />
    - - + setType(e.target.value)} /> +
    -
    setCompasDeg(180)}> - 13 -
    -
    setCompasDeg(195)}> - 12 -
    -
    setCompasDeg(210)}> - 11 -
    -
    setCompasDeg(225)}> - 10 -
    -
    setCompasDeg(240)}> - 9 -
    -
    setCompasDeg(255)}> - 8 -
    -
    setCompasDeg(270)}> - 7 -
    -
    setCompasDeg(285)}> - 6 -
    -
    setCompasDeg(300)}> - 5 -
    -
    setCompasDeg(315)}> - 4 -
    -
    setCompasDeg(330)}> - 3 -
    -
    setCompasDeg(345)}> - 2 -
    -
    setCompasDeg(0)}> - 1 -
    -
    setCompasDeg(15)}> - 24 -
    -
    setCompasDeg(30)}> - 23 -
    -
    setCompasDeg(45)}> - 22 -
    -
    setCompasDeg(60)}> - 21 -
    -
    setCompasDeg(75)}> - 20 -
    -
    setCompasDeg(90)}> - 19 -
    -
    setCompasDeg(105)}> - 18 -
    -
    setCompasDeg(120)}> - 17 -
    -
    setCompasDeg(135)}> - 16 -
    -
    setCompasDeg(150)}> - 15 -
    -
    setCompasDeg(165)}> - 14 -
    + {Array.from({ length: 180 / 15 + 1 }).map((dot, index) => ( +
    setCompasDeg(15 * (12 + index))} + > + {13 - index} +
    + ))} + {Array.from({ length: 180 / 15 - 1 }).map((dot, index) => ( +
    setCompasDeg(15 * (index + 1))} + > + {24 - index} +
    + ))}
    @@ -141,7 +131,7 @@ export default function FlowDirectionSetting(props) {
    - +
    diff --git a/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx b/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx index 16871a19..f5dc4b46 100644 --- a/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx +++ b/src/components/floor-plan/modal/lineProperty/LinePropertySetting.jsx @@ -3,99 +3,70 @@ import { useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import { useMessage } from '@/hooks/useMessage' import { usePopup } from '@/hooks/usePopup' +import { useState } from 'react' export default function LinePropertySetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition } = props const { getMessage } = useMessage() const { closePopup } = usePopup() + const properties = [ + { name: getMessage('eaves.line'), value: 'eaves' }, + { name: getMessage('ridge'), value: 'ridge' }, + { name: getMessage('oneside.flow.ridge'), value: 'onesideFlowRidge' }, + { name: getMessage('gable'), value: 'gable' }, + { name: getMessage('gable.left'), value: 'gableLeft' }, + { name: getMessage('gable.right'), value: 'gableRight' }, + { name: getMessage('yosemune'), value: 'yosemune' }, + { name: getMessage('valley'), value: 'valley' }, + { name: getMessage('l.abandon.valley'), value: 'lAbandonValley' }, + { name: getMessage('mansard'), value: 'mansard' }, + { name: getMessage('wall.merge'), value: 'wallCollection' }, + { name: getMessage('wall.merge.type'), value: 'wallCollectionType' }, + { name: getMessage('wall.merge.flow'), value: 'wallCollectionFlow' }, + { name: getMessage('wall.merge.flow.left'), value: 'wallCollectionFlowLeft' }, + { name: getMessage('wall.merge.flow.right'), value: 'wallCollectionFlowRight' }, + { name: getMessage('no.setting'), value: 'noSetting' }, + ] + const [selectedProperty, setSelectedProperty] = useState(null) return ( -
    +
    -

    各辺属性の変更

    +

    {getMessage('contextmenu.line.property.edit')}

    - 属性を変更する辺を選択してください。 - 選択した値 [龍丸] + {getMessage('modal.line.property.edit.info')} + + {getMessage('modal.line.property.edit.selected')} [ {selectedProperty?.name} ] +
    -
    設定
    +
    {getMessage('setting')}
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    -
    - - -
    + {properties.map((property, index) => { + return ( +
    + = 10 ? index + 1 : `0${index + 1}`)} + onChange={(e) => setSelectedProperty(property)} + /> + +
    + ) + })}
    - +
    diff --git a/src/components/floor-plan/modal/object/DormerOffset.jsx b/src/components/floor-plan/modal/object/DormerOffset.jsx index 442e92df..b4292821 100644 --- a/src/components/floor-plan/modal/object/DormerOffset.jsx +++ b/src/components/floor-plan/modal/object/DormerOffset.jsx @@ -13,26 +13,26 @@ export default function DormerOffset(props) {
    -

    도머 오프셋

    +

    {getMessage('contextmenu.dormer.offset')}

    -
    移動する方向を入力してください
    +
    {getMessage('modal.dormer.offset.info')}
    -

    長さ

    +

    {getMessage('length')}

    - +
    mm
    - +
    mm
    @@ -46,7 +46,7 @@ export default function DormerOffset(props) {
    - +
    diff --git a/src/components/floor-plan/modal/object/SizeSetting.jsx b/src/components/floor-plan/modal/object/SizeSetting.jsx index ca7d4773..bdb25821 100644 --- a/src/components/floor-plan/modal/object/SizeSetting.jsx +++ b/src/components/floor-plan/modal/object/SizeSetting.jsx @@ -2,7 +2,6 @@ import { useRecoilValue } from 'recoil' import { useMessage } from '@/hooks/useMessage' -import { canvasState } from '@/store/canvasAtom' import WithDraggable from '@/components/common/draggable/WithDraggable' import { usePopup } from '@/hooks/usePopup' import { contextPopupPositionState } from '@/store/popupAtom' @@ -11,16 +10,15 @@ import { useState } from 'react' export default function SizeSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const [settingTarget, setSettingTarget] = useState(1) - const { id, pos = contextPopupPosition } = props + const { id, pos = contextPopupPosition, target } = props const { getMessage } = useMessage() - const canvas = useRecoilValue(canvasState) const { closePopup } = usePopup() return (
    -

    サイズ変更

    +

    {getMessage('modal.size.setting')}

    @@ -30,11 +28,11 @@ export default function SizeSetting(props) {
    - + mm
    - + mm
    @@ -43,11 +41,11 @@ export default function SizeSetting(props) {
    - + mm
    - + mm
    @@ -62,7 +60,7 @@ export default function SizeSetting(props) {
    - +
    diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index bbd5115b..d4e690e7 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -20,16 +20,20 @@ import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/Di import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/LinePropertySetting' import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' +import { useMessage } from '@/hooks/useMessage' +import { useCanvasEvent } from '@/hooks/useCanvasEvent' -export function useContextMenu({ externalFn }) { +export function useContextMenu() { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 const setContextPopupPosition = useSetRecoilState(contextPopupPositionState) // 현재 메뉴 const [contextMenu, setContextMenu] = useState([[]]) // 메뉴.object 별 context menu const [currentContextMenu, setCurrentContextMenu] = useState(null) // 선택한 contextMenu const currentObject = useRecoilValue(currentObjectState) + const { getMessage } = useMessage() const { addPopup } = usePopup() const [popupId, setPopupId] = useState(uuidv4()) const [gridColor, setGridColor] = useRecoilState(gridColorState) + const { handleZoomClear } = useCanvasEvent() const currentMenuSetting = (position) => { switch (currentMenu) { case MENU.PLAN_DRAWING: @@ -37,26 +41,26 @@ export function useContextMenu({ externalFn }) { [ { id: 'gridMove', - name: '그리드 이동', + name: getMessage('modal.grid.move'), component: , }, { id: 'gridCopy', - name: '그리드 복사', + name: getMessage('modal.grid.copy'), component: , }, { id: 'gridColorEdit', - name: '그리드 색 변경', + name: getMessage('modal.grid.color.edit'), component: , }, { id: 'remove', - name: '삭제', + name: getMessage('delete'), }, { id: 'removeAll', - name: '전체 삭제', + name: getMessage('delete.all'), }, ], ]) @@ -75,63 +79,61 @@ export function useContextMenu({ externalFn }) { [ { id: 'refresh', - name: '새로고침', - fn: () => { - externalFn.handleZoomClear() - }, + name: getMessage('refresh'), + fn: () => handleZoomClear(), }, { id: 'roofMaterialPlacement', - name: '지붕재 배치', + name: getMessage('contextmenu.roof.material.placement'), }, { id: 'roofMaterialRemove', - name: '지붕재 삭제', + name: getMessage('contextmenu.roof.material.remove'), }, { id: 'roofMaterialRemoveAll', - name: '지붕재 전체 삭제', + name: getMessage('contextmenu.roof.material.remove.all'), }, { id: 'selectMove', - name: '선택・이동', + name: getMessage('contextmenu.select.move'), }, { id: 'wallLineRemove', - name: '외벽선 삭제', + name: getMessage('contextmenu.wallline.remove'), }, ], [ { id: 'sizeEdit', - name: '사이즈 변경', + name: getMessage('contextmenu.size.edit'), component: , }, { id: 'auxiliaryMove', - name: '보조선 이동(M)', + name: `${getMessage('contextmenu.auxiliary.move')}(M)`, component: , }, { id: 'auxiliaryCopy', - name: '보조선 복사(C)', + name: `${getMessage('contextmenu.auxiliary.copy')}(C)`, component: , }, { id: 'auxiliaryRemove', - name: '보조선 삭제(D)', + name: `${getMessage('contextmenu.auxiliary.remove')}(D)`, }, { id: 'auxiliaryVerticalBisector', - name: '보조선 수직이등분선', + name: getMessage('contextmenu.auxiliary.vertical.bisector'), }, { id: 'auxiliaryCut', - name: '보조선 절삭', + name: getMessage('contextmenu.auxiliary.cut'), }, { id: 'auxiliaryRemoveAll', - name: '보조선 전체 삭제', + name: getMessage('contextmenu.auxiliary.remove.all'), }, ], ]) @@ -146,33 +148,34 @@ export function useContextMenu({ externalFn }) { [ { id: 'sizeEdit', - name: '사이즈 변경', + name: getMessage('contextmenu.size.edit'), }, { id: 'remove', - name: '삭제(D)', + name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'move', - name: '이동(M)', + name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'copy', - name: '복사(C)', + name: `${getMessage('contextmenu.copy')}(C)`, }, ], [ { id: 'roofMaterialEdit', - name: '지붕재 변경', + name: getMessage('contextmenu.roof.material.edit'), }, { id: 'linePropertyEdit', - name: '각 변 속성 변경', + name: getMessage('contextmenu.line.property.edit'), + component: , }, { id: 'flowDirectionEdit', - name: '흐름 방향 변경', + name: getMessage('contextmenu.flow.direction.edit'), }, ], ]) @@ -200,7 +203,6 @@ export function useContextMenu({ externalFn }) { }, [currentContextMenu]) useEffect(() => { - console.log('object name', currentObject?.name) if (currentObject?.name) { switch (currentObject.name) { case 'triangleDormer': @@ -209,29 +211,29 @@ export function useContextMenu({ externalFn }) { [ { id: 'sizeEdit', - name: '사이즈 변경', - component: , + name: getMessage('contextmenu.size.edit'), + component: , }, { id: 'dormerRemove', - name: '삭제(D)', + name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'dormerMove', - name: '이동(M)', + name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'dormerCopy', - name: '복사(C)', + name: `${getMessage('contextmenu.copy')}(C)`, }, { id: 'roofMaterialEdit', - name: '지붕재 변경', + name: getMessage('contextmenu.roof.material.edit'), component: , }, { id: 'dormerOffset', - name: '도머 오프셋', + name: getMessage('contextmenu.dormer.offset'), component: , }, ], @@ -247,32 +249,32 @@ export function useContextMenu({ externalFn }) { }, { id: 'roofMaterialRemove', - name: '삭제(D)', + name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'roofMaterialMove', - name: '이동(M)', + name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'roofMaterialCopy', - name: '복사(C)', + name: `${getMessage('contextmenu.copy')}(C)`, }, ], [ { id: 'roofMaterialEdit', - name: '지붕재 변경', + name: getMessage('contextmenu.roof.material.edit'), component: , }, { id: 'linePropertyEdit', - name: '각 변 속성 변경', + name: getMessage('contextmenu.line.property.edit'), component: , }, { id: 'flowDirectionEdit', - name: '흐름 뱡향 변경', - component: , + name: getMessage('contextmenu.flow.direction.edit'), + component: , }, ], ]) @@ -282,23 +284,23 @@ export function useContextMenu({ externalFn }) { [ { id: 'sizeEdit', - name: '사이즈 변경', + name: getMessage('contextmenu.size.edit'), }, { id: 'openingRemove', - name: '삭제(D)', + name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'openingMove', - name: '이동(M)', + name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'openingCopy', - name: '복사(C)', + name: `${getMessage('contextmenu.copy')}(C)`, }, { id: 'openingOffset', - name: '개구 오프셋', + name: getMessage('contextmenu.opening.offset'), }, ], ]) @@ -308,19 +310,19 @@ export function useContextMenu({ externalFn }) { [ { id: 'lengthTextRemove', - name: '삭제', + name: getMessage('contextmenu.remove'), }, { id: 'lengthTextMove', - name: '이동', + name: getMessage('contextmenu.move'), }, { id: 'lengthTextAuxiliaryLineEdit', - name: '치수 보조선 변경', + name: getMessage('contextmenu.dimension.auxiliary.line.edit'), }, { id: 'displayEdit', - name: '표시 변경', + name: getMessage('contextmenu.display.edit'), }, ], ]) @@ -330,24 +332,24 @@ export function useContextMenu({ externalFn }) { [ { id: 'commonTextRemove', - name: '삭제', + name: getMessage('contextmenu.remove'), }, { id: 'commonTextMove', - name: '이동', + name: getMessage('contextmenu.move'), }, { id: 'commonTextCopy', - name: '복사', + name: getMessage('contextmenu.copy'), }, { id: 'commonTextFontSetting', - name: '폰트 설정', + name: getMessage('contextmenu.font.setting'), component: , }, { id: 'commonTextEdit', - name: '편집', + name: getMessage('contextmenu.edit'), }, ], ]) @@ -357,23 +359,23 @@ export function useContextMenu({ externalFn }) { [ { id: 'gridMove', - name: '그리드 이동', + name: getMessage('modal.grid.move'), }, { id: 'gridCopy', - name: '그리드 복사', + name: getMessage('modal.grid.copy'), }, { id: 'gridColorEdit', - name: '그리드 색 변경', + name: getMessage('contextmenu.grid.color.edit'), }, { id: 'remove', - name: '삭제', + name: getMessage('contextmenu.remove'), }, { id: 'removeAll', - name: '전체 삭제', + name: getMessage('contextmenu.remove.all'), }, ], ]) @@ -383,19 +385,19 @@ export function useContextMenu({ externalFn }) { [ { id: 'dimensionLineRemove', - name: '삭제', + name: getMessage('contextmenu.remove'), }, { id: 'dimensionLineMove', - name: '이동', + name: getMessage('contextmenu.move'), }, { id: 'dimensionAuxiliaryLineEdit', - name: '치수 보조선 변경', + name: getMessage('contextmenu.dimension.auxiliary.line.edit'), }, { id: 'dimensionLineDisplayEdit', - name: '표시 변경', + name: getMessage('contextmenu.display.edit'), component: , }, ], @@ -406,20 +408,20 @@ export function useContextMenu({ externalFn }) { [ { id: 'sizeEdit', - name: '사이즈 변경', + name: getMessage('contextmenu.size.edit'), component: , }, { id: 'remove', - name: '삭제(D)', + name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'move', - name: '이동(M)', + name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'copy', - name: '복사(C)', + name: `${getMessage('contextmenu.copy')}(C)`, }, ], ]) diff --git a/src/locales/ja.json b/src/locales/ja.json index c5522fe2..81b85161 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -192,6 +192,8 @@ "modal.grid.copy.info": "間隔を設定し、コピー方向を選択します", "modal.grid.copy.length": "長さ", "modal.grid.copy.save": "保存", + "modal.grid.color.edit": "그리드 색 변경(JA)", + "modal.dormer.offset.info": "移動する方向を入力してください", "modal.common.save": "保存", "modal.common.add": "追加", "modal.common.prev": "以前", @@ -261,12 +263,54 @@ "modal.placement.surface.setting.diagonal.length": "斜めの長さ", "modal.color.picker.title": "色の設定", "modal.color.picker.default.color": "基本色", + "modal.size.setting": "サイズ変更", + "modal.shape.flow.direction.setting": "面フローの設定", + "modal.shape.flow.direction.setting.orientation.setting.info": "シミュレーション計算の方向を指定します。面が向いている方位を選択してください。", + "modal.shape.flow.direction.setting.orientation.8": "8方位に選ぶ", + "modal.shape.flow.direction.setting.orientation.24": "24方位から選択する (表記は8方位です。)", + "modal.panel.batch.statistic": "パネル配置集計", + "modal.panel.batch.statistic.roof.shape": "屋根面", + "modal.panel.batch.statistic.power.generation.amount": "発電量", + "modal.panel.batch.statistic.total": "合計", + "modal.flow.direction.setting": "流れ方向の設定", + "modal.flow.direction.setting.info": "流れ方向を選択してください。", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.save": "저장되었습니다.", "plan.message.delete": "삭제되었습니다.", "setting": "設定", + "delete": "삭제(JA)", + "delete.all": "전체 삭제(JA)", + "refresh": "새로고침(JA)", + "contextmenu.roof.material.placement": "지붕재 배치(JA)", + "contextmenu.roof.material.edit": "지붕재 변경(JA)", + "contextmenu.roof.material.remove": "지붕재 삭제(JA)", + "contextmenu.roof.material.remove.all": "지붕재 전체 삭제(JA)", + "contextmenu.dormer.offset": "도머 오프셋(JA)", + "contextmenu.select.move": "선택・이동(JA)", + "contextmenu.wallline.remove": "외벽선 삭제(JA)", + "contextmenu.size.edit": "サイズ変更", + "contextmenu.auxiliary.move": "보조선 이동(JA)", + "contextmenu.auxiliary.copy": "보조선 복사(JA)", + "contextmenu.auxiliary.remove": "보조선 삭제(JA)", + "contextmenu.auxiliary.vertical.bisector": "보조선 수직이등분선(JA)", + "contextmenu.auxiliary.cut": "보조선 절삭(JA)", + "contextmenu.auxiliary.remove.all": "보조선 전체 삭제(JA)", + "contextmenu.line.property.edit": "各辺属性の変更", + "modal.line.property.edit.info": "属性を変更する辺を選択してください。", + "modal.line.property.edit.selected": "選択した値", + "contextmenu.flow.direction.edit": "흐름 방향 변경(JA)", + "contextmenu.font.setting": "폰트 설정(JA)", + "contextmenu.grid.color.edit": "그리드 색 변경(JA)", + "contextmenu.dimension.auxiliary.line.edit": "치수 보조선 변경(JA)", + "contextmenu.display.edit": "표시 변경(JA)", + "contextmenu.opening.offset": "개구 오프셋(JA)", + "contextmenu.remove": "삭제(JA)", + "contextmenu.remove.all": "전체 삭제(JA)", + "contextmenu.move": "이동(JA)", + "contextmenu.copy": "복사(JA)", + "contextmenu.edit": "편집(JA)", "common.message.no.data": "No data", "common.message.no.dataDown": "ダウンロードするデータがありません", "common.message.noData": "表示するデータがありません", @@ -357,7 +401,7 @@ "common.require": "必須", "commons.west": "立つ", "commons.east": "ドン", - "commons.south": "立つ", + "commons.south": "南", "commons.north": "北", "site.name": "Q.CAST III", "site.sub_name": "太陽光発電システム図面管理サイト", @@ -595,9 +639,23 @@ "size": "寸", "size.angle": "寸(度)", "eaves": "軒", + "eaves.line": "軒先", "gable": "ケラバ", + "gable.left": "ケラバ左", + "gable.right": "ケラバ右", + "ridge": "龍丸", + "oneside.flow.ridge": "片側の流れ", + "yosemune": "ヨセムネ", + "valley": "谷", + "l.abandon.valley": "Lの捨て渓谷", + "mansard": "マンサード", "wall": "壁", "wall.merge": "壁取り", + "wall.merge.type": "壁取り(型)", + "wall.merge.flow": "壁取合(流れ)", + "wall.merge.flow.left": "壁取合(流れ左)", + "wall.merge.flow.right": "壁取り(流れ右)", + "no.setting": "설정없음", "hajebichi": "ハゼビーチ", "straight.line": "直線", "right.angle": "直角", diff --git a/src/locales/ko.json b/src/locales/ko.json index 529dc494..12102c3b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -196,6 +196,8 @@ "modal.grid.copy.info": "간격을 설정하고 복사 방향을 선택하십시오", "modal.grid.copy.length": "길이", "modal.grid.copy.save": "저장", + "modal.grid.color.edit": "그리드 색 변경", + "modal.dormer.offset.info": "이동할 거리와 방향을 입력해주세요.", "modal.common.save": "저장", "modal.common.add": "추가", "modal.common.prev": "이전", @@ -266,12 +268,54 @@ "modal.placement.surface.setting.diagonal.length": "대각선 길이", "modal.color.picker.title": "색 설정", "modal.color.picker.default.color": "기본색상", + "modal.size.setting": "사이즈 변경", + "modal.shape.flow.direction.setting": "면 흐름 설정", + "modal.shape.flow.direction.setting.orientation.setting.info": "시뮬레이션 계산용 방위를 지정합니다. 면이 향하고 있는 방위를 선택해 주세요.", + "modal.shape.flow.direction.setting.orientation.8": "8방위로 선택한다.", + "modal.shape.flow.direction.setting.orientation.24": "24방위로 선택한다.(표기는 8방위입니다.)", + "modal.panel.batch.statistic": "패널 배치 집계", + "modal.panel.batch.statistic.roof.shape": "지붕면", + "modal.panel.batch.statistic.power.generation.amount": "발전량", + "modal.panel.batch.statistic.total": "합계", + "modal.flow.direction.setting": "흐름 방향 설정", + "modal.flow.direction.setting.info": "흐름방향을 선택하세요.", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.save": "저장되었습니다.", "plan.message.delete": "삭제되었습니다.", "setting": "설정", + "delete": "삭제", + "delete.all": "전체 삭제", + "refresh": "새로고침", + "contextmenu.roof.material.placement": "지붕재 배치", + "contextmenu.roof.material.edit": "지붕재 변경", + "contextmenu.roof.material.remove": "지붕재 삭제", + "contextmenu.roof.material.remove.all": "지붕재 전체 삭제", + "contextmenu.dormer.offset": "도머 오프셋", + "contextmenu.select.move": "선택・이동", + "contextmenu.wallline.remove": "외벽선 삭제", + "contextmenu.size.edit": "사이즈 변경", + "contextmenu.auxiliary.move": "보조선 이동", + "contextmenu.auxiliary.copy": "보조선 복사", + "contextmenu.auxiliary.remove": "보조선 삭제", + "contextmenu.auxiliary.vertical.bisector": "보조선 수직이등분선", + "contextmenu.auxiliary.cut": "보조선 절삭", + "contextmenu.auxiliary.remove.all": "보조선 전체 삭제", + "contextmenu.line.property.edit": "각 변 속성 변경", + "modal.line.property.edit.info": "속성을 변경할 변을 선택해주세요.", + "modal.line.property.edit.selected": "선택한 값", + "contextmenu.flow.direction.edit": "흐름 방향 변경", + "contextmenu.font.setting": "폰트 설정", + "contextmenu.grid.color.edit": "그리드 색 변경", + "contextmenu.dimension.auxiliary.line.edit": "치수 보조선 변경", + "contextmenu.display.edit": "표시 변경", + "contextmenu.opening.offset": "개구 오프셋", + "contextmenu.remove": "삭제", + "contextmenu.remove.all": "전체 삭제", + "contextmenu.move": "이동", + "contextmenu.copy": "복사", + "contextmenu.edit": "편집", "common.message.no.data": "No data", "common.message.no.dataDown": "No data to download", "common.message.noData": "No data to display", @@ -600,9 +644,23 @@ "size": "치수", "size.angle": "寸(度)", "eaves": "처마", + "eaves.line": "처마선", "gable": "케라바", + "gable.left": "케라바 왼쪽", + "gable.right": "케라바 오른쪽", + "ridge": "용마루", + "oneside.flow.ridge": "한쪽흐름 용마루", + "yosemune": "요세무네", + "valley": "골짜기", + "l.abandon.valley": "L의 버림 계곡", + "mansard": "멘사드", "wall": "벽", "wall.merge": "벽취합", + "wall.merge.type": "벽취합(형)", + "wall.merge.flow": "벽취합(흐름)", + "wall.merge.flow.left": "벽취합(흐름 왼쪽)", + "wall.merge.flow.right": "벽취합(흐름 오른쪽)", + "no.setting": "설정없음", "hajebichi": "하제비치", "straight.line": "직선", "right.angle": "직각", From 5465756526515e3e9100c3365ea81c4d9aa0411a Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 25 Oct 2024 17:30:59 +0900 Subject: [PATCH 112/139] =?UTF-8?q?=ED=8C=A8=EB=84=90=20=EB=B0=B0=EC=B9=98?= =?UTF-8?q?=20=EC=A7=91=EA=B3=84=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/panelBatch/PanelBatchStatistics.jsx | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx diff --git a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx new file mode 100644 index 00000000..2d36c4eb --- /dev/null +++ b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx @@ -0,0 +1,37 @@ +import WithDraggable from '@/components/common/draggable/withDraggable' +import { useState } from 'react' +import { useMessage } from '@/hooks/useMessage' + +export default function PanelBatchStatistics() { + const { getMessage } = useMessage() + const [isFold, setIsFold] = useState(false) + const [pos, setPos] = useState({ + x: 0, + y: 30, + }) + + return ( + +
    +

    {getMessage('modal.panel.batch.statistic')}

    + +
    + + + + + + + + + + + + + +
    {getMessage('modal.panel.batch.statistic.roof.shape')}{getMessage('modal.panel.batch.statistic.power.generation.amount')} (kW)
    {getMessage('modal.panel.batch.statistic.total')}0.000
    +
    +
    +
    + ) +} From c10d757f6968fef6547420cfb34202dc5b09ad4d Mon Sep 17 00:00:00 2001 From: minsik Date: Fri, 25 Oct 2024 17:38:22 +0900 Subject: [PATCH 113/139] merge --- src/components/floor-plan/CanvasFrame.jsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index 0117a871..f9183be8 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -8,12 +8,10 @@ import { useCanvas } from '@/hooks/useCanvas' import { useEvent } from '@/hooks/useEvent' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' -import { currentObjectState, modifiedPlanFlagState } from '@/store/canvasAtom' +import { currentMenuState, currentObjectState, modifiedPlanFlagState } from '@/store/canvasAtom' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import QContextMenu from '@/components/common/context-menu/QContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' -import { useRecoilValue } from 'recoil' -import { currentMenuState } from '@/store/canvasAtom' import { MENU } from '@/common/common' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' @@ -24,9 +22,9 @@ export default function CanvasFrame({ plan }) { const { handleZoomClear } = useCanvasEvent() const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() const currentObject = useRecoilValue(currentObjectState) - + const currentMenu = useRecoilValue(currentMenuState) const { contextMenu, handleClick } = useContextMenu() - const { checkCanvasObjectEvent, checkUnsavedCanvasPlan } = usePlan() + const { checkCanvasObjectEvent, checkUnsavedCanvasPlan, resetModifiedPlans } = usePlan() useEvent() const loadCanvas = () => { From 70b2141a6c0a7572e2864eef99f32c9c1fb7da06 Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 28 Oct 2024 09:33:50 +0900 Subject: [PATCH 114/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=AA=A9=EB=A1=9D,?= =?UTF-8?q?=ED=98=84=ED=99=A9=20=EB=AF=B8=EC=82=AC=EC=9A=A9=20=EC=A3=BC?= =?UTF-8?q?=EC=84=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 20 +++++++++---------- src/components/management/StuffPlanQGrid.jsx | 20 +++++++++---------- src/components/management/StuffQGrid.jsx | 10 +++++----- .../management/popup/FindAddressPopQGrid.jsx | 2 +- .../management/popup/PlanRequestPopQGrid.jsx | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 64cd7f33..138a3b85 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -33,8 +33,8 @@ export default function Stuff() { const { get } = useAxios(globalLocaleState) const gridRef = useRef() - const [selectedRowData, setSelectedRowData] = useState([]) - const [selectedRowDataCount, setSelectedRowDataCount] = useState(0) + // const [selectedRowData, setSelectedRowData] = useState([]) + // const [selectedRowDataCount, setSelectedRowDataCount] = useState(0) const router = useRouter() const pathname = usePathname() @@ -165,11 +165,11 @@ export default function Stuff() { } } - //그리드 체크박스 선택시 - const getSelectedRowdata = (data) => { - setSelectedRowData(data) - setSelectedRowDataCount(data.length) - } + //그리드 체크박스 선택시 미사용 + // const getSelectedRowdata = (data) => { + // setSelectedRowData(data) + // setSelectedRowDataCount(data.length) + // } //물건삭제 // const fnDeleteRowData = (data) => { @@ -405,8 +405,8 @@ export default function Stuff() { {convertNumberToPriceDecimal(totalCount)}
  • - {getMessage('stuff.search.grid.selected')} - {convertNumberToPriceDecimal(selectedRowDataCount)} + {/* {getMessage('stuff.search.grid.selected')} */} + {/* {convertNumberToPriceDecimal(selectedRowDataCount)} */}
  • @@ -428,7 +428,7 @@ export default function Stuff() {
    - +
    diff --git a/src/components/management/StuffPlanQGrid.jsx b/src/components/management/StuffPlanQGrid.jsx index 108e17a2..1c8b88ba 100644 --- a/src/components/management/StuffPlanQGrid.jsx +++ b/src/components/management/StuffPlanQGrid.jsx @@ -6,7 +6,7 @@ export default function StuffPlanQGrid(props) { const { planGridData, planGridColumns, isPageable = true } = props const [rowData, setRowData] = useState(null) - const [gridApi, setGridApi] = useState(null) + // const [gridApi, setGridApi] = useState(null) const [colDefs, setColDefs] = useState(planGridColumns) const defaultColDef = useMemo(() => { @@ -20,24 +20,24 @@ export default function StuffPlanQGrid(props) { } }, []) - const rowBuffer = 100 + const rowBuffer = 10 useEffect(() => { planGridData ? setRowData(planGridData) : '' }, [planGridData]) - const onGridReady = useCallback( - (params) => { - setGridApi(params.api) - planGridData ? setRowData(planGridData) : '' - }, - [planGridData], - ) + // const onGridReady = useCallback( + // (params) => { + // setGridApi(params.api) + // planGridData ? setRowData(planGridData) : '' + // }, + // [planGridData], + // ) return (
    { - props.getSelectedRowdata(event.api.getSelectedRows()) - }, []) + // 체크박스 체크시 체크박스 미사용 + // const onSelectionChanged = useCallback((event) => { + // props.getSelectedRowdata(event.api.getSelectedRows()) + // }, []) //더블클릭 const onCellDoubleClicked = useCallback((event) => { @@ -95,7 +95,7 @@ export default function StuffQGrid(props) { isRowSelectable={isRowSelectable} rowSelection={'multiple'} suppressRowClickSelection={true} - onSelectionChanged={onSelectionChanged} + // onSelectionChanged={onSelectionChanged} onCellDoubleClicked={onCellDoubleClicked} pagination={isPageable} overlayNoRowsTemplate={`${getMessage('stuff.grid.noData')}`} diff --git a/src/components/management/popup/FindAddressPopQGrid.jsx b/src/components/management/popup/FindAddressPopQGrid.jsx index 383e1cc7..ba703625 100644 --- a/src/components/management/popup/FindAddressPopQGrid.jsx +++ b/src/components/management/popup/FindAddressPopQGrid.jsx @@ -28,7 +28,7 @@ export default function FindAddressPopGrid(props) { } }, []) - const rowBuffer = 100 + const rowBuffer = 10 useEffect(() => { gridData ? setRowData(gridData) : '' diff --git a/src/components/management/popup/PlanRequestPopQGrid.jsx b/src/components/management/popup/PlanRequestPopQGrid.jsx index 6e3a8467..955a24ff 100644 --- a/src/components/management/popup/PlanRequestPopQGrid.jsx +++ b/src/components/management/popup/PlanRequestPopQGrid.jsx @@ -28,7 +28,7 @@ export default function PlanRequestPopQGrid(props) { } }, []) - const rowBuffer = 100 + const rowBuffer = 20 useEffect(() => { gridData ? setRowData(gridData) : '' From d834e68b239f29dacfacfef064c94aead07efda3 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 28 Oct 2024 10:04:43 +0900 Subject: [PATCH 115/139] =?UTF-8?q?contextmenu=20shortcut(=EB=8B=A8?= =?UTF-8?q?=EC=B6=95=ED=82=A4)=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/context-menu/QContextMenu.jsx | 14 +++--- src/components/floor-plan/CanvasFrame.jsx | 14 ++---- src/hooks/useContextMenu.js | 43 ++++++++++++++++++- src/store/contextMenu.js | 11 +++++ 4 files changed, 61 insertions(+), 21 deletions(-) create mode 100644 src/store/contextMenu.js diff --git a/src/components/common/context-menu/QContextMenu.jsx b/src/components/common/context-menu/QContextMenu.jsx index 8e3e2314..d1d73df3 100644 --- a/src/components/common/context-menu/QContextMenu.jsx +++ b/src/components/common/context-menu/QContextMenu.jsx @@ -1,15 +1,13 @@ 'use client' -import { useEffect, useState } from 'react' +import { useEffect } from 'react' import '@/styles/contents.scss' +import { useRecoilState } from 'recoil' +import { contextMenuState } from '@/store/contextMenu' export default function QContextMenu(props) { - const { contextRef, canvasProps } = props - - // const children = useRecoilValue(modalContent) - const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }) - + const { contextRef, canvasProps, handleKeyup } = props + const [contextMenu, setContextMenu] = useRecoilState(contextMenuState) const activeObject = canvasProps?.getActiveObject() //액티브된 객체를 가져옴 - let contextType = '' if (activeObject) { @@ -27,7 +25,7 @@ export default function QContextMenu(props) { const handleContextMenu = (e) => { // e.preventDefault() //기존 contextmenu 막고 setContextMenu({ visible: true, x: e.pageX, y: e.pageY }) - // console.log(111, canvasProps) + document.addEventListener('keyup', (e) => handleKeyup(e)) canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //한번 노출 후 이벤트 삭제 } diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index f9183be8..c2a73b63 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -23,7 +23,7 @@ export default function CanvasFrame({ plan }) { const { canvasLoadInit, gridInit } = useCanvasConfigInitialize() const currentObject = useRecoilValue(currentObjectState) const currentMenu = useRecoilValue(currentMenuState) - const { contextMenu, handleClick } = useContextMenu() + const { contextMenu, handleClick, handleKeyup } = useContextMenu() const { checkCanvasObjectEvent, checkUnsavedCanvasPlan, resetModifiedPlans } = usePlan() useEvent() @@ -55,19 +55,11 @@ export default function CanvasFrame({ plan }) {
    - + {contextMenu.map((menus, index) => (
      {menus.map((menu) => ( -
    • { - if (menu.fn) { - menu.fn() - } - handleClick(e, menu) - }} - > +
    • handleClick(e, menu)}> {menu.name}
    • ))} diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index d4e690e7..c5134e25 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -22,6 +22,7 @@ import LinePropertySetting from '@/components/floor-plan/modal/lineProperty/Line import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/FlowDirectionSetting' import { useMessage } from '@/hooks/useMessage' import { useCanvasEvent } from '@/hooks/useCanvasEvent' +import { contextMenuState } from '@/store/contextMenu' export function useContextMenu() { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 @@ -33,6 +34,7 @@ export function useContextMenu() { const { addPopup } = usePopup() const [popupId, setPopupId] = useState(uuidv4()) const [gridColor, setGridColor] = useRecoilState(gridColorState) + const [qContextMenu, setQContextMenu] = useRecoilState(contextMenuState) const { handleZoomClear } = useCanvasEvent() const currentMenuSetting = (position) => { switch (currentMenu) { @@ -112,15 +114,18 @@ export function useContextMenu() { { id: 'auxiliaryMove', name: `${getMessage('contextmenu.auxiliary.move')}(M)`, + shortcut: ['m', 'M'], component: , }, { id: 'auxiliaryCopy', name: `${getMessage('contextmenu.auxiliary.copy')}(C)`, + shortcut: ['c', 'C'], component: , }, { id: 'auxiliaryRemove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.auxiliary.remove')}(D)`, }, { @@ -152,14 +157,17 @@ export function useContextMenu() { }, { id: 'remove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'move', + shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'copy', + shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, ], @@ -187,11 +195,29 @@ export function useContextMenu() { } const handleClick = (e, menu) => { + if (menu?.fn) { + menu.fn() + } setContextPopupPosition({ - x: e.clientX, - y: e.clientY, + x: e?.clientX, + y: e?.clientY, }) setCurrentContextMenu(menu) + setQContextMenu({ ...qContextMenu, visible: false }) + } + + const handleKeyup = (e) => { + let menu = null + + for (let i = 0; i < contextMenu.length; i++) { + const temp = contextMenu[i].filter((menu) => { + return menu.shortcut?.includes(e.key) + }) + + if (temp.length > 0) menu = temp + } + + handleClick(null, menu) } useEffect(() => { @@ -216,14 +242,17 @@ export function useContextMenu() { }, { id: 'dormerRemove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'dormerMove', + shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'dormerCopy', + shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, { @@ -249,14 +278,17 @@ export function useContextMenu() { }, { id: 'roofMaterialRemove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'roofMaterialMove', + shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'roofMaterialCopy', + shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, ], @@ -288,14 +320,17 @@ export function useContextMenu() { }, { id: 'openingRemove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'openingMove', + shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'openingCopy', + shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, { @@ -413,14 +448,17 @@ export function useContextMenu() { }, { id: 'remove', + shortcut: ['d', 'D'], name: `${getMessage('contextmenu.remove')}(D)`, }, { id: 'move', + shortcut: ['m', 'M'], name: `${getMessage('contextmenu.move')}(M)`, }, { id: 'copy', + shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, ], @@ -439,5 +477,6 @@ export function useContextMenu() { currentContextMenu, setCurrentContextMenu, handleClick, + handleKeyup, } } diff --git a/src/store/contextMenu.js b/src/store/contextMenu.js new file mode 100644 index 00000000..31b18f53 --- /dev/null +++ b/src/store/contextMenu.js @@ -0,0 +1,11 @@ +import { atom } from 'recoil' + +export const contextMenuState = atom({ + key: 'contextMenuState', + default: { + visible: false, + x: 0, + y: 0, + }, + dangerouslyAllowMutability: true, +}) From f89b249b9899158e038fb017d8935010b208d763 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 28 Oct 2024 10:37:53 +0900 Subject: [PATCH 116/139] =?UTF-8?q?=EA=B2=BD=EC=82=AC,=20=EA=B0=81?= =?UTF-8?q?=EB=8F=84=20=EC=84=A4=EC=A0=95=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 8 +++- src/components/floor-plan/modal/Slope.jsx | 7 +-- .../modal/eavesGable/EavesGableEdit.jsx | 4 +- .../modal/eavesGable/type/Eaves.jsx | 9 ++-- .../modal/eavesGable/type/Gable.jsx | 16 +++++-- .../placementShape/PlacementShapeSetting.jsx | 18 +------ .../roofShape/RoofShapePassivitySetting.jsx | 5 +- .../modal/roofShape/RoofShapeSetting.jsx | 7 ++- .../modal/roofShape/passivity/Eaves.jsx | 9 ++-- .../modal/roofShape/passivity/Gable.jsx | 9 ++-- .../modal/roofShape/type/Direction.jsx | 4 +- .../modal/roofShape/type/Pattern.jsx | 4 +- .../floor-plan/modal/roofShape/type/Ridge.jsx | 4 +- .../floor-plan/modal/roofShape/type/Side.jsx | 7 +-- .../modal/roofShape/type/option/Eaves.jsx | 4 +- .../roofShape/type/option/HipAndGable.jsx | 4 +- .../roofShape/type/option/Jerkinhead.jsx | 12 ++++- src/hooks/common/useCanvasConfigInitialize.js | 26 ++++++++-- src/hooks/roofcover/useEavesGableEdit.js | 6 ++- .../roofcover/useRoofShapePassivitySetting.js | 7 ++- src/hooks/roofcover/useRoofShapeSetting.js | 16 ++++--- src/hooks/useLine.js | 2 + src/hooks/usePolygon.js | 2 + src/store/canvasAtom.js | 48 +++++++++++++++++++ src/store/settingAtom.js | 20 ++++++++ src/util/canvas-util.js | 9 ++++ 26 files changed, 201 insertions(+), 66 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index a1d56b08..37c9a75f 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -12,7 +12,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { idx: 0, area: 0, children: [], - initialize: function (points, options, canvas) { + initialize: function (points, options, length = 0) { this.callSuper('initialize', points, { ...options, selectable: options.selectable ?? true }) if (options.id) { this.id = options.id @@ -27,7 +27,11 @@ export const QLine = fabric.util.createClass(fabric.Line, { this.idx = options.idx ?? 0 this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) - this.setLength() + if (length !== 0) { + this.length = length + } else { + this.setLength() + } this.startPoint = { x: this.x1, y: this.y1 } this.endPoint = { x: this.x2, y: this.y2 } diff --git a/src/components/floor-plan/modal/Slope.jsx b/src/components/floor-plan/modal/Slope.jsx index ffe32af6..42b8be64 100644 --- a/src/components/floor-plan/modal/Slope.jsx +++ b/src/components/floor-plan/modal/Slope.jsx @@ -1,6 +1,6 @@ import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' -import { globalPitchState } from '@/store/canvasAtom' +import { globalPitchState, pitchSelector, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilState } from 'recoil' import { useRef } from 'react' import { usePopup } from '@/hooks/usePopup' @@ -8,7 +8,8 @@ import { usePopup } from '@/hooks/usePopup' export default function Slope({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const { closePopup } = usePopup() - const [globalPitch, setGlobalPitch] = useRecoilState(globalPitchState) + const [globalPitch, setGlobalPitch] = useRecoilState(pitchSelector) + const pitchText = useRecoilState(pitchTextSelector) const inputRef = useRef() return ( @@ -29,7 +30,7 @@ export default function Slope({ id, pos = { x: 50, y: 230 } }) {
      - {getMessage('size.angle')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx index ab8553a2..2b5a7079 100644 --- a/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx +++ b/src/components/floor-plan/modal/eavesGable/EavesGableEdit.jsx @@ -11,12 +11,13 @@ export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) { const { getMessage } = useMessage() const { closePopup } = usePopup() - const { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef } = useEavesGableEdit(id) + const { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef, pitchText } = useEavesGableEdit(id) const eavesProps = { pitchRef, offsetRef, widthRef, radioTypeRef, + pitchText, } const gableProps = { @@ -24,6 +25,7 @@ export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) { offsetRef, widthRef, radioTypeRef, + pitchText, } const wallMergeProps = { diff --git a/src/components/floor-plan/modal/eavesGable/type/Eaves.jsx b/src/components/floor-plan/modal/eavesGable/type/Eaves.jsx index 80120107..a7d7d466 100644 --- a/src/components/floor-plan/modal/eavesGable/type/Eaves.jsx +++ b/src/components/floor-plan/modal/eavesGable/type/Eaves.jsx @@ -1,14 +1,17 @@ import { useMessage } from '@/hooks/useMessage' import Image from 'next/image' import { useState } from 'react' +import { useRecoilValue } from 'recoil' +import { ANGLE_TYPE, currentAngleTypeSelector } from '@/store/canvasAtom' -export default function Eaves({ pitchRef, offsetRef, widthRef, radioTypeRef }) { +export default function Eaves({ pitchRef, offsetRef, widthRef, radioTypeRef, pitchText }) { const { getMessage } = useMessage() const [type, setType] = useState('1') const onChange = (e) => { setType(e.target.value) radioTypeRef.current = e.target.value } + const currentAngleType = useRecoilValue(currentAngleTypeSelector) return ( <>
    @@ -17,9 +20,9 @@ export default function Eaves({ pitchRef, offsetRef, widthRef, radioTypeRef }) { {getMessage('slope')}
    - +
    - + {pitchText}
    diff --git a/src/components/floor-plan/modal/eavesGable/type/Gable.jsx b/src/components/floor-plan/modal/eavesGable/type/Gable.jsx index 23f9c300..999687fd 100644 --- a/src/components/floor-plan/modal/eavesGable/type/Gable.jsx +++ b/src/components/floor-plan/modal/eavesGable/type/Gable.jsx @@ -1,14 +1,18 @@ import { useMessage } from '@/hooks/useMessage' import Image from 'next/image' import { useState } from 'react' +import { useRecoilValue } from 'recoil' +import { ANGLE_TYPE, currentAngleTypeSelector } from '@/store/canvasAtom' -export default function Gable({ pitchRef, offsetRef, widthRef, radioTypeRef }) { +export default function Gable({ pitchRef, offsetRef, widthRef, radioTypeRef, pitchText }) { const { getMessage } = useMessage() const [type, setType] = useState('1') const onChange = (e) => { setType(e.target.value) radioTypeRef.current = e.target.value } + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + return ( <>
    @@ -57,9 +61,15 @@ export default function Gable({ pitchRef, offsetRef, widthRef, radioTypeRef }) { {getMessage('slope')}
    - +
    - + {pitchText}
    diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 79a89b88..b635ea86 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -8,6 +8,7 @@ import { useMessage } from '@/hooks/useMessage' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' import { usePopup } from '@/hooks/usePopup' +import { basicSettingState } from '@/store/settingAtom' export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) { const [objectNo, setObjectNo] = useState('test123241008001') // 후에 삭제 필요 @@ -16,22 +17,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(1) const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) const { closePopup } = usePopup() - const [basicSetting, setBasicSettings] = useState({ - roofSizeSet: 1, - roofAngleSet: 'slope', - roofs: [ - { - roofApply: true, - roofSeq: 1, - roofType: 1, - roofWidth: 200, - roofHeight: 200, - roofHajebichi: 200, - roofGap: 0, - roofLayout: 'parallel', - }, - ], - }) + const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) const { getMessage } = useMessage() const { get, post } = useAxios() diff --git a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx index b9ddd97d..090eec0a 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapePassivitySetting.jsx @@ -7,18 +7,21 @@ import { useRoofShapePassivitySetting } from '@/hooks/roofcover/useRoofShapePass import { usePopup } from '@/hooks/usePopup' export default function RoofShapePassivitySetting({ id, pos = { x: 50, y: 230 } }) { - const { handleSave, handleConfirm, handleRollback, buttons, type, setType, TYPES, offsetRef, pitchRef } = useRoofShapePassivitySetting(id) + const { handleSave, handleConfirm, handleRollback, buttons, type, setType, TYPES, offsetRef, pitchRef, pitchText } = + useRoofShapePassivitySetting(id) const { getMessage } = useMessage() const { closePopup } = usePopup() const eavesProps = { offsetRef, pitchRef, + pitchText, } const gableProps = { offsetRef, pitchRef, + pitchText, } const shedProps = { diff --git a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx index 48058b1b..e60aadc6 100644 --- a/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx +++ b/src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx @@ -38,11 +38,12 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) { buttonMenu, handleConfirm, handleRollBack, + pitchText, } = useRoofShapeSetting(id) const { closePopup } = usePopup() - const ridgeProps = { pitch, setPitch, eavesOffset, setEavesOffset } - const patternProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset } + const ridgeProps = { pitch, setPitch, eavesOffset, setEavesOffset, pitchText } + const patternProps = { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, pitchText } const sideProps = { pitch, setPitch, @@ -67,6 +68,7 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) { buttonMenu, handleConfirm, handleRollBack, + pitchText, } const directionProps = { @@ -78,6 +80,7 @@ export default function RoofShapeSetting({ id, pos = { x: 50, y: 230 } }) { setGableOffset, shedWidth, setShedWidth, + pitchText, } return ( diff --git a/src/components/floor-plan/modal/roofShape/passivity/Eaves.jsx b/src/components/floor-plan/modal/roofShape/passivity/Eaves.jsx index 3a16b5c0..2ba0f3e3 100644 --- a/src/components/floor-plan/modal/roofShape/passivity/Eaves.jsx +++ b/src/components/floor-plan/modal/roofShape/passivity/Eaves.jsx @@ -1,7 +1,10 @@ import { useMessage } from '@/hooks/useMessage' +import { useRecoilValue } from 'recoil' +import { ANGLE_TYPE, currentAngleTypeSelector } from '@/store/canvasAtom' -export default function Eaves({ offsetRef, pitchRef }) { +export default function Eaves({ offsetRef, pitchRef, pitchText }) { const { getMessage } = useMessage() + const currentAngleType = useRecoilValue(currentAngleTypeSelector) return ( <>
    @@ -9,9 +12,9 @@ export default function Eaves({ offsetRef, pitchRef }) { {getMessage('slope')}
    - +
    - + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/passivity/Gable.jsx b/src/components/floor-plan/modal/roofShape/passivity/Gable.jsx index 69b2cf9d..e7d9718d 100644 --- a/src/components/floor-plan/modal/roofShape/passivity/Gable.jsx +++ b/src/components/floor-plan/modal/roofShape/passivity/Gable.jsx @@ -1,7 +1,10 @@ import { useMessage } from '@/hooks/useMessage' +import { useRecoilValue } from 'recoil' +import { ANGLE_TYPE, currentAngleTypeSelector } from '@/store/canvasAtom' -export default function Gable({ offsetRef, pitchRef }) { +export default function Gable({ offsetRef, pitchRef, pitchText }) { const { getMessage } = useMessage() + const currentAngleType = useRecoilValue(currentAngleTypeSelector) return ( <>
    @@ -9,9 +12,9 @@ export default function Gable({ offsetRef, pitchRef }) { {getMessage('slope')}
    - +
    - + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/Direction.jsx b/src/components/floor-plan/modal/roofShape/type/Direction.jsx index 51faffcb..ef2be366 100644 --- a/src/components/floor-plan/modal/roofShape/type/Direction.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Direction.jsx @@ -1,7 +1,7 @@ import { useMessage } from '@/hooks/useMessage' import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Direction({ pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, shedWidth, setShedWidth }) { +export default function Direction({ pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, shedWidth, setShedWidth, pitchText }) { const { getMessage } = useMessage() return (
    @@ -12,7 +12,7 @@ export default function Direction({ pitch, setPitch, eavesOffset, setEavesOffset
    onlyNumberWithDotInputChange(e, setPitch)} />
    - {getMessage('size')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/Pattern.jsx b/src/components/floor-plan/modal/roofShape/type/Pattern.jsx index 0c086fbe..704b3a52 100644 --- a/src/components/floor-plan/modal/roofShape/type/Pattern.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Pattern.jsx @@ -3,7 +3,7 @@ import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/inpu export default function Pattern(props) { const { getMessage } = useMessage() - const { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset } = props + const { pitch, setPitch, eavesOffset, setEavesOffset, gableOffset, setGableOffset, pitchText } = props return (
    @@ -13,7 +13,7 @@ export default function Pattern(props) {
    onlyNumberWithDotInputChange(e, setPitch)} />
    - {getMessage('size')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/Ridge.jsx b/src/components/floor-plan/modal/roofShape/type/Ridge.jsx index 13dab6f3..538cda3d 100644 --- a/src/components/floor-plan/modal/roofShape/type/Ridge.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Ridge.jsx @@ -4,7 +4,7 @@ import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/inpu export default function Ridge(props) { const { getMessage } = useMessage() - const { pitch, setPitch, eavesOffset, setEavesOffset } = props + const { pitch, setPitch, eavesOffset, setEavesOffset, pitchText } = props return (
    @@ -15,7 +15,7 @@ export default function Ridge(props) {
    onlyNumberWithDotInputChange(e, setPitch)} />
    - {getMessage('size')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/Side.jsx b/src/components/floor-plan/modal/roofShape/type/Side.jsx index b2f032ba..487ccd43 100644 --- a/src/components/floor-plan/modal/roofShape/type/Side.jsx +++ b/src/components/floor-plan/modal/roofShape/type/Side.jsx @@ -32,13 +32,14 @@ export default function Side(props) { buttonMenu, handleConfirm, handleRollBack, + pitchText, } = props - const eavesProps = { pitch, setPitch, eavesOffset, setEavesOffset } + const eavesProps = { pitch, setPitch, eavesOffset, setEavesOffset, pitchText } const gableProps = { gableOffset, setGableOffset } const wallProps = { sleeveOffset, setSleeveOffset, hasSleeve, setHasSleeve } - const hipAndGableProps = { pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth } - const jerkinheadProps = { gableOffset, setGableOffset, jerkinHeadWidth, setJerkinHeadWidth, jerkinHeadPitch, setJerkinHeadPitch } + const hipAndGableProps = { pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth, pitchText } + const jerkinheadProps = { gableOffset, setGableOffset, jerkinHeadWidth, setJerkinHeadWidth, jerkinHeadPitch, setJerkinHeadPitch, pitchText } const shedProps = { shedWidth, setShedWidth } const { getMessage } = useMessage() diff --git a/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx b/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx index 8d061a7b..cd39a439 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Eaves.jsx @@ -1,7 +1,7 @@ import { useMessage } from '@/hooks/useMessage' import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Eaves({ pitch, setPitch, eavesOffset, setEavesOffset }) { +export default function Eaves({ pitch, setPitch, eavesOffset, setEavesOffset, pitchText }) { const { getMessage } = useMessage() return ( <> @@ -12,7 +12,7 @@ export default function Eaves({ pitch, setPitch, eavesOffset, setEavesOffset })
    onlyNumberWithDotInputChange(e, setPitch)} />
    - {getMessage('size')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx b/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx index ce4a57cc..a59e94b1 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/HipAndGable.jsx @@ -1,7 +1,7 @@ import { useMessage } from '@/hooks/useMessage' import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function HipAndGable({ pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth }) { +export default function HipAndGable({ pitch, setPitch, eavesOffset, setEavesOffset, hipAndGableWidth, setHipAndGableWidth, pitchText }) { const { getMessage } = useMessage() return ( <> @@ -12,7 +12,7 @@ export default function HipAndGable({ pitch, setPitch, eavesOffset, setEavesOffs
    onlyNumberWithDotInputChange(e, setPitch)} />
    - {getMessage('size')} + {pitchText}
    diff --git a/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx b/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx index be846e94..e1b822e7 100644 --- a/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx +++ b/src/components/floor-plan/modal/roofShape/type/option/Jerkinhead.jsx @@ -1,7 +1,15 @@ import { useMessage } from '@/hooks/useMessage' import { onlyNumberInputChange, onlyNumberWithDotInputChange } from '@/util/input-utils' -export default function Jerkinhead({ gableOffset, setGableOffset, jerkinHeadWidth, setJerkinHeadWidth, jerkinHeadPitch, setJerkinHeadPitch }) { +export default function Jerkinhead({ + gableOffset, + setGableOffset, + jerkinHeadWidth, + setJerkinHeadWidth, + jerkinHeadPitch, + setJerkinHeadPitch, + pitchText, +}) { const { getMessage } = useMessage() return ( <> @@ -35,7 +43,7 @@ export default function Jerkinhead({ gableOffset, setGableOffset, jerkinHeadWidt onChange={(e) => onlyNumberWithDotInputChange(e, setJerkinHeadPitch)} />
    - {getMessage('size')} + {pitchText}
    ) diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index c2775376..2b31bbda 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -1,8 +1,8 @@ import { useEffect } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { roofDisplaySelector, settingModalFirstOptionsState } from '@/store/settingAtom' -import { canvasState, dotLineGridSettingState } from '@/store/canvasAtom' -import { setSurfaceShapePattern } from '@/util/canvas-util' +import { basicSettingState, roofDisplaySelector, settingModalFirstOptionsState } from '@/store/settingAtom' +import { canvasState, dotLineGridSettingState, pitchText, pitchTextSelector } from '@/store/canvasAtom' +import { getChonByDegree, getDegreeByChon, setSurfaceShapePattern } from '@/util/canvas-util' import { useFont } from '@/hooks/common/useFont' import { useGrid } from '@/hooks/common/useGrid' import { globalFontAtom } from '@/store/fontAtom' @@ -11,9 +11,11 @@ import { useRoof } from '@/hooks/common/useRoof' export function useCanvasConfigInitialize() { const canvas = useRecoilValue(canvasState) const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) const roofDisplay = useRecoilValue(roofDisplaySelector) const setGlobalFonts = useSetRecoilState(globalFontAtom) const setDotLineGridSetting = useSetRecoilState(dotLineGridSettingState) + const pitchText = useRecoilValue(pitchTextSelector) const {} = useFont() const {} = useGrid() const {} = useRoof() @@ -29,6 +31,24 @@ export function useCanvasConfigInitialize() { canvas.renderAll() }, [roofDisplay]) + useEffect(() => { + if (!canvas) return + const texts = canvas.getObjects().filter((obj) => obj.name === 'pitchText' || obj.name === 'flowText') + if (basicSetting.roofAngleSet === 'slope') { + texts.forEach((obj) => { + obj.set({ text: `${obj.originText}-∠${obj.pitch}${pitchText}` }) + }) + } + + if (basicSetting.roofAngleSet === 'flat') { + texts.forEach((obj) => { + obj.set({ text: `${obj.originText}-∠${getDegreeByChon(obj.pitch)}${pitchText}` }) + }) + } + + canvas.renderAll() + }, [basicSetting]) + const canvasLoadInit = () => { roofInit() //화면표시 초기화 } diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index e062a77a..92c9b324 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react' import { useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' import { LINE_TYPE } from '@/common/common' @@ -28,6 +28,8 @@ export function useEavesGableEdit(id) { const { swalFire } = useSwal() const { drawRoofPolygon } = useMode() + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) const pitchRef = useRef(null) const offsetRef = useRef(null) @@ -217,5 +219,5 @@ export function useEavesGableEdit(id) { canvas?.renderAll() } - return { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef } + return { type, setType, buttonMenu, TYPES, pitchRef, offsetRef, widthRef, radioTypeRef, pitchText } } diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index 0f51c900..e8d8dbd9 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -1,4 +1,4 @@ -import { canvasState, currentObjectState } from '@/store/canvasAtom' +import { canvasState, currentAngleTypeSelector, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { useEffect, useRef, useState } from 'react' import { useLine } from '@/hooks/useLine' @@ -19,6 +19,8 @@ export function useRoofShapePassivitySetting(id) { SHED: 'shed', } const canvas = useRecoilValue(canvasState) + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) const { getMessage } = useMessage() const { showLine, hideLine, addPitchTextsByOuterLines } = useLine() const { swalFire } = useSwal() @@ -34,6 +36,7 @@ export function useRoofShapePassivitySetting(id) { const isFix = useRef(false) const initLines = useRef([]) const [isLoading, setIsLoading] = useState(false) + const { closePopup } = usePopup() const buttons = [ { id: 1, name: getMessage('eaves'), type: TYPES.EAVES }, @@ -216,5 +219,5 @@ export function useRoofShapePassivitySetting(id) { canvas.renderAll() } - return { handleSave, handleConfirm, buttons, type, setType, TYPES, offsetRef, pitchRef, handleRollback } + return { handleSave, handleConfirm, buttons, type, setType, TYPES, offsetRef, pitchRef, handleRollback, pitchText } } diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 13dfef8b..4899888e 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -1,7 +1,7 @@ import { useEffect, useRef, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useRecoilValue, useSetRecoilState } from 'recoil' -import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom' +import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' import { LINE_TYPE } from '@/common/common' import { usePolygon } from '@/hooks/usePolygon' import { useMode } from '@/hooks/useMode' @@ -17,13 +17,16 @@ export function useRoofShapeSetting(id) { const { swalFire } = useSwal() const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) const { addPolygonByLines } = usePolygon() - const [pitch, setPitch] = useState(4) + + const [pitch, setPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8) // 경사 const [eavesOffset, setEavesOffset] = useState(500) // 처마출폭 const [gableOffset, setGableOffset] = useState(300) // 케라바출폭 const [sleeveOffset, setSleeveOffset] = useState(300) // 소매출폭 const [jerkinHeadWidth, setJerkinHeadWidth] = useState(800) // 반절처 폭 - const [jerkinHeadPitch, setJerkinHeadPitch] = useState(4.5) // 반절처 경사 + const [jerkinHeadPitch, setJerkinHeadPitch] = useState(currentAngleType === ANGLE_TYPE.SLOPE ? 4.5 : 20) // 반절처 경사 const [hipAndGableWidth, setHipAndGableWidth] = useState(800) // 팔작지붕 폭 const [shedWidth, setShedWidth] = useState(300) // 한쪽흐름 폭 const [hasSleeve, setHasSleeve] = useState('0') @@ -68,8 +71,8 @@ export function useRoofShapeSetting(id) { strokeWidth, }) - addPitchText(line) - line.setViewLengthText(false) + /*addPitchText(line) + line.setViewLengthText(false)*/ } }) canvas.renderAll() @@ -114,12 +117,10 @@ export function useRoofShapeSetting(id) { canvas?.renderAll() } - setPitch(4) setEavesOffset(500) setGableOffset(300) setSleeveOffset(300) setJerkinHeadWidth(800) - setJerkinHeadPitch(4.5) setHipAndGableWidth(800) setShedWidth(300) }, [shapeNum]) @@ -629,5 +630,6 @@ export function useRoofShapeSetting(id) { setButtonAct, handleConfirm, handleRollBack, + pitchText, } } diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index 210c1ac6..5cffa26f 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -97,9 +97,11 @@ export const useLine = () => { left, top, fontSize: 20, + originText: `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}`, fill: 'black', name: 'pitchText', parentId: line.id, + pitch: attributes.pitch, }, ) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 71ec1549..03b864db 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -406,9 +406,11 @@ export const usePolygon = () => { fill: flowFontOptions.fontColor.value, fontFamily: flowFontOptions.fontFamily.value, fontWeight: flowFontOptions.fontWeight.value, + pitch: arrow.pitch, originX: 'center', originY: 'center', name: 'flowText', + originText: `${txt}${index + 1}`, selectable: false, left: arrow.stickeyPoint.x, top: arrow.stickeyPoint.y, diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 0f2428ee..2eade854 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -1,6 +1,8 @@ import { atom, selector } from 'recoil' import { MENU } from '@/common/common' import { outerLineFixState, outerLinePointsState } from '@/store/outerLineAtom' +import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' +import { basicSettingState } from '@/store/settingAtom' export const canvasState = atom({ key: 'canvasState', @@ -305,3 +307,49 @@ export const globalPitchState = atom({ key: 'globalPitch', default: 4, }) + +export const pitchSelector = selector({ + key: 'pitchSelector', + get: ({ get }) => { + const globalPitch = get(globalPitchState) + const basicSettingStateValue = get(basicSettingState) + const roofAngleSet = basicSettingStateValue.roofAngleSet + if (roofAngleSet === 'slope') { + return globalPitch + } else { + return getDegreeByChon(globalPitch) + } + }, + set: ({ get, set }, newValue) => { + const basicSettingStateValue = get(basicSettingState) + const roofAngleSet = basicSettingStateValue.roofAngleSet + console.log(newValue) + if (roofAngleSet === 'slope') { + set(globalPitchState, newValue) + } else { + set(globalPitchState, getChonByDegree(newValue)) + } + }, +}) + +export const ANGLE_TYPE = { + SLOPE: 'slope', + FLAT: 'flat', +} + +export const currentAngleTypeSelector = selector({ + key: 'currentAngleTypeSelector', + get: ({ get }) => { + const basicSettingStateValue = get(basicSettingState) + return basicSettingStateValue.roofAngleSet + }, +}) + +export const pitchTextSelector = selector({ + key: 'pitchTextSelector', + get: ({ get }) => { + const basicSettingStateValue = get(basicSettingState) + const roofAngleSet = basicSettingStateValue.roofAngleSet + return roofAngleSet === 'slope' ? '寸' : '度' + }, +}) diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index c6e94029..2432d884 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -157,3 +157,23 @@ export const roofDisplaySelector = selector({ }, dangerouslyAllowMutability: true, }) + +export const basicSettingState = atom({ + key: 'basicSettingState', + default: { + roofSizeSet: 1, + roofAngleSet: 'slope', + roofs: [ + { + roofApply: true, + roofSeq: 1, + roofType: 1, + roofWidth: 200, + roofHeight: 200, + roofHajebichi: 200, + roofGap: 0, + roofLayout: 'parallel', + }, + ], + }, +}) diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 8ed918ca..9f8b9469 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -262,6 +262,15 @@ export const getDegreeByChon = (chon) => { return Number((radians * (180 / Math.PI)).toFixed(2)) } +/** + * + */ +export const getChonByDegree = (degree) => { + // tan(theta) = height / base + const radians = (degree * Math.PI) / 180 + return Number(Number(Math.tan(radians) * 10).toFixed(1)) +} + /** * 두 점 사이의 방향을 반환합니다. * @param a {fabric.Object} From 7d14f8da5abd740d95a6da10af120ace653bf891 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 28 Oct 2024 11:34:25 +0900 Subject: [PATCH 117/139] =?UTF-8?q?pitch=20=EC=84=B8=ED=8C=85=20default=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useEavesGableEdit.js | 9 +-- .../roofcover/useRoofShapePassivitySetting.js | 7 ++- src/hooks/roofcover/useRoofShapeSetting.js | 57 +++++++++++-------- src/hooks/useLine.js | 36 +++++++----- src/hooks/usePolygon.js | 10 +++- 5 files changed, 72 insertions(+), 47 deletions(-) diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index 92c9b324..b0085019 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -1,6 +1,6 @@ import { useEffect, useRef, useState } from 'react' import { useRecoilValue } from 'recoil' -import { canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' +import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' import { useMessage } from '@/hooks/useMessage' import { useEvent } from '@/hooks/useEvent' import { LINE_TYPE } from '@/common/common' @@ -9,6 +9,7 @@ import { useMode } from '@/hooks/useMode' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' import { usePopup } from '@/hooks/usePopup' +import { getChonByDegree } from '@/util/canvas-util' // 처마.케라바 변경 export function useEavesGableEdit(id) { @@ -107,13 +108,13 @@ export function useEavesGableEdit(id) { if (radioTypeRef.current === '1') { attributes = { type: LINE_TYPE.WALLLINE.EAVES, - pitch: pitchRef.current.value, + pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitchRef.current.value : getChonByDegree(pitchRef.current.value), offset: offsetRef.current.value / 10, } } else { attributes = { type: LINE_TYPE.WALLLINE.HIPANDGABLE, - pitch: pitchRef.current.value, + pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitchRef.current.value : getChonByDegree(pitchRef.current.value), offset: offsetRef.current.value / 10, width: widthRef.current.value / 10, } @@ -128,7 +129,7 @@ export function useEavesGableEdit(id) { } else { attributes = { type: LINE_TYPE.WALLLINE.JERKINHEAD, - pitch: pitchRef.current.value, + pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitchRef.current.value : getChonByDegree(pitchRef.current.value), offset: offsetRef.current.value / 10, width: widthRef.current.value / 10, } diff --git a/src/hooks/roofcover/useRoofShapePassivitySetting.js b/src/hooks/roofcover/useRoofShapePassivitySetting.js index e8d8dbd9..ef7a4477 100644 --- a/src/hooks/roofcover/useRoofShapePassivitySetting.js +++ b/src/hooks/roofcover/useRoofShapePassivitySetting.js @@ -1,4 +1,4 @@ -import { canvasState, currentAngleTypeSelector, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' +import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, currentObjectState, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { useEffect, useRef, useState } from 'react' import { useLine } from '@/hooks/useLine' @@ -10,6 +10,7 @@ import { usePolygon } from '@/hooks/usePolygon' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' import { usePopup } from '@/hooks/usePopup' +import { getChonByDegree } from '@/util/canvas-util' //지붕형상 수동 설정 export function useRoofShapePassivitySetting(id) { @@ -137,12 +138,12 @@ export function useRoofShapePassivitySetting(id) { attributes = { type: LINE_TYPE.WALLLINE.EAVES, offset, - pitch: pitchRef.current.value, + pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitchRef.current.value : getChonByDegree(pitchRef.current.value), } } else if (type === TYPES.GABLE) { attributes = { type: LINE_TYPE.WALLLINE.GABLE, - pitch: pitchRef.current.value, + pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitchRef.current.value : getChonByDegree(pitchRef.current.value), offset, } } else if (type === TYPES.SHED) { diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 4899888e..9aab5da7 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -9,6 +9,7 @@ import { useLine } from '@/hooks/useLine' import { outerLineFixState } from '@/store/outerLineAtom' import { useSwal } from '@/hooks/useSwal' import { usePopup } from '@/hooks/usePopup' +import { getChonByDegree } from '@/util/canvas-util' // 지붕형상 설정 export function useRoofShapeSetting(id) { @@ -37,9 +38,19 @@ export function useRoofShapeSetting(id) { const setCurrentMenu = useSetRecoilState(currentMenuState) const outerLineFix = useRecoilValue(outerLineFixState) + const pitchRef = useRef(null) + const jerkinHeadPitchRef = useRef(null) + const history = useRef([]) const { closePopup } = usePopup() + useEffect(() => { + pitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch) + }, [pitch]) + useEffect(() => { + jerkinHeadPitchRef.current = currentAngleType === ANGLE_TYPE.SLOPE ? jerkinHeadPitch : getChonByDegree(jerkinHeadPitch) + }, [jerkinHeadPitch]) + useEffect(() => { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') if (!outerLineFix || outerLines.length === 0) { @@ -71,8 +82,8 @@ export function useRoofShapeSetting(id) { strokeWidth, }) - /*addPitchText(line) - line.setViewLengthText(false)*/ + addPitchText(line) + line.setViewLengthText(false) } }) canvas.renderAll() @@ -182,7 +193,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'bottom') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -198,7 +209,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'top') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -206,7 +217,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'bottom') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -227,7 +238,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'top') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -235,7 +246,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'bottom') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -243,7 +254,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'bottom') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -251,7 +262,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'top') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -271,7 +282,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'right') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -279,7 +290,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'left') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -287,7 +298,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'left') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -295,7 +306,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'right') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -316,7 +327,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'left') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -324,7 +335,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'right') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -332,7 +343,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'right') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -340,7 +351,7 @@ export function useRoofShapeSetting(id) { if (line.direction === 'left') { line.attributes = { offset: shedWidth / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.SHED, } } @@ -437,7 +448,7 @@ export function useRoofShapeSetting(id) { outerLines.forEach((line) => { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } // hideLine(line) @@ -459,7 +470,7 @@ export function useRoofShapeSetting(id) { } else if (line.direction === 'top' || line.direction === 'bottom') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -482,7 +493,7 @@ export function useRoofShapeSetting(id) { } else if (line.direction === 'left' || line.direction === 'right') { line.attributes = { offset: eavesOffset / 10, - pitch: pitch, + pitch: pitchRef.current, type: LINE_TYPE.WALLLINE.EAVES, } } @@ -505,7 +516,7 @@ export function useRoofShapeSetting(id) { // 처마 attributes = { type: LINE_TYPE.WALLLINE.EAVES, - pitch: pitch, + pitch: pitchRef.current, offset: eavesOffset / 10, } addPitchText(currentObject) @@ -536,7 +547,7 @@ export function useRoofShapeSetting(id) { // 팔작지붕 attributes = { type: LINE_TYPE.WALLLINE.HIPANDGABLE, - pitch: pitch, + pitch: pitchRef.current, offset: eavesOffset / 10, width: hipAndGableWidth / 10, } @@ -551,7 +562,7 @@ export function useRoofShapeSetting(id) { type: LINE_TYPE.WALLLINE.JERKINHEAD, offset: gableOffset / 10, width: jerkinHeadWidth / 10, - pitch: jerkinHeadPitch, + pitch: jerkinHeadPitchRef.current, } addPitchText(currentObject) selectedLine.set({ strokeWidth: 4 }) diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index 5cffa26f..62ec937a 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -1,11 +1,13 @@ import { useRecoilValue } from 'recoil' -import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' +import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' export const useLine = () => { const canvas = useRecoilValue(canvasState) const fontSize = useRecoilValue(fontSizeState) const fontFamily = useRecoilValue(fontFamilyState) + const currentAngleType = useRecoilValue(currentAngleTypeSelector) const addLine = (points = [], options) => { const line = new QLine(points, { @@ -77,6 +79,11 @@ export const useLine = () => { let left, top + const textStr = + currentAngleType === ANGLE_TYPE.SLOPE + ? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + attributes.pitch : ''}` + : `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + getDegreeByChon(attributes.pitch) : ''}` + if (direction === 'top') { left = (startPoint.x + endPoint.x) / 2 top = (startPoint.y + endPoint.y) / 2 - 50 @@ -91,19 +98,20 @@ export const useLine = () => { top = (startPoint.y + endPoint.y) / 2 - 30 } - const text = new fabric.Text( - `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + attributes.pitch : ''}`, - { - left, - top, - fontSize: 20, - originText: `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}`, - fill: 'black', - name: 'pitchText', - parentId: line.id, - pitch: attributes.pitch, - }, - ) + if (!attributes.pitch) { + return + } + + const text = new fabric.Text(`${textStr}`, { + left, + top, + fontSize: 20, + originText: `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}`, + fill: 'black', + name: 'pitchText', + parentId: line.id, + pitch: attributes.pitch, + }) canvas.add(text) } diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 03b864db..c147e2fe 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1,7 +1,7 @@ -import { canvasState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { fabric } from 'fabric' -import { getDirectionByPoint } from '@/util/canvas-util' +import { getDegreeByChon, getDirectionByPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' @@ -12,6 +12,8 @@ export const usePolygon = () => { const isFlowDisplay = useRecoilValue(flowDisplaySelector) const flowFontOptions = useRecoilValue(fontSelector('flowText')) const lengthTextFontOptions = useRecoilValue(fontSelector('lengthText')) + const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) const addPolygon = (points, options) => { const polygon = new QPolygon(points, { @@ -401,7 +403,9 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { - const text = new fabric.Text(`${txt}${index + 1} (${arrow.pitch}寸)`, { + const textStr = `${txt}${index + 1} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})` + + const text = new fabric.Text(`${textStr}`, { fontSize: flowFontOptions.fontSize.value, fill: flowFontOptions.fontColor.value, fontFamily: flowFontOptions.fontFamily.value, From 6a979fefc934c1f32ec5595d0fbd775292a295be Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 28 Oct 2024 13:35:23 +0900 Subject: [PATCH 118/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_contents.scss | 2 +- src/styles/_reset.scss | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss index e3d8d1ee..e4f6a6b2 100644 --- a/src/styles/_contents.scss +++ b/src/styles/_contents.scss @@ -329,7 +329,7 @@ border-top: 1px solid #000; width: 100%; transition: all .17s ease-in-out; - z-index: 999; + z-index: 99; &.active{ top: calc(92.8px + 50px); } diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index 525c0488..4225db2e 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -130,6 +130,10 @@ button{ font-family: 'Pretendard', sans-serif !important; } +.no-click{ + cursor: no-drop !important; +} + // margin .mt5{margin-top: 5px !important;} .mt10{margin-top: 10px !important;} From 88a1194e1c721d3320e3e7daa3f943d64de5a4e0 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 28 Oct 2024 13:48:21 +0900 Subject: [PATCH 119/139] =?UTF-8?q?offset=EC=9A=A9=20=EB=8B=A8=EC=9C=84,?= =?UTF-8?q?=20flow=EC=9A=A9=20=EB=8B=A8=EC=9C=84=20=EB=8B=A4=EB=A6=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useCanvasConfigInitialize.js | 16 ++++++++++++---- src/hooks/roofcover/useRoofShapeSetting.js | 8 +++++++- src/hooks/useLine.js | 16 +++++++++++++--- src/store/canvasAtom.js | 11 +++++++++++ 4 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js index 2b31bbda..f49b4cb9 100644 --- a/src/hooks/common/useCanvasConfigInitialize.js +++ b/src/hooks/common/useCanvasConfigInitialize.js @@ -1,7 +1,7 @@ import { useEffect } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { basicSettingState, roofDisplaySelector, settingModalFirstOptionsState } from '@/store/settingAtom' -import { canvasState, dotLineGridSettingState, pitchText, pitchTextSelector } from '@/store/canvasAtom' +import { canvasState, dotLineGridSettingState, pitchText, pitchTextSelector, showAngleUnitSelector } from '@/store/canvasAtom' import { getChonByDegree, getDegreeByChon, setSurfaceShapePattern } from '@/util/canvas-util' import { useFont } from '@/hooks/common/useFont' import { useGrid } from '@/hooks/common/useGrid' @@ -16,6 +16,7 @@ export function useCanvasConfigInitialize() { const setGlobalFonts = useSetRecoilState(globalFontAtom) const setDotLineGridSetting = useSetRecoilState(dotLineGridSettingState) const pitchText = useRecoilValue(pitchTextSelector) + const angleUnit = useRecoilValue(showAngleUnitSelector) const {} = useFont() const {} = useGrid() const {} = useRoof() @@ -33,15 +34,22 @@ export function useCanvasConfigInitialize() { useEffect(() => { if (!canvas) return - const texts = canvas.getObjects().filter((obj) => obj.name === 'pitchText' || obj.name === 'flowText') + const offsetTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText') + const flowTexts = canvas.getObjects().filter((obj) => obj.name === 'flowText') if (basicSetting.roofAngleSet === 'slope') { - texts.forEach((obj) => { + offsetTexts.forEach((obj) => { + obj.set({ text: `${obj.originText}-∠${obj.pitch}${angleUnit}` }) + }) + flowTexts.forEach((obj) => { obj.set({ text: `${obj.originText}-∠${obj.pitch}${pitchText}` }) }) } if (basicSetting.roofAngleSet === 'flat') { - texts.forEach((obj) => { + offsetTexts.forEach((obj) => { + obj.set({ text: `${obj.originText}-∠${getDegreeByChon(obj.pitch)}${angleUnit}` }) + }) + flowTexts.forEach((obj) => { obj.set({ text: `${obj.originText}-∠${getDegreeByChon(obj.pitch)}${pitchText}` }) }) } diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 9aab5da7..e0d850f4 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -38,6 +38,8 @@ export function useRoofShapeSetting(id) { const setCurrentMenu = useSetRecoilState(currentMenuState) const outerLineFix = useRecoilValue(outerLineFixState) + const isFixRef = useRef(false) + const pitchRef = useRef(null) const jerkinHeadPitchRef = useRef(null) @@ -60,6 +62,10 @@ export function useRoofShapeSetting(id) { } return () => { + if (!isFixRef.current) { + return + } + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const pitchTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText') canvas.remove(...pitchTexts) @@ -83,7 +89,6 @@ export function useRoofShapeSetting(id) { }) addPitchText(line) - line.setViewLengthText(false) } }) canvas.renderAll() @@ -388,6 +393,7 @@ export function useRoofShapeSetting(id) { canvas?.renderAll() roof.drawHelpLine() // setShowRoofShapeSettingModal(false) + isFixRef.current = true closePopup(id) } diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index 62ec937a..7bf01a47 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -1,5 +1,13 @@ import { useRecoilValue } from 'recoil' -import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { + ANGLE_TYPE, + canvasState, + currentAngleTypeSelector, + fontFamilyState, + fontSizeState, + pitchTextSelector, + showAngleUnitSelector, +} from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' @@ -8,6 +16,8 @@ export const useLine = () => { const fontSize = useRecoilValue(fontSizeState) const fontFamily = useRecoilValue(fontFamilyState) const currentAngleType = useRecoilValue(currentAngleTypeSelector) + const pitchText = useRecoilValue(pitchTextSelector) + const angleUnit = useRecoilValue(showAngleUnitSelector) const addLine = (points = [], options) => { const line = new QLine(points, { @@ -81,8 +91,8 @@ export const useLine = () => { const textStr = currentAngleType === ANGLE_TYPE.SLOPE - ? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + attributes.pitch : ''}` - : `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + getDegreeByChon(attributes.pitch) : ''}` + ? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + attributes.pitch + angleUnit : ''}` + : `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${attributes.pitch ? '-∠' + getDegreeByChon(attributes.pitch) + angleUnit : ''}` if (direction === 'top') { left = (startPoint.x + endPoint.x) / 2 diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 2eade854..bdce5876 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -353,3 +353,14 @@ export const pitchTextSelector = selector({ return roofAngleSet === 'slope' ? '寸' : '度' }, }) + +//각도 표시, offset 길이에서는 각도가 한자가 아닌 도형으로 표시되어야 한다. +export const showAngleUnitSelector = selector({ + key: 'showAngleUnitSelector', + get: ({ get }) => { + const basicSettingStateValue = get(basicSettingState) + const roofAngleSet = basicSettingStateValue.roofAngleSet + + return roofAngleSet === 'slope' ? '寸' : '°' + }, +}) From 74b6792d96bb0ab867363c370f1965a2ab3aeb01 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 28 Oct 2024 13:58:37 +0900 Subject: [PATCH 120/139] =?UTF-8?q?=EC=A0=80=EC=9E=A5=EC=8B=9C=20propertie?= =?UTF-8?q?s=20=EC=B6=94=EA=B0=80=20db=20=3D>=20canvas=20=EC=8B=9C=20repla?= =?UTF-8?q?ce=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/usePlan.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 8ed84af4..4c655e86 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -65,6 +65,7 @@ export function usePlan() { 'text', 'pitch', 'uuid', + 'originText', ]) const str = JSON.stringify(objs) @@ -144,7 +145,7 @@ export function usePlan() { * DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화 */ const dbToCanvasFormat = (cs) => { - return cs.replace(/##/g, '"').replace(/∠/g, '∠') + return cs.replace(/##/g, '"').replace(/∠/g, '∠').replace(/°/g, '°') } /** From e7ab754b59a3092d1009026ed985946425c74b55 Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 28 Oct 2024 14:52:19 +0900 Subject: [PATCH 121/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EC=A0=95=EB=B3=B4?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EA=B2=AC=EC=A0=81?= =?UTF-8?q?=EC=84=9C=20=ED=99=94=EB=A9=B4=EC=9D=B4=EB=8F=99=EC=8B=9C=20?= =?UTF-8?q?=EB=AC=BC=EA=B1=B4=EB=B2=88=ED=98=B8=20=EA=B4=80=EB=A0=A8=20ato?= =?UTF-8?q?m=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/StuffDetail.jsx | 10 ++++++++-- src/components/management/StuffSubHeader.jsx | 7 ++++--- src/store/floorPlanObjectAtom.js | 9 +++++++++ 3 files changed, 21 insertions(+), 5 deletions(-) create mode 100644 src/store/floorPlanObjectAtom.js diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 4b15c8a0..e8104548 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -10,15 +10,18 @@ import { globalLocaleStore } from '@/store/localeAtom' import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty } from '@/util/common-utils' import { useMessage } from '@/hooks/useMessage' import { useForm } from 'react-hook-form' -import { useRecoilValue } from 'recoil' +import { useRecoilValue, useSetRecoilState } from 'recoil' import { sessionStore } from '@/store/commonAtom' import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' import WindSelectPop from './popup/WindSelectPop' import { useCommonCode } from '@/hooks/common/useCommonCode' import StuffPlanQGrid from './StuffPlanQGrid' +import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' export default function StuffDetail() { + const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //견적서 화면용 물건번호리코일 + const inputReceiveUserEl = useRef(null) //담당자ref const inputObjectNameEl = useRef(null) //물건명ref const inputZipNoEl = useRef(null) //우편번호ref @@ -1077,6 +1080,7 @@ export default function StuffDetail() { //상세화면으로 전환 if (res.status === 201) { alert(getMessage('stuff.detail.save')) + setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`) } }) @@ -1085,6 +1089,7 @@ export default function StuffDetail() { await promisePut({ url: apiUrl, data: params }).then((res) => { if (res.status === 201) { alert(getMessage('stuff.detail.save')) + setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) router.refresh() } }) @@ -1153,7 +1158,8 @@ export default function StuffDetail() { alert(getMessage('stuff.detail.delete.message1')) } else { if (confirm(getMessage('common.message.data.delete'))) { - del({ url: `/api/object/${objectNo}` }).then((res) => { + del({ url: `/api/object/${objectNo}` }).then(() => { + setFloorPlanObjectNo({ floorPlanObjectNo: '' }) router.push('/management/stuff') }) } diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index 1b10a149..f1103143 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -5,14 +5,15 @@ import Link from 'next/link' import Image from 'next/image' import { useMessage } from '@/hooks/useMessage' import { useRouter, useSearchParams } from 'next/navigation' -import { stuffSearchState } from '@/store/stuffAtom' +import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { useSetRecoilState } from 'recoil' export default function StuffSubHeader({ type }) { const { getMessage } = useMessage() const router = useRouter() - const setSchObjectNo = useSetRecoilState(stuffSearchState) + const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) + useEffect(() => { window.scrollTo(0, 0) }, []) @@ -22,7 +23,7 @@ export default function StuffSubHeader({ type }) { // url에 물건번호로 도면작성화면으로 이동 const moveFloorPlan = () => { - setSchObjectNo(objectNo) + setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) router.push('/floor-plan') } diff --git a/src/store/floorPlanObjectAtom.js b/src/store/floorPlanObjectAtom.js new file mode 100644 index 00000000..50cdccf4 --- /dev/null +++ b/src/store/floorPlanObjectAtom.js @@ -0,0 +1,9 @@ +import { atom } from 'recoil' +import { v1 } from 'uuid' +export const floorPlanObjectState = atom({ + key: `floorPlanObjectState/${v1()}`, + default: { + objectNo: '', //물건번호 + }, + dangerouslyAllowMutability: true, +}) From 7a8b575b8e5b9f52c090e775a11d4b681a12dd37 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 28 Oct 2024 14:56:36 +0900 Subject: [PATCH 122/139] refactor: canvas layout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 예외 메뉴를 위한 레이아웃 분리 --- src/app/floor-plan/[mid]/[pid]/page.jsx | 3 +++ src/app/floor-plan/layout.js | 8 +++++++- src/app/floor-plan/page.jsx | 3 ++- src/components/floor-plan/CanvasFrame.jsx | 14 +++++++------- src/components/floor-plan/CanvasLayout.jsx | 8 +++++--- src/components/floor-plan/FloorPlan.jsx | 10 +++++----- src/hooks/common/useCanvasMenu.js | 10 ++++++++++ src/hooks/usePlan.js | 3 +++ 8 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 src/app/floor-plan/[mid]/[pid]/page.jsx create mode 100644 src/hooks/common/useCanvasMenu.js diff --git a/src/app/floor-plan/[mid]/[pid]/page.jsx b/src/app/floor-plan/[mid]/[pid]/page.jsx new file mode 100644 index 00000000..473897dc --- /dev/null +++ b/src/app/floor-plan/[mid]/[pid]/page.jsx @@ -0,0 +1,3 @@ +export default function EstimatePage() { + return
    이자리....
    +} diff --git a/src/app/floor-plan/layout.js b/src/app/floor-plan/layout.js index 829599af..782bc51e 100644 --- a/src/app/floor-plan/layout.js +++ b/src/app/floor-plan/layout.js @@ -1,11 +1,17 @@ 'use client' +import FloorPlan from '@/components/floor-plan/FloorPlan' import { FloorPlanProvider } from './FloorPlanProvider' +import CanvasLayout from '@/components/floor-plan/CanvasLayout' export default function FloorPlanLayout({ children }) { console.log('FloorPlanLayout') return ( <> - {children} + + + {children} + + ) } diff --git a/src/app/floor-plan/page.jsx b/src/app/floor-plan/page.jsx index f503099e..b38a7ef0 100644 --- a/src/app/floor-plan/page.jsx +++ b/src/app/floor-plan/page.jsx @@ -1,9 +1,10 @@ +import CanvasFrame from '@/components/floor-plan/CanvasFrame' import FloorPlan from '@/components/floor-plan/FloorPlan' export default function FloorPlanPage() { return ( <> - + ) } diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index c2a73b63..9dfd3ac8 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -15,7 +15,7 @@ import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitial import { MENU } from '@/common/common' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' -export default function CanvasFrame({ plan }) { +export default function CanvasFrame() { const canvasRef = useRef(null) const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) const { canvas } = useCanvas('canvas') @@ -24,14 +24,14 @@ export default function CanvasFrame({ plan }) { const currentObject = useRecoilValue(currentObjectState) const currentMenu = useRecoilValue(currentMenuState) const { contextMenu, handleClick, handleKeyup } = useContextMenu() - const { checkCanvasObjectEvent, checkUnsavedCanvasPlan, resetModifiedPlans } = usePlan() + const { selectedPlan, checkCanvasObjectEvent, checkUnsavedCanvasPlan, resetModifiedPlans } = usePlan() useEvent() const loadCanvas = () => { if (canvas) { canvas?.clear() // 캔버스를 초기화합니다. - if (plan?.canvasStatus) { - canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () { + if (selectedPlan?.canvasStatus) { + canvas?.loadFromJSON(JSON.parse(selectedPlan.canvasStatus), function () { canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 canvas?.renderAll() // 캔버스를 다시 그립니다. }) @@ -41,15 +41,15 @@ export default function CanvasFrame({ plan }) { } useEffect(() => { - if (modifiedPlanFlag && plan?.id) { - checkCanvasObjectEvent(plan.id) + if (modifiedPlanFlag && selectedPlan?.id) { + checkCanvasObjectEvent(selectedPlan.id) } }, [modifiedPlanFlag]) useEffect(() => { loadCanvas() resetModifiedPlans() - }, [plan, canvas]) + }, [selectedPlan, canvas]) return (
    diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index ac247f6b..ea3292c0 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -9,9 +9,11 @@ import { usePlan } from '@/hooks/usePlan' import { modifiedPlansState } from '@/store/canvasAtom' import { globalLocaleStore } from '@/store/localeAtom' import { SessionContext } from '@/app/SessionProvider' +import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' -export default function CanvasLayout(props) { - const { menuNumber } = props +export default function CanvasLayout({ children }) { + // const { menuNumber } = props + const { menuNumber } = useCanvasMenu() const { session } = useContext(SessionContext) const [objectNo, setObjectNo] = useState('test123240822001') // 이후 삭제 필요 const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan @@ -60,7 +62,7 @@ export default function CanvasLayout(props) { )}
    - plan.isCurrent === true)} /> + {children}
    ) } diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index bc95d9b3..caf9a2d7 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -7,16 +7,18 @@ import { globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import CanvasLayout from '@/components/floor-plan/CanvasLayout' +import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import '@/styles/contents.scss' -export default function FloorPlan() { +export default function FloorPlan({ children }) { const globalLocaleState = useRecoilValue(globalLocaleStore) const { get } = useAxios(globalLocaleState) const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - const [menuNumber, setMenuNumber] = useState(null) + // const [menuNumber, setMenuNumber] = useState(null) + const { menuNumber, setMenuNumber } = useCanvasMenu() const modalProps = { menuNumber, @@ -57,9 +59,7 @@ export default function FloorPlan() { <>
    -
    - -
    +
    {children}
    ) diff --git a/src/hooks/common/useCanvasMenu.js b/src/hooks/common/useCanvasMenu.js new file mode 100644 index 00000000..23f594d9 --- /dev/null +++ b/src/hooks/common/useCanvasMenu.js @@ -0,0 +1,10 @@ +import { useState } from 'react' + +export const useCanvasMenu = () => { + const [menuNumber, setMenuNumber] = useState(null) + + return { + menuNumber, + setMenuNumber, + } +} diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 4c655e86..1cced0f0 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -8,6 +8,7 @@ import { useSwal } from '@/hooks/useSwal' export function usePlan() { const [planNum, setPlanNum] = useState(0) + const [selectedPlan, setSelectedPlan] = useState(null) const [canvas, setCanvas] = useRecoilState(canvasState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) @@ -279,6 +280,7 @@ export function usePlan() { } useEffect(() => { setCurrentCanvasPlan(plans.find((plan) => plan.isCurrent) || null) + setSelectedPlan(plans.find((plan) => plan.isCurrent)) }, [plans]) /** @@ -366,6 +368,7 @@ export function usePlan() { return { canvas, plans, + selectedPlan, modifiedPlans, checkCanvasObjectEvent, resetModifiedPlans, From b71afc04925648d9321209ff8b7ad67eecf3a540 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 28 Oct 2024 14:56:51 +0900 Subject: [PATCH 123/139] =?UTF-8?q?lengthText=20=EC=83=9D=EC=84=B1=20?= =?UTF-8?q?=EC=8B=9C=20=EA=B8=80=EA=BC=B4=20=EC=84=A4=EC=A0=95=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 2 +- src/components/fabric/QPolygon.js | 2 +- src/hooks/useCanvasEvent.js | 15 +++++++++------ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 37c9a75f..4ee9535a 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -152,7 +152,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { getLength() { //10배 곱해진 값 return - return Number(this.length.toFixed(2) * 10) + return Number(this.length.toFixed(1)) * 10 }, setViewLengthText(bool) { diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 31076b69..8068a772 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -183,7 +183,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const end = points[(i + 1) % points.length] const dx = end.x - start.x const dy = end.y - start.y - const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(2)) * 10 + const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10 let midPoint diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 0df650c0..ab283a08 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -11,6 +11,7 @@ import { modifiedPlanFlagState, } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' +import { fontSelector } from '@/store/fontAtom' // 캔버스에 필요한 이벤트 export function useCanvasEvent() { @@ -22,6 +23,7 @@ export function useCanvasEvent() { const fontFamily = useRecoilValue(fontFamilyState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) + const lengthTextOption = useRecoilValue(fontSelector('lengthText')) // 기본적인 이벤트 필요시 추가 const attachDefaultEventOnCanvas = () => { @@ -108,16 +110,17 @@ export function useCanvasEvent() { }) } - if (target.type.toLowerCase().includes('text')) { - target.set({ fontSize }) - target.set({ fontFamily }) - } - - if (target.name === 'lengthText') { + if (target.name === 'lengthText' && target.type.toLowerCase().includes('text') > 0) { const x = target.left const y = target.top target.lockMovementX = false target.lockMovementY = false + + target.fill = lengthTextOption.fontColor.value + target.fontFamily = lengthTextOption.fontFamily.value + target.fontSize = lengthTextOption.fontSize.value + target.fontWeight = lengthTextOption.fontWeight.value + // Add a property to store the previous value const previousValue = target.text target.on('selected', (e) => { From d65f27c036304c6037cd1e8714dbc552e87cd0de Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 28 Oct 2024 15:19:25 +0900 Subject: [PATCH 124/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=ED=99=94=EB=A9=B4=EC=97=90=EC=84=9C=20=EA=B2=AC=EC=A0=81?= =?UTF-8?q?=EC=84=9C=EB=A1=9C=20=EC=9D=B4=EB=8F=99.=20=EA=B2=AC=EC=A0=81?= =?UTF-8?q?=EC=84=9C=20=ED=99=94=EB=A9=B4=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/floor-plan/[mid]/[pid]/page.jsx | 8 +- src/components/estimate/Estimate.jsx | 307 +++++++++++++++++++ src/components/management/StuffDetail.jsx | 7 +- src/components/management/StuffPlanQGrid.jsx | 4 +- src/locales/ja.json | 26 +- src/locales/ko.json | 26 +- 6 files changed, 372 insertions(+), 6 deletions(-) create mode 100644 src/components/estimate/Estimate.jsx diff --git a/src/app/floor-plan/[mid]/[pid]/page.jsx b/src/app/floor-plan/[mid]/[pid]/page.jsx index 473897dc..80eae575 100644 --- a/src/app/floor-plan/[mid]/[pid]/page.jsx +++ b/src/app/floor-plan/[mid]/[pid]/page.jsx @@ -1,3 +1,9 @@ +import Estimate from '@/components/estimate/Estimate' + export default function EstimatePage() { - return
    이자리....
    + return ( + <> + + + ) } diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx new file mode 100644 index 00000000..e1a453fe --- /dev/null +++ b/src/components/estimate/Estimate.jsx @@ -0,0 +1,307 @@ +'use client' +import { useEffect, useState } from 'react' +import { useMessage } from '@/hooks/useMessage' +import SingleDatePicker from '../common/datepicker/SingleDatePicker' +import { useRecoilValue } from 'recoil' +import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' + +export default function Estimate() { + const { getMessage } = useMessage() + const objectRecoil = useRecoilValue(floorPlanObjectState) + console.log('견적서화면이군요', objectRecoil.floorPlanObjectNo) + return ( +
    +
    + {/* 물건번호, 견적서번호, 등록일, 변경일시 시작 */} +
    +
    +
    +
    +
    {getMessage('estimate.detail.objectNo')}
    +
    RX524231020006 (Plan No: 1)
    +
    +
    +
    {getMessage('estimate.detail.estimateNo')}
    +
    5242310200065242
    +
    +
    +
    {getMessage('estimate.detail.createDatetime')}
    +
    9999.09.28
    +
    +
    +
    {getMessage('estimate.detail.lastEditDatetime')}
    +
    9999.09.28 06:36
    +
    +
    +
    +
    + {/* 물건번호, 견적서번호, 등록일, 변경일시 끝 */} + {/* 기본정보 시작 */} +
    +
    +
    +
    +

    {getMessage('estimate.detail.header.title')}

    +
    +
    +
    + + + + + + + + + + {/* 1차 판매점명 */} + + + {/* 견적일 */} + + + + + {/* 2차 판매점명 */} + + + {/* 담당자 */} + + + + + {/* 안건명 */} + + + + + {/* 메모 */} + + + + + {/* 주문분류 */} + + + + + {/* 지붕재・사양시공 최대4개*/} + + + + + {/* 비고 */} + + + + +
    {getMessage('estimate.detail.saleStoreId')} + {getMessage('estimate.detail.estimateDate')} * + +
    + +
    +
    {getMessage('estimate.detail.otherSaleStoreId')} + {getMessage('estimate.detail.receiveUser')} * + +
    + +
    +
    + {getMessage('estimate.detail.title')} * + +
    +
    + +
    +
    + +
    +
    +
    {getMessage('estimate.detail.remarks')}물건정보에서 입력한 메모 표시
    + 注文分類/주문분류 * + +
    +
    屋根材・仕様施工 / 지붕재・사양시공 +
    +
    + +
    +
    + +
    +
    +
    +
    + {/* 마지막div엔 mb5 제외 */} +
    +
    備考 /비고 +
    + +
    +
    +
    + {/* 파일첨부 시작 */} +
    +
    +

    {getMessage('estimate.detail.header.fileList1')}

    +
    + + +
    +
    +
    +
    + + + + + + + + + + + +
    {getMessage('estimate.detail.header.fileList1')} +
    +
    + +
    +
    +

    Drag file here

    +
      +
      +
      +
      +
      + {/* 첨부파일 목록 시작 */} +
      + + + + + + + + + + +
      {getMessage('estimate.detail.header.fileList2')}
      +
      + {/* 첨부파일 목록 끝 */} + {/* 파일첨부 끝 */} + {/* 견적특이사항 시작 */} +
      +
      +

      {getMessage('estimate.detail.header.specialEstimate')}

      +
      {getMessage('estimate.detail.header.specialEstimateProductInfo')}
      +
      +
      + {/* 공통코드영역시작 */} +
      + {/* 공통코드영역끝 */} + {/* 견적특이사항 내용영역시작 */} +
      + {/* 견적특이사항 내용영역끝 */} + {/* 견적특이사항 끝 */} + {/* 제품정보 시작 */} +
      +
      +

      {getMessage('estimate.detail.header.specialEstimateProductInfo')}

      +
      +
      +
      +
      +
      +
      수량 (PCS)
      +
      74
      +
      +
      +
      용량 (Kw)
      +
      8300
      +
      +
      +
      공급가액
      +
      6,798,900
      +
      +
      +
      부가세 (10%)
      +
      679,890
      +
      +
      +
      총액
      +
      7,478,790
      +
      +
      +
      + {/* YJOD면 아래영역 숨김 */} +
      + + + + + + + + + + + + + + + + + + + +
      + {getMessage('estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice')} + * + +
      + +
      +
      {getMessage('estimate.detail.sepcialEstimateProductInfo.pkgWeight')}(모듈수량 * 수량) / 100){getMessage('estimate.detail.sepcialEstimateProductInfo.pkgPrice')}PKG단가(W) * PKG용량(W)
      +
      + {/* 제품정보 끝 */} + {/* 가격표시영역시작 */} +
      +
      +
      {getMessage('estimate.detail.header.showPrice')}
      +
      + +
      +
      +
      +
      + + {getMessage('estimate.detail.showPrice.description')} +
      +
      +
      + + +
      +
      +
      + {/* 가격표시영역끝 */} + {/* html테이블시작 */} +
      + {/* html테이블끝 */} +
      +
      + {/* 기본정보끝 */} +
      +
      + ) +} diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index e8104548..9960fb1f 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -257,7 +257,9 @@ export default function StuffDetail() { type="button" className="grid-btn" onClick={() => { - console.log('견적서조회버튼클릭') + //mid:5(견적서), /pid:플랜번호 + setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo }) + router.push(`/floor-plan/5/${params.data.planNo}`) }} > @@ -270,7 +272,8 @@ export default function StuffDetail() { console.log('엑셀버튼클릭') }} > - Excel + + {getMessage('stuff.detail.planGrid.btn2')}
      diff --git a/src/components/management/StuffPlanQGrid.jsx b/src/components/management/StuffPlanQGrid.jsx index 1c8b88ba..c1e2c605 100644 --- a/src/components/management/StuffPlanQGrid.jsx +++ b/src/components/management/StuffPlanQGrid.jsx @@ -1,4 +1,5 @@ import { useState, useMemo, useCallback, useEffect } from 'react' +import { useMessage } from '@/hooks/useMessage' import { AgGridReact } from 'ag-grid-react' import 'ag-grid-community/styles/ag-grid.css' import 'ag-grid-community/styles/ag-theme-quartz.css' @@ -8,7 +9,7 @@ export default function StuffPlanQGrid(props) { const [rowData, setRowData] = useState(null) // const [gridApi, setGridApi] = useState(null) const [colDefs, setColDefs] = useState(planGridColumns) - + const { getMessage } = useMessage() const defaultColDef = useMemo(() => { return { flex: 1, @@ -46,6 +47,7 @@ export default function StuffPlanQGrid(props) { pagination={isPageable} domLayout="autoHeight" suppressCellFocus={true} + overlayNoRowsTemplate={`${getMessage('stuff.grid.noData')}`} />
      ) diff --git a/src/locales/ja.json b/src/locales/ja.json index 97e20595..8c6d1208 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -707,5 +707,29 @@ "surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.", - "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요." + "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", + "estimate.detail.header.title": "基本情報", + "estimate.detail.objectNo": "品番", + "estimate.detail.estimateNo": "見積書番号", + "estimate.detail.createDatetime": "登録日", + "estimate.detail.lastEditDatetime": "変更日時", + "estimate.detail.saleStoreId": "一次販売店名", + "estimate.detail.estimateDate": "見積日", + "estimate.detail.otherSaleStoreId": "二次販売店名", + "estimate.detail.receiveUser": "担当者 ", + "estimate.detail.title": "案件名", + "estimate.detail.remarks": "メモ", + "estimate.detail.header.fileList1": "ファイル添付", + "estimate.detail.fileList.btn": "ファイル選択", + "estimate.detail.header.fileList2": "添付ファイル一覧", + "estimate.detail.header.specialEstimate": "見積もりの具体的な", + "estimate.detail.header.specialEstimateProductInfo": "製品情報", + "estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "住宅PKG単価 (W)", + "estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG容量 (Kw)", + "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG金額", + "estimate.detail.header.showPrice": "価格表示", + "estimate.detail.showPrice.btn1": "Pricing", + "estimate.detail.showPrice.description": "クリックして製品の特異性を確認する", + "estimate.detail.showPrice.btn2": "製品を追加", + "estimate.detail.showPrice.btn3": "製品削除" } diff --git a/src/locales/ko.json b/src/locales/ko.json index cc47a03d..cecdf4af 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -712,5 +712,29 @@ "surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.", - "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요." + "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", + "estimate.detail.header.title": "기본정보", + "estimate.detail.objectNo": "물건번호", + "estimate.detail.estimateNo": "견적서 번호", + "estimate.detail.createDatetime": "등록일", + "estimate.detail.lastEditDatetime": "변경일시", + "estimate.detail.saleStoreId": "1차 판매점명", + "estimate.detail.estimateDate": "견적일", + "estimate.detail.otherSaleStoreId": "2차 판매점명", + "estimate.detail.receiveUser": "담당자", + "estimate.detail.title": "안건명", + "estimate.detail.remarks": "메모", + "estimate.detail.header.fileList1": "파일첨부", + "estimate.detail.fileList.btn": "파일선택", + "estimate.detail.header.fileList2": "첨부파일 목록", + "estimate.detail.header.specialEstimate": "견적특이사항", + "estimate.detail.header.specialEstimateProductInfo": "제품정보", + "estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "주택PKG단가 (W)", + "estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG 용량 (Kw)", + "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액", + "estimate.detail.header.showPrice": "가격표시", + "estimate.detail.showPrice.btn1": "Pricing", + "estimate.detail.showPrice.description": "클릭하여 제품 특이사항 확인", + "estimate.detail.showPrice.btn2": "제품추가", + "estimate.detail.showPrice.btn3": "제품삭제" } From caa642b65b35090f1542dc2516f614b5fed73feb Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 28 Oct 2024 15:48:52 +0900 Subject: [PATCH 125/139] =?UTF-8?q?fix:=20menuNumber=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/FloorPlan.jsx | 5 ++++- src/hooks/common/useCanvasMenu.js | 5 +++-- src/store/menuAtom.js | 6 ++++++ 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 src/store/menuAtom.js diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index caf9a2d7..adee1b60 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -25,10 +25,13 @@ export default function FloorPlan({ children }) { setMenuNumber, } useEffect(() => { - console.log('FloorPlan useEffect 실행') fetchSettings() }, [objectNo]) + useEffect(() => { + setMenuNumber(1) + }, []) + // Canvas Setting 조회 const fetchSettings = async () => { try { diff --git a/src/hooks/common/useCanvasMenu.js b/src/hooks/common/useCanvasMenu.js index 23f594d9..f8758e3e 100644 --- a/src/hooks/common/useCanvasMenu.js +++ b/src/hooks/common/useCanvasMenu.js @@ -1,7 +1,8 @@ -import { useState } from 'react' +import { menuNumberState } from '@/store/menuAtom' +import { useRecoilState } from 'recoil' export const useCanvasMenu = () => { - const [menuNumber, setMenuNumber] = useState(null) + const [menuNumber, setMenuNumber] = useRecoilState(menuNumberState) return { menuNumber, diff --git a/src/store/menuAtom.js b/src/store/menuAtom.js new file mode 100644 index 00000000..b86ecbd0 --- /dev/null +++ b/src/store/menuAtom.js @@ -0,0 +1,6 @@ +import { atom } from 'recoil' + +export const menuNumberState = atom({ + key: 'menuNumberState', + default: null, +}) From 598772025d345b6b967ab0627226f5b0921a512f Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 28 Oct 2024 17:22:16 +0900 Subject: [PATCH 126/139] fix: remove unused code --- src/components/floor-plan/FloorPlan.jsx | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index adee1b60..a2a5abc3 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -6,7 +6,6 @@ import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import CanvasMenu from '@/components/floor-plan/CanvasMenu' -import CanvasLayout from '@/components/floor-plan/CanvasLayout' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' import '@/styles/contents.scss' @@ -28,10 +27,6 @@ export default function FloorPlan({ children }) { fetchSettings() }, [objectNo]) - useEffect(() => { - setMenuNumber(1) - }, []) - // Canvas Setting 조회 const fetchSettings = async () => { try { From 41b03e6acf27aac6f2152c7210581f973075a4cb Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 28 Oct 2024 17:22:56 +0900 Subject: [PATCH 127/139] fix: add redirect code --- src/components/floor-plan/CanvasMenu.jsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 07411efb..b2ff69f6 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -4,6 +4,7 @@ import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { usePathname, useRouter } from 'next/navigation' import MenuDepth01 from './MenuDepth01' import QSelectBox from '@/components/common/select/QSelectBox' import { v4 as uuidv4 } from 'uuid' @@ -40,6 +41,8 @@ const canvasMenus = [ export default function CanvasMenu(props) { const { menuNumber, setMenuNumber } = props + const pathname = usePathname() + const router = useRouter() const { addPopup, closePopup } = usePopup() const [type, setType] = useState('') @@ -96,6 +99,8 @@ export default function CanvasMenu(props) { setType('module') break } + + if (pathname !== '/floor-plan') router.push('/floor-plan') } const menuProps = { type, From bf471fc76610e49b7254b79338fc7d8b4648c47e Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Mon, 28 Oct 2024 17:58:57 +0900 Subject: [PATCH 128/139] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20custCd=20=EC=B6=94=EA=B0=80=20(=EC=9E=84=EC=8B=9C?= =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8=20custCd=20=EC=98=88=EC=8B=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/layout.js | 1 + src/components/auth/Login.jsx | 2 ++ src/lib/authActions.js | 1 + 3 files changed, 4 insertions(+) diff --git a/src/app/layout.js b/src/app/layout.js index b41172c9..684dfb7f 100644 --- a/src/app/layout.js +++ b/src/app/layout.js @@ -46,6 +46,7 @@ export default async function RootLayout({ children }) { storeLvl: session.storeLvl, groupId: session.groupId, pwdInitYn: session.pwdInitYn, + custCd: session.custCd, isLoggedIn: session.isLoggedIn, } } diff --git a/src/components/auth/Login.jsx b/src/components/auth/Login.jsx index ef4f92a3..283d7d99 100644 --- a/src/components/auth/Login.jsx +++ b/src/components/auth/Login.jsx @@ -98,6 +98,7 @@ export default function Login() { pwdInitYn: 'Y', storeLvl: '1', groupId: '60000', + custCd: '100000', }) setSessionState({ userId: 'NEW016610', @@ -115,6 +116,7 @@ export default function Login() { pwdInitYn: 'Y', storeLvl: '1', groupId: '60000', + custCd: '100000', }) if (chkLoginId) { Cookies.set('chkLoginId', formData.get('id'), { expires: 7 }) diff --git a/src/lib/authActions.js b/src/lib/authActions.js index 618985b9..0834833e 100644 --- a/src/lib/authActions.js +++ b/src/lib/authActions.js @@ -52,6 +52,7 @@ export async function setSession(data) { session.storeLvl = data.storeLvl session.groupId = data.groupId session.pwdInitYn = data.pwdInitYn + session.custCd = data.custCd session.isLoggedIn = true // console.log('session:', session) From 871e29a924ada0274456971bc7bdaf51790138e5 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 28 Oct 2024 18:04:01 +0900 Subject: [PATCH 129/139] fix: add 'use client' keyword --- src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx | 2 ++ .../floor-plan/modal/panelBatch/PanelBatchStatistics.jsx | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx index 9b4beb8f..8b2aca85 100644 --- a/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx +++ b/src/components/floor-plan/modal/auxiliary/AuxiliaryMove.jsx @@ -1,3 +1,5 @@ +'use client' + import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' import { useRecoilValue } from 'recoil' diff --git a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx index 2d36c4eb..9a6c7b84 100644 --- a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx +++ b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx @@ -1,6 +1,8 @@ -import WithDraggable from '@/components/common/draggable/withDraggable' +'use client' + import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' +import WithDraggable from '@/components/common/draggable/withDraggable' export default function PanelBatchStatistics() { const { getMessage } = useMessage() From 58e76cba9e16e67fb3a8fdac70f08aaa8eac4669 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 28 Oct 2024 18:14:09 +0900 Subject: [PATCH 130/139] =?UTF-8?q?=F0=9F=9A=A8chore:=20Sync=20Sass?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/styles/_modal.scss | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index 9dc39b65..62fad511 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -1788,4 +1788,22 @@ $alert-color: #101010; flex: none; } } +} + +//이미지 크기 설정 +.range-wrap{ + display: flex; + align-items: center; + input{ + flex: 1; + margin-right: 10px; + } + label{ + flex: none; + text-align: right; + width: 35px; + font-size: 13px; + color: #fff; + font-weight: 500; + } } \ No newline at end of file From 37df5f6023b90fcf6eb70c8af468e6ab89084fc4 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 28 Oct 2024 18:14:26 +0900 Subject: [PATCH 131/139] =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=81=AC?= =?UTF-8?q?=EA=B8=B0=20=EC=A1=B0=EC=A0=88=20=EB=AA=A8=EB=8B=AC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/image/ImageSizeSetting.jsx | 42 +++++++++++++++++++ src/locales/ja.json | 29 ++++++------- src/locales/ko.json | 9 ++-- 3 files changed, 62 insertions(+), 18 deletions(-) create mode 100644 src/components/floor-plan/modal/image/ImageSizeSetting.jsx diff --git a/src/components/floor-plan/modal/image/ImageSizeSetting.jsx b/src/components/floor-plan/modal/image/ImageSizeSetting.jsx new file mode 100644 index 00000000..63741e7a --- /dev/null +++ b/src/components/floor-plan/modal/image/ImageSizeSetting.jsx @@ -0,0 +1,42 @@ +import WithDraggable from '@/components/common/draggable/WithDraggable' +import { useState } from 'react' +import { usePopup } from '@/hooks/usePopup' +import { useRecoilValue } from 'recoil' +import { contextPopupPositionState } from '@/store/popupAtom' +import { useMessage } from '@/hooks/useMessage' + +export default function ImageSizeSetting(props) { + const contextPopupPosition = useRecoilValue(contextPopupPositionState) + const { id, pos = contextPopupPosition, size, setSize } = props + const [sizeValue, setSizeValue] = useState(100) + const { getMessage } = useMessage() + const { closePopup } = usePopup() + + return ( + +
      +
      +

      {getMessage('modal.image.size.setting')}

      + +
      +
      +
      + setSizeValue(e.target.value)} + /> + +
      +
      +
      +
      + ) +} diff --git a/src/locales/ja.json b/src/locales/ja.json index 97e20595..6bb6d71c 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -214,20 +214,20 @@ "modal.canvas.setting.font.plan.absorption.dimension.display": "見る", "modal.canvas.setting.font.plan.absorption.plan.size.setting": "図面サイズの設定", "modal.canvas.setting.first.option.info": "※図面に表示する項目をクリックすると適用されます。", - "modal.canvas.setting.first.option.alloc": "할당표시", - "modal.canvas.setting.first.option.outline": "외벽선표시", - "modal.canvas.setting.first.option.plan": "도면표시", - "modal.canvas.setting.first.option.roof.line": "지붕선표시", - "modal.canvas.setting.first.option.grid": "그리드표시", - "modal.canvas.setting.first.option.circuit.num": "회로 번호 표시", - "modal.canvas.setting.first.option.word": "문자 표시", - "modal.canvas.setting.first.option.trestle": "가대 표시", - "modal.canvas.setting.first.option.flow": "흐름방향 표시", - "modal.canvas.setting.first.option.total": "집계표 표시", - "modal.canvas.setting.first.option.dimension": "치수 표시(JA)", - "modal.canvas.setting.first.option.corridor.dimension": "복도치수 표시(JA)", - "modal.canvas.setting.first.option.real.dimension": "실제치수 표시(JA)", - "modal.canvas.setting.first.option.none.dimension": "치수표시없음(JA)", + "modal.canvas.setting.first.option.alloc": "割り当て表示", + "modal.canvas.setting.first.option.outline": "外壁線表示", + "modal.canvas.setting.first.option.grid": "グリッド表示", + "modal.canvas.setting.first.option.roof.line": "屋根線標示", + "modal.canvas.setting.first.option.word": "文字表示", + "modal.canvas.setting.first.option.circuit.num": "回路番号表示", + "modal.canvas.setting.first.option.flow": "流れ方向表示", + "modal.canvas.setting.first.option.trestle": "架台表示", + "modal.canvas.setting.first.option.image": "画像表示", + "modal.canvas.setting.first.option.total": "集計表表示", + "modal.canvas.setting.first.option.dimension": "寸法表示", + "modal.canvas.setting.first.option.corridor.dimension": "廊下寸法表示", + "modal.canvas.setting.first.option.real.dimension": "実際の寸法表示", + "modal.canvas.setting.first.option.none.dimension": "寸法表示なし", "modal.canvas.setting.first.option.display": "画面表示", "modal.canvas.setting.first.option.border": "ボーダーのみ", "modal.canvas.setting.first.option.line": "ラインハッチ", @@ -274,6 +274,7 @@ "modal.panel.batch.statistic.total": "合計", "modal.flow.direction.setting": "流れ方向の設定", "modal.flow.direction.setting.info": "流れ方向を選択してください。", + "modal.image.size.setting": "画像のサイズ変更", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", diff --git a/src/locales/ko.json b/src/locales/ko.json index cc47a03d..7f4555be 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -221,13 +221,13 @@ "modal.canvas.setting.first.option.info": "※도면에 표시하는 항목을 클릭하면 적용됩니다.", "modal.canvas.setting.first.option.alloc": "할당표시", "modal.canvas.setting.first.option.outline": "외벽선표시", - "modal.canvas.setting.first.option.plan": "도면표시", - "modal.canvas.setting.first.option.roof.line": "지붕선표시", "modal.canvas.setting.first.option.grid": "그리드표시", - "modal.canvas.setting.first.option.circuit.num": "회로 번호 표시", + "modal.canvas.setting.first.option.roof.line": "지붕선표시", "modal.canvas.setting.first.option.word": "문자 표시", - "modal.canvas.setting.first.option.trestle": "가대 표시", + "modal.canvas.setting.first.option.circuit.num": "회로 번호 표시", "modal.canvas.setting.first.option.flow": "흐름방향 표시", + "modal.canvas.setting.first.option.trestle": "가대 표시", + "modal.canvas.setting.first.option.image": "이미지 표시", "modal.canvas.setting.first.option.total": "집계표 표시", "modal.canvas.setting.first.option.dimension": "치수 표시", "modal.canvas.setting.first.option.corridor.dimension": "복도치수 표시", @@ -279,6 +279,7 @@ "modal.panel.batch.statistic.total": "합계", "modal.flow.direction.setting": "흐름 방향 설정", "modal.flow.direction.setting.info": "흐름방향을 선택하세요.", + "modal.image.size.setting": "이미지 크기 조절", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", From b48e43dd9ff3a19153c5fcf341ef7fd5c5f73a72 Mon Sep 17 00:00:00 2001 From: minsik Date: Mon, 28 Oct 2024 18:15:01 +0900 Subject: [PATCH 132/139] =?UTF-8?q?-=20canvas=20setting=EC=97=90=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20=ED=91=9C=EC=8B=9C=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=20-=20context=20menu=EC=97=90=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80=20=ED=81=AC=EA=B8=B0=20=EC=A1=B0=EC=A0=88=20=EA=B8=B0?= =?UTF-8?q?=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useContextMenu.js | 13 +++++++++++- src/store/settingAtom.js | 40 ++++++++++++++++++++++++++++++++----- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index c5134e25..293a0ceb 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -23,6 +23,7 @@ import FlowDirectionSetting from '@/components/floor-plan/modal/flowDirection/Fl import { useMessage } from '@/hooks/useMessage' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { contextMenuState } from '@/store/contextMenu' +import ImageSizeSetting from '@/components/floor-plan/modal/image/ImageSizeSetting' export function useContextMenu() { const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 @@ -36,7 +37,7 @@ export function useContextMenu() { const [gridColor, setGridColor] = useRecoilState(gridColorState) const [qContextMenu, setQContextMenu] = useRecoilState(contextMenuState) const { handleZoomClear } = useCanvasEvent() - const currentMenuSetting = (position) => { + const currentMenuSetting = () => { switch (currentMenu) { case MENU.PLAN_DRAWING: setContextMenu([ @@ -104,6 +105,11 @@ export function useContextMenu() { id: 'wallLineRemove', name: getMessage('contextmenu.wallline.remove'), }, + { + id: 'imageSizeEdit', + name: getMessage('modal.image.size.setting'), + component: , + }, ], [ { @@ -170,6 +176,11 @@ export function useContextMenu() { shortcut: ['c', 'C'], name: `${getMessage('contextmenu.copy')}(C)`, }, + { + id: 'imageSizeEdit', + name: getMessage('modal.image.size.setting'), + component: , + }, ], [ { diff --git a/src/store/settingAtom.js b/src/store/settingAtom.js index 2432d884..4cab929c 100644 --- a/src/store/settingAtom.js +++ b/src/store/settingAtom.js @@ -12,10 +12,16 @@ export const settingModalFirstOptionsState = atom({ { id: 6, column: 'circuitNumDisplay', name: 'modal.canvas.setting.first.option.circuit.num', selected: false }, { id: 7, column: 'flowDisplay', name: 'modal.canvas.setting.first.option.flow', selected: false }, { id: 8, column: 'trestleDisplay', name: 'modal.canvas.setting.first.option.trestle', selected: false }, + { id: 10, column: 'imageDisplay', name: 'modal.canvas.setting.first.option.image', selected: false }, { id: 9, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: false }, ], dimensionDisplay: [ - { id: 1, column: 'corridorDimension', name: 'modal.canvas.setting.first.option.corridor.dimension', selected: true }, + { + id: 1, + column: 'corridorDimension', + name: 'modal.canvas.setting.first.option.corridor.dimension', + selected: true, + }, { id: 2, column: 'realDimension', name: 'modal.canvas.setting.first.option.real.dimension', selected: false }, { id: 3, column: 'noneDimension', name: 'modal.canvas.setting.first.option.none.dimension', selected: false }, ], @@ -38,10 +44,34 @@ export const settingModalSecondOptionsState = atom({ { id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' }, ], option4: [ - { id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true, range: 10 }, - { id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false, range: 30 }, - { id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false, range: 50 }, - { id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false, range: 70 }, + { + id: 1, + column: 'adsorpRangeSmall', + name: 'modal.canvas.setting.font.plan.absorption.small', + selected: true, + range: 10, + }, + { + id: 2, + column: 'adsorpRangeSmallSemi', + name: 'modal.canvas.setting.font.plan.absorption.small.semi', + selected: false, + range: 30, + }, + { + id: 3, + column: 'adsorpRangeMedium', + name: 'modal.canvas.setting.font.plan.absorption.medium', + selected: false, + range: 50, + }, + { + id: 4, + column: 'adsorpRangeLarge', + name: 'modal.canvas.setting.font.plan.absorption.large', + selected: false, + range: 70, + }, ], }, dangerouslyAllowMutability: true, From 09abb897ac2e4b28b610b334ddaafa7f1833f25c Mon Sep 17 00:00:00 2001 From: changkyu choi Date: Mon, 28 Oct 2024 18:59:21 +0900 Subject: [PATCH 133/139] =?UTF-8?q?Canvas=20=EC=84=A4=EC=A0=95=20=EC=A4=91?= =?UTF-8?q?=EA=B0=84=20Commit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/FloorPlan.jsx | 37 +- .../modal/setting01/FirstOption.jsx | 372 +++++++++--------- .../modal/setting01/SecondOption.jsx | 260 ++++++------ src/hooks/option/useCanvasSetting.js | 268 +++++++++++++ .../option/useCanvasSettingController.js | 1 + 5 files changed, 602 insertions(+), 336 deletions(-) create mode 100644 src/hooks/option/useCanvasSetting.js diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index a2a5abc3..5639b93f 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -2,56 +2,33 @@ import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' -import { useAxios } from '@/hooks/useAxios' -import { globalLocaleStore } from '@/store/localeAtom' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import CanvasMenu from '@/components/floor-plan/CanvasMenu' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' +import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import '@/styles/contents.scss' export default function FloorPlan({ children }) { - const globalLocaleState = useRecoilValue(globalLocaleStore) - const { get } = useAxios(globalLocaleState) const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - // const [menuNumber, setMenuNumber] = useState(null) const { menuNumber, setMenuNumber } = useCanvasMenu() + const { fetchSettings } = useCanvasSetting() + const modalProps = { menuNumber, setMenuNumber, } + useEffect(() => { fetchSettings() }, [objectNo]) - // Canvas Setting 조회 - const fetchSettings = async () => { - try { - const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) - const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) - const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) - const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) - const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) - const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ - ...item, - })) - // 데이터 설정 - setSettingModalFirstOptions({ - option1: optionData1, - option2: optionData2, - dimensionDisplay: optionData5, - }) - setSettingModalSecondOptions({ - option3: optionData3, - option4: optionData4, - }) - } catch (error) { - console.error('Data fetching error:', error) - } - } + useEffect(() => { + setMenuNumber(1) + }, []) return ( <> diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index 6373d8a8..db721dd5 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -1,210 +1,216 @@ -import { useRecoilState, useRecoilValue } from 'recoil' -import { settingModalSecondOptionsState } from '@/store/settingAtom' -import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' -import { useAxios } from '@/hooks/useAxios' -import { useSwal } from '@/hooks/useSwal' -import { useFirstOption } from '@/hooks/option/useFirstOption' -import { setSurfaceShapePattern } from '@/util/canvas-util' -import { canvasState } from '@/store/canvasAtom' -import { POLYGON_TYPE } from '@/common/common' +import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' +import { useMessage } from '@/hooks/useMessage' + +//import { useRecoilState, useRecoilValue } from 'recoil' +//import { settingModalSecondOptionsState } from '@/store/settingAtom' +//import { useAxios } from '@/hooks/useAxios' +//import { useSwal } from '@/hooks/useSwal' +//import { setSurfaceShapePattern } from '@/util/canvas-util' +//import { canvasState } from '@/store/canvasAtom' +//import { POLYGON_TYPE } from '@/common/common' export default function FirstOption() { const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - const { settingModalFirstOptions, setSettingModalFirstOptions } = useFirstOption() - const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) - const { option1, option2, dimensionDisplay } = settingModalFirstOptions - const { option3, option4 } = settingModalSecondOptions + const { settingModalFirstOptions, setSettingModalFirstOptions } = useCanvasSetting() + const { settingModalSecondOptions, setSettingModalSecondOptions } = useCanvasSetting() const { getMessage } = useMessage() - const { get, post } = useAxios() - const { swalFire } = useSwal() - const canvas = useRecoilValue(canvasState) + + //const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) + //const { option1, option2, dimensionDisplay } = settingModalFirstOptions + //const { option3, option4 } = settingModalSecondOptions + //const { get, post } = useAxios() + //const { swalFire } = useSwal() + //const canvas = useRecoilValue(canvasState) + + const { fetchSettings, frontSettings, onClickOption } = useCanvasSetting() // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('FirstOption useEffect 실행') - fetchSettings() + //fetchSettings() + //frontSettings() }, [objectNo]) - // Canvas Setting 조회 및 초기화 - const fetchSettings = async () => { - try { - const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) - const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) - const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) - const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] })) - const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) - const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) + // // Canvas Setting 조회 및 초기화 + // const fetchSettings = async () => { + // try { + // const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) + // const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) + // const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) - // 데이터 설정 - setSettingModalFirstOptions({ - option1: optionData1, - option2: optionData2, - dimensionDisplay: optionData5, - }) + // // 데이터 설정 + // setSettingModalFirstOptions({ + // option1: optionData1, + // option2: optionData2, + // dimensionDisplay: optionData5, + // }) - setSettingModalSecondOptions({ - option3: optionData3, - option4: optionData4, - }) - } catch (error) { - console.error('Data fetching error:', error) - } - } + // setSettingModalSecondOptions({ + // option3: optionData3, + // option4: optionData4, + // }) + // } catch (error) { + // console.error('Data fetching error:', error) + // } + // } - const onClickOption = async (option) => { - option.selected = !option.selected + // const onClickOption = async (option) => { + // option.selected = !option.selected - setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) - setSettingModalSecondOptions({ option3, option4 }) + // setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) + // setSettingModalSecondOptions({ option3, option4 }) - try { - // 서버에 전송할 데이터 - const dataToSend = { - firstOption1: option1.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption2: option2.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption3: dimensionDisplay.map((item) => ({ - column: item.column, - selected: item.selected, - })), - // secondOption1: secondOptions[0].option1.map((item) => ({ - // name: item.id, - // name: item.name, - // // 필요한 경우 데이터 항목 추가 - // })), - secondOption2: option4.map((item) => ({ - column: item.column, - selected: item.selected, - })), - } + // try { + // // 서버에 전송할 데이터 + // const dataToSend = { + // firstOption1: option1.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption2: option2.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption3: dimensionDisplay.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // // secondOption1: secondOptions[0].option1.map((item) => ({ + // // name: item.id, + // // name: item.name, + // // // 필요한 경우 데이터 항목 추가 + // // })), + // secondOption2: option4.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // } - const patternData = { - objectNo, - //디스플레이 설정(다중) - allocDisplay: dataToSend.firstOption1[0].selected, - outlineDisplay: dataToSend.firstOption1[1].selected, - gridDisplay: dataToSend.firstOption1[2].selected, - lineDisplay: dataToSend.firstOption1[3].selected, - wordDisplay: dataToSend.firstOption1[4].selected, - circuitNumDisplay: dataToSend.firstOption1[5].selected, - flowDisplay: dataToSend.firstOption1[6].selected, - trestleDisplay: dataToSend.firstOption1[7].selected, - totalDisplay: dataToSend.firstOption1[8].selected, - //차수 표시(다건) - corridorDimension: dataToSend.firstOption3[0].selected, - realDimension: dataToSend.firstOption3[1].selected, - noneDimension: dataToSend.firstOption3[2].selected, - //화면 표시(다중) - onlyBorder: dataToSend.firstOption2[0].selected, - lineHatch: dataToSend.firstOption2[1].selected, - allPainted: dataToSend.firstOption2[2].selected, - //흡착범위 설정(단건) - adsorpRangeSmall: dataToSend.secondOption2[0].selected, - adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, - adsorpRangeMedium: dataToSend.secondOption2[2].selected, - adsorpRangeLarge: dataToSend.secondOption2[3].selected, - } + // const patternData = { + // objectNo, + // //디스플레이 설정(다중) + // allocDisplay: dataToSend.firstOption1[0].selected, + // outlineDisplay: dataToSend.firstOption1[1].selected, + // gridDisplay: dataToSend.firstOption1[2].selected, + // lineDisplay: dataToSend.firstOption1[3].selected, + // wordDisplay: dataToSend.firstOption1[4].selected, + // circuitNumDisplay: dataToSend.firstOption1[5].selected, + // flowDisplay: dataToSend.firstOption1[6].selected, + // trestleDisplay: dataToSend.firstOption1[7].selected, + // totalDisplay: dataToSend.firstOption1[8].selected, + // //차수 표시(다건) + // corridorDimension: dataToSend.firstOption3[0].selected, + // realDimension: dataToSend.firstOption3[1].selected, + // noneDimension: dataToSend.firstOption3[2].selected, + // //화면 표시(다중) + // onlyBorder: dataToSend.firstOption2[0].selected, + // lineHatch: dataToSend.firstOption2[1].selected, + // allPainted: dataToSend.firstOption2[2].selected, + // //흡착범위 설정(단건) + // adsorpRangeSmall: dataToSend.secondOption2[0].selected, + // adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + // adsorpRangeMedium: dataToSend.secondOption2[2].selected, + // adsorpRangeLarge: dataToSend.secondOption2[3].selected, + // } - // HTTP POST 요청 보내기 - await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { - swalFire({ text: getMessage(res.returnMessage) }) - }) - } catch (error) { - swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) - } - } + // // HTTP POST 요청 보내기 + // await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { + // swalFire({ text: getMessage(res.returnMessage) }) + // }) + // } catch (error) { + // swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) + // } + // } - const onClickOnlyOne = async (item) => { - //화면 표시 - if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') { - const options2 = settingModalFirstOptions?.option2.map((option2) => { - option2.selected = option2.id === item.id - return option2 - }) + // const onClickOnlyOne = async (item) => { + // //화면 표시 + // if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') { + // const options2 = settingModalFirstOptions?.option2.map((option2) => { + // option2.selected = option2.id === item.id + // return option2 + // }) - const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + // const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) - polygons.forEach((polygon) => { - setSurfaceShapePattern(polygon, item.column) - }) + // polygons.forEach((polygon) => { + // setSurfaceShapePattern(polygon, item.column) + // }) - //치수 표시 - } else { - const options = settingModalFirstOptions?.dimensionDisplay.map((option) => { - option.selected = option.id === item.id - return option - }) - } + // //치수 표시 + // } else { + // const options = settingModalFirstOptions?.dimensionDisplay.map((option) => { + // option.selected = option.id === item.id + // return option + // }) + // } - setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) + // setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) - try { - // 서버에 전송할 데이터 - const dataToSend = { - firstOption1: option1.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption2: option2.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption3: dimensionDisplay.map((item) => ({ - column: item.column, - selected: item.selected, - })), - // secondOption1: secondOptions[0].option1.map((item) => ({ - // name: item.id, - // name: item.name, - // // 필요한 경우 데이터 항목 추가 - // })), - secondOption2: option4.map((item) => ({ - column: item.column, - selected: item.selected, - })), - } + // try { + // // 서버에 전송할 데이터 + // const dataToSend = { + // firstOption1: option1.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption2: option2.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption3: dimensionDisplay.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // // secondOption1: secondOptions[0].option1.map((item) => ({ + // // name: item.id, + // // name: item.name, + // // // 필요한 경우 데이터 항목 추가 + // // })), + // secondOption2: option4.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // } - const patternData = { - objectNo, - //디스플레이 설정(다중) - allocDisplay: dataToSend.firstOption1[0].selected, - outlineDisplay: dataToSend.firstOption1[1].selected, - gridDisplay: dataToSend.firstOption1[2].selected, - lineDisplay: dataToSend.firstOption1[3].selected, - wordDisplay: dataToSend.firstOption1[4].selected, - circuitNumDisplay: dataToSend.firstOption1[5].selected, - flowDisplay: dataToSend.firstOption1[6].selected, - trestleDisplay: dataToSend.firstOption1[7].selected, - totalDisplay: dataToSend.firstOption1[8].selected, - //차수 표시(다건) - corridorDimension: dataToSend.firstOption3[0].selected, - realDimension: dataToSend.firstOption3[1].selected, - noneDimension: dataToSend.firstOption3[2].selected, - //화면 표시(다중) - onlyBorder: dataToSend.firstOption2[0].selected, - lineHatch: dataToSend.firstOption2[1].selected, - allPainted: dataToSend.firstOption2[2].selected, - //흡착범위 설정(단건) - adsorpRangeSmall: dataToSend.secondOption2[0].selected, - adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, - adsorpRangeMedium: dataToSend.secondOption2[2].selected, - adsorpRangeLarge: dataToSend.secondOption2[3].selected, - } + // const patternData = { + // objectNo, + // //디스플레이 설정(다중) + // allocDisplay: dataToSend.firstOption1[0].selected, + // outlineDisplay: dataToSend.firstOption1[1].selected, + // gridDisplay: dataToSend.firstOption1[2].selected, + // lineDisplay: dataToSend.firstOption1[3].selected, + // wordDisplay: dataToSend.firstOption1[4].selected, + // circuitNumDisplay: dataToSend.firstOption1[5].selected, + // flowDisplay: dataToSend.firstOption1[6].selected, + // trestleDisplay: dataToSend.firstOption1[7].selected, + // totalDisplay: dataToSend.firstOption1[8].selected, + // //차수 표시(다건) + // corridorDimension: dataToSend.firstOption3[0].selected, + // realDimension: dataToSend.firstOption3[1].selected, + // noneDimension: dataToSend.firstOption3[2].selected, + // //화면 표시(다중) + // onlyBorder: dataToSend.firstOption2[0].selected, + // lineHatch: dataToSend.firstOption2[1].selected, + // allPainted: dataToSend.firstOption2[2].selected, + // //흡착범위 설정(단건) + // adsorpRangeSmall: dataToSend.secondOption2[0].selected, + // adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + // adsorpRangeMedium: dataToSend.secondOption2[2].selected, + // adsorpRangeLarge: dataToSend.secondOption2[3].selected, + // } - // HTTP POST 요청 보내기 - await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { - swalFire({ text: getMessage(res.returnMessage) }) - }) - } catch (error) { - swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) - } - } + // // HTTP POST 요청 보내기 + // await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { + // swalFire({ text: getMessage(res.returnMessage) }) + // }) + // } catch (error) { + // swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) + // } + // } return ( <> @@ -225,7 +231,7 @@ export default function FirstOption() {
      {settingModalFirstOptions && settingModalFirstOptions.dimensionDisplay.map((item) => ( - @@ -237,7 +243,7 @@ export default function FirstOption() {
      {settingModalFirstOptions && settingModalFirstOptions.option2.map((item) => ( - diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index ceccce5e..ff8d61db 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,143 +1,148 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +//import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' -import { useAxios } from '@/hooks/useAxios' -import { useSwal } from '@/hooks/useSwal' -import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting' import { usePopup } from '@/hooks/usePopup' import { v4 as uuidv4 } from 'uuid' import FontSetting from '@/components/common/font/FontSetting' import PlanSizeSetting from '@/components/floor-plan/modal/setting01/planSize/PlanSizeSetting' import { dimensionLineSettingsState } from '@/store/commonUtilsAtom' +import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' + +//import { useAxios } from '@/hooks/useAxios' +//import { useSwal } from '@/hooks/useSwal' +// import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' export default function SecondOption() { - const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 - const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) - const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) - const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) - const setAdsorptionRange = useSetRecoilState(adsorptionRangeState) + //const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + //const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) + // const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) + // const setAdsorptionRange = useSetRecoilState(adsorptionRangeState) + // const { option1, option2, dimensionDisplay } = settingModalFirstOptions + // const { option3, option4 } = settingModalSecondOptions + // const { get, post } = useAxios() + // const { swalFire } = useSwal() - const { option1, option2, dimensionDisplay } = settingModalFirstOptions - const { option3, option4 } = settingModalSecondOptions const { getMessage } = useMessage() - const { get, post } = useAxios() - const { swalFire } = useSwal() const { addPopup, closePopup, closePopups } = usePopup() const [showFontSettingModal, setShowFontSettingModal] = useState(false) const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) const [showPlanSizeSettingModal, setShowPlanSizeSettingModal] = useState(false) const dimensionSettings = useRecoilValue(dimensionLineSettingsState) + const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 + const { settingModalFirstOptions, setSettingModalFirstOptions } = useCanvasSetting() + const { settingModalSecondOptions, setSettingModalSecondOptions } = useCanvasSetting() + const { adsorptionPointMode, setAdsorptionPointMode } = useCanvasSetting() + const { fetchSettings, frontSettings, onClickOption } = useCanvasSetting() + // 데이터를 최초 한 번만 조회 useEffect(() => { console.log('SecondOption useEffect 실행') - fetchSettings() + //fetchSettings() }, [objectNo]) // Canvas Setting 조회 및 초기화 - const fetchSettings = async () => { - try { - const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) - const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) - const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) - const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ - ...item, - selected: res[item.column], - })) - const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) - const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) + // const fetchSettings = async () => { + // try { + // const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) + // const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] })) + // const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) + // const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) - setSettingModalFirstOptions({ - option1: optionData1, - option2: optionData2, - dimensionDisplay: optionData5, - }) - setSettingModalSecondOptions({ - option3: optionData3, - option4: optionData4, - }) - } catch (error) { - console.error('Data fetching error:', error) - } - } + // setSettingModalFirstOptions({ + // option1: optionData1, + // option2: optionData2, + // dimensionDisplay: optionData5, + // }) + // setSettingModalSecondOptions({ + // option3: optionData3, + // option4: optionData4, + // }) + // } catch (error) { + // console.error('Data fetching error:', error) + // } + // } - const onClickOption = async (option) => { - // option4에서 한 개만 선택 가능하도록 처리 - const updatedOption4 = option4.map((item) => - item.id === option.id - ? { ...item, selected: true } - : { - ...item, - selected: false, - }, - ) + // const onClickOption = async (option) => { + // // option4에서 한 개만 선택 가능하도록 처리 + // const updatedOption4 = option4.map((item) => + // item.id === option.id + // ? { ...item, selected: true } + // : { + // ...item, + // selected: false, + // }, + // ) - setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) - setSettingModalSecondOptions({ option3, option4: updatedOption4 }) + // setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) + // setSettingModalSecondOptions({ option3, option4: updatedOption4 }) - try { - // 서버에 전송할 데이터 - const dataToSend = { - firstOption1: option1.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption2: option2.map((item) => ({ - column: item.column, - selected: item.selected, - })), - firstOption3: dimensionDisplay.map((item) => ({ - column: item.column, - selected: item.selected, - })), - // secondOption1: secondOptions[0].option3.map((item) => ({ - // name: item.id, - // name: item.name, - // // 필요한 경우 데이터 항목 추가 - // })), - secondOption2: updatedOption4.map((item) => ({ - column: item.column, - selected: item.selected, - })), - } - const patternData = { - objectNo, - //디스플레이 설정(다중) - allocDisplay: dataToSend.firstOption1[0].selected, - outlineDisplay: dataToSend.firstOption1[1].selected, - gridDisplay: dataToSend.firstOption1[2].selected, - lineDisplay: dataToSend.firstOption1[3].selected, - wordDisplay: dataToSend.firstOption1[4].selected, - circuitNumDisplay: dataToSend.firstOption1[5].selected, - flowDisplay: dataToSend.firstOption1[6].selected, - trestleDisplay: dataToSend.firstOption1[7].selected, - totalDisplay: dataToSend.firstOption1[8].selected, - //차수 표시(다건) - corridorDimension: dataToSend.firstOption3[0].selected, - realDimension: dataToSend.firstOption3[1].selected, - noneDimension: dataToSend.firstOption3[2].selected, - //화면 표시(다중) - onlyBorder: dataToSend.firstOption2[0].selected, - lineHatch: dataToSend.firstOption2[1].selected, - allPainted: dataToSend.firstOption2[2].selected, - //흡착범위 설정(단건) - adsorpRangeSmall: dataToSend.secondOption2[0].selected, - adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, - adsorpRangeMedium: dataToSend.secondOption2[2].selected, - adsorpRangeLarge: dataToSend.secondOption2[3].selected, - } + // try { + // // 서버에 전송할 데이터 + // const dataToSend = { + // firstOption1: option1.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption2: option2.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // firstOption3: dimensionDisplay.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // // secondOption1: secondOptions[0].option3.map((item) => ({ + // // name: item.id, + // // name: item.name, + // // // 필요한 경우 데이터 항목 추가 + // // })), + // secondOption2: updatedOption4.map((item) => ({ + // column: item.column, + // selected: item.selected, + // })), + // } + // const patternData = { + // objectNo, + // //디스플레이 설정(다중) + // allocDisplay: dataToSend.firstOption1[0].selected, + // outlineDisplay: dataToSend.firstOption1[1].selected, + // gridDisplay: dataToSend.firstOption1[2].selected, + // lineDisplay: dataToSend.firstOption1[3].selected, + // wordDisplay: dataToSend.firstOption1[4].selected, + // circuitNumDisplay: dataToSend.firstOption1[5].selected, + // flowDisplay: dataToSend.firstOption1[6].selected, + // trestleDisplay: dataToSend.firstOption1[7].selected, + // totalDisplay: dataToSend.firstOption1[8].selected, + // //차수 표시(다건) + // corridorDimension: dataToSend.firstOption3[0].selected, + // realDimension: dataToSend.firstOption3[1].selected, + // noneDimension: dataToSend.firstOption3[2].selected, + // //화면 표시(다중) + // onlyBorder: dataToSend.firstOption2[0].selected, + // lineHatch: dataToSend.firstOption2[1].selected, + // allPainted: dataToSend.firstOption2[2].selected, + // //흡착범위 설정(단건) + // adsorpRangeSmall: dataToSend.secondOption2[0].selected, + // adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + // adsorpRangeMedium: dataToSend.secondOption2[2].selected, + // adsorpRangeLarge: dataToSend.secondOption2[3].selected, + // } + + // // HTTP POST 요청 보내기 + // await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { + // swalFire({ text: getMessage(res.returnMessage) }) + // }) + // } catch (error) { + // swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) + // } + // setAdsorptionRange(option.range) + // } - // HTTP POST 요청 보내기 - await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { - swalFire({ text: getMessage(res.returnMessage) }) - }) - } catch (error) { - swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) - } - setAdsorptionRange(option.range) - } let dimensionId = null let fontId = null let planSizeId = null @@ -192,16 +197,6 @@ export default function SecondOption() { setShowFontSettingModal(false) switch (type) { - case 'dimensionLine': - if (!showDimensionLineSettingModal) { - setShowDimensionLineSettingModal(true) - addPopup(dimensionId, 2, ) - } else { - setShowDimensionLineSettingModal(false) - closePopup(dimensionId) - } - - break case 'font1': { //문자 글꼴변경 setShowFontSettingModal(true) @@ -210,6 +205,7 @@ export default function SecondOption() { addPopup(fontId + 1, 2, ) break } + case 'font2': { //흐름 방향 글꼴 변경 setShowFontSettingModal(true) @@ -218,6 +214,7 @@ export default function SecondOption() { addPopup(fontId + 2, 2, ) break } + case 'font3': { //치수 글꼴변경 setShowFontSettingModal(true) @@ -226,17 +223,34 @@ export default function SecondOption() { addPopup(fontId + 3, 2, ) break } - case 'font4': //회로번호 글꼴변경 + + case 'font4': { + //회로번호 글꼴변경 setShowFontSettingModal(true) fontProps.type = 'circuitNumberText' fontProps.id = fontId addPopup(fontId, 2, ) break - case 'planSize': - setShowPlanSizeSettingModal(true) + } + case 'dimensionLine': { + //치수선 설정 + if (!showDimensionLineSettingModal) { + setShowDimensionLineSettingModal(true) + addPopup(dimensionId, 2, ) + } else { + setShowDimensionLineSettingModal(false) + closePopup(dimensionId) + } + break + } + + case 'planSize': { + //도면크기 설정 + setShowPlanSizeSettingModal(true) addPopup(planSizeId, 2, ) break + } } } diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js new file mode 100644 index 00000000..2856b5c2 --- /dev/null +++ b/src/hooks/option/useCanvasSetting.js @@ -0,0 +1,268 @@ +import { useEffect, useState } from 'react' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' +import { canvasState } from '@/store/canvasAtom' +import { globalLocaleStore } from '@/store/localeAtom' +import { useMessage } from '@/hooks/useMessage' +import { useAxios } from '@/hooks/useAxios' +import { useSwal } from '@/hooks/useSwal' +import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' +import { setSurfaceShapePattern } from '@/util/canvas-util' +import { POLYGON_TYPE } from '@/common/common' + +import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom' + +export function useCanvasSetting() { + const canvas = useRecoilValue(canvasState) + + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) + const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState) + const { option1, option2, dimensionDisplay } = settingModalFirstOptions + const { option3, option4 } = settingModalSecondOptions + + const globalLocaleState = useRecoilValue(globalLocaleStore) + const { get, post } = useAxios(globalLocaleState) + const { getMessage } = useMessage() + const { swalFire } = useSwal() + + const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState) + const setAdsorptionRange = useSetRecoilState(adsorptionRangeState) + + const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요 + + useEffect(() => { + console.log('useCanvasSetting useEffect 실행1') + fetchSettings() + }, [objectNo]) + + useEffect(() => { + console.log('useCanvasSetting useEffect 실행2') + //fetchSettings() + //onClickOption() + //fetchSettings() + }, [settingModalFirstOptions, settingModalSecondOptions]) + + const fetchSettings = async () => { + try { + const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) + const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] })) + const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] })) + const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item })) + const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) + const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ + ...item, + })) + // 데이터 설정 + setSettingModalFirstOptions({ + option1: optionData1, + option2: optionData2, + dimensionDisplay: optionData5, + }) + setSettingModalSecondOptions({ + option3: optionData3, + option4: optionData4, + }) + } catch (error) { + console.error('Data fetching error:', error) + } + } + + // 옵션 클릭 후 저장 + const onClickOption = async (item) => { + //치수 표시(단 건 선택) + if (item.column === 'corridorDimension' || item.column === 'realDimension' || item.column === 'noneDimension') { + console.log('치수 표시 ', item) + const options = settingModalFirstOptions?.dimensionDisplay.map((option) => { + option.selected = option.id === item.id + return option + }) + + //화면 표시(단 건 선택) + } else if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') { + console.log('화면 표시 ', item) + const options2 = settingModalFirstOptions?.option2.map((option2) => { + option2.selected = option2.id === item.id + return option2 + }) + + const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) + + polygons.forEach((polygon) => { + setSurfaceShapePattern(polygon, item.column) + }) + + //흡착범위 설정(단 건 선택) + } else if ( + item.column === 'adsorpRangeSmall' || + item.column === 'adsorpRangeSmallSemi' || + item.column === 'adsorpRangeMedium' || + item.column === 'adsorpRangeLarge' + ) { + console.log('화면 표시2 ', item, option4) + // option4에서 한 개만 선택 가능하도록 처리 + const updatedOption4 = option4.map((option) => + option.id === item.id + ? { ...option, selected: true } + : { + ...option, + selected: false, + }, + ) + + setSettingModalSecondOptions({ option3, option4: updatedOption4 }) + + //디스플레이 설정(다 건 선택) + } else { + console.log('디스플레이 설정 ', item) + item.selected = !item.selected + } + + setSettingModalFirstOptions({ option1, option2, dimensionDisplay }) + + try { + // 서버에 전송할 데이터 + const dataToSend = { + firstOption1: option1.map((item) => ({ + column: item.column, + selected: item.selected, + })), + firstOption2: option2.map((item) => ({ + column: item.column, + selected: item.selected, + })), + firstOption3: dimensionDisplay.map((item) => ({ + column: item.column, + selected: item.selected, + })), + // secondOption1: secondOptions[0].option1.map((item) => ({ + // name: item.id, + // name: item.name, + // // 필요한 경우 데이터 항목 추가 + // })), + secondOption2: option4.map((item) => ({ + column: item.column, + selected: item.selected, + })), + } + + const patternData = { + objectNo, + //디스플레이 설정(다중) + allocDisplay: dataToSend.firstOption1[0].selected, + outlineDisplay: dataToSend.firstOption1[1].selected, + gridDisplay: dataToSend.firstOption1[2].selected, + lineDisplay: dataToSend.firstOption1[3].selected, + wordDisplay: dataToSend.firstOption1[4].selected, + circuitNumDisplay: dataToSend.firstOption1[5].selected, + flowDisplay: dataToSend.firstOption1[6].selected, + trestleDisplay: dataToSend.firstOption1[7].selected, + totalDisplay: dataToSend.firstOption1[8].selected, + //차수 표시(단 건) + corridorDimension: dataToSend.firstOption3[0].selected, + realDimension: dataToSend.firstOption3[1].selected, + noneDimension: dataToSend.firstOption3[2].selected, + //화면 표시(단 건) + onlyBorder: dataToSend.firstOption2[0].selected, + lineHatch: dataToSend.firstOption2[1].selected, + allPainted: dataToSend.firstOption2[2].selected, + //흡착범위 설정(단 건) + adsorpRangeSmall: dataToSend.secondOption2[0].selected, + adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, + adsorpRangeMedium: dataToSend.secondOption2[2].selected, + adsorpRangeLarge: dataToSend.secondOption2[3].selected, + } + + console.log('patternData ', patternData) + + // HTTP POST 요청 보내기 + await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => { + swalFire({ text: getMessage(res.returnMessage) }) + + // Canvas 디스플레이 설정 시 해당 옵션 적용 + frontSettings() + }) + } catch (error) { + swalFire({ text: getMessage(res.returnMessage), icon: 'error' }) + } + + setAdsorptionRange(item.range) + } + + // Canvas 디스플레이 설정 시 해당 옵션 적용 + const frontSettings = async () => { + const option1 = settingModalFirstOptions.option1 + + // 'allocDisplay' 할당 표시 + // 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine' + // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid' + // 'lineDisplay' 지붕선 표시 'roof', 'roofBase' + // 'wordDisplay' 문자 표시 + // 'circuitNumDisplay' 회로번호 표시 + // 'flowDisplay' 흐름방향 표시 'arrow' + // 'trestleDisplay' 가대 표시 + // 'totalDisplay' 집계표 표시 + + let optionName //옵션명 + let optionSelected //옵션상태 + + for (let i = 0; i < option1.length; i++) { + switch (option1[i].column) { + case 'allocDisplay': //할당 표시 + optionName = ['1'] + break + case 'outlineDisplay': //외벽선 표시 + optionName = ['outerLine', 'wallLine'] + break + case 'gridDisplay': //그리드 표시 + optionName = ['lindGrid', 'dotGrid'] + break + case 'lineDisplay': //지붕선 표시 + optionName = ['roof', 'roofBase'] + break + case 'wordDisplay': //문자 표시 + optionName = ['6'] + break + case 'circuitNumDisplay': //회로번호 표시 + optionName = ['7'] + break + case 'flowDisplay': //흐름방향 표시 + optionName = ['arrow'] + break + case 'trestleDisplay': //가대 표시 + optionName = ['8'] + break + case 'totalDisplay': //집계표 표시 + optionName = ['9'] + break + } + // 표시 선택 상태(true/false) + optionSelected = option1[i].selected + + canvas + .getObjects() + .filter((obj) => optionName.includes(obj.name)) + //.filter((obj) => obj.name === optionName) + .forEach((obj) => { + obj.set({ visible: optionSelected }) + //obj.set({ visible: !obj.visible }) + }) + + // console.log( + // 'optionName', + // optionName, + // canvas.getObjects().filter((obj) => optionName.includes(obj.name)), + // ) + } + } + + return { + settingModalFirstOptions, + setSettingModalFirstOptions, + settingModalSecondOptions, + setSettingModalSecondOptions, + fetchSettings, + onClickOption, + frontSettings, + adsorptionPointMode, + setAdsorptionPointMode, + } +} diff --git a/src/hooks/option/useCanvasSettingController.js b/src/hooks/option/useCanvasSettingController.js index 72a590eb..48db6c08 100644 --- a/src/hooks/option/useCanvasSettingController.js +++ b/src/hooks/option/useCanvasSettingController.js @@ -46,6 +46,7 @@ export const useCanvasSettingController = () => { } } + // const onClickOption = async (option) => { option.selected = !option.selected From b362ba8b6371a5eb113d07b5f18c2912d330a1a4 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 29 Oct 2024 10:13:16 +0900 Subject: [PATCH 134/139] =?UTF-8?q?line=20to=20polygon=EC=8B=9C=20?= =?UTF-8?q?=EA=B8=B8=EC=9D=B4=20=EC=95=88=EB=A7=9E=EB=8A=94=20=ED=98=84?= =?UTF-8?q?=EC=83=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QLine.js | 4 +--- src/components/fabric/QPolygon.js | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 4ee9535a..86a96845 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -21,9 +21,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { } this.line = this // 소수점 전부 제거 - points.forEach((point) => { - point = Math.round(point) - }) + points = points.map((point) => Math.round(point)) this.idx = options.idx ?? 0 this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 8068a772..decc99ae 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -24,8 +24,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { - point.x = Math.round(point.x) - point.y = Math.round(point.y) + point.x = Number(point.x.toFixed(1)) + point.y = Number(point.y.toFixed(1)) }) options.selectable = options.selectable ?? true options.sort = options.sort ?? true From eb636881da1277c885a4adb6d6b3e0c975649cc4 Mon Sep 17 00:00:00 2001 From: basssy Date: Tue, 29 Oct 2024 10:14:48 +0900 Subject: [PATCH 135/139] =?UTF-8?q?=EB=AC=BC=EA=B1=B4=ED=98=84=ED=99=A9=20?= =?UTF-8?q?=EB=AA=A9=EB=A1=9D,=20=EC=83=81=EC=84=B8=201=EC=B0=A8=EC=A0=90,?= =?UTF-8?q?2=EC=B0=A8=EC=A0=90=20=EC=A6=90=EA=B2=A8=EC=B0=BE=EA=B8=B0=20&?= =?UTF-8?q?=20=EB=AA=A9=EB=A1=9D=20=EA=B7=B8=EB=A6=AC=EB=93=9C=20=ED=97=A4?= =?UTF-8?q?=EB=8D=94=20=EC=A0=95=EB=A0=AC=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/management/Stuff.jsx | 4 +- src/components/management/StuffDetail.jsx | 277 ++++++++++++------ src/components/management/StuffQGrid.jsx | 2 +- .../management/StuffSearchCondition.jsx | 37 ++- 4 files changed, 219 insertions(+), 101 deletions(-) diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 138a3b85..dfd4f94b 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -43,9 +43,9 @@ export default function Stuff() { const copyNo = async (value) => { try { await navigator.clipboard.writeText(value) - alert('물건번호가 복사되었습니다.') + alert(getMessage('stuff.detail.header.message2')) } catch (error) { - alert('물건번호 복사에 실패했습니다.') + alert(getMessage('stuff.detail.header.message3')) } } diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 9960fb1f..ed47ee99 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -88,6 +88,9 @@ export default function StuffDetail() { const [prefCodeList, setPrefCodeList] = useState([]) //도도부현 코트 리스트 const [prefValue, setPrefValue] = useState('') const [saleStoreList, setSaleStoreList] = useState([]) // 판매점 리스트 + const [favoriteStoreList, setFavoriteStoreList] = useState([]) //즐겨찾기한 판매점목록 + const [showSaleStoreList, setShowSaleStoreList] = useState([]) //보여줄 판매점목록 + const [otherSaleStoreList, setOtherSaleStoreList] = useState([]) const [originOtherSaleStoreList, setOriginOtherSaleStoreList] = useState([]) @@ -318,21 +321,37 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 - get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + let url + if (sessionState?.storeId === 'T01') { + // url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` + url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` + } else { + url = `/api/object/saleStore/${sessionState?.storeId}/list` + } + + get({ url: url }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') + let favList + if (sessionState?.storeId === 'T01') { + firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) + favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B') + setSaleStoreList(firstList) + setFavoriteStoreList(favList) + setShowSaleStoreList(favList) + } else { + //1차점 셀렉트박스 + setSaleStoreList(firstList) + } const otherList = res.filter((row) => row.saleStoreLevel !== '1') - - //1차점 셀렉트박스 - setSaleStoreList(firstList) - let filterOtherList if (sessionState?.storeId === 'T01') { filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01') + setOriginOtherSaleStoreList(filterOtherList) setOtherSaleStoreList(filterOtherList) } else { - //1차점 아닌 판매점 셀렉트박스 + //T01 아니고 2차점 판매점 셀렉트박스 setOriginOtherSaleStoreList(otherList) setOtherSaleStoreList(otherList) } @@ -380,13 +399,29 @@ export default function StuffDetail() { //1차점 : X167 T01 //2차점 : 10X22, 201X112 - get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + let url + if (sessionState?.storeId === 'T01') { + // url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` + url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` + } else { + url = `/api/object/saleStore/${sessionState?.storeId}/list` + } + get({ url: url }).then((res) => { if (!isEmptyArray(res)) { const firstList = res.filter((row) => row.saleStoreLevel === '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1') + let favList - //1차점 셀렉트박스 - setSaleStoreList(firstList) + if (sessionState?.storeId === 'T01') { + firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) + favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B') + setSaleStoreList(firstList) + setFavoriteStoreList(favList) + setShowSaleStoreList(favList) + } else { + //1차점 셀렉트박스 + setSaleStoreList(firstList) + } let filterOtherList if (sessionState?.storeId === 'T01') { @@ -495,6 +530,16 @@ export default function StuffDetail() { const onRadioChange = (key) => { setSelectObjectStatusId(key.target.value) } + + //1차점 자동완성 input + const onInputChange = (key) => { + if (key !== '') { + setShowSaleStoreList(saleStoreList) + } else { + setShowSaleStoreList(favoriteStoreList) + } + } + //1차점 변경 이벤트 const onSelectionChange = (key) => { if (isObjectNotEmpty(key)) { @@ -516,7 +561,7 @@ export default function StuffDetail() { } } else { // EDIT - if (planReqNo !== null) { + if (planReqNo !== null && planReqNo !== '') { if (confirm(getMessage('stuff.detail.confirm.message1'))) { delFlg = true } else { @@ -629,7 +674,7 @@ export default function StuffDetail() { } } else { //EDIT - if (planReqNo !== null) { + if (planReqNo !== null && planReqNo !== '') { if (confirm(getMessage('stuff.detail.confirm.message1'))) { delFlg = true } else { @@ -849,7 +894,6 @@ export default function StuffDetail() { errors.installHeight = true } - // console.log('상세에러필드:::::', errors) setIsFormValid(Object.keys(errors).length === 0 ? true : false) } }, [ @@ -906,20 +950,17 @@ export default function StuffDetail() { // 저장 const onValid = async () => { const formData = form.getValues() - let errors = {} let fieldNm //담당자 if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { fieldNm = getMessage('stuff.detail.receiveUser') errors = fieldNm - inputReceiveUserEl.current.focus() } //물건명 if (!formData.objectName || formData.objectName.trim().length === 0) { fieldNm = getMessage('stuff.detail.objectStatusId') errors = fieldNm - inputObjectNameEl.current.focus() } //경칭 if (!formData.objectNameOmit) { @@ -935,13 +976,11 @@ export default function StuffDetail() { if (!formData.zipNo) { fieldNm = getMessage('stuff.detail.zipNo') errors = fieldNm - inputZipNoEl.current.focus() } //주소 if (!formData.address) { fieldNm = getMessage('stuff.detail.address') errors = fieldNm - inputAddressEl.current.focus() } //도도부현 if (!formData.prefId || formData.prefId === '0') { @@ -962,7 +1001,6 @@ export default function StuffDetail() { if (!formData.verticalSnowCover) { fieldNm = getMessage('stuff.detail.verticalSnowCover') errors = fieldNm - inputVerticalSnowCoverEl.current.focus() } //면조도구분 @@ -974,7 +1012,6 @@ export default function StuffDetail() { if (!formData.installHeight) { fieldNm = getMessage('stuff.detail.installHeight') errors = fieldNm - inputInstallHeightEl.current.focus() } if (Object.keys(errors).length > 0) { @@ -1306,33 +1343,68 @@ export default function StuffDetail() {
      -
      - -
      + {(sessionState?.storeId === 'T01' && ( + <> +
      + +
      +
      + +
      + + )) || ( + <> +
      + +
      +
      + +
      + + )}
      @@ -1651,13 +1723,7 @@ export default function StuffDetail() {
      - +
      @@ -1686,7 +1752,7 @@ export default function StuffDetail() { })} {/* 상세라디오끝 */}
      - +
      x.saleStoreName} - getOptionValue={(x) => x.saleStoreId} - isClearable={sessionState?.storeLvl === '1' ? true : false} - isDisabled={sessionState?.storeLvl !== '1' ? true : false} - value={saleStoreList.filter(function (option) { - return option.saleStoreId === selOptions - })} - /> -
      -
      - -
      + {(sessionState?.storeId === 'T01' && ( + <> +
      + +
      + + )) || ( + <> +
      + +
      + + )}
      @@ -1811,7 +1912,7 @@ export default function StuffDetail() {
      - +
      - +
      @@ -1935,7 +2030,6 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('verticalSnowCover') || ''} {...register('verticalSnowCover')} - ref={inputVerticalSnowCoverEl} />
      cm @@ -1987,7 +2081,6 @@ export default function StuffDetail() { onKeyUp={handleKeyUp} value={form.watch('installHeight') || ''} {...register('installHeight')} - ref={inputInstallHeightEl} />
      m @@ -2017,7 +2110,7 @@ export default function StuffDetail() { {getMessage('stuff.detail.remarks')}
      - +
      diff --git a/src/components/management/StuffQGrid.jsx b/src/components/management/StuffQGrid.jsx index 7a5f4eb7..32c686fb 100644 --- a/src/components/management/StuffQGrid.jsx +++ b/src/components/management/StuffQGrid.jsx @@ -39,7 +39,7 @@ export default function StuffQGrid(props) { return { filter: false, flex: 1, - sortable: false, + sortable: true, suppressMovable: true, resizable: true, suppressSizeToFit: false, diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index 1822140e..3e5b07f6 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -4,7 +4,6 @@ import React, { useEffect, useRef, useState } from 'react' import { useAxios } from '@/hooks/useAxios' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -// import Select from 'react-dropdown-select' import Select from 'react-select' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' @@ -57,7 +56,9 @@ export default function StuffSearchCondition() { const [receiveUser, setReceiveUser] = useState('') //담당자 const [dateType, setDateType] = useState('U') //갱신일(U)/등록일(R) - const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT + const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) //판매대리점 자동완성 SELECT 전체 + const [favoriteStoreList, setFavoriteStoreList] = useState([]) //즐겨찾기한 판매점목록 + const [showSaleStoreList, setShowSaleStoreList] = useState([]) //보여줄 판매점목록 // 조회 const onSubmit = () => { let diff = dayjs(endDate).diff(startDate, 'day') @@ -128,13 +129,24 @@ export default function StuffSearchCondition() { useEffect(() => { if (isObjectNotEmpty(sessionState)) { // storeId가 T01 이거나 1차점일때만 판매대리점 선택 활성화 - get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { + let url + if (sessionState?.storeId === 'T01') { + // url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` + url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` + } else { + url = `/api/object/saleStore/${sessionState?.storeId}/list` + } + get({ url: url }).then((res) => { if (!isEmptyArray(res)) { res.map((row) => { row.value = row.saleStoreId row.label = row.saleStoreName }) - setSchSelSaleStoreList(res) + const allList = res + const favList = res.filter((row) => row.priority !== 'B') + setSchSelSaleStoreList(allList) + setFavoriteStoreList(favList) + setShowSaleStoreList(favList) } }) } @@ -147,6 +159,15 @@ export default function StuffSearchCondition() { } } + //자동완성 인풋 + const onInputChange = (key) => { + if (key !== '') { + setShowSaleStoreList(schSelSaleStoreList) + } else { + setShowSaleStoreList(favoriteStoreList) + } + } + //판매대리점 자동완성 변경 const onSelectionChange = (key) => { if (isObjectNotEmpty(key)) { @@ -300,11 +321,15 @@ export default function StuffSearchCondition() { classNamePrefix="custom" placeholder="Select" ref={ref} - options={schSelSaleStoreList} + // options={schSelSaleStoreList} + options={showSaleStoreList} + onInputChange={onInputChange} onChange={onSelectionChange} getOptionLabel={(x) => x.saleStoreName} getOptionValue={(x) => x.saleStoreId} - value={schSelSaleStoreList.filter(function (option) { + // value={schSelSaleStoreList.filter(function (option) { + value={showSaleStoreList.filter(function (option) { + // console.log('자동완성 value::::', option) if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') { return false } else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') { From a7da20e8ad919d8725f2d719b8f996b00af65e36 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 29 Oct 2024 10:50:31 +0900 Subject: [PATCH 136/139] =?UTF-8?q?fix:=20=EA=B2=AC=EC=A0=81=EC=84=9C=20?= =?UTF-8?q?=ED=8E=98=EC=9D=B4=EC=A7=80=20=EB=9D=BC=EC=9D=B4=ED=84=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/floor-plan/{ => estimate}/[mid]/[pid]/page.jsx | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/app/floor-plan/{ => estimate}/[mid]/[pid]/page.jsx (100%) diff --git a/src/app/floor-plan/[mid]/[pid]/page.jsx b/src/app/floor-plan/estimate/[mid]/[pid]/page.jsx similarity index 100% rename from src/app/floor-plan/[mid]/[pid]/page.jsx rename to src/app/floor-plan/estimate/[mid]/[pid]/page.jsx From 5daf9891800be586c370c9392653d0fa35667da5 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 29 Oct 2024 12:56:38 +0900 Subject: [PATCH 137/139] =?UTF-8?q?=EA=B0=81=EB=8F=84=20=EA=B3=84=EC=82=B0?= =?UTF-8?q?=20=EC=88=98=EC=A0=95,=20=EC=A7=80=EB=B6=95=EB=A9=B4=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=EC=8B=9C=20=EC=99=B8=EB=B2=BD=EC=84=A0=20?= =?UTF-8?q?=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useEavesGableEdit.js | 5 ++++- src/hooks/roofcover/useRoofAllocationSetting.js | 6 ++++++ src/util/canvas-util.js | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index b0085019..7696dc7a 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -170,7 +170,10 @@ export function useEavesGableEdit(id) { }) const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') - + const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText') + removeTargets.forEach((obj) => { + canvas.remove(obj) + }) wallLines.forEach((wallLine) => { addPitchTextsByOuterLines() const roof = drawRoofPolygon(wallLine) diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 3f355111..3be745d6 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -130,6 +130,12 @@ export function useRoofAllocationSetting(id) { setSurfaceShapePattern(roof, roofDisplay.column) drawDirectionArrow(roof) }) + + const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine') + removeTargets.forEach((obj) => { + canvas.remove(obj) + }) + closePopup(id) } diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 9f8b9469..73464722 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -268,7 +268,7 @@ export const getDegreeByChon = (chon) => { export const getChonByDegree = (degree) => { // tan(theta) = height / base const radians = (degree * Math.PI) / 180 - return Number(Number(Math.tan(radians) * 10).toFixed(1)) + return Number(Number(Math.tan(radians) * 10).toFixed(2)) } /** From 0c1697596503dd57466a648f448b0d637d899a2b Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 29 Oct 2024 14:26:25 +0900 Subject: [PATCH 138/139] =?UTF-8?q?=EA=B0=81=EB=8F=84/=EA=B2=BD=EC=82=AC?= =?UTF-8?q?=20=EB=8B=A8=EC=9C=84=20=ED=91=9C=EC=8B=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/dimensionLine/DimensionLineSetting.jsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx index 57fe3364..d24d8d43 100644 --- a/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/dimensionLine/DimensionLineSetting.jsx @@ -1,15 +1,17 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { contextPopupPositionState } from '@/store/popupAtom' import QSelectBox from '@/components/common/select/QSelectBox' +import { pitchTextSelector } from '@/store/canvasAtom' export default function DimensionLineSetting(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, setIsShow, pos = contextPopupPosition } = props const { getMessage } = useMessage() const { closePopup } = usePopup() + const pitchText = useRecoilState(pitchTextSelector) const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] return ( @@ -52,14 +54,14 @@ export default function DimensionLineSetting(props) {
      - 寸法 + {pitchText}
      傾斜
      - 寸法 + {pitchText}
      傾き設定されている場合、入力した数値に傾き計算をした数値が表示されます。
      From 4a4d532bbeeb5e0ce7913d1b8238e0455f24197b Mon Sep 17 00:00:00 2001 From: minsik Date: Tue, 29 Oct 2024 14:27:21 +0900 Subject: [PATCH 139/139] =?UTF-8?q?-=20=EB=B0=B0=EC=B9=98=EB=A9=B4=20?= =?UTF-8?q?=EC=B4=88=EA=B8=B0=20=EC=84=A4=EC=A0=95:=20=EC=B9=98=EC=88=98?= =?UTF-8?q?=EC=9E=85=EB=A0=A5=20=EB=B0=A9=EB=B2=95=20=EC=84=A4=EC=A0=95?= =?UTF-8?q?=EC=97=90=20=EB=A7=9E=EC=B6=B0=20=EB=9D=BC=EC=9A=B0=ED=8C=85=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/CanvasMenu.jsx | 70 +++++----- src/components/floor-plan/MenuDepth01.jsx | 148 +++------------------- src/hooks/common/useMenu.js | 95 ++++++++++++++ src/store/menuAtom.js | 68 ++++++++++ 4 files changed, 216 insertions(+), 165 deletions(-) create mode 100644 src/hooks/common/useMenu.js diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index b2ff69f6..ebcac837 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -12,53 +12,51 @@ import { useMessage } from '@/hooks/useMessage' import { usePlan } from '@/hooks/usePlan' import { useSwal } from '@/hooks/useSwal' import { useEvent } from '@/hooks/useEvent' -import { canvasState, canvasZoomState, currentCanvasPlanState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' +import { + canvasSettingState, + canvasState, + canvasZoomState, + currentCanvasPlanState, + currentMenuState, + verticalHorizontalModeState, +} from '@/store/canvasAtom' import { sessionStore } from '@/store/commonAtom' import { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { settingModalFirstOptionsState, wordDisplaySelector } from '@/store/settingAtom' -import { MENU } from '@/common/common' +import { settingModalFirstOptionsState } from '@/store/settingAtom' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import { useCanvasEvent } from '@/hooks/useCanvasEvent' -import { popupState } from '@/store/popupAtom' import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01' import { usePopup } from '@/hooks/usePopup' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { useCommonUtils } from '@/hooks/common/useCommonUtils' - -const canvasMenus = [ - { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, - { index: 1, name: 'plan.menu.placement.surface.initial.setting', icon: 'con01', title: MENU.INITIAL_CANVAS_SETTING }, - { index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT }, - { index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT }, - { index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT }, - { index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT }, - { index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT }, -] +import { menusState, menuTypeState } from '@/store/menuAtom' +import useMenu from '@/hooks/common/useMenu' +import { MENU } from '@/common/common' export default function CanvasMenu(props) { const { menuNumber, setMenuNumber } = props const pathname = usePathname() const router = useRouter() - - const { addPopup, closePopup } = usePopup() - const [type, setType] = useState('') - + const { addPopup } = usePopup() + const canvasMenus = useRecoilValue(menusState) + const [type, setType] = useRecoilState(menuTypeState) const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState) const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) const setCurrentMenu = useSetRecoilState(currentMenuState) const setOuterLinePoints = useSetRecoilState(outerLinePointsState) const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState) + const canvasSetting = useRecoilValue(canvasSettingState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) - const { handleZoomClear } = useCanvasEvent() - + const sessionState = useRecoilValue(sessionStore) const globalLocale = useRecoilValue(globalLocaleStore) const canvas = useRecoilValue(canvasState) - const sessionState = useRecoilValue(sessionStore) + const { handleZoomClear } = useCanvasEvent() + const { handleMenu } = useMenu() const { getMessage } = useMessage() const { saveCanvas } = usePlan() @@ -70,14 +68,11 @@ export default function CanvasMenu(props) { dimension: false, distance: false, }) - const { commonFunctions } = useCommonUtils({ commonFunctionState, setCommonFunctionState, }) - const [popup, setPopup] = useRecoilState(popupState) - const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }] const onClickNav = (menu) => { @@ -102,9 +97,6 @@ export default function CanvasMenu(props) { if (pathname !== '/floor-plan') router.push('/floor-plan') } - const menuProps = { - type, - } const settingsModalOptions = useRecoilState(settingModalFirstOptionsState) @@ -135,7 +127,6 @@ export default function CanvasMenu(props) { } const onClickPlacementInitialMenu = () => { addPopup(placementInitialId, 1, ) - // setShowPlaceShapeModal(true) } const handleClear = () => { @@ -162,7 +153,19 @@ export default function CanvasMenu(props) { } else { setAppMessageState(JA) } - }, [menuNumber, type, globalLocale]) + }, [type, globalLocale]) + + useEffect(() => { + if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString())) { + setMenuNumber(3) + setType('surface') + setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING) + } else { + setMenuNumber(2) + setType('outline') + setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) + } + }, [canvasSetting]) return (
      @@ -173,9 +176,12 @@ export default function CanvasMenu(props) {
    • onClickNav(menu)} + onClick={() => { + if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2) return + onClickNav(menu) + }} > - @@ -263,7 +269,7 @@ export default function CanvasMenu(props) {
    • - {(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && } + {(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && }
      ) diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index 113a1f0e..63e5e67a 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -1,150 +1,32 @@ 'use client' import { useMessage } from '@/hooks/useMessage' -import { useEffect, useState } from 'react' -import { MENU } from '@/common/common' import { currentMenuState } from '@/store/canvasAtom' -import { useSetRecoilState } from 'recoil' -import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' -import { usePopup } from '@/hooks/usePopup' -import { v4 as uuidv4 } from 'uuid' -import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' -import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' -import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting' -import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing' -import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit' -import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting' -import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting' -import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' -import Slope from '@/components/floor-plan/modal/Slope' -import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting' -import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' -import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting' -import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' -import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' +import { useRecoilState, useRecoilValue } from 'recoil' +import { menuTypeState, subMenusState } from '@/store/menuAtom' +import useMenu from '@/hooks/common/useMenu' +import { useEffect } from 'react' -export default function MenuDepth01(props) { - const { type } = props +export default function MenuDepth01() { + const type = useRecoilValue(menuTypeState) const { getMessage } = useMessage() - const [activeMenu, setActiveMenu] = useState() - const setCurrentMenu = useSetRecoilState(currentMenuState) - const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch() - const { addPopup } = usePopup() - const [outlineId, setOutlineId] = useState(uuidv4()) - const onClickMenu = ({ id, menu, name }) => { - setActiveMenu(menu) + const { handleMenu } = useMenu() + const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) + const subMenus = useRecoilValue(subMenusState) + + const onClickMenu = ({ id, menu }) => { setCurrentMenu(menu) - if (type === 'outline') { - switch (id) { - case 0: - addPopup(outlineId, 1, ) - break - case 1: - addPopup(outlineId, 1, ) - break - case 2: - addPopup(outlineId, 1, ) - break - case 3: - addPopup(outlineId, 1, ) - break - case 4: - addPopup(outlineId, 1, ) - break - case 5: - addPopup(outlineId, 1, ) - break - case 6: - addPopup(outlineId, 1, ) - break - case 7: - addPopup(outlineId, 1, ) - break - } - } - - if (type === 'surface') { - switch (id) { - case 0: - addPopup(outlineId, 1, ) - break - case 1: - addPopup(outlineId, 1, ) - break - case 2: - addPopup(outlineId, 1, ) - break - case 3: - addPopup(outlineId, 1, ) - break - case 4: - deleteAllSurfacesAndObjects() - break - } - } - - if (type === 'module') { - switch (id) { - case 0: - addPopup(outlineId, 1, ) - break - case 1: - addPopup(outlineId, 1, ) - break - } - } } useEffect(() => { - setActiveMenu(null) - }, [type]) - - const menuInfo = { - outline: [ - // 지붕덮개 - { id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE }, - { id: 1, name: 'plan.menu.roof.cover.roof.shape.setting', menu: MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS }, - { - id: 2, - name: 'plan.menu.roof.cover.roof.shape.passivity.setting', - menu: MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS, - }, - { id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing', menu: MENU.ROOF_COVERING.HELP_LINE_DRAWING }, - { id: 4, name: 'plan.menu.roof.cover.eaves.kerava.edit', menu: MENU.ROOF_COVERING.EAVES_KERAVA_EDIT }, - { id: 5, name: 'plan.menu.roof.cover.movement.shape.updown', menu: MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN }, - { id: 6, name: 'plan.menu.roof.cover.outline.edit.offset', menu: MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET }, - { id: 7, name: 'plan.menu.roof.cover.roof.surface.alloc', menu: MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC }, - ], - surface: [ - // 배치면 - { id: 0, name: 'plan.menu.placement.surface.slope.setting', menu: MENU.BATCH_CANVAS.SLOPE_SETTING }, - { id: 1, name: 'plan.menu.placement.surface.drawing', menu: MENU.BATCH_CANVAS.BATCH_DRAWING }, - { id: 2, name: 'plan.menu.placement.surface.arrangement', menu: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH }, - { id: 3, name: 'plan.menu.placement.surface.object', menu: MENU.BATCH_CANVAS.OBJECT_BATCH }, - { id: 4, name: 'plan.menu.placement.surface.all.remove', menu: MENU.BATCH_CANVAS.ALL_REMOVE }, - ], - module: [ - // 모듈, 회로 구성 - - { id: 0, name: 'plan.menu.module.circuit.setting.default', menu: MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING }, - { - id: 1, - name: 'plan.menu.module.circuit.setting.circuit.trestle.setting', - menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING, - }, - { - id: 2, - name: 'plan.menu.module.circuit.setting.plan.orientation', - menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION, - }, - ], - } + handleMenu(type) + }, [currentMenu]) return (
        - {menuInfo[type].map((menu) => { + {subMenus[type]?.map((menu) => { return ( -
      • +
      • ) diff --git a/src/hooks/common/useMenu.js b/src/hooks/common/useMenu.js new file mode 100644 index 00000000..75905a73 --- /dev/null +++ b/src/hooks/common/useMenu.js @@ -0,0 +1,95 @@ +import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting' +import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting' +import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting' +import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing' +import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit' +import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting' +import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting' +import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting' +import Slope from '@/components/floor-plan/modal/Slope' +import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing' +import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting' +import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting' +import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting' +import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting' +import { usePopup } from '@/hooks/usePopup' +import { useState } from 'react' +import { v4 as uuidv4 } from 'uuid' +import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch' +import { useRecoilValue } from 'recoil' +import { currentMenuState } from '@/store/canvasAtom' +import { MENU } from '@/common/common' + +export default function useMenu() { + const menus = [] + const currentMenu = useRecoilValue(currentMenuState) + const [popupId, setPopupId] = useState(uuidv4()) + const { addPopup } = usePopup() + const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch() + const handleMenu = (type) => { + if (type === 'outline') { + switch (currentMenu) { + case MENU.ROOF_COVERING.EXTERIOR_WALL_LINE: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.HELP_LINE_DRAWING: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.EAVES_KERAVA_EDIT: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET: + addPopup(popupId, 1, ) + break + case MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC: + addPopup(popupId, 1, ) + break + } + } + + if (type === 'surface') { + switch (currentMenu) { + case MENU.BATCH_CANVAS.SLOPE_SETTING: + addPopup(popupId, 1, ) + break + case MENU.BATCH_CANVAS.BATCH_DRAWING: + addPopup(popupId, 1, ) + break + case MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH: + addPopup(popupId, 1, ) + break + case MENU.BATCH_CANVAS.OBJECT_BATCH: + addPopup(popupId, 1, ) + break + case MENU.BATCH_CANVAS.ALL_REMOVE: + deleteAllSurfacesAndObjects() + break + } + } + + if (type === 'module') { + switch (currentMenu) { + case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING: + addPopup(popupId, 1, ) + break + case MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING: + addPopup(popupId, 1, ) + break + } + } + } + + return { + menus, + handleMenu, + } +} diff --git a/src/store/menuAtom.js b/src/store/menuAtom.js index b86ecbd0..834498f0 100644 --- a/src/store/menuAtom.js +++ b/src/store/menuAtom.js @@ -1,6 +1,74 @@ import { atom } from 'recoil' +import { MENU } from '@/common/common' export const menuNumberState = atom({ key: 'menuNumberState', default: null, }) + +export const menuTypeState = atom({ + key: 'menuTypeState', + default: null, +}) + +export const menusState = atom({ + key: 'menusState', + default: [ + { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, + { + index: 1, + name: 'plan.menu.placement.surface.initial.setting', + icon: 'con01', + title: MENU.INITIAL_CANVAS_SETTING, + }, + { index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT }, + { index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT }, + { index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT }, + { index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT }, + { index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT }, + ], +}) + +export const subMenusState = atom({ + key: 'subMenusState', + default: { + outline: [ + // 지붕덮개 + { id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE }, + { id: 1, name: 'plan.menu.roof.cover.roof.shape.setting', menu: MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS }, + { + id: 2, + name: 'plan.menu.roof.cover.roof.shape.passivity.setting', + menu: MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS, + }, + { id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing', menu: MENU.ROOF_COVERING.HELP_LINE_DRAWING }, + { id: 4, name: 'plan.menu.roof.cover.eaves.kerava.edit', menu: MENU.ROOF_COVERING.EAVES_KERAVA_EDIT }, + { id: 5, name: 'plan.menu.roof.cover.movement.shape.updown', menu: MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN }, + { id: 6, name: 'plan.menu.roof.cover.outline.edit.offset', menu: MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET }, + { id: 7, name: 'plan.menu.roof.cover.roof.surface.alloc', menu: MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC }, + ], + surface: [ + // 배치면 + { id: 0, name: 'plan.menu.placement.surface.slope.setting', menu: MENU.BATCH_CANVAS.SLOPE_SETTING }, + { id: 1, name: 'plan.menu.placement.surface.drawing', menu: MENU.BATCH_CANVAS.BATCH_DRAWING }, + { id: 2, name: 'plan.menu.placement.surface.arrangement', menu: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH }, + { id: 3, name: 'plan.menu.placement.surface.object', menu: MENU.BATCH_CANVAS.OBJECT_BATCH }, + { id: 4, name: 'plan.menu.placement.surface.all.remove', menu: MENU.BATCH_CANVAS.ALL_REMOVE }, + ], + module: [ + // 모듈, 회로 구성 + + { id: 0, name: 'plan.menu.module.circuit.setting.default', menu: MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING }, + { + id: 1, + name: 'plan.menu.module.circuit.setting.circuit.trestle.setting', + menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING, + }, + { + id: 2, + name: 'plan.menu.module.circuit.setting.plan.orientation', + menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION, + }, + ], + }, +})