import { GlobalDataContext } from '@/app/GlobalDataProvider' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' import { useContext, useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { useMasterController } from '@/hooks/common/useMasterController' import { v4 as uuidv4 } from 'uuid' import { globalLocaleStore } from '@/store/localeAtom' import { POLYGON_TYPE } from '@/common/common' import { useSwal } from '@/hooks/useSwal' import { circuitNumDisplaySelector } from '@/store/settingAtom' import { fontSelector } from '@/store/fontAtom' import { PCS_MKR_MULTI_TYPE } from './PowerConditionalSelect' export default function StepUp(props) { const { models, allocationType, stepUpListData, setStepUpListData, seletedMainOption, setSeletedMainOption, seletedSubOption, setSeletedSubOption, selectedMaker, selectedModels, setSelectedModels, getSelectedPcsItemList, getModuleList, setModuleStatisticsData, } = props const { getMessage } = useMessage() const { swalFire } = useSwal() const globalLocale = useRecoilValue(globalLocaleStore) const [moduleTab, setModuleTab] = useState(1) const [moduleTabs, setModuleTabs] = useState({}) const [arrayLength, setArrayLength] = useState(3) //module-table-inner의 반복 개수 const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const { getPcsVoltageStepUpList, getPcsAutoRecommendList, getPcsVoltageChk, getPcsConnOptionItemList } = useMasterController() const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) const [optCodes, setOptCodes] = useState([]) const [mainOptions, setMainOptions] = useState([]) const [subOptions, setSubOptions] = useState([]) const [selectedRows, setSelectedRows] = useState({}) const [isManualSelection, setIsManualSelection] = useState({}) const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector) const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText')) useEffect(() => { if (allocationType === 'auto') { /** 자동일 때 모듈의 회로 정보 초기화 */ canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE) .forEach((module) => { module.circuit = null module.circuitNumber = null module.pcsItemId = null }) canvas.renderAll() /** PCS 자동 승압설정 정보 조회 */ fetchAutoStepUpData() } else { /** PCS 수동 승압설정 정보 조회 */ fetchPassiStepUpData() } }, []) /** * PCS 자동 승압설정 정보 조회 */ const isMultiOptions = () => { return selectedModels.some((model) => model.pcsSerParallelYn === 'Y') } const fetchAutoStepUpData = async () => { try { const params = { ...props.getOptYn() /** 옵션 Y/N */, useModuleItemList: props.getUseModuleItemList() /** 사용된 모듈아이템 List */, roofSurfaceList: props.getRoofSurfaceList() /** 지붕면 목록 */, pcsItemList: props.getSelectedPcsItemList() /** PCS 아이템 목록 */, } /** 회로 구성 가능 여부 체크 통과 시 승압설정 정보 조회 */ getPcsVoltageStepUpList(params).then((res) => { if (res?.result.resultCode === 'S' && res?.data) { const dataArray = Array.isArray(res.data) ? res.data : [res.data] const stepUpListData = formatStepUpListData(dataArray) /** PCS 승압설정 정보 SET */ setStepUpListData(stepUpListData) /** PCS 옵션 조회 */ // const formattedOptCodes = formatOptionCodes(res.data.optionList) // setOptCodes(formattedOptCodes) // setSeletedOption(formattedOptCodes[0]) /** 캔버스에 회로 정보 적용 */ // 병설일때 pcs 있으면 setSubOpsions, 없으면 setMainOptions console.log('stepUpListData', stepUpListData) let mChk = 0; stepUpListData[0].pcsItemList.forEach((pcsItem, index) => { const optionList = formatOptionCodes(pcsItem.optionList) if (isMultiOptions()) { if (index === 0) { setMainOptions(optionList) setSeletedMainOption(optionList[0]) } else { setSubOptions(optionList) setSeletedSubOption(optionList[0]) } } else { if (index === 0) { setMainOptions(optionList) setSeletedMainOption(optionList[0]) } } const selectedSerQty = pcsItem.serQtyList.find((serQty) => serQty.selected) if (selectedSerQty) { selectedSerQty.roofSurfaceList.forEach((roofSurface) => { const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0] const moduleIds = targetSurface.modules.map((module) => module.id) /** 기존 모듈 텍스트 삭제 */ canvas .getObjects() .filter((obj) => moduleIds.includes(obj.parentId)) .forEach((text) => canvas.remove(text)) /** 새로운 모듈 회로 정보 추가 */ roofSurface.moduleList.forEach((module) => { const targetModule = canvas.getObjects().find((obj) => obj.id === module.uniqueId) if (targetModule && module.circuit !== '' && module.circuit) { const moduleCircuitText = new fabric.Text(module.circuit, { left: targetModule.left + targetModule.width / 2, top: targetModule.top + targetModule.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: targetModule.width, height: targetModule.height, textAlign: 'center', originX: 'center', originY: 'center', name: 'circuitNumber', parentId: targetModule.id, circuitInfo: module.pcsItemId, selectable: false, visible: isDisplayCircuitNumber, }) targetModule.circuit = moduleCircuitText targetModule.pcsItemId = module.pcsItemId targetModule.circuitNumber = module.circuit canvas.add(moduleCircuitText) } else { mChk++; } }) }) } }) canvas.renderAll() setModuleStatisticsData() if (mChk > 0) { swalFire({ text: getMessage('modal.circuit.trestle.setting.step.up.allocation.module.over.count') }) } } else { swalFire({ text: getMessage('common.message.send.error') }) } }) } catch (error) { console.error('Error fetching step up data:', error) } } /** * PCS 수동 승압설정 정보 조회 */ const fetchPassiStepUpData = async () => { try { /** 모듈 데이터 가져오기 */ const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE) /** PCS별 회로 정보를 저장할 객체 */ const pcsSummary = {} /** 각 모듈을 순회하며 PCS별 회로 정보 수집 */ modules.forEach((module) => { if (!module.circuit || !module.pcsItemId) return if (!pcsSummary[module.circuit.circuitInfo.id]) { pcsSummary[module.circuit.circuitInfo.id] = { circuits: {}, totalModules: 0, } } const circuitNumber = module.circuitNumber if (!pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber]) { pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber] = 0 } pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber]++ pcsSummary[module.circuit.circuitInfo.id].totalModules++ }) const params = { useModuleItemList: props.getUseModuleItemList(), pcsItemList: getSelectedPcsItemList(), } /** PCS 접속함 및 옵션 목록 조회 */ getPcsConnOptionItemList(params).then((res) => { if (res?.result.code === 200 && res?.data) { /** PCS 아이템 리스트에 serQtyList 추가 */ const pcsItemListWithSerQty = res.data.pcsItemList.map((pcsItem, index) => { const pcsData = pcsSummary[selectedModels[index].id] || { circuits: {}, totalModules: 0 } const circuitCounts = Object.values(pcsData.circuits) const optionList = formatOptionCodes(pcsItem.optionList) if (isMultiOptions()) { if (index === 0) { setMainOptions(optionList) setSeletedMainOption(optionList[0]) } else { setSubOptions(optionList) setSeletedSubOption(optionList[0]) } } else { if (index === 0) { setMainOptions(optionList) setSeletedMainOption(optionList[0]) } } return { ...pcsItem, serQtyList: [ { /** 한 회로당 최대 모듈 수 */ serQty: circuitCounts.length > 0 ? Math.max(...circuitCounts) : 0, /** 회로 개수 */ paralQty: Object.keys(pcsData.circuits).length || 0, rmdYn: 'Y', usePossYn: 'Y', roofSurfaceList: props.getRoofSurfaceList(), }, ], } }) /** res.data with modified pcsItemList */ res.data.pcsItemList = pcsItemListWithSerQty const dataArray = Array.isArray(res.data) ? res.data : [res.data] const stepUpListData = formatStepUpListData(dataArray) /** PCS 승압설정 정보 SET */ setStepUpListData(stepUpListData) /** PCS 옵션 조회 */ // const formattedOptCodes = formatOptionCodes(res.data.optionList) // setOptCodes(formattedOptCodes) // setSeletedOption(formattedOptCodes[0]) } }) } catch (error) { console.error('Error fetching step up data:', error) } } /** * PCS 옵션 조회 */ const formatOptionCodes = (optionList = []) => { return optionList?.map((opt) => ({ code: opt.pcsOptCd ?? '', name: opt.pcsOptNm ?? '', nameJp: opt.pcsOptNmJp ?? '', })) } /** * PCS 승압설정 정보 포맷 후 추천 값 저장 */ const formatStepUpListData = (dataArray = []) => { const formattedData = dataArray?.map((stepUps) => ({ ...stepUps, optionList: formatOptionList(stepUps.optionList), pcsItemList: formatPcsItemList(stepUps.pcsItemList), selectedPcsItem: formatPcsItemList(stepUps.pcsItemList), })) return formattedData } /** * PCS 옵션 포맷 */ const formatOptionList = (optionList = []) => { return optionList?.map((option) => ({ pcsOptCd: option.pcsOptCd ?? '', pcsOptNm: option.pcsOptNm ?? '', pcsOptNmJp: option.pcsOptNmJp ?? '', })) } /** * PCS 아이템 포맷 */ const formatPcsItemList = (pcsItemList = []) => { return pcsItemList?.map((item, index) => ({ goodsNo: item.goodsNo ? item.goodsNo : '', itemId: item.itemId ? item.itemId : '', itemNm: item.itemNm ? item.itemNm : '', pcsMkrCd: item.pcsMkrCd ? item.pcsMkrCd : '', pcsSerCd: item.pcsSerCd ? item.pcsSerCd : '', uniqueIndex: `${item.itemId}_${index}`, // 고유 식별자 추가(동일한 PCS를 구분) connList: formatConnList(item.connList), serQtyList: formatSerQtyList(item.serQtyList), optionList: item.optionList ?? [], })) } /** * PCS 연결 포맷 */ const formatConnList = (connList = []) => { if (!connList) return [] // null인 경우 빈 배열 반환 return connList?.map((conn) => ({ connAllowCur: conn.connAllowCur ?? 0, connMaxParalCnt: conn.connMaxParalCnt ?? 0, goodsNo: conn.goodsNo ?? '', itemId: conn.itemId ?? '', itemNm: conn.itemNm ?? '', vstuParalCnt: conn.vstuParalCnt ?? 0, })) } /** * PCS 시리즈 포맷 */ const formatSerQtyList = (serQtyList = []) => { return serQtyList?.map((qty) => ({ code: uuidv4(), serQty: qty.serQty ?? 0, paralQty: qty.paralQty ?? 0, rmdYn: qty.rmdYn ?? 'N', usePossYn: qty.usePossYn ?? 'Y', roofSurfaceList: formatRoofSurfaceList(qty.roofSurfaceList), selected: qty.rmdYn === 'Y', })) } /** * PCS RoofSurface 포맷 */ const formatRoofSurfaceList = (roofSurfaceList = []) => { return roofSurfaceList?.map((rsf) => ({ moduleList: formatModuleList(rsf.moduleList), roofSurface: rsf.roofSurface ?? '', roofSurfaceId: rsf.roofSurfaceId ?? '', roofSurfaceIncl: rsf.roofSurfaceIncl ? +rsf.roofSurfaceIncl : '', })) } /** * PCS MatModule 포맷 */ const formatModuleList = (moduleList = []) => { return moduleList?.map((module) => ({ circuit: module.circuit ?? '', itemId: module.itemId ?? '', pcsItemId: module.pcsItemId ?? '', uniqueId: module.uniqueId ?? '', })) } /** * 각 모듈의 탭을 변경하는 함수 */ const handleTabChange = (goodsNo, idx, tabNumber) => { setModuleTabs((prev) => ({ ...prev, [`${goodsNo}_${idx}`]: tabNumber, })) } /** * 행 선택 핸들러 함수 추가 */ const handleRowClick = (mainIdx, subIdx) => { /** 자동 승압 설정인 경우만 실행 */ if (allocationType !== 'auto') return let tempStepUpListData = [...stepUpListData] let selectedData = {} tempStepUpListData[0].pcsItemList[mainIdx].serQtyList.forEach((item, index) => { if (index === subIdx) { selectedData = item } item.selected = index === subIdx }) /** 선택된 행 정보 저장 */ setStepUpListData(tempStepUpListData) /** PCS 2개 이상 또는 첫번째 PCS 선택 시에만 실행 */ if (tempStepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) { /** 파워컨디셔너 옵션 조회 요청 파라미터 */ const params = { ...props.getOptYn(), // 옵션 Y/N useModuleItemList: props.getUseModuleItemList(), // 사용된 모듈아이템 List roofSurfaceList: props.getRoofSurfaceList(), // 지붕면 목록 pcsItemList: props.getSelectedPcsItemList().map((pcsItem, index) => { /** PCS 아이템 목록 * tempStepUpListData에서 해당 PCS 아이템 찾기 * uniqueIndex를 사용하여 매칭 */ const matchingPcsItem = tempStepUpListData[0].pcsItemList.find((item) => item.uniqueIndex === `${pcsItem.itemId}_${index}`) /** 선택된 serQty 찾기 */ const selectedSerQty = matchingPcsItem?.serQtyList.find((serQty) => serQty.selected)?.serQty || 0 return { ...pcsItem, applySerQty: selectedSerQty, } }), } /** PCS가 1개 이고 2번째 또는 3번째 PCS serQty가 0인 경우는 추천 API 실행하지 않음 */ if (params.pcsItemList.length !== 1 && (params.pcsItemList[1]?.applySerQty !== 0 || params.pcsItemList[2]?.applySerQty) !== 0) { /** PCS 승압설정 정보 조회 */ getPcsVoltageStepUpList(params).then((res) => { if (res?.result.resultCode === 'S' && res?.data) { const dataArray = Array.isArray(res.data) ? res.data : [res.data] const stepUpListData = formatStepUpListData(dataArray) /** PCS 승압설정 정보 SET */ setStepUpListData(stepUpListData) /** PCS 옵션 조회 */ // const formattedOptCodes = formatOptionCodes(res.data.optionList) // setOptCodes(formattedOptCodes) // setSeletedOption(formattedOptCodes[0]) } else { swalFire({ text: getMessage('common.message.send.error') }) } }) } } /** 모듈 목록 삭제 */ canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE) .forEach((module) => { module.circuit = null module.circuitNumber = null module.pcsItemId = null }) /** 선택된 모듈 목록 추가 */ selectedData.roofSurfaceList.forEach((roofSurface) => { const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0] const moduleIds = targetSurface.modules.map((module) => { return module.id }) /** 모듈 목록 삭제 */ canvas .getObjects() .filter((obj) => moduleIds.includes(obj.parentId)) .map((text) => { canvas.remove(text) }) /** 모듈 목록 추가 */ canvas.renderAll() roofSurface.moduleList.forEach((module) => { const targetModule = canvas.getObjects().find((obj) => obj.id === module.uniqueId) if (targetModule && module.circuit !== '' && module.circuit !== null) { const moduleCircuitText = new fabric.Text(module.circuit, { left: targetModule.left + targetModule.width / 2, top: targetModule.top + targetModule.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: targetModule.width, height: targetModule.height, textAlign: 'center', originX: 'center', originY: 'center', name: 'circuitNumber', parentId: targetModule.id, circuitInfo: module.pcsItemId, visible: isDisplayCircuitNumber, }) targetModule.circuit = moduleCircuitText targetModule.pcsItemId = module.pcsItemId targetModule.circuitNumber = module.circuit canvas.add(moduleCircuitText) } }) }) canvas.renderAll() setModuleStatisticsData() } /** * 현재 선택된 값들을 가져오는 함수 추가 */ const getCurrentSelections = () => { const selectedValues = stepUpListData[0].pcsItemList.forEach((item) => { item.serQtyList.filter((serQty) => serQty.selected) return item.serQtyList.map((serQty) => { return { pcsMkrCd: serQty.pcsMkrCd, pcsSerCd: serQty.pcsSerCd, pcsItemId: serQty.itemId, pcsOptCd: seletedOption, paralQty: serQty.paralQty, connections: { connItemId: item.connList[0].itemId, }, } }) }) return selectedValues } /** props로 getCurrentSelections 함수 전달 */ useEffect(() => { if (props.onInitialize) { props.onInitialize(getCurrentSelections) } }, []) /** stepUpListData가 변경될 때마다 업데이트하는 useEffect */ useEffect(() => { if (props.onInitialize) { /** onInitialize를 props에서 가져옴 */ props.onInitialize(() => ({ ...getCurrentSelections(), stepUpListData /** stepUpListData를 포함하여 반환 */, })) } }, [stepUpListData]) return ( <>

{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}

{mainOptions.length > 0 && ( setSeletedMainOption(e)} /> )}
{isMultiOptions() && selectedModels.length === 2 && (
{subOptions.length > 0 && ( setSeletedSubOption(e)} /> )}
)}
{/*
{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')} {optCodes.length > 0 && (
{ return { ...roof, name: globalLocale === 'ko' ? roof.name : roof.nameJp } })} title={globalLocale === 'ko' ? optCodes[0].name : optCodes[0].nameJp} value={seletedOption} sourceKey="code" targetKey="code" showKey="name" onChange={(e) => setSeletedOption(e)} />
)}
*/}
{/* 3개일때 className = by-max */} {stepUpListData.map((stepUp, index) => (
{stepUp?.pcsItemList.map((pcsItem, idx) => (
{stepUp.pcsItemList[idx].goodsNo}
{pcsItem.serQtyList.map((item, serQtyIdx) => { return ( handleRowClick(idx, serQtyIdx)} style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }} > ) })}
{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')} {getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}
{item.serQty} {item.paralQty}
{(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 1 && (
{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')} {getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')} {getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}
{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 : '-'}
)} {(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 2 && (
{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')} {getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}
- -
)}
))}
))}
) }