diff --git a/src/common/common.js b/src/common/common.js index 4220e5f5..60a57c76 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -219,7 +219,8 @@ export const SAVE_KEY = [ 'originWidth', 'originHeight', 'skeletonLines', - 'skeleton' + 'skeleton', + 'viewportTransform', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype] diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index 4b718c05..63dc523a 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -2,7 +2,7 @@ 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 PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' @@ -11,7 +11,7 @@ import { useCanvas } from '@/hooks/useCanvas' import { usePlan } from '@/hooks/usePlan' import { useContextMenu } from '@/hooks/useContextMenu' import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize' -import { currentMenuState } from '@/store/canvasAtom' +import { canvasZoomState, currentMenuState } from '@/store/canvasAtom' import { totalDisplaySelector } from '@/store/settingAtom' import { POLYGON_TYPE } from '@/common/common' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' @@ -50,6 +50,7 @@ export default function CanvasFrame() { const resetSeriesState = useResetRecoilState(seriesState) const resetModelsState = useResetRecoilState(modelsState) const resetCompasDeg = useResetRecoilState(compasDegAtom) + const [zoom, setCanvasZoom] = useRecoilState(canvasZoomState) const resetSelectedModelsState = useResetRecoilState(selectedModelsState) const resetPcsCheckState = useResetRecoilState(pcsCheckState) const { handleModuleSelectionTotal } = useCanvasPopupStatusController() @@ -67,6 +68,13 @@ export default function CanvasFrame() { canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 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) { setTimeout(() => { setSelectedMenu('module') diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 6ddd94c7..97d878a0 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -2,7 +2,7 @@ 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' @@ -25,17 +25,18 @@ import { useCommonUtils } from '@/hooks/common/useCommonUtils' import useMenu from '@/hooks/common/useMenu' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' 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 { outerLinePointsState } from '@/store/outerLineAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' -import { - addedRoofsState, - basicSettingState, - corridorDimensionSelector, - selectedRoofMaterialSelector, - settingModalFirstOptionsState, -} from '@/store/settingAtom' +import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { commonUtilsState } from '@/store/commonUtilsAtom' import { menusState } from '@/store/menuAtom' @@ -51,6 +52,7 @@ import { QcastContext } from '@/app/QcastProvider' import { useRoofFn } from '@/hooks/common/useRoofFn' import { usePolygon } from '@/hooks/usePolygon' import { useTrestle } from '@/hooks/module/useTrestle' + export default function CanvasMenu(props) { const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const { selectedMenu, setSelectedMenu } = props @@ -515,7 +517,10 @@ export default function CanvasMenu(props) { if (createUser === 'T01' && sessionState.storeId !== 'T01') { setAllButtonStyles('none') } else { - setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg }) + setEstimateContextState({ + tempFlg: estimateRecoilState.tempFlg, + lockFlg: estimateRecoilState.lockFlg, + }) handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo) } } diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 3827e116..f86a7ead 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -227,11 +227,33 @@ export default function CircuitTrestleSetting({ id }) { 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 = { ...getOptYn(), useModuleItemList: getUseModuleItemList(), roofSurfaceList: getRoofSurfaceList(), - pcsItemList: getPcsItemList(), + pcsItemList: getPcsItemList(isMultiModule), } // 파워컨디셔너 추천 목록 조회 @@ -292,12 +314,12 @@ export default function CircuitTrestleSetting({ id }) { }) } else { // 회로 구성 가능 여부 체크 - getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList() }).then((res) => { + getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList(isMultiModule) }).then((res) => { if (res.resultCode === 'S') { // 회로 구성 가능 여부 체크 통과 시 승압설정 정보 조회 getPcsVoltageStepUpList({ ...params, - pcsItemList: getSelectedPcsItemList(), + pcsItemList: getSelectedPcsItemList(isMultiModule), }).then((res) => { if (res?.result.resultCode === 'S' && res?.data) { setTabNum(2) @@ -523,6 +545,7 @@ export default function CircuitTrestleSetting({ id }) { obj.circuit = null obj.pcsItemId = null obj.circuitNumber = null + obj.pcs = null }) setSelectedModels( JSON.parse(JSON.stringify(selectedModels)).map((model) => { diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index b0222aa3..5b956cc2 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -649,7 +649,13 @@ export default function StepUp(props) { style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} > {item.serQty} - {item.paralQty} + + {/* 2025.12.04 select 추가 */} + + + {/* {item.paralQty} */} ) })} diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx index 049efe10..22b0dd16 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -9,7 +9,7 @@ import { moduleStatisticsState } from '@/store/circuitTrestleAtom' import { fontSelector } from '@/store/fontAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' import { circuitNumDisplaySelector } from '@/store/settingAtom' -import { useContext, useEffect, useState } from 'react' +import { useContext, useEffect, useRef, useState } from 'react' import { useRecoilValue } from 'recoil' import { normalizeDigits } from '@/util/input-utils' @@ -32,6 +32,7 @@ export default function PassivityCircuitAllocation(props) { const { header, rows, footer } = useRecoilValue(moduleStatisticsState) const [circuitNumber, setCircuitNumber] = useState(1) const [targetModules, setTargetModules] = useState([]) + const targetModulesRef = useRef([]) const { getPcsManualConfChk } = useMasterController() const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector) const { setModuleStatisticsData } = useCircuitTrestle() @@ -59,6 +60,10 @@ export default function PassivityCircuitAllocation(props) { } }, []) + useEffect(() => { + targetModulesRef.current = targetModules + }, [targetModules]) + const handleTargetModules = (obj) => { if (!Array.isArray(targetModules)) { setTargetModules([]) @@ -79,6 +84,7 @@ export default function PassivityCircuitAllocation(props) { } const handleCircuitNumberFix = () => { + const pcsTpCd = selectedPcs.pcsTpCd // 실내집중형, 옥외멀티형 let uniqueCircuitNumbers = [ ...new Set( canvas @@ -91,13 +97,13 @@ export default function PassivityCircuitAllocation(props) { const surfaceList = targetModules.map((module) => { 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) { - let surfaceType = {} - - surfaceList.forEach((surface) => { - surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface - }) if (Object.keys(surfaceType).length > 1) { swalFire({ text: getMessage('module.circuit.fix.not.same.roof.error'), @@ -107,6 +113,7 @@ export default function PassivityCircuitAllocation(props) { return } } + if (!circuitNumber || circuitNumber === 0) { swalFire({ text: getMessage('module.circuit.minimun.error'), @@ -114,31 +121,65 @@ export default function PassivityCircuitAllocation(props) { icon: 'warning', }) return - } else if (targetModules.length === 0) { + } + + if (targetModules.length === 0) { swalFire({ text: getMessage('module.not.found'), type: 'alert', icon: 'warning', }) return - } else 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', + switch (pcsTpCd) { + case 'INDFCS': { + const originHaveThisPcsModules = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.pcs && obj.pcs.id === selectedPcs.id) + // 이미 해당 pcs로 설치된 모듈의 surface의 방향을 구한다. + const originSurfaceList = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && originHaveThisPcsModules.map((obj) => obj.surfaceId).includes(obj.id)) + + originSurfaceList.concat(originSurfaceList).forEach((surface) => { + surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface }) - 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, roofSurface: surface.direction, roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch, + roofSurfaceNorthYn: surface.direction === 'north' ? 'Y' : 'N', moduleList: surface.modules.map((module) => { return { itemId: module.moduleInfo.itemId, @@ -270,6 +312,12 @@ export default function PassivityCircuitAllocation(props) { 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([]) setCircuitNumber(+circuitNumber + 1) setModuleStatisticsData() diff --git a/src/components/floor-plan/modal/setting01/FirstOption.jsx b/src/components/floor-plan/modal/setting01/FirstOption.jsx index 51a52cdb..ef2d8e0b 100644 --- a/src/components/floor-plan/modal/setting01/FirstOption.jsx +++ b/src/components/floor-plan/modal/setting01/FirstOption.jsx @@ -1,8 +1,10 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect } from 'react' import { useMessage } from '@/hooks/useMessage' import { POLYGON_TYPE } from '@/common/common' import { useEvent } from '@/hooks/useEvent' import { useRoofFn } from '@/hooks/common/useRoofFn' +import { outlineDisplaySelector } from '@/store/settingAtom' +import { useRecoilValue } from 'recoil' export default function FirstOption(props) { const { getMessage } = useMessage() @@ -11,6 +13,7 @@ export default function FirstOption(props) { const { option1, option2, dimensionDisplay } = settingModalFirstOptions const { initEvent } = useEvent() const { setSurfaceShapePattern } = useRoofFn() + const outlineDisplay = useRecoilValue(outlineDisplaySelector) // 데이터를 최초 한 번만 조회 useEffect(() => { @@ -18,6 +21,13 @@ export default function FirstOption(props) { setSettingsDataSave({ ...settingsData }) }, []) + useEffect(() => { + const outline = canvas.getObjects().filter((obj) => obj.name === 'originRoofOuterLine') + outline.forEach((obj) => { + obj.visible = outlineDisplay + }) + }, [outlineDisplay]) + const onClickOption = async (item) => { let dimensionDisplay = settingModalFirstOptions?.dimensionDisplay let option1 = settingModalFirstOptions?.option1 @@ -58,7 +68,12 @@ export default function FirstOption(props) { // setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: [...options] }) } - setSettingsData({ ...settingsData, option1: [...option1], option2: [...option2], dimensionDisplay: [...dimensionDisplay] }) + setSettingsData({ + ...settingsData, + option1: [...option1], + option2: [...option2], + dimensionDisplay: [...dimensionDisplay], + }) } // useEffect(() => { diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index 7c53f98c..9fe5a221 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -31,8 +31,11 @@ export function useCommonUtils() { useEffect(() => { commonTextMode() if (commonUtils.dimension) { + generateTempGrid() commonDimensionMode() return + } else { + removeTempGrid() } if (commonUtils.distance) { commonDistanceMode() @@ -645,6 +648,7 @@ export function useCommonUtils() { lockMovementY: true, name: obj.name, editable: false, + selectable: true, // 복사된 객체 선택 가능하도록 설정 id: uuidv4(), //복사된 객체라 새로 따준다 }) @@ -653,19 +657,25 @@ export function useCommonUtils() { //배치면일 경우 if (obj.name === 'roof') { - clonedObj.setCoords() - clonedObj.fire('modified') - clonedObj.fire('polygonMoved') + clonedObj.canvas = canvas // canvas 참조 설정 clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial, + stroke: 'black', // 복사된 객체는 선택 해제 상태의 색상으로 설정 + selectable: true, // 선택 가능하도록 설정 + evented: true, // 마우스 이벤트를 받을 수 있도록 설정 + isFixed: false, // containsPoint에서 특별 처리 방지 }) obj.lines.forEach((line, index) => { clonedObj.lines[index].set({ attributes: line.attributes }) }) + clonedObj.fire('polygonMoved') // 내부 좌표 재계산 (points, pathOffset) + clonedObj.fire('modified') + clonedObj.setCoords() // 모든 속성 설정 후 좌표 업데이트 + canvas.setActiveObject(clonedObj) canvas.renderAll() addLengthText(clonedObj) //수치 추가 drawDirectionArrow(clonedObj) //방향 화살표 추가 @@ -905,6 +915,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 { commonFunctions, dimensionSettings, @@ -916,5 +965,7 @@ export function useCommonUtils() { editText, changeDimensionExtendLine, deleteOuterLineObject, + generateTempGrid, + removeTempGrid, } } diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 811d6fd6..3ea1894c 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -9,6 +9,7 @@ import { basicSettingState, correntObjectNoState, corridorDimensionSelector, + outlineDisplaySelector, roofDisplaySelector, roofMaterialsSelector, selectedRoofMaterialSelector, @@ -61,9 +62,11 @@ export function useRoofAllocationSetting(id) { const { saveCanvas } = usePlan() const [roofsStore, setRoofsStore] = useRecoilState(roofsState) const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) + const outerLinePoints = useRecoilValue(outerLinePointsState) const resetPoints = useResetRecoilState(outerLinePointsState) const [corridorDimension, setCorridorDimension] = useRecoilState(corridorDimensionSelector) const { changeCorridorDimensionText } = useText() + const outlineDisplay = useRecoilValue(outlineDisplaySelector) useEffect(() => { /** 배치면 초기설정에서 선택한 지붕재 배열 설정 */ @@ -305,11 +308,53 @@ export function useRoofAllocationSetting(id) { addPopup(popupId, 1, ) } else { apply() + //기존 지붕 선은 남겨둔다. + drawOriginRoofLine() resetPoints() + 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() + } + } + /** * 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우 */ diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index d991a2cf..cc4ac608 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -402,7 +402,8 @@ export function useCanvasEvent() { } } else { zoom = canvasZoom - 10 - if (zoom < 10) { //50%->10% + if (zoom < 10) { + //50%->10% return } } @@ -412,8 +413,33 @@ export function useCanvasEvent() { const handleZoomClear = () => { 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() } diff --git a/src/hooks/useCirCuitTrestle.js b/src/hooks/useCirCuitTrestle.js index a35d3c8c..83bb0b84 100644 --- a/src/hooks/useCirCuitTrestle.js +++ b/src/hooks/useCirCuitTrestle.js @@ -42,7 +42,18 @@ export function useCircuitTrestle(executeEffect = false) { } } // 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 { itemId: model.itemId, @@ -53,7 +64,18 @@ export function useCircuitTrestle(executeEffect = false) { } // 선택된 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 { itemId: model.itemId, @@ -95,6 +117,7 @@ export function useCircuitTrestle(executeEffect = false) { uniqueId: module.id ? module.id : null, } }), + roofSurfaceNorthYn: obj.direction === 'north' ? 'Y' : 'N', } }) .filter((surface) => surface.moduleList.length > 0) diff --git a/src/locales/ja.json b/src/locales/ja.json index db27c2ef..e738ebaa 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1089,6 +1089,7 @@ "module.circuit.minimun.error": "回路番号は1以上の数値を入力してください。", "module.already.exist.error": "回路番号が同じで異なるパワーコンディショナのモジュールがあります。 別の回路番号を設定してください。", "module.circuit.fix.not.same.roof.error": "異なる屋根面のモジュールが選択されています。 モジュールの選択をや直してください。", + "module.circuit.indoor.focused.error": "混合モジュールと屋内集中PCSを組み合わせる場合は、手動回路割り当てのみ対応可能です。", "construction.length.difference": "屋根面工法をすべて選択してください。", "menu.validation.canvas.roof": "パネルを配置するには、屋根面を入力する必要があります。", "batch.object.outside.roof": "オブジェクトは屋根に設置する必要があります。", diff --git a/src/locales/ko.json b/src/locales/ko.json index 4f6601cd..bed23c44 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1089,6 +1089,7 @@ "module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.", "module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.", "module.circuit.fix.not.same.roof.error": "다른 지붕면의 모듈이 선택되어 있습니다. 모듈 선택을 다시 하세요.", + "module.circuit.indoor.focused.error": "혼합 모듈과 실내 집중형 PCS를 조합하는 경우, 수동 회로 할당만 가능합니다.", "construction.length.difference": "지붕면 공법을 모두 선택하십시오.", "menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.", "batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.", diff --git a/src/styles/_reset.scss b/src/styles/_reset.scss index c0c4a2cb..472243ed 100644 --- a/src/styles/_reset.scss +++ b/src/styles/_reset.scss @@ -460,7 +460,11 @@ button{ } } - +.table-select{ + height: 20px; + color: #fff !important; + font-size: 11px !important; +} // input .form-input{ label{ diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 243936da..b2ee57db 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -269,7 +269,7 @@ export const getDegreeByChon = (chon) => { * @returns {number} */ 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: -36, max: -22, value: -30 }, { 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 }