Merge branch 'dev' into feature/jaeyoung

# Conflicts:
#	src/hooks/roofcover/usePropertiesSetting.js
#	src/hooks/roofcover/useRoofShapeSetting.js
#	src/hooks/useMouse.js
This commit is contained in:
Jaeyoung Lee 2025-02-09 14:50:52 +09:00
commit b5f86115e3
100 changed files with 6009 additions and 3905 deletions

View File

@ -1,8 +1,11 @@
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" # NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"

View File

@ -1,8 +1,11 @@
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" # NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin" NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin"

View File

@ -177,8 +177,15 @@ export const SAVE_KEY = [
'moduleRowsTotCnt', 'moduleRowsTotCnt',
'seq', 'seq',
'smartRackId', 'smartRackId',
'directionText',
'quotationParam', 'quotationParam',
'pcses', 'pcses',
'roofMaterial',
'isComplete',
'moduleInfo',
'circuitNumber',
'circuit',
'onlyOffset',
] ]
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

@ -13,6 +13,8 @@ import { QcastContext } from '@/app/QcastProvider'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import BoardDetailModal from './community/modal/BoardDetailModal'
export default function MainPage() { export default function MainPage() {
const [sessionState, setSessionState] = useRecoilState(sessionStore) const [sessionState, setSessionState] = useRecoilState(sessionStore)
const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false) const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false)
@ -79,8 +81,13 @@ export default function MainPage() {
} }
}, [sessionState]) }, [sessionState])
// FAQ
const [open, setOpen] = useState(false)
const [modalNoticeNo, setModalNoticeNo] = useState('')
return ( return (
<> <>
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
{(!chagePasswordPopOpen && ( {(!chagePasswordPopOpen && (
<> <>
<div className="background-bord"></div> <div className="background-bord"></div>
@ -120,7 +127,7 @@ export default function MainPage() {
<button className="search-icon" onClick={handleOnSubmit}></button> <button className="search-icon" onClick={handleOnSubmit}></button>
</div> </div>
</div> </div>
<MainContents /> <MainContents setFaqOpen={setOpen} setFaqModalNoticeNo={setModalNoticeNo} />
</div> </div>
</> </>
)) || ( )) || (

View File

@ -28,6 +28,8 @@ import useSWRMutation from 'swr/mutation'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions' import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions'
import { useRouter } from 'next/navigation'
import { QcastContext } from '@/app/QcastProvider'
export default function Playground() { export default function Playground() {
const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
@ -56,6 +58,13 @@ export default function Playground() {
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const router = useRouter()
const { setIsGlobalLoading } = useContext(QcastContext)
useEffect(() => {
setIsGlobalLoading(false)
}, [])
useEffect(() => { useEffect(() => {
console.log('textInput:', textInput) console.log('textInput:', textInput)
}, [textInput]) }, [textInput])
@ -891,6 +900,19 @@ export default function Playground() {
Test Data insert Test Data insert
</Button> </Button>
</div> </div>
<div className="my-2">
<Button
onClick={() => {
const params = {
pid: 1,
objectNo: 'RT01250131002',
}
router.push(`/floor-plan/estimate/5?pid=${params.pid}&objectNo=${params.objectNo}`)
}}
>
견적서 페이지 이동
</Button>
</div>
</div> </div>
</> </>
) )

View File

@ -1,21 +1,27 @@
'use client' 'use client'
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export default function AutoLoginPage() { export default function AutoLoginPage() {
const [isLoading, setIsLoading] = useState(true)
const { getMessage } = useMessage() const { getMessage } = useMessage()
return ( return (
<div className="login-input-frame"> <>
<div className="login-frame-tit "> {isLoading && <GlobalSpinner />}
<span>{getMessage('site.name')}</span> <div className="login-input-frame">
{getMessage('site.sub_name')} <div className="login-frame-tit ">
</div> <span>{getMessage('site.name')}</span>
<div className="login-input-wrap"> {getMessage('site.sub_name')}
<div className="login-area id" style={{ fontWeight: 'bolder' }}> </div>
{getMessage('login.auto.page.text')} <div className="login-input-wrap">
<div className="login-area id" style={{ fontWeight: 'bolder' }}>
{getMessage('login.auto.page.text')}
</div>
</div> </div>
</div> </div>
</div> </>
) )
} }

View File

@ -10,14 +10,15 @@ 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'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import Cookies from 'js-cookie'
import { useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
import Cookies from 'js-cookie'
import AutoLogin from './AutoLogin' import AutoLogin from './AutoLogin'
export default function Login() { export default function Login() {
const [isLoading, setIsLoading] = useState(false)
// //
const initParams = useSearchParams() const initParams = useSearchParams()
const autoLoginParam = initParams.get('autoLoginParam1') const autoLoginParam = initParams.get('autoLoginParam1')
@ -35,11 +36,13 @@ export default function Login() {
}, []) }, [])
const autoLoginProcess = async (autoLoginParam) => { const autoLoginProcess = async (autoLoginParam) => {
setIsLoading(true)
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) => {
if (res) { if (res) {
if (res.data) { if (res.data) {
post({ url: '/api/login/v1.0/user', data: { loginId: res.data } }).then((response) => { post({ url: '/api/login/v1.0/user', data: { loginId: res.data } }).then((response) => {
setIsLoading(false)
if (response) { if (response) {
const result = { ...response, storeLvl: response.groupId === '60000' ? '1' : '2', pwdInitYn: 'Y' } const result = { ...response, storeLvl: response.groupId === '60000' ? '1' : '2', pwdInitYn: 'Y' }
setSession(result) setSession(result)
@ -53,6 +56,7 @@ export default function Login() {
} }
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false)
router.push('/login') router.push('/login')
}) })
} }
@ -93,9 +97,11 @@ export default function Login() {
loginId: formData.get('id'), loginId: formData.get('id'),
pwd: formData.get('password'), pwd: formData.get('password'),
} }
setIsLoading(true)
await promisePost({ url: '/api/login/v1.0/login', data: param }) await promisePost({ url: '/api/login/v1.0/login', data: param })
.then((res) => { .then((res) => {
if (res) { if (res) {
setIsLoading(false)
if (res.data.result.resultCode === 'S') { if (res.data.result.resultCode === 'S') {
setSession(res.data.data) setSession(res.data.data)
setSessionState(res.data.data) setSessionState(res.data.data)
@ -105,7 +111,6 @@ export default function Login() {
} else { } else {
Cookies.remove('chkLoginId') Cookies.remove('chkLoginId')
} }
// router.push('/')
login() login()
} else { } else {
alert(res.data.result.resultMsg) alert(res.data.result.resultMsg)
@ -113,6 +118,7 @@ export default function Login() {
} }
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false)
alert(error.response.data.message) alert(error.response.data.message)
}) })
} }
@ -123,12 +129,14 @@ export default function Login() {
loginId: checkId, loginId: checkId,
email: checkEmail, email: checkEmail,
} }
setIsLoading(true)
await promisePatch({ await promisePatch({
url: '/api/login/v1.0/user/init-password', url: '/api/login/v1.0/user/init-password',
data: param, data: param,
}) })
.then((res) => { .then((res) => {
if (res) { if (res) {
setIsLoading(false)
if (res.data.result.resultCode == 'S') { if (res.data.result.resultCode == 'S') {
alert(getMessage('login.init_password.complete_message')) alert(getMessage('login.init_password.complete_message'))
setCheckId('') setCheckId('')
@ -140,36 +148,135 @@ export default function Login() {
} }
}) })
.catch((error) => { .catch((error) => {
setIsLoading(false)
alert(error.response.data.message) alert(error.response.data.message)
}) })
} }
return ( return (
<div className="login-wrap"> <>
<div className="login-inner"> {isLoading && <GlobalSpinner />}
<Link href={'/login'} className="login-logo"> <div className="login-wrap">
<Image src="/static/images/main/login-logo.svg" alt="react" width={236} height={43} styles={{ width: '236px', height: '43px' }} priority /> <div className="login-inner">
</Link> <Link href={'/login'} className="login-logo">
{!autoLoginParam && passwordReset === 1 && ( <Image
<> src="/static/images/main/login-logo.svg"
<div className="login-input-frame"> alt="react"
<form onSubmit={loginProcess} className="space-y-6"> width={236}
<div className="login-frame-tit"> height={43}
<span>{getMessage('site.name')}</span> styles={{ width: '236px', height: '43px' }}
{getMessage('site.sub_name')} priority
/>
</Link>
{!autoLoginParam && passwordReset === 1 && (
<>
<div className="login-input-frame">
<form onSubmit={loginProcess} className="space-y-6">
<div className="login-frame-tit">
<span>{getMessage('site.name')}</span>
{getMessage('site.sub_name')}
</div>
<div className="login-input-wrap">
<div className={`login-area id ${idFocus ? 'focus' : ''}`}>
<input
type="text"
className="login-input"
id="userId"
name="id"
required
value={userId}
placeholder={getMessage('login.id.placeholder')}
onChange={(e) => {
setUserId(e.target.value)
}}
onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)}
/>
<button
type="button"
className="id-delete"
onClick={(e) => {
setUserId('')
}}
></button>
</div>
<div className={`login-area password ${secFocus ? 'focus' : ''}`}>
<input
type={passwordVisible ? 'text' : 'password'}
className="login-input"
id="password"
name="password"
required
autoComplete="current-password"
placeholder={getMessage('login.password.placeholder')}
onChange={(e) => {
setPasswordVisible(passwordVisible)
}}
onFocus={() => setSecFocus(true)}
onBlur={() => setSecFocus(false)}
/>
<button
type="button"
className={`password-hidden ${passwordVisible ? 'visible' : ''}`}
onClick={(e) => {
e.preventDefault()
setPasswordVisible(!passwordVisible)
}}
></button>
</div>
<div className="d-check-box login">
<input
type="checkbox"
id="ch01"
name="chkLoginId"
checked={chkLoginId}
onChange={(e) => {
setChkLoginId(e.target.checked)
}}
/>
<label htmlFor="ch01">{getMessage('login.id.save')}</label>
</div>
<div className="login-btn-box">
<button type="submit" className="login-btn">
{getMessage('login')}
</button>
</div>
<div className="reset-password">
<button type="button" onClick={() => setPasswordReset(2)}>
{getMessage('login.init_password.btn')}
</button>
</div>
</div>
</form>
</div>
<div className="login-guide-wrap">
<span></span>
{getMessage('login.guide.text')}
<br />
{getMessage('login.guide.sub1')} <Link href={'../join'}>{getMessage('login.guide.join.btn')}</Link>
{getMessage('login.guide.sub2')}
</div>
</>
)}
{!autoLoginParam && passwordReset === 2 && (
<>
<div className="login-input-frame">
<div className="login-frame-tit pw-reset">
<span>{getMessage('login.init_password.title')}</span>
{getMessage('login.init_password.sub_title')}
</div> </div>
<div className="login-input-wrap"> <div className="login-input-wrap">
<div className={`login-area id ${idFocus ? 'focus' : ''}`}> <div className={`login-area id ${idFocus ? 'focus' : ''}`}>
<input <input
type="text" type="text"
className="login-input" id="checkId"
id="userId" name="checkId"
name="id" value={checkId}
required required
value={userId} className="login-input"
placeholder={getMessage('login.id.placeholder')} placeholder={getMessage('login.init_password.id.placeholder')}
onChange={(e) => { onChange={(e) => {
setUserId(e.target.value) setCheckId(e.target.value)
}} }}
onFocus={() => setIdFocus(true)} onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)} onBlur={() => setIdFocus(false)}
@ -177,146 +284,58 @@ export default function Login() {
<button <button
type="button" type="button"
className="id-delete" className="id-delete"
onClick={(e) => { onClick={() => {
setUserId('') setCheckId('')
}} }}
></button> ></button>
</div> </div>
<div className={`login-area password ${secFocus ? 'focus' : ''}`}> <div className={`login-area email ${secFocus ? 'focus' : ''}`}>
<input <input
type={passwordVisible ? 'text' : 'password'} id="checkEmail"
className="login-input" name="checkEmail"
id="password" type="email"
name="password"
required required
autoComplete="current-password" className="login-input"
placeholder={getMessage('login.password.placeholder')} value={checkEmail}
onChange={(e) => { onChange={(e) => {
setPasswordVisible(passwordVisible) setCheckEmail(e.target.value)
}} }}
placeholder={getMessage('login.init_password.email.placeholder')}
onFocus={() => setSecFocus(true)} onFocus={() => setSecFocus(true)}
onBlur={() => setSecFocus(false)} onBlur={() => setSecFocus(false)}
/> />
<button <button
type="button" type="button"
className={`password-hidden ${passwordVisible ? 'visible' : ''}`} className="id-delete"
onClick={(e) => { onClick={() => {
e.preventDefault() setCheckEmail('')
setPasswordVisible(!passwordVisible)
}} }}
></button> ></button>
</div> </div>
<div className="d-check-box login"> <div className="pwreset-btn-box">
<input <button
type="checkbox" type="button"
id="ch01" className="login-btn light mr5"
name="chkLoginId" onClick={() => {
checked={chkLoginId} setPasswordReset(1)
onChange={(e) => { setCheckEmail('')
setChkLoginId(e.target.checked) setCheckId('')
}} }}
/> >
<label htmlFor="ch01">{getMessage('login.id.save')}</label> {getMessage('login.init_password.btn.back')}
</div>
<div className="login-btn-box">
<button type="submit" className="login-btn">
{getMessage('login')}
</button> </button>
</div> <button type="button" className="login-btn" onClick={initPasswordProcess}>
<div className="reset-password">
<button type="button" onClick={() => setPasswordReset(2)}>
{getMessage('login.init_password.btn')} {getMessage('login.init_password.btn')}
</button> </button>
</div> </div>
</div> </div>
</form>
</div>
<div className="login-guide-wrap">
<span></span>
{getMessage('login.guide.text')}
<br />
{getMessage('login.guide.sub1')} <Link href={'../join'}>{getMessage('login.guide.join.btn')}</Link>
{getMessage('login.guide.sub2')}
</div>
</>
)}
{!autoLoginParam && passwordReset === 2 && (
<>
<div className="login-input-frame">
<div className="login-frame-tit pw-reset">
<span>{getMessage('login.init_password.title')}</span>
{getMessage('login.init_password.sub_title')}
</div> </div>
<div className="login-input-wrap"> </>
<div className={`login-area id ${idFocus ? 'focus' : ''}`}> )}
<input {autoLoginParam && <AutoLogin />}
type="text" </div>
id="checkId" <div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
name="checkId"
value={checkId}
required
className="login-input"
placeholder={getMessage('login.init_password.id.placeholder')}
onChange={(e) => {
setCheckId(e.target.value)
}}
onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)}
/>
<button
type="button"
className="id-delete"
onClick={() => {
setCheckId('')
}}
></button>
</div>
<div className={`login-area email ${secFocus ? 'focus' : ''}`}>
<input
id="checkEmail"
name="checkEmail"
type="email"
required
className="login-input"
value={checkEmail}
onChange={(e) => {
setCheckEmail(e.target.value)
}}
placeholder={getMessage('login.init_password.email.placeholder')}
onFocus={() => setSecFocus(true)}
onBlur={() => setSecFocus(false)}
/>
<button
type="button"
className="id-delete"
onClick={() => {
setCheckEmail('')
}}
></button>
</div>
<div className="pwreset-btn-box">
<button
type="button"
className="login-btn light mr5"
onClick={() => {
setPasswordReset(1)
setCheckEmail('')
setCheckId('')
}}
>
{getMessage('login.init_password.btn.back')}
</button>
<button type="button" className="login-btn" onClick={initPasswordProcess}>
{getMessage('login.init_password.btn')}
</button>
</div>
</div>
</div>
</>
)}
{autoLoginParam && <AutoLogin />}
</div> </div>
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div> </>
</div>
) )
} }

View File

@ -87,25 +87,60 @@ export default function FontSetting(props) {
<div className="font-option-item"> <div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font')}(F)</div> <div className="option-item-tit">{getMessage('modal.font')}(F)</div>
<div className="grid-select"> <div className="grid-select">
<QSelectBox options={fonts} value={selectedFont} onChange={(e) => setSelectedFont(e)} /> <QSelectBox
options={fonts}
value={selectedFont}
onChange={(e) => {
setSelectedFont(e)
}}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div> </div>
</div> </div>
<div className="font-option-item"> <div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.style')}(Y)</div> <div className="option-item-tit">{getMessage('modal.font.style')}(Y)</div>
<div className="grid-select"> <div className="grid-select">
<QSelectBox options={fontOptions} value={selectedFontWeight} onChange={(e) => setSelectedFontWeight(e)} /> <QSelectBox
options={fontOptions}
value={selectedFontWeight}
onChange={(e) => {
setSelectedFontWeight(e)
}}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
</div> </div>
</div> </div>
<div className="font-option-item"> <div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.size')}(S)</div> <div className="option-item-tit">{getMessage('modal.font.size')}(S)</div>
<div className="grid-select"> <div className="grid-select">
<QSelectBox options={fontSizes} value={selectedFontSize} onChange={(e) => setSelectedFontSize(e)} /> <QSelectBox
options={fontSizes}
value={selectedFontSize}
onChange={(e) => setSelectedFontSize(e)}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div> </div>
</div> </div>
<div className="font-option-item"> <div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.color')}</div> <div className="option-item-tit">{getMessage('modal.font.color')}</div>
<div className="grid-select"> <div className="grid-select">
<QSelectBox title={''} options={fontColors} value={selectedFontColor} onChange={(e) => setSelectedFontColor(e)} /> <QSelectBox
title={''}
options={fontColors}
showKey={'name'}
sourceKey={'id'}
targetKey={'id'}
value={selectedFontColor}
onChange={(e) => {
setSelectedFontColor(e)
}}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,6 +1,7 @@
'use client' 'use client'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useOnClickOutside } from 'usehooks-ts' import { useOnClickOutside } from 'usehooks-ts'
import { useMessage } from '@/hooks/useMessage'
/** /**
* *
@ -26,13 +27,15 @@ export default function QSelectBox({
showKey = '', showKey = '',
params = {}, params = {},
}) { }) {
const { getMessage } = useMessage()
/** /**
* 초기 상태 처리 * 초기 상태 처리
* useState 초기 값으로 사용해야 해서 useState 보다 위에 작성 * useState 초기 값으로 사용해야 해서 useState 보다 위에 작성
* @returns {string} 초기 상태 * @returns {string} 초기 상태
*/ */
const handleInitState = () => { const handleInitState = () => {
if (options.length === 0) return title !== '' ? title : '선택하세요.' if (options.length === 0) return title !== '' ? title : getMessage('selectbox.title')
if (showKey !== '' && !value) { if (showKey !== '' && !value) {
//value showKey //value showKey
// return options[0][showKey] // return options[0][showKey]
@ -44,13 +47,13 @@ export default function QSelectBox({
return option[sourceKey] === value[targetKey] return option[sourceKey] === value[targetKey]
}) })
if (!option) { if (!option) {
return title !== '' ? title : '선택하세요.' return title !== '' ? title : getMessage('selectbox.title')
} else { } else {
return option[showKey] return option[showKey]
} }
} else { } else {
// . // .
return title !== '' ? title : '선택하세요.' return title !== '' ? title : getMessage('selectbox.title')
} }
} }

View File

@ -19,10 +19,11 @@ import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from
import ProductFeaturesPop from './popup/ProductFeaturesPop' import ProductFeaturesPop from './popup/ProductFeaturesPop'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { correntObjectNoState } from '@/store/settingAtom' import { correntObjectNoState } from '@/store/settingAtom'
import { useRouter, useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
export default function Estimate({}) { export default function Estimate({}) {
const [uniqueData, setUniqueData] = useState([]) const [uniqueData, setUniqueData] = useState([])
@ -33,6 +34,8 @@ export default function Estimate({}) {
const [objectNo, setObjectNo] = useState('') // const [objectNo, setObjectNo] = useState('') //
const [planNo, setPlanNo] = useState('') // const [planNo, setPlanNo] = useState('') //
const { swalFire } = useSwal()
const [files, setFiles] = useState([]) // const [files, setFiles] = useState([]) //
const [originFiles, setOriginFiles] = useState([]) // const [originFiles, setOriginFiles] = useState([]) //
@ -79,6 +82,7 @@ export default function Estimate({}) {
const [specialNoteList, setSpecialNoteList] = useState([]) const [specialNoteList, setSpecialNoteList] = useState([])
const [popShowSpecialNoteList, setPopShowSpecialNoteList] = useState([]) const [popShowSpecialNoteList, setPopShowSpecialNoteList] = useState([])
const { setIsGlobalLoading } = useContext(QcastContext)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get, post, promisePost } = useAxios(globalLocaleState) const { get, post, promisePost } = useAxios(globalLocaleState)
@ -347,7 +351,11 @@ export default function Estimate({}) {
setEstimateContextState({ setEstimateContextState({
originFiles: originFiles, originFiles: originFiles,
}) })
alert(getMessage('estimate.detail.alert.delFile'))
swalFire({
text: getMessage('estimate.detail.alert.delFile'),
type: 'alert',
})
} }
// option && // option &&
@ -476,10 +484,15 @@ export default function Estimate({}) {
if (!pass) { if (!pass) {
//Pricing . Pricing . //Pricing . Pricing .
return alert(getMessage('estimate.detail.showPrice.pricingBtn.noItemId')) return swalFire({
text: getMessage('estimate.detail.showPrice.pricingBtn.noItemId'),
type: 'alert',
icon: 'warning',
})
} }
} }
setIsGlobalLoading(true)
await promisePost({ url: '/api/estimate/price/item-price-list', data: param }).then((res) => { await promisePost({ url: '/api/estimate/price/item-price-list', data: param }).then((res) => {
let updateList = [] let updateList = []
if (res) { if (res) {
@ -527,6 +540,7 @@ export default function Estimate({}) {
} }
} }
} }
setIsGlobalLoading(false)
}) })
} }
@ -787,7 +801,11 @@ export default function Estimate({}) {
const removeItem = () => { const removeItem = () => {
const array = [...selection] const array = [...selection]
if (isEmptyArray(array)) { if (isEmptyArray(array)) {
return alert(getMessage('estimate.detail.alert.selectDelItem')) return swalFire({
text: getMessage('estimate.detail.alert.selectDelItem'),
type: 'alert',
icon: 'warning',
})
} }
let delList = [] let delList = []
estimateContextState.itemList.filter((row) => { estimateContextState.itemList.filter((row) => {
@ -817,7 +835,11 @@ export default function Estimate({}) {
}) })
if (delCnt === updateList.length) { if (delCnt === updateList.length) {
return alert(getMessage('estimate.detail.save.requiredItem')) return swalFire({
text: getMessage('estimate.detail.save.requiredItem'),
type: 'alert',
icon: 'warning',
})
} }
setEstimateContextState({ setEstimateContextState({
@ -1188,7 +1210,7 @@ export default function Estimate({}) {
<input <input
type="text" type="text"
className="input-light" className="input-light"
value={estimateContextState?.charger} value={estimateContextState?.charger || ''}
onBlur={handleBlurCharger} onBlur={handleBlurCharger}
onChange={handleBlurCharger} onChange={handleBlurCharger}
/> />
@ -1206,7 +1228,7 @@ export default function Estimate({}) {
<input <input
type="text" type="text"
className="input-light" className="input-light"
value={estimateContextState?.objectName} value={estimateContextState?.objectName || ''}
onBlur={handleBlurObjectName} onBlur={handleBlurObjectName}
onChange={handleBlurObjectName} onChange={handleBlurObjectName}
/> />
@ -1297,13 +1319,13 @@ export default function Estimate({}) {
// //
let constructSpecificationMulti = estimateContextState?.constructSpecificationMulti?.split('、') let constructSpecificationMulti = estimateContextState?.constructSpecificationMulti?.split('、')
return ( return (
<div className={`form-flex-wrap ${style}`} key={`roof_${row}`}> <div className={`form-flex-wrap ${style}`} key={`roof_${index}_${row}`}>
<div className="input-wrap mr5" style={{ width: '610px' }}> <div className="input-wrap mr5" style={{ width: '610px' }}>
<input type="text" className="input-light" value={roofList} readOnly /> <input type="text" className="input-light" value={roofList || ''} readOnly />
</div> </div>
{constructSpecificationMulti ? ( {constructSpecificationMulti ? (
<div className="input-wrap" style={{ width: '200px' }}> <div className="input-wrap" style={{ width: '200px' }}>
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly /> <input type="text" className="input-light" value={constructSpecificationMulti[index] || ''} readOnly />
</div> </div>
) : null} ) : null}
</div> </div>
@ -1316,7 +1338,6 @@ export default function Estimate({}) {
<th>{getMessage('estimate.detail.remarks')}</th> <th>{getMessage('estimate.detail.remarks')}</th>
<td colSpan={3}> <td colSpan={3}>
<div className="input-wrap"> <div className="input-wrap">
{/* <input type="text" className="input-light" defaultValue={estimateContextState?.remarks || ''} onBlur={handleBlurRemarks} /> */}
<input <input
type="text" type="text"
className="input-light" className="input-light"
@ -1366,6 +1387,9 @@ export default function Estimate({}) {
{getMessage('estimate.detail.fileFlg')} {getMessage('estimate.detail.fileFlg')}
</label> </label>
</div> </div>
{estimateContextState?.northArrangement === '1' && (
<div className="drag-file-guide">{getMessage('estimate.detail.dragFileGuide')}</div>
)}
</div> </div>
</div> </div>
<div className="common-table mb10"> <div className="common-table mb10">

View File

@ -4,20 +4,21 @@ import { useMessage } from '@/hooks/useMessage'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { floorPlanObjectState, estimateState } from '@/store/floorPlanObjectAtom' import { floorPlanObjectState, estimateState } from '@/store/floorPlanObjectAtom'
import { usePathname } from 'next/navigation' import { usePathname, useSearchParams } from 'next/navigation'
export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDownPopLockFlg }) { export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDownPopLockFlg }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { promisePost } = useAxios() const { promisePost } = useAxios()
const pathName = usePathname() const pathName = usePathname()
const searchParams = useSearchParams()
//EXCEL, PDF //EXCEL, PDF
const [schDownload, setSchDownload] = useState('EXCEL') const [schDownload, setSchDownload] = useState('EXCEL')
// EXCEL // EXCEL
const [schUnitPriceFlg, setSchUnitPriceFlg] = useState('0') const [schUnitPriceFlg, setSchUnitPriceFlg] = useState('0')
// //
const [schDisplayFlg, setSchSchDisplayFlg] = useState('0') const [schDisplayFlg, setSchDisplayFlg] = useState('0')
// (:1 : 0) // (:1 : 0)
const [schWeightFlg, setSchWeightFlg] = useState('1') const [schWeightFlg, setSchWeightFlg] = useState('1')
/// ///
@ -53,8 +54,9 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
defaultSchDrawingFlg = defaultSchDrawingFlg.concat('|', '2', '|', '3') defaultSchDrawingFlg = defaultSchDrawingFlg.concat('|', '2', '|', '3')
} }
//objectRecoil.floorPlanObjectNo url
const params = { const params = {
objectNo: objectRecoil.floorPlanObjectNo, objectNo: objectRecoil?.floorPlanObjectNo ? objectRecoil.floorPlanObjectNo : searchParams.get('objectNo'),
planNo: planNo, planNo: planNo,
schDownload: schDownload, schDownload: schDownload,
schUnitPriceFlg: sendUnitPriceFlg, schUnitPriceFlg: sendUnitPriceFlg,
@ -206,7 +208,7 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
value={'0'} value={'0'}
checked={schDisplayFlg === '0'} checked={schDisplayFlg === '0'}
onChange={(e) => { onChange={(e) => {
setSchSchDisplayFlg(e.target.value) setSchDisplayFlg(e.target.value)
}} }}
/> />
<label htmlFor="schDisplayFlg0">{getMessage('estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0')}</label> <label htmlFor="schDisplayFlg0">{getMessage('estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0')}</label>
@ -219,7 +221,7 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
value={'1'} value={'1'}
checked={schDisplayFlg === '1'} checked={schDisplayFlg === '1'}
onChange={(e) => { onChange={(e) => {
setSchSchDisplayFlg(e.target.value) setSchDisplayFlg(e.target.value)
}} }}
/> />
<label htmlFor="schDisplayFlg1">{getMessage('estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1')}</label> <label htmlFor="schDisplayFlg1">{getMessage('estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1')}</label>

View File

@ -69,7 +69,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
res.map((row) => { res.map((row) => {
row.value == row.saleStoreId row.value = row.saleStoreId
row.label = row.saleStoreName row.label = row.saleStoreName
}) })
otherList = res otherList = res

View File

@ -7,16 +7,16 @@ export default function ProductFeaturesPop({ popShowSpecialNoteList, showProduct
useEffect(() => { useEffect(() => {
let pushData = [] let pushData = []
popShowSpecialNoteList.map((row) => { popShowSpecialNoteList.forEach((row) => {
let option = showProductFeatureData.split('、') let option = showProductFeatureData.split('、')
option.map((row2) => { option.forEach((row2) => {
if (row.code === row2) { if (row.code === row2) {
pushData.push(row) pushData.push(row)
} }
}) })
}) })
setShowSpecialNoteList(pushData) setShowSpecialNoteList(pushData)
}, [popShowSpecialNoteList]) }, [popShowSpecialNoteList, showProductFeatureData])
return ( return (
<div className="modal-popup"> <div className="modal-popup">

View File

@ -249,6 +249,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
}, },
addLengthText() { addLengthText() {
if ([POLYGON_TYPE.MODULE, 'arrow', POLYGON_TYPE.MODULE_SETUP_SURFACE, POLYGON_TYPE.OBJECT_SURFACE].includes(this.name)) {
return
}
this.canvas this.canvas
?.getObjects() ?.getObjects()
.filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id) .filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id)

View File

@ -16,7 +16,16 @@ 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' import {
makersState,
modelsState,
moduleStatisticsState,
pcsCheckState,
selectedMakerState,
selectedModelsState,
seriesState,
} from '@/store/circuitTrestleAtom'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
export default function CanvasFrame() { export default function CanvasFrame() {
const canvasRef = useRef(null) const canvasRef = useRef(null)
@ -25,33 +34,59 @@ export default function CanvasFrame() {
const currentMenu = useRecoilValue(currentMenuState) const currentMenu = useRecoilValue(currentMenuState)
const { floorPlanState } = useContext(FloorPlanContext) const { floorPlanState } = useContext(FloorPlanContext)
const { contextMenu, handleClick } = useContextMenu() const { contextMenu, handleClick } = useContextMenu()
const { currentCanvasPlan } = usePlan() const { plans, currentCanvasPlan, resetCanvasStatus } = usePlan()
const totalDisplay = useRecoilValue(totalDisplaySelector) // const totalDisplay = useRecoilValue(totalDisplaySelector) //
const { setIsGlobalLoading } = useContext(QcastContext) const { setIsGlobalLoading } = useContext(QcastContext)
const [moduleStatistics, setModuleStatistics] = useRecoilState(moduleStatisticsState) const resetModuleStatisticsState = useResetRecoilState(moduleStatisticsState)
const reset = useResetRecoilState(moduleStatisticsState) const resetMakersState = useResetRecoilState(makersState)
const resetSelectedMakerState = useResetRecoilState(selectedMakerState)
const resetSeriesState = useResetRecoilState(seriesState)
const resetModelsState = useResetRecoilState(modelsState)
const resetSelectedModelsState = useResetRecoilState(selectedModelsState)
const resetPcsCheckState = useResetRecoilState(pcsCheckState)
const { handleModuleSelectionTotal } = useCanvasPopupStatusController()
const loadCanvas = () => { const loadCanvas = () => {
if (canvas) { if (!canvas) return
canvas?.clear() // .
if (currentCanvasPlan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) { canvas?.clear() // .
canvas?.loadFromJSON(JSON.parse(currentCanvasPlan.canvasStatus), function () { if (currentCanvasPlan) {
const plan = plans.find((plan) => plan.id === currentCanvasPlan.id)
if (plan?.canvasStatus && floorPlanState.objectNo === currentCanvasPlan.objectNo) {
canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () {
canvasLoadInit() //config canvasLoadInit() //config
canvas?.renderAll() // . canvas?.renderAll() // .
}) })
} }
gridInit()
} }
gridInit()
} }
useEffect(() => { useEffect(() => {
loadCanvas() loadCanvas()
reset() resetRecoilData()
Object.keys(currentCanvasPlan).length > 0 && handleModuleSelectionTotal()
}, [currentCanvasPlan, canvas]) }, [currentCanvasPlan, canvas])
useEffect(() => { useEffect(() => {
setIsGlobalLoading(false) setIsGlobalLoading(false)
return () => {
canvas?.clear()
resetCanvasStatus()
}
}, []) }, [])
const resetRecoilData = () => {
resetModuleStatisticsState()
resetMakersState()
resetSelectedMakerState()
resetSeriesState()
resetModelsState()
resetSelectedModelsState()
resetPcsCheckState()
}
return ( return (
<div className="canvas-frame"> <div className="canvas-frame">
<canvas ref={canvasRef} id="canvas" style={{ position: 'relative' }}></canvas> <canvas ref={canvasRef} id="canvas" style={{ position: 'relative' }}></canvas>

View File

@ -1,6 +1,7 @@
'use client' 'use client'
import { useContext, useEffect } from 'react' import { useContext, useEffect } from 'react'
import { usePathname } from 'next/navigation'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { SessionContext } from '@/app/SessionProvider' import { SessionContext } from '@/app/SessionProvider'
@ -12,6 +13,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
export default function CanvasLayout({ children }) { export default function CanvasLayout({ children }) {
// const { menuNumber } = props // const { menuNumber } = props
const pathname = usePathname()
const { menuNumber } = useCanvasMenu() const { menuNumber } = useCanvasMenu()
const { session } = useContext(SessionContext) const { session } = useContext(SessionContext)
const { floorPlanState } = useContext(FloorPlanContext) const { floorPlanState } = useContext(FloorPlanContext)
@ -37,10 +39,12 @@ export default function CanvasLayout({ children }) {
onClick={() => handleCurrentPlan(plan.id)} onClick={() => handleCurrentPlan(plan.id)}
> >
<span>{`Plan ${plan.planNo}`}</span> <span>{`Plan ${plan.planNo}`}</span>
{index !== 0 && ( {index !== 0 && !pathname.includes('/estimate') && !pathname.includes('/simulator') && (
<i <i
className="close" className="close"
onClick={(e) => onClick={(e) => {
// handleCurrentPlan
e.stopPropagation()
swalFire({ swalFire({
text: `Plan ${plan.planNo} ` + getMessage('plan.message.confirm.delete'), text: `Plan ${plan.planNo} ` + getMessage('plan.message.confirm.delete'),
type: 'confirm', type: 'confirm',
@ -48,13 +52,13 @@ export default function CanvasLayout({ children }) {
handleDeletePlan(e, plan) handleDeletePlan(e, plan)
}, },
}) })
} }}
></i> ></i>
)} )}
</button> </button>
))} ))}
</div> </div>
{plans.length < 10 && ( {plans.length < 10 && !pathname.includes('/estimate') && !pathname.includes('/simulator') && (
<button <button
className="plane-add" className="plane-add"
onClick={async () => { onClick={async () => {

View File

@ -25,26 +25,29 @@ import { useCommonUtils } from '@/hooks/common/useCommonUtils'
import useMenu from '@/hooks/common/useMenu' import useMenu from '@/hooks/common/useMenu'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom' import { canvasSettingState, canvasState, canvasZoomState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
import { addedRoofsState, basicSettingState, selectedRoofMaterialSelector, settingModalFirstOptionsState } from '@/store/settingAtom' import {
addedRoofsState,
basicSettingState,
corridorDimensionSelector,
selectedRoofMaterialSelector,
settingModalFirstOptionsState,
} from '@/store/settingAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import { commonUtilsState } from '@/store/commonUtilsAtom' import { commonUtilsState } from '@/store/commonUtilsAtom'
import { menusState, menuTypeState } from '@/store/menuAtom' import { menusState, menuTypeState } from '@/store/menuAtom'
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { pwrGnrSimTypeState } from '@/store/simulatorAtom' import { pwrGnrSimTypeState } from '@/store/simulatorAtom'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import { POLYGON_TYPE } from '@/common/common'
import KO from '@/locales/ko.json' import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json' import JA from '@/locales/ja.json'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
export default function CanvasMenu(props) { export default function CanvasMenu(props) {
const { menuNumber, setMenuNumber } = props const { menuNumber, setMenuNumber } = props
const pathname = usePathname() const pathname = usePathname()
@ -71,7 +74,7 @@ export default function CanvasMenu(props) {
const [estimateCopyPopupOpen, setEstimateCopyPopupOpen] = useState(false) const [estimateCopyPopupOpen, setEstimateCopyPopupOpen] = useState(false)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { saveCanvas } = usePlan() const { saveCanvas, reloadCanvasStatus } = usePlan()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent() const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
// const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useContext(EventContext) // const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useContext(EventContext)
@ -109,13 +112,14 @@ export default function CanvasMenu(props) {
const params = { const params = {
objectNo: objectNo, objectNo: objectNo,
planNo: pid, planNo: selectedPlan.planNo,
schDownload: donwloadType, schDownload: donwloadType,
schDrawingFlg: drawingFlg, schDrawingFlg: drawingFlg,
pwrGnrSimType: pwrGnrSimTypeRecoil.type, pwrGnrSimType: pwrGnrSimTypeRecoil.type,
} }
const options = { responseType: 'blob' } const options = { responseType: 'blob' }
setIsGlobalLoading(true)
await promisePost({ url: url, data: params, option: options }) await promisePost({ url: url, data: params, option: options })
.then((resultData) => { .then((resultData) => {
if (resultData) { if (resultData) {
@ -142,15 +146,17 @@ export default function CanvasMenu(props) {
.catch((error) => { .catch((error) => {
alert('File does not exist.') alert('File does not exist.')
}) })
setIsGlobalLoading(false)
} }
const onClickNav = (menu) => { const onClickNav = async (menu) => {
switch (menu.index) { switch (menu.index) {
case 0: case 0:
swalFire({ swalFire({
text: getMessage('stuff.detail.move.confirmMsg'), text: getMessage('stuff.detail.move.confirmMsg'),
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
setIsGlobalLoading(true)
router.push(`/management/stuff/detail?objectNo=${objectNo}`, { scroll: false }) router.push(`/management/stuff/detail?objectNo=${objectNo}`, { scroll: false })
}, },
}) })
@ -158,47 +164,88 @@ export default function CanvasMenu(props) {
case 1: case 1:
setType('placementShape') setType('placementShape')
onClickPlacementInitialMenu() onClickPlacementInitialMenu()
await reloadCanvasStatus(objectNo, pid)
break break
case 2: case 2:
setType('outline') setType('outline')
await reloadCanvasStatus(objectNo, pid)
break break
case 3: case 3:
setType('surface') console.log('🚀 ~ onClickNav ~ menu:', menu)
console.log('🚀 ~ onClickNav ~ menuNumber:', menuNumber)
if (menuNumber > menu.index) {
const modules = canvas.getObjects().filter((module) => module.name === POLYGON_TYPE.MODULE)
if (modules.length > 0) {
swalFire({
text: getMessage('module.delete.confirm'),
type: 'confirm',
confirmFn: () => {
//
const moduleSurfacesArray = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.MODULE)
if (moduleSurfacesArray.length > 0) {
moduleSurfacesArray.forEach((moduleSurface) => {
canvas.remove(moduleSurface)
})
canvas.renderAll()
}
setType('surface')
},
denyFn: () => {
setType('surface')
},
})
}
} else {
setType('surface')
}
await reloadCanvasStatus(objectNo, pid)
break break
case 4: case 4:
if (!checkMenuAndCanvasState()) { if (menuNumber < menu.index) {
swalFire({ text: getMessage('menu.validation.canvas.roof') }) if (!checkMenuAndCanvasState()) {
return swalFire({ text: getMessage('menu.validation.canvas.roof') })
return
} else {
setType('module')
}
} else { } else {
setType('module') router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
} }
await reloadCanvasStatus(objectNo, pid)
break break
case 5: case 5:
// let pid = urlParams.get('pid') setIsGlobalLoading(true)
// (useEstimateController.js) setIsGlobalLoading(false)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => { promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) { if (res.status === 200) {
const estimateDetail = res.data const estimateDetail = res.data
if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) { // if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) {
if (estimateDetail.estimateDate !== null) {
setMenuNumber(menu.index) setMenuNumber(menu.index)
setCurrentMenu(menu.title) setCurrentMenu(menu.title)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
router.push(`/floor-plan/estimate/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`) router.push(`/floor-plan/estimate/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
} else { } else {
setIsGlobalLoading(false)
swalFire({ text: getMessage('estimate.menu.move.valid1') }) swalFire({ text: getMessage('estimate.menu.move.valid1') })
} }
} }
}) })
break break
case 6: case 6:
setIsGlobalLoading(true)
// (Simulator.jsx) setIsGlobalLoading(false)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => { promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) { if (res.status === 200) {
const estimateDetail = res.data const estimateDetail = res.data
if (estimateDetail.tempFlg === '0') { if (estimateDetail.estimateDate !== null) {
setMenuNumber(menu.index) setMenuNumber(menu.index)
setCurrentMenu(menu.title) setCurrentMenu(menu.title)
router.push(`/floor-plan/simulator/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`) router.push(`/floor-plan/simulator/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
} else { } else {
setIsGlobalLoading(false)
swalFire({ text: getMessage('simulator.menu.move.valid1') }) swalFire({ text: getMessage('simulator.menu.move.valid1') })
} }
} }
@ -210,9 +257,10 @@ export default function CanvasMenu(props) {
setMenuNumber(menu.index) setMenuNumber(menu.index)
setCurrentMenu(menu.title) setCurrentMenu(menu.title)
} }
if (pathname !== '/floor-plan') { if (pathname !== '/floor-plan') {
if (menu.index !== 0) { // if (menu.index !== 0 ) {
// or ..
if (menu.index !== 0 && menu.index !== 5 && menu.index !== 6) {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`) router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
} }
} }
@ -238,11 +286,21 @@ export default function CanvasMenu(props) {
if (menuNumber === 1) { if (menuNumber === 1) {
onClickPlacementInitialMenu() onClickPlacementInitialMenu()
} }
if (menuNumber === 3) {
const moduleSurfacesArray = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
if (moduleSurfacesArray.length > 0) {
moduleSurfacesArray.forEach((moduleSurface) => {
moduleSurface.modules = []
canvas.remove(moduleSurface)
})
canvas.renderAll()
}
}
}, [menuNumber, type]) }, [menuNumber, type])
// (btn08) // (btn08)
const handleSaveCanvas = async () => { const handleSaveCanvas = async () => {
await saveCanvas() await saveCanvas(true)
} }
// //
@ -297,15 +355,15 @@ export default function CanvasMenu(props) {
confirmFn: async () => { confirmFn: async () => {
setIsGlobalLoading(true) setIsGlobalLoading(true)
const params = { const params = {
objectNo: objectNo, objectNo: estimateRecoilState.objectNo,
planNo: pid, planNo: estimateRecoilState.planNo,
userId: sessionState.userId, userId: sessionState.userId,
} }
try { try {
await promisePost({ url: '/api/estimate/reset-estimate', data: params }).then((res) => { await promisePost({ url: '/api/estimate/reset-estimate', data: params }).then((res) => {
if (res.status === 201) { if (res.status === 201) {
swalFire({ text: getMessage('estimate.detail.reset.alertMsg'), type: 'alert' }) swalFire({ text: getMessage('estimate.detail.reset.alertMsg'), type: 'alert' })
fetchSetting(objectNo, pid, 'R') fetchSetting(estimateRecoilState.objectNo, estimateRecoilState.planNo, 'R')
} }
}) })
} catch (error) { } catch (error) {
@ -344,9 +402,14 @@ export default function CanvasMenu(props) {
}, [basicSetting])*/ }, [basicSetting])*/
const checkMenuState = (menu) => { const checkMenuState = (menu) => {
return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2) return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && [1, 2].includes(menu.index))
} }
/**
* 모듈, 회로 구성 이전 메뉴에서 메뉴 클릭으로 넘어올때
* 지붕면 할당이 끝난 지붕이 하나라도 있는지 체크
* @returns {boolean}
*/
const checkMenuAndCanvasState = () => { const checkMenuAndCanvasState = () => {
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
// //
@ -357,40 +420,109 @@ export default function CanvasMenu(props) {
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(estimateRecoilState)) { if (isObjectNotEmpty(estimateRecoilState)) {
if (estimateRecoilState?.createUser === 'T01') { const { createUser, tempFlg, lockFlg } = estimateRecoilState
if (sessionState.userId !== 'T01') {
setButtonStyle1('none') if (createUser && tempFlg && lockFlg) {
setButtonStyle2('none') if (createUser === 'T01') {
setButtonStyle3('none') if (sessionState.storeId !== 'T01') {
setButtonStyle4('none') setAllButtonStyles('none')
setButtonStyle5('none')
}
} else {
if (estimateRecoilState?.tempFlg === '1') {
setButtonStyle1('none')
setButtonStyle2('')
setButtonStyle3('none')
setButtonStyle4('none')
setButtonStyle5('none')
} else {
if (estimateRecoilState?.tempFlg === '0' && estimateRecoilState?.lockFlg === '0') {
setButtonStyle1('')
setButtonStyle2('')
setButtonStyle3('')
setButtonStyle4('')
setButtonStyle5('')
} else { } else {
setButtonStyle1('') handleButtonStyles(tempFlg, lockFlg)
setButtonStyle2('none')
setButtonStyle3('none')
setButtonStyle4('')
setButtonStyle5('')
} }
} else {
handleButtonStyles(tempFlg, lockFlg)
} }
} }
} }
}, [estimateRecoilState]) }, [estimateRecoilState])
const setAllButtonStyles = (style) => {
setButtonStyle1(style)
setButtonStyle2(style)
setButtonStyle3(style)
setButtonStyle4(style)
setButtonStyle5(style)
}
const handleButtonStyles = (tempFlg, lockFlg) => {
if (tempFlg === '1') {
setAllButtonStyles('none')
setButtonStyle2('')
} else if (tempFlg === '0' && lockFlg === '0') {
setAllButtonStyles('')
} else {
setButtonStyle1('')
setButtonStyle2('none')
setButtonStyle3('none')
setButtonStyle4('')
setButtonStyle5('')
}
}
// useEffect(() => {
// if (isObjectNotEmpty(estimateRecoilState)) {
// if (estimateRecoilState?.createUser && estimateRecoilState?.tempFlg && estimateRecoilState.lockFlg) {
// if (estimateRecoilState?.createUser === 'T01') {
// if (sessionState.storeId !== 'T01') {
// setButtonStyle1('none')
// setButtonStyle2('none')
// setButtonStyle3('none')
// setButtonStyle4('none')
// setButtonStyle5('none')
// } else {
// if (estimateRecoilState?.tempFlg === '1') {
// setButtonStyle1('none')
// setButtonStyle2('')
// setButtonStyle3('none')
// setButtonStyle4('none')
// setButtonStyle5('none')
// } else {
// if (estimateRecoilState?.tempFlg === '0' && estimateRecoilState?.lockFlg === '0') {
// setButtonStyle1('')
// setButtonStyle2('')
// setButtonStyle3('')
// setButtonStyle4('')
// setButtonStyle5('')
// } else {
// setButtonStyle1('')
// setButtonStyle2('none')
// setButtonStyle3('none')
// setButtonStyle4('')
// setButtonStyle5('')
// }
// }
// }
// } else {
// if (isObjectNotEmpty(estimateRecoilState)) {
// if (estimateRecoilState?.tempFlg && estimateRecoilState.lockFlg) {
// if (estimateRecoilState?.tempFlg === '1') {
// setButtonStyle1('none')
// setButtonStyle2('')
// setButtonStyle3('none')
// setButtonStyle4('none')
// setButtonStyle5('none')
// } else {
// if (estimateRecoilState?.tempFlg === '0' && estimateRecoilState?.lockFlg === '0') {
// setButtonStyle1('')
// setButtonStyle2('')
// setButtonStyle3('')
// setButtonStyle4('')
// setButtonStyle5('')
// } else {
// setButtonStyle1('')
// setButtonStyle2('none')
// setButtonStyle3('none')
// setButtonStyle4('')
// setButtonStyle5('')
// }
// }
// }
// }
// }
// }
// }
// }, [estimateRecoilState])
/** /**
* 견적서 잠금 / 해제 * 견적서 잠금 / 해제
* lockFlg : 0 잠금해제상태 / 1 잠금상태 * lockFlg : 0 잠금해제상태 / 1 잠금상태
@ -400,7 +532,6 @@ export default function CanvasMenu(props) {
*/ */
const handleEstimateLockController = (estimateRecoilState) => { const handleEstimateLockController = (estimateRecoilState) => {
swalFire({ swalFire({
// text: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'),
html: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'), html: estimateRecoilState.lockFlg === '0' ? getMessage('estimate.detail.lock.alertMsg') : getMessage('estimate.detail.unlock.alertMsg'),
confirmButtonText: estimateRecoilState.lockFlg === '1' ? getMessage('estimate.detail.unlock.confirmBtnName') : '', confirmButtonText: estimateRecoilState.lockFlg === '1' ? getMessage('estimate.detail.unlock.confirmBtnName') : '',
type: 'confirm', type: 'confirm',
@ -416,37 +547,49 @@ export default function CanvasMenu(props) {
await promisePost({ url: '/api/estimate/save-estimate-lock', data: params }).then((res) => { await promisePost({ url: '/api/estimate/save-estimate-lock', data: params }).then((res) => {
if (res.status === 201) { if (res.status === 201) {
estimateRecoilState.lockFlg = estimateRecoilState.lockFlg === '0' ? '1' : '0' estimateRecoilState.lockFlg = estimateRecoilState.lockFlg === '0' ? '1' : '0'
if (estimateRecoilState?.createUser === 'T01') { const { createUser, tempFlg, lockFlg } = estimateRecoilState
if (sessionState.userId !== 'T01') { if (createUser && tempFlg && lockFlg) {
setButtonStyle1('none') if (createUser === 'T01') {
setButtonStyle2('none') if (sessionState.storeId !== 'T01') {
setButtonStyle3('none') setAllButtonStyles('none')
setButtonStyle4('none')
setButtonStyle5('none')
}
} else {
if (estimateRecoilState?.tempFlg === '1') {
setButtonStyle1('none')
setButtonStyle2('')
setButtonStyle3('none')
setButtonStyle4('none')
setButtonStyle5('none')
} else {
if (estimateRecoilState?.tempFlg === '0' && estimateRecoilState?.lockFlg === '0') {
setButtonStyle1('')
setButtonStyle2('')
setButtonStyle3('')
setButtonStyle4('')
setButtonStyle5('')
} else { } else {
setButtonStyle1('') handleButtonStyles(tempFlg, lockFlg)
setButtonStyle2('none')
setButtonStyle3('none')
setButtonStyle4('')
setButtonStyle5('')
} }
} else {
handleButtonStyles(tempFlg, lockFlg)
} }
} }
// if (estimateRecoilState?.createUser === 'T01') {
// if (sessionState.storeId !== 'T01') {
// setButtonStyle1('none')
// setButtonStyle2('none')
// setButtonStyle3('none')
// setButtonStyle4('none')
// setButtonStyle5('none')
// }
// } else {
// if (estimateRecoilState?.tempFlg === '1') {
// setButtonStyle1('none')
// setButtonStyle2('')
// setButtonStyle3('none')
// setButtonStyle4('none')
// setButtonStyle5('none')
// } else {
// if (estimateRecoilState?.tempFlg === '0' && estimateRecoilState?.lockFlg === '0') {
// setButtonStyle1('')
// setButtonStyle2('')
// setButtonStyle3('')
// setButtonStyle4('')
// setButtonStyle5('')
// } else {
// setButtonStyle1('')
// setButtonStyle2('none')
// setButtonStyle3('none')
// setButtonStyle4('')
// setButtonStyle5('')
// }
// }
// }
} }
setIsGlobalLoading(false) setIsGlobalLoading(false)
}) })
@ -476,10 +619,10 @@ export default function CanvasMenu(props) {
<li <li
key={`canvas-menu-${menu.index}`} key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`} className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => { onClick={async () => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) return if (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) return
if (menuNumber === 4 && menu.index === 2) return if (menuNumber === 4 && [1, 2].includes(menu.index)) return
onClickNav(menu) await onClickNav(menu)
}} }}
> >
<button className={checkMenuState(menu) ? 'no-click' : ''}> <button className={checkMenuState(menu) ? 'no-click' : ''}>
@ -508,8 +651,12 @@ export default function CanvasMenu(props) {
<div className="select-box"> <div className="select-box">
{ {
<QSelectBox <QSelectBox
showKey={'roofMatlNm'} //options={addedRoofs}
options={addedRoofs} options={addedRoofs.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp }
})}
//showKey={'roofMatlNm'}
showKey={'name'}
value={selectedRoofMaterial} value={selectedRoofMaterial}
onChange={changeSelectedRoofMaterial} onChange={changeSelectedRoofMaterial}
sourceKey={'index'} sourceKey={'index'}
@ -553,20 +700,17 @@ export default function CanvasMenu(props) {
{menuNumber === 5 && ( {menuNumber === 5 && (
<> <>
<div className="ico-btn-from"> <div className="ico-btn-from">
{/* <button className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}> */}
<button type="button" style={{ display: buttonStyle1 }} className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}> <button type="button" style={{ display: buttonStyle1 }} className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}>
<span className="ico ico01"></span> <span className="ico ico01"></span>
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span> <span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
</button> </button>
<button type="button" style={{ display: buttonStyle2 }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}> <button type="button" style={{ display: buttonStyle2 }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
{/* <button type="button" style={{ display: buttonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}> */}
<span className="ico ico02"></span> <span className="ico ico02"></span>
<span className="name">{getMessage('plan.menu.estimate.save')}</span> <span className="name">{getMessage('plan.menu.estimate.save')}</span>
</button> </button>
<button <button
type="button" type="button"
style={{ display: buttonStyle3 }} style={{ display: buttonStyle3 }}
// style={{ display: buttonStyle }}
className="btn-frame gray ico-flx" className="btn-frame gray ico-flx"
onClick={() => { onClick={() => {
handleEstimateReset() handleEstimateReset()
@ -580,7 +724,6 @@ export default function CanvasMenu(props) {
<button <button
type="button" type="button"
style={{ display: buttonStyle4 }} style={{ display: buttonStyle4 }}
// style={{ display: buttonStyle }}
className="btn-frame gray ico-flx" className="btn-frame gray ico-flx"
onClick={() => { onClick={() => {
setEstimateCopyPopupOpen(true) setEstimateCopyPopupOpen(true)
@ -593,10 +736,8 @@ export default function CanvasMenu(props) {
<button <button
type="button" type="button"
style={{ display: buttonStyle5 }} style={{ display: buttonStyle5 }}
// style={{ display: buttonStyle }}
className="btn-frame gray ico-flx" className="btn-frame gray ico-flx"
onClick={() => { onClick={() => {
//
handleEstimateLockController(estimateRecoilState) handleEstimateLockController(estimateRecoilState)
}} }}
> >

View File

@ -7,8 +7,9 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import '@/styles/contents.scss' import '@/styles/contents.scss'
import { notFound, useSearchParams } from 'next/navigation' import { notFound, useSearchParams } from 'next/navigation'
import { useRecoilState } from 'recoil' import { useRecoilState, useResetRecoilState } from 'recoil'
import { correntObjectNoState } from '@/store/settingAtom' import { correntObjectNoState } from '@/store/settingAtom'
import { currentMenuState } from '@/store/canvasAtom'
export default function FloorPlan({ children }) { export default function FloorPlan({ children }) {
const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState) const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState)
@ -19,6 +20,12 @@ export default function FloorPlan({ children }) {
const { closeAll } = usePopup() const { closeAll } = usePopup()
const { menuNumber, setMenuNumber } = useCanvasMenu() const { menuNumber, setMenuNumber } = useCanvasMenu()
const { fetchSettings, fetchBasicSettings } = useCanvasSetting() const { fetchSettings, fetchBasicSettings } = useCanvasSetting()
const resetCurrentMenu = useResetRecoilState(currentMenuState)
useEffect(() => {
return () => {
resetCurrentMenu()
}
}, [])
// URL objectNo // URL objectNo
useEffect(() => { useEffect(() => {
@ -32,8 +39,8 @@ export default function FloorPlan({ children }) {
useEffect(() => { useEffect(() => {
if (!correntObjectNo) return // correntObjectNo if (!correntObjectNo) return // correntObjectNo
if(menuNumber === null) { if (menuNumber === null) {
setMenuNumber(1) //setMenuNumber(1)
} }
fetchSettings() fetchSettings()
fetchBasicSettings() fetchBasicSettings()

View File

@ -26,7 +26,7 @@ export default function MenuDepth01() {
useEffect(() => { useEffect(() => {
handleMenu(type) handleMenu(type)
canvas.discardActiveObject() canvas?.discardActiveObject()
}, [currentMenu]) }, [currentMenu])
return ( return (
<div className="canvas-depth2-inner"> <div className="canvas-depth2-inner">

View File

@ -9,10 +9,13 @@ import { usePlan } from '@/hooks/usePlan'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useCanvas } from '@/hooks/useCanvas' import { useCanvas } from '@/hooks/useCanvas'
import { useRecoilValue } from 'recoil' // import { initImageLoaderPopup } from '@/lib/planAction'
import { canvasState } from '@/store/canvasAtom'
export default function ImgLoad() { export default function ImgLoad() {
const { currentCanvasPlan, setCurrentCanvasPlan } = usePlan()
const { getMessage } = useMessage()
const { canvas } = useCanvas()
const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
const { const {
refImage, refImage,
queryRef, queryRef,
@ -27,23 +30,22 @@ export default function ImgLoad() {
handleMapImageDown, handleMapImageDown,
handleAddressDelete, handleAddressDelete,
} = useRefFiles() } = useRefFiles()
const { currentCanvasPlan, setCurrentCanvasPlan } = usePlan()
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
const handleModal = () => { const handleModal = () => {
setFloorPlanState({ ...floorPlanState, refFileModalOpen: false, toggleRotate: false }) setFloorPlanState({ ...floorPlanState, refFileModalOpen: false, toggleRotate: false })
setCurrentCanvasPlan({ // setCurrentCanvasPlan({
...currentCanvasPlan, // ...currentCanvasPlan,
bgImageName: refImage?.name ?? null, // bgImageName: refImage?.name ?? null,
mapPositionAddress, // mapPositionAddress,
}) // })
} }
useEffect(() => { useEffect(() => {
console.log('🚀 ~ ImgLoad ~ floorPlanState.refFileModalOpen:', floorPlanState.refFileModalOpen) console.log('🚀 ~ ImgLoad ~ floorPlanState.refFileModalOpen:', floorPlanState.refFileModalOpen)
console.log('🚀 ~ ImgLoad ~ currentCanvasPlan:', currentCanvasPlan) console.log('🚀 ~ ImgLoad ~ currentCanvasPlan:', currentCanvasPlan)
if (floorPlanState.refFileModalOpen) {
// initImageLoaderPopup({ objectNo: currentCanvasPlan.objectNo, planNo: currentCanvasPlan.planNo })
}
}, [floorPlanState.refFileModalOpen]) }, [floorPlanState.refFileModalOpen])
useEffect(() => { useEffect(() => {
@ -68,9 +70,9 @@ export default function ImgLoad() {
}, [currentCanvasPlan]) }, [currentCanvasPlan])
return ( return (
<WithDraggable isShow={floorPlanState.refFileModalOpen} pos={{ x: 1000, y: 200 }} handle=".modal"> <WithDraggable isShow={floorPlanState.refFileModalOpen} pos={{ x: 1000, y: 200 }}>
<div className={`modal-pop-wrap r`}> <div className={`modal-pop-wrap r`}>
<div className="modal-head"> <div className="modal-head modal-handle">
<h1 className="title">{getMessage('common.input.file')}</h1> <h1 className="title">{getMessage('common.input.file')}</h1>
{/* <button className="modal-close">닫기</button> */} {/* <button className="modal-close">닫기</button> */}
</div> </div>

View File

@ -6,19 +6,20 @@ import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchMod
import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement'
import Placement from '@/components/floor-plan/modal/basic/step/Placement' import Placement from '@/components/floor-plan/modal/basic/step/Placement'
import { useRecoilValue, useRecoilState } from 'recoil' import { useRecoilValue, useRecoilState } from 'recoil'
import { canvasSettingState, isManualModuleSetupState } from '@/store/canvasAtom' import { canvasSettingState, canvasState, isManualModuleSetupState } from '@/store/canvasAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { addedRoofsState } from '@/store/settingAtom' import { addedRoofsState, corridorDimensionSelector } 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 { useMasterController } from '@/hooks/common/useMasterController'
import { loginUserStore } from '@/store/commonAtom' import { loginUserStore } from '@/store/commonAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom' import { currentCanvasPlanState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
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()
@ -32,39 +33,51 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const addedRoofs = useRecoilValue(addedRoofsState) const addedRoofs = useRecoilValue(addedRoofsState)
const loginUserState = useRecoilValue(loginUserStore) const loginUserState = useRecoilValue(loginUserStore)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const canvas = useRecoilValue(canvasState)
const [isClosePopup, setIsClosePopup] = useState({ close: false, id: 0 })
// const { initEvent } = useContext(EventContext) // const { initEvent } = useContext(EventContext)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting() const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(tabNum)
const { updateObjectDate } = useMasterController() const { updateObjectDate } = useMasterController()
const handleBtnNextStep = () => { const handleBtnNextStep = () => {
if (tabNum === 1) { if (tabNum === 1) {
orientationRef.current.handleNextStep() orientationRef.current.handleNextStep()
} else if (tabNum === 2) { } else if (tabNum === 2) {
if (!isObjectNotEmpty(moduleSelectionData.module)) { if (canvasSetting.roofSizeSet !== '3') {
Swal.fire({ if (!isObjectNotEmpty(moduleSelectionData.module)) {
title: getMessage('module.not.found'), Swal.fire({
icon: 'warning', title: getMessage('module.not.found'),
}) icon: 'warning',
return })
} return
}
if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) { if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) {
Swal.fire({ Swal.fire({
title: getMessage('construction.length.difference'), title: getMessage('construction.length.difference'),
icon: 'warning', icon: 'warning',
})
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, //
}) })
return } else {
if (!isObjectNotEmpty(moduleSelectionData.flatModule)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
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,7 +85,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const placementRef = { const placementRef = {
isChidori: useRef('false'), isChidori: useRef('false'),
setupLocation: useRef('center'), setupLocation: useRef('eaves'),
isMaxSetup: useRef('false'), isMaxSetup: useRef('false'),
} }
@ -84,20 +97,49 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
setIsManualModuleSetup(!isManualModuleSetup) setIsManualModuleSetup(!isManualModuleSetup)
} }
useEffect(() => {
manualModuleSetup()
}, [isManualModuleSetup])
const updateObjectDataApi = async (params) => { const updateObjectDataApi = async (params) => {
const res = await updateObjectDate(params) const res = await updateObjectDate(params)
} }
useEffect(() => {
let hasModules = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.some((obj) => obj.modules?.length > 0)
if (hasModules) {
orientationRef.current.handleNextStep()
setTabNum(3)
}
}, [])
//
const handleClosePopup = (id) => {
if (tabNum == 3) {
if (isManualModuleSetup) {
setIsManualModuleSetup(false)
}
}
setIsClosePopup({ close: true, id: id })
}
useEffect(() => {
if (canvasSetting.roofSizeSet !== '3') {
manualModuleSetup(placementRef)
} else {
manualFlatroofModuleSetup(placementFlatRef)
}
if (isClosePopup.close) {
closePopup(isClosePopup.id)
}
}, [isManualModuleSetup, isClosePopup])
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`}>
<div className="modal-head modal-handle"> <div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.module.circuit.setting.default')}</h1> <h1 className="title">{getMessage('plan.menu.module.circuit.setting.default')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}> <button className="modal-close" onClick={() => handleClosePopup(id)}>
닫기 닫기
</button> </button>
</div> </div>
@ -111,12 +153,12 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
</div> </div>
{tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />} {tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />}
{/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/} {/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/}
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && tabNum === 2 && <Module setTabNum={setTabNum} />} {canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != '3' && tabNum === 2 && <Module setTabNum={setTabNum} />}
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />} {canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != '3' && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />}
{/*배치면 초기설정 - 입력방법: 육지붕*/} {/*배치면 초기설정 - 입력방법: 육지붕*/}
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 2 && <PitchModule setTabNum={setTabNum} />} {canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == '3' && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 3 && ( {canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == '3' && tabNum === 3 && (
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} /> <PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
)} )}
@ -145,9 +187,9 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
</button> </button>
</> </>
)} )}
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet === 3 && ( {canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && (
<> <>
<button className="btn-frame modal mr5" onClick={() => manualFlatroofModuleSetup(placementFlatRef)}> <button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')} {getMessage('modal.module.basic.setting.passivity.placement')}
</button> </button>
<button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}> <button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}>

View File

@ -56,12 +56,14 @@ export default function Module({ setTabNum }) {
}, [installHeight, verticalSnowCover]) }, [installHeight, verticalSnowCover])
useEffect(() => { useEffect(() => {
if (tempModuleSelectionData.roofConstructions.length > 0) { if (isObjectNotEmpty(tempModuleSelectionData)) {
if (tempModuleSelectionData.common.moduleItemId && isObjectNotEmpty(tempModuleSelectionData.module)) { if (tempModuleSelectionData.roofConstructions.length > 0) {
// temp (addedRoofs) if (tempModuleSelectionData.common.moduleItemId && isObjectNotEmpty(tempModuleSelectionData.module)) {
if (tempModuleSelectionData.roofConstructions.length === addedRoofs.length) { // temp (addedRoofs)
setModuleSelectionData(tempModuleSelectionData) setModuleSelectionData(tempModuleSelectionData)
moduleSelectedDataTrigger(tempModuleSelectionData) if (tempModuleSelectionData.roofConstructions.length === addedRoofs.length) {
moduleSelectedDataTrigger(tempModuleSelectionData)
}
} }
} }
} }
@ -83,7 +85,7 @@ export default function Module({ setTabNum }) {
header: [ header: [
{ name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' }, { name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' },
{ {
name: `${getMessage('높이')} (mm)`, name: `${getMessage('height')} (mm)`,
prop: 'height', prop: 'height',
}, },
{ name: `${getMessage('width')} (mm)`, prop: 'width' }, { name: `${getMessage('width')} (mm)`, prop: 'width' },
@ -156,7 +158,6 @@ export default function Module({ setTabNum }) {
<div className="module-table-box none-flex"> <div className="module-table-box none-flex">
<div className="module-table-inner"> <div className="module-table-inner">
<div className="module-table-tit">{getMessage('modal.module.basic.setting.module.stuff.info')}</div>
<div className="eaves-keraba-table"> <div className="eaves-keraba-table">
<div className="eaves-keraba-item"> <div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.surface.type')}</div> <div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.surface.type')}</div>
@ -190,7 +191,7 @@ export default function Module({ setTabNum }) {
onChange={(e) => setInputInstallHeight(e.target.value)} onChange={(e) => setInputInstallHeight(e.target.value)}
/> />
</div> </div>
<span className="thin">mm</span> <span className="thin">m</span>
</div> </div>
</div> </div>
</div> </div>
@ -227,7 +228,7 @@ export default function Module({ setTabNum }) {
onChange={(e) => setInputVerticalSnowCover(e.target.value)} onChange={(e) => setInputVerticalSnowCover(e.target.value)}
/> />
</div> </div>
<span className="thin">mm</span> <span className="thin">cm</span>
</div> </div>
</div> </div>
</div> </div>
@ -271,7 +272,6 @@ export default function Module({ setTabNum }) {
</div> </div>
</div> </div>
{/* 설정 오류시 노출 */} {/* 설정 오류시 노출 */}
<div className="reset-word"> 施工方法が選択できません 基準風速または基準積雪量を確認してください</div>
</div> </div>
</div> </div>
</> </>

View File

@ -120,7 +120,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
value={selectedTrestle} value={selectedTrestle}
sourceKey={'trestleMkrCd'} sourceKey={'trestleMkrCd'}
targetKey={'trestleMkrCd'} targetKey={'trestleMkrCd'}
showKey={'trestleMkrCdNm'} showKey={'trestleMkrCdJp'}
onChange={handleChangeTrestle} onChange={handleChangeTrestle}
/> />
)} )}
@ -138,7 +138,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
value={selectedConstMthd} value={selectedConstMthd}
sourceKey={'constMthdCd'} sourceKey={'constMthdCd'}
targetKey={'constMthdCd'} targetKey={'constMthdCd'}
showKey={'constMthdCdNm'} showKey={'constMthdCdJp'}
onChange={handleChangeConstMthd} onChange={handleChangeConstMthd}
/> />
)} )}
@ -156,7 +156,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
value={selectedRoofBase} value={selectedRoofBase}
sourceKey={'roofBaseCd'} sourceKey={'roofBaseCd'}
targetKey={'roofBaseCd'} targetKey={'roofBaseCd'}
showKey={'roofBaseCdNm'} showKey={'roofBaseCdJp'}
onChange={handleChangeRoofBase} onChange={handleChangeRoofBase}
/> />
)} )}
@ -203,7 +203,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
強化施工 強化施工
</button> </button>
</div> </div>
<div className="grid-check-form"> <div className="grid-check-form-block">
<div className="d-check-box pop"> <div className="d-check-box pop">
<input <input
type="checkbox" type="checkbox"

View File

@ -28,8 +28,18 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
}, [compasDeg]) }, [compasDeg])
const checkDegree = (e) => { const checkDegree = (e) => {
if (numberCheck(Number(e)) && Number(e) >= -180 && Number(e) <= 180) { if (e === '-0' || e === '-') {
setCompasDeg(Number(e)) setCompasDeg('-')
return
}
if (e === '0-') {
setCompasDeg('-0')
return
}
if (Number(e) >= -180 && Number(e) <= 180) {
if (numberCheck(Number(e))) {
setCompasDeg(Number(e))
}
} else { } else {
setCompasDeg(compasDeg) setCompasDeg(compasDeg)
} }
@ -46,8 +56,14 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
{Array.from({ length: 180 / 15 }).map((dot, index) => ( {Array.from({ length: 180 / 15 }).map((dot, index) => (
<div <div
key={index} key={index}
className={`circle ${getDegreeInOrientation(compasDeg) === 15 * (12 + index) ? 'act' : ''}`} className={`circle ${getDegreeInOrientation(compasDeg) === -1 * (-15 * index + 180) || (index === 0 && compasDeg >= 172 && index === 0 && compasDeg <= 180) || (compasDeg === -180 && index === 0) ? 'act' : ''}`}
onClick={() => setCompasDeg(15 * (12 + index))} onClick={() => {
if (index === 0) {
setCompasDeg(180)
return
}
setCompasDeg(-1 * (-15 * index + 180))
}}
> >
{index === 0 && <i>180°</i>} {index === 0 && <i>180°</i>}
{index === 6 && <i>-90°</i>} {index === 6 && <i>-90°</i>}
@ -56,7 +72,7 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
{Array.from({ length: 180 / 15 }).map((dot, index) => ( {Array.from({ length: 180 / 15 }).map((dot, index) => (
<div <div
key={index} key={index}
className={`circle ${getDegreeInOrientation(compasDeg) === 15 * index ? 'act' : ''}`} className={`circle ${compasDeg !== 180 && getDegreeInOrientation(compasDeg) === 15 * index ? 'act' : ''}`}
onClick={() => setCompasDeg(15 * index)} onClick={() => setCompasDeg(15 * index)}
> >
{index === 0 && <i>0°</i>} {index === 0 && <i>0°</i>}

View File

@ -2,25 +2,24 @@ import { forwardRef, useEffect, useState } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { checkedModuleState, currentCanvasPlanState } from '@/store/canvasAtom' import { checkedModuleState, currentCanvasPlanState } from '@/store/canvasAtom'
import { useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useModulePlace } from '@/hooks/module/useModulePlace' import { isObjectNotEmpty } from '@/util/common-utils'
const Placement = forwardRef((props, refs) => { const Placement = forwardRef((props, refs) => {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [isChidori, setIsChidori] = useState(false) const [isChidori, setIsChidori] = useState(false)
const [isChidoriNotAble, setIsChidoriNotAble] = useState(false) const [isChidoriNotAble, setIsChidoriNotAble] = useState(false)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const [setupLocation, setSetupLocation] = useState('center') const [setupLocation, setSetupLocation] = useState('eaves')
const [isMaxSetup, setIsMaxSetup] = useState('false') const [isMaxSetup, setIsMaxSetup] = useState('false')
const [selectedItems, setSelectedItems] = useState({}) const [selectedItems, setSelectedItems] = useState({})
const { makeModuleInstArea } = useModuleBasicSetting() const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState)
const { selectedModules } = useModulePlace()
const setCheckedModules = useSetRecoilState(checkedModuleState) const setCheckedModules = useSetRecoilState(checkedModuleState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState) const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const { makeModuleInitArea } = useModuleBasicSetting(3)
// //
useEffect(() => { useEffect(() => {
@ -30,17 +29,39 @@ const Placement = forwardRef((props, refs) => {
if (isChidroriValue) { if (isChidroriValue) {
setIsChidoriNotAble(true) setIsChidoriNotAble(true)
} }
makeModuleInitArea(moduleSelectionData)
} }
}, []) }, [])
//
useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData)) {
//
if (moduleSelectionData.roofConstructions.length > 0 && 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)
setSelectedModules(moduleSelectionData.module)
}
}
}, [moduleSelectionData])
// //
useEffect(() => { useEffect(() => {
const checkedModuleIds = Object.keys(selectedItems).filter((key) => selectedItems[key]) if (isObjectNotEmpty(selectedItems) && isObjectNotEmpty(selectedModules)) {
const moduleArray = selectedModules.itemList.filter((item) => { const checkedModuleIds = Object.keys(selectedItems).filter((key) => selectedItems[key])
return checkedModuleIds.includes(item.itemId) const moduleArray = selectedModules.itemList.filter((item) => {
}) return checkedModuleIds.includes(item.itemId)
setCheckedModules(moduleArray) })
}, [selectedItems]) setCheckedModules(moduleArray)
}
}, [selectedItems, selectedModules])
const moduleData = { const moduleData = {
header: [ header: [
@ -77,20 +98,6 @@ 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">
@ -117,29 +124,27 @@ const Placement = forwardRef((props, refs) => {
<tbody> <tbody>
{selectedModules.itemList && {selectedModules.itemList &&
selectedModules.itemList.map((item, index) => ( selectedModules.itemList.map((item, index) => (
<> <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
<input type="checkbox"
type="checkbox" id={item.itemId}
id={item.itemId} name={item.itemId}
name={item.itemId} checked={selectedItems[item.itemId]}
checked={selectedItems[item.itemId]} onChange={handleSelectedItem}
onChange={handleSelectedItem} />
/> <label htmlFor={item.itemId}></label>
<label htmlFor={item.itemId}></label> </div>
</div> </td>
</td> <td>
<td> <div className="color-wrap">
<div className="color-wrap"> <span className="color-box" style={{ backgroundColor: item.color }}></span>
<span className="color-box" style={{ backgroundColor: item.color }}></span> <span className="name">{item.itemNm}</span>
<span className="name">{item.itemNm}</span> </div>
</div> </td>
</td> <td className="al-r">{item.wpOut}</td>
<td className="al-r">{item.wpOut}</td> </tr>
</tr>
</>
))} ))}
</tbody> </tbody>
</table> </table>
@ -215,10 +220,10 @@ const Placement = forwardRef((props, refs) => {
</div> </div>
</div> </div>
<div className="self-table-flx"> <div className="self-table-flx">
<div className="d-check-box pop"> {/* <div className="d-check-box pop">
<input type="checkbox" id="ch04" checked={isMaxSetup === 'true'} value={'true'} onChange={handleMaxSetup} /> <input type="checkbox" id="ch04" checked={isMaxSetup === 'true'} value={'true'} onChange={handleMaxSetup} />
<label htmlFor="ch04">{getMessage('modal.module.basic.setting.module.placement.maximum')}</label> <label htmlFor="ch04">{getMessage('modal.module.basic.setting.module.placement.maximum')}</label>
</div> </div> */}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,12 +1,22 @@
import { useState, useEffect } from 'react'
import { useRecoilState } from 'recoil'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
import { useMasterController } from '@/hooks/common/useMasterController'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { isObjectNotEmpty } from '@/util/common-utils'
export default function PitchModule({}) { export default function PitchModule({}) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] const { getModuleTypeItemList } = useMasterController()
const [moduleList, setModuleList] = useState([])
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) //
const moduleData = { const moduleData = {
header: [ header: [
{ name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' }, { name: getMessage('module'), width: 250, prop: 'module', type: 'color-box' },
{ {
name: `${getMessage('높이')} (mm)`, name: `${getMessage('높이')} (mm)`,
prop: 'height', prop: 'height',
@ -14,24 +24,45 @@ export default function PitchModule({}) {
{ name: `${getMessage('width')} (mm)`, prop: 'width' }, { name: `${getMessage('width')} (mm)`, prop: 'width' },
{ name: `${getMessage('output')} (W)`, prop: 'output' }, { name: `${getMessage('output')} (W)`, prop: 'output' },
], ],
rows: [
{
module: { name: 'Re.RISE-G3 440', color: '#AA6768' },
height: { name: '1134' },
width: { name: '1722' },
output: { name: '440' },
},
{
module: {
name: 'Re.RISE MS-G3 290',
color: '#67A2AA',
},
height: { name: '1134' },
width: { name: '1722' },
output: { name: '240' },
},
],
} }
const getModuleData = async (roofsIds) => {
const list = await getModuleTypeItemList(roofsIds)
if (list.data.length > 0) {
//selectbox
list.data.forEach((item) => {
item.name = item.itemNm
})
//
setModuleList(list.data)
}
}
useEffect(() => {
getModuleData(['FLAT_ROOF'])
}, [])
const handleChangeModule = (option) => {
//
setSelectedModules(option) //
setModuleSelectionData({
...moduleSelectionData,
flatModule: option,
})
moduleSelectedDataTrigger({
...moduleSelectionData,
flatModule: option,
})
}
useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData.flatModule) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.flatModule)
}
}, [moduleList])
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
return ( return (
<> <>
<div className="module-table-box"> <div className="module-table-box">
@ -39,7 +70,17 @@ export default function PitchModule({}) {
<div className="outline-form mb10"> <div className="outline-form mb10">
<span className="mr10">{getMessage('modal.module.basic.setting.module.setting')}</span> <span className="mr10">{getMessage('modal.module.basic.setting.module.setting')}</span>
<div className="grid-select"> <div className="grid-select">
<QSelectBox title={'Search'} option={SelectOption01} /> {moduleList && (
<QSelectBox
title={getMessage('selectbox.title')}
options={moduleList}
value={selectedModules}
targetKey={'itemId'}
sourceKey={'itemId'}
showKey={'itemNm'}
onChange={handleChangeModule}
/>
)}
</div> </div>
</div> </div>
<div className="roof-module-table"> <div className="roof-module-table">
@ -54,33 +95,21 @@ export default function PitchModule({}) {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{moduleData.rows.map((row) => ( {selectedModules &&
<> selectedModules.itemList &&
<tr> selectedModules.itemList.map((row, index) => (
{moduleData.header.map((header) => ( <tr key={index}>
<> <td>
{header.type === 'color-box' && ( <div className="color-wrap">
<td> <span className="color-box" style={{ backgroundColor: row.color }}></span>
<div className="color-wrap"> <span className="name">{row.itemNm}</span>
<span className="color-box" style={{ backgroundColor: row[header.prop].color }}></span> </div>
<span className="name">{row[header.prop].name}</span> </td>
</div> <td>{Number(row.shortAxis).toFixed(0)}</td>
</td> <td>{Number(row.longAxis).toFixed(0)}</td>
)} <td>{Number(row.wpOut).toFixed(0)}</td>
{!header.type && header.type !== 'color-box' && <td className="al-r">{row[header.prop].name}</td>}
</>
))}
</tr> </tr>
</> ))}
))}
{Array.from({ length: 3 - moduleData.rows.length }).map((_, i) => (
<tr key={i}>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
))}
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -1,49 +1,48 @@
import { forwardRef, useState, useEffect } from 'react' import { forwardRef, useState, useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { canvasState } from '@/store/canvasAtom' import { canvasState, checkedModuleState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
const PitchPlacement = forwardRef((props, refs) => { const PitchPlacement = forwardRef((props, refs) => {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [setupLocation, setSetupLocation] = useState('south') const [setupLocation, setSetupLocation] = useState('south')
const { makeModuleInstArea } = useModuleBasicSetting()
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { initEvent } = useEvent() const { initEvent } = useEvent()
useEffect(() => { const { selectedModules } = useModuleBasicSetting(3)
makeModuleInstArea() const setCheckedModules = useSetRecoilState(checkedModuleState)
}, []) const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //
const [selectedItems, setSelectedItems] = useState({})
useEffect(() => { useEffect(() => {
handleChangeSetupLocation() handleChangeSetupLocation()
}, [setupLocation]) }, [setupLocation])
const handleSelectedItem = (e) => {
setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked })
}
const moduleData = { const moduleData = {
header: [ header: [
{ type: 'check', name: '', prop: 'check', width: 70 }, { type: 'check', name: '', prop: 'check', width: 70 },
{ type: 'color-box', name: getMessage('module'), prop: 'module' }, { type: 'color-box', name: getMessage('module'), prop: 'module' },
{ type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 }, { type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 },
], ],
rows: [
{
check: false,
module: { name: 'Re.RISE-G3 440', color: '#AA6768' },
output: { name: '440' },
},
{
check: false,
module: {
name: 'Re.RISE MS-G3 290',
color: '#67A2AA',
},
output: { name: '240' },
},
],
} }
//
useEffect(() => {
const checkedModuleIds = Object.keys(selectedItems).filter((key) => selectedItems[key])
const moduleArray = selectedModules.itemList.filter((item) => {
return checkedModuleIds.includes(item.itemId)
})
setCheckedModules(moduleArray)
}, [selectedItems])
const handleSetupLocation = (e) => { const handleSetupLocation = (e) => {
initEvent() initEvent()
refs.setupLocation.current = e.target refs.setupLocation.current = e.target
@ -81,6 +80,20 @@ const PitchPlacement = forwardRef((props, refs) => {
} }
} }
useEffect(() => {
if (moduleSelectionData && moduleSelectionData.flatModule.itemList.length > 0) {
let initCheckedModule = {}
moduleSelectionData.flatModule.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-box mb10"> <div className="module-table-box mb10">
@ -104,33 +117,30 @@ const PitchPlacement = forwardRef((props, refs) => {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{moduleData.rows.map((row) => ( {selectedModules.itemList &&
<> selectedModules.itemList.map((item, index) => (
<tr> <tr key={index}>
{moduleData.header.map((header) => ( <td className="al-c">
<> <div className="d-check-box no-text pop">
{header.type === 'color-box' && ( <input
<td> type="checkbox"
<div className="color-wrap"> id={item.itemId}
<span className="color-box" style={{ backgroundColor: row[header.prop].color }}></span> name={item.itemId}
<span className="name">{row[header.prop].name}</span> checked={selectedItems[item.itemId]}
</div> onChange={handleSelectedItem}
</td> />
)} <label htmlFor={item.itemId}></label>
{header.type === 'check' && ( </div>
<td className="al-c"> </td>
<div className="d-check-box no-text pop"> <td>
<input type="checkbox" id="ch02" /> <div className="color-wrap">
<label htmlFor="ch02"></label> <span className="color-box" style={{ backgroundColor: item.color }}></span>
</div> <span className="name">{item.itemNm}</span>
</td> </div>
)} </td>
{header.type && header.type !== 'color-box' && header.type !== 'check' && <td className="al-r">{row[header.prop].name}</td>} <td className="al-r">{item.wpOut}</td>
</>
))}
</tr> </tr>
</> ))}
))}
</tbody> </tbody>
</table> </table>
</div> </div>
@ -150,8 +160,7 @@ const PitchPlacement = forwardRef((props, refs) => {
name="radio01" name="radio01"
id="ra01" id="ra01"
value={'south'} value={'south'}
checked={setupLocation === 'south'} defaultChecked={setupLocation === 'south'}
defaultChecked
onClick={handleSetupLocation} onClick={handleSetupLocation}
/> />
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label> <label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label>
@ -162,7 +171,7 @@ const PitchPlacement = forwardRef((props, refs) => {
name="radio01" name="radio01"
id="ra02" id="ra02"
value={'excreta'} value={'excreta'}
checked={setupLocation === 'excreta'} defaultChecked={setupLocation === 'excreta'}
onClick={handleSetupLocation} onClick={handleSetupLocation}
/> />
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label> <label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label>

View File

@ -1,7 +1,6 @@
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState, useEffect, useContext } from 'react' import { useState, useEffect, useContext } from 'react'
import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect' import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect'
import CircuitAllocation from '@/components/floor-plan/modal/circuitTrestle/step/CircuitAllocation'
import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp' import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
@ -20,7 +19,11 @@ import { useTrestle } from '@/hooks/module/useTrestle'
import { selectedModuleState } from '@/store/selectedModuleOptions' import { selectedModuleState } from '@/store/selectedModuleOptions'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { stepUpListDataState } from '@/store/circuitTrestleAtom' import { useEstimate } from '@/hooks/useEstimate'
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { useImgLoader } from '@/hooks/floorPlan/useImgLoader'
import { usePlan } from '@/hooks/usePlan'
const ALLOCATION_TYPE = { const ALLOCATION_TYPE = {
AUTO: 'auto', AUTO: 'auto',
@ -29,52 +32,73 @@ const ALLOCATION_TYPE = {
export default function CircuitTrestleSetting({ id }) { export default function CircuitTrestleSetting({ id }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { apply } = useTrestle() const { apply, setViewCircuitNumberTexts } = useTrestle()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { saveEstimate } = useEstimate()
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const [makers, setMakers] = useRecoilState(makersState)
const [selectedMaker, setSelectedMaker] = useRecoilState(selectedMakerState)
const [series, setSeries] = useRecoilState(seriesState)
const [models, setModels] = useRecoilState(modelsState)
const [selectedModels, setSelectedModels] = useRecoilState(selectedModelsState)
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const [tabNum, setTabNum] = useState(1) const [tabNum, setTabNum] = useState(1)
const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO) const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO)
const [circuitAllocationType, setCircuitAllocationType] = useState(1) const [circuitAllocationType, setCircuitAllocationType] = useState(1)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState) const selectedModules = useRecoilValue(selectedModuleState)
const { getPcsAutoRecommendList, getPcsVoltageChk } = useMasterController() const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList } = useMasterController()
// () // ()
const [selectedStepUpValues, setSelectedStepUpValues] = useState({}) const [selectedStepUpValues, setSelectedStepUpValues] = useState({})
const [getStepUpSelections, setGetStepUpSelections] = useState(null) const [getStepUpSelections, setGetStepUpSelections] = useState(null)
// const { trigger: setCircuitData } = useCanvasPopupStatusController(4)
// const [stepUpListData, setStepUpListData] = useRecoilState(stepUpListDataState)
const [stepUpListData, setStepUpListData] = useState([])
const [seletedOption, setSeletedOption] = useState(null)
const { setModuleStatisticsData } = useCircuitTrestle()
const [stepUpListData, setStepUpListData] = useRecoilState(stepUpListDataState) const { handleCanvasToPng } = useImgLoader()
const { saveCanvas } = usePlan()
const {
makers,
setMakers,
selectedMaker,
setSelectedMaker,
series,
setSeries,
models,
setModels,
selectedModels,
setSelectedModels,
pcsCheck,
setPcsCheck,
getOptYn,
getPcsItemList,
getSelectedPcsItemList,
getUseModuleItemList,
getRoofSurfaceList,
getModuleList,
removeNotAllocationModules,
} = useCircuitTrestle()
// const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
useEffect(() => { useEffect(() => {
if (!managementState) { if (!managementState) {
setManagementState(managementStateLoaded) setManagementState(managementStateLoaded)
} }
// setCircuitData({
// makers,
// selectedMaker,
// series,
// models,
// selectedModels,
// pcsCheck,
// })
}, []) }, [])
useEffect(() => { //
if (allocationType === ALLOCATION_TYPE.PASSIVITY && tabNum === 2) {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
canvas.remove(...notAllocationModules)
canvas.renderAll()
}
}, [tabNum])
useEffect(() => {
console.log('stepUpListData >>> ', stepUpListData)
}, [stepUpListData])
// PCS
const onAutoRecommend = () => { const onAutoRecommend = () => {
if (series.filter((s) => s.selected).length === 0) { if (series.filter((s) => s.selected).length === 0) {
swalFire({ swalFire({
title: '시리즈를 선택해 주세요.', title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error02'),
type: 'alert', type: 'alert',
}) })
return return
@ -87,27 +111,45 @@ export default function CircuitTrestleSetting({ id }) {
pcsItemList: getPcsItemList(), pcsItemList: getPcsItemList(),
} }
//
if (selectedModels.length === 0) { if (selectedModels.length === 0) {
// PCS
getPcsAutoRecommendList(params).then((res) => { getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) { if (res.data?.pcsItemList) {
const itemList = models.filter((model) => { let pcsItemList = []
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId) let pcsObj = {}
models.forEach((model) => {
pcsObj[model.itemId] = model
}) })
const selectedModels = itemList.map((model) => { res.data?.pcsItemList.forEach((item) => {
return { if (pcsObj[item.itemId]) {
...model, pcsItemList.push({
id: uuidv4(), ...pcsObj[item.itemId],
isUsed: false,
id: uuidv4(),
})
} }
}) })
//
const pcsVoltageChkParams = { const pcsVoltageChkParams = {
...getOptYn(), ...getOptYn(),
useModuleItemList: getUseModuleItemList(), useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(), roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(), pcsItemList: pcsItemList,
} }
setSelectedModels(selectedModels) //
setSelectedModels(pcsItemList)
//
getPcsVoltageChk(pcsVoltageChkParams).then((res) => { getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
setTabNum(2) if (res.resultCode === 'S') {
setTabNum(2)
} else {
swalFire({
title: res.resultMsg,
type: 'alert',
})
}
}) })
} else { } else {
// //
@ -125,144 +167,37 @@ export default function CircuitTrestleSetting({ id }) {
} }
}) })
} else { } else {
getPcsVoltageChk(params).then((res) => { //
setTabNum(2) getPcsVoltageChk({ ...params, pcsItemList: getSelectedPcsItemList() }).then((res) => {
}) if (res.resultCode === 'S') {
} //
} getPcsVoltageStepUpList({
...params,
const getOptYn = () => { pcsItemList: getSelectedPcsItemList(),
return { }).then((res) => {
maxConnYn: pcsCheck.max ? 'Y' : 'N', setTabNum(2)
smpCirYn: pcsCheck.division ? 'Y' : 'N', })
coldZoneYn: managementState?.coldRegionFlg === '1' ? 'Y' : 'N', } else {
} swalFire({
} title: res.resultMsg,
type: 'alert',
const getPcsItemList = () => { })
return models.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
const getUseModuleItemList = () => {
return selectedModules.itemList.map((m) => {
return {
itemId: m.itemId,
mixMatlNo: m.mixMatlNo,
}
})
}
const getRoofSurfaceList = () => {
return canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.map((obj) => {
return {
roofSurfaceId: obj.id,
roofSurface: canvas
.getObjects()
.filter((o) => o.id === obj.parentId)[0]
.directionText.replace(/[0-9]/g, ''),
roofSurfaceIncl: canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch,
moduleList: getModuleList(obj).map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber ? module.circuitNumber : null,
pcsItemId: module.circuit ? module.circuit?.pcsItemId : null,
uniqueId: module.id ? module.id : null,
}
}),
} }
}) })
}
const getModuleList = (surface) => {
let moduleList = []
let [xObj, yObj] = [{}, {}]
let [xPoints, yPoints] = [[], []]
surface.modules.forEach((module) => {
if (!xObj[module.left]) {
xObj[module.left] = module.left
xPoints.push(module.left)
}
if (!yObj[module.top]) {
yObj[module.top] = module.top
yPoints.push(module.top)
}
})
switch (surface.direction) {
case 'south':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => b - a)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => a.left - b.left)
} else {
temp.sort((a, b) => b.left - a.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'north':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => a - b)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => b.left - a.left)
} else {
temp.sort((a, b) => a.left - b.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'west':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => a - b)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => a.top - b.top)
} else {
temp.sort((a, b) => b.top - a.top)
}
moduleList = [...moduleList, ...temp]
})
break
case 'east':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => b - a)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => b.top - a.top)
} else {
temp.sort((a, b) => a.top - b.top)
}
moduleList = [...moduleList, ...temp]
})
break
default:
return []
} }
return moduleList
} }
//
const onAutoAllocation = () => { const onAutoAllocation = () => {
let moduleStdQty = 0 let moduleStdQty = 0
let moduleMaxQty = 0 let moduleMaxQty = 0
const selectedModels = models.filter((m) => m.selected) const selectedModels = models.filter((m) => m.selected)
// PCS
if (selectedModels.length === 0) { if (selectedModels.length === 0) {
onAutoRecommend() onAutoRecommend()
} else { } else {
//
moduleStdQty = selectedModels.reduce((acc, model) => { moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty) return acc + parseInt(model.moduleStdQty)
}, 0) }, 0)
@ -285,42 +220,71 @@ export default function CircuitTrestleSetting({ id }) {
// setTabNum(2) // setTabNum(2)
} }
//
const onPassivityAllocation = () => { const onPassivityAllocation = () => {
if (selectedModels.length === 0) { if (selectedModels.length === 0) {
const params = { const params = {
...getOptYn(), ...getOptYn(),
useModuleItemList: getUseModuleItemList(), useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(), roofSurfaceList: getRoofSurfaceList().map((surface) => {
return {
...surface,
moduleList: surface.moduleList.map((module) => {
return {
itemId: module.itemId,
uniqueId: module.uniqueId,
}
}),
}
}),
pcsItemList: getPcsItemList(), pcsItemList: getPcsItemList(),
} }
//
getPcsAutoRecommendList(params).then((res) => { getPcsAutoRecommendList(params).then((res) => {
if (res.data?.pcsItemList) { if (res.data?.pcsItemList) {
const itemList = models.filter((model) => { let pcsItemList = []
return res.data?.pcsItemList.map((item) => item.itemId).includes(model.itemId) let pcsObj = {}
models.forEach((model) => {
pcsObj[model.itemId] = model
}) })
const selectedModels = itemList.map((model) => { res.data?.pcsItemList.forEach((item) => {
return { if (pcsObj[item.itemId]) {
...model, pcsItemList.push({
id: uuidv4(), ...pcsObj[item.itemId],
isUsed: false,
id: uuidv4(),
})
} }
}) })
const PcsVoltageChkParams = { const pcsVoltageChkParams = {
...getOptYn(), ...getOptYn(),
useModuleItemList: getUseModuleItemList(), useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(), roofSurfaceList: getRoofSurfaceList(),
pcsItemList: getPcsItemList(), pcsItemList: pcsItemList.map((item) => {
return {
itemId: item.itemId,
pcsMkrCd: item.pcsMkrCd,
pcsSerCd: item.pcsSerCd,
}
}),
} }
setSelectedModels(selectedModels) setSelectedModels(pcsItemList)
getPcsVoltageChk(PcsVoltageChkParams).then((res) => {}) getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
setAllocationType(ALLOCATION_TYPE.PASSIVITY)
})
} else { } else {
swalFire({ swalFire({
title: '파워컨디셔너를 추가해 주세요.', title: res.result.resultMsg,
type: 'alert', type: 'alert',
confirmFn: () => {
return
},
}) })
return
} }
}) })
} else if (pcsCheck.max) { } else {
const moduleStdQty = selectedModels.reduce((acc, model) => { const moduleStdQty = selectedModels.reduce((acc, model) => {
return acc + parseInt(model.moduleStdQty) return acc + parseInt(model.moduleStdQty)
}, 0) }, 0)
@ -333,14 +297,14 @@ export default function CircuitTrestleSetting({ id }) {
if (placementModules.length > target) { if (placementModules.length > target) {
swalFire({ swalFire({
title: '배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.', title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error01'),
type: 'alert', type: 'alert',
}) })
return return
} }
}
setAllocationType(ALLOCATION_TYPE.PASSIVITY) setAllocationType(ALLOCATION_TYPE.PASSIVITY)
}
} }
// StepUp // StepUp
@ -358,83 +322,59 @@ export default function CircuitTrestleSetting({ id }) {
setGetStepUpSelections(() => getCurrentSelections) setGetStepUpSelections(() => getCurrentSelections)
} }
// apply // ()
const onApply = () => { const onApply = async () => {
// canvas
const currentSelections = getStepUpSelections ? getStepUpSelections() : {} .getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
console.log('currentSelections >>> ', currentSelections) .map((obj) => {
obj.pcses = getStepUpListData()
//
const hasSelections = Object.values(currentSelections).some((stepUpConfig) => Object.values(stepUpConfig).length > 0)
console.log('hasSelections >>> ', hasSelections)
if (!hasSelections) {
swalFire({
title: '승압 설정값을 선택해주세요.1',
type: 'alert',
})
return
}
//
console.log('Applying StepUp configurations:', currentSelections)
// StepUp stepUpListData
//const stepUpData = getStepUpSelections().stepUpListData
//console.log('stepUpData >>> ', stepUpData)
// stepUpListData Recoil state
// setStepUpListData(stepUpData)
//
const configurations = Object.values(currentSelections)
.map((stepUpConfig) => {
const firstConfig = Object.values(stepUpConfig)[0] //
return {
pcsInfo: firstConfig.pcsInfo,
allocation: firstConfig.allocation,
}
})
.filter((config) => config.pcsInfo && config.allocation) //
console.log('Processed configurations:', configurations)
// stepUpListData Recoil state
setStepUpListData(configurations)
// apply
if (configurations.length > 0) {
apply()
} else {
swalFire({
title: '승압 설정값을 선택해주세요.2',
type: 'alert',
}) })
setViewCircuitNumberTexts(false)
handleCanvasToPng(1)
const result = await apply()
if (result) {
handleCanvasToPng(2)
setViewCircuitNumberTexts(true)
//
await saveCanvas(false)
//
await saveEstimate(result)
} }
// removeNotAllocationModules()
} }
//
const onClickPrev = () => { const onClickPrev = () => {
setAllocationType(ALLOCATION_TYPE.AUTO) // setAllocationType(ALLOCATION_TYPE.AUTO)
swalFire({ swalFire({
text: '할당한 회로 번호가 초기화됩니다.', text: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info'),
type: 'alert', type: 'alert',
icon: 'warning', icon: 'warning',
confirmFn: () => { confirmFn: () => {
const circuitModules = canvas const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module')
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit)) canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => { circuitModules.forEach((obj) => {
obj.circuit = null obj.circuit = null
obj.pcsItemId = null obj.pcsItemId = null
}) })
setAllocationType(ALLOCATION_TYPE.AUTO)
if (allocationType === ALLOCATION_TYPE.PASSIVITY) {
setAllocationType(ALLOCATION_TYPE.AUTO)
} else {
setTabNum(1)
}
canvas.renderAll() canvas.renderAll()
setModuleStatisticsData()
}, },
}) })
} }
//
const powerConditionalSelectProps = { const powerConditionalSelectProps = {
tabNum, tabNum,
setTabNum, setTabNum,
@ -449,8 +389,10 @@ export default function CircuitTrestleSetting({ id }) {
selectedModels, selectedModels,
setSelectedModels, setSelectedModels,
managementState, managementState,
getUseModuleItemList,
} }
//
const passivityProps = { const passivityProps = {
tabNum, tabNum,
setTabNum, setTabNum,
@ -462,18 +404,86 @@ export default function CircuitTrestleSetting({ id }) {
getRoofSurfaceList, getRoofSurfaceList,
} }
//
const stepUpProps = { const stepUpProps = {
tabNum, tabNum,
setTabNum, setTabNum,
models, models,
setModels, setModels,
allocationType,
circuitAllocationType, circuitAllocationType,
setCircuitAllocationType, setCircuitAllocationType,
selectedModels,
setSelectedModels,
getSelectedPcsItemList,
getOptYn, // Y/N getOptYn, // Y/N
getUseModuleItemList, // List getUseModuleItemList, // List
getRoofSurfaceList, // getRoofSurfaceList, //
getPcsItemList, // PCS getPcsItemList, // PCS
onValuesSelected: handleStepUpValuesSelected, // onValuesSelected: handleStepUpValuesSelected, //
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
getModuleList,
}
//
const getStepUpListData = () => {
return stepUpListData[0].pcsItemList.map((item) => {
return item.serQtyList
.filter((serQty) => serQty.selected)
.map((serQty) => {
return {
pcsMkrCd: item.pcsMkrCd,
pcsSerCd: item.pcsSerCd,
pcsItemId: item.itemId,
pscOptCd: seletedOption.code,
paralQty: serQty.paralQty,
connections: item.connList?.length
? [
{
connItemId: item.connList[0].itemId,
},
]
: [],
}
})[0]
})
}
const handleStepUp = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) {
swalFire({
title: getMessage('not.allocation.exist.module'),
type: 'alert',
confirmFn: () => {},
})
return
// canvas.remove(...notAllocationModules)
// canvas.renderAll()
}
setTabNum(2)
}
//
const handleClose = () => {
// //
const circuitTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
canvas.remove(...circuitTexts)
//
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
obj.circuitNumber = null
})
canvas.renderAll()
closePopup(id)
} }
return ( return (
@ -481,7 +491,8 @@ export default function CircuitTrestleSetting({ id }) {
<div className={`modal-pop-wrap l-2`}> <div className={`modal-pop-wrap l-2`}>
<div className="modal-head modal-handle"> <div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.circuit.trestle.setting')} </h1> <h1 className="title">{getMessage('modal.circuit.trestle.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}> {/* <button className="modal-close" onClick={() => closePopup(id)}> */}
<button className="modal-close" onClick={handleClose}>
닫기 닫기
</button> </button>
</div> </div>
@ -498,7 +509,7 @@ export default function CircuitTrestleSetting({ id }) {
{tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />} {tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />}
{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 act" onClick={() => onAutoRecommend()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')} {getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button> </button>
<button className="btn-frame modal act" onClick={() => onPassivityAllocation()}> <button className="btn-frame modal act" onClick={() => onPassivityAllocation()}>
@ -508,17 +519,17 @@ 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={() => onClickPrev()}> <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={() => handleStepUp()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')}) {getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</button> </button>
</div> </div>
)} )}
{tabNum === 2 && ( {tabNum === 2 && (
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => setTabNum(1)}> <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={() => apply()}> */} {/* <button className="btn-frame modal act" onClick={() => apply()}> */}

View File

@ -1,25 +0,0 @@
import AutoCircuitAllocation from '@/components/floor-plan/modal/circuitTrestle/step/type/AutoCircuitAllocation'
import PassivityCircuitAllocation from '@/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation'
import { useMessage } from '@/hooks/useMessage'
export default function CircuitAllocation(props) {
const { getMessage } = useMessage()
const { circuitAllocationType, setCircuitAllocationType } = props
return (
<>
<div className="module-box-tab">
<button className={`module-btn ${circuitAllocationType === 1 ? 'act' : ''}`} onClick={() => setCircuitAllocationType(1)}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className={`module-btn ${circuitAllocationType === 2 ? 'act' : ''}`} onClick={() => setCircuitAllocationType(2)}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('modal.circuit.trestle.setting.circuit.allocation')}</div>
{circuitAllocationType === 1 && <AutoCircuitAllocation />}
{circuitAllocationType === 2 && <PassivityCircuitAllocation />}
</div>
</>
)
}

View File

@ -1,11 +1,12 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider' import { GlobalDataContext } from '@/app/GlobalDataProvider'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { useMasterController } from '@/hooks/common/useMasterController' import { useMasterController } from '@/hooks/common/useMasterController'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal' 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 { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isNullOrUndefined } from '@/util/common-utils' 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'
@ -27,6 +28,7 @@ export default function PowerConditionalSelect(props) {
selectedModels, selectedModels,
setSelectedModels, setSelectedModels,
managementState, managementState,
getUseModuleItemList,
} = props } = props
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState) const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
@ -36,9 +38,11 @@ export default function PowerConditionalSelect(props) {
const { getPcsMakerList, getPcsModelList } = useMasterController() const { getPcsMakerList, getPcsModelList } = useMasterController()
const selectedModules = useRecoilValue(selectedModuleState) const selectedModules = useRecoilValue(selectedModuleState)
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const modelHeader = [ const modelHeader = [
{ name: getMessage('시리즈'), width: '15%', prop: 'pcsSerNm', type: 'color-box' }, { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.series'), width: '15%', prop: 'pcsSerNm', type: 'color-box' },
{ name: getMessage('명칭'), width: '15%', prop: 'itemNm', type: 'color-box' }, { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.name'), width: '15%', prop: 'goodsNo', type: 'color-box' },
{ {
name: `${getMessage('modal.circuit.trestle.setting.power.conditional.select.rated.output')} (kW)`, name: `${getMessage('modal.circuit.trestle.setting.power.conditional.select.rated.output')} (kW)`,
width: '10%', width: '10%',
@ -64,60 +68,54 @@ export default function PowerConditionalSelect(props) {
useEffect(() => { useEffect(() => {
if (makers.length === 0) { if (makers.length === 0) {
getPcsMakerList().then((res) => { getPcsMakerList().then((res) => {
console.log('getPcsMakerList', res.data)
setMakers(res.data) setMakers(res.data)
}) })
} }
}, []) }, [])
const checkValidation = () => {
const checkedSeries = series.filter((s) => s.selected)
if (checkedSeries.length === 0) {
swalFire({
title: 'PCS 시리즈를 선택해 주세요.',
icon: 'warning',
})
return false
} else if (checkedSeries.length === 1) {
if (checkedSeries[0].pcsMkrMultiType === 'SINGLE-P' && checkedSeries[0].pcsSerParallelYn === 'Y') {
swalFire({
title: '병설은 단독으로 안 됨',
icon: 'warning',
})
}
return false
}
return true
}
const onCheckSeries = (data) => { const onCheckSeries = (data) => {
console.log('data', data) let copySeries = []
const copySeries = series.map((s) => { if (data.pcsMkrMultiType === 'MULTI') {
return { copySeries = series.map((s) => {
...s, return {
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.selected, ...s,
} selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.selected,
}) }
})
} else if (data.pcsMkrMultiType === 'SINGLE-P') {
copySeries = series.map((s) => {
return {
...s,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.pcsMkrMultiType === 'MULTI' ? s.selected : false,
}
})
} else {
copySeries = series.map((s) => {
return {
...s,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : false,
}
})
}
setSeries(copySeries) setSeries(copySeries)
console.log('copySeries', copySeries)
handleSetmodels(copySeries.filter((s) => s.selected)) handleSetmodels(copySeries.filter((s) => s.selected))
} }
const handleSetmodels = (selectedSeries) => { const handleSetmodels = (selectedSeries) => {
console.log('series', selectedSeries)
if (selectedSeries.length === 0) { if (selectedSeries.length === 0) {
setModels([]) setModels([])
setSelectedModels([]) setSelectedModels([])
return return
} }
console.log('moduleSelectionData', moduleSelectionData)
const pcsMkrCd = selectedSeries[0]?.pcsMkrCd const pcsMkrCd = selectedSeries[0]?.pcsMkrCd
const pcsSerList = selectedSeries.map((series) => { const pcsSerList = selectedSeries.map((series) => {
return { pcsSerCd: series.pcsSerCd } return { pcsSerCd: series.pcsSerCd }
}) })
const moduleItemList = selectedModules.itemList?.map((module) => { const moduleItemList = moduleSelectionData.module.itemList.map((item) => {
return { return {
itemId: module.itemId, itemId: item.itemId,
mixMatlNo: module.mixMatlNo, mixMatlNo: item.mixMatlNo,
} }
}) })
getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList }).then((res) => { getPcsModelList({ pcsMkrCd, pcsSerList, moduleItemList }).then((res) => {
@ -143,13 +141,17 @@ export default function PowerConditionalSelect(props) {
if (selectedRow === null) return if (selectedRow === null) return
if (selectedModels.length === 3) { if (selectedModels.length === 3) {
swalFire({ swalFire({
title: '최대 3개까지 선택할 수 있습니다.', title: getMessage('max.select', [3]),
icon: 'warning', icon: 'warning',
}) })
return return
} }
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4() }]) if (selectedMaker.pcsMkrMultiType === 'MULTI') {
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4(), isUsed: false }])
} else if (!selectedModels.find((m) => m.itemId === selectedRow.itemId)) {
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4(), isUsed: false }])
}
setSelectedRow(null) setSelectedRow(null)
} }
@ -160,10 +162,14 @@ export default function PowerConditionalSelect(props) {
const onChangeMaker = (option) => { const onChangeMaker = (option) => {
if (option) { if (option) {
setModels([]) setModels([])
setSelectedModels([])
setSelectedMaker(option) setSelectedMaker(option)
const param = {
pcsMkrCd: option.pcsMkrCd,
mixMatlNo: moduleSelectionData.module.mixMatlNo,
}
getPcsMakerList(option).then((res) => { getPcsMakerList(param).then((res) => {
console.log('getPcsMakerList(series)', res.data)
setSeries( setSeries(
res.data.map((series) => { res.data.map((series) => {
return { ...series, selected: false } return { ...series, selected: false }
@ -198,7 +204,7 @@ export default function PowerConditionalSelect(props) {
<div className="module-table-inner"> <div className="module-table-inner">
<div className="circuit-check-inner overflow"> <div className="circuit-check-inner overflow">
{series?.map((series, index) => ( {series?.map((series, index) => (
<div className="d-check-box pop sel"> <div className="d-check-box pop sel" key={`series-${index}`}>
<input type="checkbox" id={`"ch0"${index}`} onChange={() => onCheckSeries(series)} checked={series.selected} /> <input type="checkbox" id={`"ch0"${index}`} onChange={() => onCheckSeries(series)} checked={series.selected} />
<label htmlFor={`"ch0"${index}`}>{globalLocale === 'ko' ? series.pcsSerNm : series.pcsSerNmJp}</label> <label htmlFor={`"ch0"${index}`}>{globalLocale === 'ko' ? series.pcsSerNm : series.pcsSerNmJp}</label>
</div> </div>
@ -238,9 +244,9 @@ export default function PowerConditionalSelect(props) {
</button> </button>
</div> </div>
<div className="circuit-data-form"> <div className="circuit-data-form">
{selectedModels?.map((model) => ( {selectedModels?.map((model, index) => (
<span className="normal-font"> <span className="normal-font" key={`model-${index}`}>
{model.itemNm} <button className="del" onClick={() => onRemoveSelectedModel(model)}></button> {model.goodsNo} <button className="del" onClick={() => onRemoveSelectedModel(model)}></button>
</span> </span>
))} ))}
</div> </div>

View File

@ -9,19 +9,36 @@ import { useRecoilState, useRecoilValue } from 'recoil'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { useMasterController } from '@/hooks/common/useMasterController' import { useMasterController } from '@/hooks/common/useMasterController'
import { v4 as uuidv4 } from 'uuid'
import { globalLocaleStore } from '@/store/localeAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { circuitNumDisplaySelector } from '@/store/settingAtom'
export default function StepUp(props) { export default function StepUp(props) {
const {
models,
allocationType,
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
selectedModels,
setSelectedModels,
getSelectedPcsItemList,
getModuleList,
} = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { swalFire } = useSwal()
const globalLocale = useRecoilValue(globalLocaleStore)
const [moduleTab, setModuleTab] = useState(1) const [moduleTab, setModuleTab] = useState(1)
const [moduleTabs, setModuleTabs] = useState({}) const [moduleTabs, setModuleTabs] = useState({})
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 { models } = props const { getPcsVoltageStepUpList, getPcsAutoRecommendList, getPcsVoltageChk, getPcsConnOptionItemList } = 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)
const [stepUpListData, setStepUpListData] = useState([])
const [optCodes, setOptCodes] = useState([]) const [optCodes, setOptCodes] = useState([])
const [selectedRows, setSelectedRows] = useState({}) const [selectedRows, setSelectedRows] = useState({})
@ -29,7 +46,7 @@ export default function StepUp(props) {
// //
const [selectedValues, setSelectedValues] = useState({}) const [selectedValues, setSelectedValues] = useState({})
const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector)
// useCanvasPopupStatusController(6) // useCanvasPopupStatusController(6)
// const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore) // const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore)
// if (Object.keys(canvasPopupStatusState[6]).length !== 0) { // if (Object.keys(canvasPopupStatusState[6]).length !== 0) {
@ -37,34 +54,176 @@ export default function StepUp(props) {
// } // }
useEffect(() => { useEffect(() => {
// PCS console.log(allocationType)
fetchStepUpData()
if (allocationType === 'auto') {
// PCS
fetchAutoStepUpData()
} else {
// PCS
fetchPassiStepUpData()
}
}, []) }, [])
// PCS // PCS
const fetchStepUpData = async () => { const fetchAutoStepUpData = async () => {
try { try {
const params = { const params = {
useYn: props.getOptYn(), // Y/N ...props.getOptYn(), // Y/N
useModuleItemList: props.getUseModuleItemList(), // List useModuleItemList: props.getUseModuleItemList(), // List
roofSurfaceList: props.getRoofSurfaceList(), // roofSurfaceList: props.getRoofSurfaceList(), //
pcsItemList: props.getPcsItemList(), // PCS pcsItemList: props.getSelectedPcsItemList(), // PCS
} }
// PCS //
const res = await getPcsVoltageStepUpList(params) getPcsVoltageStepUpList(params).then((res) => {
if (res.result.resultCode === 'S') {
if (res?.result.code === 200 && res?.data) {
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
if (res?.result.code === 200 && res?.data) { // PCS SET
const dataArray = Array.isArray(res.data) ? res.data : [res.data] setStepUpListData(stepUpListData)
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET // PCS
setStepUpListData(stepUpListData) const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
// PCS //
const formattedOptCodes = formatOptionCodes(res.data.optionList) //stepUpListData[0].pcsItemList.forEach((pcsItem) => {
setOptCodes(formattedOptCodes) stepUpListData[0].pcsItemList.forEach((pcsItem) => {
const selectedSerQty = pcsItem.serQtyList.find((serQty) => serQty.selected)
if (selectedSerQty) {
selectedSerQty.roofSurfaceList.forEach((roofSurface) => {
const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0]
const moduleIds = targetSurface.modules.map((module) => module.id)
//
canvas
.getObjects()
.filter((obj) => moduleIds.includes(obj.parentId))
.forEach((text) => canvas.remove(text))
//
roofSurface.moduleList.forEach((module) => {
const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0]
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fill: 'black',
fontSize: 20,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
selectable: false,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
})
})
}
})
canvas.renderAll()
} else {
swalFire({
title: res.result.resultMsg,
type: 'alert',
})
}
}
})
} catch (error) {
console.error('Error fetching step up data:', error)
}
}
// PCS
const fetchPassiStepUpData = async () => {
try {
// 1-1 2-2
// canvas
// .getObjects()
// .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuit)
// .map((module) => module.circuitNumber)
//
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// PCS
const pcsSummary = {}
// PCS
modules.forEach((module) => {
if (!module.circuit || !module.pcsItemId) return
if (!pcsSummary[module.pcsItemId]) {
pcsSummary[module.pcsItemId] = {
circuits: {},
totalModules: 0,
}
}
const circuitNumber = module.circuitNumber
if (!pcsSummary[module.pcsItemId].circuits[circuitNumber]) {
pcsSummary[module.pcsItemId].circuits[circuitNumber] = 0
}
pcsSummary[module.pcsItemId].circuits[circuitNumber]++
pcsSummary[module.pcsItemId].totalModules++
})
const params = {
useModuleItemList: props.getUseModuleItemList(),
pcsItemList: getSelectedPcsItemList(),
} }
// PCS
getPcsConnOptionItemList(params).then((res) => {
if (res?.result.code === 200 && res?.data) {
// PCS serQtyList
const pcsItemListWithSerQty = res.data.pcsItemList.map((pcsItem) => {
const pcsData = pcsSummary[pcsItem.itemId] || { circuits: {}, totalModules: 0 }
const circuitCounts = Object.values(pcsData.circuits)
return {
...pcsItem,
serQtyList: [
{
//
serQty: circuitCounts.length > 0 ? Math.max(...circuitCounts) : 0,
//
paralQty: Object.keys(pcsData.circuits).length || 0,
rmdYn: 'Y',
usePossYn: 'Y',
roofSurfaceList: props.getRoofSurfaceList(),
},
],
}
})
// Update res.data with modified pcsItemList
res.data.pcsItemList = pcsItemListWithSerQty
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
}
})
} catch (error) { } catch (error) {
console.error('Error fetching step up data:', error) console.error('Error fetching step up data:', error)
} }
@ -79,16 +238,6 @@ export default function StepUp(props) {
})) }))
} }
// // PCS
// const formatStepUpListData = (dataArray = []) => {
// return dataArray?.map((stepUps) => ({
// ...stepUps,
// optionList: formatOptionList(stepUps.optionList),
// pcsItemList: formatPcsItemList(stepUps.pcsItemList),
// selectedPcsItem: formatPcsItemList(stepUps.pcsItemList),
// }))
// }
// PCS // PCS
const formatStepUpListData = (dataArray = []) => { const formatStepUpListData = (dataArray = []) => {
const formattedData = dataArray?.map((stepUps) => ({ const formattedData = dataArray?.map((stepUps) => ({
@ -98,39 +247,6 @@ export default function StepUp(props) {
selectedPcsItem: formatPcsItemList(stepUps.pcsItemList), selectedPcsItem: formatPcsItemList(stepUps.pcsItemList),
})) }))
// selectedValues
const initialSelectedValues = {}
formattedData.forEach((stepUp) => {
stepUp.pcsItemList.forEach((pcsItem, pcsIdx) => {
const pcsKey = `${stepUp.id}_${pcsIdx}`
// (rmdYn === 'Y')
const recommendedRow = pcsItem.serQtyList.find((item) => item.rmdYn === 'Y')
if (recommendedRow) {
const selectionData = {
stepUpId: pcsItem.goodsNo,
pcsInfo: {
itemId: pcsItem.itemId,
goodsNo: pcsItem.goodsNo,
pcsMkrCd: pcsItem.pcsMkrCd,
pcsSerCd: pcsItem.pcsSerCd,
},
allocation: {
serQty: recommendedRow.serQty,
paralQty: recommendedRow.paralQty,
},
}
initialSelectedValues[stepUp.id] = {
...initialSelectedValues[stepUp.id],
[pcsKey]: selectionData,
}
}
})
})
setSelectedValues(initialSelectedValues)
return formattedData return formattedData
} }
@ -145,12 +261,13 @@ export default function StepUp(props) {
// PCS // PCS
const formatPcsItemList = (pcsItemList = []) => { const formatPcsItemList = (pcsItemList = []) => {
return pcsItemList?.map((item) => ({ return pcsItemList?.map((item, index) => ({
goodsNo: item.goodsNo ? item.goodsNo : '', goodsNo: item.goodsNo ? item.goodsNo : '',
itemId: item.itemId ? item.itemId : '', itemId: item.itemId ? item.itemId : '',
itemNm: item.itemNm ? item.itemNm : '', itemNm: item.itemNm ? item.itemNm : '',
pcsMkrCd: item.pcsMkrCd ? item.pcsMkrCd : '', pcsMkrCd: item.pcsMkrCd ? item.pcsMkrCd : '',
pcsSerCd: item.pcsSerCd ? item.pcsSerCd : '', pcsSerCd: item.pcsSerCd ? item.pcsSerCd : '',
uniqueIndex: `${item.itemId}_${index}`, // ( PCS )
connList: formatConnList(item.connList), connList: formatConnList(item.connList),
serQtyList: formatSerQtyList(item.serQtyList), serQtyList: formatSerQtyList(item.serQtyList),
})) }))
@ -173,11 +290,13 @@ export default function StepUp(props) {
// PCS // PCS
const formatSerQtyList = (serQtyList = []) => { const formatSerQtyList = (serQtyList = []) => {
return serQtyList?.map((qty) => ({ return serQtyList?.map((qty) => ({
code: uuidv4(),
serQty: qty.serQty ? qty.serQty : 0, serQty: qty.serQty ? qty.serQty : 0,
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), roofSurfaceList: formatRoofSurfaceList(qty.roofSurfaceList),
selected: qty.rmdYn === 'Y',
})) }))
} }
@ -209,79 +328,139 @@ export default function StepUp(props) {
} }
// //
const handleRowClick = (goodsNo, pcsIdx, serQtyIdx, serQty, paralQty) => { const handleRowClick = (mainIdx, subIdx) => {
const rowKey = `${goodsNo}_${pcsIdx}_${serQtyIdx}` //
const pcsKey = `${goodsNo}_${pcsIdx}` if (allocationType !== 'auto') return
console.log('goodsNo >> ', goodsNo, serQty, paralQty) let tempStepUpListData = [...stepUpListData]
let selectedData = {}
// PCS tempStepUpListData[0].pcsItemList[mainIdx].serQtyList.forEach((item, index) => {
const pcsItem = stepUpListData.find((stepUp) => stepUp.pcsItemList.find((item) => item.goodsNo === goodsNo))?.pcsItemList[pcsIdx] if (index === subIdx) {
selectedData = item
}
item.selected = index === subIdx
})
//
setStepUpListData(tempStepUpListData)
if (!pcsItem) { // console.log('🚀 ~ handleRowClick ~ tempStepUpListData:', tempStepUpListData)
console.error('PCS item not found:', { goodsNo, pcsIdx }) // console.log('🚀 ~ handleRowClick ~ selectedData:', selectedData)
return
}
// - // PCS 2 PCS
const selectionData = { if (stepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) {
goodsNo: goodsNo, //
pcsInfo: { const params = {
itemId: pcsItem?.itemId, ...props.getOptYn(), // Y/N
goodsNo: pcsItem?.goodsNo, useModuleItemList: props.getUseModuleItemList(), // List
pcsMkrCd: pcsItem?.pcsMkrCd, roofSurfaceList: props.getRoofSurfaceList(), //
pcsSerCd: pcsItem?.pcsSerCd, pcsItemList: props.getSelectedPcsItemList().map((pcsItem, index) => {
}, // PCS
allocation: { // tempStepUpListData PCS
serQty: serQty, // uniqueIndex
paralQty: paralQty, const matchingPcsItem = tempStepUpListData[0].pcsItemList.find((item) => item.uniqueIndex === `${pcsItem.itemId}_${index}`)
},
}
// // serQty
setSelectedValues((prev) => ({ const selectedSerQty = matchingPcsItem?.serQtyList.find((serQty) => serQty.selected)?.serQty || 0
...prev,
[goodsNo]: {
...prev[goodsNo],
[pcsKey]: selectionData,
},
}))
// return {
if (props.onValuesSelected) { ...pcsItem,
props.onValuesSelected(selectionData) applySerQty: selectedSerQty,
} }
}),
setSelectedRows((prev) => {
// stepUpId
const currentStepUpSelections = prev[goodsNo] || {}
// ,
if (currentStepUpSelections[pcsKey] === rowKey) {
return prev
} }
return { // PCS 1 2 3 PCS serQty 0 API
...prev, if (params.pcsItemList.length !== 1 && (params.pcsItemList[1]?.applySerQty !== 0 || params.pcsItemList[2]?.applySerQty) !== 0) {
[goodsNo]: { // PCS
...currentStepUpSelections, //const res = await getPcsVoltageStepUpList(params)
[pcsKey]: rowKey, //getPcsManualConfChk(params).then((res) => {
}, getPcsVoltageStepUpList(params).then((res) => {
if (res?.result.code === 200 && res?.data) {
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
}
})
} }
}
selectedData.roofSurfaceList.forEach((roofSurface) => {
const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0]
const moduleIds = targetSurface.modules.map((module) => {
return module.id
})
targetSurface.modules.map((module) => {
module.circuit = null
module.circuitNumber = null
module.pcsItemId = null
})
//
canvas
.getObjects()
.filter((obj) => moduleIds.includes(obj.parentId))
.map((text) => {
canvas.remove(text)
})
//
canvas.renderAll()
roofSurface.moduleList.forEach((module) => {
const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0]
if (module.circuit === '') return
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fill: 'black',
fontSize: 20,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
})
}) })
// , canvas.renderAll()
setIsManualSelection((prev) => ({
...prev,
[goodsNo]: {
...prev[goodsNo],
[pcsKey]: true,
},
}))
} }
// //
const getCurrentSelections = () => { const getCurrentSelections = () => {
const selectedValues = stepUpListData[0].pcsItemList.forEach((item) => {
item.serQtyList.filter((serQty) => serQty.selected)
return item.serQtyList.map((serQty) => {
return {
pcsMkrCd: serQty.pcsMkrCd,
pcsSerCd: serQty.pcsSerCd,
pcsItemId: serQty.itemId,
pcsOptCd: seletedOption,
paralQty: serQty.paralQty,
connections: {
connItemId: item.connList[0].itemId,
},
}
})
})
return selectedValues return selectedValues
} }
@ -310,7 +489,7 @@ export default function StepUp(props) {
{/* 3개일때 className = by-max */} {/* 3개일때 className = by-max */}
{stepUpListData.map((stepUp, index) => ( {stepUpListData.map((stepUp, index) => (
<div key={index} className={`module-table-box ${stepUp.pcsItemList.length === 3 ? 'by-max' : ''}`}> <div key={index} className={`module-table-box ${stepUp.pcsItemList.length === 3 ? 'by-max' : ''}`}>
{stepUp?.pcsItemList.map((_, idx) => ( {stepUp?.pcsItemList.map((pcsItem, idx) => (
<div key={idx} className="module-table-inner"> <div key={idx} className="module-table-inner">
<div className="mb-box"> <div className="mb-box">
<div className="circuit-table-tit">{stepUp.pcsItemList[idx].goodsNo}</div> <div className="circuit-table-tit">{stepUp.pcsItemList[idx].goodsNo}</div>
@ -323,20 +502,13 @@ export default function StepUp(props) {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{stepUp.pcsItemList[idx].serQtyList.map((item, serQtyIdx) => { {pcsItem.serQtyList.map((item, serQtyIdx) => {
const rowKey = `${stepUp.pcsItemList[idx].goodsNo}_${idx}_${serQtyIdx}`
const pcsKey = `${stepUp.pcsItemList[idx].goodsNo}_${idx}`
return ( return (
<tr <tr
key={rowKey} key={`row-${serQtyIdx}`}
className={`${ className={`${item.selected ? 'on' : ''}`}
(!isManualSelection[stepUp.pcsItemList[idx].goodsNo]?.[pcsKey] && item.rmdYn === 'Y') || onClick={() => handleRowClick(idx, serQtyIdx)}
(selectedRows[stepUp.pcsItemList[idx].goodsNo] && selectedRows[stepUp.pcsItemList[idx].goodsNo][pcsKey] === rowKey) style={{ cursor: allocationType === 'auto' ? 'pointer' : 'default' }}
? 'on'
: ''
}`}
onClick={() => handleRowClick(stepUp.pcsItemList[idx].goodsNo, idx, serQtyIdx, item.serQty, item.paralQty)}
style={{ cursor: 'pointer' }}
> >
<td className="al-r">{item.serQty}</td> <td className="al-r">{item.serQty}</td>
<td className="al-r">{item.paralQty}</td> <td className="al-r">{item.paralQty}</td>
@ -428,7 +600,18 @@ export default function StepUp(props) {
{optCodes.length > 0 && ( {optCodes.length > 0 && (
<div className="grid-select mr10"> <div className="grid-select mr10">
{/* <QSelectBox title={'電力検出ユニット (モニター付き)'} /> */} {/* <QSelectBox title={'電力検出ユニット (モニター付き)'} /> */}
<QSelectBox options={optCodes} title={optCodes[0].name} value={optCodes[0].name} sourceKey="code" targetKey="code" showKey="name" /> <QSelectBox
//options={optCodes}
options={optCodes.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.name : roof.nameJp }
})}
title={globalLocale === 'ko' ? optCodes[0].name : optCodes[0].nameJp}
value={seletedOption}
sourceKey="code"
targetKey="code"
showKey="name"
onChange={(e) => setSeletedOption(e)}
/>
</div> </div>
)} )}
</div> </div>

View File

@ -1,17 +0,0 @@
import { useMessage } from '@/hooks/useMessage'
export default function AutoCircuitAllocation() {
const { getMessage } = useMessage()
return (
<div className="module-table-box">
<div className="module-table-inner">
<div className="circuit-check-inner">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra01" checked={true} />
<label htmlFor="ra01">{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}</label>
</div>
</div>
</div>
</div>
)
}

View File

@ -1,46 +1,40 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider' import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useMasterController } from '@/hooks/common/useMasterController' import { useMasterController } from '@/hooks/common/useMasterController'
import { useModule } from '@/hooks/module/useModule'
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { canvasState } from '@/store/canvasAtom' 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 { circuitNumDisplaySelector } from '@/store/settingAtom'
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
export default function PassivityCircuitAllocation(props) { export default function PassivityCircuitAllocation(props) {
const { const {
tabNum,
setTabNum,
selectedModels, selectedModels,
setSelectedModels,
getOptYn: getApiProps, getOptYn: getApiProps,
getUseModuleItemList: getSelectedModuleList, getUseModuleItemList: getSelectedModuleList,
getSelectModelList: getSelectModelList, getSelectModelList: getSelectModelList,
getRoofSurfaceList,
getModelList,
} = props } = props
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
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, setModuleStatistics] = useRecoilState(moduleStatisticsState)
// 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, footer } = useRecoilValue(moduleStatisticsState)
const [header, setHeader] = useState(moduleStatistics.header)
const [rows, setRows] = useState(moduleStatistics.rows)
const [footer, setFooter] = useState(['합계'])
const [circuitNumber, setCircuitNumber] = useState(1) const [circuitNumber, setCircuitNumber] = useState(1)
const [targetModules, setTargetModules] = useState([]) const [targetModules, setTargetModules] = useState([])
const { getPcsManualConfChk } = useMasterController() const { getPcsManualConfChk } = useMasterController()
const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector)
const { setModuleStatisticsData } = useCircuitTrestle()
useEffect(() => { useEffect(() => {
console.log('header, rows', header, rows) setModuleStatisticsData()
console.log('selectedModels', selectedModels)
// setSurfaceInfo()
setTableData()
if (!managementState) { if (!managementState) {
setManagementState(managementStateLoaded) setManagementState(managementStateLoaded)
} }
@ -82,82 +76,15 @@ export default function PassivityCircuitAllocation(props) {
canvas.renderAll() canvas.renderAll()
} }
const setSurfaceInfo = () => {
const surfaces = canvas.getObjects().filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name)
// setHeaders([header[0], { name: '', prop: 'circuit' }, ...header.slice(1)])
setRows(
rows.map((row) => {
return {
...row,
circuit: '',
}
}),
)
let totals = {}
rows.forEach((row) => {
if (header.length === 4) {
if (!totals[header[2].prop]) totals[header[2].prop] = 0
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]]
}
})
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)
// -> ->
// wpOut
// setModuleData({
// header: [
// { name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' },
// { name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
// ...selectedModules.itemList.map((module) => {
// return {
// name: module.itemNm,
// prop: module.itemId,
// }
// }),
// {
// name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`,
// prop: 'powerGeneration',
// },
// ],
// rows: rows,
// })
}
const handleCircuitNumberFix = () => { const handleCircuitNumberFix = () => {
let uniqueCircuitNumbers = null let uniqueCircuitNumbers = [
...new Set(
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuitNumber)
.map((obj) => obj.circuitNumber),
),
]
if (!circuitNumber || circuitNumber === 0) { if (!circuitNumber || circuitNumber === 0) {
swalFire({ swalFire({
text: '회로번호를 1 이상입력해주세요.', text: '회로번호를 1 이상입력해주세요.',
@ -173,16 +100,8 @@ export default function PassivityCircuitAllocation(props) {
}) })
return return
} else if (selectedModels.length > 1) { } else if (selectedModels.length > 1) {
uniqueCircuitNumbers = [
...new Set(
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuitNumber)
.map((obj) => obj.circuitNumber),
),
]
let result = false let result = false
uniqueCircuitNumbers.forEach((number) => { uniqueCircuitNumbers.forEach((number) => {
if ( if (
number.split('-')[1] === circuitNumber + ')' && number.split('-')[1] === circuitNumber + ')' &&
@ -201,11 +120,15 @@ export default function PassivityCircuitAllocation(props) {
} }
} }
let tempSelectedPcs = { ...selectedPcs }
canvas.discardActiveObject() canvas.discardActiveObject()
canvas canvas
.getObjects() .getObjects()
.filter((obj) => targetModules.includes(obj.id)) .filter((obj) => targetModules.includes(obj.id))
.forEach((obj) => { .forEach((obj) => {
if (obj.circuit) {
canvas.remove(obj.circuit)
}
const moduleCircuitText = new fabric.Text(getCircuitNumber(), { const moduleCircuitText = new fabric.Text(getCircuitNumber(), {
left: obj.left + obj.width / 2, left: obj.left + obj.width / 2,
top: obj.top + obj.height / 2, top: obj.top + obj.height / 2,
@ -217,21 +140,33 @@ export default function PassivityCircuitAllocation(props) {
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: 'circuitNumber', name: 'circuitNumber',
selectable: false,
parentId: obj.id, parentId: obj.id,
circuitInfo: selectedPcs, circuitInfo: selectedPcs,
visible: isDisplayCircuitNumber,
}) })
obj.set({ obj.set({
strokeWidth: 0.3, strokeWidth: 0.3,
}) })
obj.pcsItemId = selectedPcs.itemId obj.pcsItemId = selectedPcs.itemId
obj.pcsItemCode = selectedPcs.id
obj.circuit = moduleCircuitText obj.circuit = moduleCircuitText
obj.circuitNumber = getCircuitNumber() obj.circuitNumber = getCircuitNumber()
tempSelectedPcs.used = true
setSelectedPcs(tempSelectedPcs)
canvas.add(moduleCircuitText) canvas.add(moduleCircuitText)
}) })
let pcsList = JSON.parse(JSON.stringify(selectedModels)).map((model) => {
if (model.id === selectedPcs.id) {
model.isUsed = true
}
return model
})
const roofSurfaceList = canvas const roofSurfaceList = canvas
.getObjects() .getObjects()
.filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name) .filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0)
.map((surface) => { .map((surface) => {
return { return {
roofSurfaceId: surface.id, roofSurfaceId: surface.id,
@ -247,7 +182,8 @@ export default function PassivityCircuitAllocation(props) {
} }
}) })
const pcsItemList = selectedModels.map((model) => { const usedPcses = pcsList.filter((model) => model.isUsed)
const pcsItemList = usedPcses.map((model, index) => {
return { return {
pcsMkrCd: model.pcsMkrCd, pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd, pcsSerCd: model.pcsSerCd,
@ -257,7 +193,7 @@ export default function PassivityCircuitAllocation(props) {
serQtyList: [ serQtyList: [
{ {
serQty: targetModules.length, serQty: targetModules.length,
paralQty: 0, paralQty: uniqueCircuitNumbers.length,
rmdYn: 'Y', rmdYn: 'Y',
usePossYn: 'Y', usePossYn: 'Y',
roofSurfaceList: roofSurfaceList, roofSurfaceList: roofSurfaceList,
@ -273,7 +209,7 @@ export default function PassivityCircuitAllocation(props) {
} }
getPcsManualConfChk(params).then((res) => { getPcsManualConfChk(params).then((res) => {
if (res.resultCode === 'E') { if (res?.resultCode === 'E') {
swalFire({ swalFire({
text: res.resultMsg, text: res.resultMsg,
type: 'alert', type: 'alert',
@ -292,13 +228,16 @@ export default function PassivityCircuitAllocation(props) {
canvas.renderAll() canvas.renderAll()
}, },
}) })
setSelectedPcs({ ...selectedPcs, used: false })
setTargetModules([])
return return
} }
setSelectedModels(pcsList)
setTargetModules([]) setTargetModules([])
setCircuitNumber(+circuitNumber + 1) setCircuitNumber(+circuitNumber + 1)
setTableData() setModuleStatisticsData()
}) })
} }
@ -310,116 +249,29 @@ export default function PassivityCircuitAllocation(props) {
} }
} }
const setTableData = () => {
const tempHeader = [
{ name: getMessage('simulator.table.sub1'), prop: 'name' },
{ name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
...selectedModules.itemList.map((module) => {
return {
name: module.itemNm,
prop: module.itemId,
}
}),
{ name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' },
]
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const surfaceIds = surfaces.map((surface) => surface.parentId)
const surfaceObjects = {}
const rows = surfaces.map((surface) => {
const moduleObject = {}
surfaceObjects[surface.id] = {
roofSurface: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText,
circuit: '-',
amount: 0,
wpOut: 0,
circuits: {},
}
surface.modules.forEach((module) => {
if (!surfaceObjects[surface.id][module.moduleInfo.itemId]) {
//
surfaceObjects[surface.id][module.moduleInfo.itemId] = 0 //
}
surfaceObjects[surface.id][module.moduleInfo.itemId]++
surfaceObjects[surface.id].wpOut += +module.moduleInfo.wpOut
if (module.circuit) {
if (!surfaceObjects[surface.id].circuits[module.circuitNumber]) {
surfaceObjects[surface.id].circuits[module.circuitNumber] = {
circuit: module.circuitNumber,
wpOut: 0,
circuits: { wpOut: 0 },
}
if (!surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]) {
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId] = 0
}
}
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]++
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits.wpOut += +module.moduleInfo.wpOut
surfaceObjects[surface.id].wpOut -= +module.moduleInfo.wpOut
surfaceObjects[surface.id][module.moduleInfo.itemId]--
}
})
})
console.log('rows', rows)
console.log('surfaceObjects', surfaceObjects)
let tempRows = []
Object.keys(surfaceObjects).forEach((key) => {
let tempRow = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuit,
wpOut: surfaceObjects[key].wpOut,
}
selectedModules.itemList.forEach((module) => {
tempRow[module.itemId] = surfaceObjects[key][module.itemId]
})
tempRows.push(tempRow)
Object.keys(surfaceObjects[key].circuits).forEach((circuit) => {
let row = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuits[circuit].circuit,
wpOut: surfaceObjects[key].circuits[circuit].circuits.wpOut,
}
selectedModules.itemList.forEach((module) => {
row[module.itemId] = surfaceObjects[key].circuits[circuit].circuits[module.itemId]
})
tempRows.push(row)
})
})
const tempFooter = {
name: '총합',
circuit: '-',
wpOut: tempRows.reduce((acc, row) => acc + row.wpOut, 0),
}
selectedModules.itemList.forEach((module) => {
tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0)
})
setHeader(tempHeader)
setRows(tempRows.filter((row) => row.wpOut !== 0))
setFooter(tempFooter)
setModuleStatistics({ header: tempHeader, rows: tempRows.filter((row) => row.wpOut !== 0), footer: tempFooter })
}
const initSelectedPcsCircuitNumber = () => { const initSelectedPcsCircuitNumber = () => {
swalFire({ swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.init.info'), title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset.info'),
type: 'confirm', type: 'confirm',
icon: 'warning', icon: 'warning',
confirmFn: () => { confirmFn: () => {
const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id) const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id)
const circuitNumbers = circuitModules.map((obj) => {
const circuitNumber = obj.circuitNumber.replace(/[()]/g, '').split('-')
return parseInt(circuitNumber[circuitNumber.length - 1])
})
const minCircuitNumber = Math.min(...circuitNumbers)
canvas.remove(...circuitModules.map((module) => module.circuit)) canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => { circuitModules.forEach((obj) => {
obj.circuit = null obj.circuit = null
obj.pcsItemId = null obj.pcsItemId = null
}) })
setCircuitNumber(minCircuitNumber)
setTargetModules([]) setTargetModules([])
canvas.renderAll() canvas.renderAll()
canvas.discardActiveObject() canvas.discardActiveObject()
setModuleStatisticsData()
}, },
}) })
} }
@ -427,7 +279,7 @@ export default function PassivityCircuitAllocation(props) {
const initAllPcsCircuitNumber = () => { const initAllPcsCircuitNumber = () => {
canvas.discardActiveObject() canvas.discardActiveObject()
swalFire({ swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.init.setting.info'), title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info'),
type: 'confirm', type: 'confirm',
icon: 'warning', icon: 'warning',
confirmFn: () => { confirmFn: () => {
@ -439,9 +291,9 @@ export default function PassivityCircuitAllocation(props) {
obj.circuit = null obj.circuit = null
obj.pcsItemId = null obj.pcsItemId = null
}) })
setTargetModules([])
canvas.renderAll() canvas.renderAll()
setTargetModules([])
setModuleStatisticsData()
}, },
}) })
} }
@ -479,9 +331,7 @@ 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}>
{typeof footer[header.prop] === 'number' {footer[header.prop]}
? footer[header.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: footer[header.prop]}
</td> </td>
))} ))}
</tr> </tr>
@ -509,7 +359,7 @@ export default function PassivityCircuitAllocation(props) {
onChange={() => setSelectedPcs(model)} onChange={() => setSelectedPcs(model)}
/> />
<label htmlFor={`ra0${index + 1}`}> <label htmlFor={`ra0${index + 1}`}>
{model.itemNm} ( {model.goodsNo} (
{getMessage( {getMessage(
'modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info', 'modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info',
managementState?.coldRegionFlg === '1' ? [model.serMinQty, model.serColdZoneMaxQty] : [model.serMinQty, model.serMaxQty], managementState?.coldRegionFlg === '1' ? [model.serMinQty, model.serColdZoneMaxQty] : [model.serMinQty, model.serMaxQty],
@ -518,18 +368,6 @@ export default function PassivityCircuitAllocation(props) {
</label> </label>
</div> </div>
))} ))}
{/* <div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra01" />
<label htmlFor="ra01">HQJP-KA55-5 (標準回路2枚10)</label>
</div>
<div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra02" />
<label htmlFor="ra02">HQJP-KA55-5 (標準回路2枚10)</label>
</div>
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra03" />
<label htmlFor="ra03">HQJP-KA55-5 (標準回路2枚10)</label>
</div>*/}
</div> </div>
</div> </div>
</div> </div>

View File

@ -36,7 +36,7 @@ export default function PanelEdit(props) {
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule() const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule()
useEffect(() => { useEffect(() => {
if (canvas) { if (!canvas) {
const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module') // selectedObj const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module') // selectedObj
isSetupModules.forEach((obj) => obj.set({ lockMovementX: false, lockMovementY: false })) isSetupModules.forEach((obj) => obj.set({ lockMovementX: false, lockMovementY: false }))
} }
@ -52,18 +52,30 @@ export default function PanelEdit(props) {
}) })
return return
} }
debugger
const completeSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.isComplete)
if (completeSurfaces.length > 0) {
swalFire({
title: getMessage('modal.module.can.not.edit'),
type: 'alert',
icon: 'error',
})
return
}
switch (type) { switch (type) {
case PANEL_EDIT_TYPE.MOVE: case PANEL_EDIT_TYPE.MOVE:
moduleMove(length, direction) moduleMove(length, direction)
break break
case PANEL_EDIT_TYPE.MOVE_ALL: case PANEL_EDIT_TYPE.MOVE_ALL:
moduleMoveAll(length, direction) moduleMoveAll(length, direction, props.arrayData)
break break
case PANEL_EDIT_TYPE.COPY: case PANEL_EDIT_TYPE.COPY:
moduleCopy(length, direction) moduleCopy(length, direction)
break break
case PANEL_EDIT_TYPE.COPY_ALL: case PANEL_EDIT_TYPE.COPY_ALL:
moduleCopyAll(length, direction) moduleCopyAll(length, direction, props.arrayData)
break break
case PANEL_EDIT_TYPE.COLUMN_MOVE: case PANEL_EDIT_TYPE.COLUMN_MOVE:
moduleMultiMove('column', length, direction) moduleMultiMove('column', length, direction)

View File

@ -1,10 +1,16 @@
'use client' 'use client'
import { useState } from 'react' import { useEffect, useState } from 'react'
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 { moduleStatisticsState } from '@/store/circuitTrestleAtom' import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useModule } from '@/hooks/module/useModule'
import { useEavesGableEdit } from '@/hooks/roofcover/useEavesGableEdit'
import { canvasState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
export default function PanelBatchStatistics() { export default function PanelBatchStatistics() {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -13,7 +19,14 @@ export default function PanelBatchStatistics() {
x: 0, x: 0,
y: 30, y: 30,
}) })
const canvas = useRecoilValue(canvasState)
const { header, rows, footer } = useRecoilValue(moduleStatisticsState) const { header, rows, footer } = useRecoilValue(moduleStatisticsState)
const { setModuleStatisticsData } = useCircuitTrestle()
const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
useEffect(() => {
if (moduleSelectionDataStore && moduleSelectionDataStore.module) setModuleStatisticsData()
}, [])
return ( return (
<WithDraggable isShow={true} handle=".penal-wrap" pos={pos}> <WithDraggable isShow={true} handle=".penal-wrap" pos={pos}>
@ -33,9 +46,7 @@ export default function PanelBatchStatistics() {
{rows.map((row, index) => ( {rows.map((row, index) => (
<tr key={`statistic-row-${index}`}> <tr key={`statistic-row-${index}`}>
{header.map((item, i) => ( {header.map((item, i) => (
<td key={`statistic-col-${i}`}> <td key={`statistic-col-${i}`}>{row[item.prop] ?? 0}</td>
{typeof row[item.prop] === 'number' ? row[item.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 }) : row[item.prop]}
</td>
))} ))}
</tr> </tr>
))} ))}

View File

@ -258,7 +258,11 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
<div className="grid-select no-flx" style={{ width: '171px' }}> <div className="grid-select no-flx" style={{ width: '171px' }}>
<QSelectBox <QSelectBox
title={ title={
currentRoof?.roofSizeSet === '3' ? getMessage('modal.placement.initial.setting.size.none.pitch') : currentRoof?.roofMatlNm currentRoof?.roofSizeSet === '3'
? getMessage('modal.placement.initial.setting.size.none.pitch')
: globalLocale === 'ko'
? currentRoof?.roofMatlNm
: currentRoof?.roofMatlNmJp
} }
//ref={roofRef.roofCd} //ref={roofRef.roofCd}
options={roofMaterials.map((roof) => { options={roofMaterials.map((roof) => {

View File

@ -31,6 +31,7 @@ export default function ContextRoofAllocationSetting(props) {
handleSaveContext, handleSaveContext,
currentRoofList, currentRoofList,
handleChangeInput, handleChangeInput,
handleChangePitch,
} = useRoofAllocationSetting(id) } = useRoofAllocationSetting(id)
const { findCommonCode } = useCommonCode() const { findCommonCode } = useCommonCode()
@ -45,114 +46,82 @@ export default function ContextRoofAllocationSetting(props) {
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lr mount`}> <div className={`modal-pop-wrap lr mount`}>
<div className="modal-head modal-handle"> {currentRoofList && (
<h1 className="title">{getMessage('plan.menu.estimate.roof.alloc')}</h1> <>
<button className="modal-close" onClick={() => closePopup(id)}> <div className="modal-head modal-handle">
닫기 <h1 className="title">{getMessage('plan.menu.estimate.roof.alloc')}</h1>
</button> <button className="modal-close" onClick={() => closePopup(id)}>
</div> 닫기
<div className="modal-body"> </button>
<div className="properties-guide">{getMessage('modal.roof.alloc.info')}</div>
<div className="allocation-select-wrap">
<span>{getMessage('modal.roof.alloc.select.roof.material')}</span>
<div className="grid-select">
<QSelectBox
options={roofMaterials}
value={roofMaterials[0]}
onChange={(e) => {
// const selected = roofMaterials.find((roofMaterial) => roofMaterial.roofMatlCd === e.id)
setCurrentRoofMaterial(e)
}}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
/>
</div> </div>
<button <div className="modal-body">
className="allocation-edit" <div className="properties-guide">{getMessage('modal.roof.alloc.info')}</div>
onClick={() => { <div className="allocation-select-wrap">
onAddRoofMaterial() <span>{getMessage('modal.roof.alloc.select.roof.material')}</span>
}} <div className="grid-select">
> <QSelectBox
<i className="edit-ico"></i> options={roofMaterials}
{getMessage('modal.common.add')} value={roofMaterials[0]}
</button> onChange={(e) => {
</div> // const selected = roofMaterials.find((roofMaterial) => roofMaterial.roofMatlCd === e.id)
<div className="grid-option-wrap"> setCurrentRoofMaterial(e)
{currentRoofList.length > 0 && }}
currentRoofList.map((roof, index) => { showKey={'roofMatlNm'}
return ( sourceKey={'roofMatlCd'}
<div className="grid-option-box" key={index}> targetKey={'roofMatlCd'}
<div className="d-check-radio pop no-text"> />
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} /> </div>
<label <button
htmlFor="ra01" className="allocation-edit"
onClick={(e) => { onClick={() => {
handleDefaultRoofMaterial(index) onAddRoofMaterial()
}} }}
></label> >
</div> <i className="edit-ico"></i>
<div className="grid-option-block-form"> {getMessage('modal.common.add')}
<div className="block-box"> </button>
<div className="flex-ment"> </div>
<div className="grid-select" style={{ width: '248px' }}> <div className="grid-option-overflow">
<QSelectBox <div className="grid-option-wrap">
options={roofMaterials} {currentRoofList.map((roof, index) => {
value={roof} return (
showKey={'roofMatlNm'} <div className="grid-option-box" key={index}>
sourceKey={'roofMatlCd'} <div className="d-check-radio pop no-text">
targetKey={'roofMatlCd'} <input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
onChange={(e) => handleChangeRoofMaterial(e, index)} <label
/> htmlFor="ra01"
</div> onClick={(e) => {
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>} handleDefaultRoofMaterial(index)
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>} }}
></label>
</div> </div>
</div> <div className="grid-option-block-form">
<div className="block-box"> <div className="block-box">
<div className="flex-ment">
<span>{getMessage('slope')}</span>
<div className="input-grid" style={{ width: '214px' }}>
<input
type="text"
className="input-origin block"
onChange={(e) => {
handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
}}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/>
</div>
<span>{pitchText}</span>
</div>
</div>
{(roof.widAuth || roof.lenAuth) && (
<div className="block-box">
{roof.widAuth && (
<div className="flex-ment"> <div className="flex-ment">
<span>W</span> <div className="grid-select">
<div className="input-grid" style={{ width: '100px' }}> <QSelectBox
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} /> options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div> </div>
{index === 0 && <span className="absol dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && (
<span className="absol">
<button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>
</span>
)}
</div> </div>
)} </div>
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
</div>
)}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box">
{roof.raftAuth && ( {roof.raftAuth && (
<div className="block-box"> <div className="block-box">
<div className="flex-ment"> <div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span> <span>{getMessage('modal.placement.initial.setting.rafter')}</span>
{raftCodes.length > 0 && ( {raftCodes.length > 0 && (
<div className="grid-select" style={{ width: '160px' }}> <div className="grid-select">
<QSelectBox <QSelectBox
options={raftCodes} options={raftCodes}
value={roof} value={roof}
@ -165,55 +134,116 @@ export default function ContextRoofAllocationSetting(props) {
</div> </div>
</div> </div>
)} )}
{(roof.widAuth || roof.lenAuth) && (
<>
{roof.widAuth && (
<div className="block-box">
<div className="flex-ment">
<span>W</span>
<div className="input-grid">
<input
type="text"
className="input-origin block"
defaultValue={roof.width}
readOnly={roof.widAuth === 'R'}
onChange={(e) => {
handleChangeInput(e, 'width', index)
}}
/>
</div>
</div>
</div>
)}
{roof.lenAuth && (
<div className="block-box">
<div className="flex-ment">
<span>L</span>
<div className="input-grid">
<input
type="text"
className="input-origin block"
defaultValue={roof.length}
readOnly={roof.lenAuth === 'R'}
onChange={(e) => {
handleChangeInput(e, 'length', index)
}}
/>
</div>
</div>
</div>
)}
</>
)}
{roof.roofPchAuth && ( {roof.roofPchAuth && (
<div className="block-box"> <div className="block-box">
<div className="flex-ment"> <div className="flex-ment">
<span>{getMessage('hajebichi')}</span> <span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}> <div className="input-grid">
<input <input
type="text" type="text"
className="input-origin block" className="input-origin block"
value={parseInt(roof.hajebichi)} value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'} readOnly={roof.roofPchAuth === 'R'}
onChange={(e) => handleChangeInput(e, 'hajebichi', index)}
/> />
</div> </div>
</div> </div>
</div> </div>
)} )}
</div> <div className="block-box">
)} <div className="flex-ment">
<div className="block-box"> <span>{getMessage('slope')}</span>
<div className="icon-btn-wrap"> <div className="input-grid">
<button <input
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''} type="text"
onClick={() => { className="input-origin block"
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index) onChange={(e) => {
}} // handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
> handleChangePitch(e, index)
{getMessage('modal.roof.alloc.select.parallel')} }}
<i className="allocation01"></i> value={currentAngleType === 'slope' ? roof.pitch : roof.angle}
</button> defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
<button />
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''} </div>
onClick={() => { <span className="absol">{pitchText}</span>
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index) </div>
}} </div>
> <div className="block-box">
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i> <div className="icon-btn-wrap">
</button> <button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
</div>
</div>
</div> </div>
</div> </div>
</div> )
</div> })}
) </div>
})} </div>
</div> <div className="grid-btn-wrap">
<div className="grid-btn-wrap"> <button className="btn-frame modal act" onClick={handleSaveContext}>
<button className="btn-frame modal act" onClick={handleSaveContext}> {getMessage('modal.roof.alloc.apply')}
{getMessage('modal.roof.alloc.apply')} </button>
</button> </div>
</div> </div>
</div> </>
)}
<div className="modal-foot modal-handle"></div> <div className="modal-foot modal-handle"></div>
</div> </div>
</WithDraggable> </WithDraggable>

View File

@ -33,6 +33,7 @@ export default function RoofAllocationSetting(props) {
handleChangeLayout, handleChangeLayout,
currentRoofList, currentRoofList,
handleChangeInput, handleChangeInput,
handleChangePitch,
} = useRoofAllocationSetting(id) } = useRoofAllocationSetting(id)
const pitchText = useRecoilValue(pitchTextSelector) const pitchText = useRecoilValue(pitchTextSelector)
const { findCommonCode } = useCommonCode() const { findCommonCode } = useCommonCode()
@ -99,7 +100,7 @@ export default function RoofAllocationSetting(props) {
<div className="grid-option-block-form"> <div className="grid-option-block-form">
<div className="block-box"> <div className="block-box">
<div className="flex-ment"> <div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}> <div className="grid-select">
<QSelectBox <QSelectBox
options={roofMaterials} options={roofMaterials}
value={roof} value={roof}
@ -109,97 +110,104 @@ export default function RoofAllocationSetting(props) {
onChange={(e) => handleChangeRoofMaterial(e, index)} onChange={(e) => handleChangeRoofMaterial(e, index)}
/> />
</div> </div>
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>} {index === 0 && <span className="absol dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>} {index !== 0 && (
<span className="absol">
<button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>
</span>
)}
</div> </div>
</div> </div>
<div className="block-box">
<div className="flex-ment"> {roof.raftAuth && (
<span>{getMessage('slope')}</span>
<div className="input-grid" style={{ width: '214px' }}>
<input
type="text"
className="input-origin block"
onChange={(e) => {
handleChangeInput(e, currentAngleType === 'slope' ? 'pitch' : 'angle', index)
}}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/>
</div>
<span>{pitchText}</span>
</div>
</div>
{(roof.widAuth || roof.lenAuth) && (
<div className="block-box"> <div className="block-box">
{roof.widAuth && ( <div className="flex-ment">
<div className="flex-ment"> <span>{getMessage('modal.placement.initial.setting.rafter')}</span>
<span>W</span> {raftCodes.length > 0 && (
<div className="input-grid" style={{ width: '100px' }}> <div className="grid-select">
<input <QSelectBox
type="text" options={raftCodes}
className="input-origin block" value={roof}
defaultValue={roof.width} showKey={'clCodeNm'}
onChange={(e) => handleChangeInput(e, 'width', index)} sourceKey={'clCode'}
readOnly={roof.widAuth === 'R'} targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/> />
</div> </div>
</div> )}
)} </div>
{roof.lenAuth && (
<div className="flex-ment">
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input
type="text"
className="input-origin block"
defaultValue={roof.length}
onChange={(e) => handleChangeInput(e, 'length', index)}
readOnly={roof.lenAuth === 'R'}
/>
</div>
</div>
)}
</div> </div>
)} )}
{(roof.raftAuth || roof.roofPchAuth) && (
<div className="block-box"> {(roof.widAuth || roof.lenAuth) && (
{roof.raftAuth && ( <>
{roof.widAuth && (
<div className="block-box"> <div className="block-box">
<div className="flex-ment"> <div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span> <span>W</span>
{raftCodes.length > 0 && ( <div className="input-grid">
<div className="grid-select" style={{ width: '160px' }}>
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input <input
type="text" type="text"
className="input-origin block" className="input-origin block"
onChange={(e) => handleChangeInput(e, 'hajebichi', index)} defaultValue={roof.width}
value={parseInt(roof.hajebichi)} onChange={(e) => handleChangeInput(e, 'width', index)}
readOnly={roof.roofPchAuth === 'R'} readOnly={roof.widAuth === 'R'}
/> />
</div> </div>
</div> </div>
</div> </div>
)} )}
{roof.lenAuth && (
<div className="block-box">
<div className="flex-ment">
<span>L</span>
<div className="input-grid">
<input
type="text"
className="input-origin block"
defaultValue={roof.length}
onChange={(e) => handleChangeInput(e, 'length', index)}
readOnly={roof.lenAuth === 'R'}
/>
</div>
</div>
</div>
)}
</>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid">
<input
type="text"
className="input-origin block"
onChange={(e) => handleChangeInput(e, 'hajebichi', index)}
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
</div>
</div>
</div> </div>
)} )}
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('slope')}</span>
<div className="input-grid">
<input
type="text"
className="input-origin block"
onChange={(e) => {
handleChangePitch(e, index)
}}
value={currentAngleType === 'slope' ? roof.pitch : roof.angle}
defaultValue={currentAngleType === 'slope' ? roof.pitch : roof.angle}
/>
</div>
<span className="absol">{pitchText}</span>
</div>
</div>
<div className="block-box"> <div className="block-box">
<div className="icon-btn-wrap"> <div className="icon-btn-wrap">
<button <button

View File

@ -6,7 +6,6 @@ export default function Wall({ sleeveOffset, setSleeveOffset, hasSleeve, setHasS
const { getMessage } = useMessage() const { getMessage } = useMessage()
return ( return (
<> <>
{hasSleeve}
<div className="eaves-keraba-table"> <div className="eaves-keraba-table">
<div className="eaves-keraba-item"> <div className="eaves-keraba-item">
<div className="eaves-keraba-th"> <div className="eaves-keraba-th">

View File

@ -44,7 +44,7 @@ export default function FirstOption(props) {
const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
polygons.forEach((polygon) => { polygons.forEach((polygon) => {
setSurfaceShapePattern(polygon, item.column) setSurfaceShapePattern(polygon, item.column, false, polygon.roofMaterial, true, true)
}) })
// ( ) // ( )
} else { } else {

View File

@ -21,6 +21,7 @@ export default function SecondOption(props) {
const flowFont = useRecoilValue(fontSelector('flowText')) const flowFont = useRecoilValue(fontSelector('flowText'))
const lengthFont = useRecoilValue(fontSelector('lengthText')) const lengthFont = useRecoilValue(fontSelector('lengthText'))
const circuitNumberTextFont = useRecoilValue(fontSelector('circuitNumberText')) const circuitNumberTextFont = useRecoilValue(fontSelector('circuitNumberText'))
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
const [dimensionId, setDimensionId] = useState(uuidv4()) const [dimensionId, setDimensionId] = useState(uuidv4())
const [fontId, setFontId] = useState(uuidv4()) const [fontId, setFontId] = useState(uuidv4())
const [planSizeId, setPlanSizeId] = useState(uuidv4()) const [planSizeId, setPlanSizeId] = useState(uuidv4())
@ -103,12 +104,7 @@ export default function SecondOption(props) {
// //
if (!showDimensionLineSettingModal) { if (!showDimensionLineSettingModal) {
setShowDimensionLineSettingModal(true) setShowDimensionLineSettingModal(true)
fontProps.font = { fontProps.font = dimensionLineTextFont
fontFamily: '',
fontWeight: '',
fontSize: '',
fontColor: '',
}
addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />, true) addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />, true)
} else { } else {
setShowDimensionLineSettingModal(false) setShowDimensionLineSettingModal(false)

View File

@ -6,9 +6,12 @@ import { useRecoilValue, useRecoilState } from 'recoil'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { logout, setSession, login } from '@/lib/authActions' import { logout, setSession, login } from '@/lib/authActions'
import { useSwal } from '@/hooks/useSwal'
export default function ChangePasswordPop(props) { export default function ChangePasswordPop(props) {
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { swalFire } = useSwal()
const { patch } = useAxios(globalLocaleState) const { patch } = useAxios(globalLocaleState)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [sessionState, setSessionState] = useRecoilState(sessionStore) const [sessionState, setSessionState] = useRecoilState(sessionStore)
@ -22,7 +25,7 @@ export default function ChangePasswordPop(props) {
const form = { register, setValue, getValues, handleSubmit, resetField, control, watch } const form = { register, setValue, getValues, handleSubmit, resetField, control, watch }
// // 10 10
const checkLength = (pwd1) => { const checkLength = (pwd1) => {
let str = new String(pwd1) let str = new String(pwd1)
let _byte = 0 let _byte = 0
@ -55,22 +58,38 @@ export default function ChangePasswordPop(props) {
// //
if (_password1.trim() === '') { if (_password1.trim() === '') {
alert(getMessage('main.popup.login.validate3')) swalFire({
text: getMessage('main.popup.login.validate3'),
type: 'alert',
icon: 'error',
})
return false return false
} }
if (_password2.trim() === '') { if (_password2.trim() === '') {
alert(getMessage('main.popup.login.validate3')) swalFire({
text: getMessage('main.popup.login.validate3'),
type: 'alert',
icon: 'error',
})
return false return false
} }
if (_password1 !== _password2) { if (_password1 !== _password2) {
alert(getMessage('main.popup.login.validate1')) swalFire({
text: getMessage('main.popup.login.validate1'),
type: 'alert',
icon: 'error',
})
return false return false
} }
// // 10
if (checkLength(_password1) > 10) { if (checkLength(_password1) > 10) {
return alert(getMessage('main.popup.login.validate2')) swalFire({
text: getMessage('main.popup.login.validate2'),
type: 'alert',
icon: 'error',
})
} }
const param = { const param = {
@ -83,12 +102,17 @@ export default function ChangePasswordPop(props) {
.then((res) => { .then((res) => {
if (res?.result?.code === 200) { if (res?.result?.code === 200) {
if (res?.result?.resultCode === 'S') { if (res?.result?.resultCode === 'S') {
alert(getMessage('main.popup.login.success')) swalFire({
const result = { ...sessionState, pwdInitYn: 'Y' } text: getMessage('main.popup.login.success'),
setSession(result) type: 'alert',
setSessionState(result) confirmFn: async () => {
props.setChagePasswordPopOpen(false) const result = { ...sessionState, pwdInitYn: 'Y' }
login() setSession(result)
setSessionState(result)
props.setChagePasswordPopOpen(false)
await login()
},
})
} else { } else {
alert(res?.result?.resultMsg) alert(res?.result?.resultMsg)
} }
@ -130,6 +154,7 @@ export default function ChangePasswordPop(props) {
autoComplete="off" autoComplete="off"
onChange={checkValue} onChange={checkValue}
onKeyUp={checkValue} onKeyUp={checkValue}
maxLength={10}
/> />
</div> </div>
</div> </div>
@ -150,6 +175,7 @@ export default function ChangePasswordPop(props) {
autoComplete="off" autoComplete="off"
onChange={checkValue} onChange={checkValue}
onKeyUp={checkValue} onKeyUp={checkValue}
maxLength={10}
/> />
</div> </div>
</div> </div>

View File

@ -14,10 +14,9 @@ import { useMainContentsController } from '@/hooks/main/useMainContentsControlle
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import BoardDetailModal from '../community/modal/BoardDetailModal'
import { handleFileDown } from '@/util/board-utils' import { handleFileDown } from '@/util/board-utils'
export default function MainContents() { export default function MainContents({ setFaqOpen, setFaqModalNoticeNo }) {
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -116,10 +115,6 @@ export default function MainContents() {
} }
} }
// FAQ
const [open, setOpen] = useState(false)
const [modalNoticeNo, setModalNoticeNo] = useState('')
return ( return (
<div className="main-product-list-wrap"> <div className="main-product-list-wrap">
<div className="main-product-list"> <div className="main-product-list">
@ -178,7 +173,6 @@ export default function MainContents() {
</ProductItem> </ProductItem>
</div> </div>
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
<div className="main-product-list"> <div className="main-product-list">
<ProductItem num={3} name={getMessage('main.faq')}> <ProductItem num={3} name={getMessage('main.faq')}>
{recentFaqList.length > 0 ? ( {recentFaqList.length > 0 ? (
@ -192,8 +186,8 @@ export default function MainContents() {
className="faq-title pre" className="faq-title pre"
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
onClick={() => { onClick={() => {
setOpen(true) setFaqOpen(true)
setModalNoticeNo(row.noticeNo) setFaqModalNoticeNo(row.noticeNo)
}} }}
> >
{row.title} {row.title}

View File

@ -149,7 +149,22 @@ export default function Stuff() {
cellStyle: { textAlign: 'left' }, cellStyle: { textAlign: 'left' },
}, },
{ field: 'saleStoreName', minWidth: 300, headerName: getMessage('stuff.gridHeader.saleStoreName'), cellStyle: { textAlign: 'left' } }, { field: 'saleStoreName', minWidth: 300, headerName: getMessage('stuff.gridHeader.saleStoreName'), cellStyle: { textAlign: 'left' } },
{ field: 'address', headerName: getMessage('stuff.gridHeader.address'), cellStyle: { textAlign: 'left' } }, {
field: 'address',
headerName: getMessage('stuff.gridHeader.address'),
cellStyle: { textAlign: 'left' },
cellRenderer: (params) => {
let prefName = params?.data?.prefName
let address = params?.data?.address
let showAddress
if (params?.data?.prefName && params?.data?.address) {
showAddress = prefName + ' ' + address
} else {
showAddress = null
}
return showAddress
},
},
{ field: 'dispCompanyName', headerName: getMessage('stuff.gridHeader.dispCompanyName'), cellStyle: { textAlign: 'left' } }, { field: 'dispCompanyName', headerName: getMessage('stuff.gridHeader.dispCompanyName'), cellStyle: { textAlign: 'left' } },
{ field: 'receiveUser', headerName: getMessage('stuff.gridHeader.receiveUser'), cellStyle: { textAlign: 'left' } }, { field: 'receiveUser', headerName: getMessage('stuff.gridHeader.receiveUser'), cellStyle: { textAlign: 'left' } },
{ {
@ -215,8 +230,6 @@ export default function Stuff() {
startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1, startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1,
endRow: stuffSearchParams?.endRow, endRow: stuffSearchParams?.endRow,
schSaleStoreId: stuffSearchParams?.schMyDataCheck ? stuffSearchParams.schSaleStoreId : '', schSaleStoreId: stuffSearchParams?.schMyDataCheck ? stuffSearchParams.schSaleStoreId : '',
// schSelSaleStoreId: stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : '',
// schOtherSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : '',
schSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schSelSaleStoreId, schSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schOtherSelSaleStoreId, schOtherSelSaleStoreId: stuffSearchParams?.schMyDataCheck ? '' : stuffSearchParams.schOtherSelSaleStoreId,
schSortType: stuffSearchParams.schSortType, schSortType: stuffSearchParams.schSortType,
@ -288,11 +301,6 @@ export default function Stuff() {
stuffSearchParams.schSaleStoreId = session.storeId stuffSearchParams.schSaleStoreId = session.storeId
stuffSearchParams.schOtherSelSaleStoreId = '' stuffSearchParams.schOtherSelSaleStoreId = ''
stuffSearchParams.schSelSaleStoreId = '' stuffSearchParams.schSelSaleStoreId = ''
// if (session.storeLvl === '1') {
// stuffSearchParams.schSaleStoreId = session.storeId
// stuffSearchParams.schOtherSelSaleStoreId = ''
// stuffSearchParams.schSelSaleStoreId = ''
// }
} }
async function fetchData() { async function fetchData() {

View File

@ -282,23 +282,26 @@ export default function StuffDetail() {
autoHeight: true, autoHeight: true,
cellStyle: { justifyContent: 'center' }, cellStyle: { justifyContent: 'center' },
cellRenderer: (params) => { cellRenderer: (params) => {
let buttonStyle let buttonStyle = ''
let buttonStyle2 = ''
if (params.value == null) { if (params.value == null) {
buttonStyle = { buttonStyle = 'none'
display: 'none', buttonStyle2 = 'none'
} else {
if (params?.data?.createSaleStoreId === 'T01') {
if (session?.storeId !== 'T01') {
buttonStyle = 'none'
}
} }
} if (params?.data?.tempFlg === '1') {
if (managementState?.createUser === 'T01') { buttonStyle2 = 'none'
if (session.userId !== 'T01') {
// #474
buttonStyle = { display: 'none' }
} }
} }
return ( return (
<> <>
<div className="grid-cell-btn"> <div className="grid-cell-btn">
<button <button
style={buttonStyle} style={{ display: buttonStyle }}
type="button" type="button"
className="grid-btn" className="grid-btn"
onClick={() => { onClick={() => {
@ -312,7 +315,7 @@ export default function StuffDetail() {
{getMessage('stuff.detail.planGrid.btn1')} {getMessage('stuff.detail.planGrid.btn1')}
</button> </button>
<button <button
style={buttonStyle} style={{ display: buttonStyle2 }}
type="button" type="button"
className="grid-btn" className="grid-btn"
onClick={() => { onClick={() => {
@ -347,11 +350,8 @@ export default function StuffDetail() {
} }
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res.status === 200) { if (res.status === 200) {
if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') { if (res?.data?.createSaleStoreId === 'T01') {
//createUser T01 T01 if (session?.storeId !== 'T01') {
setShowButton('none')
} else {
if (session.userId !== res?.data?.createUser) {
setShowButton('none') setShowButton('none')
} }
} }
@ -362,8 +362,9 @@ export default function StuffDetail() {
} else if (res.data.surfaceType === 'Ⅱ') { } else if (res.data.surfaceType === 'Ⅱ') {
surfaceTypeValue = '2' surfaceTypeValue = '2'
} }
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue, firstFlag: 'Y' }) setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
} else { } else {
setIsGlobalLoading(false)
setManagementState({}) setManagementState({})
swalFire({ swalFire({
text: getMessage('stuff.detail.header.notExistObjectNo'), text: getMessage('stuff.detail.header.notExistObjectNo'),
@ -379,9 +380,9 @@ export default function StuffDetail() {
setPlanGridProps({ ...planGridProps, planGridData: [] }) setPlanGridProps({ ...planGridProps, planGridData: [] })
} }
} else { } else {
setIsGlobalLoading(false)
setManagementState({}) setManagementState({})
setPlanGridProps({ ...planGridProps, planGridData: [] }) setPlanGridProps({ ...planGridProps, planGridData: [] })
swalFire({ swalFire({
text: getMessage('stuff.detail.header.notExistObjectNo'), text: getMessage('stuff.detail.header.notExistObjectNo'),
type: 'alert', type: 'alert',
@ -409,11 +410,7 @@ export default function StuffDetail() {
if (session?.storeId === 'T01') { if (session?.storeId === 'T01') {
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}` url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
if (session.storeLvl === '1') { url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
} else {
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
@ -521,11 +518,7 @@ export default function StuffDetail() {
if (session?.storeId === 'T01') { if (session?.storeId === 'T01') {
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}` url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
if (session.storeLvl === '1') { url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
} else {
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
@ -1393,7 +1386,7 @@ export default function StuffDetail() {
// //
if (res.status === 201) { if (res.status === 201) {
setIsGlobalLoading(false) setIsGlobalLoading(false)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) setFloorPlanObjectNo({ floorPlanObjectNo: res?.data?.objectNo })
swalFire({ swalFire({
text: getMessage('stuff.detail.save'), text: getMessage('stuff.detail.save'),
type: 'alert', type: 'alert',
@ -1420,7 +1413,14 @@ export default function StuffDetail() {
text: getMessage('stuff.detail.save'), text: getMessage('stuff.detail.save'),
type: 'alert', type: 'alert',
confirmFn: () => { confirmFn: () => {
callDetailApi(objectNo) let surfaceTypeValue
if (res.data.surfaceType === 'Ⅲ・Ⅳ') {
surfaceTypeValue = '3'
} else if (res.data.surfaceType === 'Ⅱ') {
surfaceTypeValue = '2'
}
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
}, },
}) })
} }
@ -1432,25 +1432,6 @@ export default function StuffDetail() {
} }
} }
const callDetailApi = async (objectNo) => {
await promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res?.data?.createUser === 'T01' && session?.userId !== 'T01') {
setShowButton('none')
} else {
if (session.userId !== res?.data?.createUser) {
setShowButton('none')
}
}
let surfaceTypeValue
if (res.data.surfaceType === 'Ⅲ・Ⅳ') {
surfaceTypeValue = '3'
} else {
surfaceTypeValue = '2'
}
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
})
}
// //
const onTempSave = async () => { const onTempSave = async () => {
const formData = form.getValues() const formData = form.getValues()
@ -1637,9 +1618,8 @@ export default function StuffDetail() {
// //
const getCellDoubleClicked = (params) => { const getCellDoubleClicked = (params) => {
//#474 if (managementState?.createSaleStoreId === 'T01') {
if (managementState.createUser === 'T01') { if (session?.storeId !== 'T01') {
if (session.userId !== 'T01') {
return false return false
} }
} }

View File

@ -68,7 +68,7 @@ export default function StuffHeader() {
<div className="sub-table-box"> <div className="sub-table-box">
<div className="info-title">{getMessage('stuff.detail.header.specificationConfirmDate')}</div> <div className="info-title">{getMessage('stuff.detail.header.specificationConfirmDate')}</div>
<div className="info-inner"> <div className="info-inner">
{managementState?.specificationConfirmDate ? `${dayjs(managementState.specificationConfirmDate).format('YYYY.MM.DD HH:mm:ss')}` : ''} {managementState?.specificationConfirmDate ? `${dayjs(managementState.specificationConfirmDate).format('YYYY.MM.DD')}` : ''}
</div> </div>
</div> </div>
<div className="sub-table-box"> <div className="sub-table-box">

View File

@ -56,7 +56,7 @@ export default function StuffSearchCondition() {
const [objectNo, setObjectNo] = useState('') // const [objectNo, setObjectNo] = useState('') //
const [saleStoreName, setSaleStoreName] = useState('') // const [saleStoreName, setSaleStoreName] = useState('') //
const [address, setAddress] = useState('') // const [address, setAddress] = useState('') //
const [objectName, setobjectName] = useState('') // const [objectName, setObjectName] = useState('') //
const [dispCompanyName, setDispCompanyName] = useState('') // const [dispCompanyName, setDispCompanyName] = useState('') //
const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') // const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //
const [receiveUser, setReceiveUser] = useState('') // const [receiveUser, setReceiveUser] = useState('') //
@ -96,8 +96,6 @@ 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 : '',
// schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schSaleStoreId: stuffSearch?.schMyDataCheck ? stuffSearch?.schSaleStoreId : '', schSaleStoreId: stuffSearch?.schMyDataCheck ? stuffSearch?.schSaleStoreId : '',
schSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schSelSaleStoreId, schSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schOtherSelSaleStoreId, schOtherSelSaleStoreId: stuffSearch?.schMyDataCheck ? '' : stuffSearch.schOtherSelSaleStoreId,
@ -122,8 +120,8 @@ 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?.schOtherSelSaleStoreId ? '' : stuffSearch.schSelSaleStoreId, schSelSaleStoreId: '',
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: otherSaleStoreId ? otherSaleStoreId : stuffSearch.schOtherSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
@ -144,8 +142,8 @@ 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: schSelSaleStoreId ? schSelSaleStoreId : stuffSearch.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: otherSaleStoreId ? otherSaleStoreId : stuffSearch.schOtherSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
@ -183,28 +181,6 @@ export default function StuffSearchCondition() {
}) })
} else if (stuffSearch.code === 'E') { } else if (stuffSearch.code === 'E') {
if (session.storeId !== 'T01' && session.storeLvl === '1') { if (session.storeId !== 'T01' && session.storeLvl === '1') {
setStuffSearch({
schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo.trim() : objectNo.trim(),
schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName.trim() : saleStoreName.trim(),
schAddress: stuffSearch?.schAddress ? stuffSearch.schAddress.trim() : address.trim(),
schObjectName: stuffSearch?.schObjectName ? stuffSearch.schObjectName.trim() : objectName.trim(),
schDispCompanyName: stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName.trim() : dispCompanyName.trim(),
schSelSaleStoreId: myDataCheck ? schSelSaleStoreId : otherSaleStoreId ? schSelSaleStoreId : '',
schOtherSelSaleStoreId: myDataCheck ? '' : otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType,
schTempFlg: tempFlg, //
schMyDataCheck: myDataCheck,
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
} else if (session.storeId === 'T01') {
if (stuffSearch.pageNo !== 1) { if (stuffSearch.pageNo !== 1) {
setStuffSearch({ setStuffSearch({
schObjectNo: objectNo ? objectNo.trim() : stuffSearch.schObjectNo.trim(), schObjectNo: objectNo ? objectNo.trim() : stuffSearch.schObjectNo.trim(),
@ -212,8 +188,8 @@ 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: schSelSaleStoreId ? schSelSaleStoreId : stuffSearch.schSelSaleStoreId,
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: otherSaleStoreId ? otherSaleStoreId : stuffSearch.schOtherSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
@ -229,14 +205,60 @@ export default function StuffSearchCondition() {
}) })
} else { } else {
setStuffSearch({ setStuffSearch({
schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo.trim() : objectNo.trim(), schObjectNo: objectNo ? objectNo.trim() : '',
schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName.trim() : saleStoreName.trim(), schSaleStoreName: saleStoreName ? saleStoreName.trim() : '',
schAddress: stuffSearch?.schAddress ? stuffSearch.schAddress.trim() : address.trim(), schAddress: address ? address.trim() : '',
schObjectName: stuffSearch?.schObjectName ? stuffSearch.schObjectName.trim() : objectName.trim(), schObjectName: objectName ? objectName.trim() : '',
schDispCompanyName: stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName.trim() : dispCompanyName.trim(), schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '',
schSelSaleStoreId: myDataCheck ? '' : otherSaleStoreId ? '' : '',
schOtherSelSaleStoreId: myDataCheck ? '' : otherSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType,
schTempFlg: tempFlg, //
schMyDataCheck: myDataCheck,
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize,
})
}
} else if (session.storeId === 'T01') {
if (stuffSearch.pageNo !== 1) {
setStuffSearch({
schObjectNo: objectNo ? objectNo.trim() : stuffSearch.schObjectNo.trim(),
schSaleStoreName: saleStoreName ? saleStoreName.trim() : '',
schAddress: address ? address.trim() : '',
schObjectName: objectName ? objectName.trim() : '',
schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '',
schSelSaleStoreId: schSelSaleStoreId ? schSelSaleStoreId : stuffSearch.schSelSaleStoreId,
schOtherSelSaleStoreId: otherSaleStoreId ? otherSaleStoreId : stuffSearch.schOtherSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType,
schTempFlg: tempFlg, //
schMyDataCheck: myDataCheck,
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E',
startRow: 1,
endRow: 1 * stuffSearch?.pageSize,
schSortType: 'U',
pageNo: 1,
pageSize: stuffSearch?.pageSize,
})
} else {
setStuffSearch({
schObjectNo: objectNo ? objectNo.trim() : '',
schSaleStoreName: saleStoreName ? saleStoreName.trim() : '',
schAddress: address ? address.trim() : '',
schObjectName: objectName ? objectName.trim() : '',
schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '',
schSelSaleStoreId: schSelSaleStoreId, schSelSaleStoreId: schSelSaleStoreId,
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(), schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
schMyDataCheck: myDataCheck, schMyDataCheck: myDataCheck,
@ -252,14 +274,15 @@ export default function StuffSearchCondition() {
} }
} else { } else {
setStuffSearch({ setStuffSearch({
schObjectNo: stuffSearch?.schObjectNo ? stuffSearch.schObjectNo.trim() : objectNo.trim(), schObjectNo: objectNo ? objectNo.trim() : '',
schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName.trim() : saleStoreName.trim(), schSaleStoreName: saleStoreName ? saleStoreName.trim() : '',
schAddress: stuffSearch?.schAddress ? stuffSearch.schAddress.trim() : address.trim(), schAddress: address ? address.trim() : '',
schObjectName: stuffSearch?.schObjectName ? stuffSearch.schObjectName.trim() : objectName.trim(), schObjectName: objectName ? objectName.trim() : '',
schDispCompanyName: stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName.trim() : dispCompanyName.trim(), schDispCompanyName: dispCompanyName ? dispCompanyName.trim() : '',
schSelSaleStoreId: schSelSaleStoreId, schSelSaleStoreId: schSelSaleStoreId,
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(), schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, // schTempFlg: tempFlg, //
schMyDataCheck: myDataCheck, schMyDataCheck: myDataCheck,
@ -314,7 +337,7 @@ export default function StuffSearchCondition() {
stuffSearch.schSaleStoreId = '' stuffSearch.schSaleStoreId = ''
setObjectNo('') setObjectNo('')
setAddress('') setAddress('')
setobjectName('') setObjectName('')
setSaleStoreName('') setSaleStoreName('')
setReceiveUser('') setReceiveUser('')
setDispCompanyName('') setDispCompanyName('')
@ -452,12 +475,7 @@ export default function StuffSearchCondition() {
//T01 //T01
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}` url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
if (session.storeLvl === '1') { url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
//T01 1
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
} else {
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
@ -600,7 +618,7 @@ export default function StuffSearchCondition() {
if (isObjectNotEmpty(key)) { if (isObjectNotEmpty(key)) {
setOtherSaleStoreId('') setOtherSaleStoreId('')
setSchSelSaleStoreId(key.saleStoreId) setSchSelSaleStoreId(key.saleStoreId)
stuffSearch.schSelSaleStoreId = key.saleStoreId // stuffSearch.schSelSaleStoreId = key.saleStoreId
// 1 saleStoreId 2 API // 1 saleStoreId 2 API
let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}` let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
let otherList let otherList
@ -645,11 +663,11 @@ export default function StuffSearchCondition() {
stuffSearch.schMyDataCheck = false stuffSearch.schMyDataCheck = false
if (isObjectNotEmpty(key)) { if (isObjectNotEmpty(key)) {
setOtherSaleStoreId(key.saleStoreId) setOtherSaleStoreId(key.saleStoreId)
stuffSearch.schOtherSelSaleStoreId = key.saleStoreId // stuffSearch.schOtherSelSaleStoreId = key.saleStoreId
//2 1 //2 1
if (session.storeId === 'T01') { if (session.storeId === 'T01') {
stuffSearch.schSelSaleStoreId = schSelSaleStoreId // stuffSearch.schSelSaleStoreId = schSelSaleStoreId
} else { } else {
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
} }
@ -682,7 +700,7 @@ export default function StuffSearchCondition() {
setObjectNo('') setObjectNo('')
setSaleStoreName('') setSaleStoreName('')
setAddress('') setAddress('')
setobjectName('') setObjectName('')
setDispCompanyName('') setDispCompanyName('')
setReceiveUser('') setReceiveUser('')
objectNoRef.current.value = '' objectNoRef.current.value = ''
@ -717,7 +735,7 @@ export default function StuffSearchCondition() {
setObjectNo('') setObjectNo('')
setSaleStoreName('') setSaleStoreName('')
setAddress('') setAddress('')
setobjectName('') setObjectName('')
setDispCompanyName('') setDispCompanyName('')
setReceiveUser('') setReceiveUser('')
objectNoRef.current.value = '' objectNoRef.current.value = ''
@ -748,15 +766,6 @@ export default function StuffSearchCondition() {
setSchSelSaleStoreId('') setSchSelSaleStoreId('')
setOtherSaleStoreId('') setOtherSaleStoreId('')
} else { } else {
setStartDate(stuffSearch?.schFromDt ? stuffSearch.schFromDt : dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(stuffSearch?.schToDt ? stuffSearch.schToDt : dayjs(new Date()).format('YYYY-MM-DD'))
setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo)
setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName)
setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address)
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg) setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg)
setMyDataCheck(stuffSearch.schMyDataCheck) setMyDataCheck(stuffSearch.schMyDataCheck)
} }
@ -775,7 +784,7 @@ export default function StuffSearchCondition() {
setObjectNo('') setObjectNo('')
setSaleStoreName('') setSaleStoreName('')
setAddress('') setAddress('')
setobjectName('') setObjectName('')
setDispCompanyName('') setDispCompanyName('')
setReceiveUser('') setReceiveUser('')
objectNoRef.current.value = '' objectNoRef.current.value = ''
@ -806,7 +815,7 @@ export default function StuffSearchCondition() {
setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo) setObjectNo(stuffSearch.schObjectNo ? stuffSearch.schObjectNo : objectNo)
setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName) setSaleStoreName(stuffSearch.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName)
setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address) setAddress(stuffSearch.schAddress ? stuffSearch.schAddress : address)
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName) setObjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName) setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser) setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType) setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
@ -987,7 +996,7 @@ export default function StuffSearchCondition() {
className="input-light" className="input-light"
defaultValue={stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo} defaultValue={stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo}
onChange={() => { onChange={() => {
stuffSearch.schObjectNo = objectNoRef.current.value // stuffSearch.schObjectNo = objectNoRef.current.value
setObjectNo(objectNoRef.current.value) setObjectNo(objectNoRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
@ -1003,7 +1012,7 @@ export default function StuffSearchCondition() {
className="input-light" className="input-light"
defaultValue={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName} defaultValue={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName}
onChange={() => { onChange={() => {
stuffSearch.schSaleStoreName = saleStoreNameRef.current.value // stuffSearch.schSaleStoreName = saleStoreNameRef.current.value
setSaleStoreName(saleStoreNameRef.current.value) setSaleStoreName(saleStoreNameRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
@ -1020,7 +1029,7 @@ export default function StuffSearchCondition() {
className="input-light" className="input-light"
defaultValue={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName} defaultValue={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName}
onChange={() => { onChange={() => {
stuffSearch.schDispCompanyName = dispCompanyNameRef.current.value // stuffSearch.schDispCompanyName = dispCompanyNameRef.current.value
setDispCompanyName(dispCompanyNameRef.current.value) setDispCompanyName(dispCompanyNameRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
@ -1038,8 +1047,8 @@ export default function StuffSearchCondition() {
className="input-light" className="input-light"
defaultValue={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName} defaultValue={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName}
onChange={() => { onChange={() => {
stuffSearch.schObjectName = objectNameRef.current.value // stuffSearch.schObjectName = objectNameRef.current.value
setobjectName(objectNameRef.current.value) setObjectName(objectNameRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
/> />
@ -1054,7 +1063,7 @@ export default function StuffSearchCondition() {
ref={receiveUserRef} ref={receiveUserRef}
defaultValue={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser} defaultValue={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser}
onChange={() => { onChange={() => {
stuffSearch.schReceiveUser = receiveUserRef.current.value // stuffSearch.schReceiveUser = receiveUserRef.current.value
setReceiveUser(receiveUserRef.current.value) setReceiveUser(receiveUserRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
@ -1070,7 +1079,7 @@ export default function StuffSearchCondition() {
className="input-light" className="input-light"
defaultValue={stuffSearch?.schAddress ? stuffSearch.schAddress : address} defaultValue={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
onChange={() => { onChange={() => {
stuffSearch.schAddress = addressRef.current.value // stuffSearch.schAddress = addressRef.current.value
setAddress(addressRef.current.value) setAddress(addressRef.current.value)
}} }}
onKeyUp={handleByOnKeyUp} onKeyUp={handleByOnKeyUp}
@ -1092,7 +1101,7 @@ export default function StuffSearchCondition() {
value={'U'} value={'U'}
onChange={(e) => { onChange={(e) => {
setDateType(e.target.value) setDateType(e.target.value)
stuffSearch.schDateType = e.target.value // stuffSearch.schDateType = e.target.value
}} }}
/> />
<label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label> <label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label>
@ -1106,7 +1115,7 @@ export default function StuffSearchCondition() {
value={'R'} value={'R'}
onChange={(e) => { onChange={(e) => {
setDateType(e.target.value) setDateType(e.target.value)
stuffSearch.schDateType = e.target.value // stuffSearch.schDateType = e.target.value
}} }}
/> />
<label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label> <label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label>
@ -1288,7 +1297,10 @@ export default function StuffSearchCondition() {
onChange={onSelectionChange2} onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isDisabled={otherSaleStoreList != null && otherSaleStoreList.length === 1 ? true : false} // isDisabled={otherSaleStoreList != null && otherSaleStoreList.length === 1 ? true : false}
isDisabled={
session?.storeLvl === '1' ? (otherSaleStoreList.length > 0 ? false : true) : otherSaleStoreList.length === 1 ? true : false
}
isClearable={true} isClearable={true}
value={otherSaleStoreList.filter(function (option) { value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSaleStoreId return option.saleStoreId === otherSaleStoreId

View File

@ -38,9 +38,8 @@ export default function StuffSubHeader({ type }) {
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(managementState)) { if (isObjectNotEmpty(managementState)) {
if (managementState.createUser === 'T01') { if (managementState?.createSaleStoreId === 'T01') {
if (session.userId !== 'T01') { if (session?.storeId !== 'T01') {
// #457 #474
setButtonStyle('none') setButtonStyle('none')
} }
} }

View File

@ -176,7 +176,6 @@ export default function Simulator() {
const [content, setContent] = useState('') const [content, setContent] = useState('')
const fetchSimulatorNotice = async () => { const fetchSimulatorNotice = async () => {
setIsGlobalLoading(true)
get({ url: '/api/pwrGnrSimulation/guideInfo' }).then((res) => { get({ url: '/api/pwrGnrSimulation/guideInfo' }).then((res) => {
if (res.data) { if (res.data) {
setContent(res.data.replaceAll('\n', '<br/>')) setContent(res.data.replaceAll('\n', '<br/>'))
@ -184,7 +183,6 @@ export default function Simulator() {
setContent(getMessage('common.message.no.data')) setContent(getMessage('common.message.no.data'))
} }
}) })
setIsGlobalLoading(false)
} }
// , list type // , list type

View File

@ -25,24 +25,17 @@ export function useCanvasConfigInitialize() {
const {} = useRoof() const {} = useRoof()
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow } = usePolygon()
useEffect(() => {
if (!canvas) return
canvas
.getObjects()
.filter((polygon) => polygon.name === 'roof')
.forEach((polygon) => {
setSurfaceShapePattern(polygon, roofDisplay.column)
})
canvas.renderAll()
}, [roofDisplay])
useEffect(() => { useEffect(() => {
if (!canvas) return if (!canvas) return
const offsetTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText') const offsetTexts = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
const flowTexts = canvas.getObjects().filter((obj) => obj.name === 'flowText') const flowTexts = canvas.getObjects().filter((obj) => obj.name === 'flowText')
if (basicSetting.roofAngleSet === 'slope') { if (basicSetting.roofAngleSet === 'slope') {
offsetTexts.forEach((obj) => { offsetTexts.forEach((obj) => {
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${obj.pitch}${angleUnit}` }) let text = `${!obj.originText ? '' : obj.originText}`
if (!obj.onlyOffset) {
text = text + `-∠${obj.pitch}${angleUnit}`
}
obj.set({ text: text })
}) })
flowTexts.forEach((obj) => { flowTexts.forEach((obj) => {
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${obj.pitch}${pitchText}` }) obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${obj.pitch}${pitchText}` })
@ -51,7 +44,11 @@ export function useCanvasConfigInitialize() {
if (basicSetting.roofAngleSet === 'flat') { if (basicSetting.roofAngleSet === 'flat') {
offsetTexts.forEach((obj) => { offsetTexts.forEach((obj) => {
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${getDegreeByChon(obj.pitch)}${angleUnit}` }) let text = `${!obj.originText ? '' : obj.originText}`
if (!obj.onlyOffset) {
text = text + `-∠${getDegreeByChon(obj.pitch)}${angleUnit}`
}
obj.set({ text: text })
}) })
flowTexts.forEach((obj) => { flowTexts.forEach((obj) => {
obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${getDegreeByChon(obj.pitch)}${pitchText}` }) obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}${getDegreeByChon(obj.pitch)}${pitchText}` })
@ -204,8 +201,8 @@ export function useCanvasConfigInitialize() {
.forEach((obj) => { .forEach((obj) => {
obj.set({ obj.set({
selectable: true, selectable: true,
lockMovementX: false, lockMovementX: true,
lockMovementY: false, lockMovementY: true,
}) })
obj.setViewLengthText(false) obj.setViewLengthText(false)
}) })

View File

@ -1,78 +1,117 @@
'use client' 'use client'
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import useSWR from 'swr' import useSWR from 'swr'
import useSWRMutation from 'swr/mutation' import useSWRMutation from 'swr/mutation'
import { useAxios } from '../useAxios' import { useAxios } from '../useAxios'
import { unescapeString } from '@/util/common-utils' import { unescapeString } from '@/util/common-utils'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState, moduleSelectionTotalState } from '@/store/selectedModuleOptions'
import { compasDegAtom } from '@/store/orientationAtom' import { compasDegAtom } from '@/store/orientationAtom'
import { currentCanvasPlanState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
export function useCanvasPopupStatusController(param = 1) { export function useCanvasPopupStatusController(param = 1) {
const popupType = parseInt(param) const popupType = parseInt(param)
const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom) const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom)
const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState) const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
const { getFetcher, postFetcher } = useAxios() const { get, getFetcher, postFetcher } = useAxios()
const canvas = useRecoilValue(canvasState)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
// console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan) // console.log('🚀 ~ Orientation ~ currentCanvasPlan:', currentCanvasPlan)
const { /**
data: popupStatus, * 팝업 상태 조회
error, * @param {number} popupTypeParam
isLoading, * @returns
} = useSWR( */
popupType ? `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}` : null, const getModuleSelection = async (popupTypeParam) => {
getFetcher, // const {
) // data: popupStatus,
// error,
// isLoading,
// } = useSWR(
// `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
// getFetcher,
// )
useEffect(() => { const res = await get({
// console.log('🚀 ~ useEffect ~ popupStatus:', popupStatus) url: `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
if (popupStatus) { })
switch (parseInt(popupStatus?.popupType)) {
case 1: return res
setCompasDeg(popupStatus.popupStatus) }
break
case 2: /**
setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus))) * 전체 팝업 상태 조회
break * 조회 전체 데이터 recoil에 저장
case 3: */
break const handleModuleSelectionTotal = async () => {
case 4: for (let i = 1; i < 3; i++) {
break const result = await getModuleSelection(i)
case 5: // setModuleSelectionTotal((prev) => ({ ...prev, [i]: JSON.parse(unescapeString(result.popupStatus)) }))
break if(!result) return
case 6: if (i === 1) {
break setCompasDeg(result.popupStatus)
default: } else if (i === 2) {
} const data = JSON.parse(unescapeString(result.popupStatus))
} else { setModuleSelectionDataStore(data)
switch (popupType) {
case 1: const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
setCompasDeg(0) const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
break roofSurfaceList.forEach((surface) => {
case 2: surface.modules = modules.filter((module) => module.surfaceId === surface.id)
setModuleSelectionDataStore({ })
common: {},
roofConstructions: [],
})
break
case 3:
break
case 4:
break
case 5:
break
case 6:
break
default:
} }
} }
}, [popupStatus]) }
// useEffect(() => {
// if (popupStatus) {
// switch (parseInt(popupStatus?.popupType)) {
// case 1:
// setCompasDeg(popupStatus.popupStatus)
// break
// case 2:
// setModuleSelectionDataStore(JSON.parse(unescapeString(popupStatus.popupStatus)))
// break
// case 3:
// break
// case 4:
// break
// case 5:
// break
// case 6:
// break
// default:
// }
// } else {
// switch (popupType) {
// case 1:
// setCompasDeg(0)
// break
// case 2:
// setModuleSelectionDataStore({
// common: {},
// roofConstructions: [],
// })
// break
// case 3:
// break
// case 4:
// break
// case 5:
// break
// case 6:
// break
// default:
// }
// }
// }, [popupStatus])
/**
* 팝업 상태 저장
*/
const { trigger, isMutating } = useSWRMutation( const { trigger, isMutating } = useSWRMutation(
`/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}`, `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupType}`,
(url, { arg }) => { (url, { arg }) => {
@ -86,5 +125,5 @@ export function useCanvasPopupStatusController(param = 1) {
}, },
) )
return { trigger } return { handleModuleSelectionTotal, trigger }
} }

View File

@ -9,6 +9,7 @@ import { canvasState } from '@/store/canvasAtom'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import Distance from '@/components/floor-plan/modal/distance/Distance' import Distance from '@/components/floor-plan/modal/distance/Distance'
import { usePolygon } from '@/hooks/usePolygon'
export function useCommonUtils() { export function useCommonUtils() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -20,6 +21,7 @@ export function useCommonUtils() {
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup() const { addPopup } = usePopup()
const { drawDirectionArrow, addLengthText } = usePolygon()
useEffect(() => { useEffect(() => {
// initEvent() // initEvent()
@ -608,6 +610,16 @@ export function useCommonUtils() {
//객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다 //객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() }) if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
//배치면일 경우
if (obj.name === 'roof') {
clonedObj.setCoords()
clonedObj.fire('polygonMoved')
clonedObj.set({ direction: obj.direction, directionText: obj.directionText })
canvas.renderAll()
addLengthText(clonedObj) //수치 추가
drawDirectionArrow(clonedObj) //방향 화살표 추가
}
initEvent() initEvent()
}) })
} }

View File

@ -71,10 +71,10 @@ export function useGrid() {
const backgroundPolygon = new fabric.Polygon( const backgroundPolygon = new fabric.Polygon(
[ [
{ x: 0, y: 0 }, { x: -1500, y: -1500 },
{ x: canvas.width, y: 0 }, { x: 2500, y: -1500 },
{ x: canvas.width, y: canvas.height }, { x: 2500, y: 2500 },
{ x: 0, y: canvas.height }, { x: -1500, y: 2500 },
], ],
{ {
fill: pattern, fill: pattern,
@ -90,9 +90,14 @@ export function useGrid() {
} }
if (patternData.lineGridDisplay) { if (patternData.lineGridDisplay) {
for (let i = 0; i < canvas.height / patternData.gridVertical + 1; i++) { for (let i = 0; i < 5000 / patternData.gridVertical + 1; i++) {
const horizontalLine = new fabric.Line( const horizontalLine = new fabric.Line(
[0, i * patternData.gridVertical - patternData.gridVertical / 2, canvas.width, i * patternData.gridVertical - patternData.gridVertical / 2], [
-1500,
-1500 + i * patternData.gridVertical - patternData.gridVertical / 2,
3000,
-1500 + i * patternData.gridVertical - patternData.gridVertical / 2,
],
{ {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,
@ -113,9 +118,14 @@ export function useGrid() {
canvas.add(horizontalLine) canvas.add(horizontalLine)
} }
for (let i = 0; i < canvas.width / patternData.gridHorizon + 1; i++) { for (let i = 0; i < 5000 / patternData.gridHorizon + 1; i++) {
const verticalLine = new fabric.Line( const verticalLine = new fabric.Line(
[i * patternData.gridHorizon - patternData.gridHorizon / 2, 0, i * patternData.gridHorizon - patternData.gridHorizon / 2, canvas.height], [
-1500 + i * patternData.gridHorizon - patternData.gridHorizon / 2,
-1500,
-1500 + i * patternData.gridHorizon - patternData.gridHorizon / 2,
3000,
],
{ {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,

View File

@ -137,16 +137,6 @@ export function useMasterController() {
* @returns * @returns
*/ */
const getPcsModelList = async (params = null) => { const getPcsModelList = async (params = null) => {
const test = {
pcsMkrCd: 'MKR003',
pcsSerList: [{ pcsSerCd: 'SER007' }, { pcsSerCd: 'SER009' }, { pcsSerCd: 'SER010' }],
moduleItemList: [
{ itemId: '107015', mixMatlNo: null },
{ itemId: '107077', mixMatlNo: null },
{ itemId: '107015', mixMatlNo: null },
],
}
return await post({ url: '/api/v1/master/getPcsSeriesItemList', data: params }).then((res) => { return await post({ url: '/api/v1/master/getPcsSeriesItemList', data: params }).then((res) => {
return res return res
}) })
@ -201,13 +191,22 @@ export function useMasterController() {
* @returns * @returns
*/ */
const getPcsVoltageStepUpList = async (params2 = null) => { const getPcsVoltageStepUpList = async (params2 = null) => {
// roofSurfaceList의 moduleList에서 circuit 속성을 제외
const modifiedRoofSurfaceList = params2.roofSurfaceList.map((surface) => ({
...surface,
moduleList: surface.moduleList.map((module) => ({
itemId: module.itemId,
uniqueId: module.uniqueId,
})),
}))
const params = { const params = {
...params2, ...params2,
maxConnYn: params2.useYn.maxConnYn, maxConnYn: params2.maxConnYn,
smpCirYn: params2.useYn.smpCirYn, smpCirYn: params2.smpCirYn,
coldZoneYn: params2.useYn.coldZoneYn, coldZoneYn: params2.coldZoneYn,
useModuleItemList: params2.useModuleItemList, useModuleItemList: params2.useModuleItemList,
roofSurfaceList: params2.roofSurfaceList, roofSurfaceList: modifiedRoofSurfaceList,
pcsItemList: params2.pcsItemList, pcsItemList: params2.pcsItemList,
} }
@ -229,8 +228,18 @@ export function useMasterController() {
* @returns * @returns
*/ */
const updateObjectDate = async (params = null) => { const updateObjectDate = async (params = null) => {
return await put({ url: '/api/object/update-object-date', data: params }).then((res) => { return await put({ url: '/api/object/update-object-date', data: params })
console.log('updateObjectDate', res) }
/**
* PCS 접속함 옵션 목록 조회
* @param {사용된 모듈 아이템 목록} useModuleItemList
* @param {PCS 제품 목록} pcsItemList
* @returns
*/
const getPcsConnOptionItemList = async (params = null) => {
return await post({ url: '/api/v1/master/getPcsConnOptionItemList', data: params }).then((res) => {
return res
}) })
} }
@ -248,5 +257,6 @@ export function useMasterController() {
getPcsVoltageStepUpList, getPcsVoltageStepUpList,
updateObjectDate, updateObjectDate,
getQuotationItem, getQuotationItem,
getPcsConnOptionItemList,
} }
} }

View File

@ -19,6 +19,7 @@ import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { currentMenuState } from '@/store/canvasAtom' import { currentMenuState } from '@/store/canvasAtom'
import { MENU } from '@/common/common' import { MENU } from '@/common/common'
import { useTrestle } from '@/hooks/module/useTrestle'
export default function useMenu() { export default function useMenu() {
const menus = [] const menus = []
@ -26,6 +27,7 @@ export default function useMenu() {
const [popupId, setPopupId] = useState(uuidv4()) const [popupId, setPopupId] = useState(uuidv4())
const { addPopup } = usePopup() const { addPopup } = usePopup()
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch({}) const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch({})
const { clear: trestleClear } = useTrestle()
const handleMenu = (type) => { const handleMenu = (type) => {
if (type === 'outline') { if (type === 'outline') {
switch (currentMenu) { switch (currentMenu) {
@ -79,6 +81,7 @@ export default function useMenu() {
if (type === 'module') { if (type === 'module') {
switch (currentMenu) { switch (currentMenu) {
case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING: case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING:
trestleClear()
addPopup(popupId, 1, <BasicSetting id={popupId} />) addPopup(popupId, 1, <BasicSetting id={popupId} />)
break break
case MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING: case MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING:

View File

@ -15,8 +15,8 @@ export function useRefFiles() {
const [currentBgImage, setCurrentBgImage] = useState(null) const [currentBgImage, setCurrentBgImage] = useState(null)
const queryRef = useRef(null) const queryRef = useRef(null)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const canvas = useRecoilValue(canvasState) // const canvas = useRecoilValue(canvasState)
const { handleBackImageLoadToCanvas } = useCanvas() const { canvas, handleBackImageLoadToCanvas } = useCanvas()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { get, post, promisePost } = useAxios() const { get, post, promisePost } = useAxios()
@ -66,15 +66,20 @@ export function useRefFiles() {
} }
const refFileSetting = (file) => { const refFileSetting = (file) => {
if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) { console.log('🚀 ~ refFileSetting ~ file:', file)
// setRefImage(file) if (file.name.split('.').pop() === 'dwg') {
file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file) handleUploadConvertRefFile(file)
} else { } else {
swalFire({ if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) {
text: '이미지가 아닙니다.', // file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
type: 'alert', handleUploadImageRefFile(file)
icon: 'error', } else {
}) swalFire({
text: '이미지가 아닙니다.',
type: 'alert',
icon: 'error',
})
}
} }
} }
/** /**
@ -121,23 +126,30 @@ export function useRefFiles() {
} }
const res = await get({ const res = await get({
url: `http://localhost:3000/api/html2canvas?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`,
}) })
console.log('🚀 ~ handleMapImageDown ~ res:', res) console.log('🚀 ~ handleMapImageDown ~ res:', res)
const file = await readImage(res.fileNm) // const file = await readImage(res.fileNm)
console.log('🚀 ~ handleMapImageDown ~ file:', file) // console.log('🚀 ~ handleMapImageDown ~ file:', file)
setCurrentBgImage(file) // setCurrentBgImage(file)
// handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`) setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
// setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: currentCanvasPlan.id, mapPositionAddress: queryRef.current.value }))
} }
/**
* 배경 이미지 로드를 위한 세팅
*/
useEffect(() => { useEffect(() => {
if (!currentBgImage) { if (!currentBgImage) {
return return
} }
console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage) console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage)
handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`) // handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`)
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: refImage?.name ?? null, mapPositionAddress: queryRef.current.value })) handleBackImageLoadToCanvas(currentBgImage)
setCurrentCanvasPlan((prev) => ({
...prev,
bgImageName: refImage?.name ?? null,
mapPositionAddress: queryRef.current.value,
}))
}, [currentBgImage]) }, [currentBgImage])
/** /**
@ -147,15 +159,17 @@ export function useRefFiles() {
const handleUploadImageRefFile = async (file) => { const handleUploadImageRefFile = async (file) => {
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
formData.append('fileName', currentCanvasPlan.id) // formData.append('fileName', currentCanvasPlan.id)
// const res = await post({ url: `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/image-upload`, data: formData }) // const res = await post({ url: `${process.env.NEXT_PUBLIC_API_SERVER_PATH}/api/image-upload`, data: formData })
const res = await post({ url: `http://localhost:3000/api/image-upload`, data: formData }) const res = await post({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/upload`,
data: formData,
})
console.log('🚀 ~ handleUploadImageRefFile ~ res:', res) console.log('🚀 ~ handleUploadImageRefFile ~ res:', res)
const image = await readImage(res.fileNm) // const image = await readImage(res.filePath)
console.log('🚀 ~ handleUploadImageRefFile ~ file:', image) // console.log('🚀 ~ handleUploadImageRefFile ~ file:', image)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
setCurrentBgImage(image)
setRefImage(file) setRefImage(file)
} }
@ -167,15 +181,24 @@ export function useRefFiles() {
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
await promisePost({ url: converterUrl, data: formData }) const res = await post({ url: converterUrl, data: formData })
.then((res) => { console.log('🚀 ~ handleUploadConvertRefFile ~ res:', res)
convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData) const result = await post({
swalFire({ text: '파일 변환 성공' }) url: `${process.env.NEXT_PUBLIC_HOST_URL}/cad/convert`,
setRefImage(res.data.Files[0].FileData) data: res,
}) })
.catch((err) => { console.log('🚀 ~ handleUploadConvertRefFile ~ result:', result)
swalFire({ text: '파일 변환 실패', icon: 'error' }) setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${result.filePath}`)
}) setRefImage(res.Files[0].FileData)
// await promisePost({ url: converterUrl, data: formData })
// .then((res) => {
// convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
// swalFire({ text: '파일 변환 성공' })
// setRefImage(res.data.Files[0].FileData)
// })
// .catch((err) => {
// swalFire({ text: '파일 변환 실패', icon: 'error' })
// })
} }
/** /**

View File

@ -16,7 +16,9 @@ export function useRoof() {
.filter((polygon) => polygon.name === 'roof') .filter((polygon) => polygon.name === 'roof')
.forEach((polygon) => { .forEach((polygon) => {
if (allocDisplay) { if (allocDisplay) {
setSurfaceShapePattern(polygon, roofDisplay.column) if (polygon.roofMaterial) {
setSurfaceShapePattern(polygon, roofDisplay.column, false, polygon.roofMaterial, true)
}
} else { } else {
polygon.set('fill', null) polygon.set('fill', null)
} }

View File

@ -1,10 +1,11 @@
import { useRecoilValue } from 'recoil' import { useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { selectedRoofMaterialSelector } from '@/store/settingAtom' import { selectedRoofMaterialSelector } from '@/store/settingAtom'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { outerLinePointsState } from '@/store/outerLineAtom'
const ROOF_COLOR = { const ROOF_COLOR = {
0: 'rgb(199,240,213)', 0: 'rgb(199,240,213)',
@ -17,22 +18,27 @@ export function useRoofFn() {
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
const currentObject = useRecoilValue(currentObjectState) const currentObject = useRecoilValue(currentObjectState)
const { addCanvasMouseEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, initEvent } = useEvent()
const resetPoints = useResetRecoilState(outerLinePointsState)
const { addPitchText } = useLine() const { addPitchText } = useLine()
//면형상 선택 클릭시 지붕 패턴 입히기 //면형상 선택 클릭시 지붕 패턴 입히기
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial = selectedRoofMaterial, isForceChange = false) { function setSurfaceShapePattern(
polygon,
mode = 'onlyBorder',
trestleMode = false,
roofMaterial = selectedRoofMaterial,
isForceChange = false,
isDisplay = false,
) {
if (!polygon) { if (!polygon) {
return return
} }
if (isForceChange) { if (isForceChange && !isDisplay) {
if (polygon.roofMaterial) { /*if (polygon.roofMaterial) {
polygon.roofMaterial = null polygon.roofMaterial = null
} }*/
} }
if (polygon.roofMaterial) {
return
}
const ratio = window.devicePixelRatio || 1 const ratio = window.devicePixelRatio || 1
const layout = roofMaterial.layout const layout = roofMaterial.layout
@ -303,5 +309,33 @@ export function useRoofFn() {
return area.points.map((p) => fabric.util.transformPoint({ x: p.x - area.pathOffset.x, y: p.y - area.pathOffset.y }, area.calcTransformMatrix())) return area.points.map((p) => fabric.util.transformPoint({ x: p.x - area.pathOffset.x, y: p.y - area.pathOffset.y }, area.calcTransformMatrix()))
} }
return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } const removeOuterLines = (currentMousePos) => {
const roofBase = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
.filter((roof) => roof.inPolygon(currentMousePos))
if (roofBase.length === 0) {
return
}
const roof = roofBase[0]
const wall = roof.wall
canvas.remove(roof)
canvas.remove(wall)
const allRoofObject = canvas
.getObjects()
.filter((obj) => /*obj !== roof && obj !== wall &&*/ obj.attributes?.roofId === roof.id || obj.parentId === roof.id || obj.parentId === wall.id)
allRoofObject.forEach((obj) => {
canvas.remove(obj)
})
canvas.renderAll()
resetPoints()
}
return { setSurfaceShapePattern, removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines }
} }

View File

@ -80,7 +80,6 @@ export const useEstimateController = (planNo) => {
res.data.pkgAsp = roundedNumber.toString() res.data.pkgAsp = roundedNumber.toString()
} }
setEstimateContextState(res.data) setEstimateContextState(res.data)
} }
} }
@ -155,7 +154,7 @@ export const useEstimateController = (planNo) => {
}) })
.catch((error) => { .catch((error) => {
console.log('::FileDownLoad Error::', error) console.log('::FileDownLoad Error::', error)
alert('File does not exist.') return swalFire({ text: getMessage('File does not exist'), type: 'alert' })
}) })
} }
@ -169,19 +168,19 @@ export const useEstimateController = (planNo) => {
if (estimateData?.charger === null || estimateData?.charger?.trim().length === 0) { if (estimateData?.charger === null || estimateData?.charger?.trim().length === 0) {
flag = false flag = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredCharger')) return swalFire({ text: getMessage('estimate.detail.save.requiredCharger'), type: 'alert' })
} }
if (estimateData?.objectName === null || estimateData?.objectName?.trim().length === 0) { if (estimateData?.objectName === null || estimateData?.objectName?.trim().length === 0) {
flag = false flag = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredObjectName')) return swalFire({ text: getMessage('estimate.detail.save.requiredObjectName'), type: 'alert' })
} }
if (isNaN(Date.parse(estimateData.estimateDate))) { if (isNaN(Date.parse(estimateData.estimateDate))) {
flag = false flag = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredEstimateDate')) return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateDate'), type: 'alert' })
} }
if (estimateData.estimateType === 'YJSS') { if (estimateData.estimateType === 'YJSS') {
@ -189,7 +188,7 @@ export const useEstimateController = (planNo) => {
if (pkgAsp === '0') { if (pkgAsp === '0') {
flag = false flag = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredPkgAsp')) return swalFire({ text: getMessage('estimate.detail.save.requiredPkgAsp'), type: 'alert' })
} }
} }
@ -209,6 +208,16 @@ export const useEstimateController = (planNo) => {
//기존에 첨부된 파일이 없으면 //기존에 첨부된 파일이 없으면
if (isEmptyArray(estimateData.newFileList)) { if (isEmptyArray(estimateData.newFileList)) {
//새로 첨부한 파일이 없으면 //새로 첨부한 파일이 없으면
//북면 먼저 체크
if (estimateData.fileFlg === '0') {
if (estimateData?.northArrangement === '1') {
fileFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredNorthArrangementFileUpload'), type: 'alert' })
}
}
if (estimateData.itemList.length > 1) { if (estimateData.itemList.length > 1) {
estimateData.itemList.map((row) => { estimateData.itemList.map((row) => {
if (row.delFlg === '0') { if (row.delFlg === '0') {
@ -217,7 +226,7 @@ export const useEstimateController = (planNo) => {
if (estimateData.fileFlg === '0') { if (estimateData.fileFlg === '0') {
fileFlg = false fileFlg = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredFileUpload')) return swalFire({ text: getMessage('estimate.detail.save.requiredFileUpload'), type: 'alert' })
} }
} }
} }
@ -235,7 +244,7 @@ export const useEstimateController = (planNo) => {
if (item.itemId === '') { if (item.itemId === '') {
itemFlg = false itemFlg = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredItemId')) return swalFire({ text: getMessage('estimate.detail.save.requiredItemId'), type: 'alert' })
} }
} }
@ -251,7 +260,7 @@ export const useEstimateController = (planNo) => {
if (item.amount < 1) { if (item.amount < 1) {
itemFlg = false itemFlg = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredAmount')) return swalFire({ text: getMessage('estimate.detail.save.requiredAmount'), type: 'alert' })
} }
if (estimateData.estimateType !== 'YJSS') { if (estimateData.estimateType !== 'YJSS') {
@ -263,7 +272,7 @@ export const useEstimateController = (planNo) => {
if (item.salePrice < 1) { if (item.salePrice < 1) {
itemFlg = false itemFlg = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredSalePrice')) return swalFire({ text: getMessage('estimate.detail.save.requiredSalePrice'), type: 'alert' })
} }
} }
@ -274,7 +283,7 @@ export const useEstimateController = (planNo) => {
if (isNaN(item.salePrice)) { if (isNaN(item.salePrice)) {
itemFlg = false itemFlg = false
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredSalePrice')) return swalFire({ text: getMessage('estimate.detail.save.requiredSalePrice'), type: 'alert' })
} }
} }
} }
@ -292,7 +301,7 @@ export const useEstimateController = (planNo) => {
}) })
if (delCnt === estimateData.itemList.length) { if (delCnt === estimateData.itemList.length) {
setIsGlobalLoading(false) setIsGlobalLoading(false)
return alert(getMessage('estimate.detail.save.requiredItem')) return swalFire({ text: getMessage('estimate.detail.save.requiredItem'), type: 'alert' })
} }
} }
@ -401,11 +410,19 @@ export const useEstimateController = (planNo) => {
*/ */
const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId) => { const handleEstimateCopy = async (sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId) => {
if (saleStoreId === '') { if (saleStoreId === '') {
return alert(getMessage('estimate.detail.productFeaturesPopup.requiredStoreId')) return swalFire({
text: getMessage('estimate.detail.productFeaturesPopup.requiredStoreId'),
type: 'alert',
icon: 'warning',
})
} }
if (copyReceiveUser.trim().length === 0) { if (copyReceiveUser.trim().length === 0) {
return alert(getMessage('estimate.detail.productFeaturesPopup.requiredReceiveUser')) return swalFire({
text: getMessage('estimate.detail.productFeaturesPopup.requiredReceiveUser'),
type: 'alert',
icon: 'warning',
})
} }
const params = { const params = {
saleStoreId: session.storeId, saleStoreId: session.storeId,

View File

@ -0,0 +1,80 @@
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { useCanvas } from '../useCanvas'
import { useAxios } from '../useAxios'
import { usePlan } from '../usePlan'
import { POLYGON_TYPE } from '@/common/common'
/**
* 이미지 로더 hook
* @returns {function} handleCanvasToPng
*/
export function useImgLoader() {
const canvas = useRecoilValue(canvasState)
const { currentCanvasPlan } = usePlan()
const { post } = useAxios()
/**
* 이미지 저장 왼쪽 , 오른쪽 아래 좌표
* return [start, end]
*/
const getImageCoordinates = () => {
const margin = 20
const objects = canvas.getObjects().filter((obj) => [POLYGON_TYPE.ROOF, 'lengthText', 'arrow'].includes(obj.name))
const minX = objects.reduce((acc, cur) => (cur.left < acc ? cur.left : acc), objects[0].left)
const minY = objects.reduce((acc, cur) => (cur.top < acc ? cur.top : acc), objects[0].top)
const maxX = objects.reduce((acc, cur) => (cur.left + cur.width > acc ? cur.left + cur.width : acc), 0)
const maxY = objects.reduce((acc, cur) => (cur.top + cur.height > acc ? cur.top + cur.height : acc), 0)
return [
{ x: minX - margin, y: minY - margin },
{ x: maxX + margin, y: maxY + margin },
]
}
/**
* 캔버스를 이미지로 저장
* @param {integer} type 1: 모듈만 있는 상태, 2: 가대까지 올린 상태
*/
const handleCanvasToPng = async (type) => {
removeMouseLines()
canvas.getObjects('image').forEach((obj) => {
if (obj.getSrc) {
const img = new Image()
img.crossOrigin = 'anonymous'
img.src = obj.getSrc()
obj.setElement(img)
}
})
canvas.renderAll()
const res = await post({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/canvas`,
data: {
objectNo: currentCanvasPlan.objectNo,
planNo: currentCanvasPlan.planNo,
type,
canvasToPng: canvas.toDataURL('image/png').replace('data:image/png;base64,', ''),
coordinates: getImageCoordinates(),
},
})
console.log('🚀 ~ handleCanvasToPng ~ res:', res)
}
/**
* 마우스 포인터의 가이드라인을 제거합니다.
*/
const removeMouseLines = () => {
if (canvas?._objects.length > 0) {
const mouseLines = canvas?._objects.filter((obj) => obj.name === 'mouseLine')
mouseLines.forEach((item) => canvas?.remove(item))
}
canvas?.renderAll()
}
return { handleCanvasToPng }
}

View File

@ -1,12 +1,15 @@
import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { isOverlap, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util' import { isOverlap, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util'
import { useRecoilValue } from 'recoil' import { useRecoilValue, useSetRecoilState } from 'recoil'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { useSwal } from '../useSwal' import { useSwal } from '../useSwal'
import { useModuleBasicSetting } from './useModuleBasicSetting' import { useModuleBasicSetting } from './useModuleBasicSetting'
import { useMessage } from '../useMessage' import { useMessage } from '../useMessage'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { moduleStatisticsState } from '@/store/circuitTrestleAtom'
import { useCircuitTrestle } from '../useCirCuitTrestle'
export const MODULE_REMOVE_TYPE = { export const MODULE_REMOVE_TYPE = {
LEFT: 'left', LEFT: 'left',
@ -35,6 +38,8 @@ export function useModule() {
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { checkModuleDisjointObjects } = useModuleBasicSetting() const { checkModuleDisjointObjects } = useModuleBasicSetting()
const selectedModules = useRecoilValue(selectedModuleState)
const { setModuleStatisticsData } = useCircuitTrestle()
const moduleMove = (length, direction) => { const moduleMove = (length, direction) => {
const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴 const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴
@ -42,6 +47,7 @@ export function useModule() {
canvas.discardActiveObject() //선택해제 canvas.discardActiveObject() //선택해제
debugger
const isSetupModules = getOtherModules(selectedObj) const isSetupModules = getOtherModules(selectedObj)
const selectedModules = canvas.getObjects().filter((obj) => selectedIds.includes(obj.id) && obj.name === 'module') //선택했던 객체들만 가져옴 const selectedModules = canvas.getObjects().filter((obj) => selectedIds.includes(obj.id) && obj.name === 'module') //선택했던 객체들만 가져옴
const setupSurface = canvas const setupSurface = canvas
@ -141,104 +147,113 @@ export function useModule() {
} }
} }
const moduleMoveAll = (length, direction) => { const moduleMoveAll = (length, direction, surfaceArray) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] surfaceArray.forEach((surface) => {
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) const modules = canvas
const objects = getObjects() .getObjects()
.filter((module) => module.name === POLYGON_TYPE.MODULE)
.filter((module) => module.surfaceId === surface.id)
const objects = getObjects()
let isWarning = false let isWarning = false
modules.forEach((module) => { modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false) const { top, left } = getPosotion(module, direction, length, false)
module.originPos = { module.originPos = {
top: module.top, top: module.top,
left: module.left, left: module.left,
fill: module.fill, fill: module.fill,
} }
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, surface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
module.set({ top, left })
module.setCoords()
canvas.renderAll() canvas.renderAll()
if (isWarning) {
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { swalFire({
isWarning = true title: getMessage('can.not.move.module'),
module.set({ fill: 'red' }) icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
} }
}) })
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
} }
const moduleCopyAll = (length, direction) => { const moduleCopyAll = (length, direction, surfaceArray) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] surfaceArray.forEach((surface) => {
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) const modules = canvas
const objects = getObjects() .getObjects()
const copyModules = [] .filter((module) => module.name === POLYGON_TYPE.MODULE)
let copyModule = null .filter((module) => module.surfaceId === surface.id)
let isWarning = false const objects = getObjects()
let moduleLength = 0 const copyModules = []
if (['up', 'down'].includes(direction)) {
modules.sort((a, b) => a.top - b.top)
moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top)
} else if (['left', 'right'].includes(direction)) {
modules.sort((a, b) => a.left - b.left)
moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left)
}
modules.forEach((module) => { let copyModule = null
const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false) let isWarning = false
module.clone((obj) => { let moduleLength = 0
obj.set({ if (['up', 'down'].includes(direction)) {
parentId: module.parentId, modules.sort((a, b) => a.top - b.top)
initOptions: module.initOptions, moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top)
direction: module.direction, } else if (['left', 'right'].includes(direction)) {
arrow: module.arrow, modules.sort((a, b) => a.left - b.left)
name: module.name, moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left)
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, moduleSetupSurface)) {
isWarning = true
copyModule.set({ fill: 'red' })
} }
canvas.renderAll()
})
if (isWarning) { modules.forEach((module) => {
swalFire({ const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
title: getMessage('can.not.copy.module'), module.clone((obj) => {
icon: 'error', obj.set({
type: 'alert', parentId: module.parentId,
confirmFn: () => { initOptions: module.initOptions,
canvas.remove(...copyModules) direction: module.direction,
canvas.renderAll() arrow: module.arrow,
}, name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, surface)) {
isWarning = true
copyModule.set({ fill: 'red' })
}
canvas.renderAll()
}) })
}
if (isWarning) {
swalFire({
title: getMessage('can.not.copy.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
canvas.remove(...copyModules)
canvas.renderAll()
},
})
}
})
} }
const moduleCopy = (length, direction) => { const moduleCopy = (length, direction) => {
@ -298,7 +313,10 @@ export function useModule() {
canvas.renderAll() canvas.renderAll()
}, },
}) })
} else {
moduleSetupSurface.set({ modules: [...moduleSetupSurface.modules, ...copyModules] })
} }
setModuleStatisticsData()
} }
const moduleMultiCopy = (type, length, direction) => { const moduleMultiCopy = (type, length, direction) => {
@ -372,6 +390,9 @@ export function useModule() {
canvas.renderAll() canvas.renderAll()
}, },
}) })
} else {
moduleSetupSurface.set({ modules: [...moduleSetupSurface.modules, ...copyModules] })
setModuleStatisticsData()
} }
} }
@ -487,6 +508,7 @@ export function useModule() {
}, },
}) })
} }
setModuleStatisticsData()
} }
const moduleRowRemove = (type) => { const moduleRowRemove = (type) => {
@ -602,6 +624,7 @@ export function useModule() {
}, },
}) })
} }
setModuleStatisticsData()
} }
const moduleColumnInsert = (type) => { const moduleColumnInsert = (type) => {
@ -697,6 +720,7 @@ export function useModule() {
}, },
}) })
} }
setModuleStatisticsData()
} }
const muduleRowInsert = (type) => { const muduleRowInsert = (type) => {
@ -794,66 +818,80 @@ export function useModule() {
}, },
}) })
} }
setModuleStatisticsData()
} }
const alignModule = (type) => { const alignModule = (type, surfaceArray) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] surfaceArray.forEach((surface) => {
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE) const modules = canvas
const objects = getObjects() .getObjects()
let [top, bottom, left, right] = [0, 0, 0, 0] .filter((module) => module.name === POLYGON_TYPE.MODULE)
.filter((module) => module.surfaceId === surface.id)
top = Math.min(...modules.map((module) => module.top)) const objects = getObjects()
bottom = Math.max(...modules.map((module) => module.top + module.height)) let [top, bottom, left, right] = [0, 0, 0, 0]
left = Math.min(...modules.map((module) => module.left))
right = Math.max(...modules.map((module) => module.left + module.width))
const moduleSurfacePos = {
top: Math.min(...moduleSetupSurface.points.map((point) => point.y)),
left: Math.min(...moduleSetupSurface.points.map((point) => point.x)),
}
const [height, width] = [bottom - top, right - left]
const verticalCenterLength = moduleSurfacePos.top + moduleSetupSurface.height / 2 - (top + height / 2)
const horizontalCenterLength = moduleSurfacePos.left + moduleSetupSurface.width / 2 - (left + width / 2)
let isWarning = false
canvas.discardActiveObject() top = Math.min(...modules.map((module) => module.top))
modules.forEach((module) => { bottom = Math.max(...modules.map((module) => module.top + module.height))
module.originPos = { left = Math.min(...modules.map((module) => module.left))
left: module.left, right = Math.max(...modules.map((module) => module.left + module.width))
top: module.top, const moduleSurfacePos = {
fill: module.fill, top: Math.min(...surface.points.map((point) => point.y)),
} left: Math.min(...surface.points.map((point) => point.x)),
if (type === MODULE_ALIGN_TYPE.VERTICAL) {
module.set({ top: module.top + verticalCenterLength })
} else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) {
module.set({ left: module.left + horizontalCenterLength })
} }
const [height, width] = [bottom - top, right - left]
const verticalCenterLength = moduleSurfacePos.top + surface.height / 2 - (top + height / 2)
const horizontalCenterLength = moduleSurfacePos.left + surface.width / 2 - (left + width / 2)
let isWarning = false
canvas.discardActiveObject()
modules.forEach((module) => {
module.originPos = {
left: module.left,
top: module.top,
fill: module.fill,
}
if (type === MODULE_ALIGN_TYPE.VERTICAL) {
module.set({ top: module.top + verticalCenterLength })
} else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) {
module.set({ left: module.left + horizontalCenterLength })
}
canvas.renderAll()
module.setCoords()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, surface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
canvas.renderAll() canvas.renderAll()
module.setCoords() if (isWarning) {
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) { swalFire({
isWarning = true title: getMessage('can.not.align.module'),
module.set({ fill: 'red' }) icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
} }
}) })
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.align.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
} }
const modulesRemove = () => { const modulesRemove = () => {
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
if (activeModule.circuit) {
swalFire({
title: getMessage('can.not.remove.module'),
icon: 'error',
type: 'alert',
})
return
}
const modules = canvas const modules = canvas
.getObjects() .getObjects()
.filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE && activeModule.id !== obj.id) .filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE && activeModule.id !== obj.id)
@ -861,6 +899,20 @@ export function useModule() {
surface.set({ modules: modules }) surface.set({ modules: modules })
canvas.remove(activeModule) canvas.remove(activeModule)
canvas.renderAll() canvas.renderAll()
setModuleStatisticsData()
}
const moduleRoofRemove = (surfaceArray) => {
surfaceArray.forEach((surface) => {
surface.modules = []
canvas
.getObjects()
.filter((module) => module.name === POLYGON_TYPE.MODULE && module.surfaceId === surface.id)
.forEach((module) => {
canvas.remove(module)
})
})
setModuleStatisticsData()
} }
const isOverlapOtherModules = (module, otherModules) => { const isOverlapOtherModules = (module, otherModules) => {
@ -941,6 +993,7 @@ export function useModule() {
moduleColumnInsert, moduleColumnInsert,
muduleRowInsert, muduleRowInsert,
modulesRemove, modulesRemove,
moduleRoofRemove,
alignModule, alignModule,
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@ import offsetPolygon from '@/util/qpolygon-utils'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { useSwal } from '@/hooks/useSwal'
import { useMessage } from '@/hooks/useMessage'
export function useModulePlace() { export function useModulePlace() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -23,211 +25,9 @@ export function useModulePlace() {
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addTargetMouseEventListener } = useEvent() const { addTargetMouseEventListener } = useEvent()
const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState) const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState)
const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false)
useEffect(() => { const { swalFire } = useSwal()
if (moduleSelectionData) { const { getMessage } = useMessage()
const common = moduleSelectionData.common
const roofConstructions = moduleSelectionData.roofConstructions
const listParams = roofConstructions.map((item) => {
return {
...common,
moduleTpCd: selectedModules.itemTp,
roofMatlCd: item.trestle.roofMatlCd,
trestleMkrCd: item.trestle.trestleMkrCd,
constMthdCd: item.trestle.constMthdCd,
roofBaseCd: item.trestle.roofBaseCd,
constTp: item.construction.constTp,
mixMatlNo: selectedModules.mixMatlNo,
roofPitch: item.addRoof.roofPchBase ? item.addRoof.roofPchBase : null,
inclCd: String(item.addRoof.pitch),
roofIndex: item.addRoof.index,
workingWidth: item.addRoof.lenBase,
}
})
setTrestleDetailParams(listParams)
}
}, [moduleSelectionData])
const getTrestleDetailListData = async () => {
const trestleDetailList = await getTrestleDetailList(trestleDetailParams)
if (trestleDetailList.length > 0) {
setTrestleDetailList(trestleDetailList)
}
}
useEffect(() => {
if (trestleDetailParams.length > 0) {
getTrestleDetailListData(trestleDetailParams)
}
}, [trestleDetailParams])
useEffect(() => {
if (trestleDetailList.length > 0) {
//지붕을 가져옴
canvas
.getObjects()
.filter((roof) => roof.name === 'roof')
.forEach((roof) => {
const roofIndex = roof.roofMaterial.index //지붕의 지붕재의 순번
trestleDetailList.forEach((detail) => {
if (detail.data !== null) {
if (Number(detail.data.roofIndex) === roofIndex) {
//roof에 상세 데이터 추가
roof.set({ trestleDetail: detail.data })
//배치면 설치 영역
makeModuleInstArea(roof, detail.data)
//surface에 상세 데이터 추가
} else {
console.log('가대 데이터가 없네요...')
}
}
})
})
}
}, [trestleDetailList])
const makeModuleInstArea = (roof, trestleDetail) => {
//지붕 객체 반환
if (!roof) {
return
}
const batchObjects = canvas
?.getObjects()
.filter(
(obj) =>
obj.name === BATCH_TYPE.OPENING ||
obj.name === BATCH_TYPE.SHADOW ||
obj.name === BATCH_TYPE.TRIANGLE_DORMER ||
obj.name === BATCH_TYPE.PENTAGON_DORMER,
) //도머s 객체
//도머도 외곽을 따야한다
const batchObjectOptions = {
stroke: 'red',
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
selectable: true,
name: POLYGON_TYPE.OBJECT_SURFACE,
originX: 'center',
originY: 'center',
}
batchObjects.forEach((obj) => {
if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) {
const groupPoints = obj.groupPoints
const offsetObjects = offsetPolygon(groupPoints, 10)
const dormerOffset = new QPolygon(offsetObjects, batchObjectOptions)
dormerOffset.setViewLengthText(false)
canvas.add(dormerOffset) //모듈설치면 만들기
} else {
const points = obj.points
const offsetObjects = offsetPolygon(points, 10)
const offset = new QPolygon(offsetObjects, batchObjectOptions)
offset.setViewLengthText(false)
canvas.add(offset) //모듈설치면 만들기
}
})
const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id)
if (isExistSurface) {
return
}
let offsetLength = canvasSetting.roofSizeSet === 3 ? -90 : (trestleDetail.eaveIntvl / 10) * -1
setSurfaceShapePattern(roof, roofDisplay.column, true) //패턴 변경
const offsetPoints = offsetPolygon(roof.points, offsetLength) //안쪽 offset
//모듈설치영역?? 생성
const surfaceId = uuidv4()
let setupSurface = new QPolygon(offsetPoints, {
stroke: 'red',
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
selectable: true,
parentId: roof.id, //가대 폴리곤의 임시 인덱스를 넣어줌
name: POLYGON_TYPE.MODULE_SETUP_SURFACE,
flowDirection: roof.direction,
direction: roof.direction,
flipX: roof.flipX,
flipY: roof.flipY,
surfaceId: surfaceId,
originX: 'center',
originY: 'center',
modules: [],
roofMaterial: roof.roofMaterial,
trestleDetail: trestleDetail,
// angle: -compasDeg,
})
setupSurface.setViewLengthText(false)
canvas.add(setupSurface) //모듈설치면 만들기
//지붕면 선택 금지
roof.set({
selectable: false,
})
//모듈설치면 클릭이벤트
addTargetMouseEventListener('mousedown', setupSurface, function () {
toggleSelection(setupSurface)
})
}
let selectedModuleInstSurfaceArray = []
//설치 범위 지정 클릭 이벤트
const toggleSelection = (setupSurface) => {
const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId)
//최초 선택일때
if (!isExist) {
//기본 선택이랑 스트로크 굵기가 같으면 선택 안됨으로 봄
setupSurface.set({
...setupSurface,
strokeWidth: 3,
strokeDashArray: [0],
fill: 'transparent',
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//중복으로 들어가는걸 방지하기 위한 코드
canvas?.renderAll()
selectedModuleInstSurfaceArray.push(setupSurface)
} else {
//선택후 재선택하면 선택안됨으로 변경
setupSurface.set({
...setupSurface,
fill: 'transparent',
strokeDashArray: [10, 4],
strokeWidth: 1,
})
canvas.discardActiveObject() // 객체의 활성 상태 해제
//폴리곤에 커스텀 인덱스를 가지고 해당 배열 인덱스를 찾아 삭제함
const removeIndex = setupSurface.parentId
const removeArrayIndex = selectedModuleInstSurfaceArray.findIndex((obj) => obj.parentId === removeIndex)
selectedModuleInstSurfaceArray.splice(removeArrayIndex, 1)
}
canvas?.renderAll()
setModuleSetupSurface([...selectedModuleInstSurfaceArray])
}
return { return {
selectedModules, selectedModules,

View File

@ -5,8 +5,11 @@ import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode' import { useCommonCode } from '@/hooks/common/useCommonCode'
import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDataState } from '@/store/selectedModuleOptions' import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import { canvasState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
export function useModuleSelection(props) { export function useModuleSelection(props) {
const canvas = useRecoilValue(canvasState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const [roughnessCodes, setRoughnessCodes] = useState([]) //면조도 목록 const [roughnessCodes, setRoughnessCodes] = useState([]) //면조도 목록
@ -41,6 +44,7 @@ export function useModuleSelection(props) {
instHt: managementState?.installHeight, //설치높이 instHt: managementState?.installHeight, //설치높이
stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속 stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속
stdSnowLd: managementState?.verticalSnowCover, //기준적설량 stdSnowLd: managementState?.verticalSnowCover, //기준적설량
saleStoreNorthFlg: managementState?.saleStoreNorthFlg, //북쪽 설치 여부
} }
if (selectedModules) { if (selectedModules) {
@ -62,6 +66,7 @@ export function useModuleSelection(props) {
// 202000 풍속 // 202000 풍속
const windCodeList = findCommonCode('202000') const windCodeList = findCommonCode('202000')
windCodeList.forEach((obj) => { windCodeList.forEach((obj) => {
obj.name = obj.clCodeNm obj.name = obj.clCodeNm
obj.id = obj.clCode obj.id = obj.clCode
@ -83,6 +88,17 @@ export function useModuleSelection(props) {
} }
getModuleData(roofsIds) getModuleData(roofsIds)
//해당 메뉴 이동시 배치면 삭제
const moduleSurfacesArray = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.MODULE)
if (moduleSurfacesArray.length > 0) {
moduleSurfacesArray.forEach((moduleSurface) => {
canvas.remove(moduleSurface)
})
canvas.renderAll()
}
}, []) }, [])
const getModuleData = async (roofsIds) => { const getModuleData = async (roofsIds) => {
@ -98,7 +114,9 @@ export function useModuleSelection(props) {
} }
//데이터가 있으면 모듈 자동 선택 //데이터가 있으면 모듈 자동 선택
//1번 모듈 리스트 조회
useEffect(() => { useEffect(() => {
//모듈리스트의 데이터가 변경 되면 모듈 선택으로 이벤트
if (moduleList.length > 0 && isObjectNotEmpty(moduleSelectionData.module)) { if (moduleList.length > 0 && isObjectNotEmpty(moduleSelectionData.module)) {
handleChangeModule(moduleSelectionData.module) handleChangeModule(moduleSelectionData.module)
} }

View File

@ -5,10 +5,8 @@ import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode' import { useCommonCode } from '@/hooks/common/useCommonCode'
import { moduleSelectionDataState, moduleSelectionInitParamsState, selectedModuleState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState, moduleSelectionInitParamsState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty, isEqualObjects } from '@/util/common-utils' import { isObjectNotEmpty, isEqualObjects } from '@/util/common-utils'
import { addedRoofsState } from '@/store/settingAtom'
export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData }) { export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData }) {
const addRoofsArray = useRecoilValue(addedRoofsState)
const globalPitchText = useRecoilValue(pitchTextSelector) //피치 텍스트 const globalPitchText = useRecoilValue(pitchTextSelector) //피치 텍스트
const { findCommonCode } = useCommonCode() const { findCommonCode } = useCommonCode()
@ -31,7 +29,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
const [roofBaseParams, setRoofBaseParams] = useState({}) //지붕밑바탕 관련 api호출 파라메터 const [roofBaseParams, setRoofBaseParams] = useState({}) //지붕밑바탕 관련 api호출 파라메터
const moduleSelectionInitParams = useRecoilValue(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등 const moduleSelectionInitParams = useRecoilValue(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const moduleSelectionInitOriginData = useRef(moduleSelectionInitParams) const moduleSelectionInitOriginData = useRef({})
const { getTrestleList, getConstructionList } = useMasterController() const { getTrestleList, getConstructionList } = useMasterController()
@ -55,6 +53,8 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
const hajebichiRef = useRef() const hajebichiRef = useRef()
const lengthRef = useRef() const lengthRef = useRef()
const [isChangeInitData, setIsChangeInitData] = useState(false)
//서까래간격 변경 //서까래간격 변경
const handleChangeRaftBase = (option) => { const handleChangeRaftBase = (option) => {
setSelectedRaftBase(option) setSelectedRaftBase(option)
@ -62,7 +62,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
// setConstMthdList([]) //공법 초기화 // setConstMthdList([]) //공법 초기화
// setRoofBaseList([]) //지붕밑바탕 초기화 // setRoofBaseList([]) //지붕밑바탕 초기화
// setConstructionList([]) //공법 초기화 // setConstructionList([]) //공법 초기화
resetSelected() resetSelected(1)
} }
//처마력바 체크 //처마력바 체크
@ -109,11 +109,13 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//리코일에 데이터가 담기는 시점에 시작 //리코일에 데이터가 담기는 시점에 시작
useEffect(() => { useEffect(() => {
if ( if (
isObjectNotEmpty(moduleSelectionData) &&
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex]) && isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex]) &&
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].trestle) && isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].trestle) &&
isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].construction) isObjectNotEmpty(moduleSelectionData.roofConstructions[tabIndex].construction)
) { ) {
setModuleConstructionSelectionData(moduleSelectionData.roofConstructions[tabIndex]) const roofConstructions = moduleSelectionData.roofConstructions.filter((item) => item.roofIndex === tabIndex)[0]
setModuleConstructionSelectionData(roofConstructions)
} }
}, [moduleSelectionData]) }, [moduleSelectionData])
@ -123,18 +125,30 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
} }
}, [moduleConstructionSelectionData]) }, [moduleConstructionSelectionData])
// useEffect(() => { useEffect(() => {
// if (isExistData) { //되돌아왔을때 재호출 하여 선택한다
// setConstructionListParams({ if (isExistData) {
// ...moduleSelectionInitParams, setTrestleParams({
// ...roofBaseParams, moduleTpCd: selectedModules.itemTp,
// roofBaseCd: selectedRoofBase.roofBaseCd, roofMatlCd: addRoof.roofMatlCd,
// inclCd: addRoof.pitch, raftBaseCd: selectedRaftBase.raftBaseCd ? selectedRaftBase.raftBaseCd : '',
// roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0, workingWidth: lengthBase,
// raftBaseCd: selectedRaftBase.raftBaseCd ? selectedRaftBase.raftBaseCd : '', })
// }) }
// } }, [isExistData])
// }, [selectedRoofBase])
useEffect(() => {
if (isExistData) {
setConstructionListParams({
...moduleSelectionInitParams,
...roofBaseParams,
roofBaseCd: selectedRoofBase.roofBaseCd,
inclCd: addRoof.pitch,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
raftBaseCd: selectedRaftBase.raftBaseCd ? selectedRaftBase.raftBaseCd : '',
})
}
}, [selectedRoofBase])
useEffect(() => { useEffect(() => {
if ( if (
@ -154,7 +168,9 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//모듈 변경 //모듈 변경
useEffect(() => { useEffect(() => {
//lengbase는 무조건 있다고 가정 하고 최초에 실행 방지 //lengbase는 무조건 있다고 가정 하고 최초에 실행 방지
if (selectedModules) { if (selectedModules) {
//여기서부터 시작
//가대메이커 파라메터 만들기 //가대메이커 파라메터 만들기
setTrestleParams({ setTrestleParams({
moduleTpCd: selectedModules.itemTp, moduleTpCd: selectedModules.itemTp,
@ -174,8 +190,11 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//가대메이커 변경 함수 //가대메이커 변경 함수
const handleChangeTrestle = (option) => { const handleChangeTrestle = (option) => {
setSelectedTrestle(option) //선택값 저장 if (isObjectNotEmpty(option)) {
setConstructionParams({ ...trestleParams, trestleMkrCd: option.trestleMkrCd, constMthdCd: '', roofBaseCd: '' }) option.raftBaseCd = selectedRaftBase.raftBaseCd
setSelectedTrestle(option) //선택값 저장
setConstructionParams({ ...trestleParams, trestleMkrCd: option.trestleMkrCd, constMthdCd: '', roofBaseCd: '' })
}
} }
useEffect(() => { useEffect(() => {
@ -186,13 +205,15 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//공법 변경 //공법 변경
const handleChangeConstMthd = (option) => { const handleChangeConstMthd = (option) => {
setSelectedConstMthd(option) //선택된값 저장 if (isObjectNotEmpty(option)) {
setRoofBaseParams({ setSelectedConstMthd(option) //선택된값 저장
...trestleParams, setRoofBaseParams({
trestleMkrCd: selectedTrestle.trestleMkrCd, ...trestleParams,
constMthdCd: option.constMthdCd, trestleMkrCd: selectedTrestle.trestleMkrCd,
roofBaseCd: '', constMthdCd: option.constMthdCd,
}) roofBaseCd: '',
})
}
} }
useEffect(() => { useEffect(() => {
@ -202,17 +223,19 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
}, [roofBaseParams]) }, [roofBaseParams])
const handleChangeRoofBase = (option) => { const handleChangeRoofBase = (option) => {
setConstructionListParams({ if (isObjectNotEmpty(option)) {
...moduleSelectionInitParams, setConstructionListParams({
trestleMkrCd: selectedTrestle.trestleMkrCd, ...moduleSelectionInitParams,
constMthdCd: selectedConstMthd.constMthdCd, trestleMkrCd: selectedTrestle.trestleMkrCd,
roofBaseCd: option.roofBaseCd, constMthdCd: selectedConstMthd.constMthdCd,
inclCd: addRoof.pitch, roofBaseCd: option.roofBaseCd,
roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0, inclCd: addRoof.pitch,
raftBaseCd: selectedRaftBase.clCode ? selectedRaftBase.clCode : '', roofPitch: hajebichiRef.current ? hajebichiRef.current.value : 0,
roofMatlCd: addRoof.roofMatlCd, raftBaseCd: selectedRaftBase.clCode ? selectedRaftBase.clCode : '',
}) roofMatlCd: addRoof.roofMatlCd,
setSelectedRoofBase(option) })
setSelectedRoofBase(option)
}
} }
//공법 리스트 변경 함수 //공법 리스트 변경 함수
@ -266,32 +289,30 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//공법 선택시 이후 프로세스 //공법 선택시 이후 프로세스
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(selectedRoofBase) && isObjectNotEmpty(selectedConstruction)) { if (isObjectNotEmpty(selectedRoofBase) && isObjectNotEmpty(selectedConstruction)) {
if (tabIndex === roofTab) { const common = { ...moduleSelectionInitParams }
const common = { ...moduleSelectionInitParams } const module = { ...selectedModules }
const module = { ...selectedModules } const newRoofConstructions = {
const newRoofConstructions = { roofIndex: tabIndex,
roofIndex: tabIndex, addRoof: addRoof,
addRoof: addRoof, trestle: selectedRoofBase,
trestle: selectedRoofBase, construction: selectedConstruction,
construction: selectedConstruction, }
}
const index = tempModuleSelectionData.roofConstructions.findIndex((obj) => obj.roofIndex === tabIndex) const index = moduleSelectionData.roofConstructions.findIndex((obj) => obj.roofIndex === tabIndex)
if (index > -1) { if (index > -1) {
const newArray = [ const newArray = [
...tempModuleSelectionData.roofConstructions.slice(0, index), ...tempModuleSelectionData.roofConstructions.slice(0, index),
newRoofConstructions, newRoofConstructions,
...tempModuleSelectionData.roofConstructions.slice(index + 1), ...tempModuleSelectionData.roofConstructions.slice(index + 1),
] ]
setTempModuleSelectionData({ common: common, module: module, roofConstructions: newArray }) setTempModuleSelectionData({ common: common, module: module, roofConstructions: newArray })
} else { } else {
setTempModuleSelectionData({ setTempModuleSelectionData({
common: common, common: common,
module: module, module: module,
roofConstructions: [...tempModuleSelectionData.roofConstructions, { ...newRoofConstructions }], roofConstructions: [...tempModuleSelectionData.roofConstructions, { ...newRoofConstructions }],
}) })
}
} }
} }
}, [selectedConstruction]) }, [selectedConstruction])
@ -299,12 +320,11 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
//거대메이커, 공법, 지붕밑바탕 api 조회 //거대메이커, 공법, 지붕밑바탕 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 && isObjectNotEmpty(moduleConstructionSelectionData?.trestle)) {
//데이터가 있으면 선택된 가대 메이커를 선택한다 //데이터가 있으면 선택된 가대 메이커를 선택한다
handleChangeTrestle(moduleConstructionSelectionData?.trestle) handleChangeTrestle(moduleConstructionSelectionData?.trestle)
} else { } else {
@ -314,7 +334,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
} else if (type === 'construction') { } else if (type === 'construction') {
//공법일때 //공법일때
setConstMthdList(optionsList.data) //공법 목록 setConstMthdList(optionsList.data) //공법 목록
if (isExistData) { if (isExistData && isObjectNotEmpty(moduleConstructionSelectionData?.construction)) {
//데이터가 있으면 선택된 공법을 선택한다 //데이터가 있으면 선택된 공법을 선택한다
handleChangeConstMthd(moduleConstructionSelectionData?.trestle) handleChangeConstMthd(moduleConstructionSelectionData?.trestle)
} else { } else {
@ -323,7 +343,7 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
} else if (type === 'roofBase') { } else if (type === 'roofBase') {
//지붕밑바탕일때 //지붕밑바탕일때
setRoofBaseList(optionsList.data) //지붕밑바탕 목록 setRoofBaseList(optionsList.data) //지붕밑바탕 목록
if (isExistData) { if (isExistData && isObjectNotEmpty(moduleConstructionSelectionData?.trestle)) {
//데이터가 있으면 선택된 지붕밑바탕을 선택한다 //데이터가 있으면 선택된 지붕밑바탕을 선택한다
handleChangeRoofBase(moduleConstructionSelectionData?.trestle) //선택된 지붕밑바탕을 선택한다 handleChangeRoofBase(moduleConstructionSelectionData?.trestle) //선택된 지붕밑바탕을 선택한다
} }
@ -333,24 +353,40 @@ export function useModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab
useEffect(() => { useEffect(() => {
//모듈이 선택되어있을때 //모듈이 선택되어있을때
if (moduleSelectionInitOriginData.current.moduleItemId && moduleSelectionInitOriginData.current.moduleTpCd) { //초기 데이터가 모두 들어있을 경우에 초기 데이터를 저장한다
//초기에 들어온 데이터가 수정된 데이터가 값이 다르다면` if (
if (!isEqualObjects(moduleSelectionInitOriginData.current, moduleSelectionInitParams)) { moduleSelectionInitParams.illuminationTp &&
resetSelected() moduleSelectionInitParams.illuminationTpNm &&
moduleSelectionInitParams.instHt &&
moduleSelectionInitParams.moduleItemId &&
moduleSelectionInitParams.moduleTpCd &&
moduleSelectionInitParams.saleStoreNorthFlg &&
moduleSelectionInitParams.stdSnowLd &&
moduleSelectionInitParams.stdWindSpeed
) {
if (!isObjectNotEmpty(moduleSelectionInitOriginData.current)) {
moduleSelectionInitOriginData.current = moduleSelectionInitParams
} }
} }
if (
isObjectNotEmpty(moduleSelectionInitOriginData.current) &&
!isEqualObjects(moduleSelectionInitOriginData.current, moduleSelectionInitParams)
) {
resetSelected(2)
}
}, [moduleSelectionInitParams]) }, [moduleSelectionInitParams])
const handleHajebichiAndLength = (e, type) => { const handleHajebichiAndLength = (e, type) => {
if (type === 'length') { if (type === 'length') {
setLengthBase(e.target.value) setLengthBase(Number(e.target.value))
} else { } else {
setHajebichi(e.target.value) setHajebichi(Number(e.target.value))
} }
resetSelected() resetSelected(3)
} }
const resetSelected = () => { const resetSelected = (num) => {
//가대 선택 초기화 //가대 선택 초기화
setSelectedTrestle({}) setSelectedTrestle({})

View File

@ -23,10 +23,13 @@ export function useOrientation() {
}, []) }, [])
const nextStep = () => { const nextStep = () => {
if (isNaN(compasDeg)) {
setCompasDeg(0)
}
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => { roofs.forEach((roof) => {
roof.set({ roof.set({
moduleCompass: compasDeg, moduleCompass: isNaN(compasDeg) ? 0 : compasDeg,
}) })
drawDirectionArrow(roof) drawDirectionArrow(roof)
}) })

File diff suppressed because it is too large Load Diff

View File

@ -26,7 +26,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
useEffect(() => { useEffect(() => {
if (canvas) { if (canvas) {
dbClickEvent() // dbClickEvent()
} }
return () => { return () => {

View File

@ -36,6 +36,9 @@ import { useCanvasMenu } from '../common/useCanvasMenu'
import { menuTypeState } from '@/store/menuAtom' import { menuTypeState } from '@/store/menuAtom'
import { usePopup } from '../usePopup' import { usePopup } from '../usePopup'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
const defaultDotLineGridSetting = { const defaultDotLineGridSetting = {
INTERVAL: { INTERVAL: {
@ -114,6 +117,16 @@ export function useCanvasSetting() {
const [fetchRoofMaterials, setFetchRoofMaterials] = useRecoilState(fetchRoofMaterialsState) const [fetchRoofMaterials, setFetchRoofMaterials] = useRecoilState(fetchRoofMaterialsState)
const [type, setType] = useRecoilState(menuTypeState) const [type, setType] = useRecoilState(menuTypeState)
const setCurrentMenu = useSetRecoilState(currentMenuState) const setCurrentMenu = useSetRecoilState(currentMenuState)
const resetModuleSelectionData = useResetRecoilState(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
const resetSelectedModules = useResetRecoilState(selectedModuleState) //선택된 모듈
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
const [raftCodes, setRaftCodes] = useState([]) // 서까래 정보
const { findCommonCode } = useCommonCode()
const [currentRoof, setCurrentRoof] = useState(null) // 현재 선택된 지붕재 정보
const SelectOptions = [ const SelectOptions = [
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 }, { id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
{ id: 2, name: '1/2', value: 1 / 2 }, { id: 2, name: '1/2', value: 1 / 2 },
@ -128,10 +141,11 @@ export function useCanvasSetting() {
const { closeAll } = usePopup() const { closeAll } = usePopup()
useEffect(() => { useEffect(() => {
console.log('correntObjectNo', correntObjectNo) const tempFetchRoofMaterials = !fetchRoofMaterials
setFetchRoofMaterials(!fetchRoofMaterials) //최초 1회만 실행하도록 처리
if (fetchRoofMaterials) { setFetchRoofMaterials(tempFetchRoofMaterials)
if (tempFetchRoofMaterials) {
addRoofMaterials() addRoofMaterials()
} }
}, []) }, [])
@ -192,6 +206,16 @@ export function useCanvasSetting() {
} }
}, [roofMaterials, correntObjectNo]) }, [roofMaterials, correntObjectNo])
//배치면 초기설정 화면이 열리지 않아도 데이터 set 하기 위해서 추가
useEffect(() => {
if (addedRoofs.length > 0) {
const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList)
setCurrentRoof({ ...addedRoofs[0] })
}
}, [addedRoofs])
useEffect(() => { useEffect(() => {
if (!canvas) { if (!canvas) {
return return
@ -350,6 +374,8 @@ export function useCanvasSetting() {
roofAngle: 21.8, roofAngle: 21.8,
}, },
] ]
setMenuNumber(1)
} }
// 데이터 설정 // 데이터 설정
@ -368,6 +394,7 @@ export function useCanvasSetting() {
layout: roofsArray[i].roofLayout, layout: roofsArray[i].roofLayout,
roofSizeSet: roofsRow[i].roofSizeSet, roofSizeSet: roofsRow[i].roofSizeSet,
roofAngleSet: roofsRow[i].roofAngleSet, roofAngleSet: roofsRow[i].roofAngleSet,
roofDbData: roofsRow[i].roofDbData,
pitch: roofsArray[i].roofPitch, pitch: roofsArray[i].roofPitch,
angle: roofsArray[i].roofAngle, angle: roofsArray[i].roofAngle,
}) })
@ -446,6 +473,15 @@ export function useCanvasSetting() {
setType('outline') setType('outline')
setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
} }
//모듈 선택 데이터 초기화
resetModuleSelectionData()
moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] })
const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE)
if (!isModuleExist) {
resetSelectedModules()
}
} catch (error) { } catch (error) {
swalFire({ text: error.message, icon: 'error' }) swalFire({ text: error.message, icon: 'error' })
} }
@ -727,7 +763,7 @@ export function useCanvasSetting() {
for (let i = 0; i < option1.length; i++) { for (let i = 0; i < option1.length; i++) {
switch (option1[i].column) { switch (option1[i].column) {
case 'allocDisplay': //할당 표시 case 'allocDisplay': //할당 표시
optionName = ['1'] optionName = []
break break
case 'outlineDisplay': //외벽선 표시 case 'outlineDisplay': //외벽선 표시
optionName = ['outerLine', POLYGON_TYPE.WALL] optionName = ['outerLine', POLYGON_TYPE.WALL]
@ -742,19 +778,20 @@ export function useCanvasSetting() {
optionName = ['commonText'] optionName = ['commonText']
break break
case 'circuitNumDisplay': //회로번호 표시 case 'circuitNumDisplay': //회로번호 표시
optionName = ['7'] optionName = ['circuitNumber']
break break
case 'flowDisplay': //흐름방향 표시 case 'flowDisplay': //흐름방향 표시
optionName = ['arrow', 'flowText'] optionName = ['arrow', 'flowText']
break break
case 'trestleDisplay': //가대 표시 case 'trestleDisplay': //가대 표시
optionName = ['8'] optionName = ['rack', 'smartRack', 'bracket', 'eaveBar', 'halfEaveBar']
break break
case 'imageDisplay': //이미지 표시 case 'imageDisplay': //이미지 표시
optionName = ['9'] optionName = ['9']
break break
case 'totalDisplay': //집계표 표시 case 'totalDisplay': //집계표 표시
optionName = ['10'] // 작업할 필요 없음
optionName = []
break break
} }
// 표시 선택 상태(true/false) // 표시 선택 상태(true/false)

View File

@ -24,7 +24,7 @@ import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
// 보조선 작성 // 보조선 작성
export function useAuxiliaryDrawing(id) { export function useAuxiliaryDrawing(id, isUseEffect = true) {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useEvent() const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useEvent()
// const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useContext(EventContext) // const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useContext(EventContext)
@ -654,6 +654,8 @@ export function useAuxiliaryDrawing(id) {
selectable: true, selectable: true,
name: 'auxiliaryLine', name: 'auxiliaryLine',
isFixed: true, isFixed: true,
attributes: { ...line1.attributes },
parentId: line1.parentId,
}, },
) )
lineHistory.current.push(newLine) lineHistory.current.push(newLine)
@ -674,6 +676,8 @@ export function useAuxiliaryDrawing(id) {
selectable: false, selectable: false,
name: 'auxiliaryLine', name: 'auxiliaryLine',
isFixed: true, isFixed: true,
attributes: { ...line1.attributes },
parentId: line1.parentId,
}) })
lineHistory.current.push(newLine) lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1) lineHistory.current = lineHistory.current.filter((history) => history !== line1)
@ -685,6 +689,8 @@ export function useAuxiliaryDrawing(id) {
selectable: false, selectable: false,
name: 'auxiliaryLine', name: 'auxiliaryLine',
isFixed: true, isFixed: true,
attributes: { ...line1.attributes },
parentId: line1.parentId,
}) })
lineHistory.current.push(newLine) lineHistory.current.push(newLine)
lineHistory.current = lineHistory.current.filter((history) => history !== line1) lineHistory.current = lineHistory.current.filter((history) => history !== line1)
@ -724,6 +730,8 @@ export function useAuxiliaryDrawing(id) {
selectable: true, selectable: true,
name: 'auxiliaryLine', name: 'auxiliaryLine',
isFixed: true, isFixed: true,
attributes: { ...line1.attributes },
parentId: line1.parentId,
intersectionPoint, intersectionPoint,
}) })
} else { } else {
@ -733,6 +741,8 @@ export function useAuxiliaryDrawing(id) {
selectable: true, selectable: true,
name: 'auxiliaryLine', name: 'auxiliaryLine',
isFixed: true, isFixed: true,
attributes: { ...line1.attributes },
parentId: line1.parentId,
intersectionPoint, intersectionPoint,
}) })
} }
@ -825,7 +835,7 @@ export function useAuxiliaryDrawing(id) {
//lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거 //lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거
// 겹치는 선 하나는 canvas에서 제거한다. // 겹치는 선 하나는 canvas에서 제거한다.
const tempLines = [...lineHistory.current] const tempLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isAuxiliaryFixed)
lineHistory.current = [] lineHistory.current = []
tempLines.forEach((line) => { tempLines.forEach((line) => {
if ( if (
@ -842,7 +852,7 @@ export function useAuxiliaryDrawing(id) {
lineHistory.current.push(line) lineHistory.current.push(line)
}) })
const innerLines = lineHistory.current const innerLines = lineHistory.current.filter((line) => line.name === 'auxiliaryLine' && line.visible)
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
const tempPolygonPoints = [...roofBase.points].map((obj) => { const tempPolygonPoints = [...roofBase.points].map((obj) => {
@ -865,6 +875,7 @@ export function useAuxiliaryDrawing(id) {
actualSize: line.attributes?.actualSize ?? 0, actualSize: line.attributes?.actualSize ?? 0,
planeSize: line.getLength(), planeSize: line.getLength(),
} }
line.isAuxiliaryFixed = true
return true return true
} }
}) })

View File

@ -1,12 +1,15 @@
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useMode } from '@/hooks/useMode' import { useMode } from '@/hooks/useMode'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import { settingModalFirstOptionsState } from '@/store/settingAtom' import { settingModalFirstOptionsState } from '@/store/settingAtom'
// 외벽선 속성 설정 // 외벽선 속성 설정
@ -21,7 +24,7 @@ export function usePropertiesSetting(id) {
const { addPolygonByLines } = usePolygon() const { addPolygonByLines } = usePolygon()
const { removeLine, hideLine } = useLine() const { removeLine, hideLine } = useLine()
const { closePopup } = usePopup() const { addPopup, closePopup } = usePopup()
useEffect(() => { useEffect(() => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
@ -136,7 +139,8 @@ export function usePropertiesSetting(id) {
}) })
}) })
canvas.discardActiveObject() canvas.discardActiveObject()
closePopup(id) // closePopup(id)
addPopup(id, 1, <RoofShapeSetting id={id} pos={{ x: 50, y: 230 }} />)
return return
} }
@ -159,10 +163,7 @@ export function usePropertiesSetting(id) {
setPoints([]) setPoints([])
canvas.renderAll() canvas.renderAll()
roof.drawHelpLine(settingModalFirstOptions) roof.drawHelpLine(settingModalFirstOptions)
addPopup(id, 1, <RoofAllocationSetting id={id} pos={{ x: 50, y: 230 }} />)
closePopup(id)
return
} else {
return return
} }
} }

View File

@ -1,4 +1,4 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
@ -26,6 +26,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util' import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions' import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { outerLinePointsState } from '@/store/outerLineAtom'
// 지붕면 할당 // 지붕면 할당
export function useRoofAllocationSetting(id) { export function useRoofAllocationSetting(id) {
@ -55,6 +56,7 @@ export function useRoofAllocationSetting(id) {
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState) const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const resetPoints = useResetRecoilState(outerLinePointsState)
useEffect(() => { useEffect(() => {
setCurrentRoofList(roofList) setCurrentRoofList(roofList)
@ -199,7 +201,7 @@ export function useRoofAllocationSetting(id) {
roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width), roofWidth: item.width === null || item.width === undefined ? 0 : Number(item.width),
roofHeight: item.length === null || item.length === undefined ? 0 : Number(item.length), roofHeight: item.length === null || item.length === undefined ? 0 : Number(item.length),
roofHajebichi: item.hajebichi === null || item.hajebichi === undefined ? 0 : Number(item.hajebichi), roofHajebichi: item.hajebichi === null || item.hajebichi === undefined ? 0 : Number(item.hajebichi),
roofGap: item.raft === null || item.raft === undefined ? 'HEI_455' : item.raft, roofGap: !item.raft ? item.raftBaseCd : item.raft,
roofLayout: item.layout === null || item.layout === undefined ? 'P' : item.layout, roofLayout: item.layout === null || item.layout === undefined ? 'P' : item.layout,
roofPitch: item.pitch === null || item.pitch === undefined ? 4 : Number(item.pitch), roofPitch: item.pitch === null || item.pitch === undefined ? 4 : Number(item.pitch),
roofAngle: item.angle === null || item.angle === undefined ? 21.8 : Number(item.angle), roofAngle: item.angle === null || item.angle === undefined ? 21.8 : Number(item.angle),
@ -240,7 +242,7 @@ export function useRoofAllocationSetting(id) {
const onDeleteRoofMaterial = (idx) => { const onDeleteRoofMaterial = (idx) => {
const isSelected = currentRoofList[idx].selected const isSelected = currentRoofList[idx].selected
const newRoofList = [...currentRoofList].filter((_, index) => index !== idx) const newRoofList = JSON.parse(JSON.stringify(currentRoofList)).filter((_, index) => index !== idx)
if (isSelected) { if (isSelected) {
newRoofList[0].selected = true newRoofList[0].selected = true
} }
@ -256,11 +258,13 @@ export function useRoofAllocationSetting(id) {
addPopup(popupId, 1, <ActualSizeSetting id={popupId} />) addPopup(popupId, 1, <ActualSizeSetting id={popupId} />)
} else { } else {
apply() apply()
resetPoints()
} }
} }
// 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우 // 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
const handleSaveContext = () => { const handleSaveContext = () => {
basicSettingSave()
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, index: idx } return { ...roof, index: idx }
}) })
@ -273,7 +277,8 @@ export function useRoofAllocationSetting(id) {
setRoofList(newRoofList) setRoofList(newRoofList)
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected) const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial) setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true)
drawDirectionArrow(currentObject)
modifyModuleSelectionData() modifyModuleSelectionData()
closeAll() closeAll()
} }
@ -314,7 +319,7 @@ export function useRoofAllocationSetting(id) {
} }
const apply = () => { const apply = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.roofMaterial)
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
try { try {
@ -340,7 +345,6 @@ export function useRoofAllocationSetting(id) {
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, index: idx, ...basicInfo } return { ...roof, index: idx, ...basicInfo }
}) })
console.log('basicInfo', newRoofList)
setBasicSetting((prev) => { setBasicSetting((prev) => {
return { return {
@ -445,9 +449,9 @@ export function useRoofAllocationSetting(id) {
setCurrentRoofList(newRoofList) setCurrentRoofList(newRoofList)
} }
const handleChangeInput = (e, type, index) => { const handleChangeInput = (e, type = '', index) => {
const value = e.target.value const value = e.target.value
if (type === 'pitch') { /*if (type === 'pitch') {
// type이 pitch인 경우 소수점 1자리까지만 입력 가능 // type이 pitch인 경우 소수점 1자리까지만 입력 가능
const reg = /^[0-9]+(\.[0-9]{0,1})?$/ const reg = /^[0-9]+(\.[0-9]{0,1})?$/
@ -481,7 +485,7 @@ export function useRoofAllocationSetting(id) {
} }
return return
} }*/
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) { if (idx === index) {
@ -494,7 +498,12 @@ export function useRoofAllocationSetting(id) {
} }
const handleChangePitch = (e, index) => { const handleChangePitch = (e, index) => {
const value = e.target.value let value = e.target.value
const reg = /^[0-9]+(\.[0-9]{0,1})?$/
if (!reg.test(value)) {
value = value.substring(0, value.length - 1)
}
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) { if (idx === index) {
const result = const result =

View File

@ -203,6 +203,20 @@ export function useRoofShapePassivitySetting(id) {
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine') const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
let checkedAllSetting = true
lines.forEach((line) => {
if (!line.attributes) {
checkedAllSetting = false
}
})
if (!checkedAllSetting) {
swalFire({ text: '설정이 완료되지 않은 외벽선이 있습니다.', icon: 'warning' })
return
}
exceptObjs.forEach((obj) => { exceptObjs.forEach((obj) => {
canvas.remove(obj) canvas.remove(obj)
}) })

View File

@ -10,6 +10,7 @@ import { outerLineFixState } from '@/store/outerLineAtom'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { getChonByDegree } from '@/util/canvas-util' import { getChonByDegree } from '@/util/canvas-util'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import { settingModalFirstOptionsState } from '@/store/settingAtom' import { settingModalFirstOptionsState } from '@/store/settingAtom'
// 지붕형상 설정 // 지붕형상 설정
@ -47,7 +48,7 @@ export function useRoofShapeSetting(id) {
const jerkinHeadPitchRef = useRef(null) const jerkinHeadPitchRef = useRef(null)
const history = useRef([]) const history = useRef([])
const { closePopup } = usePopup() const { closePopup, addPopup } = usePopup()
const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState) const settingModalFirstOptions = useRecoilValue(settingModalFirstOptionsState)
@ -170,9 +171,14 @@ export function useRoofShapeSetting(id) {
] ]
const handleSave = () => { const handleSave = () => {
let outerLines let outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.visible)
let direction let direction
if (outerLines.length < 2) {
swalFire({ text: '외벽선이 없습니다.', icon: 'error' })
return
}
switch (shapeNum) { switch (shapeNum) {
case 1: { case 1: {
outerLines = saveRidge() outerLines = saveRidge()
@ -188,19 +194,25 @@ export function useRoofShapeSetting(id) {
} }
case 4: { case 4: {
outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch const pitch = outerLines.find((line) => line.attributes.type === LINE_TYPE.WALLLINE.SHED)?.attributes.pitch
let isValid = outerLines.every((line) => line.attributes.isFixed)
// 변별로 설정중 한쪽흐름일 경우 한쪽흐름의 pitch로 설정 // 변별로 설정중 한쪽흐름일 경우 한쪽흐름의 pitch로 설정
if (pitch) { if (pitch) {
outerLines.forEach((line) => { outerLines.forEach((line) => {
if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES) { if (line.attributes.type === LINE_TYPE.WALLLINE.SHED) {
line.attributes = { line.attributes = {
...line.attributes, ...line.attributes,
pitch: pitch, pitch: pitchRef.current,
onlyOffset: true, onlyOffset: true,
} }
} }
}) })
} }
if (!isValid) {
swalFire({ text: '설정이 완료되지 않았습니다.', icon: 'error' })
return
}
break break
} }
@ -219,15 +231,15 @@ 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: true,
} }
} }
if (line.direction === 'top') { if (line.direction === 'top') {
line.attributes = { line.attributes = {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitch, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} else { } else {
@ -236,7 +248,6 @@ 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: true,
} }
} }
@ -245,6 +256,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} }
@ -267,7 +279,6 @@ 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: true,
} }
} }
@ -276,6 +287,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} else { } else {
@ -284,7 +296,6 @@ 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: true,
} }
} }
@ -293,6 +304,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} }
@ -314,7 +326,6 @@ 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: true,
} }
} }
@ -323,6 +334,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} else { } else {
@ -331,7 +343,6 @@ 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: true,
} }
} }
@ -340,6 +351,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} }
@ -362,7 +374,6 @@ 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: true,
} }
} }
@ -371,6 +382,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} else { } else {
@ -379,7 +391,6 @@ 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: true,
} }
} }
@ -388,6 +399,7 @@ export function useRoofShapeSetting(id) {
offset: shedWidth / 10, offset: shedWidth / 10,
pitch: pitchRef.current, pitch: pitchRef.current,
type: LINE_TYPE.WALLLINE.SHED, type: LINE_TYPE.WALLLINE.SHED,
onlyOffset: true,
} }
} }
} }
@ -414,7 +426,13 @@ export function useRoofShapeSetting(id) {
canvas.remove(obj) canvas.remove(obj)
}) })
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText' || obj.name === 'lengthText') const removeTargets = canvas
.getObjects()
.filter(
(obj) =>
(obj.name === 'pitchText' || obj.name === 'lengthText') &&
canvas.getObjects().find((parent) => parent.id === obj.parentId)?.name !== POLYGON_TYPE.ROOF,
)
removeTargets.forEach((obj) => { removeTargets.forEach((obj) => {
canvas.remove(obj) canvas.remove(obj)
}) })
@ -428,7 +446,7 @@ export function useRoofShapeSetting(id) {
canvas?.renderAll() canvas?.renderAll()
roof.drawHelpLine(settingModalFirstOptions) roof.drawHelpLine(settingModalFirstOptions)
isFixRef.current = true isFixRef.current = true
closePopup(id) addPopup(id, 1, <RoofAllocationSetting id={id} pos={{ x: 50, y: 230 }} />)
} }
const initLineSetting = () => { const initLineSetting = () => {
@ -488,7 +506,7 @@ export function useRoofShapeSetting(id) {
outerLines.forEach((line) => { outerLines.forEach((line) => {
line.attributes = { line.attributes = {
offset: eavesOffset / 10, offset: eavesOffset / 10,
pitch: pitchRef.current, pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
type: LINE_TYPE.WALLLINE.EAVES, type: LINE_TYPE.WALLLINE.EAVES,
onlyOffset: false, onlyOffset: false,
} }
@ -511,7 +529,7 @@ export function useRoofShapeSetting(id) {
} else if (line.direction === 'top' || line.direction === 'bottom') { } else if (line.direction === 'top' || line.direction === 'bottom') {
line.attributes = { line.attributes = {
offset: eavesOffset / 10, offset: eavesOffset / 10,
pitch: pitchRef.current, pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
type: LINE_TYPE.WALLLINE.EAVES, type: LINE_TYPE.WALLLINE.EAVES,
} }
} }
@ -534,7 +552,7 @@ export function useRoofShapeSetting(id) {
} else if (line.direction === 'left' || line.direction === 'right') { } else if (line.direction === 'left' || line.direction === 'right') {
line.attributes = { line.attributes = {
offset: eavesOffset / 10, offset: eavesOffset / 10,
pitch: pitchRef.current, pitch: currentAngleType === ANGLE_TYPE.SLOPE ? pitch : getChonByDegree(pitch),
type: LINE_TYPE.WALLLINE.EAVES, type: LINE_TYPE.WALLLINE.EAVES,
} }
} }
@ -560,6 +578,7 @@ export function useRoofShapeSetting(id) {
pitch: pitchRef.current, pitch: pitchRef.current,
offset: eavesOffset / 10, offset: eavesOffset / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' }) selectedLine.set({ stroke: '#45CD7D' })
@ -571,6 +590,7 @@ export function useRoofShapeSetting(id) {
type: LINE_TYPE.WALLLINE.GABLE, type: LINE_TYPE.WALLLINE.GABLE,
offset: gableOffset / 10, offset: gableOffset / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' }) selectedLine.set({ stroke: '#3FBAE6' })
break break
@ -582,6 +602,7 @@ export function useRoofShapeSetting(id) {
width: hasSleeve === '0' ? 0 : sleeveOffset / 10, width: hasSleeve === '0' ? 0 : sleeveOffset / 10,
sleeve: hasSleeve === '1', sleeve: hasSleeve === '1',
} }
selectedLine.attributes = { ...attributes, isFixed: true }
break break
} }
case 4: { case 4: {
@ -592,6 +613,7 @@ export function useRoofShapeSetting(id) {
offset: eavesOffset / 10, offset: eavesOffset / 10,
width: hipAndGableWidth / 10, width: hipAndGableWidth / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#45CD7D' }) selectedLine.set({ stroke: '#45CD7D' })
@ -605,6 +627,7 @@ export function useRoofShapeSetting(id) {
width: jerkinHeadWidth / 10, width: jerkinHeadWidth / 10,
pitch: jerkinHeadPitchRef.current, pitch: jerkinHeadPitchRef.current,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#3FBAE6' }) selectedLine.set({ stroke: '#3FBAE6' })
@ -617,13 +640,13 @@ export function useRoofShapeSetting(id) {
pitch: shedPitchRef.current, pitch: shedPitchRef.current,
width: shedWidth / 10, width: shedWidth / 10,
} }
selectedLine.attributes = { ...attributes, isFixed: true }
addPitchText(currentObject) addPitchText(currentObject)
selectedLine.set({ strokeWidth: 4 }) selectedLine.set({ strokeWidth: 4 })
selectedLine.set({ stroke: '#000000' }) selectedLine.set({ stroke: '#000000' })
break break
} }
} }
selectedLine.attributes = { ...attributes, isFixed: true }
canvas.renderAll() canvas.renderAll()
nextLineFocus(selectedLine) nextLineFocus(selectedLine)
@ -635,7 +658,7 @@ export function useRoofShapeSetting(id) {
const index = lines.findIndex((line) => line.idx === selectedLine.idx) const index = lines.findIndex((line) => line.idx === selectedLine.idx)
const nextLine = lines[index + 1] || lines[0] const nextLine = lines[index + 1] || lines[0]
if (nextLine.attributes.isFixed) { if (nextLine.attributes?.isFixed) {
canvas.discardActiveObject() canvas.discardActiveObject()
return return
} }

View File

@ -85,6 +85,10 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP)) canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP))
points = getSurfaceShape(surfaceId, pointer, { length1, length2, length3, length4, length5 }) points = getSurfaceShape(surfaceId, pointer, { length1, length2, length3, length4, length5 })
console.log('surfaceRefs.xInversion', surfaceRefs.xInversion)
console.log('surfaceRefs.yInversion', surfaceRefs.yInversion)
console.log('surfaceRefs.rotate', surfaceRefs.rotate)
const options = { const options = {
fill: 'transparent', fill: 'transparent',
stroke: 'black', stroke: 'black',
@ -100,7 +104,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP, name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP,
flipX: surfaceRefs.yInversion, flipX: surfaceRefs.yInversion,
flipY: surfaceRefs.xInversion, flipY: surfaceRefs.xInversion,
angle: surfaceRefs.rotate, angle: Math.abs(surfaceRefs.rotate),
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
pitch: globalPitch, pitch: globalPitch,
@ -637,7 +641,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
y: pointer.y + length3 / 2, y: pointer.y + length3 / 2,
}, },
{ {
x: pointer.x - length1 / 2 + length4 * Math.cos(angle), x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)),
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
}, },
{ {

View File

@ -13,7 +13,8 @@ import { writeImage } from '@/lib/canvas'
import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useFont } from '@/hooks/common/useFont' import { useFont } from '@/hooks/common/useFont'
import { OBJECT_PROTOTYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common' import { OBJECT_PROTOTYPE, POLYGON_TYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common'
import { usePlan } from './usePlan'
export function useCanvas(id) { export function useCanvas(id) {
const [canvas, setCanvas] = useRecoilState(canvasState) const [canvas, setCanvas] = useRecoilState(canvasState)
@ -23,7 +24,6 @@ export function useCanvas(id) {
const [canvasSize] = useRecoilState(canvasSizeState) const [canvasSize] = useRecoilState(canvasSizeState)
const [fontSize] = useRecoilState(fontSizeState) const [fontSize] = useRecoilState(fontSizeState)
const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent()
const { post } = useAxios()
const {} = useFont() const {} = useFont()
/** /**
@ -383,18 +383,18 @@ export function useCanvas(id) {
console.log('err', err) console.log('err', err)
}) })
const canvasStatus = addCanvas() // const canvasStatus = addCanvas()
const patternData = { // const patternData = {
userId: userId, // userId: userId,
imageName: title, // imageName: title,
objectNo: 'test123240822001', // objectNo: 'test123240822001',
canvasStatus: JSON.stringify(canvasStatus).replace(/"/g, '##'), // canvasStatus: JSON.stringify(canvasStatus).replace(/"/g, '##'),
} // }
await post({ url: '/api/canvas-management/canvas-statuses', data: patternData }) // await post({ url: '/api/canvas-management/canvas-statuses', data: patternData })
setThumbnails((prev) => [...prev, { imageName: `/canvasState/${title}.png`, userId, canvasStatus: JSON.stringify(canvasStatus) }]) // setThumbnails((prev) => [...prev, { imageName: `/canvasState/${title}.png`, userId, canvasStatus: JSON.stringify(canvasStatus) }])
} }
const handleFlip = () => { const handleFlip = () => {

View File

@ -0,0 +1,293 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { POLYGON_TYPE } from '@/common/common'
import { canvasState } from '@/store/canvasAtom'
import {
makersState,
modelsState,
moduleStatisticsState,
pcsCheckState,
selectedMakerState,
selectedModelsState,
seriesState,
} from '@/store/circuitTrestleAtom'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useContext } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { useMessage } from './useMessage'
import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
export function useCircuitTrestle() {
const [makers, setMakers] = useRecoilState(makersState)
const [selectedMaker, setSelectedMaker] = useRecoilState(selectedMakerState)
const [series, setSeries] = useRecoilState(seriesState)
const [models, setModels] = useRecoilState(modelsState)
const [selectedModels, setSelectedModels] = useRecoilState(selectedModelsState)
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const selectedModules = useRecoilValue(selectedModuleState)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState)
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const setModuleStatistics = useSetRecoilState(moduleStatisticsState)
const { getMessage } = useMessage()
const getOptYn = () => {
return {
maxConnYn: pcsCheck.max ? 'Y' : 'N',
smpCirYn: pcsCheck.division ? 'Y' : 'N',
coldZoneYn: managementState?.coldRegionFlg === '1' ? 'Y' : 'N',
}
}
// PCS 아이템 목록
const getPcsItemList = () => {
return models.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
// 선택된 PCS 아이템 목록
const getSelectedPcsItemList = () => {
return selectedModels.map((model) => {
return {
itemId: model.itemId,
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
}
})
}
// 사용된 모듈아이템 목록
const getUseModuleItemList = () => {
console.log('🚀 ~ getUseModuleItemList ~ selectedModules:', selectedModules)
return moduleSelectionData.module?.itemList?.map((m) => {
return {
itemId: m.itemId,
mixMatlNo: m.mixMatlNo,
}
})
}
// 지붕면 목록
const getRoofSurfaceList = () => {
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
roofSurfaceList.sort((a, b) => a.left - b.left || b.top - a.top)
return roofSurfaceList
.map((obj) => {
return {
roofSurfaceId: obj.id,
roofSurface: canvas
.getObjects()
.filter((o) => o.id === obj.parentId)[0]
.directionText.replace(/[0-9]/g, ''),
roofSurfaceIncl: canvas.getObjects().filter((o) => o.id === obj.parentId)[0].roofMaterial.pitch,
moduleList: getModuleList(obj).map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber ? module.circuitNumber : null,
pcsItemId: module.circuit ? module.circuit?.pcsItemId : null,
uniqueId: module.id ? module.id : null,
}
}),
}
})
.filter((surface) => surface.moduleList.length > 0)
}
// 모듈 목록
const getModuleList = (surface) => {
let moduleList = []
let [xObj, yObj] = [{}, {}]
let [xPoints, yPoints] = [[], []]
surface.modules.forEach((module) => {
if (!xObj[module.left]) {
xObj[module.left] = module.left
xPoints.push(module.left)
}
if (!yObj[module.top]) {
yObj[module.top] = module.top
yPoints.push(module.top)
}
})
switch (surface.direction) {
case 'south':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => b - a)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => a.left - b.left)
} else {
temp.sort((a, b) => b.left - a.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'north':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => a - b)
yPoints.forEach((y, index) => {
let temp = surface.modules.filter((m) => m.top === y)
if (index % 2 === 0) {
temp.sort((a, b) => b.left - a.left)
} else {
temp.sort((a, b) => a.left - b.left)
}
moduleList = [...moduleList, ...temp]
})
break
case 'west':
xPoints.sort((a, b) => a - b)
yPoints.sort((a, b) => a - b)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => a.top - b.top)
} else {
temp.sort((a, b) => b.top - a.top)
}
moduleList = [...moduleList, ...temp]
})
break
case 'east':
xPoints.sort((a, b) => b - a)
yPoints.sort((a, b) => b - a)
xPoints.forEach((x, index) => {
let temp = surface.modules.filter((m) => m.left === x)
if (index % 2 === 0) {
temp.sort((a, b) => b.top - a.top)
} else {
temp.sort((a, b) => a.top - b.top)
}
moduleList = [...moduleList, ...temp]
})
break
default:
return []
}
return moduleList
}
const removeNotAllocationModules = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
canvas.remove(...notAllocationModules)
canvas.renderAll()
}
const setPowerConditionerData = () => {}
const setModuleStatisticsData = () => {
console.log(canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE))
if (selectedModules?.length === 0) return
const tempHeader = [
{ name: getMessage('simulator.table.sub1'), prop: 'name' },
{ name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.circuit'), prop: 'circuit' },
...selectedModules?.itemList?.map((module) => {
return {
name: module.itemNm,
prop: module.itemId,
}
}),
{ name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`, prop: 'wpOut' },
]
const surfaceObjects = {}
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
surfaces.forEach((surface) => {
surfaceObjects[surface.id] = {
roofSurface: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].directionText,
circuit: '-',
amount: 0,
wpOut: 0,
circuits: {},
}
surface.modules.forEach((module) => {
if (!surfaceObjects[surface.id][module.moduleInfo.itemId]) {
// 지붕면에 모듈 존재 여부
surfaceObjects[surface.id][module.moduleInfo.itemId] = 0 // 모듈 초기화
}
surfaceObjects[surface.id][module.moduleInfo.itemId]++
surfaceObjects[surface.id].wpOut += +module.moduleInfo.wpOut
if (module.circuit) {
if (!surfaceObjects[surface.id].circuits[module.circuitNumber]) {
surfaceObjects[surface.id].circuits[module.circuitNumber] = {
circuit: module.circuitNumber,
wpOut: 0,
circuits: { wpOut: 0 },
}
}
if (!surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]) {
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId] = 0
}
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits[module.moduleInfo.itemId]++
surfaceObjects[surface.id].circuits[module.circuitNumber].circuits.wpOut += +module.moduleInfo.wpOut
surfaceObjects[surface.id].wpOut -= +module.moduleInfo.wpOut
surfaceObjects[surface.id][module.moduleInfo.itemId]--
}
})
})
let tempRows = []
Object.keys(surfaceObjects).forEach((key) => {
let tempRow = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuit,
wpOut: parseFloat(surfaceObjects[key].wpOut / 1000),
}
selectedModules.itemList.forEach((module) => {
tempRow[module.itemId] = surfaceObjects[key][module.itemId]
})
tempRows.push(tempRow)
Object.keys(surfaceObjects[key].circuits).forEach((circuit) => {
let row = {
name: surfaceObjects[key].roofSurface,
circuit: surfaceObjects[key].circuits[circuit].circuit,
wpOut: parseFloat(surfaceObjects[key].circuits[circuit].circuits.wpOut / 1000),
}
selectedModules.itemList.forEach((module) => {
row[module.itemId] = surfaceObjects[key].circuits[circuit].circuits[module.itemId]
})
tempRows.push(row)
})
})
const tempFooter = {
name: getMessage('modal.panel.batch.statistic.total'),
circuit: '-',
wpOut: tempRows.reduce((acc, row) => acc + row.wpOut, 0),
}
selectedModules.itemList.forEach((module) => {
tempFooter[module.itemId] = tempRows.reduce((acc, row) => acc + row[module.itemId], 0)
})
canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
setModuleStatistics({ header: tempHeader, rows: tempRows.filter((row) => row.wpOut !== 0), footer: tempFooter })
}
return {
makers,
setMakers,
selectedMaker,
setSelectedMaker,
series,
setSeries,
models,
setModels,
selectedModels,
setSelectedModels,
pcsCheck,
setPcsCheck,
getOptYn,
getPcsItemList,
getSelectedPcsItemList,
getUseModuleItemList,
getRoofSurfaceList,
getModuleList,
removeNotAllocationModules,
setModuleStatisticsData,
}
}

View File

@ -67,8 +67,8 @@ export function useContextMenu() {
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const { settingsData, setSettingsDataSave } = useCanvasSetting() const { settingsData, setSettingsDataSave } = useCanvasSetting()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { alignModule, modulesRemove } = useModule() const { alignModule, modulesRemove, moduleRoofRemove } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial } = useRoofFn() const { removeRoofMaterial, removeAllRoofMaterial, moveRoofMaterial, removeOuterLines } = useRoofFn()
const currentMenuSetting = () => { const currentMenuSetting = () => {
switch (currentMenu) { switch (currentMenu) {
@ -150,7 +150,9 @@ export function useContextMenu() {
{ {
id: 'wallLineRemove', id: 'wallLineRemove',
name: getMessage('contextmenu.wallline.remove'), name: getMessage('contextmenu.wallline.remove'),
fn: () => deleteOuterLineObject(), fn: (currentMousePos) => {
removeOuterLines(currentMousePos)
},
}, },
], ],
[ [
@ -176,7 +178,14 @@ export function useContextMenu() {
shortcut: ['d', 'D'], shortcut: ['d', 'D'],
name: `${getMessage('contextmenu.auxiliary.remove')}(D)`, name: `${getMessage('contextmenu.auxiliary.remove')}(D)`,
fn: () => { fn: () => {
if (!currentObject) return
const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0] const roof = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]
if (!roof) {
// 아직 innerLines로 세팅이 안되어있는 line인 경우 제거
canvas.remove(currentObject)
canvas.discardActiveObject()
return
}
const innerLines = roof.innerLines?.filter((line) => currentObject.id !== line.id) const innerLines = roof.innerLines?.filter((line) => currentObject.id !== line.id)
roof.innerLines = [...innerLines] roof.innerLines = [...innerLines]
canvas.remove(currentObject) canvas.remove(currentObject)
@ -187,6 +196,7 @@ export function useContextMenu() {
id: 'auxiliaryVerticalBisector', id: 'auxiliaryVerticalBisector',
name: getMessage('contextmenu.auxiliary.vertical.bisector'), name: getMessage('contextmenu.auxiliary.vertical.bisector'),
fn: () => { fn: () => {
if (!currentObject) return
const slope = (currentObject.y2 - currentObject.y1) / (currentObject.x2 - currentObject.x1) const slope = (currentObject.y2 - currentObject.y1) / (currentObject.x2 - currentObject.x1)
const length = currentObject.length const length = currentObject.length
@ -217,6 +227,11 @@ export function useContextMenu() {
name: 'auxiliaryLine', name: 'auxiliaryLine',
attributes: { ...currentObject.attributes }, attributes: { ...currentObject.attributes },
}) })
if (!currentObject.attributes.roofId) {
return
}
canvas canvas
.getObjects() .getObjects()
.filter((obj) => obj.id === currentObject.attributes.roofId)[0] .filter((obj) => obj.id === currentObject.attributes.roofId)[0]
@ -231,11 +246,21 @@ export function useContextMenu() {
swalFire({ text: '지붕을 선택해주세요.' }) swalFire({ text: '지붕을 선택해주세요.' })
return return
} }
const innerLines = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0].innerLines const innerLines = canvas.getObjects().filter((obj) => obj.id === currentObject.attributes.roofId)[0]?.innerLines
innerLines.forEach((line) => { if (innerLines) {
innerLines.forEach((line) => {
canvas.remove(line)
})
innerLines.length = 0
}
// 확정되지 않은 보조선
const notFixedAuxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isAuxiliaryFixed)
notFixedAuxiliaryLines.forEach((line) => {
canvas.remove(line) canvas.remove(line)
}) })
innerLines.length = 0
canvas.renderAll() canvas.renderAll()
}, },
}, },
@ -332,8 +357,8 @@ export function useContextMenu() {
}, [currentContextMenu]) }, [currentContextMenu])
useEffect(() => { useEffect(() => {
console.log('currentObject', currentObject)
if (currentObject?.name) { if (currentObject?.name) {
console.log('object', currentObject)
switch (currentObject.name) { switch (currentObject.name) {
case 'triangleDormer': case 'triangleDormer':
case 'pentagonDormer': case 'pentagonDormer':
@ -725,38 +750,40 @@ export function useContextMenu() {
{ {
id: 'moduleVerticalCenterAlign', id: 'moduleVerticalCenterAlign',
name: getMessage('contextmenu.module.vertical.align'), name: getMessage('contextmenu.module.vertical.align'),
fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL), fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL, currentObject.arrayData),
}, },
{ {
id: 'moduleHorizonCenterAlign', id: 'moduleHorizonCenterAlign',
name: getMessage('contextmenu.module.horizon.align'), name: getMessage('contextmenu.module.horizon.align'),
fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL), fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL, currentObject.arrayData),
}, },
{ {
id: 'moduleRemove', id: 'moduleRemove',
name: getMessage('contextmenu.module.remove'), name: getMessage('contextmenu.module.remove'),
fn: () => { fn: () => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] moduleRoofRemove(currentObject.arrayData)
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules) // const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
canvas.renderAll() // const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
// canvas.remove(...modules)
// canvas.renderAll()
}, },
}, },
{ {
id: 'moduleMove', id: 'moduleMove',
name: getMessage('contextmenu.module.move'), name: getMessage('contextmenu.module.move'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.MOVE_ALL} />, component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.MOVE_ALL} arrayData={currentObject.arrayData} />,
}, },
{ {
id: 'moduleCopy', id: 'moduleCopy',
name: getMessage('contextmenu.module.copy'), name: getMessage('contextmenu.module.copy'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COPY_ALL} />, component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COPY_ALL} arrayData={currentObject.arrayData} />,
},
{
id: 'moduleCircuitNumberEdit',
name: getMessage('contextmenu.module.circuit.number.edit'),
component: <CircuitNumberEdit id={popupId} />,
}, },
// {
// id: 'moduleCircuitNumberEdit',
// name: getMessage('contextmenu.module.circuit.number.edit'),
// component: <CircuitNumberEdit id={popupId} />,
// },
], ],
]) ])
break break

78
src/hooks/useEstimate.js Normal file
View File

@ -0,0 +1,78 @@
import { useContext } from 'react'
import { useRouter } from 'next/navigation'
import { useRecoilValue } from 'recoil'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { QcastContext } from '@/app/QcastProvider'
import { currentCanvasPlanState } from '@/store/canvasAtom'
import { loginUserStore } from '@/store/commonAtom'
export function useEstimate() {
const { managementStateLoaded } = useContext(GlobalDataContext)
const { setIsGlobalLoading } = useContext(QcastContext)
const router = useRouter()
const loginUserState = useRecoilValue(loginUserStore)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const { promisePost } = useAxios()
const { swalFire } = useSwal()
/**
* 도면 견적서 저장
*/
const saveEstimate = async (estimateParam) => {
// 로딩 임시 주석
// setIsGlobalLoading(true)
const userId = loginUserState.userId
const saleStoreId = managementStateLoaded.saleStoreId
const objectNo = currentCanvasPlan.objectNo
const planNo = currentCanvasPlan.planNo
const slope = estimateParam.roofSurfaceList[0].slope
const angle = estimateParam.roofSurfaceList[0].angle
const surfaceType = managementStateLoaded.surfaceType
const setupHeight = managementStateLoaded.installHeight
const standardWindSpeedId = managementStateLoaded.standardWindSpeedId
const snowfall = managementStateLoaded.verticalSnowCover
const drawingFlg = '1'
const saveEstimateData = {
...estimateParam,
userId: userId,
saleStoreId: saleStoreId,
objectNo: objectNo,
planNo: planNo,
slope: slope,
angle: angle,
surfaceType: surfaceType,
setupHeight: setupHeight,
standardWindSpeedId: standardWindSpeedId,
snowfall: snowfall,
drawingFlg: drawingFlg,
}
await promisePost({ url: '/api/estimate/save-estimate', data: saveEstimateData })
.then(async () => {
// 견적서 저장이 완료되면 견적서 페이지로 이동
moveEstimate(planNo, objectNo)
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
})
}
/**
* 견적서 페이지로 이동
*/
const moveEstimate = (planNo, objectNo) => {
router.push(`/floor-plan/estimate/5?pid=${planNo}&objectNo=${objectNo}`)
}
return {
saveEstimate,
moveEstimate,
}
}

View File

@ -93,10 +93,11 @@ export const useLine = () => {
let left, top let left, top
const textStr = const textStr = `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}`
currentAngleType === ANGLE_TYPE.SLOPE
? `${attributes.offset ? attributes.offset * 10 : attributes.width * 10}${!onlyOffset && attributes.pitch ? '-∠' + attributes.pitch + angleUnit : ''}` // currentAngleType === ANGLE_TYPE.SLOPE
: `${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 ? '-∠' + 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
@ -125,6 +126,7 @@ export const useLine = () => {
name: 'pitchText', name: 'pitchText',
parentId: line.id, parentId: line.id,
pitch: attributes.pitch, pitch: attributes.pitch,
onlyOffset,
}) })
canvas.add(text) canvas.add(text)

View File

@ -1,21 +1,10 @@
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { getInterSectionLineNotOverCoordinate } from '@/util/canvas-util' import { calculateIntersection, getInterSectionLineNotOverCoordinate } from '@/util/canvas-util'
export function useMouse() { export function useMouse() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
//가로선, 세로선의 교차점을 return
/*const getIntersectMousePoint = (e) => {
let pointer = canvas.getPointer(e.e)
const mouseLines = canvas.getObjects().filter((obj) => obj.name === 'mouseLine')
if (mouseLines.length < 2) {
return pointer
}
return getInterSectionLineNotOverCoordinate(mouseLines[0], mouseLines[1]) || pointer
}*/
//가로선, 세로선의 교차점을 return //가로선, 세로선의 교차점을 return
const getIntersectMousePoint = (e) => { const getIntersectMousePoint = (e) => {
let pointer = canvas.getPointer(e.e) let pointer = canvas.getPointer(e.e)

View File

@ -3,7 +3,7 @@
import { useContext, useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { usePathname, useRouter, useSearchParams } from 'next/navigation' import { usePathname, useRouter, useSearchParams } from 'next/navigation'
import { useRecoilState } from 'recoil' import { useRecoilState, useResetRecoilState } from 'recoil'
import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
@ -14,6 +14,8 @@ import { SAVE_KEY } from '@/common/common'
import { readImage, removeImage } from '@/lib/fileAction' import { readImage, removeImage } from '@/lib/fileAction'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
export function usePlan(params = {}) { export function usePlan(params = {}) {
const { floorPlanState } = useContext(FloorPlanContext) const { floorPlanState } = useContext(FloorPlanContext)
@ -33,6 +35,10 @@ export function usePlan(params = {}) {
const { get, promisePost, promisePut, promiseDel, promiseGet } = useAxios() const { get, promisePost, promisePut, promiseDel, promiseGet } = useAxios()
const { setEstimateContextState } = useEstimateController() const { setEstimateContextState } = useEstimateController()
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
/** /**
* 마우스 포인터의 가이드라인을 제거합니다. * 마우스 포인터의 가이드라인을 제거합니다.
*/ */
@ -120,16 +126,16 @@ export function usePlan(params = {}) {
/** /**
* 페이지 캔버스를 저장 * 페이지 캔버스를 저장
*/ */
const saveCanvas = async () => { const saveCanvas = async (saveAlert = true) => {
const canvasStatus = currentCanvasData('save') const canvasStatus = currentCanvasData('save')
await putCanvasStatus(canvasStatus) await putCanvasStatus(canvasStatus, saveAlert)
} }
/** /**
* objectNo에 해당하는 canvas 목록을 조회 * objectNo에 해당하는 canvas 목록을 조회
*/ */
const getCanvasByObjectNo = async (userId, objectNo, planNo) => { const getCanvasByObjectNo = async (objectNo, planNo) => {
return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) => return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` }).then((res) =>
res.map((item) => ({ res.map((item) => ({
id: item.id, id: item.id,
objectNo: item.objectNo, objectNo: item.objectNo,
@ -144,55 +150,63 @@ export function usePlan(params = {}) {
} }
/** /**
* 물건번호(object) plan 추가 (canvas 생성 planNo 할당) * 신규 plan 추가
*
* case 1) 초기 플랜 생성 : isInitPlan = true, isCopy = false
* case 2) 플랜 생성 : isInitPlan = false, isCopy = false
* case 3) 복제 플랜 생성 : isInitPlan = false, isCopy = true
*/ */
const postObjectPlan = async (userId, objectNo) => { const postObjectPlan = async (userId, objectNo, isCopy = false, isInitPlan = false) => {
return await promisePost({ url: '/api/object/add-plan', data: { userId: userId, objectNo: objectNo } }) const planData = isCopy
? {
userId: userId,
objectNo: objectNo,
copyFlg: '1',
planNo: currentCanvasPlan?.planNo,
}
: {
userId: userId,
objectNo: objectNo,
copyFlg: '0',
}
await promisePost({ url: '/api/object/add-plan', data: planData })
.then((res) => { .then((res) => {
return res.data.planNo let newPlan = {
}) id: res.data.canvasId,
.catch((error) => { objectNo: objectNo,
swalFire({ text: error.response.data.message, icon: 'error' }) planNo: res.data.planNo,
return null userId: userId,
}) canvasStatus: '',
} isCurrent: true,
bgImageName: null,
mapPositionAddress: null,
}
/**
* 신규 canvas 데이터를 저장
*/
const postCanvasStatus = async (userId, objectNo, canvasStatus, isInitPlan = false) => {
const planNo = await postObjectPlan(userId, objectNo)
if (!planNo) return
const planData = {
userId: userId,
objectNo: objectNo,
planNo: planNo,
bgImageName: currentCanvasPlan?.bgImageName ?? null,
mapPositionAddress: currentCanvasPlan?.mapPositionAddress ?? null,
canvasStatus: canvasToDbFormat(canvasStatus),
}
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => {
const newPlan = { id: res.data, objectNo: objectNo, planNo: planNo, userId: userId, canvasStatus: canvasStatus, isCurrent: true }
setCurrentCanvasPlan(newPlan)
if (isInitPlan) { if (isInitPlan) {
// 초기 플랜 생성인 경우 플랜 목록 초기화 // 초기 플랜 생성인 경우 플랜 목록 초기화
setCurrentCanvasPlan(newPlan)
setPlans([newPlan]) setPlans([newPlan])
} else { } else {
if (isCopy) {
// 복제 플랜 생성인 경우 현재 캔버스 데이터를 복제
newPlan.canvasStatus = currentCanvasData()
newPlan.bgImageName = currentCanvasPlan?.bgImageName ?? null
newPlan.mapPositionAddress = currentCanvasPlan?.mapPositionAddress ?? null
}
setCurrentCanvasPlan(newPlan)
setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan]) setPlans((plans) => [...plans.map((plan) => ({ ...plan, isCurrent: false })), newPlan])
swalFire({ text: getMessage('plan.message.save') }) swalFire({ text: getMessage('plan.message.save') })
} }
}) })
.catch((error) => { .catch((error) => {
swalFire({ text: error.message, icon: 'error' }) swalFire({ text: error.response.data.message, icon: 'error' })
}) })
} }
/** /**
* id에 해당하는 canvas 데이터를 수정 * id에 해당하는 canvas 데이터를 수정
*/ */
const putCanvasStatus = async (canvasStatus) => { const putCanvasStatus = async (canvasStatus, saveAlert = true) => {
const planData = { const planData = {
id: currentCanvasPlan.id, id: currentCanvasPlan.id,
bgImageName: currentCanvasPlan?.bgImageName ?? null, bgImageName: currentCanvasPlan?.bgImageName ?? null,
@ -202,7 +216,7 @@ export function usePlan(params = {}) {
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData }) await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => { .then((res) => {
setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)))
swalFire({ text: getMessage('plan.message.save') }) if (saveAlert) swalFire({ text: getMessage('plan.message.save') })
}) })
.catch((error) => { .catch((error) => {
swalFire({ text: error.message, icon: 'error' }) swalFire({ text: error.message, icon: 'error' })
@ -238,7 +252,9 @@ export function usePlan(params = {}) {
if (res.status === 200) { if (res.status === 200) {
const estimateDetail = res.data const estimateDetail = res.data
if (pathname === '/floor-plan/estimate/5') { if (pathname === '/floor-plan/estimate/5') {
if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) { // 견적서 이동 조건 수정
// if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) {
if (estimateDetail.estimateDate !== null) {
res.data.resetFlag = 'N' res.data.resetFlag = 'N'
if (res.data.itemList.length > 0) { if (res.data.itemList.length > 0) {
@ -263,7 +279,7 @@ export function usePlan(params = {}) {
} }
} else { } else {
// 발전시뮬레이션 // 발전시뮬레이션
if (estimateDetail.tempFlg === '0') { if (estimateDetail.estimateDate !== null) {
setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId)) setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId))
setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId }))) setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId })))
} else { } else {
@ -281,7 +297,9 @@ export function usePlan(params = {}) {
}) })
} else { } else {
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) { if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
await saveCanvas() await saveCanvas(true)
clearRecoilState()
} }
setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId)) setCurrentCanvasPlan(plans.find((plan) => plan.id === newCurrentId))
setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId }))) setPlans((plans) => plans.map((plan) => ({ ...plan, isCurrent: plan.id === newCurrentId })))
@ -294,9 +312,15 @@ export function usePlan(params = {}) {
// setBgImage() // setBgImage()
}, [currentCanvasPlan]) }, [currentCanvasPlan])
const clearRecoilState = () => {
//clear가 필요한 recoil state 관리
resetOuterLinePoints()
resetPlacementShapeDrawingPoints()
}
const handleCurrentPlanUrl = () => { const handleCurrentPlanUrl = () => {
const currentPlan = plans.find((plan) => plan.isCurrent) if (currentCanvasPlan?.planNo && currentCanvasPlan?.objectNo)
if (currentPlan) router.push(`${pathname}?pid=${currentPlan?.planNo}&objectNo=${floorPlanState?.objectNo}`) router.push(`${pathname}?pid=${currentCanvasPlan?.planNo}&objectNo=${currentCanvasPlan?.objectNo}`)
} }
const setBgImage = () => { const setBgImage = () => {
@ -309,20 +333,20 @@ export function usePlan(params = {}) {
*/ */
const handleAddPlan = async (userId, objectNo) => { const handleAddPlan = async (userId, objectNo) => {
if (currentCanvasPlan?.id) { if (currentCanvasPlan?.id) {
await saveCanvas() await saveCanvas(true)
} }
JSON.parse(currentCanvasData()).objects.length > 0 JSON.parse(currentCanvasData()).objects.length > 0
? swalFire({ ? swalFire({
text: `Plan ${currentCanvasPlan.planNo} ` + getMessage('plan.message.confirm.copy'), text: `Plan ${currentCanvasPlan.planNo} ` + getMessage('plan.message.confirm.copy'),
type: 'confirm', type: 'confirm',
confirmFn: async () => { confirmFn: async () => {
await postCanvasStatus(userId, objectNo, currentCanvasData(), false) await postObjectPlan(userId, objectNo, true, false)
}, },
denyFn: async () => { denyFn: async () => {
await postCanvasStatus(userId, objectNo, '', false) await postObjectPlan(userId, objectNo, false, false)
}, },
}) })
: await postCanvasStatus(userId, objectNo, '', false) : await postObjectPlan(userId, objectNo, false, false)
} }
/** /**
@ -373,16 +397,40 @@ export function usePlan(params = {}) {
*/ */
const loadCanvasPlanData = async (userId, objectNo, planNo) => { const loadCanvasPlanData = async (userId, objectNo, planNo) => {
console.log('🚀 ~ loadCanvasPlanData ~ userId, objectNo, planNo:', userId, objectNo, planNo) console.log('🚀 ~ loadCanvasPlanData ~ userId, objectNo, planNo:', userId, objectNo, planNo)
await getCanvasByObjectNo(userId, objectNo, planNo).then((res) => { await getCanvasByObjectNo(objectNo, planNo).then(async (res) => {
if (res.length > 0) { if (res.length > 0) {
setCurrentCanvasPlan(res.find((plan) => plan.planNo === planNo)) setCurrentCanvasPlan(res.find((plan) => plan.planNo === planNo))
setPlans(res) setPlans(res)
} else { } else {
postCanvasStatus(userId, objectNo, '', true) await postObjectPlan(userId, objectNo, false, true)
} }
}) })
} }
/**
* plan canvasStatus 초기화
*/
const resetCanvasStatus = () => {
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: null }))
setPlans((plans) => plans.map((plan) => ({ ...plan, canvasStatus: null })))
}
/**
* plan canvasStatus 불러오기
*
* 견적서/발전시뮬레이션에서 플랜 이동 현재 플랜의 canvasStatus를 불러오기 위해 사용
*/
const reloadCanvasStatus = async (objectNo, planNo) => {
if (pathname === '/floor-plan/estimate/5' || pathname === '/floor-plan/simulator/6') {
await getCanvasByObjectNo(objectNo, planNo).then((res) => {
if (res.length > 0) {
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: res.find((plan) => plan.planNo === planNo).canvasStatus }))
setPlans((plans) => plans.map((plan) => ({ ...plan, canvasStatus: res.find((plan) => plan.planNo === planNo).canvasStatus })))
}
})
}
}
/** /**
* 현재 plan 이동 -> 새로운 링크로 이동 * 현재 plan 이동 -> 새로운 링크로 이동
*/ */
@ -394,11 +442,14 @@ export function usePlan(params = {}) {
canvas, canvas,
plans, plans,
currentCanvasPlan, currentCanvasPlan,
setCurrentCanvasPlan,
selectedPlan, selectedPlan,
saveCanvas, saveCanvas,
handleCurrentPlan, handleCurrentPlan,
handleAddPlan, handleAddPlan,
handleDeletePlan, handleDeletePlan,
loadCanvasPlanData, loadCanvasPlanData,
resetCanvasStatus,
reloadCanvasStatus,
} }
} }

View File

@ -61,12 +61,18 @@ export const usePolygon = () => {
let left, top let left, top
if (line.direction === 'left' || line.direction === 'right') { if (line.direction === 'right') {
left = (x1 + x2) / 2 left = (x1 + x2) / 2
top = (y1 + y2) / 2 + 10 top = (y1 + y2) / 2 + 10
} else if (line.direction === 'top' || line.direction === 'bottom') { } else if (line.direction === 'top') {
left = (x1 + x2) / 2 + 10 left = (x1 + x2) / 2 + 10
top = (y1 + y2) / 2 top = (y1 + y2) / 2
} else if (line.direction === 'left') {
left = (x1 + x2) / 2
top = (y1 + y2) / 2 - 30
} else if (line.direction === 'bottom') {
left = (x1 + x2) / 2 - 50
top = (y1 + y2) / 2
} }
const minX = line.left const minX = line.left
@ -199,62 +205,94 @@ export const usePolygon = () => {
const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x)) const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x))
const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y)) const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y))
const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y)) const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y))
const lines = polygon.lines
let centerPoints
switch (direction) {
case 'south':
// lines중 가장 아래에 있는 라인을 찾는다.
const line = lines.reduce((acc, cur) => {
return acc.y2 > cur.y2 ? acc : cur
}, lines[0])
centerPoint = { x: (line.x2 + line.x1) / 2, y: Math.max(line.y1, line.y2) }
break
case 'north':
// lines중 가장 위에 있는 라인을 찾는다.
const line2 = lines.reduce((acc, cur) => {
return acc.y2 < cur.y2 ? acc : cur
}, lines[0])
centerPoint = { x: (line2.x2 + line2.x1) / 2, y: Math.min(line2.y1, line2.y2) }
break
case 'west':
// lines중 가장 왼쪽에 있는 라인을 찾는다.
const line3 = lines.reduce((acc, cur) => {
return acc.x2 < cur.x2 ? acc : cur
}, lines[0])
centerPoint = { x: Math.min(line3.x1, line3.x2), y: (line3.y1 + line3.y2) / 2 }
break
case 'east':
// lines중 가장 오른쪽에 있는 라인을 찾는다.
const line4 = lines.reduce((acc, cur) => {
return acc.x2 > cur.x2 ? acc : cur
}, lines[0])
centerPoint = { x: Math.max(line4.x1, line4.x2), y: (line4.y1 + line4.y2) / 2 }
break
}
switch (direction) { switch (direction) {
case 'north': case 'north':
points = [ points = [
{ x: centerPoint.x - width / 2, y: polygonMinY - 50 }, { x: centerPoint.x, y: polygonMinY - 50 },
{ x: centerPoint.x + 20 - width / 2, y: polygonMinY - 50 }, { x: centerPoint.x + 20, y: polygonMinY - 50 },
{ x: centerPoint.x + 20 - width / 2, y: polygonMinY - 80 }, { x: centerPoint.x + 20, y: polygonMinY - 80 },
{ x: centerPoint.x + 50 - width / 2, y: polygonMinY - 80 }, { x: centerPoint.x + 50, y: polygonMinY - 80 },
{ x: centerPoint.x - width / 2, y: polygonMinY - 110 }, { x: centerPoint.x, y: polygonMinY - 110 },
{ x: centerPoint.x - 50 - width / 2, y: polygonMinY - 80 }, { x: centerPoint.x - 50, y: polygonMinY - 80 },
{ x: centerPoint.x - 20 - width / 2, y: polygonMinY - 80 }, { x: centerPoint.x - 20, y: polygonMinY - 80 },
{ x: centerPoint.x - 20 - width / 2, y: polygonMinY - 50 }, { x: centerPoint.x - 20, y: polygonMinY - 50 },
] ]
stickeyPoint = { x: centerPoint.x - width / 2, y: polygonMinY - 110 } stickeyPoint = { x: centerPoint.x, y: polygonMinY - 110 }
break break
case 'south': case 'south':
points = [ points = [
{ x: centerPoint.x + width / 2, y: polygonMaxY + 50 }, { x: centerPoint.x, y: polygonMaxY + 50 },
{ x: centerPoint.x + 20 + width / 2, y: polygonMaxY + 50 }, { x: centerPoint.x + 20, y: polygonMaxY + 50 },
{ x: centerPoint.x + 20 + width / 2, y: polygonMaxY + 80 }, { x: centerPoint.x + 20, y: polygonMaxY + 80 },
{ x: centerPoint.x + 50 + width / 2, y: polygonMaxY + 80 }, { x: centerPoint.x + 50, y: polygonMaxY + 80 },
{ x: centerPoint.x + width / 2, y: polygonMaxY + 110 }, { x: centerPoint.x, y: polygonMaxY + 110 },
{ x: centerPoint.x - 50 + width / 2, y: polygonMaxY + 80 }, { x: centerPoint.x - 50, y: polygonMaxY + 80 },
{ x: centerPoint.x - 20 + width / 2, y: polygonMaxY + 80 }, { x: centerPoint.x - 20, y: polygonMaxY + 80 },
{ x: centerPoint.x - 20 + width / 2, y: polygonMaxY + 50 }, { x: centerPoint.x - 20, y: polygonMaxY + 50 },
] ]
stickeyPoint = { x: centerPoint.x + width / 2, y: polygonMaxY + 110 } stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 110 }
break break
case 'west': case 'west':
points = [ points = [
{ x: polygonMinX - 50, y: centerPoint.y - height / 2 }, { x: polygonMinX - 50, y: centerPoint.y },
{ x: polygonMinX - 50, y: centerPoint.y + 20 - height / 2 }, { x: polygonMinX - 50, y: centerPoint.y + 20 },
{ x: polygonMinX - 80, y: centerPoint.y + 20 - height / 2 }, { x: polygonMinX - 80, y: centerPoint.y + 20 },
{ x: polygonMinX - 80, y: centerPoint.y + 50 - height / 2 }, { x: polygonMinX - 80, y: centerPoint.y + 50 },
{ x: polygonMinX - 110, y: centerPoint.y - height / 2 }, { x: polygonMinX - 110, y: centerPoint.y },
{ x: polygonMinX - 80, y: centerPoint.y - 50 - height / 2 }, { x: polygonMinX - 80, y: centerPoint.y - 50 },
{ x: polygonMinX - 80, y: centerPoint.y - 20 - height / 2 }, { x: polygonMinX - 80, y: centerPoint.y - 20 },
{ x: polygonMinX - 50, y: centerPoint.y - 20 - height / 2 }, { x: polygonMinX - 50, y: centerPoint.y - 20 },
] ]
stickeyPoint = { x: polygonMinX - 110, y: centerPoint.y - height / 2 } stickeyPoint = { x: polygonMinX - 110, y: centerPoint.y }
break break
case 'east': case 'east':
points = [ points = [
{ x: polygonMaxX + 50, y: centerPoint.y + height / 2 }, { x: polygonMaxX + 50, y: centerPoint.y },
{ x: polygonMaxX + 50, y: centerPoint.y + 20 + height / 2 }, { x: polygonMaxX + 50, y: centerPoint.y + 20 },
{ x: polygonMaxX + 80, y: centerPoint.y + 20 + height / 2 }, { x: polygonMaxX + 80, y: centerPoint.y + 20 },
{ x: polygonMaxX + 80, y: centerPoint.y + 50 + height / 2 }, { x: polygonMaxX + 80, y: centerPoint.y + 50 },
{ x: polygonMaxX + 110, y: centerPoint.y + height / 2 }, { x: polygonMaxX + 110, y: centerPoint.y },
{ x: polygonMaxX + 80, y: centerPoint.y - 50 + height / 2 }, { x: polygonMaxX + 80, y: centerPoint.y - 50 },
{ x: polygonMaxX + 80, y: centerPoint.y - 20 + height / 2 }, { x: polygonMaxX + 80, y: centerPoint.y - 20 },
{ x: polygonMaxX + 50, y: centerPoint.y - 20 + height / 2 }, { x: polygonMaxX + 50, y: centerPoint.y - 20 },
] ]
stickeyPoint = { x: polygonMaxX + 110, y: centerPoint.y + height / 2 } stickeyPoint = { x: polygonMaxX + 110, y: centerPoint.y }
break break
} }
@ -309,7 +347,35 @@ export const usePolygon = () => {
let text = '' let text = ''
const compassType = (375 - getDegreeInOrientation(moduleCompass)) / 15 let compassType = (375 - getDegreeInOrientation(moduleCompass)) / 15
if (moduleCompass === 0 || (moduleCompass < 0 && moduleCompass >= -6)) {
compassType = 1
} else if (moduleCompass < 0 && moduleCompass >= -21) {
compassType = 2
} else if (moduleCompass < 0 && moduleCompass >= -36) {
compassType = 3
} else if (moduleCompass < 0 && moduleCompass >= -51) {
compassType = 4
} else if (moduleCompass < 0 && moduleCompass >= -66) {
compassType = 5
} else if (moduleCompass < 0 && moduleCompass >= -81) {
compassType = 6
} else if (moduleCompass < 0 && moduleCompass >= -96) {
compassType = 7
} else if (moduleCompass < 0 && moduleCompass >= -111) {
compassType = 8
} else if (moduleCompass < 0 && moduleCompass >= -126) {
compassType = 9
} else if (moduleCompass < 0 && moduleCompass >= -141) {
compassType = 10
} else if (moduleCompass < 0 && moduleCompass >= -156) {
compassType = 11
} else if (moduleCompass < 0 && moduleCompass >= -171) {
compassType = 12
} else if (moduleCompass === 180) {
compassType = 13
}
if ([1, 25].includes(compassType)) { if ([1, 25].includes(compassType)) {
direction === 'north' ? (text = '北') : direction === 'south' ? (text = '南') : direction === 'west' ? (text = '西') : (text = '東') direction === 'north' ? (text = '北') : direction === 'south' ? (text = '南') : direction === 'west' ? (text = '西') : (text = '東')

View File

@ -13,7 +13,7 @@ export function useTempGrid() {
//임의 그리드 모드일 경우 //임의 그리드 모드일 경우
let pointer = canvas.getPointer(e.e) let pointer = canvas.getPointer(e.e)
const tempGrid = new fabric.Line([pointer.x, 0, pointer.x, canvas.height], { const tempGrid = new fabric.Line([pointer.x, -1500, pointer.x, 2500], {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,
@ -41,7 +41,7 @@ export function useTempGrid() {
//임의 그리드 모드일 경우 //임의 그리드 모드일 경우
let pointer = { x: e.offsetX, y: e.offsetY } let pointer = { x: e.offsetX, y: e.offsetY }
const tempGrid = new fabric.Line([0, pointer.y, canvas.width, pointer.y], { const tempGrid = new fabric.Line([-1500, pointer.y, 2500, pointer.y], {
stroke: gridColor, stroke: gridColor,
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,

View File

@ -16,9 +16,7 @@ export async function getSession() {
let session let session
session = await getIronSession(cookies(), sessionOptions) session = await getIronSession(cookies(), sessionOptions)
console.log('session:', session)
if (!session.isLoggedIn) { if (!session.isLoggedIn) {
// session.isLoggedIn = defaultSession.isLoggedIn
session.isLoggedIn = false session.isLoggedIn = false
} }
@ -27,10 +25,6 @@ export async function getSession() {
export async function checkSession() { export async function checkSession() {
const session = await getSession() const session = await getSession()
// if (!session.isLoggedIn) {
// redirect('/login')
// }
return session.isLoggedIn return session.isLoggedIn
} }
@ -54,7 +48,6 @@ export async function setSession(data) {
session.pwdInitYn = data.pwdInitYn session.pwdInitYn = data.pwdInitYn
session.custCd = data.custCd session.custCd = data.custCd
session.isLoggedIn = true session.isLoggedIn = true
// console.log('session:', session)
await session.save() await session.save()
} }
@ -64,31 +57,33 @@ export async function login() {
if (session) { if (session) {
redirect('/') redirect('/')
} }
}
// const userId = formData.get('id')
// const password = formData.get('password') export const customSetMenuNumber = async ({ objectNo, pid, menuNum, callback = () => {} }) => {
let db = null
// console.log('id:', userId)
// console.log('password:', password) if (!db) {
db = await open({
// // const loginUser = await getUserByIdAndPassword({ userId, password }) filename: 'qcast3.global.sqlite',
// const loginUser = { driver: sqlite3.Database,
// id: 1, })
// userId: 'test123', }
// name: 'jinsoo Kim',
// email: 'jinsoo.kim@example.com', const chkSql = `SELECT menu_num FROM current_menu WHERE object_no = ? AND pid = ?`
// } const prevMenuNum = await getInstance().get(chkSql, objectNo, pid)
// if (!loginUser) { if (prevMenuNum) {
// throw Error('Wrong Credentials!') if (prevMenuNum > menuNum) {
// } callback()
} else {
// session.name = loginUser.name const sql = `UPDATE current_menu SET menu_num = ? WHERE object_no = ? AND pid = ?`
// session.userId = loginUser.userId await getInstance().run(sql, menuNum, objectNo, pid)
// session.email = loginUser.email
// session.isLoggedIn = true setMenuNumber(menuNum)
// console.log('session:', session) }
} else {
// await session.save() const sql = `INSERT INTO current_menu (object_no, pid, menu_num) VALUES (?, ?, ?)`
// redirect('/') await getInstance().run(sql, objectNo, pid, menuNum)
setMenuNumber(menuNum)
}
} }

View File

@ -72,15 +72,7 @@ const writeImage = async (fileName, file) => {
} }
const readImage = async (fileName) => { const readImage = async (fileName) => {
const file = await fs.readFile(`${FILE_PATH}/${fileName}`) const file = await fs.readFile(`${process.env.NEXT_PUBLIC_HOST_URL}${fileName}`)
// .then((res) => {
// console.log('readImage-then', res)
// })
// .catch((e) => {
// console.log('readImage-catch', e)
// })
console.log('🚀 ~ readImage ~ file:', file)
return file return file
} }
@ -88,7 +80,7 @@ const removeImage = async (fileName) => {
try { try {
await fs.rm(`${FILE_PATH}/${fileName}.png`) await fs.rm(`${FILE_PATH}/${fileName}.png`)
} catch (e) { } catch (e) {
console.log(e) // Error handling without console.log
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -3,19 +3,19 @@
"welcome": "환영합니다. {0}님", "welcome": "환영합니다. {0}님",
"header.menus.home": "Home", "header.menus.home": "Home",
"header.menus.management": "물건 및 도면 관리", "header.menus.management": "물건 및 도면 관리",
"header.menus.management.newStuff": "신규 물건 등록", "header.menus.management.newStuff": "신규물건등록",
"header.menus.management.detail": "물건 상세", "header.menus.management.detail": "물건상세",
"header.menus.management.stuffList": "물건 현황", "header.menus.management.stuffList": "물건현황",
"header.menus.community": "커뮤니티", "header.menus.community": "커뮤니티",
"header.menus.community.notice": "공지", "header.menus.community.notice": "공지사항",
"header.menus.community.faq": "FAQ", "header.menus.community.faq": "FAQ",
"header.menus.community.archive": "자료 다운로드", "header.menus.community.archive": "문서다운로드",
"header.logout": "로그아웃", "header.logout": "로그아웃",
"header.go": "이동", "header.go": "이동",
"header.online.warranty.system": "온라인 보증 시스템", "header.online.warranty.system": "온라인보증시스템",
"header.stem": "Stem", "header.stem": "Stem",
"plan.menu.plan.drawing": "물건정보", "plan.menu.plan.drawing": "물건정보",
"plan.menu.placement.surface.initial.setting": "배치면 초기 설정", "plan.menu.placement.surface.initial.setting": "배치면 초기설정",
"modal.placement.initial.setting.plan.drawing": "도면 작성방법", "modal.placement.initial.setting.plan.drawing": "도면 작성방법",
"modal.placement.initial.setting.plan.drawing.size.stuff": "치수 입력에 의한 물건 작성", "modal.placement.initial.setting.plan.drawing.size.stuff": "치수 입력에 의한 물건 작성",
"modal.placement.initial.setting.size": "치수 입력방법", "modal.placement.initial.setting.size": "치수 입력방법",
@ -29,7 +29,7 @@
"modal.placement.initial.setting.roof.angle.setting": "지붕각도 설정", "modal.placement.initial.setting.roof.angle.setting": "지붕각도 설정",
"modal.placement.initial.setting.roof.pitch": "경사", "modal.placement.initial.setting.roof.pitch": "경사",
"modal.placement.initial.setting.roof.angle": "각도", "modal.placement.initial.setting.roof.angle": "각도",
"modal.placement.initial.setting.roof.material": "지붕재 선택(단위: mm)", "modal.placement.initial.setting.roof.material": "지붕재 선택(단위mm)",
"modal.placement.initial.setting.roof.material.info": "대응 가능한 지붕재 및 발판은 한정되므로 반드시 사전 매뉴얼을 확인하십시오.", "modal.placement.initial.setting.roof.material.info": "대응 가능한 지붕재 및 발판은 한정되므로 반드시 사전 매뉴얼을 확인하십시오.",
"modal.placement.initial.setting.rafter": "서까래", "modal.placement.initial.setting.rafter": "서까래",
"modal.roof.shape.setting": "지붕형상 설정", "modal.roof.shape.setting": "지붕형상 설정",
@ -44,14 +44,14 @@
"plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경", "plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경",
"plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림", "plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림",
"modal.movement.flow.line.move": "동선 이동", "modal.movement.flow.line.move": "동선 이동",
"modal.movement.flow.line.move.alert": "이동 할 수 없습니다.", "modal.movement.flow.line.move.alert": "이동할 수 없습니다.",
"modal.movement.flow.line.updown": "형 올림·내림", "modal.movement.flow.line.updown": "형 올림·내림",
"modal.movement.flow.line.updown.info": "자릿수가 다른 변을 선택하고 폭을 지정하십시오.", "modal.movement.flow.line.updown.info": "자릿수가 다른 변을 선택하고 폭을 지정하십시오.",
"modal.movement.flow.line.updown.up": "자릿수를 올리다", "modal.movement.flow.line.updown.up": "자릿수를 올리다",
"modal.movement.flow.line.updown.down": "자릿수를 낮추다", "modal.movement.flow.line.updown.down": "자릿수를 낮추다",
"modal.movement.flow.line.info": "동선을 선택하고 이동 폭을 지정하십시오", "modal.movement.flow.line.info": "동선을 선택하고 이동 폭을 지정하십시오",
"modal.movement.flow.line.bottom.left": "높이 변경: 아래, 왼쪽", "modal.movement.flow.line.bottom.left": "높이변경 : 아래, 왼쪽",
"modal.movement.flow.line.top.right": "높이 변경: 위, 오른쪽", "modal.movement.flow.line.top.right": "높이변경 : 위, 오른쪽",
"plan.menu.roof.cover.outline.edit.offset": "외벽선 편집 및 오프셋", "plan.menu.roof.cover.outline.edit.offset": "외벽선 편집 및 오프셋",
"plan.menu.roof.cover.roof.surface.alloc": "지붕면 할당", "plan.menu.roof.cover.roof.surface.alloc": "지붕면 할당",
"plan.menu.roof.cover.roof.shape.edit": "지붕형상 편집", "plan.menu.roof.cover.roof.shape.edit": "지붕형상 편집",
@ -63,7 +63,7 @@
"modal.cover.outline.angle": "각도", "modal.cover.outline.angle": "각도",
"modal.cover.outline.diagonal": "대각선", "modal.cover.outline.diagonal": "대각선",
"modal.cover.outline.setting": "설정", "modal.cover.outline.setting": "설정",
"modal.cover.outline.length": "길이 (mm)", "modal.cover.outline.length": "길이(mm)",
"modal.cover.outline.arrow": "방향(화살표)", "modal.cover.outline.arrow": "방향(화살표)",
"modal.cover.outline.fix": "외벽선 확정", "modal.cover.outline.fix": "외벽선 확정",
"modal.cover.outline.rollback": "일변전으로 돌아가기", "modal.cover.outline.rollback": "일변전으로 돌아가기",
@ -71,7 +71,7 @@
"common.setting.finish": "설정완료", "common.setting.finish": "설정완료",
"common.setting.rollback": "일변전으로 돌아가기", "common.setting.rollback": "일변전으로 돌아가기",
"modal.cover.outline.remove": "외벽 제거", "modal.cover.outline.remove": "외벽 제거",
"modal.cover.outline.select.move": "외벽 선택, 이동", "modal.cover.outline.select.move": "외벽 선택 이동",
"plan.menu.placement.surface": "배치면", "plan.menu.placement.surface": "배치면",
"plan.menu.placement.surface.slope.setting": "경사설정", "plan.menu.placement.surface.slope.setting": "경사설정",
"plan.menu.placement.surface.drawing": "배치면 그리기", "plan.menu.placement.surface.drawing": "배치면 그리기",
@ -84,8 +84,8 @@
"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": "배치면 전체 삭제",
"plan.menu.module.circuit.setting": "모듈,회로 구성", "plan.menu.module.circuit.setting": "모듈, 회로 구성",
"plan.menu.module.circuit.setting.default": "기본 설정", "plan.menu.module.circuit.setting.default": "모듈/가대설정",
"modal.module.basic.setting.orientation.setting": "방위 설정", "modal.module.basic.setting.orientation.setting": "방위 설정",
"modal.module.basic.setting.orientation.setting.info": "※시뮬레이션 계산용 방위를 지정합니다. 남쪽의 방위를 설정해주세요.", "modal.module.basic.setting.orientation.setting.info": "※시뮬레이션 계산용 방위를 지정합니다. 남쪽의 방위를 설정해주세요.",
"modal.module.basic.setting.orientation.setting.angle.passivity": "각도를 직접 입력", "modal.module.basic.setting.orientation.setting.angle.passivity": "각도를 직접 입력",
@ -96,32 +96,32 @@
"modal.module.basic.setting.module.under.roof": "지붕밑바탕", "modal.module.basic.setting.module.under.roof": "지붕밑바탕",
"modal.module.basic.setting.module.setting": "모듈 선택", "modal.module.basic.setting.module.setting": "모듈 선택",
"modal.module.basic.setting.module.hajebichi": "망둥어 피치", "modal.module.basic.setting.module.hajebichi": "망둥어 피치",
"modal.module.basic.setting.module.setting.info1": "※ 구배의 범위에는 제한이 있습니다. 지붕경사가 2.5치 미만, 10치를 초과하는 경우에는 시공이 가능한지 시공 매뉴얼을 확인해주십시오.", "modal.module.basic.setting.module.setting.info1": "※ 구배의 범위에는 제한이 있습니다. 지붕경사가 2.5치 미만 10치를 초과하는 경우에는 시공이 가능한지 시공 매뉴얼을 확인해주십시오.",
"modal.module.basic.setting.module.setting.info2": "※ 모듈 배치 시에는 시공 매뉴얼에 기재된 <모듈 배치 조건>을 반드시 확인해주십시오.", "modal.module.basic.setting.module.setting.info2": "※ 모듈 배치 시에는 시공 매뉴얼에 기재된 <모듈 배치 조건>을 반드시 확인해주십시오.",
"modal.module.basic.setting.module.stuff.info": "물건정보", "modal.module.basic.setting.module.stuff.info": "물건정보",
"modal.module.basic.setting.module.surface.type": "면조도구분", "modal.module.basic.setting.module.surface.type": "면조도",
"modal.module.basic.setting.module.fitting.height": "설치높이", "modal.module.basic.setting.module.fitting.height": "설치높이",
"modal.module.basic.setting.module.standard.wind.speed": "기준 풍속", "modal.module.basic.setting.module.standard.wind.speed": "기준풍속",
"modal.module.basic.setting.module.standard.snowfall.amount": "기준 적설량", "modal.module.basic.setting.module.standard.snowfall.amount": "적설량",
"modal.module.basic.setting.module.standard.construction": "표준시공", "modal.module.basic.setting.module.standard.construction": "표준시공",
"modal.module.basic.setting.module.enforce.construction": "강화시공", "modal.module.basic.setting.module.enforce.construction": "강화시공",
"modal.module.basic.setting.module.multiple.construction": "다설시공", "modal.module.basic.setting.module.multiple.construction": "다설시공",
"modal.module.basic.setting.module.eaves.bar.fitting": "처마력 바의 설치", "modal.module.basic.setting.module.eaves.bar.fitting": "처마커버설치",
"modal.module.basic.setting.module.blind.metal.fitting": "눈막이 금구 설치", "modal.module.basic.setting.module.blind.metal.fitting": "적설방지금구설치",
"modal.module.basic.setting.module.select": "모듈 선택", "modal.module.basic.setting.module.select": "모듈/가대 선택",
"modal.module.basic.setting.module.placement": "모듈 배치", "modal.module.basic.setting.module.placement": "모듈 배치",
"modal.module.basic.setting.module.placement.select.fitting.type": "설치형태를 선택해주세요.", "modal.module.basic.setting.module.placement.select.fitting.type": "설치형태를 선택해주세요.",
"modal.module.basic.setting.module.placement.waterfowl.arrangement": "물떼새 배치", "modal.module.basic.setting.module.placement.waterfowl.arrangement": "물떼새 배치",
"modal.module.basic.setting.module.placement.do": "한다", "modal.module.basic.setting.module.placement.do": "한다",
"modal.module.basic.setting.module.placement.do.not": "하지 않는다", "modal.module.basic.setting.module.placement.do.not": "하지 않는다",
"modal.module.basic.setting.module.placement.arrangement.standard": "배치 기준", "modal.module.basic.setting.module.placement.arrangement.standard": "배치 기준",
"modal.module.basic.setting.module.placement.arrangement.standard.center": "중앙배치", "modal.module.basic.setting.module.placement.arrangement.standard.center": "중앙",
"modal.module.basic.setting.module.placement.arrangement.standard.eaves": "처마", "modal.module.basic.setting.module.placement.arrangement.standard.eaves": "처마",
"modal.module.basic.setting.module.placement.arrangement.standard.ridge": "용마루", "modal.module.basic.setting.module.placement.arrangement.standard.ridge": "용마루",
"modal.module.basic.setting.module.placement.maximum": "최대배치 실시한다.", "modal.module.basic.setting.module.placement.maximum": "최대배치",
"modal.module.basic.setting.pitch.module.placement.standard.setting": "배치 기준 설정", "modal.module.basic.setting.pitch.module.placement.standard.setting": "배치기준 설정",
"modal.module.basic.setting.pitch.module.placement.standard.setting.south": "남향으로 설치한다", "modal.module.basic.setting.pitch.module.placement.standard.setting.south": "남향설치",
"modal.module.basic.setting.pitch.module.placement.standard.setting.select": "지정한 변을 기준으로 설치한다", "modal.module.basic.setting.pitch.module.placement.standard.setting.select": "지정한 변을 기준으로 설치",
"modal.module.basic.setting.pitch.module.allocation.setting": "할당 설정", "modal.module.basic.setting.pitch.module.allocation.setting": "할당 설정",
"modal.module.basic.setting.pitch.module.allocation.setting.info": "※배치 패널 종류가 1종류일 경우에만 사용할 수 있습니다.", "modal.module.basic.setting.pitch.module.allocation.setting.info": "※배치 패널 종류가 1종류일 경우에만 사용할 수 있습니다.",
"modal.module.basic.setting.pitch.module.row.amount": "단수", "modal.module.basic.setting.pitch.module.row.amount": "단수",
@ -131,44 +131,48 @@
"modal.module.basic.setting.prev": "이전", "modal.module.basic.setting.prev": "이전",
"modal.module.basic.setting.passivity.placement": "수동 배치", "modal.module.basic.setting.passivity.placement": "수동 배치",
"modal.module.basic.setting.auto.placement": "설정값으로 자동 배치", "modal.module.basic.setting.auto.placement": "설정값으로 자동 배치",
"plan.menu.module.circuit.setting.circuit.trestle.setting": "회로 및 가대 설정", "plan.menu.module.circuit.setting.circuit.trestle.setting": "회로설정",
"modal.circuit.trestle.setting": "회로 및 가대설정", "modal.circuit.trestle.setting": "회로설정",
"modal.circuit.trestle.setting.alloc.trestle": "가대할당", "modal.circuit.trestle.setting.alloc.trestle": "가대할당",
"modal.circuit.trestle.setting.power.conditional.select": "파워컨디셔너 선택", "modal.circuit.trestle.setting.power.conditional.select": "파워컨디셔너 선택",
"modal.circuit.trestle.setting.power.conditional.select.cold.region": "한랭지사양", "modal.circuit.trestle.setting.power.conditional.select.cold.region": "한랭지사양",
"modal.circuit.trestle.setting.power.conditional.select.name": "명칭", "modal.circuit.trestle.setting.power.conditional.select.name": "명칭",
"modal.circuit.trestle.setting.power.conditional.select.rated.output": "정격출력", "modal.circuit.trestle.setting.power.conditional.select.rated.output": "정격출력",
"modal.circuit.trestle.setting.power.conditional.select.circuit.amount": "회로수", "modal.circuit.trestle.setting.power.conditional.select.circuit.amount": "회로수",
"modal.circuit.trestle.setting.power.conditional.select.max.connection": "최대접속매수", "modal.circuit.trestle.setting.power.conditional.select.max.connection": "표준매수",
"modal.circuit.trestle.setting.power.conditional.select.max.overload": "과적최대매수", "modal.circuit.trestle.setting.power.conditional.select.max.overload": "최대매수",
"modal.circuit.trestle.setting.power.conditional.select.output.current": "출력전류", "modal.circuit.trestle.setting.power.conditional.select.output.current": "출력전류",
"modal.circuit.trestle.setting.power.conditional.select.check1": "동일경사 동일 방면의 면적인 경우, 같은 면으로서 회로를 나눈다.", "modal.circuit.trestle.setting.power.conditional.select.check1": "동일경사 동일방면의 면적인 경우 같은 면으로서 회로를 나눈다.",
"modal.circuit.trestle.setting.power.conditional.select.check2": "MAX 접속(과적)으로 회로를 나눈다.", "modal.circuit.trestle.setting.power.conditional.select.check2": "MAX 접속(과적)으로 회로를 나눈다.",
"modal.circuit.trestle.setting.circuit.allocation": "회로 할당", "modal.circuit.trestle.setting.circuit.allocation": "회로 할당",
"modal.circuit.trestle.setting.circuit.allocation.auto": "자동 회로 할당", "modal.circuit.trestle.setting.circuit.allocation.auto": "자동회로 할당",
"modal.circuit.trestle.setting.circuit.allocation.passivity": "수동 회로 할당", "modal.circuit.trestle.setting.circuit.allocation.passivity": "수동회로 할당",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "회로", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit": "회로",
"modal.circuit.trestle.setting.circuit.allocation.passivity.series": "시리즈",
"modal.circuit.trestle.setting.circuit.allocation.passivity.name": "명칭",
"modal.circuit.trestle.setting.circuit.allocation.passivity.info": "동일한 회로의 모듈을 선택 상태로 만든 후 [번호 확정] 버튼을 누르면 번호가 할당됩니다.", "modal.circuit.trestle.setting.circuit.allocation.passivity.info": "동일한 회로의 모듈을 선택 상태로 만든 후 [번호 확정] 버튼을 누르면 번호가 할당됩니다.",
"modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "선택된 파워컨디셔너", "modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional": "선택된 파워컨디셔너",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num": "설정할 회로번호(1~)", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num": "설정할 회로번호(1~)",
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info": "표준회로{0}장~{1}장", "modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.info": "표준회로{0}장~{1}장",
"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.selected.power.conditional.reset.info": "선택된 파워 컨디셔너의 회로할당을 초기화합니다.",
"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.all.power.conditional.reset.info": "회로 할당의 설정을 초기화합니다.",
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error01": "배치가능 매수를 초과합니다. 파워컨디셔너를 다시 선택해 주세요.",
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.validation.error02": "시리즈를 선택해주세요.",
"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": "총 회로수",
"modal.circuit.trestle.setting.step.up.allocation.connected": "연결함", "modal.circuit.trestle.setting.step.up.allocation.connected": "연결함",
"modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "승압회로수", "modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "승압회로수",
"modal.circuit.trestle.setting.step.up.allocation.option": "승압옵션", "modal.circuit.trestle.setting.step.up.allocation.option": "승압옵션",
"modal.circuit.trestle.setting.step.up.allocation.select.monitor": "모니터 선택", "modal.circuit.trestle.setting.step.up.allocation.select.monitor": "옵션선택",
"plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용", "plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용",
"plan.menu.estimate": "견적서", "plan.menu.estimate": "견적서",
"plan.menu.estimate.roof.alloc": "지붕면 할당", "plan.menu.estimate.roof.alloc": "지붕면 할당",
"modal.roof.alloc.info": "※ 배치면 초기설정에서 저장한 [기본 지붕재]를 변경하거나, 지붕재를 추가하여 할당할 수 있습니다.", "modal.roof.alloc.info": "※ 배치면 초기설정에서 저장한 [기본 지붕재]를 변경하거나 지붕재를 추가하여 할당할 수 있습니다.",
"modal.roof.alloc.default.roof.material": "기본지붕재", "modal.roof.alloc.default.roof.material": "기본 지붕재",
"modal.roof.alloc.select.roof.material": "지붕재 선택", "modal.roof.alloc.select.roof.material": "지붕재 선택",
"modal.roof.alloc.select.parallel": "병렬식", "modal.roof.alloc.select.parallel": "병렬식",
"modal.roof.alloc.select.stairs": "계단식", "modal.roof.alloc.select.stairs": "계단식",
@ -262,10 +266,10 @@
"modal.canvas.setting.first.option.line": "라인해치", "modal.canvas.setting.first.option.line": "라인해치",
"modal.canvas.setting.first.option.all": "All painted", "modal.canvas.setting.first.option.all": "All painted",
"modal.canvas.setting.wallline.properties.setting": "외벽선 속성 설정", "modal.canvas.setting.wallline.properties.setting": "외벽선 속성 설정",
"modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고, 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n", "modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
"modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정", "modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정",
"modal.canvas.setting.wallline.properties.setting.edge": "케라바로 설정", "modal.canvas.setting.wallline.properties.setting.edge": "케라바로 설정",
"modal.eaves.gable.edit": "처마케라바 변경", "modal.eaves.gable.edit": "처마/케라바 변경",
"modal.eaves.gable.edit.basic": "통상", "modal.eaves.gable.edit.basic": "통상",
"modal.eaves.gable.edit.wall.merge.info": "하옥 등 벽에 접하는 지붕을 작성합니다.", "modal.eaves.gable.edit.wall.merge.info": "하옥 등 벽에 접하는 지붕을 작성합니다.",
"modal.wallline.offset.setting": "외벽선 편집 및 오프셋", "modal.wallline.offset.setting": "외벽선 편집 및 오프셋",
@ -304,17 +308,17 @@
"modal.flow.direction.setting": "흐름 방향 설정", "modal.flow.direction.setting": "흐름 방향 설정",
"modal.flow.direction.setting.info": "흐름방향을 선택하세요.", "modal.flow.direction.setting.info": "흐름방향을 선택하세요.",
"modal.actual.size.setting": "실측치 설정", "modal.actual.size.setting": "실측치 설정",
"modal.actual.size.setting.info": "※隅棟・谷・棟의 실제 치수를 입력해주세요.", "modal.actual.size.setting.info": "※실제 치수를 입력해주세요.",
"modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요", "modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요",
"modal.actual.size.setting.not.exist.size": "실제치수 길이를 입력해 주세요", "modal.actual.size.setting.not.exist.size": "실제치수 길이를 입력해 주세요",
"modal.actual.size.setting.plane.size.length": "복도치수 길이", "modal.actual.size.setting.plane.size.length": "복도치수 길이",
"modal.actual.size.setting.actual.size.length": "실제치수 길이", "modal.actual.size.setting.actual.size.length": "실제치수 길이",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.save": "플랜을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.copy": "플랜을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.confirm.delete": "플랜을 삭제하시겠습니까?",
"plan.message.save": "저장되었습니다.", "plan.message.save": "저장되었습니다.",
"plan.message.delete": "삭제되었습니다.", "plan.message.delete": "삭제되었습니다.",
"plan.message.leave": "물건현황(목록)으로 이동하시겠습니까? [예]를 선택한 경우, 저장하고 이동합니다.", "plan.message.leave": "물건현황(목록)으로 이동하시겠습니까? [예]를 선택한 경우 저장하고 이동합니다.",
"plan.message.corfirm.yes": "예", "plan.message.corfirm.yes": "예",
"plan.message.confirm.no": "아니오", "plan.message.confirm.no": "아니오",
"setting": "설정", "setting": "설정",
@ -328,7 +332,7 @@
"contextmenu.roof.material.remove": "지붕재 삭제", "contextmenu.roof.material.remove": "지붕재 삭제",
"contextmenu.roof.material.remove.all": "지붕재 전체 삭제", "contextmenu.roof.material.remove.all": "지붕재 전체 삭제",
"contextmenu.dormer.offset": "도머 오프셋", "contextmenu.dormer.offset": "도머 오프셋",
"contextmenu.select.move": "선택이동", "contextmenu.select.move": "선택이동",
"contextmenu.wallline.remove": "외벽선 삭제", "contextmenu.wallline.remove": "외벽선 삭제",
"contextmenu.size.edit": "사이즈 변경", "contextmenu.size.edit": "사이즈 변경",
"modal.auxiliary.size.edit": "보조선 사이즈 변경", "modal.auxiliary.size.edit": "보조선 사이즈 변경",
@ -391,7 +395,7 @@
"modal.display.edit.info": "치수선에 표시할 수치를 입력해 주세요.", "modal.display.edit.info": "치수선에 표시할 수치를 입력해 주세요.",
"modal.display.edit.before.length": "기존 길이", "modal.display.edit.before.length": "기존 길이",
"modal.display.edit.after.length": "변경 길이", "modal.display.edit.after.length": "변경 길이",
"modal.display.edit.corner.valley": "구석골의 경우", "modal.display.edit.corner.valley": "구석골의 경우",
"modal.display.edit.input.slope": "경사를 입력해주세요.", "modal.display.edit.input.slope": "경사를 입력해주세요.",
"modal.display.edit.input.slope.info": "경사 설정되어 있는 경우 입력한 수치에 경사 계산을 한 수치가 표시됩니다.", "modal.display.edit.input.slope.info": "경사 설정되어 있는 경우 입력한 수치에 경사 계산을 한 수치가 표시됩니다.",
"modal.distance": "거리 측정", "modal.distance": "거리 측정",
@ -417,6 +421,7 @@
"modal.module.circuit.number.edit": "모듈 일괄 회로 번호 변경", "modal.module.circuit.number.edit": "모듈 일괄 회로 번호 변경",
"modal.module.circuit.number.edit.info": "회로 번호를 입력해주세요.", "modal.module.circuit.number.edit.info": "회로 번호를 입력해주세요.",
"modal.module.circuit.number": "회로 번호", "modal.module.circuit.number": "회로 번호",
"modal.module.can.not.edit": "회로 구성을 완료한 모듈은 변경할 수 없습니다.",
"modal.line.property.change": "변경할 속성을 선택해 주세요.", "modal.line.property.change": "변경할 속성을 선택해 주세요.",
"modal.line.property.change.unselect": "변경할 라인을 선택해 주세요.", "modal.line.property.change.unselect": "변경할 라인을 선택해 주세요.",
"modal.line.property.change.confirm": "속성을 변경하시겠습니까?", "modal.line.property.change.confirm": "속성을 변경하시겠습니까?",
@ -440,7 +445,7 @@
"common.message.transfer.error": "An error occurred while transfer the data. Please contact site administrator.", "common.message.transfer.error": "An error occurred while transfer the data. Please contact site administrator.",
"common.message.delete.error": "An error occurred while deleting data. Please contact site administrator.", "common.message.delete.error": "An error occurred while deleting data. Please contact site administrator.",
"common.message.batch.error": "An error occurred while executing the batch. Please contact site administrator.", "common.message.batch.error": "An error occurred while executing the batch. Please contact site administrator.",
"common.message.send.error": "Error sending data, please contact your administrator.", "common.message.send.error": "Error sending data please contact your administrator.",
"common.message.communication.error": "Network error occurred. \n Please contact site administrator.", "common.message.communication.error": "Network error occurred. \n Please contact site administrator.",
"common.message.data.error": "{0} The data format is not valid.", "common.message.data.error": "{0} The data format is not valid.",
"common.message.data.setting.error": "{0} is data that has been deleted or already configured.", "common.message.data.setting.error": "{0} is data that has been deleted or already configured.",
@ -453,10 +458,10 @@
"common.message.file.template.validation01": "Unable to upload folder", "common.message.file.template.validation01": "Unable to upload folder",
"common.message.file.template.validation02": "Only Excel files can be uploaded.", "common.message.file.template.validation02": "Only Excel files can be uploaded.",
"common.message.file.template.validation03": "Non-registerable extension", "common.message.file.template.validation03": "Non-registerable extension",
"common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity : {0} MB", "common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity ",
"common.message.file.template.validation05": "업로드 파일을 선택해주세요.", "common.message.file.template.validation05": "업로드 파일을 선택해주세요. {0} MB",
"common.message.multi.insert": "Total {0} cases ({1} successes, {2} failures {3})", "common.message.multi.insert": "Total {0} cases ({1} successes {2} failures {3})",
"common.message.error": "Error occurred, please contact site administrator.", "common.message.error": "Error occurred please contact site administrator.",
"common.message.data.save": "Do you want to save it?", "common.message.data.save": "Do you want to save it?",
"common.message.data.delete": "정말로 삭제하시겠습니까?", "common.message.data.delete": "정말로 삭제하시겠습니까?",
"common.message.data.exists": "{0} is data that already exists.", "common.message.data.exists": "{0} is data that already exists.",
@ -486,7 +491,7 @@
"common.message.no.editfield": "Can not edit field", "common.message.no.editfield": "Can not edit field",
"common.message.success.rmmail": "You have successfully sent mail to the Risk Management team.", "common.message.success.rmmail": "You have successfully sent mail to the Risk Management team.",
"common.message.password.validation01": "Change passwords do not match.", "common.message.password.validation01": "Change passwords do not match.",
"common.message.password.validation02": "Please enter at least 8 digits combining English, numbers, and special characters.", "common.message.password.validation02": "Please enter at least 8 digits combining English numbers and special characters.",
"common.message.password.validation03": "Password cannot be the same as ID.", "common.message.password.validation03": "Password cannot be the same as ID.",
"common.message.menu.validation01": "There is no menu to save the order.", "common.message.menu.validation01": "There is no menu to save the order.",
"common.message.menu.validation02": "The same sort order exists.", "common.message.menu.validation02": "The same sort order exists.",
@ -537,7 +542,7 @@
"color.gold": "황금색", "color.gold": "황금색",
"color.darkblue": "남색", "color.darkblue": "남색",
"site.name": "Q.CAST III", "site.name": "Q.CAST III",
"site.sub_name": "태양광 발전 시스템 도면관리 사이트", "site.sub_name": "태양광발전시스템 도면ㆍ견적 시스템",
"site.header.link1": "선택하세요.", "site.header.link1": "선택하세요.",
"site.header.link2": "온라인보증시스템", "site.header.link2": "온라인보증시스템",
"board.notice.title": "공지사항", "board.notice.title": "공지사항",
@ -556,9 +561,9 @@
"board.sub.fileList": "첨부파일 목록", "board.sub.fileList": "첨부파일 목록",
"board.sub.updDt": "업데이트", "board.sub.updDt": "업데이트",
"board.sub.btn.close": "닫기", "board.sub.btn.close": "닫기",
"myinfo.title": "My profile", "myinfo.title": "내정보",
"myinfo.info.userId": "사용자ID", "myinfo.info.userId": "사용자ID",
"myinfo.info.nameKana": "담당자명 후리가나", "myinfo.info.nameKana": "담당자명 일본어",
"myinfo.info.name": "담당자명", "myinfo.info.name": "담당자명",
"myinfo.info.password": "비밀번호", "myinfo.info.password": "비밀번호",
"myinfo.info.chg.password": "변경 비밀번호 입력", "myinfo.info.chg.password": "변경 비밀번호 입력",
@ -583,7 +588,7 @@
"login.id.save": "ID Save", "login.id.save": "ID Save",
"login.id.placeholder": "아이디를 입력해주세요.", "login.id.placeholder": "아이디를 입력해주세요.",
"login.password.placeholder": "비밀번호를 입력해주세요.", "login.password.placeholder": "비밀번호를 입력해주세요.",
"login.guide.text": "당 사이트를 이용할 때는, 사전 신청이 필요합니다.", "login.guide.text": "당 사이트를 이용할 때는 사전 신청이 필요합니다.",
"login.guide.sub1": "ID가 없는 분은", "login.guide.sub1": "ID가 없는 분은",
"login.guide.sub2": "을 클릭해주십시오.", "login.guide.sub2": "을 클릭해주십시오.",
"login.guide.join.btn": "ID신청", "login.guide.join.btn": "ID신청",
@ -623,7 +628,7 @@
"join.btn.login_page": "로그인 화면으로 이동", "join.btn.login_page": "로그인 화면으로 이동",
"join.btn.approval_request": "ID 승인요청", "join.btn.approval_request": "ID 승인요청",
"join.complete.title": "Q.CAST3 로그인ID 발행신청 완료", "join.complete.title": "Q.CAST3 로그인ID 발행신청 완료",
"join.complete.contents": "※ 신청한 ID가 승인되면, 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.", "join.complete.contents": "※ 신청한 ID가 승인되면 담당자 정보에 입력한 이메일 주소로 로그인 관련 안내 메일이 전송됩니다.",
"join.complete.email_comment": "담당자 이메일 주소", "join.complete.email_comment": "담당자 이메일 주소",
"join.validation.check1": "{0} 형식을 확인해주세요.", "join.validation.check1": "{0} 형식을 확인해주세요.",
"join.complete.save.confirm": "Hanwha Japan 담당자에게 ID승인이 요청되면 더 이상 정보를 수정할 수 없습니다. 정말로 요청하시겠습니까?", "join.complete.save.confirm": "Hanwha Japan 담당자에게 ID승인이 요청되면 더 이상 정보를 수정할 수 없습니다. 정말로 요청하시겠습니까?",
@ -672,7 +677,7 @@
"stuff.detail.zipNo": "우편번호", "stuff.detail.zipNo": "우편번호",
"stuff.detail.address": "주소", "stuff.detail.address": "주소",
"stuff.detail.btn.addressPop": "주소검색", "stuff.detail.btn.addressPop": "주소검색",
"stuff.detail.btn.addressPop.guide": "※ 주소검색 버튼을 클릭한 후, 도도부현 정보를 선택해주십시오.", "stuff.detail.btn.addressPop.guide": "※ 주소검색 버튼을 클릭한 후 도도부현 정보를 선택해주십시오.",
"stuff.detail.prefId": "도도부현 / 주소", "stuff.detail.prefId": "도도부현 / 주소",
"stuff.detail.areaId": "발전량시뮬레이션지역", "stuff.detail.areaId": "발전량시뮬레이션지역",
"stuff.detail.standardWindSpeedId": "기준풍속", "stuff.detail.standardWindSpeedId": "기준풍속",
@ -680,7 +685,7 @@
"stuff.detail.btn.windSpeedPop": "풍속선택", "stuff.detail.btn.windSpeedPop": "풍속선택",
"stuff.detail.verticalSnowCover": "수직적설량", "stuff.detail.verticalSnowCover": "수직적설량",
"stuff.detail.coldRegionFlg": "한랭지대책시행", "stuff.detail.coldRegionFlg": "한랭지대책시행",
"stuff.detail.surfaceType": "면조도구분", "stuff.detail.surfaceType": "면조도",
"stuff.detail.saltAreaFlg": "염해지역용아이템사용", "stuff.detail.saltAreaFlg": "염해지역용아이템사용",
"stuff.detail.installHeight": "설치높이", "stuff.detail.installHeight": "설치높이",
"stuff.detail.conType": "계약조건", "stuff.detail.conType": "계약조건",
@ -688,17 +693,17 @@
"stuff.detail.conType1": "전량", "stuff.detail.conType1": "전량",
"stuff.detail.remarks": "메모", "stuff.detail.remarks": "메모",
"stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요", "stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요",
"stuff.detail.tooltip.surfaceType": "염해지역 정의는 각 메이커의 설치 뉴얼을 확인해주십시오", "stuff.detail.tooltip.surfaceType": "염해지역 정의는 각 메이커의 설치 뉴얼을 확인해주십시오",
"stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.", "stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.",
"stuff.detail.tempSave.message2": "담당자 10자리 이하로 입력해 주십시오.", "stuff.detail.tempSave.message2": "담당자이름은 10자리 이하로 입력해 주십시오.",
"stuff.detail.tempSave.message3": "2차 판매점을 선택해주세요.", "stuff.detail.tempSave.message3": "2차 판매점을 선택해주세요.",
"stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", "stuff.detail.confirm.message1": "판매점 정보를 변경하면 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?",
"stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.", "stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.",
"stuff.detail.planList.title": "플랜리스트", "stuff.detail.planList.title": "플랜목록",
"stuff.detail.planList.cnt": "전체", "stuff.detail.planList.cnt": "전체",
"stuff.detail.planList.help": "도움말", "stuff.detail.planList.help": "도움말",
"stuff.detail.planList.guide1": "1.발주는 동일 물건번호 기준 1건만 가능합니다.", "stuff.detail.planList.guide1": "1.발주는 동일 물건번호 기준 1건만 가능합니다.",
"stuff.detail.planList.guide2": "2.[Excel 다운로드]는 견적서, 도면, 시뮬레이션 결과를 엑셀파일로 한번에 다운로드 합니다.", "stuff.detail.planList.guide2": "2.[Excel 다운로드]는 견적서 도면 시뮬레이션 결과를 엑셀파일로 한번에 다운로드 합니다.",
"stuff.detail.planList.guide3": "3.플랜정보를 더블 클릭하면 도면작성 화면으로 이동합니다.", "stuff.detail.planList.guide3": "3.플랜정보를 더블 클릭하면 도면작성 화면으로 이동합니다.",
"stuff.detail.btn.delete": "물건삭제", "stuff.detail.btn.delete": "물건삭제",
"stuff.detail.btn.moveList": "물건목록", "stuff.detail.btn.moveList": "물건목록",
@ -846,8 +851,8 @@
"main.popup.login.newPassword1": "새 비밀번호 입력", "main.popup.login.newPassword1": "새 비밀번호 입력",
"main.popup.login.newPassword2": "새 비밀번호 재입력", "main.popup.login.newPassword2": "새 비밀번호 재입력",
"main.popup.login.placeholder": "반각 10자 이내", "main.popup.login.placeholder": "반각 10자 이내",
"main.popup.login.guide1": "초기화된 비밀번호로 로그인한 경우, 비밀번호를 변경해야 사이트 이용이 가능합니다.", "main.popup.login.guide1": "초기화된 비밀번호로 로그인한 경우 비밀번호를 변경해야 사이트 이용이 가능합니다.",
"main.popup.login.guide2": "비밀번호를 변경하지 않을 경우, 로그인 화면으로 이동합니다.", "main.popup.login.guide2": "비밀번호를 변경하지 않을 경우 로그인 화면으로 이동합니다.",
"main.popup.login.btn1": "변경", "main.popup.login.btn1": "변경",
"main.popup.login.btn2": "변경안함", "main.popup.login.btn2": "변경안함",
"main.popup.login.validate1": "입력한 패스워드가 다릅니다.", "main.popup.login.validate1": "입력한 패스워드가 다릅니다.",
@ -882,6 +887,7 @@
"estimate.detail.roofCns": "지붕재・사양시공", "estimate.detail.roofCns": "지붕재・사양시공",
"estimate.detail.remarks": "비고", "estimate.detail.remarks": "비고",
"estimate.detail.fileFlg": "후일자료제출", "estimate.detail.fileFlg": "후일자료제출",
"estimate.detail.dragFileGuide": "(※ 북면설치인 경우, 파일 첨부가 필수입니다.)",
"estimate.detail.header.fileList1": "파일첨부", "estimate.detail.header.fileList1": "파일첨부",
"estimate.detail.fileList.btn": "파일선택", "estimate.detail.fileList.btn": "파일선택",
"estimate.detail.fileList.extCheck": "이미지 파일만 첨부 가능합니다.", "estimate.detail.fileList.extCheck": "이미지 파일만 첨부 가능합니다.",
@ -902,12 +908,12 @@
"estimate.detail.showPrice.pricingBtn": "Pricing", "estimate.detail.showPrice.pricingBtn": "Pricing",
"estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. Pricing을 진행해주세요.", "estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. Pricing을 진행해주세요.",
"estimate.detail.showPrice.description1": "제품 가격 OPEN", "estimate.detail.showPrice.description1": "제품 가격 OPEN",
"estimate.detail.showPrice.description2": "추가, 변경 자재", "estimate.detail.showPrice.description2": "추가 변경 자재",
"estimate.detail.showPrice.description3": "첨부필수", "estimate.detail.showPrice.description3": "첨부필수",
"estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인", "estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인",
"estimate.detail.showPrice.addItem": "제품추가", "estimate.detail.showPrice.addItem": "제품추가",
"estimate.detail.showPrice.delItem": "제품삭제", "estimate.detail.showPrice.delItem": "제품삭제",
"estimate.detail.itemTableHeader.dispOrder": "Item", "estimate.detail.itemTableHeader.dispOrder": "No.",
"estimate.detail.itemTableHeader.itemId": "품번", "estimate.detail.itemTableHeader.itemId": "품번",
"estimate.detail.itemTableHeader.itemNo": "형명", "estimate.detail.itemTableHeader.itemNo": "형명",
"estimate.detail.itemTableHeader.amount": "수량", "estimate.detail.itemTableHeader.amount": "수량",
@ -944,9 +950,10 @@
"estimate.detail.productFeaturesPopup.close": "닫기", "estimate.detail.productFeaturesPopup.close": "닫기",
"estimate.detail.productFeaturesPopup.requiredStoreId": "1차 판매점은 필수값 입니다.", "estimate.detail.productFeaturesPopup.requiredStoreId": "1차 판매점은 필수값 입니다.",
"estimate.detail.productFeaturesPopup.requiredReceiveUser": "담당자는 필수값 입니다.", "estimate.detail.productFeaturesPopup.requiredReceiveUser": "담당자는 필수값 입니다.",
"estimate.detail.save.alertMsg": "저장되었습니다. 견적서에서 제품을 변경할 경우, 도면 및 회로에 반영되지 않습니다.", "estimate.detail.save.alertMsg": "저장되었습니다. 견적서에서 제품을 변경할 경우 도면 및 회로에 반영되지 않습니다.",
"estimate.detail.copy.alertMsg": "복사되었습니다.", "estimate.detail.copy.alertMsg": "복사되었습니다.",
"estimate.detail.save.requiredFileUpload": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오.", "estimate.detail.save.requiredFileUpload": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오.",
"estimate.detail.save.requiredNorthArrangementFileUpload": "북면에 모듈을 배치한 경우, 북면배치허가서를 반드시 첨부해야 합니다.",
"estimate.detail.save.requiredItem": "제품은 1개이상 등록해야 됩니다.", "estimate.detail.save.requiredItem": "제품은 1개이상 등록해야 됩니다.",
"estimate.detail.save.requiredCharger": "담당자는 필수값 입니다.", "estimate.detail.save.requiredCharger": "담당자는 필수값 입니다.",
"estimate.detail.save.requiredObjectName": "안건명은 필수값 입니다.", "estimate.detail.save.requiredObjectName": "안건명은 필수값 입니다.",
@ -956,8 +963,8 @@
"estimate.detail.save.requiredAmount": "수량은 0보다 큰값을 입력해주세요.", "estimate.detail.save.requiredAmount": "수량은 0보다 큰값을 입력해주세요.",
"estimate.detail.save.requiredSalePrice": "단가는 0보다 큰값을 입력해주세요.", "estimate.detail.save.requiredSalePrice": "단가는 0보다 큰값을 입력해주세요.",
"estimate.detail.reset.alertMsg": "초기화 되었습니다.", "estimate.detail.reset.alertMsg": "초기화 되었습니다.",
"estimate.detail.reset.confirmMsg": "수기 변경(저장)한 견적 정보가 초기화되고, 최근 저장된 도면정보가 반영됩니다. 정말로 초기화하시겠습니까?", "estimate.detail.reset.confirmMsg": "수기 변경(저장)한 견적 정보가 초기화되고 최근 저장된 도면정보가 반영됩니다. 정말로 초기화하시겠습니까?",
"estimate.detail.lock.alertMsg": "견적서를 [잠금]하면, 수정할 수 없습니다. <br />견적서를 수정하려면 잠금해제를 하십시오.", "estimate.detail.lock.alertMsg": "견적서를 [잠금]하면 수정할 수 없습니다. <br />견적서를 수정하려면 잠금해제를 하십시오.",
"estimate.detail.unlock.alertMsg": "[잠금해제]하면 견적서를 수정할 수 있습니다. <br />해제하시겠습니까?", "estimate.detail.unlock.alertMsg": "[잠금해제]하면 견적서를 수정할 수 있습니다. <br />해제하시겠습니까?",
"estimate.detail.unlock.confirmBtnName": "해제", "estimate.detail.unlock.confirmBtnName": "해제",
"estimate.detail.alert.delFile": "첨부파일을 완전히 삭제하려면 [저장]버튼을 클릭하십시오.", "estimate.detail.alert.delFile": "첨부파일을 완전히 삭제하려면 [저장]버튼을 클릭하십시오.",
@ -983,7 +990,7 @@
"simulator.table.sub9": "예측발전량 (kWh)", "simulator.table.sub9": "예측발전량 (kWh)",
"simulator.notice.sub1": "Hanwha Japan 연간 발전량", "simulator.notice.sub1": "Hanwha Japan 연간 발전량",
"simulator.notice.sub2": "시뮬레이션 안내사항", "simulator.notice.sub2": "시뮬레이션 안내사항",
"simulator.menu.move.valid1": "견적서를 생성한 후에, 발전시뮬레이션 결과를 조회할 수 있습니다.", "simulator.menu.move.valid1": "견적서를 생성한 후에 발전시뮬레이션 결과를 조회할 수 있습니다.",
"master.moduletypeitem.message.error": "지붕재 코드를 입력하세요.", "master.moduletypeitem.message.error": "지붕재 코드를 입력하세요.",
"can.not.move.module": "모듈을 이동할 수 없습니다.", "can.not.move.module": "모듈을 이동할 수 없습니다.",
"can.not.copy.module": "모듈을 복사할 수 없습니다.", "can.not.copy.module": "모듈을 복사할 수 없습니다.",
@ -998,9 +1005,14 @@
"module.place.select.module": "모듈을 선택해주세요.", "module.place.select.module": "모듈을 선택해주세요.",
"module.place.select.one.module": "모듈은 하나만 선택해주세요.", "module.place.select.one.module": "모듈은 하나만 선택해주세요.",
"batch.canvas.delete.all": "배치면 내용을 전부 삭제하시겠습니까?", "batch.canvas.delete.all": "배치면 내용을 전부 삭제하시겠습니까?",
"module.not.found": "설치 모듈을 선택하세요.", "module.not.found": "모듈을 선택하세요.",
"construction.length.difference": "지붕면 공법을 전부 선택해주세요.", "construction.length.difference": "지붕면 공법을 전부 선택해주세요.",
"menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.", "menu.validation.canvas.roof": "패널을 배치하려면 지붕면을 입력해야 합니다.",
"batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.", "batch.object.outside.roof": "오브젝트는 지붕내에 설치해야 합니다.",
"batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치 할 수 없습니다." "batch.object.notinstall.cross": "오브젝트는 겹쳐서 설치 할 수 없습니다.",
"module.not.batch.north": "북쪽에는 모듈을 배치할 수 없습니다.",
"module.trestleDetail.not.exist": "가대 상세 정보가 없습니다.",
"max.select": "최대 {0}개까지 선택할 수 있습니다.",
"module.delete.confirm": "패널을 삭제하고 면입력으로 돌아갑니다. 맞습니까?\n[예]를 선택하면 삭제하고, 면 입력으로 돌아갑니다.\n[아니오]를 선택하면 삭제하지 않고 현재 상태를 유지합니다.",
"not.allocation.exist.module": "할당하지 않은 모듈이 있습니다."
} }

View File

@ -40,7 +40,10 @@ export const moduleStatisticsState = atom({
{ name: `발전량(kW)`, prop: 'amount' }, { name: `발전량(kW)`, prop: 'amount' },
], ],
rows: [], rows: [],
footer: ['합계', '0'], footer: [
{ name: '-', prop: 'name' },
{ name: 0, prop: 'amount' },
],
}, },
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })

23
src/store/estimateAtom.js Normal file
View File

@ -0,0 +1,23 @@
import { atom } from 'recoil'
export const estimateParamAtom = atom({
// 견적서 post parameter
key: 'estimateParamAtom',
default: {
saleStoreId: '',
objectNo: '',
planNo: '',
slope: '',
angle: '',
surfaceType: '',
setupHeight: '',
standardWindSpeedId: '',
snowfall: '',
northArrangement: '',
drawingFlg: '1',
userId: '',
roofSurfaceList: [],
circuitItemList: [],
itemList: [],
},
})

View File

@ -2,7 +2,7 @@ import { atom } from 'recoil'
export const globalLocaleStore = atom({ export const globalLocaleStore = atom({
key: 'globalLocaleState', key: 'globalLocaleState',
default: 'ko', default: 'ja',
}) })
export const appMessageStore = atom({ export const appMessageStore = atom({

View File

@ -64,11 +64,11 @@ export const subMenusState = atom({
name: 'plan.menu.module.circuit.setting.circuit.trestle.setting', name: 'plan.menu.module.circuit.setting.circuit.trestle.setting',
menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING, menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING,
}, },
{ // {
id: 2, // id: 2,
name: 'plan.menu.module.circuit.setting.plan.orientation', // name: 'plan.menu.module.circuit.setting.plan.orientation',
menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION, // menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION,
}, // },
], ],
}, },
}) })

View File

@ -42,7 +42,6 @@ export const moduleSelectionOptionParamsState = atom({
stdWindSpeed: '', stdWindSpeed: '',
stdSnowLd: '', stdSnowLd: '',
inclCd: '', inclCd: '',
roofMatlCd: '',
}, },
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })

View File

@ -792,6 +792,12 @@
} }
// file drag box // file drag box
.drag-file-guide{
font-size: 13px;
font-weight: 400;
color: #45576F;
margin-left: 5px;
}
.drag-file-box{ .drag-file-box{
padding: 10px; padding: 10px;
.btn-area{ .btn-area{

View File

@ -254,7 +254,7 @@
font-weight: 600; font-weight: 600;
margin-bottom: 25px; margin-bottom: 25px;
line-height: 24px; line-height: 24px;
word-break: keep-all; word-break: break-all;
} }
.notice-contents{ .notice-contents{
font-size: 12px; font-size: 12px;

View File

@ -259,6 +259,12 @@ $alert-color: #101010;
border-bottom: 1px solid #424242; border-bottom: 1px solid #424242;
} }
} }
.grid-check-form-block{
display: block;
> div{
margin-bottom: 10px;
}
}
.grid-option-overflow{ .grid-option-overflow{
max-height: 350px; max-height: 350px;
overflow-y: auto; overflow-y: auto;
@ -305,6 +311,25 @@ $alert-color: #101010;
} }
.grid-option-block-form{ .grid-option-block-form{
flex: 1; flex: 1;
.flex-ment{
position: relative;
padding-right: 70px;
flex: 1 1 auto;
span{
width: 70px;
&.absol{
width: fit-content;
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
}
}
.input-grid{
flex: 1;
}
}
} }
} }
.select-form{ .select-form{
@ -312,6 +337,7 @@ $alert-color: #101010;
} }
.grid-select{ .grid-select{
flex: 1; flex: 1;
height: 30px;
&.no-flx{ &.no-flx{
flex: unset; flex: unset;
} }
@ -2013,7 +2039,7 @@ $alert-color: #101010;
} }
} }
.roof-module-tab2-overflow{ .roof-module-tab2-overflow{
max-height: 500px; max-height: 650px;
overflow-y: auto; overflow-y: auto;
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #4D4D4D; border-bottom: 1px solid #4D4D4D;
@ -2088,17 +2114,3 @@ $alert-color: #101010;
justify-content: flex-end; justify-content: flex-end;
} }
} }
.reset-word-wrap{
display: flex;
align-items: center;
.grid-btn-wrap{
margin-left: auto;
}
}
.reset-word{
font-size: 12px;
color: #FFCACA;
font-weight: 400;
margin-top: 10px;
}

View File

@ -535,7 +535,15 @@ input[type=text]{
} }
} }
} }
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
input[type=number] {
-moz-appearance: textfield;
}
// check-btn // check-btn
@ -651,7 +659,7 @@ input[type=text]{
padding-left: 10px; padding-left: 10px;
margin-bottom: 0; margin-bottom: 0;
word-break: break-all; word-break: break-all;
line-height: 1.2; line-height: 1.4;
display: inline; display: inline;
vertical-align: top; vertical-align: top;
color: #fff; color: #fff;
@ -1000,5 +1008,5 @@ input:checked + .slider {
// alert z-index // alert z-index
.swal2-container{ .swal2-container{
z-index: 100000; z-index: 120000;
} }

View File

@ -958,7 +958,10 @@ export const getAllRelatedObjects = (id, canvas) => {
// 모듈,회로 구성에서 사용하는 degree 범위 별 값 // 모듈,회로 구성에서 사용하는 degree 범위 별 값
export const getDegreeInOrientation = (degree) => { export const getDegreeInOrientation = (degree) => {
if (degree >= 352) { if (degree === 180 || degree === -180) {
return 180
}
if (degree >= 180 || degree < -180) {
return 0 return 0
} }
if (degree % 15 === 0) return degree if (degree % 15 === 0) return degree
@ -1032,8 +1035,3 @@ export function calculateVisibleModuleHeight(sourceWidth, sourceHeight, angle, d
height: Number(visibleHeight.toFixed(1)), // 소수점 두 자리로 고정 height: Number(visibleHeight.toFixed(1)), // 소수점 두 자리로 고정
} }
} }
export function getTrestleLength(length, degree) {
const radians = (degree * Math.PI) / 180
return length * Math.cos(radians)
}

View File

@ -130,7 +130,7 @@ export const calculateFlowDirection = (canvasAngle) => {
*/ */
export const getQueryString = (o) => { export const getQueryString = (o) => {
const queryString = Object.keys(o) const queryString = Object.keys(o)
.map((key) => `${key}=${o[key]}`) .map((key) => `${key}=${o[key] ?? ''}`)
.join('&') .join('&')
return `?${queryString}` return `?${queryString}`
} }

View File

@ -248,6 +248,7 @@ export default function offsetPolygon(vertices, offset) {
const arcSegments = 0 const arcSegments = 0
const originPolygon = new QPolygon(vertices, { fontSize: 0 }) const originPolygon = new QPolygon(vertices, { fontSize: 0 })
originPolygon.setViewLengthText(false)
if (offset > 0) { if (offset > 0) {
let result = createMarginPolygon(polygon, offset, arcSegments).vertices let result = createMarginPolygon(polygon, offset, arcSegments).vertices