Merge branch 'dev' into dev-yj
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M27 0.804011L52.9645 33.5H1.03554L27 0.804011Z" stroke="white"/>
|
||||
<svg width="20" height="12" viewBox="0 0 20 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 1.56205L17.865 11H2.13504L10 1.56205Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 177 B After Width: | Height: | Size: 189 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="44" viewBox="0 0 54 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M43.6009 0.5L53.3736 43.5H0.5V13.537H21.9375H22.4375V13.037V0.5H43.6009Z" stroke="white"/>
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M15.4907 1L18.7587 16H1V5.63636H8.14815H9.14815V4.63636V1H15.4907Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 214 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="44" viewBox="0 0 54 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.3991 43.5H53.5V25.537H29.0625H28.5625V25.037V0.5H0.626389L10.3991 43.5Z" stroke="white"/>
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.5093 16H19V10H10H8.958L9.00085 8.95888L9.32837 1H1.24132L4.5093 16Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 218 B |
@ -1,3 +1,3 @@
|
||||
<svg width="57" height="41" viewBox="0 0 57 41" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.384 8.3129L30.5329 8.53093H30.7969H39.3543L56.172 40.5H0.896303L25.3336 0.917553L30.384 8.3129Z" stroke="white"/>
|
||||
<svg width="22" height="16" viewBox="0 0 22 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10.8546 3.62169L11.1523 4.0594H11.6816H14.4443L20.3269 15H1.76631L9.65389 1.8558L10.8546 3.62169Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 230 B After Width: | Height: | Size: 246 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="41" viewBox="0 0 54 41" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M28.7562 8.30253L28.9042 8.53127L29.1766 8.53093L53.5 8.50062V40.5H0.871685L24.0017 0.953657L28.7562 8.30253Z" stroke="white"/>
|
||||
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.083 3.75037L11.379 4.06002L11.8074 4.0594L19 4.04906V15H1.69884L9.09691 1.67251L11.083 3.75037Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 240 B After Width: | Height: | Size: 247 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M17.2929 33.5H0.5V0.5H53.5V33.5H36.7071L27.3536 24.1464L27 23.7929L26.6464 24.1464L17.2929 33.5Z" stroke="white"/>
|
||||
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.05791 12H1V1H19V12H13.9421L10.7183 8.67188L10 7.93037L9.28173 8.67188L6.05791 12Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 227 B After Width: | Height: | Size: 232 B |
@ -1,3 +1,3 @@
|
||||
<svg width="40" height="50" viewBox="0 0 40 50" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 0.64603L39.5 16.6006V49.5H0.5V16.6006L20 0.64603Z" stroke="white"/>
|
||||
<svg width="15" height="19" viewBox="0 0 15 19" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7.5 1.299L14 6.68809V18H1V6.68809L7.5 1.299Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 193 B |
@ -1,5 +1,3 @@
|
||||
<svg width="54" height="42" viewBox="0 0 54 42" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.971595 41.5L10.2573 28.5H44.727L53.0842 41.5H0.971595Z" fill="#313131" stroke="white"/>
|
||||
<path d="M10.5 0.5H44.5V28.5H10.5V0.5Z" fill="#313131" stroke="white"/>
|
||||
<rect x="11" y="28" width="33" height="1" fill="#313131"/>
|
||||
<svg width="20" height="16" viewBox="0 0 20 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.96963 10.3554L4.07692 10.1429V9.90476V1H15.9231V9.90476V10.1429L16.0304 10.3554L18.375 15H1.625L3.96963 10.3554Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 334 B After Width: | Height: | Size: 263 B |
@ -1,3 +1,3 @@
|
||||
<svg width="58" height="39" viewBox="0 0 58 39" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M57.4251 17.0318L46.691 38.5H0.865706L22.7888 0.5H46.728L57.4251 17.0318Z" stroke="white"/>
|
||||
<svg width="22" height="15" viewBox="0 0 22 15" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.8541 6.14406L17.5432 14H1.70065L8.93284 1H16.9517L20.8541 6.14406Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 204 B After Width: | Height: | Size: 218 B |
@ -1,3 +1,3 @@
|
||||
<svg width="58" height="47" viewBox="0 0 58 47" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M57.339 20.1115L40.724 46.5H0.962002L33.1033 0.72297L57.339 20.1115Z" stroke="white"/>
|
||||
<svg width="22" height="18" viewBox="0 0 22 18" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20.6552 7.73365L14.6298 17H1.88045L12.3752 1.43676L20.6552 7.73365Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 216 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="0.5" y="0.5" width="53" height="33" fill="#313131" stroke="white"/>
|
||||
<svg width="20" height="12" viewBox="0 0 20 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="1" y="1" width="18" height="10" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 180 B After Width: | Height: | Size: 178 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.654784 33.5L9.66306 0.5H44.3369L53.3452 33.5H0.654784Z" stroke="white"/>
|
||||
<svg width="20" height="12" viewBox="0 0 20 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.98369 1.72462C4.10657 1.29565 4.4988 1 4.94502 1H15.055C15.5012 1 15.8934 1.29565 16.0163 1.72462L18.308 9.72462C18.491 10.3636 18.0113 11 17.3466 11H2.65336C1.98869 11 1.50899 10.3636 1.69202 9.72462L3.98369 1.72462Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 188 B After Width: | Height: | Size: 368 B |
@ -1,3 +1,3 @@
|
||||
<svg width="44" height="44" viewBox="0 0 44 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M43.5 43.5H1.20711L43.5 1.20711V43.5Z" stroke="white"/>
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M2.12132 11.2929L11.2929 2.12132C11.9229 1.49136 13 1.93752 13 2.82843V12C13 12.5523 12.5523 13 12 13H2.82843C1.93752 13 1.49136 11.9229 2.12132 11.2929Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 168 B After Width: | Height: | Size: 301 B |
@ -1,3 +1,3 @@
|
||||
<svg width="34" height="44" viewBox="0 0 34 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M33.5 1.04958V43.5H0.5V27.8255L33.5 1.04958Z" stroke="white"/>
|
||||
<svg width="13" height="17" viewBox="0 0 13 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2.11305V16H1V11.132L12 2.11305Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 175 B After Width: | Height: | Size: 183 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M0.6187 33.5L7.70137 0.5H53.3813L46.2986 33.5H0.6187Z" stroke="white"/>
|
||||
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M1.22928 12L3.51619 1H18.7707L16.4838 12H1.22928Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 184 B After Width: | Height: | Size: 197 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="34" viewBox="0 0 54 34" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M10 23.5H9.5V24V33.5H0.5V0.5H53.5V33.5H44.5V24V23.5H44H10Z" stroke="white"/>
|
||||
<svg width="20" height="13" viewBox="0 0 20 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.18518 8.17647H5.18518V9.17647V12H1V1H19V12H14.8148V9.17647V8.17647H13.8148H6.18518Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 189 B After Width: | Height: | Size: 234 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="44" viewBox="0 0 54 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M22.4375 13.037V0.5H53.5V43.5H0.5V13.537H21.9375H22.4375V13.037Z" stroke="white"/>
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.125 5V1H19V16H1V6H8.125H9.125V5Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 195 B After Width: | Height: | Size: 183 B |
@ -1,3 +1,3 @@
|
||||
<svg width="54" height="44" viewBox="0 0 54 44" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M30.4375 25.037V0.5H53.5V43.5H1.03302L15.242 25.537H29.9375H30.4375V25.037Z" stroke="white"/>
|
||||
<svg width="20" height="17" viewBox="0 0 20 17" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12.1111 9.27023L12.0905 1H19V16H1.8753L5.71843 10.2727H11.1111H12.1136L12.1111 9.27023Z" stroke="white" stroke-width="2"/>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 206 B After Width: | Height: | Size: 236 B |
@ -1,15 +1,28 @@
|
||||
'use client'
|
||||
|
||||
// import { useEffect } from 'react'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { ErrorBoundary } from 'next/dist/client/components/error-boundary'
|
||||
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import ServerError from './error'
|
||||
|
||||
import '@/styles/common.scss'
|
||||
|
||||
export const QcastProvider = ({ children }) => {
|
||||
const [planSave, setPlanSave] = useState(false)
|
||||
const { currentCanvasPlan, modifiedPlans, checkUnsavedCanvasPlan } = usePlan()
|
||||
const { commonCode, findCommonCode } = useCommonCode()
|
||||
|
||||
useEffect(() => {
|
||||
const targetElement = document.getElementById('canvas')
|
||||
if (!targetElement && currentCanvasPlan?.id && planSave) {
|
||||
setPlanSave((prev) => !prev)
|
||||
checkUnsavedCanvasPlan(currentCanvasPlan.userId)
|
||||
} else if (targetElement && currentCanvasPlan?.id) {
|
||||
setPlanSave(true)
|
||||
}
|
||||
}, [modifiedPlans])
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log('commonCode', commonCode)
|
||||
// console.log(findCommonCode(113600))
|
||||
|
||||
@ -2,13 +2,13 @@
|
||||
|
||||
import { useEffect, useRef } from 'react'
|
||||
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
|
||||
import { useCanvas } from '@/hooks/useCanvas'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import { useContextMenu } from '@/hooks/useContextMenu'
|
||||
import { currentMenuState, currentObjectState, modifiedPlanFlagState } from '@/store/canvasAtom'
|
||||
import { currentMenuState, currentObjectState } from '@/store/canvasAtom'
|
||||
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
|
||||
import QContextMenu from '@/components/common/context-menu/QContextMenu'
|
||||
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
|
||||
@ -17,14 +17,11 @@ import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/Panel
|
||||
|
||||
export default function CanvasFrame() {
|
||||
const canvasRef = useRef(null)
|
||||
const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState)
|
||||
const { canvas } = useCanvas('canvas')
|
||||
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
||||
const currentMenu = useRecoilValue(currentMenuState)
|
||||
const { contextMenu, handleClick, handleKeyup } = useContextMenu()
|
||||
|
||||
const { selectedPlan, checkCanvasObjectEvent, checkUnsavedCanvasPlan, resetModifiedPlans } = usePlan()
|
||||
|
||||
const { selectedPlan, modifiedPlanFlag, checkCanvasObjectEvent, resetModifiedPlans } = usePlan()
|
||||
useEvent()
|
||||
|
||||
const loadCanvas = () => {
|
||||
@ -42,10 +39,16 @@ export default function CanvasFrame() {
|
||||
|
||||
useEffect(() => {
|
||||
if (modifiedPlanFlag && selectedPlan?.id) {
|
||||
// checkCanvasObjectEvent(selectedPlan.id)
|
||||
checkCanvasObjectEvent(selectedPlan.id)
|
||||
}
|
||||
}, [modifiedPlanFlag])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resetModifiedPlans()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadCanvas()
|
||||
resetModifiedPlans()
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
'use client'
|
||||
|
||||
import { useContext, useEffect, useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { 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'
|
||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||
@ -16,12 +15,11 @@ export default function CanvasLayout({ children }) {
|
||||
const { menuNumber } = useCanvasMenu()
|
||||
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, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
|
||||
useEffect(() => {
|
||||
loadCanvasPlanData(session.userId, objectNo)
|
||||
|
||||
@ -12,14 +12,7 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import {
|
||||
canvasSettingState,
|
||||
canvasState,
|
||||
canvasZoomState,
|
||||
currentCanvasPlanState,
|
||||
currentMenuState,
|
||||
verticalHorizontalModeState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom'
|
||||
import { sessionStore } from '@/store/commonAtom'
|
||||
import { outerLinePointsState } from '@/store/outerLineAtom'
|
||||
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
|
||||
@ -53,7 +46,6 @@ export default function CanvasMenu(props) {
|
||||
const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState)
|
||||
const canvasSetting = useRecoilValue(canvasSettingState)
|
||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
const sessionState = useRecoilValue(sessionStore)
|
||||
const globalLocale = useRecoilValue(globalLocaleStore)
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -61,7 +53,7 @@ export default function CanvasMenu(props) {
|
||||
const { handleMenu } = useMenu()
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { saveCanvas } = usePlan()
|
||||
const { currentCanvasPlan, saveCanvas } = usePlan()
|
||||
const { swalFire } = useSwal()
|
||||
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
|
||||
const commonUtils = useRecoilValue(commonUtilsState)
|
||||
|
||||
@ -5,27 +5,29 @@ import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { contextPopupPositionState } from '@/store/popupAtom'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { useState } from 'react'
|
||||
|
||||
export default function AuxiliaryMove(props) {
|
||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
|
||||
const { id, pos = contextPopupPosition } = props
|
||||
const { getMessage } = useMessage()
|
||||
const { closePopup } = usePopup()
|
||||
const [arrow1, setArrow1] = useState(null)
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={pos}>
|
||||
<div className={`modal-pop-wrap xm`}>
|
||||
<div className="modal-head">
|
||||
<h1 className="title">補助線の移動 </h1>
|
||||
<h1 className="title">{getMessage('modal.auxiliary.move')}</h1>
|
||||
<button className="modal-close" onClick={() => closePopup(id)}>
|
||||
닫기
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="grid-option-tit">移動する方向を入力してください</div>
|
||||
<div className="grid-option-tit">{getMessage('modal.auxiliary.move.info')}</div>
|
||||
<div className="grid-option-wrap">
|
||||
<div className="grid-option-box">
|
||||
<div className="move-form">
|
||||
<p className="mb5">長さ</p>
|
||||
<p className="mb5">{getMessage('length')}</p>
|
||||
<div className="input-move-wrap mb5">
|
||||
<div className="input-move">
|
||||
<input type="text" className="input-origin" defaultValue={910} />
|
||||
@ -40,15 +42,39 @@ export default function AuxiliaryMove(props) {
|
||||
</div>
|
||||
</div>
|
||||
<div className="direction-move-wrap">
|
||||
<button className="direction up"></button>
|
||||
<button className="direction down act"></button>
|
||||
<button className="direction left"></button>
|
||||
<button className="direction right"></button>
|
||||
<button
|
||||
className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
|
||||
onClick={() => {
|
||||
setArrow1('↑')
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
|
||||
}}
|
||||
></button>
|
||||
<button
|
||||
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
|
||||
onClick={() => {
|
||||
setArrow1('↓')
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
|
||||
}}
|
||||
></button>
|
||||
<button
|
||||
className={`direction left ${arrow1 === '←' ? 'act' : ''}`}
|
||||
onClick={() => {
|
||||
setArrow1('←')
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
|
||||
}}
|
||||
></button>
|
||||
<button
|
||||
className={`direction right ${arrow1 === '→' ? 'act' : ''}`}
|
||||
onClick={() => {
|
||||
setArrow1('→')
|
||||
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
|
||||
}}
|
||||
></button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act">保存</button>
|
||||
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -49,7 +49,8 @@ const PlacementSurface = forwardRef((props, refs) => {
|
||||
{lines?.map((line, index) => (
|
||||
<div className="eaves-keraba-item" id={index} key={index}>
|
||||
<div className="eaves-keraba-th">
|
||||
{line.isDiagonal ? getMessage('modal.placement.surface.setting.diagonal.length') : num[index]}
|
||||
{/*{line.isDiagonal ? getMessage('modal.placement.surface.setting.diagonal.length') : num[index]}*/}
|
||||
{num[index]}
|
||||
</div>
|
||||
<div className="eaves-keraba-td">
|
||||
<div className="outline-form">
|
||||
|
||||
@ -241,7 +241,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
|
||||
<div className={`modal-pop-wrap l-2`}>
|
||||
<div className={`modal-pop-wrap lr-2`}>
|
||||
<div className="modal-head">
|
||||
<h1 className="title">{getMessage('plan.menu.placement.surface.arrangement')} </h1>
|
||||
<button className="modal-close" onClick={() => closePopup(id)}>
|
||||
@ -249,35 +249,45 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
|
||||
</button>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="plane-shape-menu">
|
||||
{types.map((type) => (
|
||||
<button key={type.id} className={`shape-menu-box ${selectedType?.id === type.id ? 'act' : ''}`} onClick={() => setSelectedType(type)}>
|
||||
<div className="shape-box">
|
||||
<Image
|
||||
src={`/static/images/canvas/plane_shape0${type?.id}.svg`}
|
||||
alt="react"
|
||||
width={0}
|
||||
height={0}
|
||||
style={{
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
transform: getInversionState(),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="shape-library">
|
||||
<button className="library-btn ico01" onClick={() => setRotate((yInversion !== xInversion ? rotate - 1 : rotate + 1) % 4)}></button>
|
||||
<button className="library-btn ico02" onClick={() => setYInversion(!yInversion)}></button>
|
||||
<button className="library-btn ico03" onClick={() => setXInversion(!xInversion)}></button>
|
||||
</div>
|
||||
<PlacementSurface {...placementSurfaceProps} ref={surfaceRefs} />
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act" onClick={applySurfaces}>
|
||||
{getMessage('write')}
|
||||
</button>
|
||||
<div className="plane-frame-wrap">
|
||||
<div className="plane-shape-wrap">
|
||||
<div className="plane-shape-menu">
|
||||
{types.map((type) => (
|
||||
<button
|
||||
key={type.id}
|
||||
className={`shape-menu-box ${selectedType?.id === type.id ? 'act' : ''}`}
|
||||
onClick={() => setSelectedType(type)}
|
||||
>
|
||||
<div className="shape-box">
|
||||
<Image
|
||||
src={`/static/images/canvas/plane_shape0${type?.id}.svg`}
|
||||
alt="react"
|
||||
width={0}
|
||||
height={0}
|
||||
style={{
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
transform: getInversionState(),
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
<div className="shape-library">
|
||||
<button className="library-btn ico01" onClick={() => setRotate((yInversion !== xInversion ? rotate - 1 : rotate + 1) % 4)}></button>
|
||||
<button className="library-btn ico02" onClick={() => setYInversion(!yInversion)}></button>
|
||||
<button className="library-btn ico03" onClick={() => setXInversion(!xInversion)}></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="plane-detail-wrap">
|
||||
<PlacementSurface {...placementSurfaceProps} ref={surfaceRefs} />
|
||||
<div className="plane-shape-btn">
|
||||
<button className="btn-frame modal act" onClick={applySurfaces}>
|
||||
{getMessage('write')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,16 +1,9 @@
|
||||
import { useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import {
|
||||
canvasSizeState,
|
||||
canvasState,
|
||||
canvasZoomState,
|
||||
currentObjectState,
|
||||
fontFamilyState,
|
||||
fontSizeState,
|
||||
modifiedPlanFlagState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import { fontSelector } from '@/store/fontAtom'
|
||||
|
||||
// 캔버스에 필요한 이벤트
|
||||
@ -22,8 +15,8 @@ export function useCanvasEvent() {
|
||||
const fontSize = useRecoilValue(fontSizeState)
|
||||
const fontFamily = useRecoilValue(fontFamilyState)
|
||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||
const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState)
|
||||
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
||||
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
||||
|
||||
// 기본적인 이벤트 필요시 추가
|
||||
const attachDefaultEventOnCanvas = () => {
|
||||
@ -45,10 +38,8 @@ export function useCanvasEvent() {
|
||||
onChange: (e) => {
|
||||
const target = e.target
|
||||
|
||||
if (target.name !== 'mouseLine') {
|
||||
if (!modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
if (target.name !== 'mouseLine' && !modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target) {
|
||||
@ -65,10 +56,8 @@ export function useCanvasEvent() {
|
||||
target.uuid = uuidv4()
|
||||
}
|
||||
|
||||
if (target.name !== 'mouseLine') {
|
||||
if (!modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
if (target.name !== 'mouseLine' && !modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target.type === 'QPolygon' || target.type === 'QLine') {
|
||||
@ -173,7 +162,9 @@ export function useCanvasEvent() {
|
||||
|
||||
target.on('moving', (e) => {
|
||||
target.uuid = uuidv4()
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
if (!modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target.parentDirection === 'left' || target.parentDirection === 'right') {
|
||||
const minX = target.minX
|
||||
|
||||
@ -10,6 +10,7 @@ import { SAVE_KEY } from '@/common/common'
|
||||
export function usePlan() {
|
||||
const [planNum, setPlanNum] = useState(0)
|
||||
const [selectedPlan, setSelectedPlan] = useState(null)
|
||||
const [currentCanvasStatus, setCurrentCanvasStatus] = useState(null)
|
||||
|
||||
const [canvas, setCanvas] = useRecoilState(canvasState)
|
||||
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
@ -88,11 +89,17 @@ export function usePlan() {
|
||||
* 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 확인 후 관리
|
||||
*/
|
||||
const checkCanvasObjectEvent = (planId) => {
|
||||
setCurrentCanvasStatus(currentCanvasData())
|
||||
if (!modifiedPlans.some((modifiedPlan) => modifiedPlan === planId) && checkModifiedCanvasPlan(planId)) {
|
||||
setModifiedPlans((prev) => [...prev, planId])
|
||||
setModifiedPlanFlag(false)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if (currentCanvasStatus) {
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus }))
|
||||
}
|
||||
}, [currentCanvasStatus])
|
||||
/**
|
||||
* 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단
|
||||
*/
|
||||
@ -121,17 +128,21 @@ export function usePlan() {
|
||||
setModifiedPlans([])
|
||||
setModifiedPlanFlag(false)
|
||||
}
|
||||
const checkUnsavedCanvasPlan = (str) => {
|
||||
if (modifiedPlans.length > 0) {
|
||||
swalFire({
|
||||
text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
|
||||
type: 'confirm',
|
||||
confirmFn: async () => {
|
||||
await saveCanvas(userId)
|
||||
},
|
||||
})
|
||||
setModifiedPlans([])
|
||||
}
|
||||
|
||||
/**
|
||||
* 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 후 저장
|
||||
*/
|
||||
const checkUnsavedCanvasPlan = async (userId) => {
|
||||
swalFire({
|
||||
text: `저장 안된 ${currentCanvasPlan.name} PLAN을 저장하시겠습니까? `,
|
||||
type: 'confirm',
|
||||
confirmFn: async () => {
|
||||
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)
|
||||
? await putCanvasStatus(currentCanvasPlan.canvasStatus)
|
||||
: await postCanvasStatus(userId, currentCanvasPlan.canvasStatus)
|
||||
},
|
||||
})
|
||||
resetModifiedPlans()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -361,8 +372,12 @@ export function usePlan() {
|
||||
canvas,
|
||||
plans,
|
||||
selectedPlan,
|
||||
currentCanvasPlan,
|
||||
modifiedPlans,
|
||||
modifiedPlanFlag,
|
||||
setModifiedPlanFlag,
|
||||
checkCanvasObjectEvent,
|
||||
checkUnsavedCanvasPlan,
|
||||
resetModifiedPlans,
|
||||
saveCanvas,
|
||||
handleCurrentPlan,
|
||||
|
||||
@ -293,7 +293,9 @@
|
||||
"contextmenu.select.move": "선택・이동(JA)",
|
||||
"contextmenu.wallline.remove": "외벽선 삭제(JA)",
|
||||
"contextmenu.size.edit": "サイズ変更",
|
||||
"contextmenu.auxiliary.move": "보조선 이동(JA)",
|
||||
"contextmenu.auxiliary.move": "補助線の移動",
|
||||
"modal.auxiliary.move": "補助線の移動",
|
||||
"modal.auxiliary.move.info": "移動する方向を入力してください",
|
||||
"contextmenu.auxiliary.copy": "보조선 복사(JA)",
|
||||
"contextmenu.auxiliary.remove": "보조선 삭제(JA)",
|
||||
"contextmenu.auxiliary.vertical.bisector": "보조선 수직이등분선(JA)",
|
||||
|
||||
@ -299,6 +299,8 @@
|
||||
"contextmenu.wallline.remove": "외벽선 삭제",
|
||||
"contextmenu.size.edit": "사이즈 변경",
|
||||
"contextmenu.auxiliary.move": "보조선 이동",
|
||||
"modal.auxiliary.move": "보조선 이동",
|
||||
"modal.auxiliary.move.info": "이동할 방향을 입력해주세요.",
|
||||
"contextmenu.auxiliary.copy": "보조선 복사",
|
||||
"contextmenu.auxiliary.remove": "보조선 삭제",
|
||||
"contextmenu.auxiliary.vertical.bisector": "보조선 수직이등분선",
|
||||
|
||||
@ -769,6 +769,22 @@
|
||||
.btn-area{
|
||||
padding-bottom: 15px;
|
||||
border-bottom: 1px solid #ECF0F4;
|
||||
.file-upload{
|
||||
display: inline-block;
|
||||
height: 30px;
|
||||
background-color: #94A0AD;
|
||||
padding: 0 10px;
|
||||
border-radius: 2px;
|
||||
font-size: 13px;
|
||||
line-height: 30px;
|
||||
color: #fff;
|
||||
font-weight: 500;
|
||||
cursor: pointer;
|
||||
transition: background .15s ease-in-out;
|
||||
&:hover{
|
||||
background-color: #607F9A;
|
||||
}
|
||||
}
|
||||
}
|
||||
.drag-file-area{
|
||||
position: relative;
|
||||
|
||||
@ -60,6 +60,9 @@ $alert-color: #101010;
|
||||
&.lr{
|
||||
width: 440px;
|
||||
}
|
||||
&.lr-2{
|
||||
width: 450px;
|
||||
}
|
||||
&.lrr{
|
||||
width: 480px;
|
||||
}
|
||||
@ -880,17 +883,26 @@ $alert-color: #101010;
|
||||
}
|
||||
|
||||
// 면형상 배치
|
||||
.plane-frame-wrap{
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
.plane-shape-wrap{
|
||||
flex: none;
|
||||
width: 73px;
|
||||
}
|
||||
}
|
||||
|
||||
.plane-shape-menu{
|
||||
display: grid;
|
||||
grid-template-columns: repeat(6, 1fr);
|
||||
grid-template-rows: repeat(3, 90px);
|
||||
gap: 10px;
|
||||
margin-bottom: 10px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 5px;
|
||||
.shape-menu-box{
|
||||
border-radius: 2px;
|
||||
background-color: #3D3D3D;
|
||||
padding: 8px;
|
||||
transition: all .15s ease-in-out;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
background-color: #373737;
|
||||
border: 1px solid #676767;
|
||||
transition: background .15s ease-in-out, border .15s ease-in-out;
|
||||
.shape-box{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
@ -898,11 +910,11 @@ $alert-color: #101010;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: #313131;
|
||||
border-radius: 2px;
|
||||
}
|
||||
&.act,
|
||||
&:hover{
|
||||
border-color: #008BFF;
|
||||
background-color: #008BFF;
|
||||
}
|
||||
}
|
||||
@ -910,24 +922,23 @@ $alert-color: #101010;
|
||||
|
||||
.shape-library{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
padding: 5px;
|
||||
background-color: #3D3D3D;
|
||||
margin-bottom: 24px;
|
||||
padding-top: 5px;
|
||||
.library-btn{
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
width: 100%;
|
||||
height: 34px;
|
||||
border: 1px solid #6C6C6C;
|
||||
border-radius: 2px;
|
||||
background-color: transparent;
|
||||
background-color: #373737;
|
||||
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;}
|
||||
&.ico01{background-image: url(../../public/static/images/canvas/shape_labrary01.svg); background-size: 19px 18px;}
|
||||
&.ico02{background-image: url(../../public/static/images/canvas/shape_labrary02.svg); background-size: 15px 20px;}
|
||||
&.ico03{background-image: url(../../public/static/images/canvas/shape_labrary03.svg); background-size: 19px 16px;}
|
||||
&:hover{
|
||||
border-color: #1083E3;
|
||||
background-color: #1083E3;
|
||||
@ -935,13 +946,22 @@ $alert-color: #101010;
|
||||
}
|
||||
}
|
||||
|
||||
.plane-shape-wrapper{
|
||||
.plane-detail-wrap{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
}
|
||||
.plane-shape-wrapper{
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
.plane-box{
|
||||
padding: 10px;
|
||||
width: 100%;
|
||||
padding: 10px 18px;
|
||||
border-radius: 2px;
|
||||
background-color: #3D3D3D;
|
||||
background-color: #313131;
|
||||
border: 1px solid #484848;
|
||||
.plane-box-tit{
|
||||
font-size: $pop-normal-size;
|
||||
font-weight: 600;
|
||||
@ -949,14 +969,14 @@ $alert-color: #101010;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
&.shape-box{
|
||||
flex: 1;
|
||||
.shape-box-inner{
|
||||
display: flex;
|
||||
gap:10px;
|
||||
gap:15px;
|
||||
min-height: 140px;
|
||||
.shape-img{
|
||||
position: relative;
|
||||
flex: 1;
|
||||
flex: none;
|
||||
width: 150px;
|
||||
background-color: #fff;
|
||||
border-radius: 2px;
|
||||
img{
|
||||
@ -967,11 +987,7 @@ $alert-color: #101010;
|
||||
}
|
||||
}
|
||||
.shape-data{
|
||||
flex: none;
|
||||
width: 190px;
|
||||
background-color: #313131;
|
||||
border-radius: 2px;
|
||||
padding: 15px;
|
||||
flex: 1;
|
||||
.eaves-keraba-table{
|
||||
.eaves-keraba-item{
|
||||
.eaves-keraba-th,
|
||||
@ -990,17 +1006,15 @@ $alert-color: #101010;
|
||||
}
|
||||
}
|
||||
&.direction-box{
|
||||
flex: 1;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1046,9 +1060,15 @@ $alert-color: #101010;
|
||||
font-size: $pop-normal-size;
|
||||
font-weight: $pop-normal-weight;
|
||||
color: $pop-color;
|
||||
margin-top: 24px;
|
||||
padding-bottom: 14px;
|
||||
border-bottom: 1px solid #424242;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.plane-shape-btn{
|
||||
padding-top: 10px;
|
||||
margin-top: auto;
|
||||
button{
|
||||
display: block;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
// 오브젝트 배치
|
||||
|
||||