diff --git a/src/common/common.js b/src/common/common.js index da50a5a8..cf6d37bf 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -182,6 +182,9 @@ export const SAVE_KEY = [ 'pcses', 'roofMaterial', 'isComplete', + 'moduleInfo', + 'circuitNumber', + 'circuit', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] diff --git a/src/components/floor-plan/CanvasFrame.jsx b/src/components/floor-plan/CanvasFrame.jsx index 5b3581e8..52553529 100644 --- a/src/components/floor-plan/CanvasFrame.jsx +++ b/src/components/floor-plan/CanvasFrame.jsx @@ -34,7 +34,7 @@ export default function CanvasFrame() { const currentMenu = useRecoilValue(currentMenuState) const { floorPlanState } = useContext(FloorPlanContext) const { contextMenu, handleClick } = useContextMenu() - const { currentCanvasPlan } = usePlan() + const { plans, currentCanvasPlan } = usePlan() const totalDisplay = useRecoilValue(totalDisplaySelector) // 집계표 표시 여부 const { setIsGlobalLoading } = useContext(QcastContext) const resetModuleStatisticsState = useResetRecoilState(moduleStatisticsState) @@ -48,11 +48,14 @@ export default function CanvasFrame() { const loadCanvas = () => { if (canvas) { canvas?.clear() // 캔버스를 초기화합니다. - if (currentCanvasPlan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) { - canvas?.loadFromJSON(JSON.parse(currentCanvasPlan.canvasStatus), function () { - canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 - canvas?.renderAll() // 캔버스를 다시 그립니다. - }) + if (currentCanvasPlan) { + const plan = plans.find((plan) => plan.id === currentCanvasPlan.id) + if (plan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) { + canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () { + canvasLoadInit() //config된 상태로 캔버스 객체를 그린다 + canvas?.renderAll() // 캔버스를 다시 그립니다. + }) + } } gridInit() } diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 6c29dd57..6adae9a8 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -7,8 +7,9 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting' import { usePopup } from '@/hooks/usePopup' import '@/styles/contents.scss' import { notFound, useSearchParams } from 'next/navigation' -import { useRecoilState } from 'recoil' +import { useRecoilState, useResetRecoilState } from 'recoil' import { correntObjectNoState } from '@/store/settingAtom' +import { currentMenuState } from '@/store/canvasAtom' export default function FloorPlan({ children }) { const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState) @@ -19,6 +20,12 @@ export default function FloorPlan({ children }) { const { closeAll } = usePopup() const { menuNumber, setMenuNumber } = useCanvasMenu() const { fetchSettings, fetchBasicSettings } = useCanvasSetting() + const resetCurrentMenu = useResetRecoilState(currentMenuState) + useEffect(() => { + return () => { + resetCurrentMenu() + } + }, []) // URL 파라미터에서 objectNo 설정 useEffect(() => { diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 60c2e168..84608186 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -24,6 +24,7 @@ import { useEstimate } from '@/hooks/useEstimate' import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useImgLoader } from '@/hooks/floorPlan/useImgLoader' +import { usePlan } from '@/hooks/usePlan' const ALLOCATION_TYPE = { AUTO: 'auto', @@ -53,6 +54,7 @@ export default function CircuitTrestleSetting({ id }) { const [seletedOption, setSeletedOption] = useState(null) const { handleCanvasToPng } = useImgLoader() + const { saveCanvas } = usePlan() const { makers, @@ -345,6 +347,9 @@ export default function CircuitTrestleSetting({ id }) { if (result) { handleCanvasToPng(2) setViewCircuitNumberTexts(true) + // 캔버스 저장 + await saveCanvas(false) + // 견적서 저장 await saveEstimate(result) } // removeNotAllocationModules() diff --git a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx index 1d28d7d0..06cab2f1 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx @@ -1,11 +1,12 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider' import QSelectBox from '@/components/common/select/QSelectBox' +import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useMasterController } from '@/hooks/common/useMasterController' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { pcsCheckState } from '@/store/circuitTrestleAtom' import { globalLocaleStore } from '@/store/localeAtom' -import { selectedModuleState } from '@/store/selectedModuleOptions' +import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' import { isNullOrUndefined } from '@/util/common-utils' import { useContext, useEffect, useState } from 'react' import { useRecoilState } from 'recoil' @@ -37,7 +38,8 @@ export default function PowerConditionalSelect(props) { const { getPcsMakerList, getPcsModelList } = useMasterController() const selectedModules = useRecoilValue(selectedModuleState) const { swalFire } = useSwal() - // const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) + const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2) + const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) const modelHeader = [ { name: getMessage('시리즈'), width: '15%', prop: 'pcsSerNm', type: 'color-box' }, { name: getMessage('명칭'), width: '15%', prop: 'goodsNo', type: 'color-box' }, @@ -66,7 +68,6 @@ export default function PowerConditionalSelect(props) { useEffect(() => { if (makers.length === 0) { getPcsMakerList().then((res) => { - console.log('getPcsMakerList', res.data) setMakers(res.data) }) } @@ -130,7 +131,12 @@ export default function PowerConditionalSelect(props) { const pcsSerList = selectedSeries.map((series) => { return { pcsSerCd: series.pcsSerCd } }) - const moduleItemList = getUseModuleItemList() + const moduleItemList = moduleSelectionData.module.itemList.map((item) => { + return { + itemId: item.itemId, + mixMatlNo: item.mixMatlNo, + } + }) getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList }).then((res) => { if (res?.result.code === 200 && res?.data) { setModels( @@ -179,7 +185,7 @@ export default function PowerConditionalSelect(props) { setSelectedMaker(option) const param = { pcsMkrCd: option.pcsMkrCd, - mixMatlNo: getUseModuleItemList()[0].mixMatlNo, + mixMatlNo: moduleSelectionData.module.mixMatlNo, } getPcsMakerList(param).then((res) => { 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 0463734c..635e1f8f 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -2,6 +2,7 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider' import { POLYGON_TYPE } from '@/common/common' import { useMasterController } from '@/hooks/common/useMasterController' import { useModule } from '@/hooks/module/useModule' +import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { canvasState } from '@/store/canvasAtom' @@ -28,9 +29,9 @@ export default function PassivityCircuitAllocation(props) { const { header, rows, footer } = useRecoilValue(moduleStatisticsState) const [circuitNumber, setCircuitNumber] = useState(1) const [targetModules, setTargetModules] = useState([]) - const { setModuleStatisticsData } = useModule() const { getPcsManualConfChk } = useMasterController() const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector) + const { setModuleStatisticsData } = useCircuitTrestle() useEffect(() => { setModuleStatisticsData() @@ -260,7 +261,6 @@ export default function PassivityCircuitAllocation(props) { return parseInt(circuitNumber[circuitNumber.length - 1]) }) const minCircuitNumber = Math.min(...circuitNumbers) - console.log(circuitNumbers, minCircuitNumber) canvas.remove(...circuitModules.map((module) => module.circuit)) circuitModules.forEach((obj) => { obj.circuit = null diff --git a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx index bb23102e..af66b672 100644 --- a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx +++ b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx @@ -50,9 +50,7 @@ export default function PanelBatchStatistics() { {rows.map((row, index) => ( {header.map((item, i) => ( - - {typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]} - + {row[item.prop] ?? 0} ))} ))} diff --git a/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx index 4a911e9e..2374c582 100644 --- a/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/ContextRoofAllocationSetting.jsx @@ -199,9 +199,10 @@ export default function ContextRoofAllocationSetting(props) { type="text" className="input-origin block" onChange={(e) => { - handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index) + // handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index) handleChangePitch(e, index) }} + value={currentAngleType === 'slope' ? roof.pitch : roof.angle} defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle} /> diff --git a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx index e9f4468c..acd2291c 100644 --- a/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx +++ b/src/components/floor-plan/modal/roofAllocation/RoofAllocationSetting.jsx @@ -201,6 +201,7 @@ export default function RoofAllocationSetting(props) { onChange={(e) => { handleChangePitch(e, index) }} + value={currentAngleType === 'slope' ? roof.pitch : roof.angle} defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle} /> diff --git a/src/hooks/common/useRoofFn.js b/src/hooks/common/useRoofFn.js index 2b81ea05..95af888c 100644 --- a/src/hooks/common/useRoofFn.js +++ b/src/hooks/common/useRoofFn.js @@ -307,5 +307,32 @@ export function useRoofFn() { return area.points.map((p) => fabric.util.transformPoint({ x: p.x - area.pathOffset.x, y: p.y - area.pathOffset.y }, area.calcTransformMatrix())) } - return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } + const removeOuterLines = (currentMousePos) => { + const roofBase = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.ROOF) + .filter((roof) => roof.inPolygon(currentMousePos)) + + if (roofBase.length === 0) { + return + } + + const roof = roofBase[0] + const wall = roof.wall + + canvas.remove(roof) + canvas.remove(wall) + + const allRoofObject = canvas + .getObjects() + .filter((obj) => /*obj !== roof && obj !== wall &&*/ obj.attributes?.roofId === roof.id || obj.parentId === roof.id || obj.parentId === wall.id) + + allRoofObject.forEach((obj) => { + canvas.remove(obj) + }) + + canvas.renderAll() + } + + return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines } } diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index 08e2146b..c4e456a9 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -1899,7 +1899,7 @@ export const useTrestle = () => { rackYn, racks: rackParams, rackTotCnt: rackList.length ?? 0 + smartRackGroup.length ?? 0, - rackFittingCnt: bracketList.length, + rackFittingTotCnt: bracketList.length, moduleRows: getMostLeftModules(surface), cvrYn: moduleSelection.construction.setupCover ? 'Y' : 'N', snowGdYn: moduleSelection.construction.setupSnowCover ? 'Y' : 'N', diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index ae8c78a0..c4fe1f39 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -495,7 +495,12 @@ export function useRoofAllocationSetting(id) { } const handleChangePitch = (e, index) => { - const value = e.target.value + let value = e.target.value + + const reg = /^[0-9]+(\.[0-9]{0,1})?$/ + if (!reg.test(value)) { + value = value.substring(0, value.length - 1) + } const newRoofList = currentRoofList.map((roof, idx) => { if (idx === index) { const result = diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js index 8ccd4b07..125d3d91 100644 --- a/src/hooks/roofcover/useRoofShapeSetting.js +++ b/src/hooks/roofcover/useRoofShapeSetting.js @@ -190,7 +190,9 @@ export function useRoofShapeSetting(id) { } case 4: { outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch + let isValid = outerLines.every((line) => line.attributes.isFixed) // 변별로 설정중 한쪽흐름일 경우 한쪽흐름의 pitch로 설정 if (pitch) { outerLines.forEach((line) => { @@ -203,6 +205,10 @@ export function useRoofShapeSetting(id) { } }) } + if (!isValid) { + swalFire({ text: '설정이 완료되지 않았습니다.', icon: 'error' }) + return + } break } diff --git a/src/hooks/useCirCuitTrestle.js b/src/hooks/useCirCuitTrestle.js index b72581b3..3b37d226 100644 --- a/src/hooks/useCirCuitTrestle.js +++ b/src/hooks/useCirCuitTrestle.js @@ -10,10 +10,11 @@ import { selectedModelsState, seriesState, } from '@/store/circuitTrestleAtom' -import { selectedModuleState } from '@/store/selectedModuleOptions' +import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' import { useContext } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useMessage } from './useMessage' +import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController' export function useCircuitTrestle() { const [makers, setMakers] = useRecoilState(makersState) @@ -25,7 +26,8 @@ export function useCircuitTrestle() { const selectedModules = useRecoilValue(selectedModuleState) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const canvas = useRecoilValue(canvasState) - + const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2) + const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) const setModuleStatistics = useSetRecoilState(moduleStatisticsState) const { getMessage } = useMessage() const getOptYn = () => { @@ -60,7 +62,7 @@ export function useCircuitTrestle() { // 사용된 모듈아이템 목록 const getUseModuleItemList = () => { console.log('🚀 ~ getUseModuleItemList ~ selectedModules:', selectedModules) - return selectedModules?.itemList?.map((m) => { + return moduleSelectionData.module?.itemList?.map((m) => { return { itemId: m.itemId, mixMatlNo: m.mixMatlNo, @@ -71,6 +73,10 @@ export function useCircuitTrestle() { // 지붕면 목록 const getRoofSurfaceList = () => { const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) + roofSurfaceList.forEach((surface) => { + surface.modules = modules.filter((module) => module.surfaceId === surface.id) + }) roofSurfaceList.sort((a, b) => a.left - b.left || b.top - a.top) return roofSurfaceList .map((obj) => { @@ -177,12 +183,17 @@ export function useCircuitTrestle() { const setPowerConditionerData = () => {} const setModuleStatisticsData = () => { - console.log(canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)) - if (selectedModules?.length === 0) return + const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) + roofSurfaceList.forEach((surface) => { + surface.modules = modules.filter((module) => module.surfaceId === surface.id) + }) + // console.log(moduleSelectionData) + if (!moduleSelectionData || !moduleSelectionData.module || moduleSelectionData.module?.itemList?.length === 0) return const tempHeader = [ { name: getMessage('simulator.table.sub1'), prop: 'name' }, { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' }, - ...selectedModules?.itemList?.map((module) => { + ...moduleSelectionData.module?.itemList?.map((module) => { return { name: module.itemNm, prop: module.itemId, @@ -236,7 +247,7 @@ export function useCircuitTrestle() { circuit: surfaceObjects[key].circuit, wpOut: parseFloat(surfaceObjects[key].wpOut / 1000), } - selectedModules.itemList.forEach((module) => { + moduleSelectionData.module.itemList.forEach((module) => { tempRow[module.itemId] = surfaceObjects[key][module.itemId] }) tempRows.push(tempRow) @@ -247,7 +258,7 @@ export function useCircuitTrestle() { circuit: surfaceObjects[key].circuits[circuit].circuit, wpOut: parseFloat(surfaceObjects[key].circuits[circuit].circuits.wpOut / 1000), } - selectedModules.itemList.forEach((module) => { + moduleSelectionData.module.itemList.forEach((module) => { row[module.itemId] = surfaceObjects[key].circuits[circuit].circuits[module.itemId] }) tempRows.push(row) @@ -259,8 +270,8 @@ export function useCircuitTrestle() { circuit: '-', wpOut: tempRows.reduce((acc, row) => acc + row.wpOut, 0), } - selectedModules.itemList.forEach((module) => { - tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0) + moduleSelectionData.module.itemList.forEach((module) => { + tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + (row[module.itemId] ?? 0), 0) }) canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) setModuleStatistics({ header: tempHeader, rows: tempRows.filter((row) => row.wpOut !== 0), footer: tempFooter }) diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index bb3c1683..38cdedc1 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -68,7 +68,7 @@ export function useContextMenu() { const { settingsData, setSettingsDataSave } = useCanvasSetting() const { swalFire } = useSwal() const { alignModule, modulesRemove, moduleRoofRemove } = useModule() - const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } = useRoofFn() + const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines } = useRoofFn() const currentMenuSetting = () => { switch (currentMenu) { @@ -150,7 +150,9 @@ export function useContextMenu() { { id: 'wallLineRemove', name: getMessage('contextmenu.wallline.remove'), - fn: () => deleteOuterLineObject(), + fn: (currentMousePos) => { + removeOuterLines(currentMousePos) + }, }, ], [ diff --git a/src/hooks/useEstimate.js b/src/hooks/useEstimate.js index e2ed851d..7abe27b1 100644 --- a/src/hooks/useEstimate.js +++ b/src/hooks/useEstimate.js @@ -5,7 +5,6 @@ import { useRecoilValue } from 'recoil' import { useAxios } from '@/hooks/useAxios' import { useSwal } from '@/hooks/useSwal' -import { usePlan } from '@/hooks/usePlan' import { GlobalDataContext } from '@/app/GlobalDataProvider' import { QcastContext } from '@/app/QcastProvider' import { currentCanvasPlanState } from '@/store/canvasAtom' @@ -20,7 +19,6 @@ export function useEstimate() { const { promisePost } = useAxios() const { swalFire } = useSwal() - const { saveCanvas } = usePlan() /** * 도면 견적서 저장 @@ -58,8 +56,7 @@ export function useEstimate() { await promisePost({ url: '/api/estimate/save-estimate', data: saveEstimateData }) .then(async () => { - // 견적서 저장이 완료되면 캔버스 저장 후 견적서 페이지로 이동 - await saveCanvas(false) + // 견적서 저장이 완료되면 견적서 페이지로 이동 moveEstimate(planNo, objectNo) }) .catch((error) => {