Merge remote-tracking branch 'origin/qcast-pub' into dev

This commit is contained in:
김민식 2025-01-07 11:10:52 +09:00
commit 5c9fe1045f
5 changed files with 358 additions and 183 deletions

View File

@ -212,7 +212,7 @@ export default function CanvasMenu(props) {
}, [canvasSetting])
const checkMenuState = (menu) => {
return ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2)
return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2)
}
// Excel/PDF
@ -283,7 +283,7 @@ export default function CanvasMenu(props) {
key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => {
if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) return
if (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) return
if (menuNumber === 4 && menu.index === 2) return
onClickNav(menu)
}}

View File

@ -14,7 +14,9 @@ import { useModule } from '@/hooks/module/useModule'
export const PANEL_EDIT_TYPE = {
MOVE: 'move',
MOVE_ALL: 'moveAll',
COPY: 'copy',
COPY_ALL: 'copyAll',
COLUMN_MOVE: 'columnMove',
COLUMN_COPY: 'columnCopy',
ROW_MOVE: 'rowMove',
@ -29,7 +31,7 @@ export default function PanelEdit(props) {
const [direction, setDirection] = useState('up')
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule()
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule()
useEffect(() => {
if (canvas) {
@ -44,9 +46,15 @@ export default function PanelEdit(props) {
case PANEL_EDIT_TYPE.MOVE:
moduleMove(length, direction)
break
case PANEL_EDIT_TYPE.MOVE_ALL:
moduleMoveAll(length, direction)
break
case PANEL_EDIT_TYPE.COPY:
moduleCopy(length, direction)
break
case PANEL_EDIT_TYPE.COPY_ALL:
moduleCopyAll(length, direction)
break
case PANEL_EDIT_TYPE.COLUMN_MOVE:
moduleMultiMove('column', length, direction)
break

View File

@ -73,119 +73,121 @@ export default function RoofAllocationSetting(props) {
{getMessage('modal.common.add')}
</button>
</div>
<div className="grid-option-wrap">
{currentRoofList.map((roof, index) => {
return (
<div className="grid-option-box" key={index}>
<div className="d-check-radio pop no-text">
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
<label
htmlFor="ra01"
onClick={(e) => {
handleDefaultRoofMaterial(index)
}}
></label>
</div>
<div className="grid-option-block-form">
<div className="block-box">
<div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}>
<QSelectBox
options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div>
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
</div>
<div className="grid-option-overflow">
<div className="grid-option-wrap">
{currentRoofList.map((roof, index) => {
return (
<div className="grid-option-box" key={index}>
<div className="d-check-radio pop no-text">
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
<label
htmlFor="ra01"
onClick={(e) => {
handleDefaultRoofMaterial(index)
}}
></label>
</div>
{(roof.widAuth || roof.lenAuth) && (
<div className="grid-option-block-form">
<div className="block-box">
{roof.widAuth && (
<div className="flex-ment">
<span>W</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} />
</div>
<div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}>
<QSelectBox
options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div>
)}
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
</div>
</div>
)}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box">
{roof.raftAuth && (
<div className="block-box">
{(roof.widAuth || roof.lenAuth) && (
<div className="block-box">
{roof.widAuth && (
<div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && (
<div className="grid-select" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
<span>W</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} />
</div>
</div>
</div>
)}
</div>
)}
<div className="block-box">
<div className="icon-btn-wrap">
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
)}
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
</div>
)}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box">
{roof.raftAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && (
<div className="grid-select" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
</div>
</div>
</div>
)}
</div>
)}
<div className="block-box">
<div className="icon-btn-wrap">
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
</div>
</div>
</div>
</div>
</div>
)
})}
)
})}
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>

View File

@ -26,7 +26,8 @@ export const MODULE_INSERT_TYPE = {
}
export const MODULE_ALIGN_TYPE = {
TOP: 'top',
VERTICAL: 'vertical',
HORIZONTAL: 'horizontal',
}
export function useModule() {
@ -83,6 +84,162 @@ export function useModule() {
}
}
}
const moduleMultiMove = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
swalFire({
title: '여러 개의 모듈을 선택할 수 없습니다.',
icon: 'error',
type: 'alert',
})
canvas.discardActiveObject()
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
const otherModules = getOtherModules(modules)
const objects = getObjects()
const moduleSetupSurface = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (otherModules.length > 0) {
if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleMoveAll = (length, direction) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleCopyAll = (length, direction) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
const copyModules = []
let copyModule = null
let isWarning = false
let moduleLength = 0
if (['up', 'down'].includes(direction)) {
modules.sort((a, b) => a.top - b.top)
moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top)
} else if (['left', 'right'].includes(direction)) {
modules.sort((a, b) => a.left - b.left)
moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left)
}
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, moduleSetupSurface)) {
isWarning = true
copyModule.set({ fill: 'red' })
}
canvas.renderAll()
})
if (isWarning) {
swalFire({
title: getMessage('can.not.copy.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
canvas.remove(...copyModules)
canvas.renderAll()
},
})
}
}
const moduleCopy = (length, direction) => {
if (canvas.getActiveObjects().length === 0) return
@ -144,63 +301,6 @@ export function useModule() {
}
}
const moduleMultiMove = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
swalFire({
title: '여러 개의 모듈을 선택할 수 없습니다.',
icon: 'error',
type: 'alert',
})
canvas.discardActiveObject()
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
const otherModules = getOtherModules(modules)
const objects = getObjects()
const moduleSetupSurface = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (otherModules.length > 0) {
if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleMultiCopy = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
@ -694,7 +794,64 @@ export function useModule() {
}
}
const alignModule = (type) => {}
const alignModule = (type) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
const top = Math.min(...modules.map((module) => module.top))
const left = Math.min(...modules.map((module) => module.left))
const moduleSurfacePos = {
top: Math.min(...moduleSetupSurface.points.map((point) => point.y)),
left: Math.min(...moduleSetupSurface.points.map((point) => point.x)),
}
const [height, width] = [bottom - top, right - left]
const verticalCenterLength = moduleSurfacePos.top + moduleSetupSurface.height / 2 - (top + height / 2)
const horizontalCenterLength = moduleSurfacePos.left + moduleSetupSurface.width / 2 - (left + width / 2)
let isWarning = false
canvas.discardActiveObject()
modules.forEach((module) => {
module.originPos = {
left: module.left,
top: module.top,
fill: module.fill,
}
if (type === MODULE_ALIGN_TYPE.VERTICAL) {
module.set({ top: module.top + verticalCenterLength })
} else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) {
module.set({ left: module.left + horizontalCenterLength })
}
canvas.renderAll()
module.setCoords()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.align.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const modulesRemove = () => {
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules)
canvas.renderAll()
}
const isOverlapOtherModules = (module, otherModules) => {
return otherModules.some(
@ -765,11 +922,15 @@ export function useModule() {
return {
moduleMove,
moduleMultiMove,
moduleMoveAll,
moduleCopy,
moduleMultiCopy,
moduleCopyAll,
moduleColumnRemove,
moduleRowRemove,
moduleColumnInsert,
muduleRowInsert,
modulesRemove,
alignModule,
}
}

View File

@ -1,7 +1,7 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
import { MENU } from '@/common/common'
import { MENU, POLYGON_TYPE } from '@/common/common'
import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize'
import { usePopup } from '@/hooks/usePopup'
import { v4 as uuidv4 } from 'uuid'
@ -40,6 +40,7 @@ import { useCanvasSetting } from './option/useCanvasSetting'
import { useGrid } from './common/useGrid'
import { useAdsorptionPoint } from './useAdsorptionPoint'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { MODULE_ALIGN_TYPE, useModule } from './module/useModule'
export function useContextMenu() {
const canvas = useRecoilValue(canvasState)
@ -66,6 +67,7 @@ export function useContextMenu() {
const commonTextFont = useRecoilValue(fontSelector('commonText'))
const { settingsData, setSettingsDataSave } = useCanvasSetting()
const { swalFire } = useSwal()
const { alignModule } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn()
const currentMenuSetting = () => {
@ -691,36 +693,38 @@ export function useContextMenu() {
])
break
case 'moduleSetupSurface':
case 'dimensionLineText':
case 'roof':
setContextMenu([
[
{
id: 'moduleVerticalCenterAlign',
name: getMessage('contextmenu.module.vertical.align'),
fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL),
},
{
id: 'moduleHorizonCenterAlign',
name: getMessage('contextmenu.module.horizon.align'),
},
{
id: 'moduleLeftAlign',
name: getMessage('contextmenu.module.left.align'),
},
{
id: 'moduleRightAlign',
name: getMessage('contextmenu.module.right.align'),
},
{
id: 'moduleUpAlign',
name: getMessage('contextmenu.module.up.align'),
},
{
id: 'moduleDownAlign',
name: getMessage('contextmenu.module.down.align'),
fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL),
},
{
id: 'moduleRemove',
name: getMessage('contextmenu.module.remove'),
fn: () => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules)
canvas.renderAll()
},
},
{
id: 'moduleMove',
name: getMessage('contextmenu.module.move'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.MOVE_ALL} />,
},
{
id: 'moduleCopy',
name: getMessage('contextmenu.module.copy'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COPY_ALL} />,
},
{
id: 'moduleCircuitNumberEdit',