diff --git a/src/common/common.js b/src/common/common.js index 9aad21d6..0424fcfd 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -187,6 +187,7 @@ export const SAVE_KEY = [ 'circuit', 'onlyOffset', 'isChidory', + 'textVisible', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index aedb141b..deb95caf 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -22,7 +22,7 @@ import { usePlan } from '@/hooks/usePlan' import { usePopup } from '@/hooks/usePopup' import { useSwal } from '@/hooks/useSwal' import { QcastContext } from '@/app/QcastProvider' - +import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' export default function Estimate({}) { const [uniqueData, setUniqueData] = useState([]) const [handlePricingFlag, setHandlePricingFlag] = useState(false) @@ -87,7 +87,7 @@ export default function Estimate({}) { const { getMessage } = useMessage() const { closeAll } = usePopup() - + const { setMenuNumber } = useCanvasMenu() //새로 추가한 첨부파일 props const fileUploadProps = { uploadFiles: files, @@ -119,8 +119,6 @@ export default function Estimate({}) { if (estimateContextState?.itemList.length > 0) { tempList = estimateContextState.itemList.filter((item) => !res.some((resItem) => resItem.itemId === item.itemId)) updatedRes = [...res, ...tempList] - // console.log('tempList::::::::', tempList) - // console.log('updatedRes::::::::', updatedRes) } else { updatedRes = [...res] } @@ -144,6 +142,7 @@ export default function Estimate({}) { }, [selectedPlan]) useEffect(() => { + setMenuNumber(5) initEstimate() }, []) @@ -1130,6 +1129,14 @@ export default function Estimate({}) { setSpecialNoteFirstFlg(false) }, [estimateContextState.resetFlag]) + useEffect(() => { + if (estimateContextState?.itemList.length > 0) { + const tempList = estimateContextState.itemList.filter((item) => !displayItemList.some((resItem) => resItem.itemId === item.itemId)) + if (tempList.length > 0) { + setDisplayItemList((prevList) => [...prevList, ...tempList]) + } + } + }, [estimateContextState]) return (
@@ -1140,7 +1147,6 @@ export default function Estimate({}) {
{getMessage('estimate.detail.objectNo')}
- {/* {objectNo} (Plan No: {estimateContextState.planNo}) */} {currentObjectNo} (Plan No: {planNo})
@@ -1569,9 +1575,7 @@ export default function Estimate({}) { {/* 견적특이사항 선택한 내용 영역끝 */}
- {/* 견적 특이사항 코드영역 끝 */} - {/* 견적특이사항 영역끝 */} {/* 제품정보 시작 */}
@@ -1581,10 +1585,6 @@ export default function Estimate({}) {
- {/*
-
{getMessage('estimate.detail.sepcialEstimateProductInfo.totAmount')}
-
{convertNumberToPriceDecimal(estimateContextState?.totAmount)}
-
*/}
{getMessage('estimate.detail.sepcialEstimateProductInfo.totVolKw')}
{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}
@@ -1603,6 +1603,7 @@ export default function Estimate({}) {
+ {/* //todo: 추후 YJSS가 다시 나타날 경우 주석 풀기 */} {/* YJOD면 아래영역 숨김 */} {/*
@@ -1883,7 +1884,6 @@ export default function Estimate({}) {
- {/* html테이블끝 */} diff --git a/src/components/estimate/popup/EstimateCopyPop.jsx b/src/components/estimate/popup/EstimateCopyPop.jsx index 6ff2e540..3bc25c74 100644 --- a/src/components/estimate/popup/EstimateCopyPop.jsx +++ b/src/components/estimate/popup/EstimateCopyPop.jsx @@ -296,7 +296,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) { type="button" className="btn-origin navy mr5" onClick={() => { - handleEstimateCopy(sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId) + handleEstimateCopy(sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId, setEstimateCopyPopupOpen) }} > {getMessage('estimate.detail.estimateCopyPopup.copyBtn')} diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 7fc1afc1..9c9791c9 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -13,6 +13,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { area: 0, children: [], padding: 5, + textVisible: true, initialize: function (points, options, length = 0) { // 소수점 전부 제거 @@ -29,6 +30,7 @@ export const QLine = fabric.util.createClass(fabric.Line, { this.idx = options.idx ?? 0 this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 }) this.textMode = options.textMode ?? 'plane' // plane:복시도, actual:실측, none:표시안함 + this.textVisible = options.textVisible ?? true if (length !== 0) { this.length = length } else { @@ -40,6 +42,9 @@ export const QLine = fabric.util.createClass(fabric.Line, { }, init: function () { + if (!this.textVisible) { + return + } this.addLengthText() this.on('moving', () => { diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 23e0de55..b0c46798 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -177,6 +177,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { attributes: { offset: 0, }, + textVisible: false, parent: this, parentId: this.id, direction: getDirectionByPoint(point, nextPoint), diff --git a/src/components/floor-plan/CanvasMenu.jsx b/src/components/floor-plan/CanvasMenu.jsx index 59f2b673..1ed413cf 100644 --- a/src/components/floor-plan/CanvasMenu.jsx +++ b/src/components/floor-plan/CanvasMenu.jsx @@ -171,8 +171,6 @@ export default function CanvasMenu(props) { await reloadCanvasStatus(objectNo, pid) break case 3: - console.log('🚀 ~ onClickNav ~ menu:', menu) - console.log('🚀 ~ onClickNav ~ menuNumber:', menuNumber) if (menuNumber > menu.index) { const modules = canvas.getObjects().filter((module) => module.name === POLYGON_TYPE.MODULE) if (modules.length > 0) { @@ -199,6 +197,7 @@ export default function CanvasMenu(props) { return }, }) + return } else { setType('surface') } @@ -217,21 +216,24 @@ export default function CanvasMenu(props) { } } else { router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`) + setType('module') } await reloadCanvasStatus(objectNo, pid) break case 5: setIsGlobalLoading(true) - //로딩바해제는 견적서 상세조회쪽(useEstimateController.js)에서 setIsGlobalLoading(false) promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => { if (res.status === 200) { const estimateDetail = res.data - // if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) { if (estimateDetail.estimateDate !== null) { setMenuNumber(menu.index) setCurrentMenu(menu.title) setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) + setIsGlobalLoading(false) router.push(`/floor-plan/estimate/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`) + if (pathname === '/floor-plan/estimate/5') { + setIsGlobalLoading(false) + } } else { setIsGlobalLoading(false) swalFire({ text: getMessage('estimate.menu.move.valid1') }) @@ -241,7 +243,6 @@ export default function CanvasMenu(props) { break case 6: setIsGlobalLoading(true) - //로딩바해제는 발전시뮬레이션 조회쪽에서(Simulator.jsx) setIsGlobalLoading(false) promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => { if (res.status === 200) { const estimateDetail = res.data @@ -249,6 +250,9 @@ export default function CanvasMenu(props) { setMenuNumber(menu.index) setCurrentMenu(menu.title) router.push(`/floor-plan/simulator/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`) + if (pathname === '/floor-plan/simulator/6') { + setIsGlobalLoading(false) + } } else { setIsGlobalLoading(false) swalFire({ text: getMessage('simulator.menu.move.valid1') }) @@ -435,21 +439,16 @@ export default function CanvasMenu(props) { useEffect(() => { if (isObjectNotEmpty(estimateContextState)) { - const { createUser, tempFlg, lockFlg } = estimateContextState - + const { createUser, tempFlg, lockFlg, docNo } = estimateContextState if (createUser && tempFlg && lockFlg) { - if (createUser === 'T01') { - if (sessionState.storeId !== 'T01') { - setAllButtonStyles('none') - } else { - handleButtonStyles(tempFlg, lockFlg) - } + if (createUser === 'T01' && sessionState.storeId !== 'T01') { + setAllButtonStyles('none') } else { - handleButtonStyles(tempFlg, lockFlg) + handleButtonStyles(tempFlg, lockFlg, docNo) } } } - }, [estimateContextState?.createUser, estimateContextState?.tempFlg, estimateContextState?.lockFlg]) + }, [estimateContextState?.createUser, estimateContextState?.tempFlg, estimateContextState?.lockFlg, estimateContextState.docNo]) const setAllButtonStyles = (style) => { setButtonStyle1(style) @@ -459,7 +458,7 @@ export default function CanvasMenu(props) { setButtonStyle5(style) } - const handleButtonStyles = (tempFlg, lockFlg) => { + const handleButtonStyles = (tempFlg, lockFlg, docNo) => { if (tempFlg === '1') { setAllButtonStyles('none') setButtonStyle2('') @@ -472,6 +471,9 @@ export default function CanvasMenu(props) { setButtonStyle4('') setButtonStyle5('') } + if (!docNo) { + setButtonStyle1('none') + } } /** @@ -500,16 +502,11 @@ export default function CanvasMenu(props) { estimateRecoilState.lockFlg = estimateRecoilState.lockFlg === '0' ? '1' : '0' const { createUser, tempFlg, lockFlg } = estimateRecoilState if (createUser && tempFlg && lockFlg) { - if (createUser === 'T01') { - if (sessionState.storeId !== 'T01') { - setAllButtonStyles('none') - } else { - setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg }) - handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg) - } + if (createUser === 'T01' && sessionState.storeId !== 'T01') { + setAllButtonStyles('none') } else { setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg }) - handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg) + handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo) } } } @@ -573,16 +570,26 @@ export default function CanvasMenu(props) {
{ { - return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp } - })} - //showKey={'roofMatlNm'} + title={ + +basicSetting.roofSizeSet === 3 + ? getMessage('modal.placement.initial.setting.size.none.pitch') + : globalLocale === 'ko' + ? selectedRoofMaterial?.roofMatlNm + : selectedRoofMaterial?.roofMatlNmJp + } + options={ + +basicSetting.roofSizeSet === 3 + ? [] + : addedRoofs.map((roof) => { + return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp } + }) + } showKey={'name'} value={selectedRoofMaterial} onChange={changeSelectedRoofMaterial} sourceKey={'index'} targetKey={'index'} + disabled={+basicSetting.roofSizeSet === 3} /> }
diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index a7f26838..5cc8b7ba 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -1,5 +1,5 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' -import { useState, useEffect, useContext } from 'react' +import { useState, useEffect, useContext, useRef } from 'react' import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect' import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp' import { useMessage } from '@/hooks/useMessage' @@ -33,7 +33,7 @@ const ALLOCATION_TYPE = { export default function CircuitTrestleSetting({ id }) { const { getMessage } = useMessage() const { closePopup } = usePopup() - const { apply, setViewCircuitNumberTexts, getEstimateData } = useTrestle() + const { apply, setViewCircuitNumberTexts, getEstimateData, clear: clearTrestle } = useTrestle() const { swalFire } = useSwal() const { saveEstimate } = useEstimate() const canvas = useRecoilValue(canvasState) @@ -43,7 +43,7 @@ export default function CircuitTrestleSetting({ id }) { const [circuitAllocationType, setCircuitAllocationType] = useState(1) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const selectedModules = useRecoilValue(selectedModuleState) - const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList } = useMasterController() + const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList, getPcsManualConfChk } = useMasterController() // 회로할당(승합설정)에서 선택된 값들을 저장할 상태 추가 const [selectedStepUpValues, setSelectedStepUpValues] = useState({}) @@ -53,10 +53,9 @@ export default function CircuitTrestleSetting({ id }) { const [stepUpListData, setStepUpListData] = useState([]) const [seletedOption, setSeletedOption] = useState(null) const { setModuleStatisticsData } = useCircuitTrestle() - const { handleCanvasToPng } = useImgLoader() const { saveCanvas } = usePlan() - + const passivityCircuitAllocationRef = useRef() const { setIsGlobalLoading } = useContext(QcastContext) const { @@ -385,6 +384,7 @@ export default function CircuitTrestleSetting({ id }) { obj.pcsItemId = null obj.circuitNumber = null }) + setSelectedModels(JSON.parse(JSON.stringify(selectedModels)).map((model) => (model.isUsed = false))) if (allocationType === ALLOCATION_TYPE.PASSIVITY) { setAllocationType(ALLOCATION_TYPE.AUTO) @@ -392,6 +392,7 @@ export default function CircuitTrestleSetting({ id }) { } else { setTabNum(1) } + clearTrestle() canvas.renderAll() setModuleStatisticsData() @@ -479,16 +480,18 @@ export default function CircuitTrestleSetting({ id }) { } const handleStepUp = () => { - const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit) - if (notAllocationModules.length > 0) { - swalFire({ - title: getMessage('not.allocation.exist.module'), - type: 'alert', - }) - return - } else { - setTabNum(2) - } + handlePassivityAllocationCkeck() + // const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit) + // if (notAllocationModules.length > 0) { + // swalFire({ + // title: getMessage('not.allocation.exist.module'), + // type: 'alert', + // }) + // return + // } else { + // passivityCircuitAllocationRef.current.onApply() + // setTabNum(2) + // } } // 닫기 버튼 클릭 시 처리하는 함수 추가 @@ -510,6 +513,83 @@ export default function CircuitTrestleSetting({ id }) { closePopup(id) } + const handlePassivityAllocationCkeck = () => { + let pcsCount = {} + let result = {} + canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE) + .forEach((module) => { + const circuitNumber = module.circuitNumber.replace(/[()]/g, '') + pcsCount[circuitNumber] = (pcsCount[circuitNumber] || 0) + 1 + }) + for (const key in pcsCount) { + const firstPart = key.split('-')[0] // '-' 기준으로 첫 번째 부분을 추출 + const value = pcsCount[key] + + // 그룹이 없으면 초기화 + if (!result[firstPart]) { + result[firstPart] = { maxValue: value, count: 1 } + } else { + // 이미 그룹이 있으면 큰 값으로 갱신, count는 증가 + result[firstPart].maxValue = Math.max(result[firstPart].maxValue, value) + result[firstPart].count += 1 + } + } + const params = { + ...getOptYn(), + useModuleItemList: getUseModuleItemList(), + roofSurfaceList: getRoofSurfaceList(), + pcsItemList: selectedModels.map((model, index) => { + return { + pcsMkrCd: model.pcsMkrCd, + pcsSerCd: model.pcsSerCd, + itemId: model.itemId, + itemNm: model.itemNm, + goodsNo: model.goodsNo, + serQtyList: [ + { + serQty: result[index + 1].maxValue, + paralQty: result[index + 1].count, + rmdYn: 'Y', + usePossYn: 'Y', + roofSurfaceList: canvas + .getObjects() + .filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0) + .map((surface) => { + return { + roofSurfaceId: surface.id, + roofSurface: surface.direction, + roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch, + moduleList: surface.modules.map((module) => { + return { + itemId: module.moduleInfo.itemId, + circuit: module.circuitNumber, + pcsItemId: module.pcsItemId, + } + }), + } + }), + }, + ], + } + }), + } + + getPcsManualConfChk(params).then((res) => { + if (res?.resultCode === 'E') { + swalFire({ + text: res.resultMsg, + type: 'alert', + icon: 'warning', + }) + return + } else { + setTabNum(2) + } + }) + } + return (
@@ -531,7 +611,9 @@ export default function CircuitTrestleSetting({ id }) {
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && } - {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && } + {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && ( + + )} {tabNum === 2 && } {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index d8fa01e5..239487e9 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -322,7 +322,7 @@ export default function StepUp(props) { moduleList: formatModuleList(rsf.moduleList), roofSurface: rsf.roofSurface ? rsf.roofSurface : '', roofSurfaceId: rsf.roofSurfaceId ? rsf.roofSurfaceId : '', - roofSurfaceIncl: rsf.roofSurfaceIncl ? rsf.roofSurfaceIncl : '', + roofSurfaceIncl: rsf.roofSurfaceIncl ? +rsf.roofSurfaceIncl : '', })) } // PCS MatModule 포맷 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 6ec3ba25..a526f05a 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -15,6 +15,7 @@ import { useRecoilState, useRecoilValue } from 'recoil' export default function PassivityCircuitAllocation(props) { const { + setTabNum, selectedModels, setSelectedModels, getOptYn: getApiProps, @@ -88,14 +89,14 @@ export default function PassivityCircuitAllocation(props) { ] if (!circuitNumber || circuitNumber === 0) { swalFire({ - text: '회로번호를 1 이상입력해주세요.', + text: getMessage('module.circuit.minimun.error'), type: 'alert', icon: 'warning', }) return } else if (targetModules.length === 0) { swalFire({ - text: '모듈을 선택해주세요.', + text: getMessage('module.not.found'), type: 'alert', icon: 'warning', }) @@ -113,7 +114,7 @@ export default function PassivityCircuitAllocation(props) { }) if (result) { swalFire({ - text: '회로 번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로 번호를 설정하십시오.', + text: getMessage('module.already.exist.error'), type: 'alert', icon: 'warning', }) @@ -175,7 +176,7 @@ export default function PassivityCircuitAllocation(props) { return { roofSurfaceId: surface.id, 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, moduleList: surface.modules.map((module) => { return { itemId: module.moduleInfo.itemId, @@ -185,7 +186,30 @@ export default function PassivityCircuitAllocation(props) { }), } }) + let pcsCount = {} + let result = {} + canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE) + .forEach((module) => { + if (module.circuitNumber) { + const circuitNumber = module.circuitNumber.replace(/[()]/g, '') + pcsCount[circuitNumber] = (pcsCount[circuitNumber] || 0) + 1 + } + }) + for (const key in pcsCount) { + const firstPart = key.split('-')[0] // '-' 기준으로 첫 번째 부분을 추출 + const value = pcsCount[key] + // 그룹이 없으면 초기화 + if (!result[firstPart]) { + result[firstPart] = { maxValue: value, count: 1 } + } else { + // 이미 그룹이 있으면 큰 값으로 갱신, count는 증가 + result[firstPart].maxValue = Math.max(result[firstPart].maxValue, value) + result[firstPart].count += 1 + } + } const usedPcses = pcsList.filter((model) => model.isUsed) const pcsItemList = usedPcses.map((model, index) => { return { @@ -196,8 +220,8 @@ export default function PassivityCircuitAllocation(props) { goodsNo: model.goodsNo, serQtyList: [ { - serQty: targetModules.length, - paralQty: uniqueCircuitNumbers.length, + serQty: result[index + 1].maxValue, + paralQty: result[index + 1].count, rmdYn: 'Y', usePossYn: 'Y', roofSurfaceList: roofSurfaceList, @@ -262,12 +286,13 @@ export default function PassivityCircuitAllocation(props) { const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id) const circuitNumbers = circuitModules.map((obj) => { const circuitNumber = obj.circuitNumber.replace(/[()]/g, '').split('-') - return parseInt(circuitNumber[circuitNumber.length - 1]) + return parseInt(circuitNumber[0]) }) const minCircuitNumber = Math.min(...circuitNumbers) canvas.remove(...circuitModules.map((module) => module.circuit)) circuitModules.forEach((obj) => { obj.circuit = null + obj.circuitNumber = null obj.pcsItemId = null }) setCircuitNumber(minCircuitNumber) @@ -293,15 +318,184 @@ export default function PassivityCircuitAllocation(props) { canvas.remove(...circuitModules.map((module) => module.circuit)) circuitModules.forEach((obj) => { obj.circuit = null + obj.circuitNumber = null obj.pcsItemId = null }) canvas.renderAll() + setCircuitNumber(1) setTargetModules([]) setModuleStatisticsData() }, }) } + const onApply = () => { + let uniqueCircuitNumbers = [ + ...new Set( + canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuitNumber) + .map((obj) => obj.circuitNumber), + ), + ] + if (!circuitNumber || circuitNumber === 0) { + swalFire({ + text: getMessage('module.circuit.minimun.error'), + type: 'alert', + icon: 'warning', + }) + return + } else 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', + }) + return + } + } + + let tempSelectedPcs = { ...selectedPcs } + canvas.discardActiveObject() + canvas + .getObjects() + .filter((obj) => targetModules.includes(obj.id)) + .forEach((obj) => { + if (obj.circuit) { + canvas.remove(obj.circuit) + } + const moduleCircuitText = new fabric.Text(getCircuitNumber(), { + left: obj.left + obj.width / 2, + top: obj.top + obj.height / 2, + fontFamily: circuitNumberText.fontFamily.value, + fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal', + fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', + fontSize: circuitNumberText.fontSize.value, + fill: circuitNumberText.fontColor.value, + width: obj.width, + height: obj.height, + textAlign: 'center', + originX: 'center', + originY: 'center', + name: 'circuitNumber', + selectable: false, + parentId: obj.id, + circuitInfo: selectedPcs, + visible: isDisplayCircuitNumber, + }) + obj.set({ + strokeWidth: 0.3, + }) + obj.pcsItemId = selectedPcs.itemId + obj.pcsItemCode = selectedPcs.id + obj.circuit = moduleCircuitText + obj.circuitNumber = getCircuitNumber() + tempSelectedPcs.used = true + setSelectedPcs(tempSelectedPcs) + canvas.add(moduleCircuitText) + }) + + let pcsList = JSON.parse(JSON.stringify(selectedModels)).map((model) => { + if (model.id === selectedPcs.id) { + model.isUsed = true + } + return model + }) + + const roofSurfaceList = canvas + .getObjects() + .filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0) + .map((surface) => { + return { + roofSurfaceId: surface.id, + roofSurface: surface.direction, + roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch, + moduleList: surface.modules.map((module) => { + return { + itemId: module.moduleInfo.itemId, + circuit: module.circuitNumber, + pcsItemId: module.pcsItemId, + } + }), + } + }) + const usedPcses = pcsList.filter((model) => model.isUsed) + const pcsItemList = usedPcses.map((model, index) => { + return { + pcsMkrCd: model.pcsMkrCd, + pcsSerCd: model.pcsSerCd, + itemId: model.itemId, + itemNm: model.itemNm, + goodsNo: model.goodsNo, + serQtyList: [ + { + serQty: targetModules.length, + paralQty: uniqueCircuitNumbers.length, + rmdYn: 'Y', + usePossYn: 'Y', + roofSurfaceList: roofSurfaceList, + }, + ], + } + }) + + const params = { + ...getApiProps(), + useModuleItemList: getSelectedModuleList(), + pcsItemList: pcsItemList, + } + + getPcsManualConfChk(params).then((res) => { + if (res?.resultCode === 'E') { + swalFire({ + text: res.resultMsg, + type: 'alert', + icon: 'warning', + confirmFn: () => { + const circuitNumbers = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber' && targetModules.includes(obj.parentId)) + canvas.remove(...circuitNumbers) + canvas + .getObjects() + .filter((obj) => obj.name === 'module' && targetModules.includes(obj.id)) + .forEach((obj) => { + obj.pcsItemId = null + obj.circuit = null + obj.circuitNumber = null + }) + canvas.renderAll() + }, + }) + setSelectedPcs({ ...selectedPcs, used: false }) + setTargetModules([]) + return + } + + setSelectedModels(pcsList) + + setTargetModules([]) + setModuleStatisticsData() + setTabNum(2) + }) + } + return ( <>
diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 9f8c54b2..140c9abd 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -170,6 +170,10 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla } const handleRoofLayoutChange = (value) => { + if (+currentRoof.roofSizeSet === 3) { + setCurrentRoof({ ...currentRoof, layout: ROOF_MATERIAL_LAYOUT.PARALLEL }) + return + } setCurrentRoof({ ...currentRoof, layout: value }) } @@ -451,7 +455,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
+
+
+
+
+
{getMessage('modal.canvas.setting.roofline.properties.setting.info')}
+
+
{getMessage('setting')}
+
+ + + +
+
+
+ + +
+
+
+
+ + ) +} diff --git a/src/components/floor-plan/modal/placementSurface/PlacementSurface.jsx b/src/components/floor-plan/modal/placementSurface/PlacementSurface.jsx index c06386b5..7ab89106 100644 --- a/src/components/floor-plan/modal/placementSurface/PlacementSurface.jsx +++ b/src/components/floor-plan/modal/placementSurface/PlacementSurface.jsx @@ -11,23 +11,42 @@ const PlacementSurface = forwardRef((props, refs) => { const num = ['①', '②', '③', '④', '⑤'] const getImageUrl = () => { + // re_는 normal의 y축 대칭 이미지 + const imageName = id < 10 ? '0' + id : id + let imageRotate = 0 if (xInversion && !yInversion) { - return `/static/images/canvas/shape/re_${rotate % 4 !== 0 ? Math.abs(rotate % 4) * 90 + 'deg' : 'normal'}/plane_tab${id < 10 ? '0' + id : id}.svg` + if (rotate % 2 === 0 || rotate < 0) { + imageRotate = Math.abs(rotate % 4) + } else { + if (rotate < 0) { + imageRotate = Math.abs((rotate - 2) % 4) + } else { + imageRotate = Math.abs((rotate + 2) % 4) + } + } + } else if (xInversion && yInversion) { + imageRotate = Math.abs((rotate + 4) % 4) + } else if (xInversion !== yInversion && rotate < 0) { + imageRotate = Math.abs(rotate) + } else if (!xInversion && yInversion) { + if (rotate % 2 === 0 || rotate < 0) { + imageRotate = Math.abs(rotate % 4) + } else { + if (rotate < 0) { + imageRotate = Math.abs((rotate - 2) % 4) + } else { + imageRotate = Math.abs((rotate + 2) % 4) + } + } + } else { + imageRotate = (rotate + 4) % 4 } - - if (!xInversion && yInversion) { - return `/static/images/canvas/shape/re_${rotate % 4 !== 0 ? Math.abs(rotate % 4) * 90 + 'deg' : 'normal'}/plane_tab${id < 10 ? '0' + id : id}.svg` + const rotateType = imageRotate % 4 !== 0 ? (imageRotate % 4) * 90 + 'deg' : 'normal' + if (xInversion !== yInversion) { + return `/static/images/canvas/shape/re_${rotateType}/plane_tab${imageName}.svg` + } else { + return `/static/images/canvas/shape/${rotateType}/plane_tab${imageName}.svg` } - - if (xInversion && yInversion) { - return `/static/images/canvas/shape/${rotate % 4 !== 0 ? Math.abs(rotate % 4) * 90 + 'deg' : 'normal'}/plane_tab${id < 10 ? '0' + id : id}.svg` - } - - if (rotate < 0) { - return `/static/images/canvas/shape/${rotate !== 0 ? Math.abs((rotate + 4) * 90) + 'deg' : 'normal'}/plane_tab${id < 10 ? '0' + id : id}.svg` - } - - return `/static/images/canvas/shape/${rotate !== 0 ? Math.abs(rotate * 90) + 'deg' : 'normal'}/plane_tab${id < 10 ? '0' + id : id}.svg` } const azimuthButton = (direction, e) => { diff --git a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx index 58ab430a..967d849e 100644 --- a/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx +++ b/src/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting.jsx @@ -239,12 +239,11 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } }) applySurfaceShape(surfaceRefs, selectedType, id) } - const handleRotate = () => {} - const handleInversion = (type) => { if (type === 'x') { + const x = xInversion setXInversion(!xInversion) - setRotate(xInversion ? rotate + 2 : rotate - 2) + setRotate(x ? rotate + 2 : rotate - 2) // setXInversion(!xInversion) } else if (type === 'y') { // setRotate(rotate + 2) @@ -295,6 +294,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
+ {/* */} {/* */} diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 748de71c..a95f34d2 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -229,9 +229,8 @@ export default function StuffDetail() { }, { // 가대 - // field: 'supportMethodIdMulti', - field: 'standTypeNo', - headerName: getMessage('stuff.detail.planGridHeader.standTypeNo'), + field: 'supportMethodIdMulti', + headerName: getMessage('stuff.detail.planGridHeader.supportMethodIdMulti'), wrapText: true, autoHeight: true, cellStyle: { alignItems: 'flex-start' /* 좌측정렬*/, cursor: 'pointer' }, @@ -291,15 +290,14 @@ export default function StuffDetail() { buttonStyle = 'none' buttonStyle2 = 'none' } else { - if (params?.data?.createSaleStoreId === 'T01') { - if (session?.storeId !== 'T01') { - buttonStyle = 'none' - } + if (params?.data?.createSaleStoreId === 'T01' && session?.storeId !== 'T01') { + buttonStyle = 'none' } - if (params?.data?.tempFlg === '1') { + if (params?.data?.tempFlg === '1' || !params?.data?.docNo) { buttonStyle2 = 'none' } } + return ( <>
diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx index 58be659c..05c00a13 100644 --- a/src/components/management/StuffSearchCondition.jsx +++ b/src/components/management/StuffSearchCondition.jsx @@ -761,6 +761,15 @@ export default function StuffSearchCondition() { setSchSelSaleStoreId('') setOtherSaleStoreId('') } else { + setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo) + setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName) + setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName) + setObjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName) + setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser) + setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address) + setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType) + setStartDate(stuffSearch?.schFromDt ? stuffSearch.schFromDt : dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')) + setEndDate(stuffSearch?.schToDt ? stuffSearch.schToDt : dayjs(new Date()).format('YYYY-MM-DD')) setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg) } } else { diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index bb6f48b9..368926a2 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -8,7 +8,6 @@ import { useRouter, useSearchParams } from 'next/navigation' import { useSetRecoilState } from 'recoil' -import { QcastContext } from '@/app/QcastProvider' import { useMessage } from '@/hooks/useMessage' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' @@ -24,8 +23,6 @@ export default function StuffSubHeader({ type }) { const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) - const { isGlobalLoading } = useContext(QcastContext) - const { managementState } = useContext(GlobalDataContext) const [buttonStyle, setButtonStyle] = useState('') @@ -70,7 +67,7 @@ export default function StuffSubHeader({ type }) {
{type === 'list' && ( <> - +

{getMessage('header.menus.management')}

    @@ -92,7 +89,7 @@ export default function StuffSubHeader({ type }) { <>
    • - + {getMessage('stuff.temp.subTitle')}
    • @@ -116,7 +113,7 @@ export default function StuffSubHeader({ type }) { <>
      • - + {getMessage('stuff.temp.subTitle')}
      • diff --git a/src/hooks/common/useCommonUtils.js b/src/hooks/common/useCommonUtils.js index da5d558d..b7e944c5 100644 --- a/src/hooks/common/useCommonUtils.js +++ b/src/hooks/common/useCommonUtils.js @@ -591,8 +591,8 @@ export function useCommonUtils() { //배치면일 경우 if (obj.name === 'roof') { clonedObj.setCoords() - clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial }) clonedObj.fire('polygonMoved') + clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial }) canvas.renderAll() addLengthText(clonedObj) //수치 추가 drawDirectionArrow(clonedObj) //방향 화살표 추가 diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 10d90416..4a3bf0c2 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -83,6 +83,10 @@ export const useEstimateController = (planNo, flag) => { res.data.pkgAsp = roundedNumber.toString() } setEstimateContextState(res.data) + } else { + swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' }) + setIsLoading(true) + setIsGlobalLoading(false) } } }) @@ -90,8 +94,7 @@ export const useEstimateController = (planNo, flag) => { setIsGlobalLoading(false) } catch (error) { console.error('견적서 상세조회 Error: ', error) - - swalFire({ text: getMessage('estimate.menu.move.valid1') }) + swalFire({ text: getMessage('stuff.detail.header.notExistObjectNo'), type: 'alert', icon: 'error' }) setIsLoading(true) setIsGlobalLoading(false) } @@ -415,7 +418,7 @@ export const useEstimateController = (planNo, flag) => { * (견적서 번호(estimateData.docNo)가 생성된 이후 버튼 활성화 ) * T01관리자 계정 및 1차판매점에게만 제공 */ - const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId) => { + const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId, setEstimateCopyPopupOpen) => { //todo: 추후 YJSS가 다시 나타날 경우 아래 swalFire 제거 필요 if (estimateData.estimateType === 'YJSS') { return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' }) @@ -455,6 +458,7 @@ export const useEstimateController = (planNo, flag) => { text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'), type: 'alert', confirmFn: () => { + setEstimateCopyPopupOpen(false) //팝업닫고 router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false }) }, }) diff --git a/src/hooks/module/useModuleSelection.js b/src/hooks/module/useModuleSelection.js index 26bac8e8..23c201b0 100644 --- a/src/hooks/module/useModuleSelection.js +++ b/src/hooks/module/useModuleSelection.js @@ -1,4 +1,4 @@ -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { useContext, useEffect, useState } from 'react' import { GlobalDataContext } from '@/app/GlobalDataProvider' import { useMasterController } from '@/hooks/common/useMasterController' @@ -7,6 +7,7 @@ import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDat import { isObjectNotEmpty } from '@/util/common-utils' import { canvasState } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' +import { moduleStatisticsState } from '@/store/circuitTrestleAtom' export function useModuleSelection(props) { const canvas = useRecoilValue(canvasState) @@ -25,6 +26,7 @@ export function useModuleSelection(props) { const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등 const { getModuleTypeItemList } = useMasterController() const { findCommonCode } = useCommonCode() + const resetStatisticsData = useResetRecoilState(moduleStatisticsState) const bindInitData = () => { setInstallHeight(managementState?.installHeight) @@ -98,6 +100,7 @@ export function useModuleSelection(props) { canvas.remove(moduleSurface) }) canvas.renderAll() + resetStatisticsData() } }, []) diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index ebbfd7cf..17f58814 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -710,7 +710,7 @@ export const useTrestle = () => { slope, classType: currentAngleType === 'slope' ? '0' : '1', angle: getDegreeByChon(slope), - azimuth: surfaceCompass ?? moduleCompass ?? 0, + azimuth: getAzimuth(surface), moduleList, } }) @@ -726,6 +726,70 @@ export const useTrestle = () => { return { itemList, northArrangement, roofSurfaceList, circuitItemList } } + const getAzimuth = (surface) => { + const { moduleCompass, surfaceCompass, direction } = surface + + if (surfaceCompass) { + if (surfaceCompass > 180) { + return surfaceCompass - 360 + } + return surfaceCompass + } + + switch (direction) { + case 'south': { + if (moduleCompass < 0) { + return -1 * moduleCompass + } else if (moduleCompass === 0) { + return 0 + } else if (moduleCompass < 180) { + return -1 * moduleCompass + } else if (moduleCompass === 180) { + return 180 + } + } + case 'north': { + if (moduleCompass < 0) { + return -1 * (180 + moduleCompass) + } else if (moduleCompass === 0) { + return 180 + } else if (moduleCompass < 180) { + return 180 - moduleCompass + } else if (moduleCompass === 180) { + return 0 + } + } + case 'west': { + if (moduleCompass > -180 && moduleCompass < -90) { + return -180 - (90 + moduleCompass) + } else if (moduleCompass < 0) { + return 180 - (90 + moduleCompass) + } else if (moduleCompass === 0) { + return 90 + } else if (moduleCompass < 180) { + return 90 - moduleCompass + } else if (moduleCompass === 180) { + return -90 + } + } + case 'east': { + if (moduleCompass < 0) { + return -(90 + moduleCompass) + } else if (moduleCompass === 0) { + return -90 + } else if (moduleCompass < 90) { + return -180 + (90 - moduleCompass) + } else if (moduleCompass < 180) { + return 180 + (90 - moduleCompass) + } else if (moduleCompass === 180) { + return 90 + } + } + } + + return 0 + } + const getNorthArrangement = () => { const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) let northArrangement = '0' @@ -2086,7 +2150,7 @@ export const useTrestle = () => { moduleTpCd: module.itemTp, roofMatlCd: parent.roofMaterial.roofMatlCd, mixMatlNo: module.mixMatlNo, - raftBaseCd: addRoof.raft, + raftBaseCd: addRoof.raft ?? addRoof.raftBaseCd, inclCd: addRoof.pitch, roofPitch: !addRoof.roofPchBase ? addRoof.roofPchBase : Number(addRoof.roofPchBase), exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수 @@ -2354,6 +2418,9 @@ export const useTrestle = () => { if ((rightModule && !leftModule) || (!rightModule && leftModule)) { // 둘중 하나가 없는경우는 처마커버 노출 추가 moduleRowResultData.exposedSideEavesCnt++ + } else if (!rightModule && !leftModule) { + // 양쪽 둘다 없는경우는 처마커버 노출 2개 추가 + moduleRowResultData.exposedSideEavesCnt += 2 } } } diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 5df718ec..37161700 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -140,8 +140,6 @@ export function useCanvasSetting() { const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) // 선택된 지붕재 정보 const { floorPlanState } = useContext(FloorPlanContext) // 플랜 상태 const { closeAll } = usePopup() // 팝업 닫기 - // const previousObjectNoRef = useRef(null) // 최초 데이터 설정 확인 - // const previousRoofMaterialsRef = useRef(null) // 최초 데이터 설정 확인 useEffect(() => { const tempFetchRoofMaterials = !fetchRoofMaterials @@ -188,26 +186,6 @@ export function useCanvasSetting() { setBasicSettings({ ...basicSetting, selectedRoofMaterial: selectedRoofMaterial }) } - // useEffect(() => { - // // 지붕재 select 정보가 존재해야 배치면초기설정 DB 정보 비교 후 지붕재 정보를 가져올 수 있음 - // if ( - // (!previousObjectNoRef.current && !correntObjectNo && previousObjectNoRef.current !== correntObjectNo) || - // (roofMaterials.length !== 0 && JSON.stringify(previousRoofMaterialsRef.current) !== JSON.stringify(roofMaterials)) - // ) { - // // 1회만 실행 - // if (roofMaterials && previousRoofMaterialsYn === 'N') { - // if (correntObjectNo) { - // //fetchBasicSettings() - // previousRoofMaterialsYn = 'Y' - // } - // } - - // // 이전 값을 업데이트 - // previousObjectNoRef.current = correntObjectNo - // previousRoofMaterialsRef.current = roofMaterials - // } - // }, [roofMaterials, correntObjectNo]) - /** * 배치면 초기설정 화면이 열리지 않아도 데이터 set 하기 위해서 추가 */ @@ -330,12 +308,6 @@ export function useCanvasSetting() { * 기본설정(PlacementShapeSetting) 조회 및 초기화 */ const fetchBasicSettings = async (planNo, openPoint) => { - /* roofMaterials가 로드될 때까지 대기 */ - if (!roofMaterials || roofMaterials.length === 0) { - console.log('Waiting for roofMaterials to load...') - return - } - try { await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}`, @@ -433,6 +405,7 @@ export function useCanvasSetting() { if (addRoofs.length > 0) { setAddedRoofs(addRoofs) + setBasicSettings({ ...basicSetting, roofMaterials: addRoofs[0], @@ -442,13 +415,23 @@ export function useCanvasSetting() { roofsData: roofsArray, selectedRoofMaterial: addRoofs.find((roof) => roof.selected), }) + + setCanvasSetting({ + ...basicSetting, + roofMaterials: addRoofs[0], + planNo: roofsRow[0].planNo, + roofSizeSet: roofsRow[0].roofSizeSet, + roofAngleSet: roofsRow[0].roofAngleSet, + roofsData: roofsArray, + selectedRoofMaterial: addRoofs.find((roof) => roof.selected), + }) } }) } catch (error) { console.error('Data fetching error:', error) } - setCanvasSetting({ ...basicSetting }) + // setCanvasSetting({ ...basicSetting }) } /** @@ -482,12 +465,15 @@ export function useCanvasSetting() { await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => { swalFire({ text: getMessage(res.returnMessage) }) - /* 배치면초기설정 조회 */ + /* BasicSettings Recoil 설정 */ setBasicSettings({ ...params }) }) - /* CanvasSetting Recoil 설정 */ - setCanvasSetting({ ...basicSetting }) + /* CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ + setCanvasSetting({ + ...basicSetting, + roofSizeSet: String(params.roofSizeSet), + }) /* 배치면초기설정 조회 */ fetchBasicSettings(params.planNo, null) @@ -515,6 +501,67 @@ export function useCanvasSetting() { } } + /** + * 기본설정(PlacementShapeSetting) 복사 저장 + */ + const basicSettingCopySave = async (params) => { + try { + const patternData = { + objectNo: correntObjectNo, + planNo: Number(params.planNo), + roofSizeSet: Number(params.roofSizeSet), + roofAngleSet: params.roofAngleSet, + roofMaterialsAddList: params.roofsData.map((item) => ({ + planNo: Number(item.planNo), + roofApply: item.roofApply, + roofSeq: item.roofSeq, + roofMatlCd: item.roofMatlCd, + roofWidth: item.roofWidth, + roofHeight: item.roofHeight, + roofHajebichi: item.roofHajebichi, + roofGap: item.roofGap, + roofLayout: item.roofLayout, + roofPitch: item.roofPitch, + roofAngle: item.roofAngle, + })), + } + + await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => { + swalFire({ text: getMessage(res.returnMessage) }) + }) + + /* CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ + setCanvasSetting({ + ...basicSetting, + roofSizeSet: String(params.roofSizeSet), + }) + + /* 배치면초기설정 조회 */ + fetchBasicSettings(Number(params.planNo), null) + + /* 메뉴 설정 */ + if (['2', '3'].includes(params?.roofSizeSet)) { + setMenuNumber(3) + setType('surface') + setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING) + } else { + setMenuNumber(2) + setType('outline') + setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) + } + + /* 모듈 선택 데이터 초기화 */ + resetModuleSelectionData() + moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] }) + const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE) + if (!isModuleExist) { + resetSelectedModules() + } + } catch (error) { + swalFire({ text: error.message, icon: 'error' }) + } + } + /** * CanvasSetting 조회 및 초기화 */ @@ -892,7 +939,7 @@ export function useCanvasSetting() { optionName = ['rack', 'smartRack', 'bracket', 'eaveBar', 'halfEaveBar'] break case 'imageDisplay': - optionName = ['9'] + optionName = ['backGroundImage'] break case 'totalDisplay': /** @@ -929,6 +976,7 @@ export function useCanvasSetting() { setAdsorptionRange, fetchSettings, fetchBasicSettings, + basicSettingCopySave, frontSettings, globalFont, setGlobalFont, diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index dee54673..c2b7ff98 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -34,6 +34,7 @@ import { usePopup } from '@/hooks/usePopup' import { roofDisplaySelector } from '@/store/settingAtom' import { useRoofFn } from '@/hooks/common/useRoofFn' +import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' // 면형상 배치 export function usePlacementShapeDrawing(id) { @@ -76,7 +77,7 @@ export function usePlacementShapeDrawing(id) { const isFix = useRef(false) - const { closePopup } = usePopup() + const { closePopup, addPopup } = usePopup() const globalPitch = useRecoilValue(globalPitchState) @@ -244,7 +245,8 @@ export function usePlacementShapeDrawing(id) { setPoints([]) canvas?.renderAll() - closePopup(id) + + addPopup(id, 1, , false) } if (points.length < 3) { diff --git a/src/hooks/surface/useRoofLinePropertySetting.js b/src/hooks/surface/useRoofLinePropertySetting.js new file mode 100644 index 00000000..d6615ddf --- /dev/null +++ b/src/hooks/surface/useRoofLinePropertySetting.js @@ -0,0 +1,169 @@ +import { LINE_TYPE } from '@/common/common' +import { canvasState, currentObjectState } from '@/store/canvasAtom' +import { useEffect, useRef } from 'react' +import { useRecoilValue } from 'recoil' +import { usePopup } from '../usePopup' +import useSWR from 'swr' +import { useSwal } from '../useSwal' +import { useMessage } from '../useMessage' + +const LINE_COLOR = { + EAVES: '#45CD7D', + GABLE: '#3FBAE6', + RIDGE: '#9e9e9e', + DEFAULT: '#000000', + ACTIVE: '#EA10AC', +} + +export function useRoofLinePropertySetting(props) { + const { id, roof, setIsHidden } = props + const canvas = useRecoilValue(canvasState) + const currentObject = useRecoilValue(currentObjectState) + const history = useRef([]) + const { closePopup } = usePopup() + const { swalFire } = useSwal() + const { getMessage } = useMessage() + + useEffect(() => { + if (currentObject && currentObject.name === 'roofLine') { + roof.lines.forEach((line) => { + const lineType = line.attributes?.type + if (!lineType) { + line.set({ + stroke: '#000000', + strokeWidth: 4, + }) + } + }) + currentObject.set({ + stroke: LINE_COLOR.ACTIVE, + strokeWidth: 4, + }) + canvas.renderAll() + } + }, [currentObject]) + + const roofLinesInit = () => { + roof.lines.forEach((line) => { + canvas.add(line) + line.set({ + stroke: LINE_COLOR.DEFAULT, + strokeWidth: 4, + visible: true, + name: 'roofLine', + }) + line.bringToFront() + }) + canvas.renderAll() + } + + const handleSetEaves = () => { + if (!currentObject) return + currentObject.set({ + attributes: { + ...currentObject.attributes, + type: LINE_TYPE.WALLLINE.EAVES, + }, + stroke: LINE_COLOR.EAVES, + }) + + history.current.push(currentObject) + nextLineFocus(currentObject) + canvas.renderAll() + } + + const handleSetGable = () => { + if (!currentObject) return + currentObject.set({ + attributes: { + ...currentObject.attributes, + type: LINE_TYPE.WALLLINE.GABLE, + }, + stroke: LINE_COLOR.GABLE, + }) + + history.current.push(currentObject) + nextLineFocus(currentObject) + canvas.renderAll() + } + + const handleSetRidge = () => { + if (!currentObject) return + currentObject.set({ + attributes: { + ...currentObject.attributes, + type: LINE_TYPE.SUBLINE.RIDGE, + }, + stroke: LINE_COLOR.RIDGE, + }) + + history.current.push(currentObject) + nextLineFocus(currentObject) + canvas.renderAll() + } + + const handleRollback = () => { + if (history.current.length === 0) { + return + } + const lastLine = history.current.pop() + + delete lastLine.attributes + + lastLine.set({ + stroke: LINE_COLOR.DEFAULT, + strokeWidth: 4, + }) + + canvas.setActiveObject(lastLine) + canvas.renderAll() + } + + const handleFix = () => { + // const roof = canvas.getObjects().find((obj) => currentObject.parentId === obj.id) + const notSettingLines = roof.lines.filter( + (line) => + !line.attributes.type || ![LINE_TYPE.WALLLINE.EAVES, LINE_TYPE.WALLLINE.GABLE, LINE_TYPE.SUBLINE.RIDGE].includes(line.attributes.type), + ) + if (notSettingLines.length > 0) { + swalFire({ text: getMessage('modal.canvas.setting.roofline.properties.setting.not.setting'), type: 'alert', icon: 'warning' }) + return + } + + roof.lines.forEach((line) => { + line.set({ + stroke: LINE_COLOR.DEFAULT, + strokeWidth: 4, + visible: false, + }) + }) + + canvas.renderAll() + closePopup(id) + if (setIsHidden) setIsHidden(false) + } + + const nextLineFocus = (selectedLine) => { + // const roof = canvas.getObjects().find((obj) => currentObject.parentId === obj.id) + const lines = roof?.lines + if (!lines) return + const index = lines.findIndex((line) => line === selectedLine) + + const nextLine = lines[index + 1] || lines[0] + if (!nextLine.attributes?.type) { + canvas.setActiveObject(nextLine) + } else { + //activeObject 해제 + canvas.discardActiveObject() + } + } + + return { + roofLinesInit, + handleSetEaves, + handleSetGable, + handleSetRidge, + handleRollback, + handleFix, + } +} diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 298ef982..dd0ae21f 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -19,6 +19,8 @@ import { QLine } from '@/components/fabric/QLine' import { useRoofFn } from '@/hooks/common/useRoofFn' import { outerLinePointsState } from '@/store/outerLineAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' +import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' +import { v4 as uuidv4 } from 'uuid' export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { const { getMessage } = useMessage() @@ -34,7 +36,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { const { swalFire } = useSwal() const { addCanvasMouseEventListener, initEvent } = useEvent() // const { addCanvasMouseEventListener, initEvent } = useContext(EventContext) - const { closePopup } = usePopup() + const { addPopup, closePopup } = usePopup() const { setSurfaceShapePattern } = useRoofFn() const applySurfaceShape = (surfaceRefs, selectedType, id) => { @@ -101,15 +103,44 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { lockScalingX: true, // X 축 크기 조정 잠금 lockScalingY: true, // Y 축 크기 조정 잠금 name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP, - flipX: xInversion !== yInversion ? yInversion : false, - flipY: xInversion !== yInversion ? xInversion : false, - angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate), + flipX: xInversion !== yInversion, + // angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate), + // angle: rotate, originX: 'center', originY: 'center', pitch: globalPitch, } obj = new QPolygon(points, options) + let imageRotate = 0 + if (xInversion && !yInversion) { + if (rotate % 180 === 0 || rotate < 0) { + imageRotate = Math.abs(rotate % 360) + } else { + if (rotate < 0) { + imageRotate = Math.abs((rotate - 180) % 360) + } else { + imageRotate = Math.abs((rotate + 180) % 360) + } + } + } else if (xInversion && yInversion) { + imageRotate = Math.abs((rotate + 360) % 360) + } else if (xInversion !== yInversion && rotate < 0) { + imageRotate = Math.abs(rotate) + } else if (!xInversion && yInversion) { + if (rotate % 180 === 0 || rotate < 0) { + imageRotate = Math.abs(rotate % 360) + } else { + if (rotate < 0) { + imageRotate = Math.abs((rotate - 180) % 360) + } else { + imageRotate = Math.abs((rotate + 180) % 360) + } + } + } else { + imageRotate = (rotate + 4) % 4 + } + obj.set({ angle: imageRotate }) obj.setCoords() //좌표 변경 적용 canvas?.add(obj) @@ -159,13 +190,16 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { direction: direction, }) canvas?.add(batchSurface) + canvas.setActiveObject(batchSurface) setSurfaceShapePattern(batchSurface, roofDisplay.column) drawDirectionArrow(batchSurface) - if (setIsHidden) setIsHidden(false) + // if (setIsHidden) setIsHidden(false) // closePopup(id) initEvent() + const popupId = uuidv4() + addPopup(popupId, 2, ) }) } else { if (setIsHidden) setIsHidden(false) diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 52be5c90..2afbe126 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -3,7 +3,7 @@ import { fabric } from 'fabric' import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util' -import { useRecoilState } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { canvasSizeState, canvasState, fontSizeState } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { QPolygon } from '@/components/fabric/QPolygon' @@ -15,6 +15,7 @@ import { useAxios } from '@/hooks/useAxios' import { useFont } from '@/hooks/common/useFont' import { OBJECT_PROTOTYPE, POLYGON_TYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common' import { usePlan } from './usePlan' +import { imageDisplaySelector } from '@/store/settingAtom' export function useCanvas(id) { const [canvas, setCanvas] = useRecoilState(canvasState) @@ -24,6 +25,7 @@ export function useCanvas(id) { const [canvasSize] = useRecoilState(canvasSizeState) const [fontSize] = useRecoilState(fontSizeState) const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() + const isImageDisplay = useRecoilValue(imageDisplaySelector) const {} = useFont() /** @@ -530,6 +532,7 @@ export function useCanvas(id) { lockRotation: false, lockScalingX: false, lockScalingY: false, + visible: isImageDisplay, }) // image = img canvas?.add(img) diff --git a/src/hooks/useCirCuitTrestle.js b/src/hooks/useCirCuitTrestle.js index 0d811dfd..8e73d59d 100644 --- a/src/hooks/useCirCuitTrestle.js +++ b/src/hooks/useCirCuitTrestle.js @@ -62,7 +62,6 @@ export function useCircuitTrestle() { // 사용된 모듈아이템 목록 const getUseModuleItemList = () => { - console.log('🚀 ~ getUseModuleItemList ~ selectedModules:', selectedModules) return selectedModules?.itemList?.map((m) => { return { itemId: m.itemId, @@ -83,7 +82,7 @@ export function useCircuitTrestle() { .getObjects() .filter((o) => o.id === obj.parentId)[0] .directionText.replace(/[0-9]/g, ''), - roofSurfaceIncl: canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch, + roofSurfaceIncl: +canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch, moduleList: getModuleList(obj).map((module) => { return { itemId: module.moduleInfo.itemId, diff --git a/src/hooks/useLine.js b/src/hooks/useLine.js index e2667e80..b447d4f0 100644 --- a/src/hooks/useLine.js +++ b/src/hooks/useLine.js @@ -40,7 +40,7 @@ export const useLine = () => { }) canvas ?.getObjects() - .find((obj) => obj.parent === line) + .find((obj) => obj.parentId === line.id) .set({ visible: false, }) @@ -53,7 +53,7 @@ export const useLine = () => { }) canvas ?.getObjects() - .find((obj) => obj.parent === line) + .find((obj) => obj.parentId === line.id) .set({ visible: true, }) diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 40b2b29e..10bc7e45 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -5,7 +5,7 @@ import { usePathname, useRouter } from 'next/navigation' import { useRecoilState, useResetRecoilState } from 'recoil' -import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom' +import { canvasState, currentCanvasPlanState, plansState, canvasSettingState } from '@/store/canvasAtom' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' @@ -39,7 +39,8 @@ export function usePlan(params = {}) { const resetOuterLinePoints = useResetRecoilState(outerLinePointsState) const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState) - const { fetchBasicSettings } = useCanvasSetting() + const { fetchBasicSettings, basicSettingCopySave } = useCanvasSetting() + const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) /** * 마우스 포인터의 가이드라인 제거 @@ -184,41 +185,55 @@ export function usePlan(params = {}) { objectNo: objectNo, copyFlg: '0', } - await promisePost({ url: '/api/object/add-plan', data: planData }) - .then((res) => { - let newPlan = { - id: res.data.canvasId, - objectNo: objectNo, - planNo: res.data.planNo, - userId: userId, - canvasStatus: '', - isCurrent: true, - bgImageName: null, - mapPositionAddress: null, - } + try { + const res = await promisePost({ url: '/api/object/add-plan', data: planData }) + let newPlan = { + id: res.data.canvasId, + objectNo: objectNo, + planNo: res.data.planNo, + userId: userId, + canvasStatus: '', + isCurrent: true, + bgImageName: null, + mapPositionAddress: null, + } - if (isInitPlan) { - /* 초기 플랜 생성인 경우 플랜 목록 초기화 */ - setCurrentCanvasPlan(newPlan) - setPlans([newPlan]) - } else { - if (isCopy) { - /* 복제 플랜 생성인 경우 현재 캔버스 데이터를 복제 */ - newPlan.canvasStatus = currentCanvasData() - newPlan.bgImageName = currentCanvasPlan?.bgImageName ?? null - newPlan.mapPositionAddress = currentCanvasPlan?.mapPositionAddress ?? null - } - setCurrentCanvasPlan(newPlan) - setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan]) - swalFire({ text: getMessage('plan.message.save') }) - } + if (isInitPlan) { + /* 초기 플랜 생성인 경우 플랜 목록 초기화 */ + setCurrentCanvasPlan(newPlan) + setPlans([newPlan]) /* 플랜 추가 시 배치면초기설정 정보 조회 */ fetchBasicSettings(newPlan.planNo, null) - }) - .catch((error) => { - swalFire({ text: error.response.data.message, icon: 'error' }) - }) + } else { + if (isCopy) { + /* 복제 플랜 생성인 경우 현재 캔버스 데이터를 복제 */ + newPlan.canvasStatus = currentCanvasData() + newPlan.bgImageName = currentCanvasPlan?.bgImageName ?? null + newPlan.mapPositionAddress = currentCanvasPlan?.mapPositionAddress ?? null + + /* 복제 시 배치면 초기설정 복사 */ + basicSettingCopySave({ + ...canvasSetting, + planNo: newPlan.planNo, + selectedRoofMaterial: { + ...canvasSetting.selectedRoofMaterial, + planNo: newPlan.planNo, + }, + roofsData: canvasSetting.roofsData.map((roof) => ({ + ...roof, + planNo: newPlan.planNo, + })), + }) + } + setCurrentCanvasPlan(newPlan) + setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan]) + + swalFire({ text: getMessage('plan.message.save') }) + } + } catch (error) { + swalFire({ text: error.response.data.message, icon: 'error' }) + } } /** @@ -275,7 +290,6 @@ export function usePlan(params = {}) { const objectNo = floorPlanState.objectNo //견적서 or 발전시뮬 - if (pathname !== '/floor-plan') { await promiseGet({ url: `/api/estimate/${objectNo}/${planNo}/detail` }) .then((res) => { @@ -304,9 +318,6 @@ export function usePlan(params = {}) { // 클릭한 플랜 탭으로 이동 setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId)) setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId }))) - - /* 플랜 이동 시 배치면초기설정 정보 조회 (견적서 메뉴 제외) */ - fetchBasicSettings(planNo, null) } else { swalFire({ text: getMessage('estimate.menu.move.valid1') }) } @@ -494,7 +505,13 @@ export function usePlan(params = {}) { * @param {string} planNo - 플랜번호 */ const deleteBasicSettings = async (objectNo, planNo) => { - await promiseDel({ url: `/api/canvas-management/delete-basic-settings/${objectNo}/${planNo}` }) + try { + await promiseDel({ url: `/api/canvas-management/canvas-basic-settings/delete-basic-settings/${objectNo}/${planNo}` }) + } catch (error) { + /* 오류를 무시하고 계속 진행 */ + console.log('Basic settings delete failed or not found:', error) + // swalFire({ text: error.message, icon: 'error' }) + } } return { diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 99845d46..1dc3f231 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -7,7 +7,7 @@ import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' import { fontSelector } from '@/store/fontAtom' import { QLine } from '@/components/fabric/QLine' -import { POLYGON_TYPE } from '@/common/common' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) @@ -909,6 +909,29 @@ export const usePolygon = () => { const allLines = [...polygonLines, ...innerLines] + // 2025-02-19 대각선은 케라바, 직선은 용마루로 세팅 + innerLines.forEach((innerLine) => { + const startPoint = innerLine.startPoint + const endPoint = innerLine.endPoint + + // startPoint와 endPoint의 각도가 0,90,180,270이면 직선으로 판단 + if (Math.abs(startPoint.x - endPoint.x) < 2 || Math.abs(startPoint.y - endPoint.y) < 2) { + if (!innerLine.attributes || !innerLine.attributes.type) { + innerLine.attributes = { + ...innerLine.attributes, + type: LINE_TYPE.SUBLINE.RIDGE, + } + } + } else { + if (!innerLine.attributes || !innerLine.attributes.type) { + innerLine.attributes = { + ...innerLine.attributes, + type: LINE_TYPE.SUBLINE.GABLE, + } + } + } + }) + /** * 왼쪽 상단을 startPoint로 전부 변경 */ diff --git a/src/locales/ja.json b/src/locales/ja.json index 9f06310e..677f9cab 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -269,6 +269,10 @@ "modal.canvas.setting.wallline.properties.setting.info": "※属性を変更する外壁線を選択し、軒で設定またはケラバで設定\nボタンをクリックして設定値を適用してください。\n", "modal.canvas.setting.wallline.properties.setting.eaves": "軒で設定", "modal.canvas.setting.wallline.properties.setting.edge": "ケラバに設定", + "modal.canvas.setting.wallline.properties.setting.ridge": "용마루로 설정(JA)", + "modal.canvas.setting.roofline.properties.setting": "지붕선 속성 설정(JA)", + "modal.canvas.setting.roofline.properties.setting.info": "※ 속성을 변경할 지붕선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n(JA)", + "modal.canvas.setting.roofline.properties.setting.not.setting": "설정하지 않은 라인이 존재합니다.(JA)", "modal.eaves.gable.edit": "軒/ケラバ変更", "modal.eaves.gable.edit.basic": "通常", "modal.eaves.gable.edit.wall.merge.info": "河屋などの壁に面する屋根を作成します。", @@ -659,9 +663,9 @@ "stuff.planReqPopup.title": "設計依頼のインポート", "stuff.temp.subTitle": "商品情報", "stuff.temp.subTitle2": "作図", - "stuff.detail.header.notExistObjectNo": "存在しないものです。", - "stuff.detail.header.successCopy": "物件番号がコピーされました。", - "stuff.detail.header.failCopy": "物件番号のコピーに失敗しました。", + "stuff.detail.header.notExistObjectNo": "存在しないもの番号です.", + "stuff.detail.header.successCopy": "物件番号がコピーされました.", + "stuff.detail.header.failCopy": "物件番号のコピーに失敗しました.", "stuff.detail.header.objectNo": "物件番号", "stuff.detail.header.specificationConfirmDate": "仕様確認日", "stuff.detail.header.lastEditDatetime": "更新日時", @@ -783,7 +787,7 @@ "stuff.detail.planGridHeader.capacity": "システム容量", "stuff.detail.planGridHeader.roofMaterialIdMulti": "屋根材", "stuff.detail.planGridHeader.constructSpecificationMulti": "施工方法", - "stuff.detail.planGridHeader.supprotMethodIdMulti": "架台", + "stuff.detail.planGridHeader.supportMethodIdMulti": "架台", "stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー", "stuff.detail.planGridHeader.management": "管理", "stuff.detail.planGrid.btn1": "見積書の照会", @@ -1009,6 +1013,8 @@ "module.place.select.one.module": "モジュールは1つだけ選択してください。", "batch.canvas.delete.all": "配置面の内容をすべて削除しますか?", "module.not.found": "インストールモジュールを選択してください。", + "module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.(JA)", + "module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.(JA)", "construction.length.difference": "屋根面工法をすべて選択してください。", "menu.validation.canvas.roof": "パネルを配置するには、屋根面を入力する必要があります。", "batch.object.outside.roof": "オブジェクトは屋根に設置する必要があります。", diff --git a/src/locales/ko.json b/src/locales/ko.json index b43e6853..67b4b301 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -269,6 +269,10 @@ "modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n", "modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정", "modal.canvas.setting.wallline.properties.setting.edge": "케라바로 설정", + "modal.canvas.setting.wallline.properties.setting.ridge": "용마루로 설정", + "modal.canvas.setting.roofline.properties.setting": "지붕선 속성 설정", + "modal.canvas.setting.roofline.properties.setting.info": "※ 속성을 변경할 지붕선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n", + "modal.canvas.setting.roofline.properties.setting.not.setting": "설정하지 않은 라인이 존재합니다.", "modal.eaves.gable.edit": "처마/케라바 변경", "modal.eaves.gable.edit.basic": "통상", "modal.eaves.gable.edit.wall.merge.info": "하옥 등 벽에 접하는 지붕을 작성합니다.", @@ -659,7 +663,7 @@ "stuff.planReqPopup.title": "설계의뢰 불러오기", "stuff.temp.subTitle": "물건정보", "stuff.temp.subTitle2": "도면작성", - "stuff.detail.header.notExistObjectNo": "존재하지 않는 물건입니다.", + "stuff.detail.header.notExistObjectNo": "존재하지 않는 물건번호 입니다.", "stuff.detail.header.successCopy": "물건번호가 복사되었습니다.", "stuff.detail.header.failCopy": "물건번호 복사에 실패했습니다.", "stuff.detail.header.objectNo": "물건번호", @@ -783,7 +787,7 @@ "stuff.detail.planGridHeader.capacity": "시스템용량", "stuff.detail.planGridHeader.roofMaterialIdMulti": "지붕재", "stuff.detail.planGridHeader.constructSpecificationMulti": "시공방법", - "stuff.detail.planGridHeader.supprotMethodIdMulti": "가대", + "stuff.detail.planGridHeader.supportMethodIdMulti": "가대", "stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너", "stuff.detail.planGridHeader.management": "관리", "stuff.detail.planGrid.btn1": "견적서 조회", @@ -1010,6 +1014,8 @@ "module.place.select.one.module": "모듈은 하나만 선택해주세요.", "batch.canvas.delete.all": "배치면 내용을 전부 삭제하시겠습니까?", "module.not.found": "모듈을 선택하세요.", + "module.circuit.minimun.error": "회로번호는 1 이상입력해주세요.", + "module.already.exist.error": "회로번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로번호를 설정하십시오.", "construction.length.difference": "지붕면 공법을 전부 선택해주세요.", "menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.", "batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.", diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index b6e2d322..a19aba2e 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -769,6 +769,13 @@ $alert-color: #101010; background-color: #365f6e; } } + &.gray{ + background-color: #535353; + border: 1px solid #9e9e9e; + &:hover{ + background-color: #6b6b6b; + } + } } } } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 0444c93d..557342b8 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -3525,7 +3525,14 @@ export const calcLinePlaneSize = (points) => { * @returns number */ export const calcLineActualSize = (points, degree) => { + const { x1, y1, x2, y2 } = points const planeSize = calcLinePlaneSize(points) - const height = Big(Math.tan(Big(degree).times(Math.PI / 180))).times(planeSize) + let height = Big(Math.tan(Big(degree).times(Math.PI / 180))).times(planeSize) + /** + * 대각선일 경우 높이 계산 변경 + */ + if (x1 !== x2 && y1 !== y2) { + height = Big(Math.tan(Big(degree).times(Math.PI / 180))).times(Big(x1).minus(x2).times(10).round()) + } return Big(planeSize).pow(2).plus(height.pow(2)).sqrt().abs().round().toNumber() } diff --git a/startscript.js b/startscript.js index 37f52696..350b2c06 100644 --- a/startscript.js +++ b/startscript.js @@ -1,2 +1,2 @@ var exec = require('child_process').exec -exec('yarn start', { windowsHide: true }) +exec('yarn serve', { windowsHide: true })