Merge branch 'dev' of https://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into dev
This commit is contained in:
commit
f65c34a7ad
@ -3,7 +3,6 @@
|
||||
import { createContext, useEffect, useState } from 'react'
|
||||
import { ErrorBoundary } from 'next/dist/client/components/error-boundary'
|
||||
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import ServerError from './error'
|
||||
|
||||
import '@/styles/common.scss'
|
||||
@ -19,7 +18,6 @@ export const QcastContext = createContext({
|
||||
export const QcastProvider = ({ children }) => {
|
||||
const [planSave, setPlanSave] = useState(false)
|
||||
const [isGlobalLoading, setIsGlobalLoading] = useState(false)
|
||||
const { currentCanvasPlan, modifiedPlans, checkUnsavedCanvasPlan } = usePlan()
|
||||
const { commonCode, findCommonCode } = useCommonCode()
|
||||
|
||||
const [qcastState, setQcastState] = useState({
|
||||
@ -30,16 +28,6 @@ export const QcastProvider = ({ children }) => {
|
||||
businessChargerMail: null,
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
const targetElement = document.getElementById('canvas')
|
||||
if (!targetElement && currentCanvasPlan?.id && planSave) {
|
||||
setPlanSave((prev) => !prev)
|
||||
checkUnsavedCanvasPlan()
|
||||
} else if (targetElement && currentCanvasPlan?.id) {
|
||||
setPlanSave(true)
|
||||
}
|
||||
}, [modifiedPlans])
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log('commonCode', commonCode)
|
||||
// console.log(findCommonCode(113600))
|
||||
|
||||
@ -36,7 +36,7 @@ export default function Playground() {
|
||||
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
|
||||
const { getMessage } = useMessage()
|
||||
const { swalFire } = useSwal()
|
||||
const { getRoofMaterialList, getModuleTypeItemList } = useMasterController()
|
||||
const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController()
|
||||
|
||||
const [color, setColor] = useState('#ff0000')
|
||||
|
||||
@ -154,6 +154,41 @@ export default function Playground() {
|
||||
console.log('users:', users)
|
||||
}, [users])
|
||||
|
||||
const trestleData = [{ moduleTpCd: '1', roofMatlCd: '2', raftBaseCd: '', trestleMkrCd: '4', constMthdCd: '', roofBaseCd: '6' }]
|
||||
const constructionData = [
|
||||
{
|
||||
moduleTpCd: '',
|
||||
roofMatlCd: '',
|
||||
trestleMkrCd: '',
|
||||
constMthdCd: '',
|
||||
roofBaseCd: '',
|
||||
illuminationTp: '',
|
||||
instHt: '',
|
||||
stdWindSpeed: '',
|
||||
stdSnowLd: '',
|
||||
inclCd: '',
|
||||
raftBaseCd: '',
|
||||
roofPitch: 0,
|
||||
},
|
||||
]
|
||||
const trestleDetailData = [
|
||||
{
|
||||
moduleTpCd: '',
|
||||
roofMatlCd: '',
|
||||
trestleMkrCd: '',
|
||||
constMthdCd: '',
|
||||
roofBaseCd: '',
|
||||
illuminationTp: '',
|
||||
instHt: '',
|
||||
stdWindSpeed: '',
|
||||
stdSnowLd: '',
|
||||
inclCd: '',
|
||||
constTp: '',
|
||||
mixMatlNo: 0,
|
||||
roofPitch: 0,
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="container mx-auto p-4 m-4 border">
|
||||
@ -166,7 +201,7 @@ export default function Playground() {
|
||||
}}
|
||||
>
|
||||
지붕재 목록 조회 API 호출
|
||||
</button>
|
||||
</button>{' '}
|
||||
<button
|
||||
className="btn-frame deepgray"
|
||||
onClick={() => {
|
||||
@ -174,8 +209,33 @@ export default function Playground() {
|
||||
}}
|
||||
>
|
||||
모듈 타입별 아이템 목록 조회 API 호출
|
||||
</button>{' '}
|
||||
<button
|
||||
className="btn-frame deepgray"
|
||||
onClick={() => {
|
||||
getTrestleList(trestleData)
|
||||
}}
|
||||
>
|
||||
가대 목록 조회 API 호출
|
||||
</button>{' '}
|
||||
<button
|
||||
className="btn-frame deepgray"
|
||||
onClick={() => {
|
||||
getConstructionList(constructionData)
|
||||
}}
|
||||
>
|
||||
시공법 목록 조회 API 호출
|
||||
</button>{' '}
|
||||
<button
|
||||
className="btn-frame deepgray"
|
||||
onClick={() => {
|
||||
getTrestleDetailList(trestleDetailData)
|
||||
}}
|
||||
>
|
||||
가대 상세 조회 API 호출
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="m-2">
|
||||
<button
|
||||
className="btn-frame deepgray"
|
||||
|
||||
@ -188,7 +188,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
||||
|
||||
// 보조선 그리기
|
||||
drawHelpLine() {
|
||||
// drawHelpLineInHexagon(this, pitch)
|
||||
const types = []
|
||||
this.lines.forEach((line) => types.push(line.attributes.type))
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ export default function CanvasFrame() {
|
||||
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
|
||||
const currentMenu = useRecoilValue(currentMenuState)
|
||||
const { contextMenu, handleClick } = useContextMenu()
|
||||
const { selectedPlan, modifiedPlanFlag, checkCanvasObjectEvent, resetModifiedPlans, currentCanvasPlan } = usePlan()
|
||||
const { selectedPlan, currentCanvasPlan } = usePlan()
|
||||
const totalDisplay = useRecoilValue(totalDisplaySelector) // 집계표 표시 여부
|
||||
// useEvent()
|
||||
// const { initEvent } = useContext(EventContext)
|
||||
@ -41,21 +41,8 @@ export default function CanvasFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (modifiedPlanFlag && selectedPlan?.id) {
|
||||
checkCanvasObjectEvent(selectedPlan.id)
|
||||
}
|
||||
}, [modifiedPlanFlag])
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
resetModifiedPlans()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
loadCanvas()
|
||||
resetModifiedPlans()
|
||||
}, [selectedPlan, canvas])
|
||||
|
||||
return (
|
||||
|
||||
@ -20,7 +20,7 @@ export default function CanvasLayout({ children }) {
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { swalFire } = useSwal()
|
||||
const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
const { plans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
|
||||
useEffect(() => {
|
||||
loadCanvasPlanData(session.userId, objectNo, pid)
|
||||
@ -36,10 +36,7 @@ export default function CanvasLayout({ children }) {
|
||||
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
|
||||
onClick={() => handleCurrentPlan(plan.id)}
|
||||
>
|
||||
<span>
|
||||
{`Plan ${plan.ordering}`}
|
||||
{modifiedPlans.some((modifiedPlan) => modifiedPlan === plan.id) && ' [ M ]'}
|
||||
</span>
|
||||
<span>{`Plan ${plan.ordering}`}</span>
|
||||
<i
|
||||
className="close"
|
||||
onClick={(e) =>
|
||||
@ -56,7 +53,12 @@ export default function CanvasLayout({ children }) {
|
||||
))}
|
||||
</div>
|
||||
{plans.length < 10 && (
|
||||
<button className="plane-add" onClick={() => handleAddPlan(session.userId, objectNo)}>
|
||||
<button
|
||||
className="plane-add"
|
||||
onClick={async () => {
|
||||
await handleAddPlan(session.userId, objectNo)
|
||||
}}
|
||||
>
|
||||
<span></span>
|
||||
</button>
|
||||
)}
|
||||
|
||||
@ -41,6 +41,7 @@ import { pwrGnrSimTypeState } from '@/store/simulatorAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||
|
||||
export default function CanvasMenu(props) {
|
||||
const { menuNumber, setMenuNumber } = props
|
||||
@ -78,6 +79,9 @@ export default function CanvasMenu(props) {
|
||||
const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
|
||||
const { restoreModuleInstArea } = useModuleBasicSetting()
|
||||
|
||||
//견적서버튼 노출용
|
||||
const [buttonStyle, setButtonStyle] = useState('')
|
||||
|
||||
const onClickNav = (menu) => {
|
||||
setMenuNumber(menu.index)
|
||||
setCurrentMenu(menu.title)
|
||||
@ -241,6 +245,16 @@ export default function CanvasMenu(props) {
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (isObjectNotEmpty(estimateRecoilState)) {
|
||||
if (estimateRecoilState?.createUser === 'T01') {
|
||||
if (sessionState.userId !== 'T01') {
|
||||
setButtonStyle('none')
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [estimateRecoilState])
|
||||
|
||||
return (
|
||||
<div className={`canvas-menu-wrap ${[2, 3, 4].some((num) => num === menuNumber) ? 'active' : ''}`}>
|
||||
<div className="canvas-menu-inner">
|
||||
@ -320,11 +334,12 @@ export default function CanvasMenu(props) {
|
||||
<span className="ico ico01"></span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
|
||||
</button>
|
||||
<button className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||
<button style={{ display: buttonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||
<span className="ico ico02"></span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.save')}</span>
|
||||
</button>
|
||||
<button
|
||||
style={{ display: buttonStyle }}
|
||||
className="btn-frame gray ico-flx"
|
||||
onClick={() => {
|
||||
handleEstimateReset()
|
||||
@ -345,7 +360,7 @@ export default function CanvasMenu(props) {
|
||||
<span className="name">{getMessage('plan.menu.estimate.copy')}</span>
|
||||
</button>
|
||||
)}
|
||||
<button className="btn-frame gray ico-flx">
|
||||
<button style={{ display: buttonStyle }} className="btn-frame gray ico-flx">
|
||||
<span className="ico ico05"></span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.unLock')}</span>
|
||||
</button>
|
||||
|
||||
@ -10,7 +10,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { useRecoilValue, useSetRecoilState, useResetRecoilState, useRecoilState } from 'recoil'
|
||||
import { useRecoilValue, useSetRecoilState, useResetRecoilState } from 'recoil'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import FindAddressPop from './popup/FindAddressPop'
|
||||
import PlanRequestPop from './popup/PlanRequestPop'
|
||||
@ -41,7 +41,6 @@ export default function StuffDetail() {
|
||||
const { session } = useContext(SessionContext)
|
||||
|
||||
const router = useRouter()
|
||||
const pathname = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
const { getMessage } = useMessage()
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import { useContext, useEffect } from 'react'
|
||||
import { useState, useContext, useEffect } from 'react'
|
||||
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
@ -11,20 +11,37 @@ import { useSetRecoilState } from 'recoil'
|
||||
import { QcastContext } from '@/app/QcastProvider'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { queryStringFormatter } from '@/util/common-utils'
|
||||
import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
|
||||
import { ManagementContext } from '@/app/management/ManagementProvider'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
|
||||
export default function StuffSubHeader({ type }) {
|
||||
const { getMessage } = useMessage()
|
||||
const router = useRouter()
|
||||
const { session } = useContext(SessionContext)
|
||||
|
||||
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState)
|
||||
|
||||
const { isGlobalLoading } = useContext(QcastContext)
|
||||
|
||||
const { managementState } = useContext(ManagementContext)
|
||||
|
||||
const [buttonStyle, setButtonStyle] = useState('')
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (isObjectNotEmpty(managementState)) {
|
||||
if (managementState.createUser === 'T01') {
|
||||
if (session.userId !== 'T01') {
|
||||
setButtonStyle('none')
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [managementState])
|
||||
|
||||
const searchParams = useSearchParams()
|
||||
const objectNo = searchParams.get('objectNo') //url에서 물건번호 꺼내서 바로 set
|
||||
|
||||
@ -98,7 +115,7 @@ export default function StuffSubHeader({ type }) {
|
||||
{getMessage('stuff.temp.subTitle')}
|
||||
</Link>
|
||||
</li>
|
||||
<li className="title-item">
|
||||
<li className="title-item" style={{ display: buttonStyle }}>
|
||||
<a className="sub-header-title" onClick={moveFloorPlan}>
|
||||
<span className="icon drawing"></span>
|
||||
{getMessage('stuff.temp.subTitle2')}
|
||||
|
||||
@ -39,10 +39,6 @@ export const useCommonCode = () => {
|
||||
return resultCodes
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
findCommonCode()
|
||||
}, [globalLocale])
|
||||
|
||||
useEffect(() => {
|
||||
const getCommonCode = async () => {
|
||||
await promiseGet({ url: '/api/commcode/qc-comm-code' }).then((res) => {
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import axios from 'axios'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { getQueryString } from '@/util/common-utils'
|
||||
|
||||
/**
|
||||
* 마스터 컨트롤러 훅
|
||||
@ -7,6 +9,8 @@ import axios from 'axios'
|
||||
*/
|
||||
export function useMasterController() {
|
||||
const { get } = useAxios()
|
||||
const { getMessage } = useMessage()
|
||||
const { swalFire } = useSwal()
|
||||
|
||||
/**
|
||||
* 지붕재 목록 조회
|
||||
@ -21,11 +25,17 @@ export function useMasterController() {
|
||||
|
||||
/**
|
||||
* 모듈 타입별 아이템 목록 조회
|
||||
* @param {지붕재 코드} roofMaterialCd
|
||||
* @param {지붕재 코드} roofMatlCd
|
||||
* @returns
|
||||
*/
|
||||
const getModuleTypeItemList = async (roofMaterialCd) => {
|
||||
return await get({ url: `/api/v1/master/getModuleTypeItemList/${roofMaterialCd}` }).then((res) => {
|
||||
const getModuleTypeItemList = async (roofMatlCd) => {
|
||||
if (!roofMatlCd || roofMatlCd.trim() === '') {
|
||||
swalFire({ text: getMessage('master.moduletypeitem.message.error'), type: 'alert', icon: 'error' })
|
||||
return null
|
||||
}
|
||||
const param = { roofMatlCd: roofMatlCd }
|
||||
const paramString = getQueryString(param)
|
||||
return await get({ url: `/api/v1/master/getModuleTypeItemList${paramString}` }).then((res) => {
|
||||
console.log('🚀🚀 ~ getModuleTypeItemList ~ res:', res)
|
||||
return res
|
||||
})
|
||||
@ -33,11 +43,25 @@ export function useMasterController() {
|
||||
|
||||
/**
|
||||
* 가대 목록 조회
|
||||
* @param
|
||||
* @param {모듈타입코드} moduleTpCd
|
||||
* @param {지붕재코드} roofMatlCd
|
||||
* @param {서까래기초코드} raftBaseCd
|
||||
* @param {가대메이커코드} trestleMkrCd
|
||||
* @param {공법코드} constMthdCd
|
||||
* @param {지붕기초코드} roofBaseCd
|
||||
* @returns
|
||||
*/
|
||||
const getTrestleList = async (params) => {
|
||||
return await get({ url: `/api/v1/master/getTrestleList/${params}` }).then((res) => {
|
||||
console.log('🚀🚀 ~ getTrestleList ~ params:', params)
|
||||
params = getQueryString({
|
||||
moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '',
|
||||
roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '',
|
||||
raftBaseCd: params.raftBaseCd ? params.raftBaseCd : '',
|
||||
trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '',
|
||||
constMthdCd: params.constMthdCd ? params.constMthdCd : '',
|
||||
roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '',
|
||||
})
|
||||
return await get({ url: '/api/v1/master/getTrestleList' + params }).then((res) => {
|
||||
console.log('🚀🚀 ~ getTrestleList ~ res:', res)
|
||||
return res
|
||||
})
|
||||
@ -45,11 +69,38 @@ export function useMasterController() {
|
||||
|
||||
/**
|
||||
* 모듈 시공법 목록 조회
|
||||
* @param
|
||||
* @param {모듈타입코드} moduleTpCd
|
||||
* @param {지붕재코드} roofMatlCd
|
||||
* @param {가대메이커코드} trestleMkrCd
|
||||
* @param {공법코드} constMthdCd
|
||||
* @param {지붕기초코드} roofBaseCd
|
||||
* @param {면조도} illuminationTp
|
||||
* @param {설치높이} instHt
|
||||
* @param {풍속} stdWindSpeed
|
||||
* @param {적설량} stdSnowLd
|
||||
* @param {경사도코드} inclCd
|
||||
* @param {서까래기초코드} raftBaseCd
|
||||
* @param {하제(망둥어)피치} roofPitch
|
||||
*
|
||||
* @returns
|
||||
*/
|
||||
const getConstructionList = async (params) => {
|
||||
return await get({ url: `/api/v1/master/getConstructionList/${params}` }).then((res) => {
|
||||
console.log('🚀🚀 ~ getConstructionList ~ params:', params)
|
||||
params = getQueryString({
|
||||
moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '',
|
||||
roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '',
|
||||
trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '',
|
||||
constMthdCd: params.constMthdCd ? params.constMthdCd : '',
|
||||
roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '',
|
||||
illuminationTp: params.illuminationTp ? params.illuminationTp : '',
|
||||
instHt: params.instHt ? params.instHt : '',
|
||||
stdWindSpeed: params.stdWindSpeed ? params.stdWindSpeed : '',
|
||||
stdSnowLd: params.stdSnowLd ? params.stdSnowLd : '',
|
||||
inclCd: params.inclCd ? params.inclCd : '',
|
||||
raftBaseCd: params.raftBaseCd ? params.raftBaseCd : '',
|
||||
roofPitch: params.roofPitch ? params.roofPitch : 0,
|
||||
})
|
||||
return await get({ url: '/api/v1/master/getConstructionList' + params }).then((res) => {
|
||||
console.log('🚀🚀 ~ getConstructionList ~ res:', res)
|
||||
return res
|
||||
})
|
||||
@ -57,11 +108,39 @@ export function useMasterController() {
|
||||
|
||||
/**
|
||||
* 가대 상세 조회
|
||||
* @param
|
||||
* @param {모듈타입코드} moduleTpCd
|
||||
* @param {지붕재코드} roofMatlCd
|
||||
* @param {가대메이커코드} trestleMkrCd
|
||||
* @param {공법코드} constMthdCd
|
||||
* @param {지붕기초코드} roofBaseCd
|
||||
* @param {면조도} illuminationTp
|
||||
* @param {설치높이} instHt
|
||||
* @param {풍속} stdWindSpeed
|
||||
* @param {적설량} stdSnowLd
|
||||
* @param {경사도코드} inclCd
|
||||
* @param {시공법} constTp
|
||||
* @param {혼합모듈번호} mixMatlNo
|
||||
* @param {하제(망둥어)피치}roofPitch
|
||||
* @returns
|
||||
*/
|
||||
const getTrestleDetailList = async (params) => {
|
||||
return await get({ url: `/api/v1/master/getTrestleDetailList/${params}` }).then((res) => {
|
||||
console.log('🚀🚀 ~ getConstructionList ~ params:', params)
|
||||
params = getQueryString({
|
||||
moduleTpCd: params.moduleTpCd ? params.moduleTpCd : '',
|
||||
roofMatlCd: params.roofMatlCd ? params.roofMatlCd : '',
|
||||
trestleMkrCd: params.trestleMkrCd ? params.trestleMkrCd : '',
|
||||
constMthdCd: params.constMthdCd ? params.constMthdCd : '',
|
||||
roofBaseCd: params.roofBaseCd ? params.roofBaseCd : '',
|
||||
illuminationTp: params.illuminationTp ? params.illuminationTp : '',
|
||||
instHt: params.instHt ? params.instHt : '',
|
||||
stdWindSpeed: params.stdWindSpeed ? params.stdWindSpeed : '',
|
||||
stdSnowLd: params.stdSnowLd ? params.stdSnowLd : '',
|
||||
inclCd: params.inclCd ? params.inclCd : '',
|
||||
constTp: params.constTp ? params.constTp : '',
|
||||
mixMatlNo: params.mixMatlNo ? params.mixMatlNo : 0,
|
||||
roofPitch: params.roofPitch ? params.roofPitch : 0,
|
||||
})
|
||||
return await get({ url: '/api/v1/master/getTrestleDetailList' + params }).then((res) => {
|
||||
console.log('🚀🚀 ~ getTrestleDetailList ~ res:', res)
|
||||
return res
|
||||
})
|
||||
|
||||
@ -5,6 +5,7 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||
import { getDegreeByChon } from '@/util/canvas-util'
|
||||
|
||||
//동선이동 형 올림 내림
|
||||
export function useMovementSetting(id) {
|
||||
@ -227,6 +228,20 @@ export function useMovementSetting(id) {
|
||||
}
|
||||
})
|
||||
polygon.set({ points: newPoints })
|
||||
polygon.setCoords()
|
||||
polygon.addLengthText()
|
||||
polygon.initLines()
|
||||
const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
|
||||
const currentDegree = polygon.attributes.pitch > 0 ? getDegreeByChon(polygon.attributes.pitch) : polygon.attributes.degree
|
||||
polygon.lines.forEach((line) => {
|
||||
line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
|
||||
if (currentDegree > 0 && slope(line) !== slope(currentObject)) {
|
||||
const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
|
||||
line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
|
||||
} else {
|
||||
line.attributes.actualSize = line.attributes.planeSize
|
||||
}
|
||||
})
|
||||
})
|
||||
} else {
|
||||
roof.innerLines
|
||||
@ -239,7 +254,7 @@ export function useMovementSetting(id) {
|
||||
(line.x2 === currentX2 && line.y2 === currentY2),
|
||||
)
|
||||
.forEach((line) => {
|
||||
console.log('line : ', line)
|
||||
const lineDegree = 90 - Math.asin(line.attributes.planeSize / line.attributes.actualSize) * (180 / Math.PI)
|
||||
if (line.x1 === currentX1 && line.y1 === currentY1) {
|
||||
line.set({ x1: newPoint[0], y1: newPoint[1] })
|
||||
} else if (line.x2 === currentX1 && line.y2 === currentY1) {
|
||||
@ -250,20 +265,18 @@ export function useMovementSetting(id) {
|
||||
line.set({ x2: newPoint[2], y2: newPoint[3] })
|
||||
}
|
||||
line.setCoords()
|
||||
line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
|
||||
line.attributes.actualSize = Math.round(
|
||||
Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(line.attributes.planeSize * Math.tan(lineDegree * (Math.PI / 180)), 2)),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 })
|
||||
currentObject.setCoords()
|
||||
|
||||
console.log('currentObject : ', currentObject.x1, currentObject.y1, currentObject.x2, currentObject.y2)
|
||||
|
||||
canvas.renderAll()
|
||||
canvas.discardActiveObject()
|
||||
|
||||
if (roof.separatePolygon.length > 0) {
|
||||
console.log('roof.separatePolygon : ', roof.separatePolygon)
|
||||
}
|
||||
}
|
||||
|
||||
//형 올림내림 마우스 클릭 이벤트
|
||||
|
||||
@ -3,7 +3,6 @@ import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { canvasSizeState, canvasState, canvasZoomState, currentObjectState } from '@/store/canvasAtom'
|
||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
import { fontSelector } from '@/store/fontAtom'
|
||||
|
||||
// 캔버스에 필요한 이벤트
|
||||
@ -14,7 +13,6 @@ export function useCanvasEvent() {
|
||||
const canvasSize = useRecoilValue(canvasSizeState)
|
||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
||||
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
||||
|
||||
useEffect(() => {
|
||||
canvas?.setZoom(canvasZoom / 100)
|
||||
@ -40,10 +38,6 @@ export function useCanvasEvent() {
|
||||
onChange: (e) => {
|
||||
const target = e.target
|
||||
|
||||
if (target.name !== 'mouseLine' && !modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target) {
|
||||
// settleDown(target)
|
||||
}
|
||||
@ -58,10 +52,6 @@ export function useCanvasEvent() {
|
||||
target.uuid = uuidv4()
|
||||
}
|
||||
|
||||
if (target.name !== 'mouseLine' && !modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target.type === 'QPolygon' || target.type === 'QLine') {
|
||||
const textObjs = canvas?.getObjects().filter((obj) => obj.name === 'lengthText')
|
||||
textObjs.forEach((obj) => {
|
||||
@ -164,9 +154,6 @@ export function useCanvasEvent() {
|
||||
|
||||
target.on('moving', (e) => {
|
||||
target.uuid = uuidv4()
|
||||
if (!modifiedPlanFlag) {
|
||||
setModifiedPlanFlag((prev) => !prev)
|
||||
}
|
||||
|
||||
if (target.parentDirection === 'left' || target.parentDirection === 'right') {
|
||||
const minX = target.minX
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { canvasState, currentCanvasPlanState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom'
|
||||
import { canvasState, currentCanvasPlanState, plansState } from '@/store/canvasAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
@ -12,14 +12,11 @@ import { useCanvas } from '@/hooks/useCanvas'
|
||||
export function usePlan() {
|
||||
const [planNum, setPlanNum] = useState(0)
|
||||
const [selectedPlan, setSelectedPlan] = useState(null)
|
||||
const [currentCanvasStatus, setCurrentCanvasStatus] = useState(null)
|
||||
|
||||
const [canvas, setCanvas] = useRecoilState(canvasState)
|
||||
|
||||
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
const [plans, setPlans] = useRecoilState(plansState) // 전체 plan
|
||||
const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan
|
||||
const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag
|
||||
|
||||
const { swalFire } = useSwal()
|
||||
const { getMessage } = useMessage()
|
||||
@ -95,64 +92,6 @@ export function usePlan() {
|
||||
return addCanvas()
|
||||
}
|
||||
|
||||
/**
|
||||
* 캔버스에서 발생하는 실시간 오브젝트 이벤트를 감지하여 수정 여부를 확인 후 관리
|
||||
*/
|
||||
const checkCanvasObjectEvent = (planId) => {
|
||||
setCurrentCanvasStatus(currentCanvasData())
|
||||
if (!modifiedPlans.some((modifiedPlan) => modifiedPlan === planId) && checkModifiedCanvasPlan(planId)) {
|
||||
setModifiedPlans((prev) => [...prev, planId])
|
||||
setModifiedPlanFlag(false)
|
||||
}
|
||||
}
|
||||
useEffect(() => {
|
||||
if (currentCanvasStatus) {
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus }))
|
||||
}
|
||||
}, [currentCanvasStatus])
|
||||
|
||||
/**
|
||||
* 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단
|
||||
*/
|
||||
const checkModifiedCanvasPlan = (planId) => {
|
||||
const planData = plans.find((plan) => plan.id === planId)
|
||||
if (planData.canvasStatus === '') {
|
||||
// 빈 상태로 저장된 캔버스
|
||||
return true
|
||||
}
|
||||
|
||||
// 각각 object들의 uuid 목록을 추출하여 비교
|
||||
const canvasStatus = currentCanvasData()
|
||||
const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects)
|
||||
const dbObjsUuids = getObjectUuids(JSON.parse(planData.canvasStatus).objects)
|
||||
return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index])
|
||||
}
|
||||
const getObjectUuids = (objects) => {
|
||||
return objects
|
||||
.filter((obj) => obj.hasOwnProperty('uuid'))
|
||||
.map((obj) => obj.uuid)
|
||||
.sort()
|
||||
}
|
||||
|
||||
const resetModifiedPlans = () => {
|
||||
setModifiedPlans([])
|
||||
setModifiedPlanFlag(false)
|
||||
}
|
||||
|
||||
/**
|
||||
* 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 후 저장
|
||||
*/
|
||||
const checkUnsavedCanvasPlan = async () => {
|
||||
swalFire({
|
||||
text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.save.modified'),
|
||||
type: 'confirm',
|
||||
confirmFn: async () => {
|
||||
await putCanvasStatus(currentCanvasPlan.canvasStatus)
|
||||
},
|
||||
})
|
||||
resetModifiedPlans()
|
||||
}
|
||||
|
||||
/**
|
||||
* DB에 저장된 데이터를 canvas에서 사용할 수 있도록 포맷화
|
||||
*/
|
||||
@ -206,8 +145,8 @@ export function usePlan() {
|
||||
}
|
||||
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
|
||||
.then((res) => {
|
||||
setPlans([...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }])
|
||||
handleCurrentPlan(res.data)
|
||||
setPlans((plans) => [...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }])
|
||||
updateCurrentPlan(res.data)
|
||||
setPlanNum(planNum + 1)
|
||||
})
|
||||
.catch((error) => {
|
||||
@ -228,7 +167,6 @@ export function usePlan() {
|
||||
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
|
||||
.then((res) => {
|
||||
setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
})
|
||||
.catch((error) => {
|
||||
swalFire({ text: error.message, icon: 'error' })
|
||||
@ -251,13 +189,11 @@ export function usePlan() {
|
||||
|
||||
/**
|
||||
* plan 이동
|
||||
* 현재 plan의 작업상태를 확인, 저장 후 이동
|
||||
* 현재 plan의 작업상태를 저장 후 이동
|
||||
*/
|
||||
const handleCurrentPlan = async (newCurrentId) => {
|
||||
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
|
||||
if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) {
|
||||
await saveCanvas()
|
||||
}
|
||||
await saveCanvas()
|
||||
updateCurrentPlan(newCurrentId)
|
||||
}
|
||||
}
|
||||
@ -281,9 +217,12 @@ export function usePlan() {
|
||||
|
||||
/**
|
||||
* 새로운 plan 생성
|
||||
* 현재 plan의 데이터가 있을 경우 복제 여부를 확인
|
||||
* 현재 plan의 데이터가 있을 경우 현재 plan 저장 및 복제 여부를 확인
|
||||
*/
|
||||
const handleAddPlan = async (userId, objectNo) => {
|
||||
if (currentCanvasPlan?.id) {
|
||||
await saveCanvas()
|
||||
}
|
||||
JSON.parse(currentCanvasData()).objects.length > 0
|
||||
? swalFire({
|
||||
text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.copy'),
|
||||
@ -324,7 +263,6 @@ export function usePlan() {
|
||||
await delCanvasById(id)
|
||||
.then((res) => {
|
||||
setPlans((plans) => plans.filter((plan) => plan.id !== id))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
removeImage(currentCanvasPlan.id)
|
||||
swalFire({ text: getMessage('plan.message.delete') })
|
||||
})
|
||||
@ -362,14 +300,6 @@ export function usePlan() {
|
||||
canvas,
|
||||
plans,
|
||||
selectedPlan,
|
||||
currentCanvasPlan,
|
||||
setCurrentCanvasPlan,
|
||||
modifiedPlans,
|
||||
modifiedPlanFlag,
|
||||
setModifiedPlanFlag,
|
||||
checkCanvasObjectEvent,
|
||||
checkUnsavedCanvasPlan,
|
||||
resetModifiedPlans,
|
||||
saveCanvas,
|
||||
handleCurrentPlan,
|
||||
handleAddPlan,
|
||||
|
||||
@ -295,7 +295,6 @@
|
||||
"modal.actual.size.setting.plane.size.length": "廊下の寸法の長さ",
|
||||
"modal.actual.size.setting.actual.size.length": "実寸長",
|
||||
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
|
||||
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
|
||||
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
|
||||
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
|
||||
"plan.message.save": "저장되었습니다.",
|
||||
@ -932,5 +931,6 @@
|
||||
"simulator.table.sub8": "台",
|
||||
"simulator.table.sub9": "予測発電量 (kWh)",
|
||||
"simulator.notice.sub1": "Hanwha Japan 年間発電量",
|
||||
"simulator.notice.sub2": "シミュレーション案内事項"
|
||||
"simulator.notice.sub2": "シミュレーション案内事項",
|
||||
"master.moduletypeitem.message.error": "지붕재 코드를 입력하세요."
|
||||
}
|
||||
|
||||
@ -300,7 +300,6 @@
|
||||
"modal.actual.size.setting.plane.size.length": "복도치수 길이",
|
||||
"modal.actual.size.setting.actual.size.length": "실제치수 길이",
|
||||
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
|
||||
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
|
||||
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
|
||||
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
|
||||
"plan.message.save": "저장되었습니다.",
|
||||
@ -942,5 +941,6 @@
|
||||
"simulator.table.sub8": "대",
|
||||
"simulator.table.sub9": "예측발전량 (kWh)",
|
||||
"simulator.notice.sub1": "Hanwha Japan 연간 발전량",
|
||||
"simulator.notice.sub2": "시뮬레이션 안내사항"
|
||||
"simulator.notice.sub2": "시뮬레이션 안내사항",
|
||||
"master.moduletypeitem.message.error": "지붕재 코드를 입력하세요."
|
||||
}
|
||||
|
||||
@ -272,17 +272,6 @@ export const plansState = atom({
|
||||
default: [],
|
||||
})
|
||||
|
||||
// 변경된 canvas plan 목록
|
||||
export const modifiedPlansState = atom({
|
||||
key: 'modifiedPlansState',
|
||||
default: [],
|
||||
})
|
||||
// 변경감지 flag
|
||||
export const modifiedPlanFlagState = atom({
|
||||
key: 'modifiedPlanFlagState',
|
||||
default: false,
|
||||
})
|
||||
|
||||
export const tempGridModeState = atom({
|
||||
key: 'tempGridModeState',
|
||||
default: false,
|
||||
|
||||
@ -1,84 +1,84 @@
|
||||
.test {
|
||||
background-color: #797979;
|
||||
font: 30px sans-serif;
|
||||
font-style: italic;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.grid-container2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr); /* 2개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr); /* 3개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr); /* 4개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container5 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr); /* 5개의 열 */
|
||||
grid-template-rows: repeat(5, 30px); /* 5개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 0px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid black; /* 그리드 외각선 */
|
||||
text-align: center; /* 그리드 내 가운데 정렬 */
|
||||
}
|
||||
|
||||
.grid-item2 {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.grid-item3 {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid #000;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.grid-item.Y {
|
||||
background-color: #d3d0d0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.N {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.selected {
|
||||
background-color: #d3d0d0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.unselected {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
.test {
|
||||
background-color: #797979;
|
||||
font: 30px sans-serif;
|
||||
font-style: italic;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.grid-container2 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr); /* 2개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container3 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr); /* 3개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container4 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr); /* 4개의 열 */
|
||||
grid-template-rows: repeat(6, 30px); /* 6개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 5px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-container5 {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(5, 1fr); /* 5개의 열 */
|
||||
grid-template-rows: repeat(5, 30px); /* 5개의 행 */
|
||||
justify-items: center; /* 각 그리드 아이템을 수평 가운데 정렬 */
|
||||
align-items: center; /* 각 그리드 아이템을 수직 가운데 정렬 */
|
||||
gap: 0px; /* 그리드 아이템 사이의 간격 */
|
||||
}
|
||||
|
||||
.grid-item {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: 1px solid black; /* 그리드 외각선 */
|
||||
text-align: center; /* 그리드 내 가운데 정렬 */
|
||||
}
|
||||
|
||||
.grid-item2 {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid #000;
|
||||
}
|
||||
|
||||
.grid-item3 {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border: 1px solid #000;
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.grid-item.Y {
|
||||
background-color: #d3d0d0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.N {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.selected {
|
||||
background-color: #d3d0d0;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.grid-item.unselected {
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
@ -117,3 +117,15 @@ export const calculateFlowDirection = (canvasAngle) => {
|
||||
right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 자바스크립트 객체로 쿼리스트링 생성
|
||||
* @param {javascript object} o 쿼리스트링 생성할 객체
|
||||
* @returns {string} 쿼리스트링
|
||||
*/
|
||||
export const getQueryString = (o) => {
|
||||
const queryString = Object.keys(o)
|
||||
.map((key) => `${key}=${o[key]}`)
|
||||
.join('&')
|
||||
return `?${queryString}`
|
||||
}
|
||||
|
||||
@ -1109,7 +1109,6 @@ const drawHips = (roof, canvas) => {
|
||||
const vectorX2 = ridgeCoordinate.x1 - currentRoof.x2
|
||||
const vectorY2 = ridgeCoordinate.y1 - currentRoof.y2
|
||||
const angle2 = Math.atan2(vectorY2, vectorX2) * (180 / Math.PI)
|
||||
console.log('angle2', Math.abs(Math.round(angle2)) % 45)
|
||||
if (Math.abs(Math.round(angle2)) % 45 === 0) {
|
||||
const hip2 = new QLine([currentRoof.x2, currentRoof.y2, ridgeCoordinate.x1, ridgeCoordinate.y1], {
|
||||
fontSize: roof.fontSize,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user