From bdd7de6fff9d6fc2e3f914ec17098707dbe84a41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Wed, 15 Jan 2025 18:51:53 +0900 Subject: [PATCH 1/4] =?UTF-8?q?=ED=9A=8C=EB=A1=9C.=20=EA=B0=80=EB=8C=80=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=9C=EB=B0=9C=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../circuitTrestle/CircuitTrestleSetting.jsx | 120 +++++++++++++----- .../step/PowerConditionalSelect.jsx | 56 ++++++-- .../modal/circuitTrestle/step/StepUp.jsx | 59 ++++++++- .../step/type/PassivityCircuitAllocation.jsx | 39 +++++- src/hooks/common/useMasterController.js | 34 ++++- src/store/circuitTrestleAtom.js | 5 + 6 files changed, 257 insertions(+), 56 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index b14bfa31..41bc9183 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -12,12 +12,15 @@ import { get } from 'react-hook-form' import { correntObjectNoState } from '@/store/settingAtom' import { useRecoilValue } from 'recoil' import { GlobalDataContext } from '@/app/GlobalDataProvider' + import { useRecoilState } from 'recoil' -import { powerConditionalState } from '@/store/circuitTrestleAtom' +import { modelState, pcsCheckState, powerConditionalState } from '@/store/circuitTrestleAtom' import { POLYGON_TYPE } from '@/common/common' import { useSwal } from '@/hooks/useSwal' import { canvasState } from '@/store/canvasAtom' +import { selectedModuleState } from '@/store/selectedModuleOptions' + const ALLOCATION_TYPE = { AUTO: 'auto', PASSIVITY: 'passivity', @@ -29,36 +32,21 @@ export default function CircuitTrestleSetting({ id }) { // 탭 번호 2: 회로 할당 const [tabNum, setTabNum] = useState(1) const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO) + + const [makers, setMakers] = useState([]) + const [series, setSeries] = useState([]) + const [model, setModel] = useRecoilState(modelState) + const [selectedModels, setSelectedModels] = useState(model.selectedModels) + const [models, setModels] = useState(model.models) + const [selectedMaker, setSelectedMaker] = useState(null) + const [selectedSeries, setSelectedSeries] = useState(null) + const correntObjectNo = useRecoilValue(correntObjectNoState) + const { getPcsMakerList } = useMasterController() + const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) + const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const canvas = useRecoilValue(canvasState) + const { apply } = useTrestle() const { swalFire } = useSwal() - - const apply = () => { - closePopup(id) - } - - useEffect(() => { - // console.log(canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)) - // if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length === 0) { - // swalFire({ - // title: '모듈을 배치해주세요.', - // type: 'alert', - // confirmFn: () => { - // closePopup(id) - // }, - // }) - // } - }, []) - - // useEffect(() => { - // console.log('🚀 ~ CircuitTrestleSetting ~ series:', series) - // const selectedSeries = series.filter((s) => s.selectd).map((s) => s.pcsSerCd) - // if (selectedSeries.length > 0) { - // getPcsMakerList(selectedSeries).then((res) => { - // setModels(res.data) - // }) - // } - // }, [series]) - // 회로 할당 유형 const [circuitAllocationType, setCircuitAllocationType] = useState(1) const powerConditionalSelectProps = { @@ -72,6 +60,76 @@ export default function CircuitTrestleSetting({ id }) { setCircuitAllocationType, } + useEffect(() => { + console.log('🚀 ~ CircuitTrestleSetting ~ model:', model) + setSelectedModels(model.selectedModels) + }, [model]) + + const onAutoAllocation = () => { + let moduleStdQty = 0 + let moduleMaxQty = 0 + + if (selectedModels.length === 0) { + moduleStdQty = models.reduce((acc, model) => { + return acc + parseInt(model.moduleStdQty) + }, 0) + + moduleMaxQty = models.reduce((acc, model) => { + return acc + parseInt(model.moduleMaxQty) + }, 0) + } 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) + } + + const onPassivityAllocation = () => { + console.log('🚀 ~ onPassivityAllocation ~ selectedModels:', model) + if (selectedModels.length === 0) { + swalFire({ + title: '파워 컨디셔너를 추가해 주세요.', + type: 'alert', + }) + return + } 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) + } + return (
@@ -94,10 +152,10 @@ export default function CircuitTrestleSetting({ id }) { {tabNum === 2 && } {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
- -
diff --git a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx index 420a2e35..a58abfc3 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect.jsx @@ -3,7 +3,8 @@ import QSelectBox from '@/components/common/select/QSelectBox' import { useMasterController } from '@/hooks/common/useMasterController' import { useEvent } from '@/hooks/useEvent' import { useMessage } from '@/hooks/useMessage' -import { makerState, modelState, seriesState } from '@/store/circuitTrestleAtom' +import { useSwal } from '@/hooks/useSwal' +import { makerState, modelState, pcsCheckState, seriesState } from '@/store/circuitTrestleAtom' import { globalLocaleStore } from '@/store/localeAtom' import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' import { useContext, useEffect, useState } from 'react' @@ -11,8 +12,6 @@ import { useRecoilState } from 'recoil' import { useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' -const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] - export default function PowerConditionalSelect(props) { let { tabNum, setTabNum } = props const [makerData, setMakerData] = useRecoilState(makerState) @@ -21,15 +20,17 @@ export default function PowerConditionalSelect(props) { const [series, setSeries] = useRecoilState(seriesState) const [seriesList, setSeriesList] = useState(series.series) const [selectedSeries, setSelectedSeries] = useState(series.selectedSeries) - const model = useRecoilValue(modelState) + const [model, setModel] = useRecoilState(modelState) const [models, setModels] = useState(model.models) const [selectedModels, setSelectedModels] = useState(model.selectedModels) + const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { getMessage } = useMessage() const [selectedRow, setSelectedRow] = useState(null) const globalLocale = useRecoilValue(globalLocaleStore) const { getPcsMakerList, getPcsModelList } = useMasterController() const selectedModules = useRecoilValue(selectedModuleState) + const { swalFire } = useSwal() const modelHeader = [ { name: getMessage('명칭'), width: '15%', prop: 'itemNm', type: 'color-box' }, { @@ -60,20 +61,26 @@ export default function PowerConditionalSelect(props) { setMakers(res.data) }) } + console.log('🚀 ~ useEffect ~ selectedModules:', selectedModules) if (!managementState) { - console.log('🚀 ~ useEffect ~ managementState:', managementState) setManagementState(managementStateLoaded) } // promiseGet({ url: `/api/object/${correntObjectNo}/detail` }).then((res) => { // console.log('🚀 ~ useEffect ~ /api/object/${correntObjectNo}/detail:', res) // // coldRegionFlg-한랭지사양, conType// 계약조건(잉여~,전량) // }) + return () => { + setMakerData({ makers, selectedMaker }) + setSeries({ series: seriesList, selectedSeries }) + setModel({ models, selectedModels }) + } }, []) useEffect(() => { console.log('🚀 ~ PowerConditionalSelect ~ selectedMaker:', selectedMaker) if (selectedMaker) { setSelectedModels([]) + setModels([]) getPcsMakerList(selectedMaker).then((res) => { setSeriesList( res.data.map((series) => { @@ -85,7 +92,6 @@ export default function PowerConditionalSelect(props) { }, [selectedMaker]) useEffect(() => { - console.log('🚀 ~ useEffect ~ seriesList:', seriesList) if (seriesList.filter((series) => series.selected).length === 0) return const pcsMkrCd = seriesList.filter((series) => series.selected)[0]?.pcsMkrCd const pcsSerList = seriesList @@ -99,7 +105,6 @@ export default function PowerConditionalSelect(props) { mixMatlNo: module.mixMatlNo, } }) - console.log('🚀 ~ useEffect ~ moduleItemList:', selectedModules) getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList }).then((res) => { if (res?.result.code === 200) { console.log('🚀 ~ useEffect ~ res:', res.data) @@ -107,6 +112,8 @@ export default function PowerConditionalSelect(props) { res.data.map((model) => { return { ...model, + moduleStdQty: parseInt(model.moduleStdQty), + moduleMaxQty: parseInt(model.moduleMaxQty), code: uuidv4(), selected: false, } @@ -116,26 +123,49 @@ export default function PowerConditionalSelect(props) { }) }, [seriesList]) + useEffect(() => { + console.log('🚀 ~ useEffect ~ models:', models) + }, [models]) + + useEffect(() => { + console.log('🚀 ~ useEffect ~ pcsCheck:', pcsCheck) + }, [pcsCheck]) + const onCheckSeries = (series) => { setSeriesList((prev) => prev.map((s) => ({ ...s, selected: s.pcsSerCd === series.pcsSerCd ? !s.selected : s.selected }))) } const onAddSelectedModel = () => { + if (selectedRow === null) return + if (selectedModels.length === 3) { + swalFire({ + title: '최대 3개까지 선택할 수 있습니다.', + icon: 'warning', + }) + + return + } setSelectedModels([...selectedModels, selectedRow]) setSelectedRow(null) } + const onRemoveSelectedModel = (model) => { + setSelectedModels(selectedModels.filter((m) => m.code !== model.code)) + } + useEffect(() => { - const selectedModelsIds = selectedModels.map((model) => model.itemId) + console.log('🚀 ~ useEffect ~ selectedModels:', selectedModels) + const selectedModelsIds = selectedModels.map((model) => model.code) setModels( models.map((model) => { return { ...model, - selected: selectedModelsIds.includes(model.itemId) === selectedRow.itemId ? true : false, + selected: selectedModelsIds.includes(model.code), } }), ) + setModel({ ...model, selectedModels: selectedModels }) }, [selectedModels]) return ( <> @@ -154,7 +184,7 @@ export default function PowerConditionalSelect(props) { onChange={(option) => setSelectedMaker(option)} />
- {managementState?.conType === '1' && ( + {managementState?.coldRegionFlg === '1' && ( {getMessage('modal.circuit.trestle.setting.power.conditional.select.cold.region')} )} @@ -206,7 +236,7 @@ export default function PowerConditionalSelect(props) {
{selectedModels?.map((model) => ( - {model.itemNm} + {model.itemNm} ))}
@@ -214,11 +244,11 @@ export default function PowerConditionalSelect(props) {
- + setPcsCheck({ ...pcsCheck, division: !pcsCheck.division })} />
- + setPcsCheck({ ...pcsCheck, max: !pcsCheck.max })} /> diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 287d9ff8..27efaae7 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -1,6 +1,11 @@ +import { GlobalDataContext } from '@/app/GlobalDataProvider' import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' -import { useState } from 'react' +import { canvasState } from '@/store/canvasAtom' +import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom' +import { selectedModuleState } from '@/store/selectedModuleOptions' +import { useContext, useState } from 'react' +import { useRecoilState } from 'recoil' const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] @@ -8,6 +13,58 @@ export default function StepUp({}) { const { getMessage } = useMessage() const [moduleTab, setModuleTab] = useState(1) const [arrayLength, setArrayLength] = useState(3) //module-table-inner의 반복 개수 + const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) + const model = useRecoilValue(modelState) + const { getPcsAutoRecommendList } = useMasterController() + const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) + const canvas = useRecoilValue(canvasState) + const selectedModules = useRecoilValue(selectedModuleState) + useEffect(() => { + if (!managementState) { + console.log('🚀 ~ useEffect ~ managementState:', managementState) + setManagementState(managementStateLoaded) + } + + const useModuleItemList = model.selectedModels.map((model) => { + return { itemId: model.itemId, mixMatlNo: model.mixMatlNo } + }) + // [{ roofSurfaceId: '', roofSurface: '', roofSurfaceIncl: '', moduleList: [{ itemId: '' }] }], + const roofSurfaceList = canvas + .getObjects() + .filter((obj) => ['roofSurface', 'moduleSetupSurface'].includes(obj.name)) + .map((obj) => { + return { + roofSurfaceId: obj.id, + roofSurface: obj.name, + roofSurfaceIncl: obj.angle, + moduleList: selectedModules.itemList?.map((module) => { + return { + itemId: module.itemId, + mixMatlNo: module.mixMatlNo, + } + }), + } + }) + // [{ itemId: '', pcsMkrCd: '', pcsSerCd: '' }], + const pscItemList = model.selectedModels.map((model) => { + return { + itemId: model.itemId, + pcsMkrCd: model.pcsMkrCd, + pcsSerCd: model.pcsSerCd, + } + }) + + const params = { + maxConnYn: pcsCheck.max, + smpCirYn: pcsCheck.division, + coldZoneYn: managementState.coldRegionFlg, + useModuleItemList: useModuleItemList, + roofSurfaceList: roofSurfaceList, + pscItemList: pscItemList, + } + getPcsAutoRecommendList(params) + }, []) + return ( <>
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 7c01cd6c..5ace632a 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -1,15 +1,22 @@ import { useMessage } from '@/hooks/useMessage' +import { modelState } from '@/store/circuitTrestleAtom' +import { selectedModuleState } from '@/store/selectedModuleOptions' +import { useEffect, useState } from 'react' +import { useRecoilValue } from 'recoil' export default function PassivityCircuitAllocation() { const { getMessage } = useMessage() + const selectedModules = useRecoilValue(selectedModuleState) const moduleData = { header: [ { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, - { name: getMessage('modal.circuit.trestle.setting.circuit'), prop: 'circuit' }, - { - name: getMessage('Q.TRON M-G2'), - prop: 'moduleName', - }, + { name: getMessage('modal.circuit.trestle.setting.circuilt'), prop: 'circuit' }, + ...selectedModules.itemList.map((module) => { + return { + name: module.itemNm, + prop: 'moduleName', + } + }), { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'powerGeneration', @@ -30,6 +37,12 @@ export default function PassivityCircuitAllocation() { }, ], } + const model = useRecoilValue(modelState) + const [selectedModels, setSelectedModels] = useState(model.selectedModels) + const [selectedPcs, setSelectedPcs] = useState(selectedModels[0]) + useEffect(() => { + console.log('🚀 ~ useEffect ~ selectedPcs:', selectedPcs) + }, [selectedPcs]) return ( <>
@@ -69,7 +82,19 @@ export default function PassivityCircuitAllocation() {
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional')}
-
+ {selectedModels.map((model, index) => ( +
+ setSelectedPcs(model)} + /> + +
+ ))} + {/*
@@ -80,7 +105,7 @@ export default function PassivityCircuitAllocation() {
-
+
*/}
diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js index f6dacdff..0e90fcdb 100644 --- a/src/hooks/common/useMasterController.js +++ b/src/hooks/common/useMasterController.js @@ -4,6 +4,8 @@ import { useSwal } from '@/hooks/useSwal' import { getQueryString } from '@/util/common-utils' import { trestleRequest, constructionRequest, trestleDetailRequest } from '@/models/apiModels' import { POST } from '@/app/api/image-upload/route' +import { canvasState } from '@/store/canvasAtom' +import { useRecoilValue } from 'recoil' /** * 마스터 컨트롤러 훅 @@ -130,21 +132,44 @@ export function useMasterController() { } /** - * PCS 메이커, 시리즈 목록 조회 - * @param {PCS 메이커코드} pcsMkrCd - * @param {혼합모듈번호} mixMatlNo + * 모듈 타입별 아이템 목록 조회 + * @param {PCS 메이커코드} pcsMkrCd + * @param {PCS시리즈코드 목록} pcsSerList + * @param {모듈아이템 ID 목록} moduleItemList * @returns */ const getPcsModelList = async (params = null) => { const test = { pcsMkrCd: 'MKR003', pcsSerList: [{ pcsSerCd: 'SER007' }, { pcsSerCd: 'SER009' }, { pcsSerCd: 'SER010' }], - moduleItemList: [{ itemId: '107015', mixMatlNo: '' }, { itemId: '107077' }, { itemId: '107015' }], + moduleItemList: [ + { itemId: '107015', mixMatlNo: null }, + { itemId: '107077', mixMatlNo: null }, + { itemId: '107015', mixMatlNo: null }, + ], } + return await post({ url: '/api/v1/master/getPcsSeriesItemList', data: test }).then((res) => { return res }) } + /** + * 시리즈중 자동으로 추천 PCS 정보 조회 + * @param {Max접속(과적)여부} maxConnYn + * @param {동일회로도여부} smpCirYn + * @param {한랭지여부} coldZoneYn + * @param {사용된 모듈 아이템 List} useModuleItemList + * @param {지붕면별 목록} roofSurfaceList + * @param {PCS 제품 목록} pcsItemList + * @returns + */ + const getPcsAutoRecommendList = async (params = null) => { + const paramString = getQueryString(params) + return await post({ url: '/api/master/pcsAutoRecommendList', data: params }).then((res) => { + console.log('🚀🚀 ~ getPcsAutoRecommendList ~ res:', res) + return res + }) + } return { getRoofMaterialList, @@ -154,5 +179,6 @@ export function useMasterController() { getTrestleDetailList, getPcsMakerList, getPcsModelList, + getPcsAutoRecommendList, } } diff --git a/src/store/circuitTrestleAtom.js b/src/store/circuitTrestleAtom.js index bac7ee7a..3fbb0b3e 100644 --- a/src/store/circuitTrestleAtom.js +++ b/src/store/circuitTrestleAtom.js @@ -15,3 +15,8 @@ export const modelState = atom({ key: 'modelState', default: { models: [], selectedModels: [] }, }) + +export const pcsCheckState = atom({ + key: 'divisionCircuitState', + default: { division: true, max: false }, +}) From 1d89b1f35558c12abb28ed97aa11b1cc8ad2f351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Thu, 16 Jan 2025 17:29:28 +0900 Subject: [PATCH 2/4] =?UTF-8?q?=ED=9A=8C=EB=A1=9C.=20=EA=B0=80=EB=8C=80=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=9C=EB=B0=9C=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../circuitTrestle/CircuitTrestleSetting.jsx | 3 +- .../modal/circuitTrestle/step/StepUp.jsx | 15 ++---- .../step/type/PassivityCircuitAllocation.jsx | 53 ++++++++++++++++--- src/locales/ja.json | 2 + src/locales/ko.json | 2 + 5 files changed, 58 insertions(+), 17 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 555ec619..75dba1a3 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -95,7 +95,8 @@ export default function CircuitTrestleSetting({ id }) { return } - setAllocationType(ALLOCATION_TYPE.AUTO) + // setAllocationType(ALLOCATION_TYPE.AUTO) + setTabNum(2) } const onPassivityAllocation = () => { diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 0898de1c..a3f69548 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -4,16 +4,11 @@ import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' import { modelState, pcsCheckState } from '@/store/circuitTrestleAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' -import { useContext, useState } from 'react' -import { useRecoilState } from 'recoil' -import { useState } from 'react' -import { useRecoilValue } from 'recoil' +import { useContext, useEffect, useState } from 'react' +import { useRecoilState, useRecoilValue } from 'recoil' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' -import { useMessage } from '@/hooks/useMessage' -import QSelectBox from '@/components/common/select/QSelectBox' - -const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] +import { useMasterController } from '@/hooks/common/useMasterController' export default function StepUp({}) { const { getMessage } = useMessage() @@ -25,6 +20,7 @@ export default function StepUp({}) { const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) + useEffect(() => { if (!managementState) { console.log('🚀 ~ useEffect ~ managementState:', managementState) @@ -71,7 +67,6 @@ export default function StepUp({}) { getPcsAutoRecommendList(params) }, []) - useCanvasPopupStatusController(6) const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore) if (Object.keys(canvasPopupStatusState[6]).length !== 0) { @@ -186,7 +181,7 @@ export default function StepUp({}) { {getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
- +
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 5ace632a..cd2e4469 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -1,16 +1,27 @@ +import { GlobalDataContext } from '@/app/GlobalDataProvider' import { useMessage } from '@/hooks/useMessage' +import { canvasState } from '@/store/canvasAtom' import { modelState } from '@/store/circuitTrestleAtom' import { selectedModuleState } from '@/store/selectedModuleOptions' -import { useEffect, useState } from 'react' +import { useContext, useEffect, useState } from 'react' import { useRecoilValue } from 'recoil' +const DIRECTION = { + north: '北', + south: '南', + west: '西', + east: '東', +} + export default function PassivityCircuitAllocation() { const { getMessage } = useMessage() + const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) + const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const moduleData = { header: [ { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, - { name: getMessage('modal.circuit.trestle.setting.circuilt'), prop: 'circuit' }, + { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' }, ...selectedModules.itemList.map((module) => { return { name: module.itemNm, @@ -40,9 +51,25 @@ export default function PassivityCircuitAllocation() { const model = useRecoilValue(modelState) const [selectedModels, setSelectedModels] = useState(model.selectedModels) const [selectedPcs, setSelectedPcs] = useState(selectedModels[0]) + const [totalWpout, setTotalWpout] = useState(0) + useEffect(() => { - console.log('🚀 ~ useEffect ~ selectedPcs:', selectedPcs) - }, [selectedPcs]) + setSurfaceInfo() + if (!managementState) { + setManagementState(managementStateLoaded) + } + }, []) + + const setSurfaceInfo = () => { + const surfaces = canvas.getObjects().filter((obj) => ['roofSurface', 'moduleSetupSurface'].includes(obj.name)) + const modules = canvas.getObjects().filter((obj) => obj.name === 'module') + surfaces.forEach((surface) => { + surface.moduleList = modules.filter((obj) => obj.surfaceId === surface.id) + }) + // 지붕면 리스트 -> 지붕면에 있는 모듈 리스트 -> 발전량 총합 계산 + // wpOut + console.log('🚀 ~ setSurfaceInfo ~ modules:', surfaces) + } return ( <>
@@ -62,7 +89,7 @@ export default function PassivityCircuitAllocation() { {moduleData.rows.map((row, index) => ( - + {moduleData.header.map((header) => ( {row[header.prop].name} @@ -70,6 +97,13 @@ export default function PassivityCircuitAllocation() { ))} ))} + + 총합 + {Array.from({ length: moduleData.header.length - 2 }).map((_, index) => { + return + })} + {totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })} +
@@ -91,7 +125,14 @@ export default function PassivityCircuitAllocation() { checked={selectedPcs === model} onChange={() => setSelectedPcs(model)} /> - + ))} {/*
diff --git a/src/locales/ja.json b/src/locales/ja.json index a96ff061..ff6018f6 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -141,9 +141,11 @@ "modal.circuit.trestle.setting.circuit.allocation": "回路割り当て", "modal.circuit.trestle.setting.circuit.allocation.auto": "自動回路割り当て", "modal.circuit.trestle.setting.circuit.allocation.passivity": "手動回路割当", + "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "回路", "modal.circuit.trestle.setting.circuit.allocation.passivity.info": "同じ回路のモジュールを選択状態にした後、 [番号確認]ボタンを押すと番号が割り当てられます。", "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "選択したパワーコンディショナー", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num": "設定する回路番号 (1~)", + "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info": "標準回路{0}枚~{1}枚", "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset": "選択されたパワーコンディショナーの回路番号の初期化", "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "すべての回路番号の初期化", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定", diff --git a/src/locales/ko.json b/src/locales/ko.json index 2d049d61..d23f1813 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -145,9 +145,11 @@ "modal.circuit.trestle.setting.circuit.allocation": "회로 할당", "modal.circuit.trestle.setting.circuit.allocation.auto": "자동 회로 할당", "modal.circuit.trestle.setting.circuit.allocation.passivity": "수동 회로 할당", + "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "회로", "modal.circuit.trestle.setting.circuit.allocation.passivity.info": "동일한 회로의 모듈을 선택 상태로 만든 후 [번호 확정] 버튼을 누르면 번호가 할당됩니다.", "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "선택된 파워컨디셔너", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num": "설정할 회로번호(1~)", + "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info": "표준회로{0}장~{1}장", "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset": "선택된 파워컨디셔너의 회로번호 초기화", "modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "모든 회로번호 초기화", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정", From 72aeeb4e3905fc9d2f56e279c2cc57728c288afa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Fri, 17 Jan 2025 18:31:39 +0900 Subject: [PATCH 3/4] =?UTF-8?q?=ED=9A=8C=EB=A1=9C.=20=EA=B0=80=EB=8C=80=20?= =?UTF-8?q?=EC=84=A4=EC=A0=95=20=EA=B0=9C=EB=B0=9C=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../step/type/PassivityCircuitAllocation.jsx | 129 ++++++++++-------- .../modal/panelBatch/PanelBatchStatistics.jsx | 22 ++- src/hooks/module/useModuleBasicSetting.js | 62 ++++++++- src/hooks/usePlan.js | 1 + src/store/circuitTrestleAtom.js | 5 + 5 files changed, 155 insertions(+), 64 deletions(-) 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 cd2e4469..e9da38b3 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -1,4 +1,5 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider' +import { POLYGON_TYPE } from '@/common/common' import { useMessage } from '@/hooks/useMessage' import { canvasState } from '@/store/canvasAtom' import { modelState } from '@/store/circuitTrestleAtom' @@ -18,36 +19,10 @@ export default function PassivityCircuitAllocation() { const canvas = useRecoilValue(canvasState) const selectedModules = useRecoilValue(selectedModuleState) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) - const moduleData = { - header: [ - { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, - { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' }, - ...selectedModules.itemList.map((module) => { - return { - name: module.itemNm, - prop: 'moduleName', - } - }), - { - name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, - prop: 'powerGeneration', - }, - ], - rows: [ - { - roofShape: { name: 'M 1' }, - circuit: { name: 'M 1' }, - moduleName: { name: '8' }, - powerGeneration: { name: '3,400' }, - }, - { - roofShape: { name: 'M 1' }, - circuit: { name: 'M 1' }, - moduleName: { name: '8' }, - powerGeneration: { name: '3,400' }, - }, - ], - } + const [moduleData, setModuleData] = useState({ + header: [], + rows: [], + }) const model = useRecoilValue(modelState) const [selectedModels, setSelectedModels] = useState(model.selectedModels) const [selectedPcs, setSelectedPcs] = useState(selectedModels[0]) @@ -61,14 +36,47 @@ export default function PassivityCircuitAllocation() { }, []) const setSurfaceInfo = () => { - const surfaces = canvas.getObjects().filter((obj) => ['roofSurface', 'moduleSetupSurface'].includes(obj.name)) - const modules = canvas.getObjects().filter((obj) => obj.name === 'module') - surfaces.forEach((surface) => { - surface.moduleList = modules.filter((obj) => obj.surfaceId === surface.id) + const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name) + let totalWpout = 0 + const rows = surfaces.map((surface) => { + let wpOut = 0 + let moduleInfo = {} + surface.modules.forEach((module) => { + wpOut += +module.moduleInfo.wpOut + if (!moduleInfo[module.moduleInfo.itemId]) moduleInfo[module.moduleInfo.itemId] = 0 + moduleInfo[module.moduleInfo.itemId]++ + }) + totalWpout += wpOut + console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module) + return { + roofShape: DIRECTION[surface.direction], + powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }), + ...moduleInfo, + } }) + + setTotalWpout(totalWpout) // 지붕면 리스트 -> 지붕면에 있는 모듈 리스트 -> 발전량 총합 계산 // wpOut - console.log('🚀 ~ setSurfaceInfo ~ modules:', surfaces) + console.log('🚀 ~ setSurfaceInfo ~ modules:', rows) + console.log('🚀 ~ setSurfaceInfo ~ surfaces:', surfaces) + setModuleData({ + header: [ + { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, + { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' }, + ...selectedModules.itemList.map((module) => { + return { + name: module.itemNm, + prop: module.itemId, + } + }), + { + name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, + prop: 'powerGeneration', + }, + ], + rows: rows, + }) } return ( <> @@ -79,33 +87,36 @@ export default function PassivityCircuitAllocation() {
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.info')}
- - - - {moduleData.header.map((header) => ( - - ))} - - - - {moduleData.rows.map((row, index) => ( - + {moduleData.header && ( +
{header.name}
+ + {moduleData.header.map((header) => ( - + ))} - ))} - - - {Array.from({ length: moduleData.header.length - 2 }).map((_, index) => { - return - })} - - - -
- {row[header.prop].name} - {header.name}
총합{totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })}
+ + + {moduleData.rows.map((row, index) => ( + + {moduleData.header.map((header) => ( + + {row[header.prop]} + + ))} + + ))} + + 총합 + {Array.from({ length: moduleData.header.length - 3 }).map((_, index) => { + return + })} + {totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })} + {totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })} + + + + )}
diff --git a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx index addc4cf8..fa4f82f6 100644 --- a/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx +++ b/src/components/floor-plan/modal/panelBatch/PanelBatchStatistics.jsx @@ -3,6 +3,8 @@ import { useState } from 'react' import { useMessage } from '@/hooks/useMessage' import WithDraggable from '@/components/common/draggable/WithDraggable' +import { moduleStatisticsState } from '@/store/circuitTrestleAtom' +import { useRecoilValue } from 'recoil' export default function PanelBatchStatistics() { const { getMessage } = useMessage() @@ -11,6 +13,7 @@ export default function PanelBatchStatistics() { x: 0, y: 30, }) + const { header, rows, footer } = useRecoilValue(moduleStatisticsState) return ( @@ -21,14 +24,25 @@ export default function PanelBatchStatistics() { - - + {header.map((item) => ( + + ))} + {rows.map((row) => ( + + {header.map((item) => ( + // + + ))} + + ))} - - + {footer.map((item) => ( + + // + ))}
{getMessage('modal.panel.batch.statistic.roof.shape')}{getMessage('modal.panel.batch.statistic.power.generation.amount')} (kW){item.name}
{item.prop === 'name' ? item.name : item.prop === 'powerGeneration' ? item.powerGeneration : item.amount}{row[item.prop]}
{getMessage('modal.panel.batch.statistic.total')}0.000{item}{item.amount}
diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 11c2ce8d..256d51c6 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -16,6 +16,7 @@ import { QLine } from '@/components/fabric/QLine' import { useRoofFn } from '@/hooks/common/useRoofFn' import { useEffect } from 'react' import { useMessage } from '@/hooks/useMessage' +import { moduleStatisticsState } from '@/store/circuitTrestleAtom' export function useModuleBasicSetting() { const canvas = useRecoilValue(canvasState) @@ -31,6 +32,7 @@ export function useModuleBasicSetting() { const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) const checkedModule = useRecoilValue(checkedModuleState) const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) + const [moduleStatistics, setModuleStatistics] = useRecoilState(moduleStatisticsState) useEffect(() => { // console.log('basicSetting', basicSetting) @@ -1206,7 +1208,7 @@ export function useModuleBasicSetting() { }) moduleSetupSurface.set({ modules: moduleSetupArray }) - + getModuleStatistics() // const moduleArray = [...moduleIsSetup] // moduleArray.push({ // surfaceId: moduleSetupSurface.surfaceId, @@ -2279,6 +2281,64 @@ export function useModuleBasicSetting() { return isDisjoint } + const getModuleStatistics = () => { + const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name) + console.log('🚀 ~ getModuleStatistics ~ surfaces:', surfaces) + let totalWpout = 0 + let moduleInfo = {} + const rows = surfaces.map((surface) => { + let wpOut = 0 + + surface.modules.forEach((module) => { + wpOut += +module.moduleInfo.wpOut + if (!moduleInfo[module.moduleInfo.itemId]) { + moduleInfo[module.moduleInfo.itemId] = 0 + } + + moduleInfo[module.moduleInfo.itemId]++ + }) + totalWpout += wpOut + console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module) + return { + name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, + // powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }), + amount: wpOut, + ...moduleInfo, + } + }) + + console.log('🚀 ~ getModuleStatistics ~ moduleInfo:', moduleInfo) + const header = [ + { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' }, + ...Object.keys(moduleInfo).map((key) => { + return { name: moduleInfo[key], prop: key } + }), + { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'amount' }, + ] + let footer = ['합계'] + let footerData = {} + rows.forEach((row) => { + Object.keys(moduleInfo).map((key) => { + if (!footerData[key]) footerData[key] = 0 + footerData[key] += row[key] + }) + }) + Object.keys(footerData).forEach((key) => { + footer.push(footerData[key]) + }) + footer.push(totalWpout) + // const footer = [ + // '합계', + // ...Object.keys(moduleInfo).map((key) => { + // return { name: moduleInfo[key].name, prop: moduleInfo[key] } + // }), + // totalWpout, + // ] + // const footer = [] + console.log('@@@@@@@@@@', header, rows, footer) + setModuleStatistics({ header: header, rows, footer: footer }) + } + return { makeModuleInstArea, manualModuleSetup, diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 510b7874..a92aca69 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -368,6 +368,7 @@ export function usePlan(params = {}) { * plan 조회 */ const loadCanvasPlanData = async (userId, objectNo, planNo) => { + console.log('🚀 ~ loadCanvasPlanData ~ userId, objectNo, planNo:', userId, objectNo, planNo) await getCanvasByObjectNo(userId, objectNo).then((res) => { if (res.length > 0) { setPlans(res) diff --git a/src/store/circuitTrestleAtom.js b/src/store/circuitTrestleAtom.js index 3fbb0b3e..2ba3963b 100644 --- a/src/store/circuitTrestleAtom.js +++ b/src/store/circuitTrestleAtom.js @@ -20,3 +20,8 @@ export const pcsCheckState = atom({ key: 'divisionCircuitState', default: { division: true, max: false }, }) + +export const moduleStatisticsState = atom({ + key: 'moduleStatisticsState', + default: { header: [], rows: [], footer: [] }, +}) From cb610d098dd15fd9dfa96b7586ad4cdcfba4b3e6 Mon Sep 17 00:00:00 2001 From: Minsiki Date: Sat, 18 Jan 2025 19:14:16 +0900 Subject: [PATCH 4/4] =?UTF-8?q?=EC=A7=91=EA=B3=84=ED=91=9C=20=EA=B0=9C?= =?UTF-8?q?=EB=B0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 22 +++++++++++++--------- src/store/circuitTrestleAtom.js | 13 ++++++++++++- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 256d51c6..08a06320 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -2288,22 +2288,26 @@ export function useModuleBasicSetting() { let moduleInfo = {} const rows = surfaces.map((surface) => { let wpOut = 0 - + moduleInfo = {} surface.modules.forEach((module) => { - wpOut += +module.moduleInfo.wpOut if (!moduleInfo[module.moduleInfo.itemId]) { - moduleInfo[module.moduleInfo.itemId] = 0 + moduleInfo[module.moduleInfo.itemId] = { name: module.moduleInfo.itemNm, amount: 0, id: module.moduleInfo.itemId } } + wpOut += +module.moduleInfo.wpOut - moduleInfo[module.moduleInfo.itemId]++ + moduleInfo[module.moduleInfo.itemId].amount++ }) totalWpout += wpOut console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module) + const rowObject = {} + Object.keys(moduleInfo).forEach((key) => { + rowObject[key] = moduleInfo[key].amount + }) return { - name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, + ...rowObject, // 총 발전량 = 발전량 * 모듈 개수 + name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, // 지붕면 // powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }), - amount: wpOut, - ...moduleInfo, + wpOut: wpOut, } }) @@ -2311,9 +2315,9 @@ export function useModuleBasicSetting() { const header = [ { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' }, ...Object.keys(moduleInfo).map((key) => { - return { name: moduleInfo[key], prop: key } + return { name: moduleInfo[key].name, prop: key } }), - { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'amount' }, + { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' }, ] let footer = ['합계'] let footerData = {} diff --git a/src/store/circuitTrestleAtom.js b/src/store/circuitTrestleAtom.js index 2ba3963b..86836b48 100644 --- a/src/store/circuitTrestleAtom.js +++ b/src/store/circuitTrestleAtom.js @@ -1,3 +1,4 @@ +import { useMessage } from '@/hooks/useMessage' import { atom } from 'recoil' export const makerState = atom({ @@ -23,5 +24,15 @@ export const pcsCheckState = atom({ export const moduleStatisticsState = atom({ key: 'moduleStatisticsState', - default: { header: [], rows: [], footer: [] }, + default: { + header: [ + { name: '지붕면', prop: 'name' }, + { name: `발전량(kW)`, prop: 'amount' }, + ], + rows: [], + footer: [ + { name: '합계', prop: 'name' }, + { name: `발전량(kW)`, prop: 'amount' }, + ], + }, })