Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-10-31 09:19:43 +09:00
commit 4c23de12b4
31 changed files with 251 additions and 164 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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()

View File

@ -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)

View File

@ -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)

View File

@ -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>

View File

@ -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">

View File

@ -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>

View File

@ -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

View File

@ -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,

View File

@ -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)",

View File

@ -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": "보조선 수직이등분선",

View File

@ -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;

View File

@ -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%;
}
}
// 오브젝트 배치