diff --git a/src/common/common.js b/src/common/common.js index 59e8be6c..92ddbdca 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -174,6 +174,9 @@ export const SAVE_KEY = [ 'turfPoints', 'tempIndex', 'surfaceId', + 'moduleRowsTotCnt', + 'seq', + 'smartRackId', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 51ca0318..35774e8a 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -94,10 +94,18 @@ export default function CircuitTrestleSetting({ id }) { setModels(res.data.pcsItemList) setTabNum(2) } else { - swalFire({ - title: '파워컨디셔너를 추가해 주세요.', - type: 'alert', - }) + // 데이터가 없는 경우 오류 메시지 확인 필요 + if (res.result.resultCode === 'E') { + swalFire({ + title: res.result.resultMsg, + type: 'alert', + }) + } else { + swalFire({ + title: '파워컨디셔너를 추가해 주세요.', + type: 'alert', + }) + } } }) } @@ -124,7 +132,7 @@ export default function CircuitTrestleSetting({ id }) { return selectedModules.itemList.map((m) => { return { itemId: m.itemId, - //mixMatlNo: m.mixMatlNo, + mixMatlNo: m.mixMatlNo, } }) } diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 1d436a13..bd722b8e 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -24,19 +24,21 @@ export default function StepUp(props) { const [stepUpListData, setStepUpListData] = useState([]) const [optCodes, setOptCodes] = useState([]) - useCanvasPopupStatusController(6) - const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore) - if (Object.keys(canvasPopupStatusState[6]).length !== 0) { - console.log('🚀 ~ useEffect ~ canvasPopupStatusState :', canvasPopupStatusState) - } + const [selectedRows, setSelectedRows] = useState({}) + const [isManualSelection, setIsManualSelection] = useState({}) + + // useCanvasPopupStatusController(6) + // const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore) + // if (Object.keys(canvasPopupStatusState[6]).length !== 0) { + // console.log('🚀 ~ useEffect ~ canvasPopupStatusState :', canvasPopupStatusState) + // } useEffect(() => { - console.log('🚀 ~ useEffect ~ >>>>>>>>>>>> props:', props) - // PCS 승압설정 정보 조회 fetchStepUpData() }, []) + // PCS 승압설정 정보 조회 const fetchStepUpData = async () => { try { const params = { @@ -46,14 +48,14 @@ export default function StepUp(props) { pcsItemList: props.getPcsItemList(), // PCS 아이템 목록 } - console.log('🚀 ~ fetchStepUpData ~ params:', params) - + // PCS 승압설정 정보 조회 const res = await getPcsVoltageStepUpList(params) - console.log('🚀 ~ fetchStepUpData ~ res:', res) + if (res?.result.code === 200 && res?.data) { const dataArray = Array.isArray(res.data) ? res.data : [res.data] const stepUpListData = formatStepUpListData(dataArray) - console.log('🚀 ~ useEffect ~ getPcsVoltageStepUpList ~ stepUpListData:', stepUpListData) + + // PCS 승압설정 정보 SET setStepUpListData(stepUpListData) // PCS 옵션 조회 @@ -80,6 +82,7 @@ export default function StepUp(props) { ...stepUps, optionList: formatOptionList(stepUps.optionList), pcsItemList: formatPcsItemList(stepUps.pcsItemList), + selectedPcsItem: formatPcsItemList(stepUps.pcsItemList), })) } @@ -107,6 +110,8 @@ export default function StepUp(props) { // PCS 연결 포맷 const formatConnList = (connList = []) => { + if (!connList) return [] // null인 경우 빈 배열 반환 + return connList?.map((conn) => ({ connAllowCur: conn.connAllowCur ? conn.connAllowCur : 0, connMaxParalCnt: conn.connMaxParalCnt ? conn.connMaxParalCnt : 0, @@ -122,6 +127,8 @@ export default function StepUp(props) { return serQtyList?.map((qty) => ({ serQty: qty.serQty ? qty.serQty : 0, paralQty: qty.paralQty ? qty.paralQty : 0, + rmdYn: qty.rmdYn ? qty.rmdYn : 'N', + usePossYn: qty.usePossYn ? qty.usePossYn : 'Y', })) } @@ -133,6 +140,39 @@ export default function StepUp(props) { })) } + // 행 선택 핸들러 함수 추가 + const handleRowClick = (stepUpId, pcsIdx, serQtyIdx) => { + const rowKey = `${stepUpId}_${pcsIdx}_${serQtyIdx}` + const pcsKey = `${stepUpId}_${pcsIdx}` + + setSelectedRows((prev) => { + // 현재 stepUpId에 대한 선택 상태가 없으면 빈 객체로 초기화 + const currentStepUpSelections = prev[stepUpId] || {} + + // 이미 선택된 행을 다시 클릭하는 경우, 선택을 해제하지 않음 + if (currentStepUpSelections[pcsKey] === rowKey) { + return prev + } + + return { + ...prev, + [stepUpId]: { + ...currentStepUpSelections, + [pcsKey]: rowKey, + }, + } + }) + + // 수동 선택 상태를 업데이트하되, 기존 추천 선택은 유지 + setIsManualSelection((prev) => ({ + ...prev, + [stepUpId]: { + ...prev[stepUpId], + [pcsKey]: true, + }, + })) + } + return ( <>
@@ -143,9 +183,7 @@ export default function StepUp(props) { {stepUp?.pcsItemList.map((_, idx) => (
-
- {stepUp.pcsItemList[idx].goodsNo} -
+
{stepUp.pcsItemList[idx].goodsNo}
@@ -155,9 +193,21 @@ export default function StepUp(props) { - {stepUp.pcsItemList[idx].serQtyList.map((item) => { + {stepUp.pcsItemList[idx].serQtyList.map((item, serQtyIdx) => { + const rowKey = `${stepUp.id}_${idx}_${serQtyIdx}` + const pcsKey = `${stepUp.id}_${idx}` return ( - + handleRowClick(stepUp.id, idx, serQtyIdx)} + style={{ cursor: 'pointer' }} + > @@ -195,9 +245,17 @@ export default function StepUp(props) { - - - + + +
{item.serQty} {item.paralQty}
{stepUp.pcsItemList[idx].connList?.goodsNo}{stepUp.pcsItemList[idx].connList?.connMaxParalCnt}{stepUp.pcsItemList[idx].connList?.vstuParalCnt} + {stepUp.pcsItemList[idx].connList?.[0]?.goodsNo ? stepUp.pcsItemList[idx].connList?.[0]?.goodsNo : '-'} + + {stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt + ? (stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt ?? '-') + : '-'} + + {stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt ? stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt : '-'} +
diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index 684b6673..e8a1361f 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -350,6 +350,10 @@ export default function StuffDetail() { if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') { //createUser가 T01인데 로그인사용자가 T01이 아니면 버튼숨기기 setShowButton('none') + } else { + if (session.storeId !== res?.data?.createUser) { + setShowButton('none') + } } if (isObjectNotEmpty(res.data)) { let surfaceTypeValue @@ -358,7 +362,7 @@ export default function StuffDetail() { } else if (res.data.surfaceType === 'Ⅱ') { surfaceTypeValue = '2' } - setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue }) + setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue, firstFlag: 'Y' }) } else { setManagementState({}) swalFire({ @@ -1403,6 +1407,7 @@ export default function StuffDetail() { // 수정모드일때는 PUT await promisePut({ url: apiUrl, data: params }) .then((res) => { + console.log('수정::::::::::::', params) setIsGlobalLoading(true) if (res.status === 201) { @@ -1413,8 +1418,6 @@ export default function StuffDetail() { type: 'alert', confirmFn: () => { callDetailApi(objectNo) - // setManagementState({ ...managementState, params }) - // router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false }) }, }) } @@ -1426,48 +1429,22 @@ export default function StuffDetail() { } } - const callDetailApi = (objectNo) => { - promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { - if (res.status === 200) { - if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') { - //createUser가 T01인데 로그인사용자가 T01이 아니면 버튼숨기기 + const callDetailApi = async (objectNo) => { + await promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { + if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') { + setShowButton('none') + } else { + if (session.storeId !== res?.data?.createUser) { setShowButton('none') } - if (isObjectNotEmpty(res.data)) { - let surfaceTypeValue - if (res.data.surfaceType === 'Ⅲ・Ⅳ') { - surfaceTypeValue = '3' - } else if (res.data.surfaceType === 'Ⅱ') { - surfaceTypeValue = '2' - } - setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue }) - } else { - setManagementState({}) - swalFire({ - text: getMessage('stuff.detail.header.notExistObjectNo'), - type: 'alert', - confirmFn: () => { - router.push('/management/stuff', { scroll: false }) - }, - }) - } - if (isNotEmptyArray(res.data.planList)) { - setPlanGridProps({ ...planGridProps, planGridData: res.data.planList }) - } else { - setPlanGridProps({ ...planGridProps, planGridData: [] }) - } - } else { - setManagementState({}) - setPlanGridProps({ ...planGridProps, planGridData: [] }) - - swalFire({ - text: getMessage('stuff.detail.header.notExistObjectNo'), - type: 'alert', - confirmFn: () => { - router.push('/management/stuff', { scroll: false }) - }, - }) } + let surfaceTypeValue + if (res.data.surfaceType === 'Ⅲ・Ⅳ') { + surfaceTypeValue = '3' + } else { + surfaceTypeValue = '2' + } + setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue }) }) } @@ -1679,7 +1656,6 @@ export default function StuffDetail() { } } } - return ( <> {(editMode === 'NEW' && ( diff --git a/src/components/simulator/Simulator.jsx b/src/components/simulator/Simulator.jsx index 3abb6969..306b5365 100644 --- a/src/components/simulator/Simulator.jsx +++ b/src/components/simulator/Simulator.jsx @@ -18,7 +18,12 @@ import { convertNumberToPriceDecimal } from '@/util/common-utils' import { usePlan } from '@/hooks/usePlan' import { usePopup, closeAll } from '@/hooks/usePopup' +import { QcastContext } from '@/app/QcastProvider' + export default function Simulator() { + // global 로딩바 + const { setIsGlobalLoading } = useContext(QcastContext) + const { floorPlanState } = useContext(FloorPlanContext) const { objectNo, pid } = floorPlanState const { selectedPlan } = usePlan() @@ -136,9 +141,12 @@ export default function Simulator() { const [hatsudenryouPeakcutAllSnow, setHatsudenryouPeakcutAllSnow] = useState([]) const fetchObjectDetail = async (objectNo, currentPid) => { + setIsGlobalLoading(true) + const apiUrl = `/api/pwrGnrSimulation/calculations?objectNo=${objectNo}&planNo=${currentPid}` const resultData = await get({ url: apiUrl }) + if (resultData) { setObjectDetail(resultData) if (resultData.hatsudenryouAll) { @@ -161,12 +169,14 @@ export default function Simulator() { setModuleInfoList(resultData.roofModuleList) } } + setIsGlobalLoading(false) } // 시뮬레이션 안내사항 조회 const [content, setContent] = useState('') const fetchSimulatorNotice = async () => { + setIsGlobalLoading(true) get({ url: '/api/pwrGnrSimulation/guideInfo' }).then((res) => { if (res.data) { setContent(res.data.replaceAll('\n', '
')) @@ -174,6 +184,7 @@ export default function Simulator() { setContent(getMessage('common.message.no.data')) } }) + setIsGlobalLoading(false) } // 차트 데이터 변경 시, list type 셋팅 diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index c41ab251..acc2aab1 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -3,6 +3,7 @@ import { canvasState } from '@/store/canvasAtom' import { POLYGON_TYPE } from '@/common/common' import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { getDegreeByChon, getTrestleLength } from '@/util/canvas-util' +import { v4 as uuidv4 } from 'uuid' // 회로 및 가대설정 export const useTrestle = () => { @@ -33,14 +34,15 @@ export const useTrestle = () => { alert('앞에서 셋팅 안됨') return } - let isEaveBar = construction.setupCover + let moduleRowsTotCnt = 0 + let isEaveBar = construction.setupCover let isSnowGuard = construction.setupSnowCover const direction = parent.direction const rack = surface.trestleDetail.rack let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn } = surface.trestleDetail - rackYn = 'N' - rackQty = 5 + // rackYn = 'N' + // rackQty = 5 cvrPlvrYn = 'Y' if (!rack) { @@ -112,6 +114,7 @@ export const useTrestle = () => { stroke: 'blue', strokeWidth: 4, selectable: false, + surfaceId: surface.id, parentId: module.id, }) canvas.add(eaveBar) @@ -141,6 +144,7 @@ export const useTrestle = () => { stroke: 'blue', strokeWidth: 4, selectable: false, + surfaceId: surface.id, parentId: module.id, }) canvas.add(halfEaveBar) @@ -296,6 +300,8 @@ export const useTrestle = () => { return rack.value.moduleRows === centerRows })?.value.racks + moduleRowsTotCnt = Math.max(leftRows, rightRows, centerRows) + if (rackYn === 'Y') { drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) @@ -356,7 +362,7 @@ export const useTrestle = () => { const leftRacks = rackInfos.find((rack) => { return rack.value.moduleRows === leftRows })?.value.racks - + moduleRowsTotCnt = Math.max(leftRows, moduleRowsTotCnt) if (rackYn === 'Y') { drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn) } @@ -409,6 +415,8 @@ export const useTrestle = () => { const rightRacks = rackInfos.find((rack) => { return rack.value.moduleRows === rightRows })?.value.racks + + moduleRowsTotCnt = Math.max(rightRows, moduleRowsTotCnt) // 해당 rack으로 그려준다. if (rackYn === 'Y') { drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn) @@ -417,12 +425,16 @@ export const useTrestle = () => { module.set({ rightRows }) }) + surface.set({ moduleRowsTotCnt }) + if (rackYn === 'N') { // rack이 없을경우 installBracketWithOutRack(surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory) } else if (rackYn === 'Y') { installBracket(surface) } + + console.log(getTrestleParams(surface)) }) } @@ -612,32 +624,69 @@ export const useTrestle = () => { switch (direction) { case 'south': { rackInfos.forEach((rackInfo) => { - const { rackLen, itemId, supFitQty, supFitIntvlPct } = rackInfo + const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo + let rackLength = getTrestleLength(rackLen, degree) / 10 - const rackLength = getTrestleLength(rackLen, degree) / 10 + if (smartRackYn === 'Y') { + let smartRackId = uuidv4() + smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { + rackLength = getTrestleLength(setRackTpLen, degree) / 10 + if (setRackTpCd === 'RACK') { + const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { + name: 'smartRack', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, - const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], { - name: 'rack', - stroke: 'red', - strokeWidth: 4, - selectable: false, - fill: 'red', - shadow: { - color: 'black', // Outline color - blur: 10, - offsetX: 0, - offsetY: 0, - }, - parentId: module.id, - supFitQty, - supFitIntvlPct, - rackLen, - rackId: itemId, - direction: 'top', - }) + parentId: module.id, + surfaceId: surface.id, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + seq, + smartRackId, + rackId: itemId, + direction: 'top', + }) + canvas.add(rack) + canvas.renderAll() + } else if (setRackTpCd === 'INTVL') { + startPointY -= rackLength + 8 + } + }) + } else { + const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], { + name: 'rack', + stroke: 'red', + strokeWidth: 4, + selectable: false, + fill: 'red', + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + rackId: itemId, + direction: 'top', + }) - canvas.add(rack) - canvas.renderAll() + canvas.add(rack) + canvas.renderAll() + } startPointY -= rackLength + 8 }) @@ -646,32 +695,68 @@ export const useTrestle = () => { } case 'east': { rackInfos.forEach((rackInfo) => { - const { rackLen, itemId, supFitQty, supFitIntvlPct } = rackInfo + const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo - const rackLength = getTrestleLength(rackLen, degree) / 10 + let rackLength = getTrestleLength(rackLen, degree) / 10 + if (smartRackYn === 'Y') { + let smartRackId = uuidv4() + smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { + rackLength = getTrestleLength(setRackTpLen, degree) / 10 + if (setRackTpCd === 'RACK') { + const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], { + name: 'smartRack', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + seq, + smartRackId, + rackId: itemId, + direction: 'left', + }) + canvas.add(rack) + canvas.renderAll() + } else if (setRackTpCd === 'INTVL') { + startPointX -= rackLength + } + }) + } else { + const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], { + name: 'rack', + stroke: 'red', + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + strokeWidth: 4, + selectable: false, + supFitQty, + supFitIntvlPct, + rackLen, + rackYn, + rackRowsCd, + rackId: itemId, + direction: 'left', + }) - const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], { - name: 'rack', - stroke: 'red', - shadow: { - color: 'black', // Outline color - blur: 10, - offsetX: 0, - offsetY: 0, - }, - parentId: module.id, - strokeWidth: 4, - selectable: false, - supFitQty, - supFitIntvlPct, - rackLen, - rackYn, - rackId: itemId, - direction: 'left', - }) - - canvas.add(rack) - canvas.renderAll() + canvas.add(rack) + canvas.renderAll() + } startPointX -= rackLength + 8 }) @@ -680,31 +765,66 @@ export const useTrestle = () => { case 'west': { rackInfos.forEach((rackInfo) => { - const { rackLen, itemId, supFitQty, supFitIntvlPct } = rackInfo + const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo + let rackLength = getTrestleLength(rackLen, degree) / 10 + if (smartRackYn === 'Y') { + let smartRackId = uuidv4() + smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { + rackLength = getTrestleLength(setRackTpLen, degree) / 10 + if (setRackTpCd === 'RACK') { + const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { + name: 'smartRack', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + seq, + smartRackId, + rackId: itemId, + direction: 'right', + }) + canvas.add(rack) + canvas.renderAll() + } else if (setRackTpCd === 'INTVL') { + startPointX += rackLength + 8 + } + }) + } else { + const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { + name: 'rack', + stroke: 'red', + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + strokeWidth: 4, + selectable: false, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + rackId: itemId, + direction: 'right', + }) - const rackLength = getTrestleLength(rackLen, degree) / 10 - - const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { - name: 'rack', - stroke: 'red', - shadow: { - color: 'black', // Outline color - blur: 10, - offsetX: 0, - offsetY: 0, - }, - parentId: module.id, - strokeWidth: 4, - selectable: false, - supFitQty, - supFitIntvlPct, - rackLen, - rackId: itemId, - direction: 'right', - }) - - canvas.add(rack) - canvas.renderAll() + canvas.add(rack) + canvas.renderAll() + } startPointX += rackLength + 8 }) @@ -712,32 +832,66 @@ export const useTrestle = () => { } case 'north': { rackInfos.forEach((rackInfo) => { - const { rackLen, itemId, supFitQty, supFitIntvlPct } = rackInfo - - const rackLength = getTrestleLength(rackLen, degree) / 10 - - const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], { - name: 'rack', - stroke: 'red', - shadow: { - color: 'black', // Outline color - blur: 10, - offsetX: 0, - offsetY: 0, - }, - parentId: module.id, - strokeWidth: 4, - selectable: false, - supFitQty, - supFitIntvlPct, - rackLen, - rackId: itemId, - direction: 'bottom', - }) - - canvas.add(rack) - canvas.renderAll() + const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo + let rackLength = getTrestleLength(rackLen, degree) / 10 + if (smartRackYn === 'Y') { + let smartRackId = uuidv4() + smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { + rackLength = getTrestleLength(setRackTpLen, degree) / 10 + if (setRackTpCd === 'RACK') { + const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { + name: 'smartRack', + stroke: 'blue', + strokeWidth: 4, + selectable: false, + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + seq, + smartRackId, + rackId: itemId, + direction: 'right', + }) + canvas.add(rack) + canvas.renderAll() + } else if (setRackTpCd === 'INTVL') { + startPointY += rackLength + 8 + } + }) + } else { + const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], { + name: 'rack', + stroke: 'red', + shadow: { + color: 'black', // Outline color + blur: 10, + offsetX: 0, + offsetY: 0, + }, + parentId: module.id, + surfaceId: surface.id, + strokeWidth: 4, + selectable: false, + supFitQty, + supFitIntvlPct, + rackLen, + rackRowsCd, + rackId: itemId, + direction: 'bottom', + }) + canvas.add(rack) + canvas.renderAll() + } startPointY += rackLength + 8 }) break @@ -777,6 +931,7 @@ export const useTrestle = () => { fill: 'green', name: 'bracket', parentId: rack.parentId, + surfaceId: surface.id, width: bracketLength, height: bracketLength, selectable: false, @@ -795,6 +950,7 @@ export const useTrestle = () => { fill: 'green', name: 'bracket', parentId: rack.parentId, + surfaceId: surface.id, width: bracketLength, height: bracketLength, selectable: false, @@ -812,6 +968,7 @@ export const useTrestle = () => { top: y2 - bracketLength / 3, fill: 'green', parentId: rack.parentId, + surfaceId: surface.id, name: 'bracket', width: bracketLength, height: bracketLength, @@ -831,6 +988,7 @@ export const useTrestle = () => { fill: 'green', name: 'bracket', parentId: rack.parentId, + surfaceId: surface.id, width: bracketLength, height: bracketLength, selectable: false, @@ -845,9 +1003,10 @@ export const useTrestle = () => { //랙 없음 인 경우 지지금구 설치 const installBracketWithOutRack = (surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory) => { - let { rackQty, rackIntvlPct, moduleIntvlHor, moduleIntvlVer } = surface.trestleDetail + let { rackQty, rackIntvlPct, moduleIntvlHor, moduleIntvlVer, lessSupFitQty, lessSupFitIntvlPct } = surface.trestleDetail const direction = surface.direction - rackQty = 3 + rackQty = lessSupFitQty + rackIntvlPct = lessSupFitIntvlPct canvas.renderAll() exposedBottomModules.forEach((module) => { @@ -990,6 +1149,7 @@ export const useTrestle = () => { fill: 'green', name: 'bracket', parentId: module.id, + surfaceId: module.surfaceId, width: 10, height: 10, selectable: false, @@ -1318,5 +1478,270 @@ export const useTrestle = () => { return groups } - return { apply } + const getTrestleParams = (surface) => { + const result = calculateForApi(surface) + + const eaveBar = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'eaveBar') + const halfEaveBar = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'halfEaveBar') + + const rackList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'rack') + const smartRackList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'smartRack') + // smartRackList을 smartRackId 기준으로 그룹화 한 배열 + const smartRackGroup = smartRackList.reduce((acc, cur) => { + if (!acc[cur.smartRackId]) { + acc[cur.smartRackId] = [] + } + acc[cur.smartRackId].push(cur) + return acc + }, {}) + + const bracketList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'bracket') + let rackParams = rackList.map((rack, index) => { + return { + seq: index, + rackId: rack.rackId, + rackFittingCnt: rack.supFitQty, + rackRows: rack.rackRowsCd, + } + }) + + return { + exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수 + exposedHalfBottomTotCnt: result.exposedHalfBottom, // 노출 반하면 갯수 + exposedTopTotCnt: result.exposedTop, // 노출 상면 총 수 + exposedHalfTopTotCnt: result.exposedHalfTop, // 노출 반상면 총 수 + exposedBottomTotCnt: result.exposedBottomPoints.length, // 노출 하면 수 + touchedSurfaceTotCnt: result.touchDimension, // 접면 총 수 + touchedHalfSurfaceTotCnt: result.halfTouchDimension, // 반접면 총 수 + moduleRowsTotCnt: surface.moduleRowsTotCnt, // 모듈 총 단 수 + eavesTotCnt: eaveBar.length, + eavesHalfTotCnt: halfEaveBar.length, + racks: rackParams, + rackTotCnt: rackList.length + smartRackGroup.length, + rackFittingCnt: bracketList.length, + moduleRows: getMostLeftModules(surface), + } + } + + // 가장 왼쪽에 있는 모듈을 기준으로 같은 단에 있는 모듈들 파라미터 생성 + const getMostLeftModules = (surface) => { + const { direction, modules } = surface + const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId) + const roofMaterialIndex = parent.roofMaterial.index + const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction + let isEaveBar = construction.setupCover + let isSnowGuard = construction.setupSnowCover + let { rackYn, cvrPlvrYn, moduleIntvlHor, moduleIntvlVer, rackQty, lessSupFitQty } = surface.trestleDetail + cvrPlvrYn = 'Y' + if (rackYn === 'N') { + rackQty = lessSupFitQty + } + + // 같은 단에 있는 모듈들의 리스트 + let sameLineModuleList = [] + let result = [] + + if (direction === 'south') { + // 모듈의 top으로 groupBy + const groupedByTop = modules.reduce((acc, module) => { + const key = module.top + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(module) + return acc + }, {}) + // groupedByTop의 키값을 기준으로 정렬한 데이터를 배열로 변환 + sameLineModuleList = Object.values(groupedByTop).sort((a, b) => b[0].top - a[0].top) + } else if (direction === 'north') { + const groupedByTop = modules.reduce((acc, module) => { + const key = module.top + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(module) + return acc + }, {}) + sameLineModuleList = Object.values(groupedByTop).sort((a, b) => a[0].top - b[0].top) + } else if (direction === 'east') { + const groupedByLeft = modules.reduce((acc, module) => { + const key = module.left + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(module) + return acc + }, {}) + sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => a[0].left - b[0].left) + } else if (direction === 'west') { + const groupedByLeft = modules.reduce((acc, module) => { + const key = module.left + if (!acc[key]) { + acc[key] = [] + } + acc[key].push(module) + return acc + }, {}) + sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => b[0].left - a[0].left) + } + sameLineModuleList.forEach((modules, index) => { + const moduleRowResultData = { + seq: index, + moduleItemId: modules[0].moduleInfo.itemId, + moduleTpCd: modules[0].moduleInfo.itemTp, + moduleCnt: modules.length, + exposedBottomCnt: 0, + exposedHalfBottomCnt: 0, + exposedTopCnt: 0, + exposedHalfTopCnt: 0, + touchedSurfaceCnt: 0, + touchedHalfSurfaceCnt: 0, + exposedBottomBracketCnt: 0, + exposedHalfBottomBracketCnt: 0, + exposedTopBracketCnt: 0, + exposedHalfTopBracketCnt: 0, + touchedSurfaceBracketCnt: 0, + touchedHalfSurfaceBracketCnt: 0, + eavesCnt: 0, + eavesHalfCnt: 0, + exposedSideEavesCnt: 0, + } + + if (direction === 'south') { + modules.sort((a, b) => a.left - b.left) + } else if (direction === 'north') { + modules.sort((a, b) => b.left - a.left) + } else if (direction === 'east') { + modules.sort((a, b) => a.top - b.top) + } else if (direction === 'west') { + modules.sort((a, b) => b.top - a.top) + } + // 모듈 하면,최하면 등 구해야함 + modules.forEach((module, index) => { + // 해당 모듈 주변에 다른 모듈이 있는지 확인 + let { bottomModule, topModule, bottomLeftModule, bottomRightModule, topLeftModule, topRightModule } = findSideModule(module, surface) + if (bottomModule) { + moduleRowResultData.touchedSurfaceCnt++ + } + if (!bottomModule) { + if (bottomLeftModule && bottomRightModule) { + moduleRowResultData.touchedSurfaceCnt++ + } else if ((bottomLeftModule && !bottomRightModule) || (!bottomLeftModule && bottomRightModule)) { + moduleRowResultData.touchedHalfSurfaceCnt++ + moduleRowResultData.exposedHalfBottomCnt++ + if (cvrPlvrYn === 'Y') { + moduleRowResultData.eavesHalfCnt++ + } + } else { + moduleRowResultData.exposedBottomCnt++ + if (isEaveBar) { + moduleRowResultData.eavesCnt++ + } + } + } + if (!topModule) { + if ((topLeftModule && !topRightModule) || (!topLeftModule && topRightModule)) { + moduleRowResultData.exposedHalfTopCnt++ + } else if (!topLeftModule && !topRightModule) { + moduleRowResultData.exposedTopCnt++ + } + } + }) + + result.push(moduleRowResultData) + }) + + if (isEaveBar) { + } + + return result + } + + // 해당 모듈이 해당 설치면에서 상하좌우, 대각선에 있는지 확인 + const findSideModule = (module, surface) => { + const { direction, modules } = surface + let { rackYn, cvrPlvrYn, moduleIntvlHor, moduleIntvlVer, rackQty, lessSupFitQty } = surface.trestleDetail + + const centerPoints = modules.map((module) => { + return module.getCenterPoint() + }) + + const horizontal = ['south', 'north'].includes(direction) ? moduleIntvlHor : moduleIntvlVer + + const vertical = ['south', 'north'].includes(direction) ? moduleIntvlVer : moduleIntvlHor + const maxX = 2 + horizontal * 3 + const maxY = 2 + vertical * 3 + let { width, height } = { ...module } + let { x, y } = { ...module.getCenterPoint() } + + let bottomLeftPoint + let bottomRightPoint + + let topLeftPoint + let topRightPoint + let bottomModule + let topModule + let bottomLeftModule + let bottomRightModule + let topLeftModule + let topRightModule + + switch (direction) { + case 'south': + width = width + horizontal + height = height + vertical + bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY) + bottomLeftPoint = { x: x - width / 2, y: y + height } + bottomRightPoint = { x: x + width / 2, y: y + height } + topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY) + topLeftPoint = { x: x - width / 2, y: y - height } + topRightPoint = { x: x + width / 2, y: y - height } + break + case 'north': + width = width + horizontal + height = height + vertical + bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY) + bottomLeftPoint = { x: x + width / 2, y: y - height } + bottomRightPoint = { x: x - width / 2, y: y - height } + topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY) + topLeftPoint = { x: x + width / 2, y: y + height } + topRightPoint = { x: x - width / 2, y: y + height } + break + case 'east': + bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY) + width = width + horizontal + bottomLeftPoint = { x: x + width, y: y + height / 2 } + bottomRightPoint = { x: x + width, y: y - height / 2 } + topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY) + topLeftPoint = { x: x - width, y: y + height / 2 } + topRightPoint = { x: x - width, y: y - height / 2 } + break + case 'west': + bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY) + width = width + horizontal + bottomLeftPoint = { x: x - width, y: y - height / 2 } + bottomRightPoint = { x: x - width, y: y + height / 2 } + topLeftPoint = { x: x + width, y: y - height / 2 } + topRightPoint = { x: x + width, y: y + height / 2 } + topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY) + break + } + + topLeftModule = centerPoints.find( + (centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY, + ) + topRightModule = centerPoints.find( + (centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY, + ) + bottomLeftModule = centerPoints.find( + (centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY, + ) + bottomRightModule = centerPoints.find( + (centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY, + ) + + return { bottomModule, topModule, bottomLeftModule, bottomRightModule, topLeftModule, topRightModule } + } + + return { apply, getTrestleParams } } diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js index 550bc5c0..425f0642 100644 --- a/src/hooks/roofcover/usePropertiesSetting.js +++ b/src/hooks/roofcover/usePropertiesSetting.js @@ -122,40 +122,47 @@ export function usePropertiesSetting(id) { const handleFix = () => { const isClose = confirm('외벽선 속성 설정을 완료하시겠습니까?') if (isClose) { + const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + + const notSetAttributes = lines.filter((line) => !line.attributes?.type) + if (notSetAttributes.length > 0) { + // 세팅이 하나라도 안되어있으면 초기화 + lines.forEach((line) => { + line.set({ + stroke: '#000000', + strokeWidth: 4, + }) + }) + canvas.discardActiveObject() + closePopup(id) + return + } + + lines.forEach((line) => { + line.set({ + attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL }, + stroke: '#000000', + strokeWidth: 4, + }) + + hideLine(line) + }) + + const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) + + wall.lines = [...lines] + + const roof = drawRoofPolygon(wall) + + setPoints([]) + canvas.renderAll() + roof.drawHelpLine() + closePopup(id) return } else { return } - - const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') - - const notSetAttributes = lines.filter((line) => !line.attributes?.type) - if (notSetAttributes.length > 0) { - alert('설정되지 않은 외벽선이 있습니다.') - return - } - - lines.forEach((line) => { - line.set({ - attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL }, - stroke: '#000000', - strokeWidth: 4, - }) - - hideLine(line) - }) - - const wall = addPolygonByLines(lines, { name: POLYGON_TYPE.WALL, fill: 'transparent', stroke: 'black' }) - - wall.lines = [...lines] - - const roof = drawRoofPolygon(wall) - - setPoints([]) - canvas.renderAll() - roof.drawHelpLine() - closePopup(id) } const closeModal = (fn) => { diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index 89f88607..4cb3586f 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -1,6 +1,6 @@ 'use client' -import { useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue } from 'recoil' import { canvasState, globalPitchState } from '@/store/canvasAtom' import { MENU, POLYGON_TYPE } from '@/common/common' import { getIntersectionPoint } from '@/util/canvas-util' @@ -16,11 +16,13 @@ import { fontSelector } from '@/store/fontAtom' import { slopeSelector } from '@/store/commonAtom' import { QLine } from '@/components/fabric/QLine' import { useRoofFn } from '@/hooks/common/useRoofFn' +import { outerLinePointsState } from '@/store/outerLineAtom' export function useSurfaceShapeBatch() { const { getMessage } = useMessage() const { drawDirectionArrow } = usePolygon() const lengthTextFont = useRecoilValue(fontSelector('lengthText')) + const [points, setPoints] = useRecoilState(outerLinePointsState) const canvas = useRecoilValue(canvasState) const globalPitch = useRecoilValue(globalPitchState) @@ -653,6 +655,7 @@ export function useSurfaceShapeBatch() { type: 'confirm', confirmFn: () => { canvas.clear() + setPoints([]) swalFire({ text: getMessage('plan.message.delete') }) }, // denyFn: () => {