2025-02-04 20:06:52 +09:00

639 lines
21 KiB
JavaScript

import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState, useEffect, useContext } from 'react'
import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect'
import CircuitAllocation from '@/components/floor-plan/modal/circuitTrestle/step/CircuitAllocation'
import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp'
import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import PassivityCircuitAllocation from './step/type/PassivityCircuitAllocation'
import { useMasterController } from '@/hooks/common/useMasterController'
import { correntObjectNoState } from '@/store/settingAtom'
import { useRecoilValue } from 'recoil'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useRecoilState } from 'recoil'
import { makersState, modelsState, modelState, pcsCheckState, selectedMakerState, selectedModelsState, seriesState } from '@/store/circuitTrestleAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { canvasState } from '@/store/canvasAtom'
import { useTrestle } from '@/hooks/module/useTrestle'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { v4 as uuidv4 } from 'uuid'
import { stepUpListDataState } from '@/store/circuitTrestleAtom'
import { useEstimate } from '@/hooks/useEstimate'
const ALLOCATION_TYPE = {
AUTO: 'auto',
PASSIVITY: 'passivity',
}
export default function CircuitTrestleSetting({ id }) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const { apply } = useTrestle()
const { swalFire } = useSwal()
const { saveEstimate } = useEstimate()
const canvas = useRecoilValue(canvasState)
const [makers, setMakers] = useRecoilState(makersState)
const [selectedMaker, setSelectedMaker] = useRecoilState(selectedMakerState)
const [series, setSeries] = useRecoilState(seriesState)
const [models, setModels] = useRecoilState(modelsState)
const [selectedModels, setSelectedModels] = useRecoilState(selectedModelsState)
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const [tabNum, setTabNum] = useState(1)
const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO)
const [circuitAllocationType, setCircuitAllocationType] = useState(1)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState)
const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList } = useMasterController()
// 회로할당(승합설정)에서 선택된 값들을 저장할 상태 추가
const [selectedStepUpValues, setSelectedStepUpValues] = useState({})
const [getStepUpSelections, setGetStepUpSelections] = useState(null)
// const [stepUpListData, setStepUpListData] = useRecoilState(stepUpListDataState)
const [stepUpListData, setStepUpListData] = useState([])
const [seletedOption, setSeletedOption] = useState(null)
useEffect(() => {
if (!managementState) {
setManagementState(managementStateLoaded)
}
}, [])
// 수동할당 시 모듈 삭제
useEffect(() => {
if (allocationType === ALLOCATION_TYPE.PASSIVITY && tabNum === 2) {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
canvas.remove(...notAllocationModules)
canvas.renderAll()
}
}, [tabNum])
// 시리즈중 자동으로 추천 PCS 정보 조회
const onAutoRecommend = () => {
if (series.filter((s) => s.selected).length === 0) {
swalFire({
title: '시리즈를 선택해 주세요.',
type: 'alert',
})
return
}
const params = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
// 파워컨디셔너 추천 목록 조회
if (selectedModels.length === 0) {
// 시리즈중 자동으로 추천 PCS 정보 조회
getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) {
const itemList = models.filter((model) => {
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId)
})
const selectedModels = itemList.map((model) => {
return {
...model,
id: uuidv4(),
isUsed: false,
}
})
// 회로 구성 가능 여부 체크 요청 파라미터
const pcsVoltageChkParams = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
// 추천 목록 선택
setSelectedModels(selectedModels)
// 회로 구성 가능 여부 체크
getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
if (res.resultCode === 'S') {
setTabNum(2)
} else {
swalFire({
title: res.resultMsg,
type: 'alert',
})
}
})
} else {
// 데이터가 없는 경우 오류 메시지 확인 필요
if (res.result.resultCode === 'E') {
swalFire({
title: res.result.resultMsg,
type: 'alert',
})
} else {
swalFire({
title: '파워컨디셔너를 추가해 주세요.',
type: 'alert',
})
}
}
})
} else {
// 회로 구성 가능 여부 체크
getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList() }).then((res) => {
if (res.resultCode === 'S') {
// 회로 구성 가능 여부 체크 통과 시 승압설정 정보 조회
getPcsVoltageStepUpList({
...params,
pcsItemList: getSelectedPcsItemList(),
}).then((res) => {
setTabNum(2)
})
} else {
swalFire({
title: res.resultMsg,
type: 'alert',
})
}
})
}
}
// 옵션 Y/N
const getOptYn = () => {
return {
maxConnYn: pcsCheck.max ? 'Y' : 'N',
smpCirYn: pcsCheck.division ? 'Y' : 'N',
coldZoneYn: managementState?.coldRegionFlg === '1' ? 'Y' : 'N',
}
}
// PCS 아이템 목록
const getPcsItemList = () => {
return models.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
// 선택된 PCS 아이템 목록
const getSelectedPcsItemList = () => {
return selectedModels.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
// 사용된 모듈아이템 목록
const getUseModuleItemList = () => {
return selectedModules.itemList.map((m) => {
return {
itemId: m.itemId,
mixMatlNo: m.mixMatlNo,
}
})
}
// 지붕면 목록
const getRoofSurfaceList = () => {
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
roofSurfaceList.sort((a, b) => a.left - b.left || b.top - a.top)
return roofSurfaceList.map((obj) => {
return {
roofSurfaceId: obj.id,
roofSurface: canvas
.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,
moduleList: getModuleList(obj).map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber ? module.circuitNumber : null,
pcsItemId: module.circuit ? module.circuit?.pcsItemId : null,
uniqueId: module.id ? module.id : null,
}
}),
}
})
}
// 모듈 목록
const getModuleList = (surface) => {
let moduleList = []
let [xObj, yObj] = [{}, {}]
let [xPoints, yPoints] = [[], []]
surface.modules.forEach((module) => {
if (!xObj[module.left]) {
xObj[module.left] = module.left
xPoints.push(module.left)
}
if (!yObj[module.top]) {
yObj[module.top] = module.top
yPoints.push(module.top)
}
})
switch (surface.direction) {
case 'south':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => b - a)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => a.left - b.left)
} else {
temp.sort((a, b) => b.left - a.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'north':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => a - b)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => b.left - a.left)
} else {
temp.sort((a, b) => a.left - b.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'west':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => a - b)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => a.top - b.top)
} else {
temp.sort((a, b) => b.top - a.top)
}
moduleList = [...moduleList, ...temp]
})
break
case 'east':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => b - a)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => b.top - a.top)
} else {
temp.sort((a, b) => a.top - b.top)
}
moduleList = [...moduleList, ...temp]
})
break
default:
return []
}
return moduleList
}
// 자동할당 버튼 클릭 시
const onAutoAllocation = () => {
let moduleStdQty = 0
let moduleMaxQty = 0
const selectedModels = models.filter((m) => m.selected)
// 시리즈중 자동으로 추천 PCS 정보 조회
if (selectedModels.length === 0) {
onAutoRecommend()
} else {
// 모듈 최소 매수
moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty)
}, 0)
moduleMaxQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleMaxQty)
}, 0)
}
// const target = pcsCheck.max ? moduleMaxQty : moduleStdQty
// const placementModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// if (placementModules.length > target) {
// swalFire({
// title: '배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.',
// type: 'alert',
// })
// return
// }
// setAllocationType(ALLOCATION_TYPE.AUTO)
// setTabNum(2)
}
// 수동할당 버튼 클릭 시
const onPassivityAllocation = () => {
if (selectedModels.length === 0) {
const params = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
// 파워컨디셔너 추천 목록 조회
getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) {
const itemList = models.filter((model) => {
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId)
})
const selectedModels = itemList.map((model) => {
return {
...model,
id: uuidv4(),
}
})
const PcsVoltageChkParams = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(),
}
setSelectedModels(selectedModels)
getPcsVoltageChk(PcsVoltageChkParams).then((res) => {})
} else {
swalFire({
title: '파워컨디셔너를 추가해 주세요.',
type: 'alert',
})
}
})
} else if (pcsCheck.max) {
const moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty)
}, 0)
const moduleMaxQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleMaxQty)
}, 0)
const target = pcsCheck.max ? moduleMaxQty : moduleStdQty
const placementModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
if (placementModules.length > target) {
swalFire({
title: '배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.',
type: 'alert',
})
return
}
}
setAllocationType(ALLOCATION_TYPE.PASSIVITY)
}
// StepUp에서 선택된 값들을 처리하는 함수 수정
const handleStepUpValuesSelected = (selectionData) => {
const { gooodsNo } = selectionData
setSelectedStepUpValues((prev) => ({
...prev,
[gooodsNo]: selectionData,
}))
}
// StepUp 컴포넌트 초기화 핸들러
const handleStepUpInitialize = (getCurrentSelections) => {
setGetStepUpSelections(() => getCurrentSelections)
}
// 회로할당(승압설정) 저장 버튼 클릭 시
const onApply = async () => {
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.map((obj) => {
obj.pcses = getStepUpListData()
})
const result = await apply()
if (result) {
await saveEstimate(result)
}
removeNotAllocationModules()
}
const removeNotAllocationModules = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
canvas.remove(...notAllocationModules)
canvas.renderAll()
}
// 이전 버튼 클릭 시
const onClickPrev = () => {
setAllocationType(ALLOCATION_TYPE.AUTO)
swalFire({
text: '할당한 회로 번호가 초기화됩니다.',
type: 'alert',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
setAllocationType(ALLOCATION_TYPE.AUTO)
canvas.renderAll()
},
})
}
// 파워컨디셔너 컴포넌트 속성
const powerConditionalSelectProps = {
tabNum,
setTabNum,
makers,
setMakers,
selectedMaker,
setSelectedMaker,
series,
setSeries,
models,
setModels,
selectedModels,
setSelectedModels,
managementState,
}
// 수동할당 컴포넌트 속성
const passivityProps = {
tabNum,
setTabNum,
pcsCheck,
selectedModels,
setSelectedModels,
getOptYn,
getUseModuleItemList,
getRoofSurfaceList,
}
// 승압설정 컴포넌트 속성
const stepUpProps = {
tabNum,
setTabNum,
models,
setModels,
allocationType,
circuitAllocationType,
setCircuitAllocationType,
selectedModels,
setSelectedModels,
getSelectedPcsItemList,
getOptYn, // 옵션 Y/N
getUseModuleItemList, // 사용된 모듈아이템 List
getRoofSurfaceList, // 지붕면 목록
getPcsItemList, // PCS 아이템 목록
onValuesSelected: handleStepUpValuesSelected, // 선택된 값들을 처리하는 함수
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
getModuleList,
}
// 승압설정 목록 조회
const getStepUpListData = () => {
return stepUpListData[0].pcsItemList.map((item) => {
return item.serQtyList
.filter((serQty) => serQty.selected)
.map((serQty) => {
return {
pcsMkrCd: item.pcsMkrCd,
pcsSerCd: item.pcsSerCd,
pcsItemId: item.itemId,
pscOptCd: seletedOption.code,
paralQty: serQty.paralQty,
connections: [
{
connItemId: item.connList[0].itemId,
},
],
}
})[0]
})
}
// 닫기 버튼 클릭 시 처리하는 함수 추가
const handleClose = () => {
// // 회로 번호 텍스트 제거
// const circuitTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
// canvas.remove(...circuitTexts)
// // 모듈의 회로 정보 초기화
// canvas
// .getObjects()
// .filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// .forEach((obj) => {
// obj.circuit = null
// obj.pcsItemId = null
// obj.circuitNumber = null
// })
// canvas.renderAll()
// closePopup(id)
swalFire({
title: '변경사항을 저장하시겠습니까?',
//text: '저장하지 않은 변경사항은 모두 사라집니다.',
type: 'confirm',
confirmButtonText: '저장',
cancelButtonText: '취소',
icon: 'warning',
confirmFn: async () => {
// 저장 로직 실행
await onApply()
closePopup(id)
},
denyFn: () => {
// 회로 번호 텍스트 제거
const circuitTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
canvas.remove(...circuitTexts)
// 모듈의 회로 정보 초기화
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
obj.circuitNumber = null
})
canvas.renderAll()
closePopup(id)
},
})
}
return (
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
<div className={`modal-pop-wrap l-2`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.circuit.trestle.setting')} </h1>
{/* <button className="modal-close" onClick={() => closePopup(id)}> */}
<button className="modal-close" onClick={handleClose}>
닫기
</button>
</div>
<div className="modal-body">
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.circuit.trestle.setting.power.conditional.select')}</div>
<span className={`tab-arr ${tabNum === 2 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 2 ? 'act' : ''}`}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</div>
</div>
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...passivityProps} />}
{tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => onAutoRecommend()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className="btn-frame modal act" onClick={() => onPassivityAllocation()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div>
)}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')}
</button>
<button className="btn-frame modal act" onClick={() => setTabNum(2)}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</button>
</div>
)}
{tabNum === 2 && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => setTabNum(1)}>
{getMessage('modal.common.prev')}
</button>
{/* <button className="btn-frame modal act" onClick={() => apply()}> */}
<button className="btn-frame modal act" onClick={onApply}>
{getMessage('modal.common.save')}({getMessage('modal.circuit.trestle.setting.circuit.allocation')})
</button>
</div>
)}
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable>
)
}