Merge branch 'dev' into feature/jaeyoung

This commit is contained in:
Jaeyoung Lee 2025-02-03 18:07:31 +09:00
commit b10c91909a
38 changed files with 597 additions and 311 deletions

View File

@ -1,6 +1,8 @@
'use client' 'use client'
import { createContext, useState } from 'react' import { loginUserStore } from '@/store/commonAtom'
import { createContext, useEffect, useState } from 'react'
import { useRecoilState } from 'recoil'
export const SessionContext = createContext({ export const SessionContext = createContext({
session: {}, session: {},
@ -8,5 +10,11 @@ export const SessionContext = createContext({
export default function SessionProvider({ useSession, children }) { export default function SessionProvider({ useSession, children }) {
const [session, setSession] = useState(useSession) const [session, setSession] = useState(useSession)
const [loginUserState, setLoginUserState] = useRecoilState(loginUserStore)
useEffect(() => {
setLoginUserState(session)
}, [session])
return <SessionContext.Provider value={{ session }}>{children}</SessionContext.Provider> return <SessionContext.Provider value={{ session }}>{children}</SessionContext.Provider>
} }

View File

@ -55,10 +55,6 @@ export default async function RootLayout({ children }) {
redirect('/login') redirect('/login')
} }
if (headerPathname === '/login' && session.isLoggedIn) {
redirect('/')
}
return ( return (
<RecoilRootWrapper> <RecoilRootWrapper>
<GlobalDataProvider> <GlobalDataProvider>

View File

@ -177,6 +177,8 @@ export const SAVE_KEY = [
'moduleRowsTotCnt', 'moduleRowsTotCnt',
'seq', 'seq',
'smartRackId', 'smartRackId',
'quotationParam',
'pcses',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]

View File

@ -5,7 +5,7 @@ import Image from 'next/image'
import Link from 'next/link' import Link from 'next/link'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { setSession, login } from '@/lib/authActions' import { setSession, login, checkSession } from '@/lib/authActions'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
@ -21,11 +21,19 @@ export default function Login() {
// //
const initParams = useSearchParams() const initParams = useSearchParams()
const autoLoginParam = initParams.get('autoLoginParam1') const autoLoginParam = initParams.get('autoLoginParam1')
useEffect(() => { useEffect(() => {
if (autoLoginParam) { if (autoLoginParam) {
autoLoginProcess(autoLoginParam) autoLoginProcess(autoLoginParam)
} }
checkSession().then((res) => {
if (res) {
login()
}
})
}, []) }, [])
const autoLoginProcess = async (autoLoginParam) => { const autoLoginProcess = async (autoLoginParam) => {
await promisePost({ url: '/api/login/v1.0/user/login/autoLoginDecryptData', data: { loginId: autoLoginParam } }) await promisePost({ url: '/api/login/v1.0/user/login/autoLoginDecryptData', data: { loginId: autoLoginParam } })
.then((res) => { .then((res) => {

View File

@ -2,7 +2,7 @@
import { useContext, useEffect, useRef } from 'react' import { useContext, useEffect, useRef } from 'react'
import { useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import QContextMenu from '@/components/common/context-menu/QContextMenu' import QContextMenu from '@/components/common/context-menu/QContextMenu'
import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics' import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics'
@ -16,6 +16,7 @@ import { totalDisplaySelector } from '@/store/settingAtom'
import { MENU } from '@/common/common' import { MENU } from '@/common/common'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
export default function CanvasFrame() { export default function CanvasFrame() {
const canvasRef = useRef(null) const canvasRef = useRef(null)
@ -27,7 +28,8 @@ export default function CanvasFrame() {
const { currentCanvasPlan } = usePlan() const { currentCanvasPlan } = usePlan()
const totalDisplay = useRecoilValue(totalDisplaySelector) // const totalDisplay = useRecoilValue(totalDisplaySelector) //
const { setIsGlobalLoading } = useContext(QcastContext) const { setIsGlobalLoading } = useContext(QcastContext)
const [moduleStatistics, setModuleStatistics] = useRecoilState(moduleStatisticsState)
const reset = useResetRecoilState(moduleStatisticsState)
const loadCanvas = () => { const loadCanvas = () => {
if (canvas) { if (canvas) {
canvas?.clear() // . canvas?.clear() // .
@ -43,6 +45,7 @@ export default function CanvasFrame() {
useEffect(() => { useEffect(() => {
loadCanvas() loadCanvas()
reset()
}, [currentCanvasPlan, canvas]) }, [currentCanvasPlan, canvas])
useEffect(() => { useEffect(() => {

View File

@ -1,6 +1,6 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useEffect, useRef, useState } from 'react' import { useContext, useEffect, useRef, useState } from 'react'
import Module from '@/components/floor-plan/modal/basic/step/Module' import Module from '@/components/floor-plan/modal/basic/step/Module'
import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchModule' import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchModule'
import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement'
@ -16,6 +16,9 @@ import { addedRoofsState } from '@/store/settingAtom'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import Swal from 'sweetalert2' import Swal from 'sweetalert2'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { useMasterController } from '@/hooks/common/useMasterController'
import { loginUserStore } from '@/store/commonAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom'
export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -27,9 +30,12 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState) const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const addedRoofs = useRecoilValue(addedRoofsState) const addedRoofs = useRecoilValue(addedRoofsState)
const loginUserState = useRecoilValue(loginUserStore)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
// const { initEvent } = useContext(EventContext) // const { initEvent } = useContext(EventContext)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting() const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting()
const { updateObjectDate } = useMasterController()
const handleBtnNextStep = () => { const handleBtnNextStep = () => {
if (tabNum === 1) { if (tabNum === 1) {
orientationRef.current.handleNextStep() orientationRef.current.handleNextStep()
@ -49,6 +55,16 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
}) })
return return
} }
//
updateObjectDataApi({
objectNo: currentCanvasPlan.objectNo, //_no
standardWindSpeedId: moduleSelectionData.common.stdWindSpeed, //
verticalSnowCover: moduleSelectionData.common.stdSnowLd, //
surfaceType: moduleSelectionData.common.illuminationTpNm, //
installHeight: moduleSelectionData.common.instHt, //
userId: loginUserState.userId, //
})
} }
setTabNum(tabNum + 1) setTabNum(tabNum + 1)
@ -72,6 +88,10 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
manualModuleSetup() manualModuleSetup()
}, [isManualModuleSetup]) }, [isManualModuleSetup])
const updateObjectDataApi = async (params) => {
const res = await updateObjectDate(params)
}
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lx-2`}> <div className={`modal-pop-wrap lx-2`}>

View File

@ -1,4 +1,4 @@
import { useState } from 'react' import { useState, useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
@ -15,6 +15,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
roofBaseList, roofBaseList,
constructionList, constructionList,
globalPitchText, globalPitchText,
selectedRaftBase,
selectedTrestle, selectedTrestle,
selectedConstMthd, selectedConstMthd,
selectedRoofBase, selectedRoofBase,
@ -27,8 +28,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
hajebichi, hajebichi,
lengthRef, lengthRef,
hajebichiRef, hajebichiRef,
setLengthBase, handleHajebichiAndLength,
setHajebichi,
handleChangeRaftBase, handleChangeRaftBase,
handleChangeTrestle, handleChangeTrestle,
handleChangeConstMthd, handleChangeConstMthd,
@ -59,7 +59,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
type="text" type="text"
className="input-origin block" className="input-origin block"
value={lengthBase} value={lengthBase}
onChange={(e) => setLengthBase(e.target.value)} onChange={(e) => handleHajebichiAndLength(e, 'length')}
disabled={roofMaterial.lenAuth === 'R' ? true : false} disabled={roofMaterial.lenAuth === 'R' ? true : false}
ref={lengthRef} ref={lengthRef}
/> />
@ -77,9 +77,9 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
{raftCodes.length > 0 && ( {raftCodes.length > 0 && (
<QSelectBox <QSelectBox
options={raftCodes} options={raftCodes}
value={addRoof} value={selectedRaftBase}
sourceKey={'clCode'} sourceKey={'clCode'}
targetKey={'raftBaseCd'} targetKey={'clCode'}
showKey={'clCodeNm'} showKey={'clCodeNm'}
disabled={roofMaterial.raftAuth === 'R' ? true : false} disabled={roofMaterial.raftAuth === 'R' ? true : false}
onChange={handleChangeRaftBase} onChange={handleChangeRaftBase}
@ -100,7 +100,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
type="text" type="text"
className="input-origin block" className="input-origin block"
disabled={roofMaterial.roofPchAuth === 'R' ? true : false} disabled={roofMaterial.roofPchAuth === 'R' ? true : false}
onChange={(e) => setHajebichi(e.target.value)} onChange={(e) => handleHajebichiAndLength(e, 'hajebichi')}
value={hajebichi} value={hajebichi}
ref={hajebichiRef} ref={hajebichiRef}
/> />

View File

@ -57,10 +57,6 @@ const Placement = forwardRef((props, refs) => {
refs.isChidori.current = e.target.value refs.isChidori.current = e.target.value
} }
useEffect(() => {
console.log('isChidori', isChidori)
}, [isChidori])
const handleSetupLocation = (e) => { const handleSetupLocation = (e) => {
setSetupLocation(e.target.value) setSetupLocation(e.target.value)
refs.setupLocation.current = e.target.value refs.setupLocation.current = e.target.value
@ -81,6 +77,20 @@ const Placement = forwardRef((props, refs) => {
setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked }) setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked })
} }
useEffect(() => {
if (moduleSelectionData && moduleSelectionData.module.itemList.length > 0) {
let initCheckedModule = {}
moduleSelectionData.module.itemList.forEach((obj, index) => {
if (index === 0) {
initCheckedModule = { [obj.itemId]: true }
} else {
initCheckedModule = { ...initCheckedModule, [obj.itemId]: true }
}
})
setSelectedItems(initCheckedModule)
}
}, [])
return ( return (
<> <>
<div className="module-table-flex-wrap mb10"> <div className="module-table-flex-wrap mb10">
@ -111,7 +121,13 @@ const Placement = forwardRef((props, refs) => {
<tr key={index}> <tr key={index}>
<td className="al-c"> <td className="al-c">
<div className="d-check-box no-text pop"> <div className="d-check-box no-text pop">
<input type="checkbox" id={item.itemId} name={item.itemId} onChange={handleSelectedItem} /> <input
type="checkbox"
id={item.itemId}
name={item.itemId}
checked={selectedItems[item.itemId]}
onChange={handleSelectedItem}
/>
<label htmlFor={item.itemId}></label> <label htmlFor={item.itemId}></label>
</div> </div>
</td> </td>

View File

@ -163,7 +163,6 @@ export default function CircuitTrestleSetting({ id }) {
.getObjects() .getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.map((obj) => { .map((obj) => {
getModuleList(obj)
return { return {
roofSurfaceId: obj.id, roofSurfaceId: obj.id,
roofSurface: canvas roofSurface: canvas
@ -176,6 +175,7 @@ export default function CircuitTrestleSetting({ id }) {
itemId: module.moduleInfo.itemId, itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber ? module.circuitNumber : null, circuit: module.circuitNumber ? module.circuitNumber : null,
pcsItemId: module.circuit ? module.circuit?.pcsItemId : null, pcsItemId: module.circuit ? module.circuit?.pcsItemId : null,
uniqueId: module.id ? module.id : null,
} }
}), }),
} }
@ -429,6 +429,8 @@ export default function CircuitTrestleSetting({ id }) {
obj.circuit = null obj.circuit = null
obj.pcsItemId = null obj.pcsItemId = null
}) })
setAllocationType(ALLOCATION_TYPE.AUTO)
canvas.renderAll()
}, },
}) })
} }
@ -506,7 +508,7 @@ export default function CircuitTrestleSetting({ id }) {
)} )}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && ( {tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && (
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => setAllocationType(ALLOCATION_TYPE.AUTO)}> <button className="btn-frame modal mr5" onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')} {getMessage('modal.common.prev')}
</button> </button>
<button className="btn-frame modal act" onClick={() => setTabNum(2)}> <button className="btn-frame modal act" onClick={() => setTabNum(2)}>

View File

@ -177,6 +177,26 @@ export default function StepUp(props) {
paralQty: qty.paralQty ? qty.paralQty : 0, paralQty: qty.paralQty ? qty.paralQty : 0,
rmdYn: qty.rmdYn ? qty.rmdYn : 'N', rmdYn: qty.rmdYn ? qty.rmdYn : 'N',
usePossYn: qty.usePossYn ? qty.usePossYn : 'Y', usePossYn: qty.usePossYn ? qty.usePossYn : 'Y',
roofSurfaceList: formatRoofSurfaceList(qty.roofSurfaceList),
}))
}
// 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 : '',
})) }))
} }

View File

@ -7,7 +7,7 @@ import { canvasState } from '@/store/canvasAtom'
import { moduleStatisticsState } 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 { useRecoilState, useRecoilValue } from 'recoil'
export default function PassivityCircuitAllocation(props) { export default function PassivityCircuitAllocation(props) {
const { const {
@ -25,7 +25,7 @@ export default function PassivityCircuitAllocation(props) {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState) const selectedModules = useRecoilValue(selectedModuleState)
const moduleStatistics = useRecoilValue(moduleStatisticsState) const [moduleStatistics, setModuleStatistics] = useRecoilState(moduleStatisticsState)
// const [totalWpout, setTotalWpout] = useState(0) // const [totalWpout, setTotalWpout] = useState(0)
const [selectedPcs, setSelectedPcs] = useState(selectedModels[0]) const [selectedPcs, setSelectedPcs] = useState(selectedModels[0])
// const { header, rows: row } = moduleStatistics // const { header, rows: row } = moduleStatistics
@ -157,6 +157,7 @@ export default function PassivityCircuitAllocation(props) {
} }
const handleCircuitNumberFix = () => { const handleCircuitNumberFix = () => {
let uniqueCircuitNumbers = null
if (!circuitNumber || circuitNumber === 0) { if (!circuitNumber || circuitNumber === 0) {
swalFire({ swalFire({
text: '회로번호를 1 이상입력해주세요.', text: '회로번호를 1 이상입력해주세요.',
@ -172,7 +173,7 @@ export default function PassivityCircuitAllocation(props) {
}) })
return return
} else if (selectedModels.length > 1) { } else if (selectedModels.length > 1) {
const uniqueCircuitNumbers = [ uniqueCircuitNumbers = [
...new Set( ...new Set(
canvas canvas
.getObjects() .getObjects()
@ -255,7 +256,7 @@ export default function PassivityCircuitAllocation(props) {
goodsNo: model.goodsNo, goodsNo: model.goodsNo,
serQtyList: [ serQtyList: [
{ {
serQty: 0, serQty: targetModules.length,
paralQty: 0, paralQty: 0,
rmdYn: 'Y', rmdYn: 'Y',
usePossYn: 'Y', usePossYn: 'Y',
@ -311,15 +312,15 @@ export default function PassivityCircuitAllocation(props) {
const setTableData = () => { const setTableData = () => {
const tempHeader = [ const tempHeader = [
{ name: '지붕면', prop: 'name' }, { name: getMessage('simulator.table.sub1'), prop: 'name' },
{ name: '회로', 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: '발전량(kW)', prop: 'wpOut' }, { name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' },
] ]
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
@ -396,15 +397,16 @@ export default function PassivityCircuitAllocation(props) {
selectedModules.itemList.forEach((module) => { selectedModules.itemList.forEach((module) => {
tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0) tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0)
}) })
console.log('tempHeader, tempRows, tempFooter', tempHeader, tempRows, tempFooter)
setHeader(tempHeader) setHeader(tempHeader)
setRows(tempRows.filter((row) => row.wpOut !== 0)) setRows(tempRows.filter((row) => row.wpOut !== 0))
setFooter(tempFooter) setFooter(tempFooter)
setModuleStatistics({ header: tempHeader, rows: tempRows.filter((row) => row.wpOut !== 0), footer: tempFooter })
} }
const initSelectedPcsCircuitNumber = () => { const initSelectedPcsCircuitNumber = () => {
swalFire({ swalFire({
title: '선택된 파워 컨디셔너의 회로할당을 초기화합니다.', title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.init.info'),
type: 'confirm', type: 'confirm',
icon: 'warning', icon: 'warning',
confirmFn: () => { confirmFn: () => {
@ -425,7 +427,7 @@ export default function PassivityCircuitAllocation(props) {
const initAllPcsCircuitNumber = () => { const initAllPcsCircuitNumber = () => {
canvas.discardActiveObject() canvas.discardActiveObject()
swalFire({ swalFire({
title: '회로 할당의 설정을 초기화합니다.', title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.init.setting.info'),
type: 'confirm', type: 'confirm',
icon: 'warning', icon: 'warning',
confirmFn: () => { confirmFn: () => {
@ -467,7 +469,9 @@ export default function PassivityCircuitAllocation(props) {
<tr key={'row' + index}> <tr key={'row' + index}>
{header.map((header, i) => ( {header.map((header, i) => (
<td className="al-c" key={'rowcell' + i}> <td className="al-c" key={'rowcell' + i}>
{row[header.prop]} {typeof row[header.prop] === 'number'
? row[header.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: row[header.prop]}
</td> </td>
))} ))}
</tr> </tr>
@ -475,7 +479,9 @@ export default function PassivityCircuitAllocation(props) {
<tr> <tr>
{header.map((header, i) => ( {header.map((header, i) => (
<td className="al-c" key={'footer' + i}> <td className="al-c" key={'footer' + i}>
{footer[header.prop]} {typeof footer[header.prop] === 'number'
? footer[header.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: footer[header.prop]}
</td> </td>
))} ))}
</tr> </tr>

View File

@ -292,8 +292,8 @@ export default function DotLineGrid(props) {
</button> </button>
</div> </div>
</div> </div>
<div className="modal-foot modal-handle"></div>
</div> </div>
<div className="modal-foot modal-handle"></div>
</WithDraggable> </WithDraggable>
) )
} }

View File

@ -13,7 +13,7 @@ export default function LinePropertySetting(props) {
const { id, pos = contextPopupPosition, target } = props const { id, pos = contextPopupPosition, target } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { changeSurfaceLinePropertyEvent, changeSurfaceLineProperty, changeSurfaceLinePropertyReset } = useSurfaceShapeBatch() const { changeSurfaceLinePropertyEvent, changeSurfaceLineProperty, changeSurfaceLinePropertyReset } = useSurfaceShapeBatch({})
const { initEvent } = useEvent() const { initEvent } = useEvent()
// const { initEvent } = useContext(EventContext) // const { initEvent } = useContext(EventContext)

View File

@ -17,7 +17,7 @@ export default function SizeSetting(props) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { resizeObjectBatch } = useObjectBatch({}) const { resizeObjectBatch } = useObjectBatch({})
const { resizeSurfaceShapeBatch } = useSurfaceShapeBatch() const { resizeSurfaceShapeBatch } = useSurfaceShapeBatch({})
const widthRef = useRef(null) const widthRef = useRef(null)
const heightRef = useRef(null) const heightRef = useRef(null)

View File

@ -25,24 +25,27 @@ export default function PanelBatchStatistics() {
<thead> <thead>
<tr> <tr>
{header.map((item, index) => ( {header.map((item, index) => (
<th key={index}>{item.name}</th> <th key={`statistic-hd-${index}`}>{item.name}</th>
))} ))}
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{rows.map((row, index) => ( {rows.map((row, index) => (
<tr key={index}> <tr key={`statistic-row-${index}`}>
{header.map((item, i) => ( {header.map((item, i) => (
<td key={index}> <td key={`statistic-col-${i}`}>
{typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]} {typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]}
</td> </td>
))} ))}
</tr> </tr>
))} ))}
<tr> <tr>
{footer.map((item, index) => ( {header.map((header, index) => (
<td key={index}>{typeof item === 'number' ? item.toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : item}</td> <td key={`statistic-ft-${index}`}>
// <td className="al-r">{item.amount}</td> {typeof footer[header.prop] === 'number'
? footer[header.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: footer[header.prop]}
</td>
))} ))}
</tr> </tr>
</tbody> </tbody>

View File

@ -1,3 +1,4 @@
'use client'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
@ -17,7 +18,9 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
const [yInversion, setYInversion] = useState(false) const [yInversion, setYInversion] = useState(false)
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { applySurfaceShape } = useSurfaceShapeBatch() const [isHidden, setIsHidden] = useState(false)
const { applySurfaceShape } = useSurfaceShapeBatch({ isHidden, setIsHidden })
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
@ -232,6 +235,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
surfaceRefs.xInversion = xInversion // surfaceRefs.xInversion = xInversion //
surfaceRefs.yInversion = yInversion // surfaceRefs.yInversion = yInversion //
surfaceRefs.rotate = rotate * 90 // surfaceRefs.rotate = rotate * 90 //
setIsHidden(true)
applySurfaceShape(surfaceRefs, selectedType, id) applySurfaceShape(surfaceRefs, selectedType, id)
} }
@ -241,7 +245,7 @@ export default function PlacementSurfaceSetting({ id, pos = { x: 50, y: 230 } })
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lr-2`}> <div className={`modal-pop-wrap lr-2`} style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
<div className="modal-head modal-handle"> <div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.arrangement')} </h1> <h1 className="title">{getMessage('plan.menu.placement.surface.arrangement')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}> <button className="modal-close" onClick={() => closePopup(id)}>

View File

@ -42,7 +42,6 @@ export default function Stuff() {
// //
const copyNo = async (value) => { const copyNo = async (value) => {
if (navigator.clipboard && window.isSecureContext) { if (navigator.clipboard && window.isSecureContext) {
console.log('trttt')
await navigator.clipboard await navigator.clipboard
.writeText(value) .writeText(value)
.then(() => { .then(() => {
@ -51,9 +50,11 @@ export default function Stuff() {
type: 'alert', type: 'alert',
}) })
}) })
.catch((e) => { .catch(() => {
console.log(e) swalFire({
alert(getMessage('stuff.detail.header.failCopy')) text: getMessage('stuff.detail.header.failCopy'),
type: 'alert',
})
}) })
} else { } else {
// Use the 'out of viewport hidden text area' trick // Use the 'out of viewport hidden text area' trick
@ -213,8 +214,11 @@ export default function Stuff() {
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1, startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1,
endRow: stuffSearchParams?.endRow, endRow: stuffSearchParams?.endRow,
schSelSaleStoreId: stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : '', schSaleStoreId: stuffSearchParams?.schMyDataCheck ? stuffSearchParams.schSaleStoreId : '',
schOtherSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : '', // schSelSaleStoreId: stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : '',
// schOtherSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : '',
schSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schOtherSelSaleStoreId,
schSortType: stuffSearchParams.schSortType, schSortType: stuffSearchParams.schSortType,
pageNo: stuffSearchParams?.pageNo ? stuffSearchParams.pageNo : 1, pageNo: stuffSearchParams?.pageNo ? stuffSearchParams.pageNo : 1,
pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100, pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100,
@ -223,6 +227,7 @@ export default function Stuff() {
if (!params.saleStoreId) { if (!params.saleStoreId) {
params.saleStoreId = session.storeId params.saleStoreId = session.storeId
} }
async function fetchData() { async function fetchData() {
const apiUrl = `/api/object/list?${queryStringFormatter(params)}` const apiUrl = `/api/object/list?${queryStringFormatter(params)}`
await get({ await get({
@ -279,11 +284,15 @@ export default function Stuff() {
stuffSearchParams.saleStoreId = session.storeId stuffSearchParams.saleStoreId = session.storeId
} }
if (stuffSearchParams.schMyDataCheck) { if (stuffSearchParams.schMyDataCheck) {
if (session.storeLvl === '1') { //0203 schSaleStoreId storeId schSelSaleStoreId, schOtherSelSaleStoreId
//schOtherSelSaleStoreId schSelSaleStoreId saleStoreId stuffSearchParams.schSaleStoreId = session.storeId
stuffSearchParams.schOtherSelSaleStoreId = '' stuffSearchParams.schOtherSelSaleStoreId = ''
stuffSearchParams.schSelSaleStoreId = session.storeId stuffSearchParams.schSelSaleStoreId = ''
} // if (session.storeLvl === '1') {
// stuffSearchParams.schSaleStoreId = session.storeId
// stuffSearchParams.schOtherSelSaleStoreId = ''
// stuffSearchParams.schSelSaleStoreId = ''
// }
} }
async function fetchData() { async function fetchData() {

View File

@ -87,6 +87,7 @@ export default function StuffSearchCondition() {
} }
setIsGlobalLoading(true) setIsGlobalLoading(true)
if (stuffSearch.code === 'S') { if (stuffSearch.code === 'S') {
if (stuffSearch.pageNo !== 1) { if (stuffSearch.pageNo !== 1) {
setStuffSearch({ setStuffSearch({
@ -95,8 +96,11 @@ export default function StuffSearchCondition() {
schAddress: address ? address.trim() : '', schAddress: address ? address.trim() : '',
schObjectName: objectName ? objectName.trim() : '', schObjectName: objectName ? objectName.trim() : '',
schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '', schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '',
schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : '', // schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : '',
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', // schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schSaleStoreId: stuffSearch?.schMyDataCheck ? stuffSearch?.schSaleStoreId : '',
schSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schOtherSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
@ -307,6 +311,7 @@ export default function StuffSearchCondition() {
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = '' stuffSearch.schTempFlg = ''
stuffSearch.schMyDataCheck = false stuffSearch.schMyDataCheck = false
stuffSearch.schSaleStoreId = ''
setObjectNo('') setObjectNo('')
setAddress('') setAddress('')
setobjectName('') setobjectName('')
@ -332,6 +337,7 @@ export default function StuffSearchCondition() {
schDispCompanyName: '', schDispCompanyName: '',
schSelSaleStoreId: '', schSelSaleStoreId: '',
schOtherSelSaleStoreId: '', schOtherSelSaleStoreId: '',
schSaleStoreId: '',
schDateType: 'U', schDateType: 'U',
schTempFlg: '', schTempFlg: '',
schMyDataCheck: false, schMyDataCheck: false,
@ -346,6 +352,7 @@ export default function StuffSearchCondition() {
if (otherSaleStoreList.length === 1) { if (otherSaleStoreList.length === 1) {
setOtherSaleStoreId(session.storeId) setOtherSaleStoreId(session.storeId)
stuffSearch.schOtherSelSaleStoreId = session.storeId stuffSearch.schOtherSelSaleStoreId = session.storeId
stuffSearch.schSaleStoreId = ''
stuffSearch.schObjectNo = '' stuffSearch.schObjectNo = ''
stuffSearch.schAddress = '' stuffSearch.schAddress = ''
stuffSearch.schObjectName = '' stuffSearch.schObjectName = ''
@ -364,6 +371,7 @@ export default function StuffSearchCondition() {
} else if (otherSaleStoreList.length > 1) { } else if (otherSaleStoreList.length > 1) {
setOtherSaleStoreId('') setOtherSaleStoreId('')
stuffSearch.schOtherSelSaleStoreId = session.storeId stuffSearch.schOtherSelSaleStoreId = session.storeId
stuffSearch.schSaleStoreId = ''
stuffSearch.schObjectNo = '' stuffSearch.schObjectNo = ''
stuffSearch.schAddress = '' stuffSearch.schAddress = ''
stuffSearch.schObjectName = '' stuffSearch.schObjectName = ''
@ -394,11 +402,13 @@ export default function StuffSearchCondition() {
stuffSearch.schSortType = 'U' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
stuffSearch.schSaleStoreId = ''
} }
} else if (session?.storeLvl === '1') { } else if (session?.storeLvl === '1') {
if (otherSaleStoreList.length > 0) { if (otherSaleStoreList.length > 0) {
handleClear2() handleClear2()
setOtherSaleStoreId('') setOtherSaleStoreId('')
stuffSearch.schSaleStoreId = ''
stuffSearch.schObjectNo = '' stuffSearch.schObjectNo = ''
stuffSearch.schAddress = '' stuffSearch.schAddress = ''
stuffSearch.schObjectName = '' stuffSearch.schObjectName = ''
@ -414,6 +424,7 @@ export default function StuffSearchCondition() {
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
} else { } else {
stuffSearch.schSaleStoreId = ''
stuffSearch.schObjectNo = '' stuffSearch.schObjectNo = ''
stuffSearch.schAddress = '' stuffSearch.schAddress = ''
stuffSearch.schObjectName = '' stuffSearch.schObjectName = ''
@ -583,8 +594,8 @@ export default function StuffSearchCondition() {
// //
const onSelectionChange = (key) => { const onSelectionChange = (key) => {
// //
setMyDataCheck(false) setMyDataCheck(stuffSearch.schMyDataCheck)
stuffSearch.schMyDataCheck = false // stuffSearch.schMyDataCheck = false
if (isObjectNotEmpty(key)) { if (isObjectNotEmpty(key)) {
setOtherSaleStoreId('') setOtherSaleStoreId('')
@ -695,6 +706,7 @@ export default function StuffSearchCondition() {
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schSaleStoreId = ''
stuffSearch.schSortType = 'U' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
@ -729,6 +741,7 @@ export default function StuffSearchCondition() {
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schSaleStoreId = ''
stuffSearch.schSortType = 'U' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
@ -759,7 +772,6 @@ export default function StuffSearchCondition() {
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
setOtherSaleStoreId('') setOtherSaleStoreId('')
} }
setObjectNo('') setObjectNo('')
setSaleStoreName('') setSaleStoreName('')
setAddress('') setAddress('')
@ -841,47 +853,59 @@ export default function StuffSearchCondition() {
// //
const checkMyData = (e) => { const checkMyData = (e) => {
//0203 schSaleStoreId storeId schSelSaleStoreId, schOtherSelSaleStoreId
if (session?.storeId === 'T01') { if (session?.storeId === 'T01') {
if (e.target.checked) { if (e.target.checked) {
stuffSearch.schMyDataCheck = e.target.value stuffSearch.schMyDataCheck = e.target.checked
setMyDataCheck(true) setMyDataCheck(true)
setOtherSaleStoreId('') //2 setOtherSaleStoreId('') //2
setSchSelSaleStoreId('T01') setSchSelSaleStoreId('T01')
stuffSearch.schSelSaleStoreId = 'T01'
stuffSearch.schSaleStoreId = session.storeId
stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
const key = { saleStoreId: session.storeId }
onSelectionChange(key)
} else { } else {
stuffSearch.schMyDataCheck = e.target.value stuffSearch.schSaleStoreId = ''
stuffSearch.schMyDataCheck = e.target.checked
setSchSelSaleStoreId('')
setMyDataCheck(false) setMyDataCheck(false)
onSelectionChange(null)
} }
} else if (session?.storeLvl === '1') { } else if (session?.storeLvl === '1') {
if (e.target.checked) { if (e.target.checked) {
stuffSearch.schMyDataCheck = e.target.value stuffSearch.schMyDataCheck = e.target.checked
setMyDataCheck(true) setMyDataCheck(true)
//schOtherSelSaleStoreId
//schSelSaleStoreId saleStoreId
setOtherSaleStoreId('') //2 setOtherSaleStoreId('') //2
setSchSelSaleStoreId(schSelSaleStoreId) setSchSelSaleStoreId(schSelSaleStoreId)
stuffSearch.schSelSaleStoreId = schSelSaleStoreId stuffSearch.schSaleStoreId = session.storeId
stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
} else { } else {
stuffSearch.schMyDataCheck = e.target.checked
stuffSearch.schSaleStoreId = ''
setMyDataCheck(false) setMyDataCheck(false)
} }
} else { } else {
//2 3,4 //2 3,4
//3,4 //3,4
if (e.target.checked) { if (e.target.checked) {
stuffSearch.schMyDataCheck = e.target.value stuffSearch.schMyDataCheck = e.target.checked
setMyDataCheck(true) setMyDataCheck(true)
if (otherSaleStoreList.length > 1) { if (otherSaleStoreList.length > 1) {
stuffSearch.schOtherSelSaleStoreId = session.storeId stuffSearch.schSaleStoreId = session.storeId
stuffSearch.schOtherSelSaleStoreId = ''
setOtherSaleStoreId(session.storeId) setOtherSaleStoreId(session.storeId)
} else { } else {
stuffSearch.schSaleStoreId = session.storeId
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = session.storeId stuffSearch.schOtherSelSaleStoreId = ''
} }
} else { } else {
setMyDataCheck(false) setMyDataCheck(false)
stuffSearch.schMyDataCheck = e.target.value stuffSearch.schMyDataCheck = e.target.checked
stuffSearch.schSaleStoreId = ''
} }
} }
} }

View File

@ -301,6 +301,8 @@ export function useCommonUtils() {
...commonUtilsState, ...commonUtilsState,
dimension: false, dimension: false,
}) })
initEvent()
} }
// 캔버스 다시 그리기 // 캔버스 다시 그리기
@ -655,6 +657,7 @@ export function useCommonUtils() {
const closeDistancePopup = () => { const closeDistancePopup = () => {
const obj = canvas?.getObjects().filter((obj) => obj.name === 'distance') const obj = canvas?.getObjects().filter((obj) => obj.name === 'distance')
if (obj) canvas.remove(...obj) if (obj) canvas.remove(...obj)
initEvent()
} }
//선택된 그룹객체 restore 하고 item으로 다시 그리고 그 그린 객체 가지고 수정해서 재그룹화 시킨다 //선택된 그룹객체 restore 하고 item으로 다시 그리고 그 그린 객체 가지고 수정해서 재그룹화 시킨다

View File

@ -12,7 +12,7 @@ import { useRecoilValue } from 'recoil'
* @returns * @returns
*/ */
export function useMasterController() { export function useMasterController() {
const { get, post } = useAxios() const { get, post, put } = useAxios()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { swalFire } = useSwal() const { swalFire } = useSwal()
@ -216,6 +216,24 @@ export function useMasterController() {
}) })
} }
const getQuotationItem = async (params) => {
return await post({ url: '/api/v1/master/getQuotationItem', data: params }).then((res) => {
return res
})
}
/**
* 물건 정보 업데이트 api 호출
* @param {objectNo standardWindSpeedId verticalSnowCover surfaceType installHeight userId} params
* @param {물건번호 기준풍속코드 적설량 면조도구분 설치높이 작성자아아디 } params
* @returns
*/
const updateObjectDate = async (params = null) => {
return await put({ url: '/api/object/update-object-date', data: params }).then((res) => {
console.log('updateObjectDate', res)
})
}
return { return {
getRoofMaterialList, getRoofMaterialList,
getModuleTypeItemList, getModuleTypeItemList,
@ -228,5 +246,7 @@ export function useMasterController() {
getPcsVoltageChk, getPcsVoltageChk,
getPcsManualConfChk, getPcsManualConfChk,
getPcsVoltageStepUpList, getPcsVoltageStepUpList,
updateObjectDate,
getQuotationItem,
} }
} }

View File

@ -25,7 +25,7 @@ export default function useMenu() {
const currentMenu = useRecoilValue(currentMenuState) const currentMenu = useRecoilValue(currentMenuState)
const [popupId, setPopupId] = useState(uuidv4()) const [popupId, setPopupId] = useState(uuidv4())
const { addPopup } = usePopup() const { addPopup } = usePopup()
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch() const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch({})
const handleMenu = (type) => { const handleMenu = (type) => {
if (type === 'outline') { if (type === 'outline') {
switch (currentMenu) { switch (currentMenu) {

View File

@ -394,6 +394,8 @@ export function useModuleBasicSetting() {
return return
} }
console.log('placementRef', placementRef)
const isChidori = placementRef.isChidori.current === 'true' ? true : false const isChidori = placementRef.isChidori.current === 'true' ? true : false
const setupLocation = placementRef.setupLocation.current const setupLocation = placementRef.setupLocation.current
const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false

View File

@ -71,12 +71,16 @@ export function useModulePlace() {
.forEach((roof) => { .forEach((roof) => {
const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번 const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번
trestleDetailList.forEach((detail) => { trestleDetailList.forEach((detail) => {
if (Number(detail.data.roofIndex) === roofIndex) { if (detail.data !== null) {
//roof에 상세 데이터 추가 if (Number(detail.data.roofIndex) === roofIndex) {
roof.set({ trestleDetail: detail.data }) //roof에 상세 데이터 추가
//배치면 설치 영역 roof.set({ trestleDetail: detail.data })
makeModuleInstArea(roof, detail.data) //배치면 설치 영역
//surface에 상세 데이터 추가 makeModuleInstArea(roof, detail.data)
//surface에 상세 데이터 추가
} else {
console.log('가대 데이터가 없네요...')
}
} }
}) })
}) })

View File

@ -37,6 +37,7 @@ export function useModuleSelection(props) {
bindInitData() bindInitData()
const initParams = { const initParams = {
illuminationTp: managementState?.surfaceTypeValue, //면조도 illuminationTp: managementState?.surfaceTypeValue, //면조도
illuminationTpNm: managementState?.surfaceType, //면조도명
instHt: managementState?.installHeight, //설치높이 instHt: managementState?.installHeight, //설치높이
stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속 stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속
stdSnowLd: managementState?.verticalSnowCover, //기준적설량 stdSnowLd: managementState?.verticalSnowCover, //기준적설량
@ -119,6 +120,7 @@ export function useModuleSelection(props) {
setModuleSelectionInitParams({ setModuleSelectionInitParams({
...moduleSelectionInitParams, ...moduleSelectionInitParams,
illuminationTp: option.clCode, illuminationTp: option.clCode,
illuminationTpNm: option.clCodeNm,
}) })
setManagementState({ setManagementState({

View File

@ -59,9 +59,10 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
const handleChangeRaftBase = (option) => { const handleChangeRaftBase = (option) => {
setSelectedRaftBase(option) setSelectedRaftBase(option)
setTrestleParams({ ...trestleParams, raftBaseCd: option.clCode }) //가대메이커 setTrestleParams({ ...trestleParams, raftBaseCd: option.clCode }) //가대메이커
setConstMthdList([]) //공법 초기화 // setConstMthdList([]) //공법 초기화
setRoofBaseList([]) //지붕밑바탕 초기화 // setRoofBaseList([]) //지붕밑바탕 초기화
setConstructionList([]) //공법 초기화 // setConstructionList([]) //공법 초기화
resetSelected()
} }
//처마력바 체크 //처마력바 체크
@ -85,7 +86,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
useEffect(() => { useEffect(() => {
setHajebichi(addRoof.hajebichi) setHajebichi(addRoof.hajebichi)
setLengthBase(addRoof.lenBase) setLengthBase(addRoof.length)
// 202600 경사도 // 202600 경사도
const raftCodeList = findCommonCode('203800') const raftCodeList = findCommonCode('203800')
@ -96,7 +97,13 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
}) })
setRaftCodes(raftCodeList) setRaftCodes(raftCodeList)
console.log('moduleSelectionData', moduleSelectionData) if (addRoof.raft) {
setSelectedRaftBase({
...selectedRaftBase,
raftBaseCd: addRoof.raft,
clCode: addRoof.raft,
})
}
}, []) }, [])
//리코일에 데이터가 담기는 시점에 시작 //리코일에 데이터가 담기는 시점에 시작
@ -116,38 +123,18 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
} }
}, [moduleConstructionSelectionData]) }, [moduleConstructionSelectionData])
//높이를 변경하면 addRoofs에 적용
// useEffect(() => { // useEffect(() => {
// const copyAddRoof = { ...addRoof } // if (isExistData) {
// copyAddRoof.length = Number(lengthBase) // setConstructionListParams({
// copyAddRoof.lenBase = lengthBase // ...moduleSelectionInitParams,
// const index = addRoof.index // ...roofBaseParams,
// const newArray = [...addRoofsArray.slice(0, index), copyAddRoof, ...addRoofsArray.slice(index + 1)] // roofBaseCd: selectedRoofBase.roofBaseCd,
// setAddedRoofs(newArray) // inclCd: addRoof.pitch,
// }, [lengthBase]) // roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
// raftBaseCd: selectedRaftBase.raftBaseCd ? selectedRaftBase.raftBaseCd : '',
// //망둥어 피치를 변경하면 addRoof 변경 // })
// useEffect(() => { // }
// const copyAddRoof = { ...addRoof } // }, [selectedRoofBase])
// copyAddRoof.hajebichi = Number(hajebichi)
// copyAddRoof.roofPchBase = hajebichi
// const index = addRoof.index
// const newArray = [...addRoofsArray.slice(0, index), copyAddRoof, ...addRoofsArray.slice(index + 1)]
// setAddedRoofs(newArray)
// }, [hajebichi])
useEffect(() => {
if (isExistData) {
setConstructionListParams({
...moduleSelectionInitParams,
...roofBaseParams,
roofBaseCd: selectedRoofBase.roofBaseCd,
inclCd: addRoof.pitch,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
raftBaseCd: addRoof.raftBaseCd,
})
}
}, [selectedRoofBase])
useEffect(() => { useEffect(() => {
if ( if (
@ -172,7 +159,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
setTrestleParams({ setTrestleParams({
moduleTpCd: selectedModules.itemTp, moduleTpCd: selectedModules.itemTp,
roofMatlCd: addRoof.roofMatlCd, roofMatlCd: addRoof.roofMatlCd,
raftBaseCd: addRoof.raftBaseCd, raftBaseCd: selectedRaftBase.raftBaseCd ? selectedRaftBase.raftBaseCd : '',
workingWidth: lengthBase, workingWidth: lengthBase,
}) })
} }
@ -222,7 +209,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
roofBaseCd: option.roofBaseCd, roofBaseCd: option.roofBaseCd,
inclCd: addRoof.pitch, inclCd: addRoof.pitch,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0, roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
raftBaseCd: addRoof.raftBaseCd, raftBaseCd: selectedRaftBase.clCode ? selectedRaftBase.clCode : '',
roofMatlCd: addRoof.roofMatlCd, roofMatlCd: addRoof.roofMatlCd,
}) })
setSelectedRoofBase(option) setSelectedRoofBase(option)
@ -309,29 +296,36 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
} }
}, [selectedConstruction]) }, [selectedConstruction])
//거대메이커, 공법, 지붕밑바탕 api 조회
const getModuleOptionsListData = async (params, type) => { const getModuleOptionsListData = async (params, type) => {
const optionsList = await getTrestleList(params) const optionsList = await getTrestleList(params)
if (optionsList.data.length > 0) { if (optionsList.data.length > 0) {
if (type === 'trestle') { if (type === 'trestle') {
setTrestleList(optionsList.data) //가대 메이커일때
setTrestleList(optionsList.data) //가대 목록
if (isExistData) { if (isExistData) {
//데이터가 있으면 선택된 가대 메이커를 선택한다
handleChangeTrestle(moduleConstructionSelectionData?.trestle) handleChangeTrestle(moduleConstructionSelectionData?.trestle)
} else { } else {
setConstMthdList([]) setConstMthdList([]) //공법 목록 초기화
setRoofBaseList([]) setRoofBaseList([]) //지붕밑바탕 목록 초기화
} }
} else if (type === 'construction') { } else if (type === 'construction') {
setConstMthdList(optionsList.data) //공법일때
setConstMthdList(optionsList.data) //공법 목록
if (isExistData) { if (isExistData) {
//데이터가 있으면 선택된 공법을 선택한다
handleChangeConstMthd(moduleConstructionSelectionData?.trestle) handleChangeConstMthd(moduleConstructionSelectionData?.trestle)
} else { } else {
setRoofBaseList([]) setRoofBaseList([]) //지붕밑바탕 목록 초기화
} }
} else if (type === 'roofBase') { } else if (type === 'roofBase') {
setRoofBaseList(optionsList.data) //지붕밑바탕일때
setRoofBaseList(optionsList.data) //지붕밑바탕 목록
if (isExistData) { if (isExistData) {
handleChangeRoofBase(moduleConstructionSelectionData?.trestle) //데이터가 있으면 선택된 지붕밑바탕을 선택한다
handleChangeRoofBase(moduleConstructionSelectionData?.trestle) //선택된 지붕밑바탕을 선택한다
} }
} }
} }
@ -342,51 +336,64 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
if (moduleSelectionInitOriginData.current.moduleItemId && moduleSelectionInitOriginData.current.moduleTpCd) { if (moduleSelectionInitOriginData.current.moduleItemId && moduleSelectionInitOriginData.current.moduleTpCd) {
//초기에 들어온 데이터가 수정된 데이터가 값이 다르다면` //초기에 들어온 데이터가 수정된 데이터가 값이 다르다면`
if (!isEqualObjects(moduleSelectionInitOriginData.current, moduleSelectionInitParams)) { if (!isEqualObjects(moduleSelectionInitOriginData.current, moduleSelectionInitParams)) {
//가대 선택 초기화 resetSelected()
setSelectedTrestle({})
//공법 선택 초기화
setSelectedConstMthd({})
//지붕밑바탕 선택 초기화
setSelectedRoofBase({})
//공법 리스트 초기화
setConstructionList([])
// 기본 정보 초기화
setModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
// 선택 데이터 초 기화
setModuleConstructionSelectionData({
addRoof: addRoof,
trestle: {},
construction: {},
})
//임시 데이터 초기화
setTempModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
//처마커버 해제
setCvrChecked(false)
//눈막이금구 해제
setSnowGdChecked(false)
// 데이터 없음으로 변경
setIsExistData(false)
//변경된 데이터를 ref에 저장
moduleSelectionInitOriginData.current = moduleSelectionInitParams
} }
} }
}, [moduleSelectionInitParams]) }, [moduleSelectionInitParams])
const handleHajebichiAndLength = (e, type) => {
if (type === 'length') {
setLengthBase(e.target.value)
} else {
setHajebichi(e.target.value)
}
resetSelected()
}
const resetSelected = () => {
//가대 선택 초기화
setSelectedTrestle({})
//공법 선택 초기화
setSelectedConstMthd({})
//지붕밑바탕 선택 초기화
setSelectedRoofBase({})
//공법 리스트 초기화
setConstructionList([])
// 기본 정보 초기화
setModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
// 선택 데이터 초 기화
setModuleConstructionSelectionData({
addRoof: addRoof,
trestle: {},
construction: {},
})
//임시 데이터 초기화
setTempModuleSelectionData({
...moduleSelectionData,
roofConstructions: [],
})
//처마커버 해제
setCvrChecked(false)
//눈막이금구 해제
setSnowGdChecked(false)
// 데이터 없음으로 변경
setIsExistData(false)
//변경된 데이터를 ref에 저장
moduleSelectionInitOriginData.current = moduleSelectionInitParams
}
return { return {
raftCodes, raftCodes,
trestleList, trestleList,
@ -394,6 +401,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
roofBaseList, roofBaseList,
constructionList, constructionList,
globalPitchText, globalPitchText,
selectedRaftBase,
selectedTrestle, selectedTrestle,
selectedConstMthd, selectedConstMthd,
selectedRoofBase, selectedRoofBase,
@ -406,8 +414,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
hajebichi, hajebichi,
lengthRef, lengthRef,
hajebichiRef, hajebichiRef,
setLengthBase, handleHajebichiAndLength,
setHajebichi,
handleChangeRaftBase, handleChangeRaftBase,
handleChangeTrestle, handleChangeTrestle,
handleChangeConstMthd, handleChangeConstMthd,

View File

@ -4,11 +4,13 @@ import { POLYGON_TYPE } from '@/common/common'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { getDegreeByChon, getTrestleLength } from '@/util/canvas-util' import { getDegreeByChon, getTrestleLength } from '@/util/canvas-util'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { useMasterController } from '@/hooks/common/useMasterController'
// 회로 및 가대설정 // 회로 및 가대설정
export const useTrestle = () => { export const useTrestle = () => {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터 const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
const { getQuotationItem } = useMasterController()
const apply = () => { const apply = () => {
//처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함. //처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함.
@ -17,7 +19,7 @@ export const useTrestle = () => {
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
// 기존 eaveBar를 삭제 // 기존 eaveBar를 삭제
canvas.getObjects().forEach((obj) => { canvas.getObjects().forEach((obj) => {
if (obj.name === 'eaveBar' || obj.name === 'rack') { if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') {
canvas.remove(obj) canvas.remove(obj)
} }
}) })
@ -96,7 +98,7 @@ export const useTrestle = () => {
canvas canvas
.getObjects() .getObjects()
.filter((obj) => ['eaveBar', 'halfEaveBar'].includes(obj.name) && obj.parent === surface) .filter((obj) => ['eaveBar', 'halfEaveBar'].includes(obj.name) && obj.parentId === surface.id)
.forEach((obj) => { .forEach((obj) => {
canvas.remove(obj) canvas.remove(obj)
}) })
@ -435,7 +437,18 @@ export const useTrestle = () => {
installBracket(surface) installBracket(surface)
} }
console.log(getTrestleParams(surface)) const quotationParam = getTrestleParams(surface)
surface.set({ quotationParam })
getQuoationItems()
})
}
const getQuoationItems = () => {
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const params = { trestles: surfaces.map((surface) => surface.quotationParam) }
getQuotationItem(params).then((res) => {
console.log(res)
}) })
} }
@ -633,9 +646,9 @@ export const useTrestle = () => {
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10 rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') { if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
name: 'smartRack', name: 'smartRack',
stroke: 'blue', stroke: 'red',
strokeWidth: 4, strokeWidth: 4,
selectable: false, selectable: false,
shadow: { shadow: {
@ -706,7 +719,7 @@ export const useTrestle = () => {
if (setRackTpCd === 'RACK') { if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], { const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
name: 'smartRack', name: 'smartRack',
stroke: 'blue', stroke: 'red',
strokeWidth: 4, strokeWidth: 4,
selectable: false, selectable: false,
shadow: { shadow: {
@ -775,7 +788,7 @@ export const useTrestle = () => {
if (setRackTpCd === 'RACK') { if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
name: 'smartRack', name: 'smartRack',
stroke: 'blue', stroke: 'red',
strokeWidth: 4, strokeWidth: 4,
selectable: false, selectable: false,
shadow: { shadow: {
@ -840,9 +853,9 @@ export const useTrestle = () => {
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => { smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10 rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') { if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], { const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
name: 'smartRack', name: 'smartRack',
stroke: 'blue', stroke: 'red',
strokeWidth: 4, strokeWidth: 4,
selectable: false, selectable: false,
shadow: { shadow: {
@ -906,7 +919,7 @@ export const useTrestle = () => {
modules.forEach((module) => { modules.forEach((module) => {
canvas canvas
.getObjects() .getObjects()
.filter((obj) => obj.name === 'rack') .filter((obj) => obj.name === 'rack' || obj.name === 'smartRack')
.forEach((rack) => { .forEach((rack) => {
if (rack.parentId === module.id) { if (rack.parentId === module.id) {
canvas.remove(canvas.getObjects().filter((obj) => obj.name === 'bracket' && obj.parentId === rack.id)) canvas.remove(canvas.getObjects().filter((obj) => obj.name === 'bracket' && obj.parentId === rack.id))
@ -1171,7 +1184,7 @@ export const useTrestle = () => {
const getBracketPoints = (n, percent) => { const getBracketPoints = (n, percent) => {
if (n < 2) { if (n < 2) {
throw new Error('Number of points must be at least 2') return []
} }
const points = [] const points = []
@ -1479,6 +1492,7 @@ export const useTrestle = () => {
return groups return groups
} }
// 견적서 아이템 조회 api parameter 생성
const getTrestleParams = (surface) => { const getTrestleParams = (surface) => {
const result = calculateForApi(surface) const result = calculateForApi(surface)
@ -1505,8 +1519,24 @@ export const useTrestle = () => {
rackRows: rack.rackRowsCd, rackRows: rack.rackRowsCd,
} }
}) })
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
const roofMaterialIndex = parent.roofMaterial.index
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
const { common, module } = moduleSelectionData
// const { constTp } = construction
let { cvrPlvrYn } = surface.trestleDetail
const { trestleMkrCd, constMthdCd, roofBaseCd } = moduleSelection.trestle
const { illuminationTp, instHt, stdSnowLd, stdWindSpeed } = common
const { constTp } = moduleSelection.construction
const { addRoof } = moduleSelection
return { return {
moduleTpCd: module.itemTp,
roofMatlCd: parent.roofMaterial.roofMatlCd,
mixMatlNo: module.mixMatlNo,
raftBaseCd: addRoof.raft,
roofPitch: addRoof.roofPchBase,
exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수 exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수
exposedHalfBottomTotCnt: result.exposedHalfBottom, // 노출 반하면 갯수 exposedHalfBottomTotCnt: result.exposedHalfBottom, // 노출 반하면 갯수
exposedTopTotCnt: result.exposedTop, // 노출 상면 총 수 exposedTopTotCnt: result.exposedTop, // 노출 상면 총 수
@ -1521,9 +1551,56 @@ export const useTrestle = () => {
rackTotCnt: rackList.length ?? 0 + smartRackGroup.length ?? 0, rackTotCnt: rackList.length ?? 0 + smartRackGroup.length ?? 0,
rackFittingCnt: bracketList.length, rackFittingCnt: bracketList.length,
moduleRows: getMostLeftModules(surface), moduleRows: getMostLeftModules(surface),
cvrYn: moduleSelection.construction.setupCover ? 'Y' : 'N',
snowGuardYn: moduleSelection.construction.setupSnowCover ? 'Y' : 'N',
plvrYn: cvrPlvrYn,
modules: getModules(surface),
pcses: surface.pcses ?? [],
trestleMkrCd,
constMthdCd,
roofBaseCd,
illuminationTp,
instHt,
stdSnowLd,
stdWindSpeed,
constTp,
} }
} }
const getModules = (surface) => {
const { modules } = surface
const params = modules.map((module, index) => {
return {
moduleTpCd: module.moduleInfo.itemTp,
moduleItemId: module.moduleInfo.itemId,
}
})
//params를 moduleTpCd, moduleItemId로 그룹화 하면서 cnt를 계산
const groupedParams = params.reduce((acc, cur) => {
const key = `${cur.moduleTpCd}-${cur.moduleItemId}`
if (!acc[key]) {
acc[key] = {
moduleTpCd: cur.moduleTpCd,
moduleItemId: cur.moduleItemId,
cnt: 0,
}
}
acc[key].cnt++
return acc
}, {})
// map 형태의 데이터를 배열로 변환
return Object.values(groupedParams).map((groupedParam, index) => {
return {
moduleTpCd: groupedParam.moduleTpCd,
moduleItemId: groupedParam.moduleItemId,
moduleCnt: groupedParam.cnt,
}
})
}
// 가장 왼쪽에 있는 모듈을 기준으로 같은 단에 있는 모듈들 파라미터 생성 // 가장 왼쪽에 있는 모듈을 기준으로 같은 단에 있는 모듈들 파라미터 생성
const getMostLeftModules = (surface) => { const getMostLeftModules = (surface) => {
const { direction, modules } = surface const { direction, modules } = surface

View File

@ -196,33 +196,33 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
surfaceShapePolygons.forEach((surface) => { surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) { if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface selectedSurface = surface
rect = new fabric.Rect({
fill: 'white',
stroke: 'black',
strokeWidth: 1,
width: width,
height: height,
left: pointer.x - width / 2,
top: pointer.y - height / 2,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
parentId: selectedSurface.id,
})
//개구냐 그림자냐에 따라 변경
rect.set({
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
name: objTempName,
})
canvas?.add(rect)
} }
}) })
rect = new fabric.Rect({
fill: 'white',
stroke: 'black',
strokeWidth: 1,
width: width,
height: height,
left: pointer.x - width / 2,
top: pointer.y - height / 2,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
parentId: selectedSurface.id,
})
//개구냐 그림자냐에 따라 변경
rect.set({
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
name: objTempName,
})
canvas?.add(rect)
}) })
addCanvasMouseEventListener('mouse:up', (e) => { addCanvasMouseEventListener('mouse:up', (e) => {
@ -726,7 +726,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
initEvent() initEvent()
dbClickEvent() dbClickEvent()
if (setIsHidden) setIsHidden(false)
} }
}) })
} }

View File

@ -487,6 +487,7 @@ export function useRoofShapeSetting(id) {
offset: eavesOffset / 10, offset: eavesOffset / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.EAVES, type: LINE_TYPE.WALLLINE.EAVES,
onlyOffset: false,
} }
// hideLine(line) // hideLine(line)
}) })

View File

@ -1,5 +1,6 @@
'use client' 'use client'
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState, globalPitchState } from '@/store/canvasAtom' import { canvasState, globalPitchState } from '@/store/canvasAtom'
import { MENU, POLYGON_TYPE } from '@/common/common' import { MENU, POLYGON_TYPE } from '@/common/common'
@ -18,7 +19,7 @@ import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
export function useSurfaceShapeBatch() { export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
@ -72,6 +73,9 @@ export function useSurfaceShapeBatch() {
let isDrawing = true let isDrawing = true
let obj = null let obj = null
let points = [] let points = []
//일단 팝업을 가린다
if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) { if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) {
addCanvasMouseEventListener('mouse:move', (e) => { addCanvasMouseEventListener('mouse:move', (e) => {
if (!isDrawing) { if (!isDrawing) {
@ -106,9 +110,7 @@ export function useSurfaceShapeBatch() {
obj.setCoords() //좌표 변경 적용 obj.setCoords() //좌표 변경 적용
canvas?.add(obj) canvas?.add(obj)
canvas?.renderAll() canvas?.renderAll()
closePopup(id)
}) })
addCanvasMouseEventListener('mouse:down', (e) => { addCanvasMouseEventListener('mouse:down', (e) => {
@ -156,9 +158,14 @@ export function useSurfaceShapeBatch() {
canvas?.add(batchSurface) canvas?.add(batchSurface)
setSurfaceShapePattern(batchSurface, roofDisplay.column) setSurfaceShapePattern(batchSurface, roofDisplay.column)
drawDirectionArrow(batchSurface) drawDirectionArrow(batchSurface)
closePopup(id)
if (setIsHidden) setIsHidden(false)
// closePopup(id)
initEvent() initEvent()
}) })
} else {
if (setIsHidden) setIsHidden(false)
} }
} }
@ -200,12 +207,15 @@ export function useSurfaceShapeBatch() {
} }
} }
if (surfaceId === 18) { if (surfaceId === 18) {
if (length1 >= length2) { if (length2 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' }) swalFire({ text: getMessage('surface.shape.validate.size.3to2'), icon: 'error' })
check = false check = false
} }
if (length4 >= length3) { }
swalFire({ text: getMessage('surface.shape.validate.size.3to4'), icon: 'error' })
if (surfaceId === 6) {
if (length2 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.3to2'), icon: 'error' })
check = false check = false
} }
} }
@ -226,7 +236,7 @@ export function useSurfaceShapeBatch() {
} }
} }
if (surfaceId === 12 || surfaceId === 13 || surfaceId === 16 || surfaceId === 17) { if (surfaceId === 12 || surfaceId === 13 || surfaceId === 16) {
if (length2 >= length1) { if (length2 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' }) swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false check = false
@ -237,12 +247,24 @@ export function useSurfaceShapeBatch() {
check = false check = false
} }
} }
if (surfaceId === 17) {
if (length2 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false
}
if (length3 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to3'), icon: 'error' })
check = false
}
}
} else if ([7, 9, 10, 11, 14].includes(surfaceId)) { } else if ([7, 9, 10, 11, 14].includes(surfaceId)) {
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0 || length5 === 0) { if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0 || length5 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' }) swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false check = false
} }
if (surfaceId === 9 || surfaceId === 10 || surfaceId === 11) { if (surfaceId === 9 || surfaceId === 10) {
if (length2 + length3 >= length1) { if (length2 + length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' }) swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' })
check = false check = false
@ -253,6 +275,17 @@ export function useSurfaceShapeBatch() {
} }
} }
if (surfaceId === 11) {
if (length1 > length2 + length3) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23low'), icon: 'error' })
check = false
}
if (length5 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to5'), icon: 'error' })
check = false
}
}
if (surfaceId === 14) { if (surfaceId === 14) {
if (length2 + length3 >= length1) { if (length2 + length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' }) swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' })

View File

@ -59,7 +59,7 @@ export function useContextMenu() {
const [column, setColumn] = useState(null) const [column, setColumn] = useState(null)
const { handleZoomClear } = useCanvasEvent() const { handleZoomClear } = useCanvasEvent()
const { moveObjectBatch } = useObjectBatch({}) const { moveObjectBatch } = useObjectBatch({})
const { moveSurfaceShapeBatch } = useSurfaceShapeBatch() const { moveSurfaceShapeBatch } = useSurfaceShapeBatch({})
const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom) const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom)
const { addLine, removeLine } = useLine() const { addLine, removeLine } = useLine()
const { removeGrid } = useGrid() const { removeGrid } = useGrid()

View File

@ -95,8 +95,8 @@ export const useLine = () => {
const textStr = const textStr =
currentAngleType === ANGLE_TYPE.SLOPE currentAngleType === ANGLE_TYPE.SLOPE
? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${onlyOffset && attributes.pitch ? '-∠' + attributes.pitch + angleUnit : ''}` ? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${!onlyOffset && attributes.pitch ? '-∠' + attributes.pitch + angleUnit : ''}`
: `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${onlyOffset && attributes.pitch ? '-∠' + getDegreeByChon(attributes.pitch) + angleUnit : ''}` : `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${!onlyOffset && attributes.pitch ? '-∠' + getDegreeByChon(attributes.pitch) + angleUnit : ''}`
if (direction === 'top') { if (direction === 'top') {
left = (startPoint.x + endPoint.x) / 2 left = (startPoint.x + endPoint.x) / 2

View File

@ -149,6 +149,8 @@
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset": "選択されたパワーコンディショナーの回路番号の初期化", "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.all.power.conditional.reset": "すべての回路番号の初期化",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定",
"modal.circuit.trestle.setting.circuit.allocation.passivity.init.info": "선택된 파워 컨디셔너의 회로할당을 초기화합니다.(JA)",
"modal.circuit.trestle.setting.circuit.allocation.passivity.init.setting.info": "회로 할당의 설정을 초기화합니다.(JA)",
"modal.circuit.trestle.setting.step.up.allocation": "昇圧設定", "modal.circuit.trestle.setting.step.up.allocation": "昇圧設定",
"modal.circuit.trestle.setting.step.up.allocation.serial.amount": "シリアル枚数", "modal.circuit.trestle.setting.step.up.allocation.serial.amount": "シリアル枚数",
"modal.circuit.trestle.setting.step.up.allocation.total.amount": "総回路数", "modal.circuit.trestle.setting.step.up.allocation.total.amount": "総回路数",
@ -851,6 +853,7 @@
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to23low": "①길이는 ②+③보다 클 수 없습니다..",
"surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.", "surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.",

View File

@ -155,6 +155,8 @@
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset": "선택된 파워컨디셔너의 회로번호 초기화", "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.all.power.conditional.reset": "모든 회로번호 초기화",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정",
"modal.circuit.trestle.setting.circuit.allocation.passivity.init.info": "선택된 파워 컨디셔너의 회로할당을 초기화합니다.",
"modal.circuit.trestle.setting.circuit.allocation.passivity.init.setting.info": "회로 할당의 설정을 초기화합니다.",
"modal.circuit.trestle.setting.step.up.allocation": "승압 설정", "modal.circuit.trestle.setting.step.up.allocation": "승압 설정",
"modal.circuit.trestle.setting.step.up.allocation.serial.amount": "직렬매수", "modal.circuit.trestle.setting.step.up.allocation.serial.amount": "직렬매수",
"modal.circuit.trestle.setting.step.up.allocation.total.amount": "총 회로수", "modal.circuit.trestle.setting.step.up.allocation.total.amount": "총 회로수",
@ -856,8 +858,11 @@
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to3": "①길이는 ③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to23": "①길이는 ②+③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.1to23low": "②+③길이는 ①보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.", "surface.shape.validate.size.2to3": "②길이는 ③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.3to2": "③길이는 ②보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.", "surface.shape.validate.size.3to4": "③길이는 ④보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.4to3": "④길이는 ③보다 큰 값을 넣어주세요.",
"surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.",
"estimate.detail.header.title": "기본정보", "estimate.detail.header.title": "기본정보",
"estimate.detail.objectNo": "물건번호", "estimate.detail.objectNo": "물건번호",

View File

@ -32,3 +32,8 @@ export const slopeSelector = selectorFamily({
return defaultSlope[degree] return defaultSlope[degree]
}, },
}) })
export const loginUserStore = atom({
key: 'loginUserState',
default: {},
})

View File

@ -4,16 +4,16 @@ export const settingModalFirstOptionsState = atom({
key: 'settingModalFirstOptions', key: 'settingModalFirstOptions',
default: { default: {
option1: [ option1: [
{ id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false }, { id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: true },
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true }, { id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true },
{ id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false }, { id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: true },
{ id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false }, { id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: true },
{ id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: false }, { id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: true },
{ id: 6, column: 'circuitNumDisplay', name: 'modal.canvas.setting.first.option.circuit.num', selected: false }, { id: 6, column: 'circuitNumDisplay', name: 'modal.canvas.setting.first.option.circuit.num', selected: true },
{ id: 7, column: 'flowDisplay', name: 'modal.canvas.setting.first.option.flow', selected: false }, { id: 7, column: 'flowDisplay', name: 'modal.canvas.setting.first.option.flow', selected: true },
{ id: 8, column: 'trestleDisplay', name: 'modal.canvas.setting.first.option.trestle', selected: false }, { id: 8, column: 'trestleDisplay', name: 'modal.canvas.setting.first.option.trestle', selected: true },
{ id: 9, column: 'imageDisplay', name: 'modal.canvas.setting.first.option.image', selected: false }, { id: 9, column: 'imageDisplay', name: 'modal.canvas.setting.first.option.image', selected: false },
{ id: 10, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: false }, { id: 10, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: true },
], ],
dimensionDisplay: [ dimensionDisplay: [
{ {

View File

@ -13,6 +13,7 @@ export const stuffSearchState = atom({
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일 schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일 schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일
code: 'S', code: 'S',
schSaleStoreId: '', //내물건보기 체크용
schSelSaleStoreId: '', //1차판매대리점 선택 schSelSaleStoreId: '', //1차판매대리점 선택
schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택 schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택
startRow: 1, startRow: 1,

View File

@ -244,6 +244,9 @@ table{
&.on{ &.on{
background-color: #272727; background-color: #272727;
} }
&.wrong{
background-color: #7E3434;
}
} }
td{ td{
height: 40px; height: 40px;

View File

@ -1,84 +1,84 @@
.test { .test {
background-color: #797979; background-color: #797979;
font: 30px sans-serif; font: 30px sans-serif;
font-style: italic; font-style: italic;
color: white; color: white;
} }
.grid-container2 { .grid-container2 {
display: grid; display: grid;
grid-template-columns: repeat(2, 1fr); /* 2개의 열 */ grid-template-columns: repeat(2, 1fr); /* 2개의 열 */
grid-template-rows: repeat(6, 30px); /* 6개의 행 */ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
gap: 5px; /* 그리드 아이템 사이의 간격 */ gap: 5px; /* 그리드 아이템 사이의 간격 */
} }
.grid-container3 { .grid-container3 {
display: grid; display: grid;
grid-template-columns: repeat(3, 1fr); /* 3개의 열 */ grid-template-columns: repeat(3, 1fr); /* 3개의 열 */
grid-template-rows: repeat(6, 30px); /* 6개의 행 */ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
gap: 5px; /* 그리드 아이템 사이의 간격 */ gap: 5px; /* 그리드 아이템 사이의 간격 */
} }
.grid-container4 { .grid-container4 {
display: grid; display: grid;
grid-template-columns: repeat(4, 1fr); /* 4개의 열 */ grid-template-columns: repeat(4, 1fr); /* 4개의 열 */
grid-template-rows: repeat(6, 30px); /* 6개의 행 */ grid-template-rows: repeat(6, 30px); /* 6개의 행 */
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
gap: 5px; /* 그리드 아이템 사이의 간격 */ gap: 5px; /* 그리드 아이템 사이의 간격 */
} }
.grid-container5 { .grid-container5 {
display: grid; display: grid;
grid-template-columns: repeat(5, 1fr); /* 5개의 열 */ grid-template-columns: repeat(5, 1fr); /* 5개의 열 */
grid-template-rows: repeat(5, 30px); /* 5개의 행 */ grid-template-rows: repeat(5, 30px); /* 5개의 행 */
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */ justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */ align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
gap: 0px; /* 그리드 아이템 사이의 간격 */ gap: 0px; /* 그리드 아이템 사이의 간격 */
} }
.grid-item { .grid-item {
width: 100%; width: 100%;
height: 100%; height: 100%;
border: 1px solid black; /* 그리드 외각선 */ border: 1px solid black; /* 그리드 외각선 */
text-align: center; /* 그리드 내 가운데 정렬 */ text-align: center; /* 그리드 내 가운데 정렬 */
} }
.grid-item2 { .grid-item2 {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
border: 1px solid #000; border: 1px solid #000;
} }
.grid-item3 { .grid-item3 {
padding: 20px; padding: 20px;
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
border: 1px solid #000; border: 1px solid #000;
transition: background-color 0.3s ease; transition: background-color 0.3s ease;
} }
.grid-item.Y { .grid-item.Y {
background-color: #d3d0d0; background-color: #d3d0d0;
color: black; color: black;
} }
.grid-item.N { .grid-item.N {
background-color: white; background-color: white;
color: black; color: black;
} }
.grid-item.selected { .grid-item.selected {
background-color: #d3d0d0; background-color: #d3d0d0;
color: black; color: black;
} }
.grid-item.unselected { .grid-item.unselected {
background-color: white; background-color: white;
color: black; color: black;
} }