This commit is contained in:
hyojun.choi 2025-01-21 17:15:24 +09:00
commit d82eccf229
12 changed files with 187 additions and 123 deletions

View File

@ -75,7 +75,11 @@ export default function QSelectBox({
useOnClickOutside(ref, handleClose) useOnClickOutside(ref, handleClose)
return ( return (
<div className={`sort-select ${openSelect ? 'active' : ''}`} ref={ref} onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}> <div
className={`sort-select ${openSelect ? 'active' : ''} ${disabled ? 'disabled' : ''}`}
ref={ref}
onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}
>
<p>{selected}</p> <p>{selected}</p>
<ul className="select-item-wrap"> <ul className="select-item-wrap">
{options?.length > 0 && {options?.length > 0 &&

View File

@ -51,9 +51,18 @@ export default function CircuitTrestleSetting({ id }) {
models, models,
setModels, setModels,
} }
const circuitProps = {
const passivityProps = {
tabNum, tabNum,
setTabNum, setTabNum,
models,
setModels,
}
const stepUpProps = {
tabNum,
setTabNum,
models,
setModels,
circuitAllocationType, circuitAllocationType,
setCircuitAllocationType, setCircuitAllocationType,
} }
@ -61,6 +70,7 @@ export default function CircuitTrestleSetting({ id }) {
const onAutoAllocation = () => { const onAutoAllocation = () => {
let moduleStdQty = 0 let moduleStdQty = 0
let moduleMaxQty = 0 let moduleMaxQty = 0
const selectedModels = models.filter((m) => m.selected)
if (selectedModels.length === 0) { if (selectedModels.length === 0) {
moduleStdQty = models.reduce((acc, model) => { moduleStdQty = models.reduce((acc, model) => {
@ -144,8 +154,8 @@ export default function CircuitTrestleSetting({ id }) {
</div> </div>
</div> </div>
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />} {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...powerConditionalSelectProps} />} {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...passivityProps} />}
{tabNum === 2 && <StepUp />} {tabNum === 2 && <StepUp {...stepUpProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && ( {tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => onAutoAllocation()}> <button className="btn-frame modal mr5" onClick={() => onAutoAllocation()}>

View File

@ -6,6 +6,7 @@ import { useSwal } from '@/hooks/useSwal'
import { pcsCheckState } from '@/store/circuitTrestleAtom' import { pcsCheckState } from '@/store/circuitTrestleAtom'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { selectedModuleState } from '@/store/selectedModuleOptions' import { selectedModuleState } from '@/store/selectedModuleOptions'
import { isNullOrUndefined } from '@/util/common-utils'
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
@ -46,6 +47,8 @@ export default function PowerConditionalSelect(props) {
] ]
useEffect(() => { useEffect(() => {
console.log('series', series)
console.log('models', models)
if (makers.length === 0) { if (makers.length === 0) {
getPcsMakerList().then((res) => { getPcsMakerList().then((res) => {
setMakers(res.data) setMakers(res.data)
@ -71,17 +74,20 @@ export default function PowerConditionalSelect(props) {
console.log('🚀 ~ PowerConditionalSelect ~ selectedMaker:', selectedMaker) console.log('🚀 ~ PowerConditionalSelect ~ selectedMaker:', selectedMaker)
if (selectedMaker) { if (selectedMaker) {
setModels(null) setModels(null)
getPcsMakerList(selectedMaker).then((res) => { if (series.length === 0)
setSeries( getPcsMakerList(selectedMaker).then((res) => {
res.data.map((series) => { setSeries(
return { ...series, selected: false } res.data.map((series) => {
}), // return { ...series, selected: isNullOrUndefined(series.selected) ? false : series.selected }
) return { ...series, selected: false }
}) }),
)
})
} }
}, [selectedMaker]) }, [selectedMaker])
useEffect(() => { useEffect(() => {
console.log('🚀 ~ useEffect ~ series:', series)
if (series.filter((s) => s.selected).length === 0) return if (series.filter((s) => s.selected).length === 0) return
const pcsMkrCd = series.filter((s) => s.selected)[0]?.pcsMkrCd const pcsMkrCd = series.filter((s) => s.selected)[0]?.pcsMkrCd
const pcsSerList = series const pcsSerList = series

View File

@ -10,13 +10,13 @@ import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupSta
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { useMasterController } from '@/hooks/common/useMasterController' import { useMasterController } from '@/hooks/common/useMasterController'
export default function StepUp({}) { export default function StepUp(props) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [moduleTab, setModuleTab] = useState(1) const [moduleTab, setModuleTab] = useState(1)
const [arrayLength, setArrayLength] = useState(3) //module-table-inner const [arrayLength, setArrayLength] = useState(3) //module-table-inner
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const model = useRecoilValue(modelState) const { models } = props
const { getPcsVoltageStepUpList } = useMasterController() const { getPcsVoltageStepUpList, getPcsAutoRecommendList } = useMasterController()
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState) const selectedModules = useRecoilValue(selectedModuleState)
@ -27,9 +27,11 @@ export default function StepUp({}) {
setManagementState(managementStateLoaded) setManagementState(managementStateLoaded)
} }
const useModuleItemList = model.selectedModels.map((model) => { const useModuleItemList = models
return { itemId: model.itemId, mixMatlNo: model.mixMatlNo } .filter((m) => m.selected)
}) .map((model) => {
return { itemId: model.itemId, mixMatlNo: model.mixMatlNo }
})
// [{ roofSurfaceId: '', roofSurface: '', roofSurfaceIncl: '', moduleList: [{ itemId: '' }] }], // [{ roofSurfaceId: '', roofSurface: '', roofSurfaceIncl: '', moduleList: [{ itemId: '' }] }],
const roofSurfaceList = canvas const roofSurfaceList = canvas
.getObjects() .getObjects()
@ -48,13 +50,15 @@ export default function StepUp({}) {
} }
}) })
// [{ itemId: '', pcsMkrCd: '', pcsSerCd: '' }], // [{ itemId: '', pcsMkrCd: '', pcsSerCd: '' }],
const pscItemList = model.selectedModels.map((model) => { const pscItemList = models
return { .filter((m) => m.selected)
itemId: model.itemId, .map((model) => {
pcsMkrCd: model.pcsMkrCd, return {
pcsSerCd: model.pcsSerCd, itemId: model.itemId,
} pcsMkrCd: model.pcsMkrCd,
}) pcsSerCd: model.pcsSerCd,
}
})
const params = { const params = {
maxConnYn: pcsCheck.max, maxConnYn: pcsCheck.max,

View File

@ -2,31 +2,24 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { modelState } from '@/store/circuitTrestleAtom' import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { selectedModuleState } from '@/store/selectedModuleOptions' import { selectedModuleState } from '@/store/selectedModuleOptions'
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
const DIRECTION = { export default function PassivityCircuitAllocation(props) {
north: '北', const { tabNum, setTabNum, models, setModels } = props
south: '南',
west: '西',
east: '東',
}
export default function PassivityCircuitAllocation() {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const [moduleData, setModuleData] = useState({ const selectedModules = useRecoilValue(selectedModuleState)
header: [], const moduleStatistics = useRecoilValue(moduleStatisticsState)
rows: [], // const [totalWpout, setTotalWpout] = useState(0)
}) const [selectedPcs, setSelectedPcs] = useState(models.filter((model) => model.selected)[0])
const model = useRecoilValue(modelState) const { header, rows: row } = moduleStatistics
const [selectedModels, setSelectedModels] = useState(model.selectedModels) const [headers, setHeaders] = useState(header)
const [selectedPcs, setSelectedPcs] = useState(selectedModels[0]) const [rows, setRows] = useState(row)
const [totalWpout, setTotalWpout] = useState(0) const [footer, setFooter] = useState(['합계'])
useEffect(() => { useEffect(() => {
setSurfaceInfo() setSurfaceInfo()
@ -35,48 +28,90 @@ export default function PassivityCircuitAllocation() {
} }
}, []) }, [])
useEffect(() => {
console.log('🚀 ~ useEffect ~ headers:', headers)
}, [headers])
useEffect(() => {
console.log('🚀 ~ useEffect ~ rows:', rows)
}, [rows])
const setSurfaceInfo = () => { const setSurfaceInfo = () => {
console.log('🚀 ~ setSurfaceInfo ~ headers:', headers)
console.log('🚀 ~ setSurfaceInfo ~ rows:', rows)
// console.log('🚀 ~ setSurfaceInfo ~ surfaces:', surfaces)
const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name) const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
let totalWpout = 0 setHeaders([header[0], { name: '회로', prop: 'circuit' }, ...header.slice(1)])
const rows = surfaces.map((surface) => { setRows(
let wpOut = 0 rows.map((row) => {
let moduleInfo = {} return {
surface.modules.forEach((module) => { ...row,
wpOut += +module.moduleInfo.wpOut circuit: '',
if (!moduleInfo[module.moduleInfo.itemId]) moduleInfo[module.moduleInfo.itemId] = 0 }
moduleInfo[module.moduleInfo.itemId]++ }),
}) )
totalWpout += wpOut let totals = {}
console.log('🚀 ~ moduleData.rows=surfaces.map ~ module:', module)
return { rows.forEach((row) => {
roofShape: DIRECTION[surface.direction], if (header.length === 4) {
powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }), if (!totals[header[2].prop]) totals[header[2].prop] = 0
...moduleInfo, totals[header[2].prop] += +row[header[2].prop]
} else if (header.length === 5) {
if (!totals[header[2].prop]) totals[header[2].prop] = 0
totals[header[2].prop] += +row[header[2].prop]
if (!totals[header[3].prop]) totals[header[3].prop] = 0
totals[header[3]] += +row[header[3]]
} }
}) })
console.log(totals)
setFooter([
...['합계', ''],
...Object.keys(totals).map((key) => {
return totals[key]
}),
Object.keys(totals).reduce((acc, key) => {
return acc + totals[key]
}, 0),
])
// 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) // setTotalWpout(totalWpout)
// -> -> // -> ->
// wpOut // wpOut
console.log('🚀 ~ setSurfaceInfo ~ modules:', rows)
console.log('🚀 ~ setSurfaceInfo ~ surfaces:', surfaces) // setModuleData({
setModuleData({ // header: [
header: [ // { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' },
{ name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' }, // { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
{ name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' }, // ...selectedModules.itemList.map((module) => {
...selectedModules.itemList.map((module) => { // return {
return { // name: module.itemNm,
name: module.itemNm, // prop: module.itemId,
prop: module.itemId, // }
} // }),
}), // {
{ // name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`,
name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, // prop: 'powerGeneration',
prop: 'powerGeneration', // },
}, // ],
], // rows: rows,
rows: rows, // })
})
} }
return ( return (
<> <>
@ -87,32 +122,27 @@ export default function PassivityCircuitAllocation() {
<div className="bold-font mb10">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}</div> <div className="bold-font mb10">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}</div>
<div className="normal-font mb15">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.info')}</div> <div className="normal-font mb15">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.info')}</div>
<div className="roof-module-table overflow-y"> <div className="roof-module-table overflow-y">
{moduleData.header && ( {header && (
<table> <table>
<thead> <thead>
<tr> <tr>
{moduleData.header.map((header) => ( {headers.map((header) => (
<th key={header.prop}>{header.name}</th> <th key={'header' + header.prop}>{header.name}</th>
))} ))}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{moduleData.rows.map((row, index) => ( {rows.map((row, index) => (
<tr key={index} className="wrong"> <tr key={'row' + index}>
{moduleData.header.map((header) => ( {headers.map((header) => (
<td className="al-c" key={header.prop}> <td className="al-c">{row[header.prop]}</td>
{row[header.prop]}
</td>
))} ))}
</tr> </tr>
))} ))}
<tr className="wrong"> <tr>
<td className="al-c">총합</td> {footer.map((footer) => (
{Array.from({ length: moduleData.header.length - 3 }).map((_, index) => { <td className="al-c">{footer}</td>
return <td key={index} className="al-c"></td> ))}
})}
<td className="al-c">{totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })}</td>
<td className="al-c">{totalWpout.toLocaleString('ko-KR', { maximumFractionDigits: 4 })}</td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
@ -127,25 +157,27 @@ export default function PassivityCircuitAllocation() {
<div className="bold-font">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional')}</div> <div className="bold-font">{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional')}</div>
</div> </div>
<div className="hexagonal-item"> <div className="hexagonal-item">
{selectedModels.map((model, index) => ( {models
<div className="d-check-radio pop mb10"> .filter((model) => model.selected)
<input .map((model, index) => (
type="radio" <div className="d-check-radio pop mb10" key={'model' + index}>
name="radio01" <input
id={`ra0${index + 1}`} type="radio"
checked={selectedPcs === model} name="radio01"
onChange={() => setSelectedPcs(model)} id={`ra0${index + 1}`}
/> checked={selectedPcs === model}
<label htmlFor="ra01"> onChange={() => setSelectedPcs(model)}
{model.itemNm} ( />
{getMessage( <label htmlFor="ra01">
'modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info', {model.itemNm} (
managementState?.coldRegionFlg === '1' ? [model.serMinQty, model.serColdZoneMaxQty] : [model.serMinQty, model.serMaxQty], {getMessage(
)} 'modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info',
) managementState?.coldRegionFlg === '1' ? [model.serMinQty, model.serColdZoneMaxQty] : [model.serMinQty, model.serMaxQty],
</label> )}
</div> )
))} </label>
</div>
))}
{/* <div className="d-check-radio pop mb10"> {/* <div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra01" /> <input type="radio" name="radio01" id="ra01" />
<label htmlFor="ra01">HQJP-KA55-5 (標準回路2枚10)</label> <label htmlFor="ra01">HQJP-KA55-5 (標準回路2枚10)</label>

View File

@ -33,8 +33,9 @@ export default function PanelBatchStatistics() {
{rows.map((row, index) => ( {rows.map((row, index) => (
<tr key={index}> <tr key={index}>
{header.map((item, i) => ( {header.map((item, i) => (
// <td>{item.prop === 'name' ? item.name : item.prop === 'powerGeneration' ? item.powerGeneration : item.amount}</td> <td key={index}>
<td key={i}>{row[item.prop]}</td> {typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]}
</td>
))} ))}
</tr> </tr>
))} ))}

View File

@ -2308,12 +2308,14 @@ export function useModuleBasicSetting() {
}) })
return { return {
...rowObject, // 총 발전량 = 발전량 * 모듈 개수 ...rowObject, // 총 발전량 = 발전량 * 모듈 개수
...surface,
name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, // 지붕면 name: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText, // 지붕면
// powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }), // powerGeneration: wpOut.toLocaleString('ko-KR', { maximumFractionDigits: 4 }),
wpOut: wpOut, wpOut: wpOut,
} }
}) })
console.log('🚀 ~ getModuleStatistics ~ rows:', rows)
console.log('🚀 ~ getModuleStatistics ~ moduleInfo:', moduleInfo) console.log('🚀 ~ getModuleStatistics ~ moduleInfo:', moduleInfo)
const header = [ const header = [
{ name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' }, { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'name' },
@ -2334,15 +2336,7 @@ export function useModuleBasicSetting() {
footer.push(footerData[key]) footer.push(footerData[key])
}) })
footer.push(totalWpout) footer.push(totalWpout)
// const footer = [ console.log({ header: header, rows, footer: 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 }) setModuleStatistics({ header: header, rows, footer: footer })
} }

View File

@ -51,6 +51,7 @@ export function useModulePlace() {
useEffect(() => { useEffect(() => {
//지붕을 가져옴 //지붕을 가져옴
console.log('🚀 ~ trestleDetailList.forEach ~ trestleDetailList:', trestleDetailList)
canvas canvas
.getObjects() .getObjects()
.filter((roof) => roof.name === 'roof') .filter((roof) => roof.name === 'roof')

View File

@ -281,6 +281,12 @@
"modal.object.setting.direction.select": "方向の選択", "modal.object.setting.direction.select": "方向の選択",
"modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。", "modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。",
"modal.placement.surface.setting.diagonal.length": "斜めの長さ", "modal.placement.surface.setting.diagonal.length": "斜めの長さ",
"modal.placement.surface.drawing.straight.line": "직선(JA)",
"modal.placement.surface.drawing.right.angle": "직각(JA)",
"modal.placement.surface.drawing.double.pitch": "이구배(JA)",
"modal.placement.surface.drawing.angle": "각도(JA)",
"modal.placement.surface.drawing.diagonal": "대각선(JA)",
"modal.placement.surface.drawing.fix": "배치면 확정(JA)",
"modal.color.picker.title": "色の設定", "modal.color.picker.title": "色の設定",
"modal.color.picker.default.color": "基本色", "modal.color.picker.default.color": "基本色",
"modal.size.setting": "サイズ変更", "modal.size.setting": "サイズ変更",

View File

@ -80,6 +80,7 @@
"modal.placement.surface.drawing.double.pitch": "이구배", "modal.placement.surface.drawing.double.pitch": "이구배",
"modal.placement.surface.drawing.angle": "각도", "modal.placement.surface.drawing.angle": "각도",
"modal.placement.surface.drawing.diagonal": "대각선", "modal.placement.surface.drawing.diagonal": "대각선",
"modal.placement.surface.drawing.fix": "배치면 확정",
"plan.menu.placement.surface.arrangement": "면형상 배치", "plan.menu.placement.surface.arrangement": "면형상 배치",
"plan.menu.placement.surface.object": "오브젝트 배치", "plan.menu.placement.surface.object": "오브젝트 배치",
"plan.menu.placement.surface.all.remove": "배치면 전체 삭제", "plan.menu.placement.surface.all.remove": "배치면 전체 삭제",

View File

@ -42,4 +42,5 @@ export const moduleStatisticsState = atom({
rows: [], rows: [],
footer: ['합계', '0'], footer: ['합계', '0'],
}, },
dangerouslyAllowMutability: true,
}) })

View File

@ -149,3 +149,7 @@ export const unescapeString = (str) => {
return str.replace(regex, (matched) => chars[matched] || matched) return str.replace(regex, (matched) => chars[matched] || matched)
} }
} }
export const isNullOrUndefined = (value) => {
return value === null || value === undefined
}