dev #445

Merged
ysCha merged 4 commits from dev into dev-deploy 2025-12-04 19:11:03 +09:00
15 changed files with 302 additions and 52 deletions

View File

@ -219,7 +219,8 @@ export const SAVE_KEY = [
'originWidth', 'originWidth',
'originHeight', 'originHeight',
'skeletonLines', 'skeletonLines',
'skeleton' 'skeleton',
'viewportTransform',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -2,7 +2,7 @@
import { useContext, useEffect, useRef } from 'react' import { useContext, useEffect, useRef } from 'react'
import { useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import QContextMenu from '@/components/common/context-menu/QContextMenu' import QContextMenu from '@/components/common/context-menu/QContextMenu'
import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics'
@ -11,7 +11,7 @@ import { useCanvas } from '@/hooks/useCanvas'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { useContextMenu } from '@/hooks/useContextMenu' import { useContextMenu } from '@/hooks/useContextMenu'
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
import { currentMenuState } from '@/store/canvasAtom' import { canvasZoomState, currentMenuState } from '@/store/canvasAtom'
import { totalDisplaySelector } from '@/store/settingAtom' import { totalDisplaySelector } from '@/store/settingAtom'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
@ -50,6 +50,7 @@ export default function CanvasFrame() {
const resetSeriesState = useResetRecoilState(seriesState) const resetSeriesState = useResetRecoilState(seriesState)
const resetModelsState = useResetRecoilState(modelsState) const resetModelsState = useResetRecoilState(modelsState)
const resetCompasDeg = useResetRecoilState(compasDegAtom) const resetCompasDeg = useResetRecoilState(compasDegAtom)
const [zoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const resetSelectedModelsState = useResetRecoilState(selectedModelsState) const resetSelectedModelsState = useResetRecoilState(selectedModelsState)
const resetPcsCheckState = useResetRecoilState(pcsCheckState) const resetPcsCheckState = useResetRecoilState(pcsCheckState)
const { handleModuleSelectionTotal } = useCanvasPopupStatusController() const { handleModuleSelectionTotal } = useCanvasPopupStatusController()
@ -67,6 +68,13 @@ export default function CanvasFrame() {
canvasLoadInit() //config canvasLoadInit() //config
canvas?.renderAll() // . canvas?.renderAll() // .
if (canvas.viewportTransform) {
if (canvas.viewportTransform[0] !== 1) {
setCanvasZoom(Number((canvas.viewportTransform[0] * 100).toFixed(0)))
}
}
canvas.originViewPortTransform = canvas.viewportTransform
if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) { if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) {
setTimeout(() => { setTimeout(() => {
setSelectedMenu('module') setSelectedMenu('module')

View File

@ -2,7 +2,7 @@
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { usePathname, useRouter, useSearchParams } from 'next/navigation' import { usePathname, useRouter } from 'next/navigation'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
@ -25,17 +25,18 @@ import { useCommonUtils } from '@/hooks/common/useCommonUtils'
import useMenu from '@/hooks/common/useMenu' import useMenu from '@/hooks/common/useMenu'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState, currentCanvasPlanState } from '@/store/canvasAtom' import {
canvasSettingState,
canvasState,
canvasZoomState,
currentCanvasPlanState,
currentMenuState,
verticalHorizontalModeState,
} from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
import { import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom'
addedRoofsState,
basicSettingState,
corridorDimensionSelector,
selectedRoofMaterialSelector,
settingModalFirstOptionsState,
} from '@/store/settingAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import { commonUtilsState } from '@/store/commonUtilsAtom' import { commonUtilsState } from '@/store/commonUtilsAtom'
import { menusState } from '@/store/menuAtom' import { menusState } from '@/store/menuAtom'
@ -51,6 +52,7 @@ import { QcastContext } from '@/app/QcastProvider'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { useTrestle } from '@/hooks/module/useTrestle' import { useTrestle } from '@/hooks/module/useTrestle'
export default function CanvasMenu(props) { export default function CanvasMenu(props) {
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const { selectedMenu, setSelectedMenu } = props const { selectedMenu, setSelectedMenu } = props
@ -515,7 +517,10 @@ export default function CanvasMenu(props) {
if (createUser === 'T01' && sessionState.storeId !== 'T01') { if (createUser === 'T01' && sessionState.storeId !== 'T01') {
setAllButtonStyles('none') setAllButtonStyles('none')
} else { } else {
setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg }) setEstimateContextState({
tempFlg: estimateRecoilState.tempFlg,
lockFlg: estimateRecoilState.lockFlg,
})
handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo) handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo)
} }
} }

View File

@ -227,11 +227,33 @@ export default function CircuitTrestleSetting({ id }) {
return return
} }
const isMultiModule = selectedModules.itemList.length > 1
let isAllIndfcs = false
if (isMultiModule) {
//INDFCS , OUTDMULTI
// 1. pcs alert
if (selectedModels.length > 0) {
isAllIndfcs = selectedModels.every((model) => model.pcsTpCd === 'INDFCS')
} else {
isAllIndfcs = models.every((model) => model.pcsTpCd === 'INDFCS')
}
}
if (isAllIndfcs) {
swalFire({
title: getMessage('module.circuit.indoor.focused.error'),
type: 'alert',
})
return
}
const params = { const params = {
...getOptYn(), ...getOptYn(),
useModuleItemList: getUseModuleItemList(), useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(), roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(), pcsItemList: getPcsItemList(isMultiModule),
} }
// //
@ -292,12 +314,12 @@ export default function CircuitTrestleSetting({ id }) {
}) })
} else { } else {
// //
getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList() }).then((res) => { getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList(isMultiModule) }).then((res) => {
if (res.resultCode === 'S') { if (res.resultCode === 'S') {
// //
getPcsVoltageStepUpList({ getPcsVoltageStepUpList({
...params, ...params,
pcsItemList: getSelectedPcsItemList(), pcsItemList: getSelectedPcsItemList(isMultiModule),
}).then((res) => { }).then((res) => {
if (res?.result.resultCode === 'S' && res?.data) { if (res?.result.resultCode === 'S' && res?.data) {
setTabNum(2) setTabNum(2)
@ -523,6 +545,7 @@ export default function CircuitTrestleSetting({ id }) {
obj.circuit = null obj.circuit = null
obj.pcsItemId = null obj.pcsItemId = null
obj.circuitNumber = null obj.circuitNumber = null
obj.pcs = null
}) })
setSelectedModels( setSelectedModels(
JSON.parse(JSON.stringify(selectedModels)).map((model) => { JSON.parse(JSON.stringify(selectedModels)).map((model) => {

View File

@ -649,7 +649,13 @@ export default function StepUp(props) {
style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }}
> >
<td className="al-r">{item.serQty}</td> <td className="al-r">{item.serQty}</td>
<td className="al-r">{item.paralQty}</td> <td className="al-r">
{/* 2025.12.04 select 추가 */}
<select className="select-light dark table-select" name="" id="">
<option value="">{item.paralQty}</option>
</select>
</td>
{/* <td className="al-r">{item.paralQty}</td> */}
</tr> </tr>
) )
})} })}

View File

@ -9,7 +9,7 @@ import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { fontSelector } from '@/store/fontAtom' import { fontSelector } from '@/store/fontAtom'
import { selectedModuleState } from '@/store/selectedModuleOptions' import { selectedModuleState } from '@/store/selectedModuleOptions'
import { circuitNumDisplaySelector } from '@/store/settingAtom' import { circuitNumDisplaySelector } from '@/store/settingAtom'
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useRef, useState } from 'react'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { normalizeDigits } from '@/util/input-utils' import { normalizeDigits } from '@/util/input-utils'
@ -32,6 +32,7 @@ export default function PassivityCircuitAllocation(props) {
const { header, rows, footer } = useRecoilValue(moduleStatisticsState) const { header, rows, footer } = useRecoilValue(moduleStatisticsState)
const [circuitNumber, setCircuitNumber] = useState(1) const [circuitNumber, setCircuitNumber] = useState(1)
const [targetModules, setTargetModules] = useState([]) const [targetModules, setTargetModules] = useState([])
const targetModulesRef = useRef([])
const { getPcsManualConfChk } = useMasterController() const { getPcsManualConfChk } = useMasterController()
const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector) const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector)
const { setModuleStatisticsData } = useCircuitTrestle() const { setModuleStatisticsData } = useCircuitTrestle()
@ -59,6 +60,10 @@ export default function PassivityCircuitAllocation(props) {
} }
}, []) }, [])
useEffect(() => {
targetModulesRef.current = targetModules
}, [targetModules])
const handleTargetModules = (obj) => { const handleTargetModules = (obj) => {
if (!Array.isArray(targetModules)) { if (!Array.isArray(targetModules)) {
setTargetModules([]) setTargetModules([])
@ -79,6 +84,7 @@ export default function PassivityCircuitAllocation(props) {
} }
const handleCircuitNumberFix = () => { const handleCircuitNumberFix = () => {
const pcsTpCd = selectedPcs.pcsTpCd // ,
let uniqueCircuitNumbers = [ let uniqueCircuitNumbers = [
...new Set( ...new Set(
canvas canvas
@ -91,13 +97,13 @@ export default function PassivityCircuitAllocation(props) {
const surfaceList = targetModules.map((module) => { const surfaceList = targetModules.map((module) => {
return canvas.getObjects().filter((obj) => obj.id === canvas.getObjects().filter((obj) => obj.id === module)[0].surfaceId)[0] return canvas.getObjects().filter((obj) => obj.id === canvas.getObjects().filter((obj) => obj.id === module)[0].surfaceId)[0]
}) })
let surfaceType = {}
surfaceList.forEach((surface) => {
surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
})
if (surfaceList.length > 1) { if (surfaceList.length > 1) {
let surfaceType = {}
surfaceList.forEach((surface) => {
surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
})
if (Object.keys(surfaceType).length > 1) { if (Object.keys(surfaceType).length > 1) {
swalFire({ swalFire({
text: getMessage('module.circuit.fix.not.same.roof.error'), text: getMessage('module.circuit.fix.not.same.roof.error'),
@ -107,6 +113,7 @@ export default function PassivityCircuitAllocation(props) {
return return
} }
} }
if (!circuitNumber || circuitNumber === 0) { if (!circuitNumber || circuitNumber === 0) {
swalFire({ swalFire({
text: getMessage('module.circuit.minimun.error'), text: getMessage('module.circuit.minimun.error'),
@ -114,31 +121,65 @@ export default function PassivityCircuitAllocation(props) {
icon: 'warning', icon: 'warning',
}) })
return return
} else if (targetModules.length === 0) { }
if (targetModules.length === 0) {
swalFire({ swalFire({
text: getMessage('module.not.found'), text: getMessage('module.not.found'),
type: 'alert', type: 'alert',
icon: 'warning', icon: 'warning',
}) })
return return
} else if (selectedModels.length > 1) { }
let result = false
uniqueCircuitNumbers.forEach((number) => { switch (pcsTpCd) {
if ( case 'INDFCS': {
number.split('-')[1] === circuitNumber + ')' && const originHaveThisPcsModules = canvas
number.split('-')[0] !== '(' + (selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1) .getObjects()
) { .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.pcs && obj.pcs.id === selectedPcs.id)
result = true // pcs surface .
} const originSurfaceList = canvas
}) .getObjects()
if (result) { .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && originHaveThisPcsModules.map((obj) => obj.surfaceId).includes(obj.id))
swalFire({
text: getMessage('module.already.exist.error'), originSurfaceList.concat(originSurfaceList).forEach((surface) => {
type: 'alert', surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
icon: 'warning',
}) })
return
if (surfaceList.length > 1) {
if (Object.keys(surfaceType).length > 1) {
swalFire({
text: getMessage('module.circuit.fix.not.same.roof.error'),
type: 'alert',
icon: 'warning',
})
return
}
}
break
}
case 'OUTDMULTI': {
if (selectedModels.length > 1) {
let result = false
uniqueCircuitNumbers.forEach((number) => {
if (
number.split('-')[1] === circuitNumber + ')' &&
number.split('-')[0] !== '(' + (selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1)
) {
result = true
}
})
if (result) {
swalFire({
text: getMessage('module.already.exist.error'),
type: 'alert',
icon: 'warning',
})
return
}
}
} }
} }
@ -189,6 +230,7 @@ export default function PassivityCircuitAllocation(props) {
roofSurfaceId: surface.id, roofSurfaceId: surface.id,
roofSurface: surface.direction, roofSurface: surface.direction,
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch, roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
roofSurfaceNorthYn: surface.direction === 'north' ? 'Y' : 'N',
moduleList: surface.modules.map((module) => { moduleList: surface.modules.map((module) => {
return { return {
itemId: module.moduleInfo.itemId, itemId: module.moduleInfo.itemId,
@ -270,6 +312,12 @@ export default function PassivityCircuitAllocation(props) {
return return
} }
targetModules.forEach((module) => {
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
const targetModule = modules.find((obj) => obj.id === module)
targetModule.pcs = selectedPcs
})
setTargetModules([]) setTargetModules([])
setCircuitNumber(+circuitNumber + 1) setCircuitNumber(+circuitNumber + 1)
setModuleStatisticsData() setModuleStatisticsData()

View File

@ -1,8 +1,10 @@
import React, { useEffect, useState } from 'react' import React, { useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outlineDisplaySelector } from '@/store/settingAtom'
import { useRecoilValue } from 'recoil'
export default function FirstOption(props) { export default function FirstOption(props) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -11,6 +13,7 @@ export default function FirstOption(props) {
const { option1, option2, dimensionDisplay } = settingModalFirstOptions const { option1, option2, dimensionDisplay } = settingModalFirstOptions
const { initEvent } = useEvent() const { initEvent } = useEvent()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const outlineDisplay = useRecoilValue(outlineDisplaySelector)
// //
useEffect(() => { useEffect(() => {
@ -18,6 +21,13 @@ export default function FirstOption(props) {
setSettingsDataSave({ ...settingsData }) setSettingsDataSave({ ...settingsData })
}, []) }, [])
useEffect(() => {
const outline = canvas.getObjects().filter((obj) => obj.name === 'originRoofOuterLine')
outline.forEach((obj) => {
obj.visible = outlineDisplay
})
}, [outlineDisplay])
const onClickOption = async (item) => { const onClickOption = async (item) => {
let dimensionDisplay = settingModalFirstOptions?.dimensionDisplay let dimensionDisplay = settingModalFirstOptions?.dimensionDisplay
let option1 = settingModalFirstOptions?.option1 let option1 = settingModalFirstOptions?.option1
@ -58,7 +68,12 @@ export default function FirstOption(props) {
// setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: [...options] }) // setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: [...options] })
} }
setSettingsData({ ...settingsData, option1: [...option1], option2: [...option2], dimensionDisplay: [...dimensionDisplay] }) setSettingsData({
...settingsData,
option1: [...option1],
option2: [...option2],
dimensionDisplay: [...dimensionDisplay],
})
} }
// useEffect(() => { // useEffect(() => {

View File

@ -31,8 +31,11 @@ export function useCommonUtils() {
useEffect(() => { useEffect(() => {
commonTextMode() commonTextMode()
if (commonUtils.dimension) { if (commonUtils.dimension) {
generateTempGrid()
commonDimensionMode() commonDimensionMode()
return return
} else {
removeTempGrid()
} }
if (commonUtils.distance) { if (commonUtils.distance) {
commonDistanceMode() commonDistanceMode()
@ -655,7 +658,7 @@ export function useCommonUtils() {
if (obj.name === 'roof') { if (obj.name === 'roof') {
clonedObj.setCoords() clonedObj.setCoords()
clonedObj.fire('modified') clonedObj.fire('modified')
clonedObj.fire('polygonMoved') // clonedObj.fire('polygonMoved')
clonedObj.set({ clonedObj.set({
direction: obj.direction, direction: obj.direction,
directionText: obj.directionText, directionText: obj.directionText,
@ -905,6 +908,45 @@ export function useCommonUtils() {
} }
} }
const generateTempGrid = () => {
if (!canvas) return
const objects = canvas.getObjects().filter((obj) => ['QPolygon'].includes(obj.type))
const gridLines = []
objects.forEach((obj) => {
const lines = obj.lines
lines.forEach((line) => {
const gridLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], {
stroke: 'gray',
strokeWidth: 1,
selectable: false,
evented: false,
opacity: 0.5,
name: 'tempGrid',
direction: line.x1 === line.x2 ? 'vertical' : 'horizontal',
visible: false,
})
gridLines.push(gridLine)
})
})
gridLines.forEach((line) => {
canvas.add(line)
})
canvas.renderAll()
}
const removeTempGrid = () => {
if (!canvas) return
const tempGrids = canvas.getObjects().filter((obj) => obj.name === 'tempGrid' && !obj.visible)
tempGrids.forEach((grid) => canvas.remove(grid))
canvas.renderAll()
}
return { return {
commonFunctions, commonFunctions,
dimensionSettings, dimensionSettings,
@ -916,5 +958,7 @@ export function useCommonUtils() {
editText, editText,
changeDimensionExtendLine, changeDimensionExtendLine,
deleteOuterLineObject, deleteOuterLineObject,
generateTempGrid,
removeTempGrid,
} }
} }

View File

@ -9,6 +9,7 @@ import {
basicSettingState, basicSettingState,
correntObjectNoState, correntObjectNoState,
corridorDimensionSelector, corridorDimensionSelector,
outlineDisplaySelector,
roofDisplaySelector, roofDisplaySelector,
roofMaterialsSelector, roofMaterialsSelector,
selectedRoofMaterialSelector, selectedRoofMaterialSelector,
@ -59,9 +60,11 @@ export function useRoofAllocationSetting(id) {
const { saveCanvas } = usePlan() const { saveCanvas } = usePlan()
const [roofsStore, setRoofsStore] = useRecoilState(roofsState) const [roofsStore, setRoofsStore] = useRecoilState(roofsState)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const outerLinePoints = useRecoilValue(outerLinePointsState)
const resetPoints = useResetRecoilState(outerLinePointsState) const resetPoints = useResetRecoilState(outerLinePointsState)
const [corridorDimension, setCorridorDimension] = useRecoilState(corridorDimensionSelector) const [corridorDimension, setCorridorDimension] = useRecoilState(corridorDimensionSelector)
const { changeCorridorDimensionText } = useText() const { changeCorridorDimensionText } = useText()
const outlineDisplay = useRecoilValue(outlineDisplaySelector)
useEffect(() => { useEffect(() => {
/** 배치면 초기설정에서 선택한 지붕재 배열 설정 */ /** 배치면 초기설정에서 선택한 지붕재 배열 설정 */
@ -303,11 +306,53 @@ export function useRoofAllocationSetting(id) {
addPopup(popupId, 1, <ActualSizeSetting id={popupId} />) addPopup(popupId, 1, <ActualSizeSetting id={popupId} />)
} else { } else {
apply() apply()
//기존 지붕 선은 남겨둔다.
drawOriginRoofLine()
resetPoints() resetPoints()
basicSettingSave() basicSettingSave()
} }
} }
const drawOriginRoofLine = () => {
// outerLinePoints 배열을 이용하여 빨간색 Line 객체들 생성
if (outerLinePoints && outerLinePoints.length > 1) {
// 연속된 점들을 연결하여 라인 생성
for (let i = 0; i < outerLinePoints.length - 1; i++) {
const point1 = outerLinePoints[i]
const point2 = outerLinePoints[i + 1]
const line = new fabric.Line([point1.x, point1.y, point2.x, point2.y], {
stroke: 'black',
strokeDashArray: [5, 2],
strokeWidth: 1,
selectable: false,
name: 'originRoofOuterLine',
visible: outlineDisplay,
})
canvas.add(line)
}
// 마지막 점과 첫 점을 연결하여 폐곡선 만들기
if (outerLinePoints.length > 2) {
const lastPoint = outerLinePoints[outerLinePoints.length - 1]
const firstPoint = outerLinePoints[0]
const closingLine = new fabric.Line([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], {
stroke: 'red',
strokeWidth: 2,
selectable: false,
name: 'originRoofOuterLine',
})
canvas.add(closingLine)
}
canvas.renderAll()
}
}
/** /**
* 지붕재 오른쪽 마우스 클릭 단일로 지붕재 변경 필요한 경우 * 지붕재 오른쪽 마우스 클릭 단일로 지붕재 변경 필요한 경우
*/ */

View File

@ -402,7 +402,8 @@ export function useCanvasEvent() {
} }
} else { } else {
zoom = canvasZoom - 10 zoom = canvasZoom - 10
if (zoom < 10) { //50%->10% if (zoom < 10) {
//50%->10%
return return
} }
} }
@ -412,8 +413,33 @@ export function useCanvasEvent() {
const handleZoomClear = () => { const handleZoomClear = () => {
setCanvasZoom(100) setCanvasZoom(100)
canvas.set({ zoom: 1 })
canvas.viewportTransform = [1, 0, 0, 1, 0, 0] zoomToAllObjects()
canvas.renderAll()
}
const zoomToAllObjects = () => {
const objects = canvas.getObjects().filter((obj) => obj.visible)
if (objects.length === 0) return
let minX = Infinity,
minY = Infinity
let maxX = -Infinity,
maxY = -Infinity
objects.forEach((obj) => {
const bounds = obj.getBoundingRect()
minX = Math.min(minX, bounds.left)
minY = Math.min(minY, bounds.top)
maxX = Math.max(maxX, bounds.left + bounds.width)
maxY = Math.max(maxY, bounds.top + bounds.height)
})
const centerX = (minX + maxX) / 2
const centerY = (minY + maxY) / 2
const centerPoint = new fabric.Point(centerX, centerY)
canvas.zoomToPoint(centerPoint, 1)
canvas.renderAll() canvas.renderAll()
} }

View File

@ -42,7 +42,18 @@ export function useCircuitTrestle(executeEffect = false) {
} }
} }
// PCS 아이템 목록 // PCS 아이템 목록
const getPcsItemList = () => { const getPcsItemList = (isMultiModule = false) => {
if (isMultiModule) {
return models
.filter((model) => model.pcsTpCd !== 'INDFCS')
.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
return models.map((model) => { return models.map((model) => {
return { return {
itemId: model.itemId, itemId: model.itemId,
@ -53,7 +64,18 @@ export function useCircuitTrestle(executeEffect = false) {
} }
// 선택된 PCS 아이템 목록 // 선택된 PCS 아이템 목록
const getSelectedPcsItemList = () => { const getSelectedPcsItemList = (isMultiModule = false) => {
if (isMultiModule) {
return selectedModels
.filter((model) => model.pcsTpCd !== 'INDFCS')
.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
return selectedModels.map((model) => { return selectedModels.map((model) => {
return { return {
itemId: model.itemId, itemId: model.itemId,
@ -95,6 +117,7 @@ export function useCircuitTrestle(executeEffect = false) {
uniqueId: module.id ? module.id : null, uniqueId: module.id ? module.id : null,
} }
}), }),
roofSurfaceNorthYn: obj.direction === 'north' ? 'Y' : 'N',
} }
}) })
.filter((surface) => surface.moduleList.length > 0) .filter((surface) => surface.moduleList.length > 0)

View File

@ -1089,6 +1089,7 @@
"module.circuit.minimun.error": "回路番号は1以上の数値を入力してください。", "module.circuit.minimun.error": "回路番号は1以上の数値を入力してください。",
"module.already.exist.error": "回路番号が同じで異なるパワーコンディショナのモジュールがあります。 別の回路番号を設定してください。", "module.already.exist.error": "回路番号が同じで異なるパワーコンディショナのモジュールがあります。 別の回路番号を設定してください。",
"module.circuit.fix.not.same.roof.error": "異なる屋根面のモジュールが選択されています。 モジュールの選択をや直してください。", "module.circuit.fix.not.same.roof.error": "異なる屋根面のモジュールが選択されています。 モジュールの選択をや直してください。",
"module.circuit.indoor.focused.error": "混合モジュールと屋内集中PCSを組み合わせる場合は、手動回路割り当てのみ対応可能です。",
"construction.length.difference": "屋根面工法をすべて選択してください。", "construction.length.difference": "屋根面工法をすべて選択してください。",
"menu.validation.canvas.roof": "パネルを配置するには、屋根面を入力する必要があります。", "menu.validation.canvas.roof": "パネルを配置するには、屋根面を入力する必要があります。",
"batch.object.outside.roof": "オブジェクトは屋根に設置する必要があります。", "batch.object.outside.roof": "オブジェクトは屋根に設置する必要があります。",

View File

@ -1089,6 +1089,7 @@
"module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.", "module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.",
"module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.", "module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.",
"module.circuit.fix.not.same.roof.error": "다른 지붕면의 모듈이 선택되어 있습니다. 모듈 선택을 다시 하세요.", "module.circuit.fix.not.same.roof.error": "다른 지붕면의 모듈이 선택되어 있습니다. 모듈 선택을 다시 하세요.",
"module.circuit.indoor.focused.error": "혼합 모듈과 실내 집중형 PCS를 조합하는 경우, 수동 회로 할당만 가능합니다.",
"construction.length.difference": "지붕면 공법을 모두 선택하십시오.", "construction.length.difference": "지붕면 공법을 모두 선택하십시오.",
"menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.", "menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.",
"batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.", "batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.",

View File

@ -460,7 +460,11 @@ button{
} }
} }
.table-select{
height: 20px;
color: #fff !important;
font-size: 11px !important;
}
// input // input
.form-input{ .form-input{
label{ label{

View File

@ -269,7 +269,7 @@ export const getDegreeByChon = (chon) => {
* @returns {number} * @returns {number}
*/ */
export const getChonByDegree = (degree) => { export const getChonByDegree = (degree) => {
return Number((Math.tan((degree * Math.PI) / 180) * 10).toFixed(1)) return Number((Math.tan((degree * Math.PI) / 180) * 10).toFixed(2))
} }
/** /**
@ -1036,11 +1036,11 @@ export const getDegreeInOrientation = (degree) => {
{ min: -51, max: -37, value: -45 }, { min: -51, max: -37, value: -45 },
{ min: -36, max: -22, value: -30 }, { min: -36, max: -22, value: -30 },
{ min: -21, max: -7, value: -15 }, { min: -21, max: -7, value: -15 },
{ min: -6, max: 0, value: 0 } { min: -6, max: 0, value: 0 },
] ]
// 해당 범위에 맞는 값 찾기 // 해당 범위에 맞는 값 찾기
const range = degreeRanges.find(range => degree >= range.min && degree <= range.max) const range = degreeRanges.find((range) => degree >= range.min && degree <= range.max)
return range ? range.value : degree return range ? range.value : degree
} }