2025-02-19 17:06:04 +09:00

655 lines
26 KiB
JavaScript

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'
export default function StepUp(props) {
const {
models,
allocationType,
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
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 { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState)
const [optCodes, setOptCodes] = useState([])
const [selectedRows, setSelectedRows] = useState({})
const [isManualSelection, setIsManualSelection] = useState({})
// 선택된 값들을 저장할 상태 추가
const [selectedValues, setSelectedValues] = useState({})
const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector)
const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText'))
// useCanvasPopupStatusController(6)
// const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore)
// if (Object.keys(canvasPopupStatusState[6]).length !== 0) {
// console.log('🚀 ~ useEffect ~ canvasPopupStatusState :', canvasPopupStatusState)
// }
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 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])
// 캔버스에 회로 정보 적용
//stepUpListData[0].pcsItemList.forEach((pcsItem) => {
stepUpListData[0].pcsItemList.forEach((pcsItem) => {
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().filter((obj) => obj.id === module.uniqueId)[0]
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)
})
})
}
})
canvas.renderAll()
setModuleStatisticsData()
} else {
swalFire({ text: getMessage('common.message.send.error') })
// swalFire({
// title: res.result.resultMsg,
// type: 'alert',
// })
}
})
} catch (error) {
console.error('Error fetching step up data:', error)
}
}
// PCS 수동 승압설정 정보 조회
const fetchPassiStepUpData = async () => {
try {
// 1-1 2-2
// canvas
// .getObjects()
// .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuit)
// .map((module) => module.circuitNumber)
// 모듈 데이터 가져오기
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.pcsItemId]) {
pcsSummary[module.pcsItemId] = {
circuits: {},
totalModules: 0,
}
}
const circuitNumber = module.circuitNumber
if (!pcsSummary[module.pcsItemId].circuits[circuitNumber]) {
pcsSummary[module.pcsItemId].circuits[circuitNumber] = 0
}
pcsSummary[module.pcsItemId].circuits[circuitNumber]++
pcsSummary[module.pcsItemId].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) => {
const pcsData = pcsSummary[pcsItem.itemId] || { circuits: {}, totalModules: 0 }
const circuitCounts = Object.values(pcsData.circuits)
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(),
},
],
}
})
// Update 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 ? opt.pcsOptCd : '',
name: opt.pcsOptNm ? opt.pcsOptNm : '',
nameJp: opt.pcsOptNmJp ? 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 ? option.pcsOptCd : '',
pcsOptNm: option.pcsOptNm ? option.pcsOptNm : '',
pcsOptNmJp: option.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),
}))
}
// PCS 연결 포맷
const formatConnList = (connList = []) => {
if (!connList) return [] // null인 경우 빈 배열 반환
return connList?.map((conn) => ({
connAllowCur: conn.connAllowCur ? conn.connAllowCur : 0,
connMaxParalCnt: conn.connMaxParalCnt ? conn.connMaxParalCnt : 0,
goodsNo: conn.goodsNo ? conn.goodsNo : '',
itemId: conn.itemId ? conn.itemId : '',
itemNm: conn.itemNm ? conn.itemNm : '',
vstuParalCnt: conn.vstuParalCnt ? conn.vstuParalCnt : 0,
}))
}
// PCS 시리즈 포맷
const formatSerQtyList = (serQtyList = []) => {
return serQtyList?.map((qty) => ({
code: uuidv4(),
serQty: qty.serQty ? qty.serQty : 0,
paralQty: qty.paralQty ? qty.paralQty : 0,
rmdYn: qty.rmdYn ? qty.rmdYn : 'N',
usePossYn: qty.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 ? rsf.roofSurface : '',
roofSurfaceId: rsf.roofSurfaceId ? rsf.roofSurfaceId : '',
roofSurfaceIncl: rsf.roofSurfaceIncl ? +rsf.roofSurfaceIncl : '',
}))
}
// PCS MatModule 포맷
const formatModuleList = (moduleList = []) => {
return moduleList?.map((module) => ({
circuit: module.circuit ? module.circuit : '',
itemId: module.itemId ? module.itemId : '',
pcsItemId: module.pcsItemId ? module.pcsItemId : '',
uniqueId: module.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)
// console.log('🚀 ~ handleRowClick ~ tempStepUpListData:', tempStepUpListData)
// console.log('🚀 ~ handleRowClick ~ selectedData:', selectedData)
// PCS 2개 이상 또는 첫번째 PCS 선택 시에만 실행
if (stepUpListData[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 승압설정 정보 조회
//const res = await getPcsVoltageStepUpList(params)
//getPcsManualConfChk(params).then((res) => {
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') })
// swalFire({
// title: res.result.resultMsg,
// type: 'alert',
// })
}
})
}
}
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().filter((obj) => obj.id === module.uniqueId)[0]
if (module.circuit === '') return
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 (
<>
<div className="properties-setting-wrap outer">
<div className="circuit-title-sel">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
</span>
{optCodes.length > 0 && (
<div className="grid-select mr10">
{/* <QSelectBox title={'電力検出ユニット (モニター付き)'} /> */}
<QSelectBox
//options={optCodes}
options={optCodes.map((roof) => {
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)}
/>
</div>
)}
</div>
</div>
<div className="slope-wrap">
<div className="circuit-overflow">
{/* 3개일때 className = by-max */}
{stepUpListData.map((stepUp, index) => (
<div key={index} className={`module-table-box ${stepUp.pcsItemList.length === 3 ? 'by-max' : ''}`}>
{stepUp?.pcsItemList.map((pcsItem, idx) => (
<div key={idx} className="module-table-inner">
<div className="mb-box">
<div className="circuit-table-tit">{stepUp.pcsItemList[idx].goodsNo}</div>
<div className="roof-module-table overflow-y min">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}</th>
</tr>
</thead>
<tbody>
{pcsItem.serQtyList.map((item, serQtyIdx) => {
return (
<tr
key={`row-${serQtyIdx}`}
className={`${item.selected ? 'on' : ''}`}
onClick={() => handleRowClick(idx, serQtyIdx)}
style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }}
>
<td className="al-r">{item.serQty}</td>
<td className="al-r">{item.paralQty}</td>
</tr>
)
})}
</tbody>
</table>
</div>
</div>
<div className="module-box-tab mb10">
<button
className={`module-btn ${(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 1 ? 'act' : ''}`}
onClick={() => handleTabChange(stepUp.pcsItemList[idx].goodsNo, idx, 1)}
>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.connected')}
</button>
<button
className={`module-btn ${(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 2 ? 'act' : ''}`}
onClick={() => handleTabChange(stepUp.pcsItemList[idx].goodsNo, idx, 2)}
>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.option')}
</button>
</div>
<div className="circuit-table-flx-wrap">
{(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 1 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.goodsNo ? stepUp.pcsItemList[idx].connList?.[0]?.goodsNo : '-'}
</td>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt
? (stepUp.pcsItemList[idx].connList?.[0]?.connMaxParalCnt ?? '-')
: '-'}
</td>
<td className="al-c">
{stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt ? stepUp.pcsItemList[idx].connList?.[0]?.vstuParalCnt : '-'}
</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
{(moduleTabs[`${stepUp.pcsItemList[idx].goodsNo}_${idx}`] || 1) === 2 && (
<div className="circuit-table-flx-box">
<div className="roof-module-table min mb10">
<table>
<thead>
<tr>
{/* <th>名称</th>
<th>昇圧回路数</th> */}
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>
</thead>
<tbody>
<tr>
<td className="al-c">-</td>
<td className="al-c">-</td>
</tr>
</tbody>
</table>
</div>
</div>
)}
</div>
</div>
))}
</div>
))}
</div>
</div>
</div>
</>
)
}