Compare commits
80 Commits
main
...
feature/qc
| Author | SHA1 | Date | |
|---|---|---|---|
| 25957a37e1 | |||
| 83f0eef9eb | |||
| 46f90aff1f | |||
| 11f69a01bb | |||
| c8f70e0746 | |||
| de5901492b | |||
| 6f5b70342d | |||
| 7b1c9b681e | |||
| 25e8dcc050 | |||
| 3027f47d5d | |||
| 1f723c9ce7 | |||
| 5e9c22a928 | |||
| 54d06f7d51 | |||
| 7f402d5b45 | |||
| 2473cfac17 | |||
| e293d5dfde | |||
| cf9acde872 | |||
| 93b645e9e8 | |||
| 25778a099f | |||
| ba9a49501c | |||
| a2d192084b | |||
| cdaeab1d42 | |||
| 47e3ae7d29 | |||
| 65ec3d5153 | |||
|
|
592275c0de | ||
| 5e27ab282c | |||
| 75549b66b5 | |||
|
|
437d552b3a | ||
| 85d9aca6d3 | |||
|
|
82e3527432 | ||
|
|
7ec9854173 | ||
|
|
b458b4e853 | ||
| 1ba9853a32 | |||
| f1d976521d | |||
| a7ddfacdd2 | |||
| b51dacf421 | |||
| f25dac0ae3 | |||
| c99deaf93f | |||
| 8d65765daf | |||
| 2f8ca712c9 | |||
| f2470b346c | |||
| 1a5f78a970 | |||
| 5979555bcb | |||
| 26047df3c8 | |||
|
|
12936ec1f9 | ||
|
|
1bb92a975e | ||
| f2a083f022 | |||
| 786c35e656 | |||
|
|
88bcf27bfb | ||
|
|
617afb8b1f | ||
|
|
414d6fa0c5 | ||
| 6919dac8f1 | |||
|
|
79d873c135 | ||
|
|
0e8ce8b2e2 | ||
|
|
c4d17d2147 | ||
| e75db5ace1 | |||
| 8848713c72 | |||
| 39d48e61f3 | |||
| e624aa0de0 | |||
| e7410e5373 | |||
| 05dd069e53 | |||
| ac015123cd | |||
| f7fe0f6528 | |||
| 6b76108d8b | |||
|
|
590040fa1d | ||
|
|
325c2c1cc0 | ||
|
|
521bfd4303 | ||
|
|
b136bc213c | ||
| 84e8af50b8 | |||
| 11438773a1 | |||
| 2e762537fc | |||
| 57446fa6d8 | |||
| 1fa02de62f | |||
| 06fa1766d6 | |||
| 63297328ed | |||
| 7c15da2b4c | |||
| 3432d64a3c | |||
| 9be21fc2b2 | |||
|
|
c467fc7fa8 | ||
|
|
f915dab239 |
10
ecosystem.config.js
Normal file
10
ecosystem.config.js
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
module.exports = {
|
||||||
|
apps: [
|
||||||
|
{
|
||||||
|
name: 'qcast-front-production',
|
||||||
|
script: 'npm run start:dev',
|
||||||
|
instance: 2,
|
||||||
|
exec_mode: 'cluster',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
@ -5,7 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev",
|
"dev": "next dev",
|
||||||
"build": "next build",
|
"build": "next build",
|
||||||
"start": "next start -p 5000",
|
"start:cluster1": "next start -p 5000",
|
||||||
|
"start:cluster2": "next start -p 5001",
|
||||||
"start:dev": "next start -p 5010",
|
"start:dev": "next start -p 5010",
|
||||||
"lint": "next lint",
|
"lint": "next lint",
|
||||||
"serve": "node server.js"
|
"serve": "node server.js"
|
||||||
@ -23,7 +24,7 @@
|
|||||||
"js-cookie": "^3.0.5",
|
"js-cookie": "^3.0.5",
|
||||||
"mathjs": "^13.0.2",
|
"mathjs": "^13.0.2",
|
||||||
"mssql": "^11.0.1",
|
"mssql": "^11.0.1",
|
||||||
"next": "14.2.21",
|
"next": "14.2.25",
|
||||||
"next-international": "^1.2.4",
|
"next-international": "^1.2.4",
|
||||||
"react": "^18",
|
"react": "^18",
|
||||||
"react-chartjs-2": "^5.2.0",
|
"react-chartjs-2": "^5.2.0",
|
||||||
|
|||||||
@ -203,6 +203,7 @@ export const SAVE_KEY = [
|
|||||||
'fontWeight',
|
'fontWeight',
|
||||||
'dormerAttributes',
|
'dormerAttributes',
|
||||||
'toFixed',
|
'toFixed',
|
||||||
|
'isSortedPoints',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]
|
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]
|
||||||
|
|||||||
@ -2,26 +2,111 @@
|
|||||||
|
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
import { setSession, login } from '@/lib/authActions'
|
||||||
|
import { sessionStore } from '@/store/commonAtom'
|
||||||
|
import { useRecoilState } from 'recoil'
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { globalLocaleStore } from '@/store/localeAtom'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
|
|
||||||
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
|
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
|
||||||
|
|
||||||
export default function AutoLoginPage() {
|
export default function AutoLoginPage({ autoLoginParam }) {
|
||||||
const [isLoading, setIsLoading] = useState(true)
|
const router = useRouter()
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(autoLoginParam === 'Y' ? false : true)
|
||||||
|
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
|
||||||
|
|
||||||
|
const { promisePost } = useAxios(globalLocaleState)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
const [userId, setUserId] = useState('')
|
||||||
|
const [sessionState, setSessionState] = useRecoilState(sessionStore)
|
||||||
|
|
||||||
|
const [idFocus, setIdFocus] = useState(false)
|
||||||
|
|
||||||
|
const loginProcess = async () => {
|
||||||
|
setIsLoading(true)
|
||||||
|
await promisePost({ url: '/api/login/v1.0/user', data: { loginId: userId } }).then((response) => {
|
||||||
|
setIsLoading(false)
|
||||||
|
if (response.data) {
|
||||||
|
const res = response.data
|
||||||
|
const result = { ...res, storeLvl: res.groupId === '60000' ? '1' : '2', pwdInitYn: 'Y' }
|
||||||
|
setSession(result)
|
||||||
|
setSessionState(result)
|
||||||
|
login()
|
||||||
|
} else {
|
||||||
|
alert(getMessage('login.fail'))
|
||||||
|
router.push('/login?autoLoginParam1=Y')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading && <GlobalSpinner />}
|
{isLoading && <GlobalSpinner />}
|
||||||
<div className="login-input-frame">
|
{autoLoginParam !== 'Y' ? (
|
||||||
<div className="login-frame-tit ">
|
<>
|
||||||
<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>
|
) : (
|
||||||
|
<>
|
||||||
|
<div className="login-input-frame">
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault()
|
||||||
|
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-btn-box">
|
||||||
|
<button type="submit" className="login-btn">
|
||||||
|
{getMessage('login')}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,9 @@ export default function Login() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (autoLoginParam) {
|
if (autoLoginParam) {
|
||||||
autoLoginProcess(autoLoginParam)
|
if (autoLoginParam !== 'Y') {
|
||||||
|
autoLoginProcess(autoLoginParam)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
|
// console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
|
||||||
@ -334,7 +336,7 @@ export default function Login() {
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{autoLoginParam && <AutoLogin />}
|
{autoLoginParam && <AutoLogin autoLoginParam={autoLoginParam} />}
|
||||||
</div>
|
</div>
|
||||||
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
|
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -6,29 +6,19 @@ import { contextMenuListState, contextMenuState } from '@/store/contextMenu'
|
|||||||
import { useTempGrid } from '@/hooks/useTempGrid'
|
import { useTempGrid } from '@/hooks/useTempGrid'
|
||||||
import { useContextMenu } from '@/hooks/useContextMenu'
|
import { useContextMenu } from '@/hooks/useContextMenu'
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState, currentObjectState } from '@/store/canvasAtom'
|
||||||
|
|
||||||
export default function QContextMenu(props) {
|
export default function QContextMenu(props) {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const { contextRef, canvasProps } = props
|
const { contextRef, canvasProps } = props
|
||||||
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState)
|
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState)
|
||||||
const contextMenuList = useRecoilValue(contextMenuListState)
|
const contextMenuList = useRecoilValue(contextMenuListState)
|
||||||
const activeObject = canvasProps?.getActiveObject() //액티브된 객체를 가져옴
|
const currentObject = useRecoilValue(currentObjectState)
|
||||||
const { tempGridMode, setTempGridMode } = useTempGrid()
|
const { tempGridMode, setTempGridMode } = useTempGrid()
|
||||||
const { handleKeyup } = useContextMenu()
|
const { handleKeyup } = useContextMenu()
|
||||||
const { addDocumentEventListener, removeDocumentEvent } = useEvent()
|
const { addDocumentEventListener, removeDocumentEvent } = useEvent()
|
||||||
// const { addDocumentEventListener, removeDocumentEvent } = useContext(EventContext)
|
// const { addDocumentEventListener, removeDocumentEvent } = useContext(EventContext)
|
||||||
|
|
||||||
let contextType = ''
|
|
||||||
|
|
||||||
if (activeObject) {
|
|
||||||
if (activeObject.initOptions && activeObject.initOptions.name) {
|
|
||||||
//이건 바뀔 가능성이 있음
|
|
||||||
if (activeObject.initOptions?.name?.indexOf('guide') > -1) {
|
|
||||||
contextType = 'surface' //면형상
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const getYPosition = (e) => {
|
const getYPosition = (e) => {
|
||||||
const contextLength = contextMenuList.reduce((acc, cur, index) => {
|
const contextLength = contextMenuList.reduce((acc, cur, index) => {
|
||||||
return acc + cur.length
|
return acc + cur.length
|
||||||
@ -36,11 +26,13 @@ export default function QContextMenu(props) {
|
|||||||
return e?.clientY - (contextLength * 25 + contextMenuList.length * 2 * 17)
|
return e?.clientY - (contextLength * 25 + contextMenuList.length * 2 * 17)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
const handleContextMenu = (e) => {
|
||||||
if (!contextRef.current) return
|
// e.preventDefault() //기존 contextmenu 막고
|
||||||
|
|
||||||
|
if (currentObject) {
|
||||||
|
const isArray = currentObject.hasOwnProperty('arrayData')
|
||||||
|
if (isArray && currentObject.arrayData.length === 0) return
|
||||||
|
|
||||||
const handleContextMenu = (e) => {
|
|
||||||
e.preventDefault() //기존 contextmenu 막고
|
|
||||||
if (tempGridMode) return
|
if (tempGridMode) return
|
||||||
const position = {
|
const position = {
|
||||||
x: window.innerWidth / 2 < e.pageX ? e.pageX - 240 : e.pageX,
|
x: window.innerWidth / 2 < e.pageX ? e.pageX - 240 : e.pageX,
|
||||||
@ -48,21 +40,24 @@ export default function QContextMenu(props) {
|
|||||||
}
|
}
|
||||||
setContextMenu({ visible: true, ...position, currentMousePos: canvasProps.getPointer(e) })
|
setContextMenu({ visible: true, ...position, currentMousePos: canvasProps.getPointer(e) })
|
||||||
addDocumentEventListener('keyup', document, handleKeyup)
|
addDocumentEventListener('keyup', document, handleKeyup)
|
||||||
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //한번 노출 후 이벤트 삭제
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleClick = (e) => {
|
const handleClick = (e) => {
|
||||||
// e.preventDefault()
|
// e.preventDefault()
|
||||||
|
setContextMenu({ ...contextMenu, visible: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleOutsideClick = (e) => {
|
||||||
|
// e.preventDefault()
|
||||||
|
if (contextMenu.visible) {
|
||||||
setContextMenu({ ...contextMenu, visible: false })
|
setContextMenu({ ...contextMenu, visible: false })
|
||||||
|
removeDocumentEvent('keyup')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleOutsideClick = (e) => {
|
useEffect(() => {
|
||||||
// e.preventDefault()
|
if (!contextRef.current) return
|
||||||
if (contextMenu.visible) {
|
|
||||||
setContextMenu({ ...contextMenu, visible: false })
|
|
||||||
removeDocumentEvent('keyup')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
canvasProps?.upperCanvasEl.addEventListener('contextmenu', handleContextMenu)
|
canvasProps?.upperCanvasEl.addEventListener('contextmenu', handleContextMenu)
|
||||||
document.addEventListener('click', handleClick)
|
document.addEventListener('click', handleClick)
|
||||||
@ -72,43 +67,9 @@ export default function QContextMenu(props) {
|
|||||||
removeDocumentEvent('keyup')
|
removeDocumentEvent('keyup')
|
||||||
document.removeEventListener('click', handleClick)
|
document.removeEventListener('click', handleClick)
|
||||||
document.removeEventListener('click', handleOutsideClick)
|
document.removeEventListener('click', handleOutsideClick)
|
||||||
|
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //한번 노출 후 이벤트 삭제
|
||||||
}
|
}
|
||||||
}, [contextRef, contextMenuList])
|
}, [contextRef, contextMenuList, currentObject])
|
||||||
|
|
||||||
const handleObjectMove = () => {
|
|
||||||
activeObject.set({
|
|
||||||
lockMovementX: false, // X 축 이동 잠금
|
|
||||||
lockMovementY: false, // Y 축 이동 잠금
|
|
||||||
})
|
|
||||||
|
|
||||||
canvasProps?.on('object:modified', function (e) {
|
|
||||||
activeObject.set({
|
|
||||||
lockMovementX: true, // X 축 이동 잠금
|
|
||||||
lockMovementY: true, // Y 축 이동 잠금
|
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleObjectDelete = () => {
|
|
||||||
if (confirm('삭제하실거?')) {
|
|
||||||
canvasProps.remove(activeObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleObjectCopy = () => {
|
|
||||||
activeObject.clone((cloned) => {
|
|
||||||
cloned.set({
|
|
||||||
left: activeObject.left + activeObject.width + 20,
|
|
||||||
initOptions: { ...activeObject.initOptions },
|
|
||||||
lockMovementX: true, // X 축 이동 잠금
|
|
||||||
lockMovementY: true, // Y 축 이동 잠금
|
|
||||||
lockRotation: true, // 회전 잠금
|
|
||||||
lockScalingX: true, // X 축 크기 조정 잠금
|
|
||||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
|
||||||
})
|
|
||||||
canvasProps?.add(cloned)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@ -87,7 +87,7 @@ export default function QSelectBox({
|
|||||||
<ul className="select-item-wrap">
|
<ul className="select-item-wrap">
|
||||||
{options?.length > 0 &&
|
{options?.length > 0 &&
|
||||||
options?.map((option, index) => (
|
options?.map((option, index) => (
|
||||||
<li key={option.id || index} className="select-item" onClick={() => handleClickSelectOption(option)}>
|
<li key={option.id + '_' + index} className="select-item" onClick={() => handleClickSelectOption(option)}>
|
||||||
<button key={option.id + 'btn'}>{showKey !== '' ? option[showKey] : option.name}</button>
|
<button key={option.id + 'btn'}>{showKey !== '' ? option[showKey] : option.name}</button>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -175,7 +175,10 @@ export default function Estimate({}) {
|
|||||||
row.check = false
|
row.check = false
|
||||||
estimateOption.map((row2) => {
|
estimateOption.map((row2) => {
|
||||||
if (row.pkgYn === '0') {
|
if (row.pkgYn === '0') {
|
||||||
if (row2 === row.code) {
|
// if (row2 === row.code) {
|
||||||
|
// row.check = true
|
||||||
|
// }
|
||||||
|
if (row.code.split('、').includes(row2)) {
|
||||||
row.check = true
|
row.check = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -217,7 +220,10 @@ export default function Estimate({}) {
|
|||||||
row.check = false
|
row.check = false
|
||||||
estimateOption.map((row2) => {
|
estimateOption.map((row2) => {
|
||||||
if (row.pkgYn === '0') {
|
if (row.pkgYn === '0') {
|
||||||
if (row2 === row.code) {
|
// if (row2 === row.code) {
|
||||||
|
// row.check = true
|
||||||
|
// }
|
||||||
|
if (row.code.split('、').includes(row2)) {
|
||||||
row.check = true
|
row.check = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -240,7 +246,6 @@ export default function Estimate({}) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
setSpecialNoteList(res)
|
setSpecialNoteList(res)
|
||||||
|
|
||||||
setSpecialNoteFirstFlg(true)
|
setSpecialNoteFirstFlg(true)
|
||||||
@ -377,8 +382,8 @@ export default function Estimate({}) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (estimateContextState.estimateType !== '') {
|
if (estimateContextState.estimateType !== '') {
|
||||||
const param = {
|
const param = {
|
||||||
saleStoreId: session.storeId,
|
saleStoreId: estimateContextState.sapSaleStoreId,
|
||||||
sapSalesStoreCd: session.custCd,
|
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
|
||||||
docTpCd: estimateContextState?.estimateType,
|
docTpCd: estimateContextState?.estimateType,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,6 +392,8 @@ export default function Estimate({}) {
|
|||||||
if (isNotEmptyArray(res?.data)) {
|
if (isNotEmptyArray(res?.data)) {
|
||||||
setStorePriceList(res.data)
|
setStorePriceList(res.data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setItemChangeYn(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
if (estimateContextState.estimateType === 'YJSS') {
|
if (estimateContextState.estimateType === 'YJSS') {
|
||||||
@ -416,8 +423,6 @@ export default function Estimate({}) {
|
|||||||
handlePricing('UNIT_PRICE')
|
handlePricing('UNIT_PRICE')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setItemChangeYn(true)
|
|
||||||
}
|
}
|
||||||
}, [estimateContextState?.estimateType])
|
}, [estimateContextState?.estimateType])
|
||||||
|
|
||||||
@ -469,6 +474,21 @@ export default function Estimate({}) {
|
|||||||
} else {
|
} else {
|
||||||
item.check = false
|
item.check = false
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let codes = item.code.split('、')
|
||||||
|
let flg = '0'
|
||||||
|
if (codes.length > 1) {
|
||||||
|
for (let i = 0; i < pushData.length; i++) {
|
||||||
|
if (codes.indexOf(pushData[i]) > -1) {
|
||||||
|
flg = '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (flg === '1') {
|
||||||
|
item.check = true
|
||||||
|
} else {
|
||||||
|
item.check = false
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -481,8 +501,8 @@ export default function Estimate({}) {
|
|||||||
//Pricing 버튼
|
//Pricing 버튼
|
||||||
const handlePricing = async (showPriceCd) => {
|
const handlePricing = async (showPriceCd) => {
|
||||||
const param = {
|
const param = {
|
||||||
saleStoreId: session.storeId,
|
saleStoreId: estimateContextState.sapSaleStoreId,
|
||||||
sapSalesStoreCd: session.custCd,
|
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
|
||||||
docTpCd: estimateContextState.estimateType,
|
docTpCd: estimateContextState.estimateType,
|
||||||
priceCd: showPriceCd,
|
priceCd: showPriceCd,
|
||||||
itemIdList: estimateContextState.itemList.filter((item) => item.delFlg === '0' && item.paDispOrder === null),
|
itemIdList: estimateContextState.itemList.filter((item) => item.delFlg === '0' && item.paDispOrder === null),
|
||||||
@ -506,7 +526,6 @@ export default function Estimate({}) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsGlobalLoading(true)
|
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 = []
|
||||||
@ -1342,7 +1361,12 @@ export default function Estimate({}) {
|
|||||||
</th>
|
</th>
|
||||||
<td colSpan={3}>
|
<td colSpan={3}>
|
||||||
<div className="radio-wrap">
|
<div className="radio-wrap">
|
||||||
<div className="d-check-radio light mr10">
|
{/*pkgRank is null, empty 인 경우 : 사용불가, 이전에 등록된 경우 사용가능, style로 제어*/}
|
||||||
|
<div className="d-check-radio light mr10" style={{display:
|
||||||
|
(isNotEmptyArray(storePriceList) > 0
|
||||||
|
&& storePriceList[0].pkgRank !== null
|
||||||
|
&& storePriceList[0].pkgRank !== ''
|
||||||
|
|| estimateContextState?.estimateType === 'YJSS') ? "" : "none"}}>
|
||||||
<input
|
<input
|
||||||
type="radio"
|
type="radio"
|
||||||
name="estimateType"
|
name="estimateType"
|
||||||
|
|||||||
@ -45,8 +45,11 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
options.sort = options.sort ?? true
|
options.sort = options.sort ?? true
|
||||||
options.parentId = options.parentId ?? null
|
options.parentId = options.parentId ?? null
|
||||||
|
|
||||||
|
this.isSortedPoints = false
|
||||||
|
|
||||||
if (!options.sort && points.length <= 8) {
|
if (!options.sort && points.length <= 8) {
|
||||||
points = sortedPointLessEightPoint(points)
|
points = sortedPointLessEightPoint(points)
|
||||||
|
this.isSortedPoints = true
|
||||||
} else {
|
} else {
|
||||||
let isDiagonal = false
|
let isDiagonal = false
|
||||||
points.forEach((point, i) => {
|
points.forEach((point, i) => {
|
||||||
@ -62,6 +65,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
|
|
||||||
if (!isDiagonal) {
|
if (!isDiagonal) {
|
||||||
points = sortedPoints(points)
|
points = sortedPoints(points)
|
||||||
|
this.isSortedPoints = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -119,10 +123,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
this.addLengthText()
|
this.addLengthText()
|
||||||
|
|
||||||
this.on('moving', () => {
|
this.on('moving', () => {
|
||||||
|
this.initLines()
|
||||||
this.addLengthText()
|
this.addLengthText()
|
||||||
})
|
})
|
||||||
|
|
||||||
this.on('modified', (e) => {
|
this.on('modified', (e) => {
|
||||||
|
this.initLines()
|
||||||
this.addLengthText()
|
this.addLengthText()
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -183,8 +189,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
|
|
||||||
this.lines = []
|
this.lines = []
|
||||||
|
|
||||||
this.points.forEach((point, i) => {
|
this.getCurrentPoints().forEach((point, i) => {
|
||||||
const nextPoint = this.points[(i + 1) % this.points.length]
|
const nextPoint = this.getCurrentPoints()[(i + 1) % this.points.length]
|
||||||
const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
|
const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
|
||||||
stroke: this.stroke,
|
stroke: this.stroke,
|
||||||
strokeWidth: this.strokeWidth,
|
strokeWidth: this.strokeWidth,
|
||||||
|
|||||||
@ -30,11 +30,14 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
|||||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
import { useEvent } from '@/hooks/useEvent'
|
||||||
import { compasDegAtom } from '@/store/orientationAtom'
|
import { compasDegAtom } from '@/store/orientationAtom'
|
||||||
|
import { hotkeyStore } from '@/store/hotkeyAtom'
|
||||||
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
|
||||||
export default function CanvasFrame() {
|
export default function CanvasFrame() {
|
||||||
const canvasRef = useRef(null)
|
const canvasRef = useRef(null)
|
||||||
const { canvas } = useCanvas('canvas')
|
const { canvas } = useCanvas('canvas')
|
||||||
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
||||||
|
const { closeAll } = usePopup()
|
||||||
const currentMenu = useRecoilValue(currentMenuState)
|
const currentMenu = useRecoilValue(currentMenuState)
|
||||||
const { floorPlanState } = useContext(FloorPlanContext)
|
const { floorPlanState } = useContext(FloorPlanContext)
|
||||||
const { contextMenu, handleClick } = useContextMenu()
|
const { contextMenu, handleClick } = useContextMenu()
|
||||||
@ -92,6 +95,8 @@ export default function CanvasFrame() {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
|
// 혹시 모를 팝업이 떠있는 경우 닫고 시작한다.
|
||||||
|
closeAll()
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
canvas?.clear()
|
canvas?.clear()
|
||||||
@ -110,6 +115,38 @@ export default function CanvasFrame() {
|
|||||||
resetPcsCheckState()
|
resetPcsCheckState()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 캔버스가 있을 경우 핫키 이벤트 처리
|
||||||
|
* hotkeyStore에 핫키 이벤트 리스너 추가
|
||||||
|
*
|
||||||
|
* const hotkeys = [
|
||||||
|
{ key: 'c', fn: () => asdf() },
|
||||||
|
{ key: 'v', fn: () => qwer() },
|
||||||
|
]
|
||||||
|
setHotkeyStore(hotkeys)
|
||||||
|
*/
|
||||||
|
const hotkeyState = useRecoilValue(hotkeyStore)
|
||||||
|
const hotkeyHandlerRef = useRef(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
hotkeyHandlerRef.current = (e) => {
|
||||||
|
hotkeyState.forEach((hotkey) => {
|
||||||
|
if (e.key === hotkey.key) {
|
||||||
|
hotkey.fn()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('keyup', hotkeyHandlerRef.current)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (hotkeyHandlerRef.current) {
|
||||||
|
document.removeEventListener('keyup', hotkeyHandlerRef.current)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [hotkeyState])
|
||||||
|
/** 핫키 이벤트 처리 끝 */
|
||||||
|
|
||||||
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>
|
||||||
|
|||||||
@ -634,7 +634,7 @@ export default function CanvasMenu(props) {
|
|||||||
onClick={() => setEstimatePopupOpen(true)}
|
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.docDownload')}</span>
|
||||||
</button>
|
</button>
|
||||||
<button type="button" style={{ display: saveButtonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
<button type="button" style={{ display: saveButtonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||||
<span className="ico ico02"></span>
|
<span className="ico ico02"></span>
|
||||||
|
|||||||
@ -479,7 +479,7 @@ export default function CircuitTrestleSetting({ id }) {
|
|||||||
console.log(stepUpListData)
|
console.log(stepUpListData)
|
||||||
stepUpListData[0].pcsItemList.map((item, index) => {
|
stepUpListData[0].pcsItemList.map((item, index) => {
|
||||||
return item.serQtyList
|
return item.serQtyList
|
||||||
.filter((serQty) => serQty.selected)
|
.filter((serQty) => serQty.selected && serQty.paralQty > 0)
|
||||||
.forEach((serQty) => {
|
.forEach((serQty) => {
|
||||||
pcs.push({
|
pcs.push({
|
||||||
pcsMkrCd: item.pcsMkrCd,
|
pcsMkrCd: item.pcsMkrCd,
|
||||||
|
|||||||
@ -110,6 +110,7 @@ export default function PowerConditionalSelect(props) {
|
|||||||
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : false,
|
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : false,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
setSelectedModels([])
|
||||||
}
|
}
|
||||||
setSeries(copySeries)
|
setSeries(copySeries)
|
||||||
handleSetmodels(copySeries.filter((s) => s.selected))
|
handleSetmodels(copySeries.filter((s) => s.selected))
|
||||||
|
|||||||
@ -573,7 +573,7 @@ export default function StepUp(props) {
|
|||||||
value={seletedMainOption}
|
value={seletedMainOption}
|
||||||
sourceKey="code"
|
sourceKey="code"
|
||||||
targetKey="code"
|
targetKey="code"
|
||||||
showKey="name"
|
showKey={`${globalLocale === 'ja' ? 'nameJp' : 'name'}`}
|
||||||
onChange={(e) => setSeletedMainOption(e)}
|
onChange={(e) => setSeletedMainOption(e)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
@ -586,7 +586,7 @@ export default function StepUp(props) {
|
|||||||
value={seletedSubOption}
|
value={seletedSubOption}
|
||||||
sourceKey="code"
|
sourceKey="code"
|
||||||
targetKey="code"
|
targetKey="code"
|
||||||
showKey="name"
|
showKey={`${globalLocale === 'ja' ? 'nameJp' : 'name'}`}
|
||||||
onChange={(e) => setSeletedSubOption(e)}
|
onChange={(e) => setSeletedSubOption(e)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import { useMessage } from '@/hooks/useMessage'
|
|||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
|
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
|
||||||
|
|
||||||
const FLOW_DIRECTION_TYPE = {
|
const FLOW_DIRECTION_TYPE = {
|
||||||
EIGHT_AZIMUTH: 'eightAzimuth',
|
EIGHT_AZIMUTH: 'eightAzimuth',
|
||||||
@ -19,6 +20,8 @@ export default function FlowDirectionSetting(props) {
|
|||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
|
const { changeSurfaceLineType } = useSurfaceShapeBatch({})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
return () => {
|
return () => {
|
||||||
canvas?.discardActiveObject()
|
canvas?.discardActiveObject()
|
||||||
@ -53,6 +56,7 @@ export default function FlowDirectionSetting(props) {
|
|||||||
})
|
})
|
||||||
drawDirectionArrow(roof)
|
drawDirectionArrow(roof)
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
|
changeSurfaceLineType(roof)
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
|
|||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
import { canvasState } from '@/store/canvasAtom'
|
import { canvasState } from '@/store/canvasAtom'
|
||||||
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
||||||
|
import { usePlan } from '@/hooks/usePlan'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 지붕 레이아웃
|
* 지붕 레이아웃
|
||||||
@ -45,6 +46,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
|
|||||||
const { setSurfaceShapePattern } = useRoofFn()
|
const { setSurfaceShapePattern } = useRoofFn()
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
||||||
|
const { saveCanvas } = usePlan()
|
||||||
|
|
||||||
const roofRef = {
|
const roofRef = {
|
||||||
roofCd: useRef(null),
|
roofCd: useRef(null),
|
||||||
@ -205,7 +207,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
|
|||||||
/**
|
/**
|
||||||
* 배치면초기설정 저장 버튼 클릭
|
* 배치면초기설정 저장 버튼 클릭
|
||||||
*/
|
*/
|
||||||
const handleSaveBtn = () => {
|
const handleSaveBtn = async () => {
|
||||||
const roofInfo = {
|
const roofInfo = {
|
||||||
...currentRoof,
|
...currentRoof,
|
||||||
planNo: basicSetting.planNo,
|
planNo: basicSetting.planNo,
|
||||||
@ -254,6 +256,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
|
|||||||
|
|
||||||
/* 저장 후 화면 닫기 */
|
/* 저장 후 화면 닫기 */
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
|
await saveCanvas(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -271,7 +274,11 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<th>{getMessage('modal.placement.initial.setting.plan.drawing')}</th>
|
<th>{getMessage('modal.placement.initial.setting.plan.drawing')}</th>
|
||||||
<td>{getMessage('modal.placement.initial.setting.plan.drawing.size.stuff')}</td>
|
<td>
|
||||||
|
{getMessage('modal.placement.initial.setting.plan.drawing.size.stuff')}
|
||||||
|
|
||||||
|
{getMessage('modal.placement.initial.setting.plan.drawing.only.number')}
|
||||||
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>
|
||||||
|
|||||||
@ -1033,8 +1033,7 @@ export default function StuffDetail() {
|
|||||||
const _saleStoreId = watch('saleStoreId')
|
const _saleStoreId = watch('saleStoreId')
|
||||||
// 2차 판매점명
|
// 2차 판매점명
|
||||||
const _otherSaleStoreId = watch('otherSaleStoreId')
|
const _otherSaleStoreId = watch('otherSaleStoreId')
|
||||||
// zipNo: '', //우편번호
|
// zipNo: '', //우편번호 필수값제거 #947
|
||||||
const _zipNo = watch('zipNo')
|
|
||||||
// prefId: '', //도도부현
|
// prefId: '', //도도부현
|
||||||
const _prefId = watch('prefId')
|
const _prefId = watch('prefId')
|
||||||
// address: '', //주소
|
// address: '', //주소
|
||||||
@ -1071,10 +1070,6 @@ export default function StuffDetail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formData.zipNo) {
|
|
||||||
errors.zipNo = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.prefId) {
|
if (!formData.prefId) {
|
||||||
errors.prefId = true
|
errors.prefId = true
|
||||||
}
|
}
|
||||||
@ -1115,10 +1110,6 @@ export default function StuffDetail() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!formData.zipNo) {
|
|
||||||
errors.zipNo = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!formData.prefId || formData.prefId === '0') {
|
if (!formData.prefId || formData.prefId === '0') {
|
||||||
errors.prefId = true
|
errors.prefId = true
|
||||||
}
|
}
|
||||||
@ -1144,7 +1135,6 @@ export default function StuffDetail() {
|
|||||||
_objectName,
|
_objectName,
|
||||||
_saleStoreId,
|
_saleStoreId,
|
||||||
_otherSaleStoreId,
|
_otherSaleStoreId,
|
||||||
_zipNo,
|
|
||||||
_prefId,
|
_prefId,
|
||||||
_address,
|
_address,
|
||||||
_areaId,
|
_areaId,
|
||||||
@ -1189,6 +1179,14 @@ export default function StuffDetail() {
|
|||||||
}
|
}
|
||||||
}, [prefValue])
|
}, [prefValue])
|
||||||
|
|
||||||
|
// 도도부현 /주소 disabled제거 변경
|
||||||
|
const onChangePrefCode = (e) => {
|
||||||
|
setPrefValue(e.prefId)
|
||||||
|
|
||||||
|
form.setValue('prefId', e.prefId)
|
||||||
|
form.setValue('prefName', e.prefName)
|
||||||
|
}
|
||||||
|
|
||||||
// 발전량 시뮬레이션 변경
|
// 발전량 시뮬레이션 변경
|
||||||
const handleAreaIdOnChange = (e) => {
|
const handleAreaIdOnChange = (e) => {
|
||||||
form.setValue('areaId', e.areaId)
|
form.setValue('areaId', e.areaId)
|
||||||
@ -1243,12 +1241,6 @@ export default function StuffDetail() {
|
|||||||
errors = fieldNm
|
errors = fieldNm
|
||||||
}
|
}
|
||||||
|
|
||||||
//우편번호
|
|
||||||
if (!formData.zipNo) {
|
|
||||||
fieldNm = getMessage('stuff.detail.zipNo')
|
|
||||||
errors = fieldNm
|
|
||||||
}
|
|
||||||
|
|
||||||
//1차판매점명
|
//1차판매점명
|
||||||
if (!formData.saleStoreId) {
|
if (!formData.saleStoreId) {
|
||||||
fieldNm = getMessage('stuff.detail.saleStoreId')
|
fieldNm = getMessage('stuff.detail.saleStoreId')
|
||||||
@ -1558,7 +1550,7 @@ export default function StuffDetail() {
|
|||||||
type: 'alert',
|
type: 'alert',
|
||||||
icon: 'error',
|
icon: 'error',
|
||||||
})
|
})
|
||||||
console.log('error::::::', error)
|
console.error('error::::::', error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2004,9 +1996,7 @@ export default function StuffDetail() {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>{getMessage('stuff.detail.zipNo')}</th>
|
||||||
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
|
|
||||||
</th>
|
|
||||||
<td>
|
<td>
|
||||||
<div className="flx-box">
|
<div className="flx-box">
|
||||||
<div className="input-wrap mr5" style={{ width: '200px' }}>
|
<div className="input-wrap mr5" style={{ width: '200px' }}>
|
||||||
@ -2038,10 +2028,10 @@ export default function StuffDetail() {
|
|||||||
getOptionLabel={(x) => x.prefName}
|
getOptionLabel={(x) => x.prefName}
|
||||||
getOptionValue={(x) => x.prefId}
|
getOptionValue={(x) => x.prefId}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
|
onChange={onChangePrefCode}
|
||||||
value={prefCodeList.filter(function (option) {
|
value={prefCodeList.filter(function (option) {
|
||||||
return option.prefId === prefValue
|
return option.prefId === prefValue
|
||||||
})}
|
})}
|
||||||
isDisabled={true}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@ -2571,9 +2561,7 @@ export default function StuffDetail() {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>
|
<th>{getMessage('stuff.detail.zipNo')}</th>
|
||||||
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
|
|
||||||
</th>
|
|
||||||
<td>
|
<td>
|
||||||
<div className="flx-box">
|
<div className="flx-box">
|
||||||
<div className="input-wrap mr5" style={{ width: '200px' }}>
|
<div className="input-wrap mr5" style={{ width: '200px' }}>
|
||||||
@ -2606,10 +2594,10 @@ export default function StuffDetail() {
|
|||||||
getOptionLabel={(x) => x.prefName}
|
getOptionLabel={(x) => x.prefName}
|
||||||
getOptionValue={(x) => x.prefId}
|
getOptionValue={(x) => x.prefId}
|
||||||
isSearchable={false}
|
isSearchable={false}
|
||||||
|
onChange={onChangePrefCode}
|
||||||
value={prefCodeList.filter(function (option) {
|
value={prefCodeList.filter(function (option) {
|
||||||
return option.prefId === prefValue
|
return option.prefId === prefValue
|
||||||
})}
|
})}
|
||||||
isDisabled={true}
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -136,7 +136,7 @@ export const useEstimateController = (planNo, flag) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setEstimateData({ ...estimateContextState, userId: session.userId, sapSalesStoreCd: session.custCd })
|
setEstimateData({ ...estimateContextState, userId: session.userId })
|
||||||
}, [estimateContextState])
|
}, [estimateContextState])
|
||||||
|
|
||||||
// 첨부파일 다운로드
|
// 첨부파일 다운로드
|
||||||
@ -452,8 +452,6 @@ export const useEstimateController = (planNo, flag) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const params = {
|
const params = {
|
||||||
saleStoreId: session.storeId,
|
|
||||||
sapSalesStoreCd: session.custCd,
|
|
||||||
objectNo: estimateData.objectNo,
|
objectNo: estimateData.objectNo,
|
||||||
planNo: sendPlanNo,
|
planNo: sendPlanNo,
|
||||||
copySaleStoreId: otherSaleStoreId ? otherSaleStoreId : saleStoreId,
|
copySaleStoreId: otherSaleStoreId ? otherSaleStoreId : saleStoreId,
|
||||||
@ -462,24 +460,30 @@ export const useEstimateController = (planNo, flag) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setIsGlobalLoading(true)
|
setIsGlobalLoading(true)
|
||||||
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params }).then((res) => {
|
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params })
|
||||||
setIsGlobalLoading(false)
|
.then((res) => {
|
||||||
if (res.status === 201) {
|
|
||||||
if (isObjectNotEmpty(res.data)) {
|
|
||||||
let newObjectNo = res.data.objectNo
|
|
||||||
swalFire({
|
|
||||||
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
|
|
||||||
type: 'alert',
|
|
||||||
confirmFn: () => {
|
|
||||||
setEstimateCopyPopupOpen(false) //팝업닫고
|
|
||||||
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
setIsGlobalLoading(false)
|
setIsGlobalLoading(false)
|
||||||
}
|
if (res.status === 201) {
|
||||||
})
|
if (isObjectNotEmpty(res.data)) {
|
||||||
|
let newObjectNo = res.data.objectNo
|
||||||
|
swalFire({
|
||||||
|
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
|
||||||
|
type: 'alert',
|
||||||
|
confirmFn: () => {
|
||||||
|
setEstimateCopyPopupOpen(false) //팝업닫고
|
||||||
|
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch((e) => {
|
||||||
|
console.error('캔버스 복사 중 오류 발생')
|
||||||
|
swalFire({ text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessageError'), type: 'alert', icon: 'error' })
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkLength = (value) => {
|
const checkLength = (value) => {
|
||||||
|
|||||||
@ -549,6 +549,7 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
* 스냅기능
|
* 스냅기능
|
||||||
*/
|
*/
|
||||||
let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40
|
let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40
|
||||||
|
let sideSnapDistance = 15
|
||||||
let trestleSnapDistance = 15
|
let trestleSnapDistance = 15
|
||||||
|
|
||||||
let intvHor =
|
let intvHor =
|
||||||
@ -588,51 +589,102 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
const holdCellCenterX = holdCellLeft + toFixedWithoutRounding(cell.width / 2, 2)
|
const holdCellCenterX = holdCellLeft + toFixedWithoutRounding(cell.width / 2, 2)
|
||||||
const holdCellCenterY = holdCellTop + toFixedWithoutRounding(cell.height / 2, 2)
|
const holdCellCenterY = holdCellTop + toFixedWithoutRounding(cell.height / 2, 2)
|
||||||
|
|
||||||
|
//흐름방향따라 달라야 한다.
|
||||||
|
if (flowDirection === 'south' || flowDirection === 'north') {
|
||||||
|
if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) {
|
||||||
|
//움직이는 모듈 가운데 -> 설치 모듈 가운데
|
||||||
|
tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
//움직이는 모듈왼쪽 -> 가운데
|
||||||
|
if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) {
|
||||||
|
tempModule.left = holdCellCenterX + intvHor / 2
|
||||||
|
}
|
||||||
|
// 오른쪽 -> 가운데
|
||||||
|
if (Math.abs(smallRight - holdCellCenterX) < snapDistance) {
|
||||||
|
tempModule.left = holdCellCenterX - width - intvHor / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 좌측에 스냅
|
||||||
|
if (Math.abs(smallRight - holdCellLeft) < snapDistance) {
|
||||||
|
// console.log('모듈 좌측 스냅')
|
||||||
|
tempModule.left = holdCellLeft - width - intvHor
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 우측에 스냅
|
||||||
|
if (Math.abs(smallLeft - holdCellRight) < snapDistance) {
|
||||||
|
// console.log('모듈 우측 스냅')
|
||||||
|
tempModule.left = holdCellRight + intvHor
|
||||||
|
}
|
||||||
|
//설치된 셀에 위쪽에 스냅
|
||||||
|
if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellTop - height - intvVer
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 밑쪽에 스냅
|
||||||
|
if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellBottom + intvVer
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 윗쪽에 스냅
|
||||||
|
if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellTop
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//흐름방향 west, east
|
||||||
|
|
||||||
|
//가운데 가운데
|
||||||
|
if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) {
|
||||||
|
tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
//위쪽 -> 가운데
|
||||||
|
if (Math.abs(smallTop - holdCellCenterY) < snapDistance) {
|
||||||
|
// console.log('holdCellCenterX', holdCellCenterX)
|
||||||
|
// console.log('smallLeft', smallLeft)
|
||||||
|
|
||||||
|
// console.log('모듈 센터에 스냅')
|
||||||
|
tempModule.top = holdCellCenterY + intvHor / 2
|
||||||
|
|
||||||
|
// console.log('tempModule.left', tempModule.left)
|
||||||
|
}
|
||||||
|
// 밑 -> 가운데
|
||||||
|
if (Math.abs(smallBottom - holdCellCenterY) < snapDistance) {
|
||||||
|
tempModule.top = holdCellCenterY - height - intvHor / 2
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 좌측에 스냅
|
||||||
|
if (Math.abs(smallRight - holdCellLeft) < snapDistance) {
|
||||||
|
// console.log('모듈 좌측 스냅')
|
||||||
|
tempModule.left = holdCellLeft - width - intvHor
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 우측에 스냅
|
||||||
|
if (Math.abs(smallLeft - holdCellRight) < snapDistance) {
|
||||||
|
// console.log('모듈 우측 스냅')
|
||||||
|
tempModule.left = holdCellRight + intvHor
|
||||||
|
}
|
||||||
|
//설치된 셀에 위쪽에 스냅
|
||||||
|
if (Math.abs(smallBottom - holdCellTop) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellTop - height - intvVer
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 밑쪽에 스냅
|
||||||
|
if (Math.abs(smallTop - holdCellBottom) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellBottom + intvVer
|
||||||
|
}
|
||||||
|
|
||||||
|
//설치된 셀에 윗쪽에 스냅
|
||||||
|
if (Math.abs(smallTop - holdCellTop) < sideSnapDistance) {
|
||||||
|
tempModule.top = holdCellTop
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.abs(smallLeft - holdCellLeft) < snapDistance) {
|
||||||
|
tempModule.left = holdCellLeft
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//가운데 -> 가운대
|
//가운데 -> 가운대
|
||||||
if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) {
|
|
||||||
tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
//왼쪽 -> 가운데
|
|
||||||
if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) {
|
|
||||||
// console.log('holdCellCenterX', holdCellCenterX)
|
|
||||||
// console.log('smallLeft', smallLeft)
|
|
||||||
|
|
||||||
// console.log('모듈 센터에 스냅')
|
|
||||||
tempModule.left = holdCellCenterX + intvHor / 2
|
|
||||||
|
|
||||||
// console.log('tempModule.left', tempModule.left)
|
|
||||||
}
|
|
||||||
// 오른쪽 -> 가운데
|
|
||||||
if (Math.abs(smallRight - holdCellCenterX) < snapDistance) {
|
|
||||||
tempModule.left = holdCellCenterX - width - intvHor / 2
|
|
||||||
}
|
|
||||||
|
|
||||||
//설치된 셀에 좌측에 스냅
|
|
||||||
if (Math.abs(smallRight - holdCellLeft) < snapDistance) {
|
|
||||||
// console.log('모듈 좌측 스냅')
|
|
||||||
tempModule.left = holdCellLeft - width - intvHor
|
|
||||||
}
|
|
||||||
|
|
||||||
//설치된 셀에 우측에 스냅
|
|
||||||
if (Math.abs(smallLeft - holdCellRight) < snapDistance) {
|
|
||||||
// console.log('모듈 우측 스냅')
|
|
||||||
tempModule.left = holdCellRight + intvHor
|
|
||||||
}
|
|
||||||
//설치된 셀에 위쪽에 스냅
|
|
||||||
if (Math.abs(smallBottom - holdCellTop) < 10) {
|
|
||||||
tempModule.top = holdCellTop - height - intvVer
|
|
||||||
}
|
|
||||||
|
|
||||||
//설치된 셀에 밑쪽에 스냅
|
|
||||||
if (Math.abs(smallTop - holdCellBottom) < 10) {
|
|
||||||
tempModule.top = holdCellBottom + intvVer
|
|
||||||
}
|
|
||||||
|
|
||||||
//설치된 셀에 윗쪽에 스냅
|
|
||||||
if (Math.abs(smallTop - holdCellTop) < 10) {
|
|
||||||
tempModule.top = holdCellTop
|
|
||||||
}
|
|
||||||
|
|
||||||
//세로 가운데 -> 가운데
|
//세로 가운데 -> 가운데
|
||||||
// if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) {
|
// if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) {
|
||||||
@ -641,11 +693,6 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
// //위쪽 -> 가운데
|
// //위쪽 -> 가운데
|
||||||
// if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) {
|
// if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) {
|
||||||
// tempModule.top = holdCellCenterY
|
// tempModule.top = holdCellCenterY
|
||||||
// }
|
|
||||||
// //아랫쪽 -> 가운데
|
|
||||||
// if (Math.abs(smallBottom - holdCellCenterY) < cellSnapDistance) {
|
|
||||||
// tempModule.top = holdCellCenterY - height
|
|
||||||
// }
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,22 +720,19 @@ export function useModuleBasicSetting(tabNum) {
|
|||||||
// if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
|
// if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) {
|
||||||
// tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2
|
// tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// 모듈이 가운데가 세로중앙선에 붙게 스냅
|
// 모듈이 가운데가 세로중앙선에 붙게 스냅
|
||||||
if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
|
// if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
|
||||||
tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2
|
// tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 모듈오른쪽이 세로중앙선에 붙게 스냅
|
// 모듈오른쪽이 세로중앙선에 붙게 스냅
|
||||||
// if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
|
// if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) {
|
||||||
// tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX
|
// tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX
|
||||||
// }
|
// }
|
||||||
} else {
|
} else {
|
||||||
// 모듈이 가로중앙선에 스냅
|
// 모듈이 가로중앙선에 스냅
|
||||||
if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) {
|
// if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) {
|
||||||
tempModule.top = bigCenterY - tempModule.height / 2
|
// tempModule.top = bigCenterY - tempModule.height / 2
|
||||||
}
|
// }
|
||||||
|
|
||||||
// if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) {
|
// if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) {
|
||||||
// tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2
|
// tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2
|
||||||
// }
|
// }
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useRecoilValue, useSetRecoilState } from 'recoil'
|
|
||||||
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
|
|
||||||
import { useMasterController } from '@/hooks/common/useMasterController'
|
|
||||||
import { canvasSettingState, canvasState, currentCanvasPlanState, moduleSetupSurfaceState } from '@/store/canvasAtom'
|
|
||||||
import { POLYGON_TYPE, BATCH_TYPE } from '@/common/common'
|
|
||||||
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
|
||||||
import { roofDisplaySelector } from '@/store/settingAtom'
|
|
||||||
import offsetPolygon from '@/util/qpolygon-utils'
|
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
|
||||||
import { useEvent } from '@/hooks/useEvent'
|
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
|
||||||
|
|
||||||
export function useModulePlace() {
|
|
||||||
const canvas = useRecoilValue(canvasState)
|
|
||||||
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
|
|
||||||
const [trestleDetailParams, setTrestleDetailParams] = useState([])
|
|
||||||
const [trestleDetailList, setTrestleDetailList] = useState([])
|
|
||||||
const selectedModules = useRecoilValue(selectedModuleState)
|
|
||||||
const { getTrestleDetailList } = useMasterController()
|
|
||||||
const canvasSetting = useRecoilValue(canvasSettingState)
|
|
||||||
const { setSurfaceShapePattern } = useRoofFn()
|
|
||||||
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
|
||||||
const { addTargetMouseEventListener } = useEvent()
|
|
||||||
const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState)
|
|
||||||
const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false)
|
|
||||||
const { swalFire } = useSwal()
|
|
||||||
const { getMessage } = useMessage()
|
|
||||||
|
|
||||||
return {
|
|
||||||
selectedModules,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -10,6 +10,7 @@ import { useSwal } from '@/hooks/useSwal'
|
|||||||
import { useContext } from 'react'
|
import { useContext } from 'react'
|
||||||
import { QcastContext } from '@/app/QcastProvider'
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
|
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
|
||||||
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
|
|
||||||
// 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주
|
// 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주
|
||||||
const MODULE_MARGIN = 10
|
const MODULE_MARGIN = 10
|
||||||
@ -26,6 +27,7 @@ export const useTrestle = () => {
|
|||||||
|
|
||||||
const { getSelectedPcsItemList } = useCircuitTrestle()
|
const { getSelectedPcsItemList } = useCircuitTrestle()
|
||||||
const { resetCircuits } = useCircuitTrestle()
|
const { resetCircuits } = useCircuitTrestle()
|
||||||
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
const apply = () => {
|
const apply = () => {
|
||||||
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
|
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
|
||||||
@ -58,7 +60,6 @@ export const useTrestle = () => {
|
|||||||
}
|
}
|
||||||
const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction
|
const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction
|
||||||
if (!construction) {
|
if (!construction) {
|
||||||
swalFire({ text: 'construction 존재안함', icon: 'error' })
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,9 +132,9 @@ export const useTrestle = () => {
|
|||||||
surface.isChidory = isChidory
|
surface.isChidory = isChidory
|
||||||
|
|
||||||
if (plvrYn === 'N' && isChidory) {
|
if (plvrYn === 'N' && isChidory) {
|
||||||
swalFire({ text: '치조불가공법입니다.', icon: 'error' })
|
swalFire({ text: getMessage('chidory.can.not.install'), icon: 'error' })
|
||||||
clear()
|
clear()
|
||||||
throw new Error('치조불가공법입니다.')
|
throw new Error(getMessage('chidory.can.not.install'))
|
||||||
}
|
}
|
||||||
|
|
||||||
surface.set({ isChidory: isChidory })
|
surface.set({ isChidory: isChidory })
|
||||||
|
|||||||
@ -84,7 +84,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
|
|||||||
// innerLines가 있을경우 삭제
|
// innerLines가 있을경우 삭제
|
||||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
if (roofs.length === 0) {
|
if (roofs.length === 0) {
|
||||||
swalFire({ text: '지붕형상이 없습니다.' })
|
swalFire({ text: getMessage('roof.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,7 +52,7 @@ export function useEavesGableEdit(id) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
if (!outerLineFix || outerLines.length === 0) {
|
if (!outerLineFix || outerLines.length === 0) {
|
||||||
swalFire({ text: '외벽선이 없습니다.' })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useRecoilState, useRecoilValue, useResetRecoilState, 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 { useContext, useEffect, useRef, useState } from 'react'
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
@ -26,6 +26,8 @@ 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'
|
import { outerLinePointsState } from '@/store/outerLineAtom'
|
||||||
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
|
import { usePlan } from '@/hooks/usePlan'
|
||||||
|
|
||||||
export function useRoofAllocationSetting(id) {
|
export function useRoofAllocationSetting(id) {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -49,8 +51,9 @@ export function useRoofAllocationSetting(id) {
|
|||||||
const { get, post } = useAxios(globalLocaleState)
|
const { get, post } = useAxios(globalLocaleState)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
|
const { setIsGlobalLoading } = useContext(QcastContext)
|
||||||
const { setSurfaceShapePattern } = useRoofFn()
|
const { setSurfaceShapePattern } = useRoofFn()
|
||||||
|
const { saveCanvas } = usePlan()
|
||||||
|
|
||||||
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
|
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
|
||||||
const resetPoints = useResetRecoilState(outerLinePointsState)
|
const resetPoints = useResetRecoilState(outerLinePointsState)
|
||||||
@ -68,30 +71,19 @@ export function useRoofAllocationSetting(id) {
|
|||||||
roof.innerLines.forEach((line) => {
|
roof.innerLines.forEach((line) => {
|
||||||
/** 실측값이 없는 경우 라인 두께 4로 설정 */
|
/** 실측값이 없는 경우 라인 두께 4로 설정 */
|
||||||
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
|
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
|
||||||
line.set({
|
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
|
||||||
strokeWidth: 4,
|
|
||||||
stroke: 'black',
|
|
||||||
selectable: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 현재 선택된 라인인 경우 라인 두께 2로 설정 */
|
/** 현재 선택된 라인인 경우 라인 두께 2로 설정 */
|
||||||
if (editingLines.includes(line)) {
|
if (editingLines.includes(line)) {
|
||||||
line.set({
|
line.set({ strokeWidth: 2, stroke: 'black', selectable: true })
|
||||||
strokeWidth: 2,
|
|
||||||
stroke: 'black',
|
|
||||||
selectable: true,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
|
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
|
||||||
if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) {
|
if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) {
|
||||||
currentObject.set({
|
currentObject.set({ strokeWidth: 4, stroke: '#EA10AC' })
|
||||||
strokeWidth: 4,
|
|
||||||
stroke: '#EA10AC',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}, [currentObject])
|
}, [currentObject])
|
||||||
|
|
||||||
@ -99,7 +91,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
|
/** 현재 선택된 객체가 보조라인, 피라미드, 힙인 경우 두께 4로 설정 */
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
if (roofBases.length === 0) {
|
if (roofBases.length === 0) {
|
||||||
swalFire({ text: '할당할 지붕이 없습니다.' })
|
swalFire({ text: getMessage('roofAllocation.not.found'), icon: 'warning' })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -112,9 +104,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
*/
|
*/
|
||||||
const fetchBasicSettings = async (planNo) => {
|
const fetchBasicSettings = async (planNo) => {
|
||||||
try {
|
try {
|
||||||
await get({
|
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` }).then((res) => {
|
||||||
url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}`,
|
|
||||||
}).then((res) => {
|
|
||||||
let roofsArray = {}
|
let roofsArray = {}
|
||||||
|
|
||||||
if (res.length > 0) {
|
if (res.length > 0) {
|
||||||
@ -184,11 +174,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
|
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
|
||||||
})
|
})
|
||||||
|
|
||||||
setBasicInfo({
|
setBasicInfo({ planNo: '' + res[0].planNo, roofSizeSet: '' + res[0].roofSizeSet, roofAngleSet: '' + res[0].roofAngleSet })
|
||||||
planNo: '' + res[0].planNo,
|
|
||||||
roofSizeSet: '' + res[0].roofSizeSet,
|
|
||||||
roofAngleSet: '' + res[0].roofAngleSet,
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Data fetching error:', error)
|
console.error('Data fetching error:', error)
|
||||||
@ -200,6 +186,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
*/
|
*/
|
||||||
const basicSettingSave = async () => {
|
const basicSettingSave = async () => {
|
||||||
try {
|
try {
|
||||||
|
setIsGlobalLoading(true)
|
||||||
const patternData = {
|
const patternData = {
|
||||||
objectNo: correntObjectNo,
|
objectNo: correntObjectNo,
|
||||||
planNo: Number(basicSetting.planNo),
|
planNo: Number(basicSetting.planNo),
|
||||||
@ -222,6 +209,8 @@ export function useRoofAllocationSetting(id) {
|
|||||||
|
|
||||||
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
|
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
|
||||||
swalFire({ text: getMessage(res.returnMessage) })
|
swalFire({ text: getMessage(res.returnMessage) })
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
saveCanvas(false)
|
||||||
})
|
})
|
||||||
|
|
||||||
//Recoil 설정
|
//Recoil 설정
|
||||||
@ -242,22 +231,34 @@ export function useRoofAllocationSetting(id) {
|
|||||||
swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.exceed.count') })
|
swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.exceed.count') })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
setCurrentRoofList([
|
|
||||||
...currentRoofList,
|
const originCurrentRoofList = currentRoofList.map((roof) => {
|
||||||
{
|
return { ...roof, selected: false }
|
||||||
...currentRoofMaterial,
|
})
|
||||||
selected: false,
|
originCurrentRoofList.push({
|
||||||
id: currentRoofMaterial.roofMatlCd,
|
...currentRoofMaterial,
|
||||||
name: currentRoofMaterial.roofMatlNm,
|
selected: true,
|
||||||
index: currentRoofList.length,
|
id: currentRoofMaterial.roofMatlCd,
|
||||||
},
|
name: currentRoofMaterial.roofMatlNm,
|
||||||
])
|
index: currentRoofList.length,
|
||||||
|
})
|
||||||
|
|
||||||
|
setCurrentRoofList(originCurrentRoofList)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 지붕재 삭제
|
* 지붕재 삭제
|
||||||
*/
|
*/
|
||||||
const onDeleteRoofMaterial = (idx) => {
|
const onDeleteRoofMaterial = (idx) => {
|
||||||
|
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
|
||||||
|
for (let i = 0; i < roofs.length; i++) {
|
||||||
|
if (roofs[i].roofMaterial?.index === idx) {
|
||||||
|
swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.material.can.not.delete') })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const isSelected = currentRoofList[idx].selected
|
const isSelected = currentRoofList[idx].selected
|
||||||
const newRoofList = JSON.parse(JSON.stringify(currentRoofList)).filter((_, index) => index !== idx)
|
const newRoofList = JSON.parse(JSON.stringify(currentRoofList)).filter((_, index) => index !== idx)
|
||||||
if (isSelected) {
|
if (isSelected) {
|
||||||
@ -270,8 +271,6 @@ export function useRoofAllocationSetting(id) {
|
|||||||
* 선택한 지붕재로 할당
|
* 선택한 지붕재로 할당
|
||||||
*/
|
*/
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
basicSettingSave()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
|
* 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
|
||||||
*/
|
*/
|
||||||
@ -280,6 +279,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
} else {
|
} else {
|
||||||
apply()
|
apply()
|
||||||
resetPoints()
|
resetPoints()
|
||||||
|
basicSettingSave()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -287,23 +287,45 @@ export function useRoofAllocationSetting(id) {
|
|||||||
* 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
|
* 지붕재 오른쪽 마우스 클릭 후 단일로 지붕재 변경 필요한 경우
|
||||||
*/
|
*/
|
||||||
const handleSaveContext = () => {
|
const handleSaveContext = () => {
|
||||||
basicSettingSave()
|
|
||||||
const newRoofList = currentRoofList.map((roof, idx) => {
|
const newRoofList = currentRoofList.map((roof, idx) => {
|
||||||
|
if (roof.index !== idx) {
|
||||||
|
// 기존 저장된 지붕재의 index 수정
|
||||||
|
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF && obj.roofMaterial?.index === roof.index)
|
||||||
|
roofs.forEach((roof) => {
|
||||||
|
setSurfaceShapePattern(roof, roofDisplay.column, false, { ...roof, index: idx }, true)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return { ...roof, index: idx, raft: roof.raft ? roof.raft : roof.raftBaseCd }
|
return { ...roof, index: idx, raft: roof.raft ? roof.raft : roof.raftBaseCd }
|
||||||
})
|
})
|
||||||
|
|
||||||
setBasicSetting((prev) => {
|
setBasicSetting((prev) => {
|
||||||
return {
|
return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) }
|
||||||
...prev,
|
|
||||||
selectedRoofMaterial: newRoofList.find((roof) => roof.selected),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
setRoofList(newRoofList)
|
setRoofList(newRoofList)
|
||||||
|
setRoofMaterials(newRoofList)
|
||||||
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
|
const selectedRoofMaterial = newRoofList.find((roof) => roof.selected)
|
||||||
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true)
|
setSurfaceShapePattern(currentObject, roofDisplay.column, false, selectedRoofMaterial, true)
|
||||||
drawDirectionArrow(currentObject)
|
drawDirectionArrow(currentObject)
|
||||||
modifyModuleSelectionData()
|
modifyModuleSelectionData()
|
||||||
closeAll()
|
closeAll()
|
||||||
|
basicSettingSave()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 기존 세팅된 지붕에 지붕재 내용을 바뀐 내용으로 수정
|
||||||
|
* @param newRoofMaterials
|
||||||
|
*/
|
||||||
|
const setRoofMaterials = (newRoofMaterials) => {
|
||||||
|
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
newRoofMaterials.forEach((roofMaterial) => {
|
||||||
|
const index = roofMaterial.index
|
||||||
|
const tempRoofs = roofs.filter((roof) => roof.roofMaterial?.index === index)
|
||||||
|
tempRoofs.forEach((roof) => {
|
||||||
|
setSurfaceShapePattern(roof, roofDisplay.column, false, roofMaterial)
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -313,11 +335,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
if (!checkInnerLines()) {
|
if (!checkInnerLines()) {
|
||||||
apply()
|
apply()
|
||||||
} else {
|
} else {
|
||||||
swalFire({
|
swalFire({ type: 'alert', icon: 'error', text: getMessage('실제치수를 입력해 주세요.') })
|
||||||
type: 'alert',
|
|
||||||
icon: 'error',
|
|
||||||
text: getMessage('실제치수를 입력해 주세요.'),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,11 +350,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
if (roof.separatePolygon.length === 0) {
|
if (roof.separatePolygon.length === 0) {
|
||||||
roof.innerLines.forEach((line) => {
|
roof.innerLines.forEach((line) => {
|
||||||
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
|
if (!line.attributes.actualSize || line.attributes?.actualSize === 0) {
|
||||||
line.set({
|
line.set({ strokeWidth: 4, stroke: 'black', selectable: true })
|
||||||
strokeWidth: 4,
|
|
||||||
stroke: 'black',
|
|
||||||
selectable: true,
|
|
||||||
})
|
|
||||||
result = true
|
result = true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -361,6 +375,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
splitPolygonWithLines(roofBase)
|
splitPolygonWithLines(roofBase)
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log(e)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,10 +398,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
setBasicSetting((prev) => {
|
setBasicSetting((prev) => {
|
||||||
return {
|
return { ...prev, selectedRoofMaterial: newRoofList.find((roof) => roof.selected) }
|
||||||
...prev,
|
|
||||||
selectedRoofMaterial: newRoofList.find((roof) => roof.selected),
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
setRoofList(newRoofList)
|
setRoofList(newRoofList)
|
||||||
|
|
||||||
@ -394,9 +406,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
|
|
||||||
roofs.forEach((roof) => {
|
roofs.forEach((roof) => {
|
||||||
if (roof.isFixed) return
|
if (roof.isFixed) return
|
||||||
roof.set({
|
roof.set({ isFixed: true })
|
||||||
isFixed: true,
|
|
||||||
})
|
|
||||||
|
|
||||||
/** 모양 패턴 설정 */
|
/** 모양 패턴 설정 */
|
||||||
setSurfaceShapePattern(
|
setSurfaceShapePattern(
|
||||||
@ -408,6 +418,8 @@ export function useRoofAllocationSetting(id) {
|
|||||||
drawDirectionArrow(roof)
|
drawDirectionArrow(roof)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
setRoofMaterials(newRoofList)
|
||||||
|
|
||||||
/** 외곽선 삭제 */
|
/** 외곽선 삭제 */
|
||||||
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
|
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
|
||||||
removeTargets.forEach((obj) => {
|
removeTargets.forEach((obj) => {
|
||||||
@ -431,10 +443,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
if (id === line.id) {
|
if (id === line.id) {
|
||||||
setEditingLines([...editingLines.filter((editLine) => editLine.id !== line.id), line])
|
setEditingLines([...editingLines.filter((editLine) => editLine.id !== line.id), line])
|
||||||
line.attributes.actualSize = size
|
line.attributes.actualSize = size
|
||||||
line.set({
|
line.set({ strokeWidth: 2, stroke: 'black' })
|
||||||
strokeWidth: 2,
|
|
||||||
stroke: 'black',
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export function useRoofShapePassivitySetting(id) {
|
|||||||
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
const { addCanvasMouseEventListener, initEvent } = useEvent()
|
||||||
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
|
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
|
||||||
const { drawRoofPolygon } = useMode()
|
const { drawRoofPolygon } = useMode()
|
||||||
const { addPolygonByLines } = usePolygon()
|
const { addPolygonByLines, addLengthText } = usePolygon()
|
||||||
const currentObject = useRecoilValue(currentObjectState)
|
const currentObject = useRecoilValue(currentObjectState)
|
||||||
const offsetRef = useRef(null)
|
const offsetRef = useRef(null)
|
||||||
const pitchRef = useRef(null)
|
const pitchRef = useRef(null)
|
||||||
@ -51,7 +51,7 @@ export function useRoofShapePassivitySetting(id) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
if (!outerLineFix || outerLines.length === 0) {
|
if (!outerLineFix || outerLines.length === 0) {
|
||||||
swalFire({ text: '외벽선이 없습니다.' })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -248,6 +248,7 @@ export function useRoofShapePassivitySetting(id) {
|
|||||||
// 완료 한 경우에는 지붕까지 그려줌
|
// 완료 한 경우에는 지붕까지 그려줌
|
||||||
addPitchTextsByOuterLines()
|
addPitchTextsByOuterLines()
|
||||||
const roof = drawRoofPolygon(wall)
|
const roof = drawRoofPolygon(wall)
|
||||||
|
addLengthText(roof)
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
|
|||||||
@ -191,7 +191,7 @@ export function useRoofShapeSetting(id) {
|
|||||||
let direction
|
let direction
|
||||||
|
|
||||||
if (outerLines.length < 2) {
|
if (outerLines.length < 2) {
|
||||||
swalFire({ text: '외벽선이 없습니다.', icon: 'error' })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,7 @@ export function useWallLineOffsetSetting(id) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
if (outerLines.length === 0) {
|
if (outerLines.length === 0) {
|
||||||
swalFire({ text: '외벽선이 없습니다.' })
|
swalFire({ text: getMessage('wall.line.not.found') })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,6 +32,7 @@ import {
|
|||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
import { POLYGON_TYPE } from '@/common/common'
|
import { POLYGON_TYPE } from '@/common/common'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
import { useSurfaceShapeBatch } from './useSurfaceShapeBatch'
|
||||||
|
|
||||||
import { roofDisplaySelector } from '@/store/settingAtom'
|
import { roofDisplaySelector } from '@/store/settingAtom'
|
||||||
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
import { useRoofFn } from '@/hooks/common/useRoofFn'
|
||||||
@ -50,6 +51,8 @@ export function usePlacementShapeDrawing(id) {
|
|||||||
const { addPolygonByLines, drawDirectionArrow } = usePolygon()
|
const { addPolygonByLines, drawDirectionArrow } = usePolygon()
|
||||||
const { tempGridMode } = useTempGrid()
|
const { tempGridMode } = useTempGrid()
|
||||||
const { setSurfaceShapePattern } = useRoofFn()
|
const { setSurfaceShapePattern } = useRoofFn()
|
||||||
|
const { changeSurfaceLineType } = useSurfaceShapeBatch({})
|
||||||
|
|
||||||
const canvasSetting = useRecoilValue(canvasSettingState)
|
const canvasSetting = useRecoilValue(canvasSettingState)
|
||||||
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
|
||||||
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
const adsorptionPointAddMode = useRecoilValue(adsorptionPointAddModeState)
|
||||||
@ -253,11 +256,14 @@ export function usePlacementShapeDrawing(id) {
|
|||||||
setPoints([])
|
setPoints([])
|
||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
|
|
||||||
if (+canvasSetting?.roofSizeSet === 3) {
|
// if (+canvasSetting?.roofSizeSet === 3) {
|
||||||
closePopup(id)
|
// closePopup(id)
|
||||||
return
|
// return
|
||||||
}
|
// }
|
||||||
addPopup(id, 1, <PlacementSurfaceLineProperty id={id} roof={roof} />, false)
|
// addPopup(id, 1, <PlacementSurfaceLineProperty id={id} roof={roof} />, false)
|
||||||
|
|
||||||
|
changeSurfaceLineType(roof)
|
||||||
|
closePopup(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.length < 3) {
|
if (points.length < 3) {
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
import { useEffect } from 'react'
|
import { useEffect } from 'react'
|
||||||
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||||
import { canvasSettingState, canvasState, currentCanvasPlanState, globalPitchState } from '@/store/canvasAtom'
|
import { canvasSettingState, canvasState, currentCanvasPlanState, globalPitchState } from '@/store/canvasAtom'
|
||||||
import { MENU, POLYGON_TYPE } from '@/common/common'
|
import { MENU, POLYGON_TYPE, LINE_TYPE } from '@/common/common'
|
||||||
import { getIntersectionPoint, toFixedWithoutRounding } from '@/util/canvas-util'
|
import { getIntersectionPoint, toFixedWithoutRounding } from '@/util/canvas-util'
|
||||||
import { degreesToRadians } from '@turf/turf'
|
import { degreesToRadians } from '@turf/turf'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
@ -111,7 +111,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
lockScalingX: true, // X 축 크기 조정 잠금
|
lockScalingX: true, // X 축 크기 조정 잠금
|
||||||
lockScalingY: true, // Y 축 크기 조정 잠금
|
lockScalingY: true, // Y 축 크기 조정 잠금
|
||||||
name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP,
|
name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP,
|
||||||
flipX: xInversion !== yInversion,
|
// flipX: xInversion !== yInversion,
|
||||||
// angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate),
|
// angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate),
|
||||||
// angle: rotate,
|
// angle: rotate,
|
||||||
originX: 'center',
|
originX: 'center',
|
||||||
@ -120,6 +120,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
obj = new QPolygon(points, options)
|
obj = new QPolygon(points, options)
|
||||||
|
|
||||||
let imageRotate = 0
|
let imageRotate = 0
|
||||||
if (xInversion && !yInversion) {
|
if (xInversion && !yInversion) {
|
||||||
if (rotate % 180 === 0 || rotate < 0) {
|
if (rotate % 180 === 0 || rotate < 0) {
|
||||||
@ -148,7 +149,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
} else {
|
} else {
|
||||||
imageRotate = (rotate + 360) % 360
|
imageRotate = (rotate + 360) % 360
|
||||||
}
|
}
|
||||||
obj.set({ angle: imageRotate })
|
obj.set({ angle: imageRotate, flipX: xInversion !== yInversion })
|
||||||
obj.setCoords() //좌표 변경 적용
|
obj.setCoords() //좌표 변경 적용
|
||||||
|
|
||||||
canvas?.add(obj)
|
canvas?.add(obj)
|
||||||
@ -158,6 +159,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
addCanvasMouseEventListener('mouse:down', (e) => {
|
addCanvasMouseEventListener('mouse:down', (e) => {
|
||||||
isDrawing = false
|
isDrawing = false
|
||||||
|
|
||||||
|
const { xInversion, yInversion } = surfaceRefs
|
||||||
canvas?.remove(obj)
|
canvas?.remove(obj)
|
||||||
|
|
||||||
//각도 추가
|
//각도 추가
|
||||||
@ -178,6 +180,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//회전, flip등이 먹은 기준으로 새로생성
|
//회전, flip등이 먹은 기준으로 새로생성
|
||||||
|
// const batchSurface = addPolygon(reorderedPoints, {
|
||||||
const batchSurface = addPolygon(obj.getCurrentPoints(), {
|
const batchSurface = addPolygon(obj.getCurrentPoints(), {
|
||||||
fill: 'transparent',
|
fill: 'transparent',
|
||||||
stroke: 'red',
|
stroke: 'red',
|
||||||
@ -196,18 +199,25 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
pitch: globalPitch,
|
pitch: globalPitch,
|
||||||
surfaceId: surfaceId,
|
surfaceId: surfaceId,
|
||||||
direction: direction,
|
direction: direction,
|
||||||
|
isXInversion: xInversion,
|
||||||
|
isYInversion: yInversion,
|
||||||
})
|
})
|
||||||
canvas.setActiveObject(batchSurface)
|
canvas.setActiveObject(batchSurface)
|
||||||
setSurfaceShapePattern(batchSurface, roofDisplay.column)
|
setSurfaceShapePattern(batchSurface, roofDisplay.column)
|
||||||
drawDirectionArrow(batchSurface)
|
drawDirectionArrow(batchSurface)
|
||||||
|
|
||||||
// if (setIsHidden) setIsHidden(false)
|
|
||||||
|
|
||||||
// closePopup(id)
|
// closePopup(id)
|
||||||
initEvent()
|
initEvent()
|
||||||
if (+canvasSetting?.roofSizeSet === 3) return
|
// if (+canvasSetting?.roofSizeSet === 3) return
|
||||||
const popupId = uuidv4()
|
// const popupId = uuidv4()
|
||||||
addPopup(popupId, 2, <PlacementSurfaceLineProperty roof={batchSurface} id={popupId} setIsHidden={setIsHidden} />)
|
// addPopup(popupId, 2, <PlacementSurfaceLineProperty roof={batchSurface} id={popupId} setIsHidden={setIsHidden} />)
|
||||||
|
|
||||||
|
// console.log('xInversion', xInversion) //상하반전
|
||||||
|
// console.log('yInversion', yInversion) //좌우반전
|
||||||
|
|
||||||
|
changeSurfaceLineType(batchSurface)
|
||||||
|
|
||||||
|
if (setIsHidden) setIsHidden(false)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if (setIsHidden) setIsHidden(false)
|
if (setIsHidden) setIsHidden(false)
|
||||||
@ -488,18 +498,18 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
}
|
}
|
||||||
case 10: {
|
case 10: {
|
||||||
points = [
|
points = [
|
||||||
{ x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
|
|
||||||
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
|
|
||||||
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 },
|
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 },
|
||||||
{ x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 },
|
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
|
||||||
{
|
{ x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
|
||||||
x: pointer.x + length1 / 2 - length1 + length2,
|
|
||||||
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
x: pointer.x + length1 / 2 - length1 + length2 + length3,
|
x: pointer.x + length1 / 2 - length1 + length2 + length3,
|
||||||
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
|
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
x: pointer.x + length1 / 2 - length1 + length2,
|
||||||
|
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
|
||||||
|
},
|
||||||
|
{ x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 },
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -613,27 +623,27 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
}
|
}
|
||||||
case 14: {
|
case 14: {
|
||||||
points = [
|
points = [
|
||||||
{ x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 },
|
|
||||||
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
|
|
||||||
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 },
|
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 },
|
||||||
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
|
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
|
||||||
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 },
|
{ x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 },
|
||||||
{ x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 },
|
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2,
|
x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2,
|
||||||
y: pointer.y + length4 / 2 - length4 + length5,
|
y: pointer.y + length4 / 2 - length4 + length5,
|
||||||
},
|
},
|
||||||
|
{ x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 },
|
||||||
|
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 },
|
||||||
|
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 15: {
|
case 15: {
|
||||||
points = [
|
points = [
|
||||||
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 },
|
|
||||||
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
|
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
|
||||||
{ x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) },
|
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 },
|
||||||
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
|
|
||||||
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 },
|
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 },
|
||||||
|
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
|
||||||
|
{ x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) },
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -641,28 +651,28 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
case 16: {
|
case 16: {
|
||||||
points = [
|
points = [
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2,
|
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
|
||||||
y: pointer.y + length3 / 2,
|
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
|
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
|
||||||
y: pointer.y + length3 / 2 - (length3 - length4),
|
y: pointer.y + length3 / 2 - (length3 - length4),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
|
x: pointer.x - length1 / 2,
|
||||||
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
|
y: pointer.y + length3 / 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
|
x: pointer.x - length1 / 2 + length1,
|
||||||
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
|
y: pointer.y + length3 / 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
|
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
|
||||||
y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4,
|
y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + length1,
|
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
|
||||||
y: pointer.y + length3 / 2,
|
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
@ -673,25 +683,25 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이
|
const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이
|
||||||
|
|
||||||
points = [
|
points = [
|
||||||
{
|
|
||||||
x: pointer.x - length1 / 2 + length1,
|
|
||||||
y: pointer.y + length3 / 2,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2,
|
x: pointer.x - length1 / 2,
|
||||||
y: pointer.y + length3 / 2,
|
y: pointer.y + length3 / 2,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)),
|
x: pointer.x - length1 / 2 + length1,
|
||||||
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
|
y: pointer.y + length3 / 2,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)),
|
||||||
|
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2,
|
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2,
|
||||||
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
|
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)),
|
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)),
|
||||||
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)),
|
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
break
|
break
|
||||||
@ -1066,45 +1076,294 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
canvas?.renderAll()
|
canvas?.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
const updateFlippedPoints = (polygon) => {
|
/**
|
||||||
if (!(polygon instanceof fabric.Polygon)) {
|
* 면형상 작도시 라인 속성 넣는 로직
|
||||||
console.error('The object is not a Polygon.')
|
* 폴리곤으로 보면 직선방향에 따라 아래쪽인지 윗쪽인지 판단이 가능하다고 생각하여
|
||||||
return
|
* south -> 밑면은 무조건 right direction이라 가정하고 작업함 좌우반전시 반대로 그려지는 경우도 생기지만 그럴땐 흐름방향에 따라 최대값(최소값)을 찾아
|
||||||
}
|
* 해당 하는 흐름에 맞게 변경함
|
||||||
|
* @param { } polygon
|
||||||
|
*/
|
||||||
|
|
||||||
const { flipX, flipY, width, height, points, left, top, scaleX, scaleY } = polygon
|
//폴리곤, 상하반전, 좌우반전
|
||||||
|
const changeSurfaceLineType = (polygon) => {
|
||||||
|
const { isXInversion, isYInversion } = polygon //상하반전, 좌우반전
|
||||||
|
|
||||||
// 현재 points의 사본 가져오기
|
polygon.lines.forEach((line) => {
|
||||||
const newPoints = points.map((point) => {
|
line.attributes.type = LINE_TYPE.WALLLINE.GABLE
|
||||||
let x = point.x
|
|
||||||
let y = point.y
|
|
||||||
|
|
||||||
// flipX 적용
|
|
||||||
if (flipX) {
|
|
||||||
x = width - x
|
|
||||||
}
|
|
||||||
|
|
||||||
// flipY 적용
|
|
||||||
if (flipY) {
|
|
||||||
y = height - y
|
|
||||||
}
|
|
||||||
|
|
||||||
// 스케일 및 전역 좌표 고려
|
|
||||||
x = (x - width / 2) * scaleX + width / 2
|
|
||||||
y = (y - height / 2) * scaleY + height / 2
|
|
||||||
|
|
||||||
return { x, y }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// flipX, flipY를 초기화
|
const directionConfig = {
|
||||||
polygon.flipX = false
|
south: { evaesDirection: 'right', ridgeDirection: 'left', coord1: 'y1', coord2: 'y2' },
|
||||||
polygon.flipY = false
|
north: { evaesDirection: 'left', ridgeDirection: 'right', coord1: 'y1', coord2: 'y2' },
|
||||||
|
east: { evaesDirection: 'top', ridgeDirection: 'bottom', coord1: 'x1', coord2: 'x2' },
|
||||||
|
west: { evaesDirection: 'bottom', ridgeDirection: 'top', coord1: 'x1', coord2: 'x2' },
|
||||||
|
}
|
||||||
|
|
||||||
// points 업데이트
|
const { evaesDirection, ridgeDirection, coord1, coord2 } = directionConfig[polygon.direction] || directionConfig.west
|
||||||
polygon.set({ points: newPoints })
|
|
||||||
polygon.setCoords()
|
|
||||||
|
|
||||||
return polygon
|
polygon.lines.forEach((line) => {
|
||||||
|
if (line[coord1] === line[coord2]) {
|
||||||
|
if (line.direction === evaesDirection) {
|
||||||
|
line.attributes.type = LINE_TYPE.WALLLINE.EAVES
|
||||||
|
} else if (line.direction === ridgeDirection) {
|
||||||
|
line.attributes.type = LINE_TYPE.SUBLINE.RIDGE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 진짜 처마 라인인지 확인하는 로직 -> 특정 모양에 따라 처마가 없는 경우가 있는데 위에 로직으로는
|
||||||
|
* 용마루도 처마로 만들어서 재보정
|
||||||
|
*/
|
||||||
|
//직선 찾는 로직
|
||||||
|
const maxLine = polygon.lines.filter((line) => line[coord1] === line[coord2])
|
||||||
|
|
||||||
|
if (maxLine.length > 0) {
|
||||||
|
const maxLineSorted = maxLine.reduce((a, b) => {
|
||||||
|
return (polygon.direction === 'south' || polygon.direction === 'east' ? b : a)[coord1] >
|
||||||
|
(polygon.direction === 'south' || polygon.direction === 'east' ? a : b)[coord1]
|
||||||
|
? b
|
||||||
|
: a
|
||||||
|
})
|
||||||
|
|
||||||
|
//정렬된 폴리곤이 아니면(대각선이 존재하는 폴리곤일때)
|
||||||
|
if (!polygon.isSortedPoints) {
|
||||||
|
//좌우 반전을 했으면 반대로 정의함
|
||||||
|
if (isYInversion || isXInversion) {
|
||||||
|
polygon.lines.forEach((line) => {
|
||||||
|
if (line.attributes.type === LINE_TYPE.WALLLINE.EAVES) {
|
||||||
|
line.attributes.type = LINE_TYPE.SUBLINE.RIDGE
|
||||||
|
} else if (line.attributes.type === LINE_TYPE.SUBLINE.RIDGE) {
|
||||||
|
line.attributes.type = LINE_TYPE.WALLLINE.EAVES
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxLine.length === 1) {
|
||||||
|
const maxLineCoord = polygon.lines.reduce((a, b) => {
|
||||||
|
return (polygon.direction === 'south' || polygon.direction === 'east' ? b : a)[coord1] >
|
||||||
|
(polygon.direction === 'south' || polygon.direction === 'east' ? a : b)[coord1]
|
||||||
|
? b
|
||||||
|
: a
|
||||||
|
})
|
||||||
|
|
||||||
|
const isRealEavesLine = polygon.lines.filter((line) => line.attributes.type === LINE_TYPE.WALLLINE.EAVES)
|
||||||
|
if (isRealEavesLine.length > 0) {
|
||||||
|
isRealEavesLine.forEach((line) => {
|
||||||
|
if (polygon.direction === 'south' || polygon.direction === 'north') {
|
||||||
|
const targetCoord =
|
||||||
|
polygon.direction === 'south' ? Math.max(maxLineCoord.y1, maxLineCoord.y2) : Math.min(maxLineCoord.y1, maxLineCoord.y2)
|
||||||
|
const realLineCoord = polygon.direction === 'south' ? Math.max(line.y1, line.y2) : Math.min(line.y1, line.y2)
|
||||||
|
|
||||||
|
if (targetCoord !== realLineCoord) {
|
||||||
|
line.attributes.type = LINE_TYPE.SUBLINE.RIDGE
|
||||||
|
}
|
||||||
|
} else if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||||
|
const targetCoord =
|
||||||
|
polygon.direction === 'east' ? Math.max(maxLineCoord.x1, maxLineCoord.x2) : Math.min(maxLineCoord.x1, maxLineCoord.x2)
|
||||||
|
const realLineCoord = polygon.direction === 'east' ? Math.max(line.x1, line.x2) : Math.min(line.x1, line.x2)
|
||||||
|
|
||||||
|
if (targetCoord !== realLineCoord) {
|
||||||
|
line.attributes.type = LINE_TYPE.SUBLINE.RIDGE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findCentroid(points) {
|
||||||
|
let sumX = 0,
|
||||||
|
sumY = 0
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
sumX += points[i].x
|
||||||
|
sumY += points[i].y
|
||||||
|
}
|
||||||
|
return { x: sumX / points.length, y: sumY / points.length }
|
||||||
|
}
|
||||||
|
|
||||||
|
// 도형의 포인트를 왼쪽부터 반시계 방향으로 정렬하는 함수
|
||||||
|
/**
|
||||||
|
* 다각형의 점들을 시계 반대 방향으로 정렬하는 함수
|
||||||
|
* @param {Array} points - {x, y} 좌표 객체 배열
|
||||||
|
* @param {Object} startPoint - 시작점 (제공되지 않으면 가장 왼쪽 아래 점을 사용)
|
||||||
|
* @returns {Array} 시계 반대 방향으로 정렬된 점들의 배열
|
||||||
|
*/
|
||||||
|
function orderPointsCounterClockwise(points, startPoint = null) {
|
||||||
|
if (points.length <= 3) {
|
||||||
|
return points // 점이 3개 이하면 이미 다각형의 모든 점이므로 그대로 반환
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시작점이 제공되지 않았다면 가장 왼쪽 아래 점을 찾음
|
||||||
|
let start = startPoint
|
||||||
|
if (!start) {
|
||||||
|
start = points[0]
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
if (points[i].x < start.x || (points[i].x === start.x && points[i].y < start.y)) {
|
||||||
|
start = points[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 다각형의 중심점 계산
|
||||||
|
let centerX = 0,
|
||||||
|
centerY = 0
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
centerX += points[i].x
|
||||||
|
centerY += points[i].y
|
||||||
|
}
|
||||||
|
centerX /= points.length
|
||||||
|
centerY /= points.length
|
||||||
|
|
||||||
|
// 시작점에서 시계 반대 방향으로 각도 계산
|
||||||
|
let angles = []
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
// 시작점은 제외
|
||||||
|
if (points[i] === start) continue
|
||||||
|
|
||||||
|
// 시작점을 기준으로 각 점의 각도 계산
|
||||||
|
let angle = Math.atan2(points[i].y - start.y, points[i].x - start.x)
|
||||||
|
|
||||||
|
// 각도가 음수면 2π를 더해 0~2π 범위로 변환
|
||||||
|
if (angle < 0) angle += 2 * Math.PI
|
||||||
|
|
||||||
|
angles.push({
|
||||||
|
point: points[i],
|
||||||
|
angle: angle,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 각도에 따라 정렬 (시계 반대 방향)
|
||||||
|
angles.sort((a, b) => a.angle - b.angle)
|
||||||
|
|
||||||
|
// 정렬된 배열 생성 (시작점을 첫 번째로)
|
||||||
|
let orderedPoints = [start]
|
||||||
|
for (let i = 0; i < angles.length; i++) {
|
||||||
|
orderedPoints.push(angles[i].point)
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderedPoints
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 특정 점에서 시작하여 시계 반대 방향으로 다음 점을 찾는 함수
|
||||||
|
* @param {Object} currentPoint - 현재 점 {x, y}
|
||||||
|
* @param {Array} points - 모든 점들의 배열
|
||||||
|
* @param {Array} visited - 방문한 점들의 인덱스 배열
|
||||||
|
* @param {Object} prevVector - 이전 벡터 방향 (첫 호출에서는 null)
|
||||||
|
* @returns {Object} 다음 점의 인덱스와 객체
|
||||||
|
*/
|
||||||
|
function findNextCounterClockwisePoint(currentPoint, points, visited, prevVector = null) {
|
||||||
|
let minAngle = Infinity
|
||||||
|
let nextIndex = -1
|
||||||
|
|
||||||
|
// 이전 벡터가 없으면 (첫 점인 경우) 아래쪽을 향하는 벡터 사용
|
||||||
|
if (!prevVector) {
|
||||||
|
prevVector = { x: 0, y: -1 }
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
// 이미 방문했거나 현재 점이면 건너뜀
|
||||||
|
if (visited.includes(i) || (points[i].x === currentPoint.x && points[i].y === currentPoint.y)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재 점에서 다음 후보 점으로의 벡터
|
||||||
|
let vector = {
|
||||||
|
x: points[i].x - currentPoint.x,
|
||||||
|
y: points[i].y - currentPoint.y,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 벡터의 크기
|
||||||
|
let magnitude = Math.sqrt(vector.x * vector.x + vector.y * vector.y)
|
||||||
|
|
||||||
|
// 단위 벡터로 정규화
|
||||||
|
vector.x /= magnitude
|
||||||
|
vector.y /= magnitude
|
||||||
|
|
||||||
|
// 이전 벡터와 현재 벡터 사이의 각도 계산 (내적 사용)
|
||||||
|
let dotProduct = prevVector.x * vector.x + prevVector.y * vector.y
|
||||||
|
let crossProduct = prevVector.x * vector.y - prevVector.y * vector.x
|
||||||
|
|
||||||
|
// 각도 계산 (atan2 사용)
|
||||||
|
let angle = Math.atan2(crossProduct, dotProduct)
|
||||||
|
|
||||||
|
// 시계 반대 방향으로 가장 작은 각도를 가진 점 찾기
|
||||||
|
// 각도가 음수면 2π를 더해 0~2π 범위로 변환
|
||||||
|
if (angle < 0) angle += 2 * Math.PI
|
||||||
|
|
||||||
|
if (angle < minAngle) {
|
||||||
|
minAngle = angle
|
||||||
|
nextIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextIndex !== -1 ? { index: nextIndex, point: points[nextIndex] } : null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 다각형의 점들을 시계 반대 방향으로 추적하는 함수
|
||||||
|
* @param {Array} points - {x, y} 좌표 객체 배열
|
||||||
|
* @param {Object} startPoint - 시작점 (제공되지 않으면 가장 왼쪽 아래 점을 사용)
|
||||||
|
* @returns {Array} 시계 반대 방향으로 정렬된 점들의 배열
|
||||||
|
*/
|
||||||
|
function tracePolygonCounterClockwise(points, startPoint = null) {
|
||||||
|
if (points.length <= 3) {
|
||||||
|
return orderPointsCounterClockwise(points, startPoint)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 시작점이 제공되지 않았다면 가장 왼쪽 아래 점을 찾음
|
||||||
|
let startIndex = 0
|
||||||
|
if (!startPoint) {
|
||||||
|
for (let i = 1; i < points.length; i++) {
|
||||||
|
if (points[i].x < points[startIndex].x || (points[i].x === points[startIndex].x && points[i].y < points[startIndex].y)) {
|
||||||
|
startIndex = i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startPoint = points[startIndex]
|
||||||
|
} else {
|
||||||
|
// 시작점이 제공된 경우 해당 점의 인덱스 찾기
|
||||||
|
for (let i = 0; i < points.length; i++) {
|
||||||
|
if (points[i].x === startPoint.x && points[i].y === startPoint.y) {
|
||||||
|
startIndex = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 결과 배열 초기화
|
||||||
|
let orderedPoints = [startPoint]
|
||||||
|
let visited = [startIndex]
|
||||||
|
|
||||||
|
let currentPoint = startPoint
|
||||||
|
let prevVector = null
|
||||||
|
|
||||||
|
// 모든 점을 방문할 때까지 반복
|
||||||
|
while (visited.length < points.length) {
|
||||||
|
let next = findNextCounterClockwisePoint(currentPoint, points, visited, prevVector)
|
||||||
|
|
||||||
|
if (!next) break // 더 이상 찾을 점이 없으면 종료
|
||||||
|
|
||||||
|
orderedPoints.push(next.point)
|
||||||
|
visited.push(next.index)
|
||||||
|
|
||||||
|
// 이전 벡터 업데이트 (현재 점에서 다음 점으로의 벡터)
|
||||||
|
prevVector = {
|
||||||
|
x: next.point.x - currentPoint.x,
|
||||||
|
y: next.point.y - currentPoint.y,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 벡터 정규화
|
||||||
|
let magnitude = Math.sqrt(prevVector.x * prevVector.x + prevVector.y * prevVector.y)
|
||||||
|
prevVector.x /= magnitude
|
||||||
|
prevVector.y /= magnitude
|
||||||
|
|
||||||
|
currentPoint = next.point
|
||||||
|
}
|
||||||
|
|
||||||
|
return orderedPoints
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -1115,5 +1374,6 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
|
|||||||
changeSurfaceLinePropertyEvent,
|
changeSurfaceLinePropertyEvent,
|
||||||
changeSurfaceLineProperty,
|
changeSurfaceLineProperty,
|
||||||
changeSurfaceLinePropertyReset,
|
changeSurfaceLinePropertyReset,
|
||||||
|
changeSurfaceLineType,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -81,9 +81,9 @@ export function useContextMenu() {
|
|||||||
switch (selectedMenu) {
|
switch (selectedMenu) {
|
||||||
case 'outline':
|
case 'outline':
|
||||||
break
|
break
|
||||||
default:
|
// default:
|
||||||
setContextMenu([])
|
// setContextMenu([])
|
||||||
break
|
// break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -79,6 +79,9 @@ export function useEvent() {
|
|||||||
// 마우스 위치 기준으로 확대/축소
|
// 마우스 위치 기준으로 확대/축소
|
||||||
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom)
|
canvas.zoomToPoint({ x: opt.e.offsetX, y: opt.e.offsetY }, zoom)
|
||||||
|
|
||||||
|
canvas.requestRenderAll()
|
||||||
|
canvas.calcOffset()
|
||||||
|
|
||||||
// 이벤트의 기본 동작 방지 (스크롤 방지)
|
// 이벤트의 기본 동작 방지 (스크롤 방지)
|
||||||
opt.e.preventDefault()
|
opt.e.preventDefault()
|
||||||
opt.e.stopPropagation()
|
opt.e.stopPropagation()
|
||||||
@ -104,6 +107,10 @@ export function useEvent() {
|
|||||||
const horizonLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'horizontal')
|
const horizonLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'horizontal')
|
||||||
const verticalLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'vertical')
|
const verticalLines = canvas.getObjects().filter((obj) => obj.name === 'lineGrid' && obj.direction === 'vertical')
|
||||||
|
|
||||||
|
if (!horizonLines || !verticalLines) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const closestHorizontalLine = horizonLines.reduce((prev, curr) => {
|
const closestHorizontalLine = horizonLines.reduce((prev, curr) => {
|
||||||
const prevDistance = calculateDistance(pointer, prev)
|
const prevDistance = calculateDistance(pointer, prev)
|
||||||
const currDistance = calculateDistance(pointer, curr)
|
const currDistance = calculateDistance(pointer, curr)
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import { compasDegAtom } from '@/store/orientationAtom'
|
|||||||
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
|
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
|
||||||
import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
|
import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
|
||||||
import { useCanvasMenu } from './common/useCanvasMenu'
|
import { useCanvasMenu } from './common/useCanvasMenu'
|
||||||
|
import { QcastContext } from '@/app/QcastProvider'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 플랜 처리 훅
|
* 플랜 처리 훅
|
||||||
@ -52,6 +53,9 @@ export function usePlan(params = {}) {
|
|||||||
const { fetchBasicSettings, basicSettingCopySave } = useCanvasSetting()
|
const { fetchBasicSettings, basicSettingCopySave } = useCanvasSetting()
|
||||||
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
||||||
|
|
||||||
|
/** 전역 로딩바 컨텍스트 */
|
||||||
|
const { setIsGlobalLoading } = useContext(QcastContext)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 플랜 복사 시 모듈이 있을경우 모듈 데이터 복사하기 위한 처리
|
* 플랜 복사 시 모듈이 있을경우 모듈 데이터 복사하기 위한 처리
|
||||||
*/
|
*/
|
||||||
@ -414,7 +418,7 @@ export function usePlan(params = {}) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedPlan(currentCanvasPlan)
|
setSelectedPlan(currentCanvasPlan)
|
||||||
handleCurrentPlanUrl()
|
handleCurrentPlanUrl()
|
||||||
resetCurrentObject()
|
// resetCurrentObject()
|
||||||
resetModuleSetupSurface()
|
resetModuleSetupSurface()
|
||||||
}, [currentCanvasPlan])
|
}, [currentCanvasPlan])
|
||||||
|
|
||||||
@ -450,13 +454,21 @@ export function usePlan(params = {}) {
|
|||||||
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 () => {
|
||||||
|
setIsGlobalLoading(true)
|
||||||
await postObjectPlan(userId, objectNo, true, false)
|
await postObjectPlan(userId, objectNo, true, false)
|
||||||
|
setIsGlobalLoading(false)
|
||||||
},
|
},
|
||||||
denyFn: async () => {
|
denyFn: async () => {
|
||||||
|
setIsGlobalLoading(true)
|
||||||
await postObjectPlan(userId, objectNo, false, false)
|
await postObjectPlan(userId, objectNo, false, false)
|
||||||
|
setIsGlobalLoading(false)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
: await postObjectPlan(userId, objectNo, false, false)
|
: async () => {
|
||||||
|
setIsGlobalLoading(true)
|
||||||
|
await postObjectPlan(userId, objectNo, false, false)
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -176,6 +176,10 @@ export const usePolygon = () => {
|
|||||||
* @param showDirectionText
|
* @param showDirectionText
|
||||||
*/
|
*/
|
||||||
const drawDirectionArrow = (polygon, showDirectionText = true) => {
|
const drawDirectionArrow = (polygon, showDirectionText = true) => {
|
||||||
|
if (!polygon) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (polygon.points.length < 3) {
|
if (polygon.points.length < 3) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -767,7 +771,7 @@ export const usePolygon = () => {
|
|||||||
obj.type === 'QLine' &&
|
obj.type === 'QLine' &&
|
||||||
obj.attributes?.type !== 'pitchSizeLine' &&
|
obj.attributes?.type !== 'pitchSizeLine' &&
|
||||||
obj.attributes?.roofId === polygon.id &&
|
obj.attributes?.roofId === polygon.id &&
|
||||||
(innerLineTypes.includes(obj.name) || !obj.name),
|
innerLineTypes.includes(obj.name),
|
||||||
)
|
)
|
||||||
|
|
||||||
innerLines = [...polygon.innerLines]
|
innerLines = [...polygon.innerLines]
|
||||||
|
|||||||
@ -37,7 +37,7 @@
|
|||||||
"modal.roof.shape.setting.patten.a": "Aパターン",
|
"modal.roof.shape.setting.patten.a": "Aパターン",
|
||||||
"modal.roof.shape.setting.patten.b": "Bパターン",
|
"modal.roof.shape.setting.patten.b": "Bパターン",
|
||||||
"modal.roof.shape.setting.side": "別に設定",
|
"modal.roof.shape.setting.side": "別に設定",
|
||||||
"plan.menu.roof.cover": "屋根作図",
|
"plan.menu.roof.cover": "伏せ図入力",
|
||||||
"plan.menu.roof.cover.outline.drawing": "外壁線を描く",
|
"plan.menu.roof.cover.outline.drawing": "外壁線を描く",
|
||||||
"plan.menu.roof.cover.roof.shape.setting": "屋根形状の設定",
|
"plan.menu.roof.cover.roof.shape.setting": "屋根形状の設定",
|
||||||
"plan.menu.roof.cover.roof.shape.passivity.setting": "屋根形状の手動設定",
|
"plan.menu.roof.cover.roof.shape.passivity.setting": "屋根形状の手動設定",
|
||||||
@ -72,7 +72,7 @@
|
|||||||
"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": "配置面の描画",
|
||||||
"modal.placement.surface.drawing.straight.line": "直線",
|
"modal.placement.surface.drawing.straight.line": "直線",
|
||||||
@ -128,7 +128,7 @@
|
|||||||
"modal.module.basic.setting.pitch.module.row.margin": "上下間隔",
|
"modal.module.basic.setting.pitch.module.row.margin": "上下間隔",
|
||||||
"modal.module.basic.setting.pitch.module.column.amount": "列数",
|
"modal.module.basic.setting.pitch.module.column.amount": "列数",
|
||||||
"modal.module.basic.setting.pitch.module.column.margin": "左右間隔",
|
"modal.module.basic.setting.pitch.module.column.margin": "左右間隔",
|
||||||
"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": "回路設定",
|
||||||
@ -178,7 +178,7 @@
|
|||||||
"modal.roof.alloc.select.parallel": "筋配置",
|
"modal.roof.alloc.select.parallel": "筋配置",
|
||||||
"modal.roof.alloc.select.stairs": "千鳥配置",
|
"modal.roof.alloc.select.stairs": "千鳥配置",
|
||||||
"modal.roof.alloc.apply": "選択した屋根材として割り当て",
|
"modal.roof.alloc.apply": "選択した屋根材として割り当て",
|
||||||
"plan.menu.estimate.docDown": "各種資料ダウンロード",
|
"plan.menu.estimate.docDownload": "見積書出力",
|
||||||
"plan.menu.estimate.save": "保存",
|
"plan.menu.estimate.save": "保存",
|
||||||
"plan.menu.estimate.reset": "初期化",
|
"plan.menu.estimate.reset": "初期化",
|
||||||
"plan.menu.estimate.copy": "見積書のコピー",
|
"plan.menu.estimate.copy": "見積書のコピー",
|
||||||
@ -558,7 +558,7 @@
|
|||||||
"board.faq.title": "FAQ",
|
"board.faq.title": "FAQ",
|
||||||
"board.faq.sub.title": "FAQリスト",
|
"board.faq.sub.title": "FAQリスト",
|
||||||
"board.archive.title": "各種資料ダウンロード",
|
"board.archive.title": "各種資料ダウンロード",
|
||||||
"board.archive.sub.title": "見積書一覧",
|
"board.archive.sub.title": "掲載資料一覧",
|
||||||
"board.list.header.rownum": "番号",
|
"board.list.header.rownum": "番号",
|
||||||
"board.list.header.title": "タイトル",
|
"board.list.header.title": "タイトル",
|
||||||
"board.list.header.regDt": "登録日",
|
"board.list.header.regDt": "登録日",
|
||||||
@ -594,6 +594,7 @@
|
|||||||
"myinfo.message.password.error": "パスワードが間違っています。",
|
"myinfo.message.password.error": "パスワードが間違っています。",
|
||||||
"login": "ログイン",
|
"login": "ログイン",
|
||||||
"login.auto.page.text": "自動ログイン中です。",
|
"login.auto.page.text": "自動ログイン中です。",
|
||||||
|
"login.fail": "アカウントが存在しないか、パスワードが間違っています。",
|
||||||
"login.id.save": "ID保存",
|
"login.id.save": "ID保存",
|
||||||
"login.id.placeholder": "IDを入力してください。",
|
"login.id.placeholder": "IDを入力してください。",
|
||||||
"login.password.placeholder": "パスワードを入力してください。",
|
"login.password.placeholder": "パスワードを入力してください。",
|
||||||
@ -886,7 +887,7 @@
|
|||||||
"estimate.detail.drawingEstimateCreateDate": "登録日",
|
"estimate.detail.drawingEstimateCreateDate": "登録日",
|
||||||
"estimate.detail.lastEditDatetime": "変更日時",
|
"estimate.detail.lastEditDatetime": "変更日時",
|
||||||
"estimate.detail.saleStoreId": "一次販売店名",
|
"estimate.detail.saleStoreId": "一次販売店名",
|
||||||
"estimate.detail.estimateDate": "見積日",
|
"estimate.detail.estimateDate": "見積作成日",
|
||||||
"estimate.detail.otherSaleStoreId": "二次販売店名",
|
"estimate.detail.otherSaleStoreId": "二次販売店名",
|
||||||
"estimate.detail.noOtherSaleStoreId": "二次店なし",
|
"estimate.detail.noOtherSaleStoreId": "二次店なし",
|
||||||
"estimate.detail.receiveUser": "担当者",
|
"estimate.detail.receiveUser": "担当者",
|
||||||
@ -957,6 +958,7 @@
|
|||||||
"estimate.detail.estimateCopyPopup.close": "閉じる",
|
"estimate.detail.estimateCopyPopup.close": "閉じる",
|
||||||
"estimate.detail.estimateCopyPopup.copyBtn": "見積コピー",
|
"estimate.detail.estimateCopyPopup.copyBtn": "見積コピー",
|
||||||
"estimate.detail.estimateCopyPopup.copy.alertMessage": "見積書がコピーされました。コピーした見積情報に移動します。",
|
"estimate.detail.estimateCopyPopup.copy.alertMessage": "見積書がコピーされました。コピーした見積情報に移動します。",
|
||||||
|
"estimate.detail.estimateCopyPopup.copy.alertMessageError": "キャンバスのコピー中にエラーが発生しました.",
|
||||||
"estimate.detail.productFeaturesPopup.title": "製品特異事項",
|
"estimate.detail.productFeaturesPopup.title": "製品特異事項",
|
||||||
"estimate.detail.productFeaturesPopup.close": "閉じる",
|
"estimate.detail.productFeaturesPopup.close": "閉じる",
|
||||||
"estimate.detail.productFeaturesPopup.requiredStoreId": "一次販売店は必須です。",
|
"estimate.detail.productFeaturesPopup.requiredStoreId": "一次販売店は必須です。",
|
||||||
@ -997,7 +999,7 @@
|
|||||||
"simulator.table.sub5": "枚数",
|
"simulator.table.sub5": "枚数",
|
||||||
"simulator.table.sub6": "合計",
|
"simulator.table.sub6": "合計",
|
||||||
"simulator.table.sub7": "パワーコンディショナー",
|
"simulator.table.sub7": "パワーコンディショナー",
|
||||||
"simulator.table.sub8": "ティーン",
|
"simulator.table.sub8": "台",
|
||||||
"simulator.table.sub9": "予測発電量(kWh)",
|
"simulator.table.sub9": "予測発電量(kWh)",
|
||||||
"simulator.notice.sub1": "ハンファジャパン年間発電量",
|
"simulator.notice.sub1": "ハンファジャパン年間発電量",
|
||||||
"simulator.notice.sub2": "シミュレーションガイド",
|
"simulator.notice.sub2": "シミュレーションガイド",
|
||||||
@ -1034,5 +1036,13 @@
|
|||||||
"roof.exceed.count": "屋根材は4つまで選択可能です。",
|
"roof.exceed.count": "屋根材は4つまで選択可能です。",
|
||||||
"outerLine.property.fix": "外壁線の属性設定 を完了しますか?",
|
"outerLine.property.fix": "外壁線の属性設定 を完了しますか?",
|
||||||
"outerLine.property.close": "外壁線の属性設定 を終了しますか?",
|
"outerLine.property.close": "外壁線の属性設定 を終了しますか?",
|
||||||
"want.to.complete.auxiliary.creation": "보補助線の作成を完了しますか?"
|
"want.to.complete.auxiliary.creation": "補助線の作成を完了しますか?",
|
||||||
|
"modal.placement.initial.setting.plan.drawing.only.number": "(※数字は[半角]入力のみ可能です。)",
|
||||||
|
"wall.line.not.found": "外壁がありません",
|
||||||
|
"roof.line.not.found": "屋根形状がありません",
|
||||||
|
"roof.material.can.not.delete": "割り当てられた配置面があります。",
|
||||||
|
"chidory.can.not.install": "千鳥配置できない工法です。",
|
||||||
|
"module.layout.setup.max.count": "모듈의 최대 단수는 {0}, 최대 열수는 {1} 입니다. (JA)",
|
||||||
|
"module.layout.setup.max.count.multiple": "모듈 {0}번의 최대 단수는 {1}, 최대 열수는 {2} 입니다. (JA)",
|
||||||
|
"roofAllocation.not.found": "할당할 지붕이 없습니다. (JA)"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -178,7 +178,7 @@
|
|||||||
"modal.roof.alloc.select.parallel": "병렬식",
|
"modal.roof.alloc.select.parallel": "병렬식",
|
||||||
"modal.roof.alloc.select.stairs": "계단식",
|
"modal.roof.alloc.select.stairs": "계단식",
|
||||||
"modal.roof.alloc.apply": "선택한 지붕재로 할당",
|
"modal.roof.alloc.apply": "선택한 지붕재로 할당",
|
||||||
"plan.menu.estimate.docDown": "문서 다운로드",
|
"plan.menu.estimate.docDownload": "문서 다운로드",
|
||||||
"plan.menu.estimate.save": "저장",
|
"plan.menu.estimate.save": "저장",
|
||||||
"plan.menu.estimate.reset": "초기화",
|
"plan.menu.estimate.reset": "초기화",
|
||||||
"plan.menu.estimate.copy": "견적서 복사",
|
"plan.menu.estimate.copy": "견적서 복사",
|
||||||
@ -594,6 +594,7 @@
|
|||||||
"myinfo.message.password.error": "비밀번호가 틀렸습니다.",
|
"myinfo.message.password.error": "비밀번호가 틀렸습니다.",
|
||||||
"login": "로그인",
|
"login": "로그인",
|
||||||
"login.auto.page.text": "자동로그인 중 입니다.",
|
"login.auto.page.text": "자동로그인 중 입니다.",
|
||||||
|
"login.fail": "계정이 없거나 비밀번호가 잘못되었습니다.",
|
||||||
"login.id.save": "ID Save",
|
"login.id.save": "ID Save",
|
||||||
"login.id.placeholder": "아이디를 입력해주세요.",
|
"login.id.placeholder": "아이디를 입력해주세요.",
|
||||||
"login.password.placeholder": "비밀번호를 입력해주세요.",
|
"login.password.placeholder": "비밀번호를 입력해주세요.",
|
||||||
@ -886,7 +887,7 @@
|
|||||||
"estimate.detail.drawingEstimateCreateDate": "등록일",
|
"estimate.detail.drawingEstimateCreateDate": "등록일",
|
||||||
"estimate.detail.lastEditDatetime": "변경일시",
|
"estimate.detail.lastEditDatetime": "변경일시",
|
||||||
"estimate.detail.saleStoreId": "1차 판매점명",
|
"estimate.detail.saleStoreId": "1차 판매점명",
|
||||||
"estimate.detail.estimateDate": "견적일",
|
"estimate.detail.estimateDate": "견적작성일",
|
||||||
"estimate.detail.otherSaleStoreId": "2차 판매점명",
|
"estimate.detail.otherSaleStoreId": "2차 판매점명",
|
||||||
"estimate.detail.noOtherSaleStoreId": "2차점 없음",
|
"estimate.detail.noOtherSaleStoreId": "2차점 없음",
|
||||||
"estimate.detail.receiveUser": "담당자",
|
"estimate.detail.receiveUser": "담당자",
|
||||||
@ -957,6 +958,7 @@
|
|||||||
"estimate.detail.estimateCopyPopup.close": "닫기",
|
"estimate.detail.estimateCopyPopup.close": "닫기",
|
||||||
"estimate.detail.estimateCopyPopup.copyBtn": "견적복사",
|
"estimate.detail.estimateCopyPopup.copyBtn": "견적복사",
|
||||||
"estimate.detail.estimateCopyPopup.copy.alertMessage": "견적서가 복사되었습니다. 복사된 물건정보로 이동합니다.",
|
"estimate.detail.estimateCopyPopup.copy.alertMessage": "견적서가 복사되었습니다. 복사된 물건정보로 이동합니다.",
|
||||||
|
"estimate.detail.estimateCopyPopup.copy.alertMessageError": "캔버스 복사 중 오류 발생.",
|
||||||
"estimate.detail.productFeaturesPopup.title": "제품특이사항",
|
"estimate.detail.productFeaturesPopup.title": "제품특이사항",
|
||||||
"estimate.detail.productFeaturesPopup.close": "닫기",
|
"estimate.detail.productFeaturesPopup.close": "닫기",
|
||||||
"estimate.detail.productFeaturesPopup.requiredStoreId": "1차 판매점은 필수값 입니다.",
|
"estimate.detail.productFeaturesPopup.requiredStoreId": "1차 판매점은 필수값 입니다.",
|
||||||
@ -1034,5 +1036,13 @@
|
|||||||
"roof.exceed.count": "지붕재는 4개까지 선택 가능합니다.",
|
"roof.exceed.count": "지붕재는 4개까지 선택 가능합니다.",
|
||||||
"outerLine.property.fix": "외벽선 속성 설정을 완료하시겠습니까?",
|
"outerLine.property.fix": "외벽선 속성 설정을 완료하시겠습니까?",
|
||||||
"outerLine.property.close": "외벽선 속성 설정을 종료하시겠습니까?",
|
"outerLine.property.close": "외벽선 속성 설정을 종료하시겠습니까?",
|
||||||
"want.to.complete.auxiliary.creation": "보조선 작성을 완료하시겠습니까?"
|
"want.to.complete.auxiliary.creation": "보조선 작성을 완료하시겠습니까?",
|
||||||
|
"modal.placement.initial.setting.plan.drawing.only.number": "(※ 숫자는 [반각]입력만 가능합니다.)",
|
||||||
|
"wall.line.not.found": "외벽선이 없습니다.",
|
||||||
|
"roof.line.not.found": "지붕형상이 없습니다.",
|
||||||
|
"roof.material.can.not.delete": "할당된 배치면이 있습니다.",
|
||||||
|
"chidory.can.not.install": "치조 불가 공법입니다.",
|
||||||
|
"module.layout.setup.max.count": "모듈의 최대 단수는 {0}, 최대 열수는 {1} 입니다.",
|
||||||
|
"module.layout.setup.max.count.multiple": "모듈 {0}번의 최대 단수는 {1}, 최대 열수는 {2} 입니다.",
|
||||||
|
"roofAllocation.not.found": "할당할 지붕이 없습니다."
|
||||||
}
|
}
|
||||||
|
|||||||
6
src/store/hotkeyAtom.js
Normal file
6
src/store/hotkeyAtom.js
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { atom } from 'recoil'
|
||||||
|
|
||||||
|
export const hotkeyStore = atom({
|
||||||
|
key: 'hotkeyState',
|
||||||
|
default: [],
|
||||||
|
})
|
||||||
@ -348,15 +348,15 @@ export const calculateIntersection = (line1, line2) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Determine the min and max for line1 and line2 for both x and y
|
// Determine the min and max for line1 and line2 for both x and y
|
||||||
const line1MinX = Math.min(line1.x1, line1.x2)
|
const line1MinX = Math.min(line1.x1, line1.x2) - 5
|
||||||
const line1MaxX = Math.max(line1.x1, line1.x2)
|
const line1MaxX = Math.max(line1.x1, line1.x2) + 5
|
||||||
const line2MinX = Math.min(line2.x1, line2.x2)
|
const line2MinX = Math.min(line2.x1, line2.x2) - 5
|
||||||
const line2MaxX = Math.max(line2.x1, line2.x2)
|
const line2MaxX = Math.max(line2.x1, line2.x2) + 5
|
||||||
|
|
||||||
const line1MinY = Math.min(line1.y1, line1.y2)
|
const line1MinY = Math.min(line1.y1, line1.y2) - 5
|
||||||
const line1MaxY = Math.max(line1.y1, line1.y2)
|
const line1MaxY = Math.max(line1.y1, line1.y2) + 5
|
||||||
const line2MinY = Math.min(line2.y1, line2.y2)
|
const line2MinY = Math.min(line2.y1, line2.y2) - 5
|
||||||
const line2MaxY = Math.max(line2.y1, line2.y2)
|
const line2MaxY = Math.max(line2.y1, line2.y2) + 5
|
||||||
|
|
||||||
// Check if the intersection X and Y are within the range of both lines
|
// Check if the intersection X and Y are within the range of both lines
|
||||||
if (
|
if (
|
||||||
@ -518,14 +518,23 @@ export const sortedPointLessEightPoint = (points) => {
|
|||||||
*/
|
*/
|
||||||
// 직선의 방정식.
|
// 직선의 방정식.
|
||||||
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
|
||||||
export function isPointOnLine(line, point) {
|
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }) {
|
||||||
const a = line.y2 - line.y1
|
/*const a = line.y2 - line.y1
|
||||||
const b = line.x1 - line.x2
|
const b = line.x1 - line.x2
|
||||||
const c = line.x2 * line.y1 - line.x1 * line.y2
|
const c = line.x2 * line.y1 - line.x1 * line.y2
|
||||||
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
||||||
|
|
||||||
// 점이 선 위에 있는지 확인
|
// 점이 선 위에 있는지 확인
|
||||||
return result <= 10
|
return result <= 10*/
|
||||||
|
// 직선 방정식 만족 여부 확인
|
||||||
|
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
|
||||||
|
if (Math.abs(crossProduct) > 5) return false // 작은 오차 허용
|
||||||
|
|
||||||
|
// 점이 선분의 범위 내에 있는지 확인
|
||||||
|
const withinXRange = Math.min(x1, x2) <= x && x <= Math.max(x1, x2)
|
||||||
|
const withinYRange = Math.min(y1, y2) <= y && y <= Math.max(y1, y2)
|
||||||
|
|
||||||
|
return withinXRange && withinYRange
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* 점과 가까운 line 찾기
|
* 점과 가까운 line 찾기
|
||||||
|
|||||||
@ -305,6 +305,9 @@ export function removeDuplicatePolygons(polygons) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const isSamePoint = (a, b) => {
|
export const isSamePoint = (a, b) => {
|
||||||
|
if (!a || !b) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2
|
return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
var exec = require('child_process').exec
|
var exec = require('child_process').exec
|
||||||
exec('yarn start', { windowsHide: true })
|
exec('yarn dev', { windowsHide: true })
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user