diff --git a/src/app/QcastProvider.js b/src/app/QcastProvider.js index 16a62d63..861ee8f9 100644 --- a/src/app/QcastProvider.js +++ b/src/app/QcastProvider.js @@ -3,7 +3,6 @@ import { createContext, useEffect, useState } from 'react' import { ErrorBoundary } from 'next/dist/client/components/error-boundary' import { useCommonCode } from '@/hooks/common/useCommonCode' -import { usePlan } from '@/hooks/usePlan' import ServerError from './error' import '@/styles/common.scss' @@ -19,7 +18,6 @@ export const QcastContext = createContext({ export const QcastProvider = ({ children }) => { const [planSave, setPlanSave] = useState(false) const [isGlobalLoading, setIsGlobalLoading] = useState(false) - const { currentCanvasPlan, modifiedPlans, checkUnsavedCanvasPlan } = usePlan() const { commonCode, findCommonCode } = useCommonCode() const [qcastState, setQcastState] = useState({ @@ -30,16 +28,6 @@ export const QcastProvider = ({ children }) => { businessChargerMail: null, }) - useEffect(() => { - const targetElement = document.getElementById('canvas') - if (!targetElement && currentCanvasPlan?.id && planSave) { - setPlanSave((prev) => !prev) - checkUnsavedCanvasPlan() - } else if (targetElement && currentCanvasPlan?.id) { - setPlanSave(true) - } - }, [modifiedPlans]) - // useEffect(() => { // console.log('commonCode', commonCode) // console.log(findCommonCode(113600)) diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index e3d185ec..6646aac6 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -36,7 +36,7 @@ export default function Playground() { const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL const { getMessage } = useMessage() const { swalFire } = useSwal() - const { getRoofMaterialList, getModuleTypeItemList } = useMasterController() + const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController() const [color, setColor] = useState('#ff0000') @@ -154,6 +154,41 @@ export default function Playground() { console.log('users:', users) }, [users]) + const trestleData = [{ moduleTpCd: '1', roofMatlCd: '2', raftBaseCd: '', trestleMkrCd: '4', constMthdCd: '', roofBaseCd: '6' }] + const constructionData = [ + { + moduleTpCd: '', + roofMatlCd: '', + trestleMkrCd: '', + constMthdCd: '', + roofBaseCd: '', + illuminationTp: '', + instHt: '', + stdWindSpeed: '', + stdSnowLd: '', + inclCd: '', + raftBaseCd: '', + roofPitch: 0, + }, + ] + const trestleDetailData = [ + { + moduleTpCd: '', + roofMatlCd: '', + trestleMkrCd: '', + constMthdCd: '', + roofBaseCd: '', + illuminationTp: '', + instHt: '', + stdWindSpeed: '', + stdSnowLd: '', + inclCd: '', + constTp: '', + mixMatlNo: 0, + roofPitch: 0, + }, + ] + return ( <>
@@ -166,7 +201,7 @@ export default function Playground() { }} > 지붕재 목록 조회 API 호출 - + {' '} {' '} + {' '} + {' '} +
+
{plans.length < 10 && ( - )} diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 5ed215f9..435fc762 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -41,6 +41,7 @@ import { pwrGnrSimTypeState } from '@/store/simulatorAtom' import { useAxios } from '@/hooks/useAxios' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' +import { isObjectNotEmpty } from '@/util/common-utils' export default function CanvasMenu(props) { const { menuNumber, setMenuNumber } = props @@ -78,6 +79,9 @@ export default function CanvasMenu(props) { const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext) const { restoreModuleInstArea } = useModuleBasicSetting() + //견적서버튼 노출용 + const [buttonStyle, setButtonStyle] = useState('') + const onClickNav = (menu) => { setMenuNumber(menu.index) setCurrentMenu(menu.title) @@ -241,6 +245,16 @@ export default function CanvasMenu(props) { }) } + useEffect(() => { + if (isObjectNotEmpty(estimateRecoilState)) { + if (estimateRecoilState?.createUser === 'T01') { + if (sessionState.userId !== 'T01') { + setButtonStyle('none') + } + } + } + }, [estimateRecoilState]) + return (
num === menuNumber) ? 'active' : ''}`}>
@@ -320,11 +334,12 @@ export default function CanvasMenu(props) { {getMessage('plan.menu.estimate.docDown')} - )} - diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index bba99266..95cb2fef 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -10,7 +10,7 @@ import { globalLocaleStore } from '@/store/localeAtom' import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' import { useMessage } from '@/hooks/useMessage' import { useForm } from 'react-hook-form' -import { useRecoilValue, useSetRecoilState, useResetRecoilState, useRecoilState } from 'recoil' +import { useRecoilValue, useSetRecoilState, useResetRecoilState } from 'recoil' import { SessionContext } from '@/app/SessionProvider' import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' @@ -41,7 +41,6 @@ export default function StuffDetail() { const { session } = useContext(SessionContext) const router = useRouter() - const pathname = usePathname() const searchParams = useSearchParams() const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index ab838335..27acf615 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -1,6 +1,6 @@ 'use client' -import { useContext, useEffect } from 'react' +import { useState, useContext, useEffect } from 'react' import Link from 'next/link' import Image from 'next/image' @@ -11,20 +11,37 @@ import { useSetRecoilState } from 'recoil' import { QcastContext } from '@/app/QcastProvider' import { useMessage } from '@/hooks/useMessage' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import { queryStringFormatter } from '@/util/common-utils' +import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' + +import { ManagementContext } from '@/app/management/ManagementProvider' +import { SessionContext } from '@/app/SessionProvider' export default function StuffSubHeader({ type }) { const { getMessage } = useMessage() const router = useRouter() + const { session } = useContext(SessionContext) const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) const { isGlobalLoading } = useContext(QcastContext) + const { managementState } = useContext(ManagementContext) + + const [buttonStyle, setButtonStyle] = useState('') useEffect(() => { window.scrollTo(0, 0) }, []) + useEffect(() => { + if (isObjectNotEmpty(managementState)) { + if (managementState.createUser === 'T01') { + if (session.userId !== 'T01') { + setButtonStyle('none') + } + } + } + }, [managementState]) + const searchParams = useSearchParams() const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set @@ -98,7 +115,7 @@ export default function StuffSubHeader({ type }) { {getMessage('stuff.temp.subTitle')} -
  • +
  • {getMessage('stuff.temp.subTitle2')} diff --git a/src/hooks/common/useCommonCode.js b/src/hooks/common/useCommonCode.js index bab32007..fc902ef2 100644 --- a/src/hooks/common/useCommonCode.js +++ b/src/hooks/common/useCommonCode.js @@ -39,10 +39,6 @@ export const useCommonCode = () => { return resultCodes } - useEffect(() => { - findCommonCode() - }, [globalLocale]) - useEffect(() => { const getCommonCode = async () => { await promiseGet({ url: '/api/commcode/qc-comm-code' }).then((res) => { diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js index ced80244..f03ff639 100644 --- a/src/hooks/common/useMasterController.js +++ b/src/hooks/common/useMasterController.js @@ -1,5 +1,7 @@ import { useAxios } from '@/hooks/useAxios' -import axios from 'axios' +import { useMessage } from '@/hooks/useMessage' +import { useSwal } from '@/hooks/useSwal' +import { getQueryString } from '@/util/common-utils' /** * 마스터 컨트롤러 훅 @@ -7,6 +9,8 @@ import axios from 'axios' */ export function useMasterController() { const { get } = useAxios() + const { getMessage } = useMessage() + const { swalFire } = useSwal() /** * 지붕재 목록 조회 @@ -21,11 +25,17 @@ export function useMasterController() { /** * 모듈 타입별 아이템 목록 조회 - * @param {지붕재 코드} roofMaterialCd + * @param {지붕재 코드} roofMatlCd * @returns */ - const getModuleTypeItemList = async (roofMaterialCd) => { - return await get({ url: `/api/v1/master/getModuleTypeItemList/${roofMaterialCd}` }).then((res) => { + const getModuleTypeItemList = async (roofMatlCd) => { + if (!roofMatlCd || roofMatlCd.trim() === '') { + swalFire({ text: getMessage('master.moduletypeitem.message.error'), type: 'alert', icon: 'error' }) + return null + } + const param = { roofMatlCd: roofMatlCd } + const paramString = getQueryString(param) + return await get({ url: `/api/v1/master/getModuleTypeItemList${paramString}` }).then((res) => { console.log('🚀🚀 ~ getModuleTypeItemList ~ res:', res) return res }) @@ -33,11 +43,25 @@ export function useMasterController() { /** * 가대 목록 조회 - * @param + * @param {모듈타입코드} moduleTpCd + * @param {지붕재코드} roofMatlCd + * @param {서까래기초코드} raftBaseCd + * @param {가대메이커코드} trestleMkrCd + * @param {공법코드} constMthdCd + * @param {지붕기초코드} roofBaseCd * @returns */ const getTrestleList = async (params) => { - return await get({ url: `/api/v1/master/getTrestleList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getTrestleList ~ params:', params) + params = getQueryString({ + moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '', + roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '', + raftBaseCd: params.raftBaseCd ? params.raftBaseCd : '', + trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '', + constMthdCd: params.constMthdCd ? params.constMthdCd : '', + roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '', + }) + return await get({ url: '/api/v1/master/getTrestleList' + params }).then((res) => { console.log('🚀🚀 ~ getTrestleList ~ res:', res) return res }) @@ -45,11 +69,38 @@ export function useMasterController() { /** * 모듈 시공법 목록 조회 - * @param + * @param {모듈타입코드} moduleTpCd + * @param {지붕재코드} roofMatlCd + * @param {가대메이커코드} trestleMkrCd + * @param {공법코드} constMthdCd + * @param {지붕기초코드} roofBaseCd + * @param {면조도} illuminationTp + * @param {설치높이} instHt + * @param {풍속} stdWindSpeed + * @param {적설량} stdSnowLd + * @param {경사도코드} inclCd + * @param {서까래기초코드} raftBaseCd + * @param {하제(망둥어)피치} roofPitch + * * @returns */ const getConstructionList = async (params) => { - return await get({ url: `/api/v1/master/getConstructionList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getConstructionList ~ params:', params) + params = getQueryString({ + moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '', + roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '', + trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '', + constMthdCd: params.constMthdCd ? params.constMthdCd : '', + roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '', + illuminationTp: params.illuminationTp ? params.illuminationTp : '', + instHt: params.instHt ? params.instHt : '', + stdWindSpeed: params.stdWindSpeed ? params.stdWindSpeed : '', + stdSnowLd: params.stdSnowLd ? params.stdSnowLd : '', + inclCd: params.inclCd ? params.inclCd : '', + raftBaseCd: params.raftBaseCd ? params.raftBaseCd : '', + roofPitch: params.roofPitch ? params.roofPitch : 0, + }) + return await get({ url: '/api/v1/master/getConstructionList' + params }).then((res) => { console.log('🚀🚀 ~ getConstructionList ~ res:', res) return res }) @@ -57,11 +108,39 @@ export function useMasterController() { /** * 가대 상세 조회 - * @param + * @param {모듈타입코드} moduleTpCd + * @param {지붕재코드} roofMatlCd + * @param {가대메이커코드} trestleMkrCd + * @param {공법코드} constMthdCd + * @param {지붕기초코드} roofBaseCd + * @param {면조도} illuminationTp + * @param {설치높이} instHt + * @param {풍속} stdWindSpeed + * @param {적설량} stdSnowLd + * @param {경사도코드} inclCd + * @param {시공법} constTp + * @param {혼합모듈번호} mixMatlNo + * @param {하제(망둥어)피치}roofPitch * @returns */ const getTrestleDetailList = async (params) => { - return await get({ url: `/api/v1/master/getTrestleDetailList/${params}` }).then((res) => { + console.log('🚀🚀 ~ getConstructionList ~ params:', params) + params = getQueryString({ + moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '', + roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '', + trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '', + constMthdCd: params.constMthdCd ? params.constMthdCd : '', + roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '', + illuminationTp: params.illuminationTp ? params.illuminationTp : '', + instHt: params.instHt ? params.instHt : '', + stdWindSpeed: params.stdWindSpeed ? params.stdWindSpeed : '', + stdSnowLd: params.stdSnowLd ? params.stdSnowLd : '', + inclCd: params.inclCd ? params.inclCd : '', + constTp: params.constTp ? params.constTp : '', + mixMatlNo: params.mixMatlNo ? params.mixMatlNo : 0, + roofPitch: params.roofPitch ? params.roofPitch : 0, + }) + return await get({ url: '/api/v1/master/getTrestleDetailList' + params }).then((res) => { console.log('🚀🚀 ~ getTrestleDetailList ~ res:', res) return res }) diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index ced2e72b..6e06212e 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -5,6 +5,7 @@ import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' +import { getDegreeByChon } from '@/util/canvas-util' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -227,6 +228,20 @@ export function useMovementSetting(id) { } }) polygon.set({ points: newPoints }) + polygon.setCoords() + polygon.addLengthText() + polygon.initLines() + const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1)) + const currentDegree = polygon.attributes.pitch > 0 ? getDegreeByChon(polygon.attributes.pitch) : polygon.attributes.degree + polygon.lines.forEach((line) => { + line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10) + if (currentDegree > 0 && slope(line) !== slope(currentObject)) { + const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize + line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2))) + } else { + line.attributes.actualSize = line.attributes.planeSize + } + }) }) } else { roof.innerLines @@ -239,7 +254,7 @@ export function useMovementSetting(id) { (line.x2 === currentX2 && line.y2 === currentY2), ) .forEach((line) => { - console.log('line : ', line) + const lineDegree = 90 - Math.asin(line.attributes.planeSize / line.attributes.actualSize) * (180 / Math.PI) if (line.x1 === currentX1 && line.y1 === currentY1) { line.set({ x1: newPoint[0], y1: newPoint[1] }) } else if (line.x2 === currentX1 && line.y2 === currentY1) { @@ -250,20 +265,18 @@ export function useMovementSetting(id) { line.set({ x2: newPoint[2], y2: newPoint[3] }) } line.setCoords() + line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10) + line.attributes.actualSize = Math.round( + Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(line.attributes.planeSize * Math.tan(lineDegree * (Math.PI / 180)), 2)), + ) }) } currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 }) currentObject.setCoords() - console.log('currentObject : ', currentObject.x1, currentObject.y1, currentObject.x2, currentObject.y2) - canvas.renderAll() canvas.discardActiveObject() - - if (roof.separatePolygon.length > 0) { - console.log('roof.separatePolygon : ', roof.separatePolygon) - } } //형 올림내림 마우스 클릭 이벤트 diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 0e8cd64b..7ea3e03c 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -3,7 +3,6 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' import { canvasSizeState, canvasState, canvasZoomState, currentObjectState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' -import { usePlan } from '@/hooks/usePlan' import { fontSelector } from '@/store/fontAtom' // 캔버스에 필요한 이벤트 @@ -14,7 +13,6 @@ export function useCanvasEvent() { const canvasSize = useRecoilValue(canvasSizeState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const lengthTextOption = useRecoilValue(fontSelector('lengthText')) - const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan() useEffect(() => { canvas?.setZoom(canvasZoom / 100) @@ -40,10 +38,6 @@ export function useCanvasEvent() { onChange: (e) => { const target = e.target - if (target.name !== 'mouseLine' && !modifiedPlanFlag) { - setModifiedPlanFlag((prev) => !prev) - } - if (target) { // settleDown(target) } @@ -58,10 +52,6 @@ export function useCanvasEvent() { target.uuid = uuidv4() } - if (target.name !== 'mouseLine' && !modifiedPlanFlag) { - setModifiedPlanFlag((prev) => !prev) - } - if (target.type === 'QPolygon' || target.type === 'QLine') { const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText') textObjs.forEach((obj) => { @@ -164,9 +154,6 @@ export function useCanvasEvent() { target.on('moving', (e) => { target.uuid = uuidv4() - if (!modifiedPlanFlag) { - setModifiedPlanFlag((prev) => !prev) - } if (target.parentDirection === 'left' || target.parentDirection === 'right') { const minX = target.minX diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 532759a4..b49d1eca 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useRecoilState } from 'recoil' import { v4 as uuidv4 } from 'uuid' -import { canvasState, currentCanvasPlanState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom' +import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' @@ -12,14 +12,11 @@ import { useCanvas } from '@/hooks/useCanvas' export function usePlan() { const [planNum, setPlanNum] = useState(0) const [selectedPlan, setSelectedPlan] = useState(null) - const [currentCanvasStatus, setCurrentCanvasStatus] = useState(null) const [canvas, setCanvas] = useRecoilState(canvasState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [plans, setPlans] = useRecoilState(plansState) // 전체 plan - const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan - const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag const { swalFire } = useSwal() const { getMessage } = useMessage() @@ -95,64 +92,6 @@ export function usePlan() { return addCanvas() } - /** - * 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 확인 후 관리 - */ - const checkCanvasObjectEvent = (planId) => { - setCurrentCanvasStatus(currentCanvasData()) - if (!modifiedPlans.some((modifiedPlan) => modifiedPlan === planId) && checkModifiedCanvasPlan(planId)) { - setModifiedPlans((prev) => [...prev, planId]) - setModifiedPlanFlag(false) - } - } - useEffect(() => { - if (currentCanvasStatus) { - setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus })) - } - }, [currentCanvasStatus]) - - /** - * 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 - */ - const checkModifiedCanvasPlan = (planId) => { - const planData = plans.find((plan) => plan.id === planId) - if (planData.canvasStatus === '') { - // 빈 상태로 저장된 캔버스 - return true - } - - // 각각 object들의 uuid 목록을 추출하여 비교 - const canvasStatus = currentCanvasData() - const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects) - const dbObjsUuids = getObjectUuids(JSON.parse(planData.canvasStatus).objects) - return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index]) - } - const getObjectUuids = (objects) => { - return objects - .filter((obj) => obj.hasOwnProperty('uuid')) - .map((obj) => obj.uuid) - .sort() - } - - const resetModifiedPlans = () => { - setModifiedPlans([]) - setModifiedPlanFlag(false) - } - - /** - * 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 후 저장 - */ - const checkUnsavedCanvasPlan = async () => { - swalFire({ - text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.save.modified'), - type: 'confirm', - confirmFn: async () => { - await putCanvasStatus(currentCanvasPlan.canvasStatus) - }, - }) - resetModifiedPlans() - } - /** * DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화 */ @@ -206,8 +145,8 @@ export function usePlan() { } await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData }) .then((res) => { - setPlans([...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }]) - handleCurrentPlan(res.data) + setPlans((plans) => [...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }]) + updateCurrentPlan(res.data) setPlanNum(planNum + 1) }) .catch((error) => { @@ -228,7 +167,6 @@ export function usePlan() { await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData }) .then((res) => { setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) - setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) @@ -251,13 +189,11 @@ export function usePlan() { /** * plan 이동 - * 현재 plan의 작업상태를 확인, 저장 후 이동 + * 현재 plan의 작업상태를 저장 후 이동 */ const handleCurrentPlan = async (newCurrentId) => { if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) { - if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) { - await saveCanvas() - } + await saveCanvas() updateCurrentPlan(newCurrentId) } } @@ -281,9 +217,12 @@ export function usePlan() { /** * 새로운 plan 생성 - * 현재 plan의 데이터가 있을 경우 복제 여부를 확인 + * 현재 plan의 데이터가 있을 경우 현재 plan 저장 및 복제 여부를 확인 */ const handleAddPlan = async (userId, objectNo) => { + if (currentCanvasPlan?.id) { + await saveCanvas() + } JSON.parse(currentCanvasData()).objects.length > 0 ? swalFire({ text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.copy'), @@ -324,7 +263,6 @@ export function usePlan() { await delCanvasById(id) .then((res) => { setPlans((plans) => plans.filter((plan) => plan.id !== id)) - setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) removeImage(currentCanvasPlan.id) swalFire({ text: getMessage('plan.message.delete') }) }) @@ -362,14 +300,6 @@ export function usePlan() { canvas, plans, selectedPlan, - currentCanvasPlan, - setCurrentCanvasPlan, - modifiedPlans, - modifiedPlanFlag, - setModifiedPlanFlag, - checkCanvasObjectEvent, - checkUnsavedCanvasPlan, - resetModifiedPlans, saveCanvas, handleCurrentPlan, handleAddPlan, diff --git a/src/locales/ja.json b/src/locales/ja.json index 243418a8..ff40d26b 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -295,7 +295,6 @@ "modal.actual.size.setting.plane.size.length": "廊下の寸法の長さ", "modal.actual.size.setting.actual.size.length": "実寸長", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", - "plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.save": "저장되었습니다.", @@ -932,5 +931,6 @@ "simulator.table.sub8": "台", "simulator.table.sub9": "予測発電量 (kWh)", "simulator.notice.sub1": "Hanwha Japan 年間発電量", - "simulator.notice.sub2": "シミュレーション案内事項" + "simulator.notice.sub2": "シミュレーション案内事項", + "master.moduletypeitem.message.error": "지붕재 코드를 입력하세요." } diff --git a/src/locales/ko.json b/src/locales/ko.json index 495fe2dc..8260419f 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -300,7 +300,6 @@ "modal.actual.size.setting.plane.size.length": "복도치수 길이", "modal.actual.size.setting.actual.size.length": "실제치수 길이", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?", - "plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.save": "저장되었습니다.", @@ -942,5 +941,6 @@ "simulator.table.sub8": "대", "simulator.table.sub9": "예측발전량 (kWh)", "simulator.notice.sub1": "Hanwha Japan 연간 발전량", - "simulator.notice.sub2": "시뮬레이션 안내사항" + "simulator.notice.sub2": "시뮬레이션 안내사항", + "master.moduletypeitem.message.error": "지붕재 코드를 입력하세요." } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index b0e21d41..89f7e14d 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -272,17 +272,6 @@ export const plansState = atom({ default: [], }) -// 변경된 canvas plan 목록 -export const modifiedPlansState = atom({ - key: 'modifiedPlansState', - default: [], -}) -// 변경감지 flag -export const modifiedPlanFlagState = atom({ - key: 'modifiedPlanFlagState', - default: false, -}) - export const tempGridModeState = atom({ key: 'tempGridModeState', default: false, diff --git a/src/styles/_test.scss b/src/styles/_test.scss index e84a5eda..c7ecff96 100644 --- a/src/styles/_test.scss +++ b/src/styles/_test.scss @@ -1,84 +1,84 @@ -.test { - background-color: #797979; - font: 30px sans-serif; - font-style: italic; - color: white; -} - -.grid-container2 { - display: grid; - grid-template-columns: repeat(2, 1fr); /* 2개의 열 */ - grid-template-rows: repeat(6, 30px); /* 6개의 행 */ - justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ - align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ - gap: 5px; /* 그리드 아이템 사이의 간격 */ -} - -.grid-container3 { - display: grid; - grid-template-columns: repeat(3, 1fr); /* 3개의 열 */ - grid-template-rows: repeat(6, 30px); /* 6개의 행 */ - justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ - align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ - gap: 5px; /* 그리드 아이템 사이의 간격 */ -} - -.grid-container4 { - display: grid; - grid-template-columns: repeat(4, 1fr); /* 4개의 열 */ - grid-template-rows: repeat(6, 30px); /* 6개의 행 */ - justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ - align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ - gap: 5px; /* 그리드 아이템 사이의 간격 */ -} - -.grid-container5 { - display: grid; - grid-template-columns: repeat(5, 1fr); /* 5개의 열 */ - grid-template-rows: repeat(5, 30px); /* 5개의 행 */ - justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ - align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ - gap: 0px; /* 그리드 아이템 사이의 간격 */ -} - -.grid-item { - width: 100%; - height: 100%; - border: 1px solid black; /* 그리드 외각선 */ - text-align: center; /* 그리드 내 가운데 정렬 */ -} - -.grid-item2 { - padding: 20px; - text-align: center; - cursor: pointer; - border: 1px solid #000; -} - -.grid-item3 { - padding: 20px; - text-align: center; - cursor: pointer; - border: 1px solid #000; - transition: background-color 0.3s ease; -} - -.grid-item.Y { - background-color: #d3d0d0; - color: black; -} - -.grid-item.N { - background-color: white; - color: black; -} - -.grid-item.selected { - background-color: #d3d0d0; - color: black; -} - -.grid-item.unselected { - background-color: white; - color: black; -} +.test { + background-color: #797979; + font: 30px sans-serif; + font-style: italic; + color: white; +} + +.grid-container2 { + display: grid; + grid-template-columns: repeat(2, 1fr); /* 2개의 열 */ + grid-template-rows: repeat(6, 30px); /* 6개의 행 */ + justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ + align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ + gap: 5px; /* 그리드 아이템 사이의 간격 */ +} + +.grid-container3 { + display: grid; + grid-template-columns: repeat(3, 1fr); /* 3개의 열 */ + grid-template-rows: repeat(6, 30px); /* 6개의 행 */ + justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ + align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ + gap: 5px; /* 그리드 아이템 사이의 간격 */ +} + +.grid-container4 { + display: grid; + grid-template-columns: repeat(4, 1fr); /* 4개의 열 */ + grid-template-rows: repeat(6, 30px); /* 6개의 행 */ + justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ + align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ + gap: 5px; /* 그리드 아이템 사이의 간격 */ +} + +.grid-container5 { + display: grid; + grid-template-columns: repeat(5, 1fr); /* 5개의 열 */ + grid-template-rows: repeat(5, 30px); /* 5개의 행 */ + justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ + align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ + gap: 0px; /* 그리드 아이템 사이의 간격 */ +} + +.grid-item { + width: 100%; + height: 100%; + border: 1px solid black; /* 그리드 외각선 */ + text-align: center; /* 그리드 내 가운데 정렬 */ +} + +.grid-item2 { + padding: 20px; + text-align: center; + cursor: pointer; + border: 1px solid #000; +} + +.grid-item3 { + padding: 20px; + text-align: center; + cursor: pointer; + border: 1px solid #000; + transition: background-color 0.3s ease; +} + +.grid-item.Y { + background-color: #d3d0d0; + color: black; +} + +.grid-item.N { + background-color: white; + color: black; +} + +.grid-item.selected { + background-color: #d3d0d0; + color: black; +} + +.grid-item.unselected { + background-color: white; + color: black; +} diff --git a/src/util/common-utils.js b/src/util/common-utils.js index 06b96b60..95e6be87 100644 --- a/src/util/common-utils.js +++ b/src/util/common-utils.js @@ -117,3 +117,15 @@ export const calculateFlowDirection = (canvasAngle) => { right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle, } } + +/** + * 자바스크립트 객체로 쿼리스트링 생성 + * @param {javascript object} o 쿼리스트링 생성할 객체 + * @returns {string} 쿼리스트링 + */ +export const getQueryString = (o) => { + const queryString = Object.keys(o) + .map((key) => `${key}=${o[key]}`) + .join('&') + return `?${queryString}` +} diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index b2253953..63c04e89 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1109,7 +1109,6 @@ const drawHips = (roof, canvas) => { const vectorX2 = ridgeCoordinate.x1 - currentRoof.x2 const vectorY2 = ridgeCoordinate.y1 - currentRoof.y2 const angle2 = Math.atan2(vectorY2, vectorX2) * (180 / Math.PI) - console.log('angle2', Math.abs(Math.round(angle2)) % 45) if (Math.abs(Math.round(angle2)) % 45 === 0) { const hip2 = new QLine([currentRoof.x2, currentRoof.y2, ridgeCoordinate.x1, ridgeCoordinate.y1], { fontSize: roof.fontSize,