+
num === menuNumber) ? 'active' : ''}`}>
{canvasMenus.map((menu) => {
@@ -205,11 +209,12 @@ export default function CanvasMenu(props) {
key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => {
- if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2) return
+ if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) return
+ if (menuNumber === 4 && menu.index === 2) return
onClickNav(menu)
}}
>
-
- {menuNumber !== 6 && menuNumber !== 5 && (
+ {![5, 6].some((num) => num === menuNumber) && (
<>
{
@@ -248,7 +253,7 @@ export default function CanvasMenu(props) {
handleZoom(false)
}}
>
- {canvasZoom}%
+ {canvasZoom}%
{
@@ -314,8 +319,8 @@ export default function CanvasMenu(props) {
)}
-
- {(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) &&
}
+
num === menuNumber) ? 'active' : ''}`}>
+ {[2, 3, 4].some((num) => num === menuNumber) && }
{/* 견적서(menuNumber=== 5) 상세화면인경우 문서다운로드 팝업 */}
{estimatePopupOpen &&
}
diff --git a/src/components/floor-plan/modal/basic/step/Orientation.jsx b/src/components/floor-plan/modal/basic/step/Orientation.jsx
index 85ff6b33..b080b1b1 100644
--- a/src/components/floor-plan/modal/basic/step/Orientation.jsx
+++ b/src/components/floor-plan/modal/basic/step/Orientation.jsx
@@ -1,6 +1,6 @@
import { forwardRef, useImperativeHandle, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
-import { useOrientation } from '@/hooks/popup/useOrientation'
+import { useOrientation } from '@/hooks/module/useOrientation'
import { getDegreeInOrientation } from '@/util/canvas-util'
export const Orientation = forwardRef(({ tabNum }, ref) => {
diff --git a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx
index a0573dd1..da49b07c 100644
--- a/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx
+++ b/src/components/floor-plan/modal/flowDirection/FlowDirectionSetting.jsx
@@ -6,7 +6,7 @@ import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
-import { FLOW_DIRECTION_TYPE, useFlowDirectionSetting } from '@/hooks/popup/useFlowDirectionSetting'
+import { FLOW_DIRECTION_TYPE, useFlowDirectionSetting } from '@/hooks/contextpopup/useFlowDirectionSetting'
import { canvasState } from '@/store/canvasAtom'
export default function FlowDirectionSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
diff --git a/src/components/floor-plan/modal/image/ImageSizeSetting.jsx b/src/components/floor-plan/modal/image/ImageSizeSetting.jsx
deleted file mode 100644
index 309df494..00000000
--- a/src/components/floor-plan/modal/image/ImageSizeSetting.jsx
+++ /dev/null
@@ -1,42 +0,0 @@
-import WithDraggable from '@/components/common/draggable/WithDraggable'
-import { useState } from 'react'
-import { usePopup } from '@/hooks/usePopup'
-import { useRecoilValue } from 'recoil'
-import { contextPopupPositionState } from '@/store/popupAtom'
-import { useMessage } from '@/hooks/useMessage'
-
-export default function ImageSizeSetting(props) {
- const contextPopupPosition = useRecoilValue(contextPopupPositionState)
- const { id, pos = contextPopupPosition, size, setSize } = props
- const [sizeValue, setSizeValue] = useState(100)
- const { getMessage } = useMessage()
- const { closePopup } = usePopup()
-
- return (
-
-
-
-
{getMessage('modal.image.size.setting')}
- closePopup(id)}>
- 닫기
-
-
-
-
- setSizeValue(e.target.value)}
- />
-
-
-
-
-
- )
-}
diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx
index 6a69aaca..26d6f1b9 100644
--- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx
+++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx
@@ -12,7 +12,6 @@ import { usePopup } from '@/hooks/usePopup'
import SizeGuide from '@/components/floor-plan/modal/placementShape/SizeGuide'
import MaterialGuide from '@/components/floor-plan/modal/placementShape/MaterialGuide'
import WithDraggable from '@/components/common/draggable/WithDraggable'
-import { SessionContext } from '@/app/SessionProvider'
export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) {
const [objectNo, setObjectNo] = useState('test123241008001') // 후에 삭제 필요
diff --git a/src/components/header/Header.jsx b/src/components/header/Header.jsx
index 29cec36b..548387ef 100644
--- a/src/components/header/Header.jsx
+++ b/src/components/header/Header.jsx
@@ -4,7 +4,7 @@ import { Fragment, useCallback, useEffect, useState } from 'react'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
-import { useRecoilState, useRecoilValue } from 'recoil'
+import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { dimmedStore, sessionStore } from '@/store/commonAtom'
import { useMessage } from '@/hooks/useMessage'
@@ -16,6 +16,8 @@ import UserInfoModal from '@/components/myInfo/UserInfoModal'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
+import { stuffSearchState } from '@/store/stuffAtom'
+
export const ToggleonMouse = (e, act, target) => {
const listWrap = e.target.closest(target)
const ListItem = Array.from(listWrap.childNodes)
@@ -34,6 +36,8 @@ export const ToggleonMouse = (e, act, target) => {
export default function Header(props) {
const [userInfoModal, setUserInfoModal] = useState(false)
+ const resetStuffRecoil = useResetRecoilState(stuffSearchState)
+
const { userSession } = props
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const { getMessage } = useMessage()
@@ -184,7 +188,14 @@ export default function Header(props) {
{userInfoModal &&
}
- logout()}>
+ {
+ //리코일은 새로고침 하지 않으면 남아있어서 로그아웃해도 남아있음..
+ resetStuffRecoil()
+ logout()
+ }}
+ >
{getMessage('header.logout')}
diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx
index 3dc9a2f4..e6b281c4 100644
--- a/src/components/management/Stuff.jsx
+++ b/src/components/management/Stuff.jsx
@@ -39,9 +39,9 @@ export default function Stuff() {
const copyNo = async (value) => {
try {
await navigator.clipboard.writeText(value)
- alert(getMessage('stuff.detail.header.message2'))
+ alert(getMessage('stuff.detail.header.successCopy'))
} catch (error) {
- alert(getMessage('stuff.detail.header.message3'))
+ alert(getMessage('stuff.detail.header.failCopy'))
}
}
@@ -209,6 +209,7 @@ export default function Stuff() {
endRow: pageNo * pageSize,
schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId,
schSortType: 'R',
+ code: 'S',
}
setStuffSearch({
...params,
diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx
index ccb943c3..eea328d8 100644
--- a/src/components/management/StuffDetail.jsx
+++ b/src/components/management/StuffDetail.jsx
@@ -19,10 +19,15 @@ import { useCommonCode } from '@/hooks/common/useCommonCode'
import StuffPlanQGrid from './StuffPlanQGrid'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { ManagementContext } from '@/app/management/ManagementProvider'
+import DocDownOptionPop from '../estimate/popup/DocDownOptionPop'
export default function StuffDetail() {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //견적서 화면용 물건번호리코일
+ const [estimatePopupOpen, setEstimatePopupOpen] = useState(false)
+
+ const [popPlanNo, setPopPlanNo] = useState('1') //default 1
+
//공통코드
const { commonCode, findCommonCode } = useCommonCode()
const [selOptions, setSelOptions] = useState('') //선택한 1차점
@@ -266,11 +271,12 @@ export default function StuffDetail() {
type="button"
className="grid-btn"
onClick={() => {
- console.log('엑셀버튼클릭')
+ setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo })
+ handleEstimatePopup(params.data.planNo)
}}
>
- {getMessage('stuff.detail.planGrid.btn2')}
+ {getMessage('stuff.detail.planGrid.docDownload')}
>
@@ -280,6 +286,12 @@ export default function StuffDetail() {
],
})
+ // 문서다운로드 팝업 오픈 셋팅
+ const handleEstimatePopup = (planNo) => {
+ setPopPlanNo(planNo)
+ setEstimatePopupOpen(true)
+ }
+
useEffect(() => {
if (objectNo) {
setEditMode('EDIT')
@@ -289,10 +301,12 @@ export default function StuffDetail() {
}
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res.status === 200) {
- if (res.data != null) {
+ if (isObjectNotEmpty(res.data)) {
setManagementState(res.data)
} else {
setManagementState({})
+ alert(getMessage('stuff.detail.header.notExistObjectNo'))
+ router.push('/management/stuff')
}
if (isNotEmptyArray(res.data.planList)) {
setPlanGridProps({ ...planGridProps, planGridData: res.data.planList })
@@ -302,6 +316,9 @@ export default function StuffDetail() {
} else {
setManagementState({})
setPlanGridProps({ ...planGridProps, planGridData: [] })
+
+ alert(getMessage('stuff.detail.header.notExistObjectNo'))
+ router.push('/management/stuff')
}
})
} else {
@@ -2433,6 +2450,8 @@ export default function StuffDetail() {
{showWindSpeedButtonValid && (
)}
+
+ {estimatePopupOpen &&
}
>
)
}
diff --git a/src/components/management/StuffSearchCondition.jsx b/src/components/management/StuffSearchCondition.jsx
index 4a625539..1c7ececb 100644
--- a/src/components/management/StuffSearchCondition.jsx
+++ b/src/components/management/StuffSearchCondition.jsx
@@ -116,8 +116,10 @@ export default function StuffSearchCondition() {
schAddress: address,
schObjectName: objectName,
schDispCompanyName: dispCompanyName,
- schSelSaleStoreId: stuffSearch?.schSelSaleStoreId,
- schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId,
+ // schSelSaleStoreId: stuffSearch?.schSelSaleStoreId,
+ // schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId,
+ schSelSaleStoreId: schSelSaleStoreId,
+ schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser,
schDateType: dateType,
schFromDt: dayjs(startDate).format('YYYY-MM-DD'),
@@ -157,6 +159,7 @@ export default function StuffSearchCondition() {
setStuffSearch({
schSelSaleStoreId: '',
schOtherSelSaleStoreId: '',
+ schDateType: 'U',
})
} else {
if (otherSaleStoreList.length > 1) {
@@ -312,8 +315,8 @@ export default function StuffSearchCondition() {
} else {
//X누름
//화면에선 지우는데 리코일은 조회누르지 않으면 보존
- setSchSelSaleStoreId('')
- // stuffSearch.schSelSaleStoreId = ''
+ // setSchSelSaleStoreId('') //값이 안비워짐..
+ setSchSelSaleStoreId(null)
//2차점 판매점목록비우기
setOtherSaleStoreList([])
@@ -333,7 +336,6 @@ export default function StuffSearchCondition() {
if (session.storeLvl === '1') {
if (stuffSearch.schOtherSelSaleStoreId === '') {
// 화면에선 지우는데 조회누르기 전이면 리코일은 남김
- // stuffSearch.schSelSaleStoreId = ''
setSchSelSaleStoreId(session.storeId)
} else {
// 화면에선 지우는데 조회누르기 전이면 리코일은 남김
@@ -357,6 +359,7 @@ export default function StuffSearchCondition() {
setobjectName(stuffSearch.schObjectName ? stuffSearch.schObjectName : objectName)
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
+ setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
}, [stuffSearch])
useEffect(() => {
@@ -638,7 +641,7 @@ export default function StuffSearchCondition() {
type="radio"
name="radio_ptype"
id="radio_u"
- checked={stuffSearch.schDateType === 'U' ? true : false}
+ checked={dateType === 'U' ? true : false}
value={'U'}
onChange={(e) => {
setDateType(e.target.value)
@@ -652,7 +655,7 @@ export default function StuffSearchCondition() {
type="radio"
name="radio_ptype"
id="radio_r"
- checked={stuffSearch.schDateType === 'R' ? true : false}
+ checked={dateType === 'R' ? true : false}
value={'R'}
onChange={(e) => {
setDateType(e.target.value)
diff --git a/src/components/simulator/Simulator.jsx b/src/components/simulator/Simulator.jsx
index c909ca17..f3a26ede 100644
--- a/src/components/simulator/Simulator.jsx
+++ b/src/components/simulator/Simulator.jsx
@@ -105,8 +105,8 @@ export default function Simulator() {
useEffect(() => {
if (objectNo) {
fetchObjectDetail(objectNo)
+ fetchSimulatorNotice()
}
- fetchSimulatorNotice()
}, [objectNo, plan])
// 물건 상세 정보 조회
@@ -158,23 +158,25 @@ export default function Simulator() {
{getMessage('simulator.title.sub1')}
- {objectDetail.objectNo} (Plan No: {objectDetail.planNo})
+ {objectDetail.objectNo} (Plan No: {plan?.id})
{/* 작성일 */}
{getMessage('simulator.title.sub2')}
-
{`${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}`}
+
+ {objectDetail.drawingEstimateCreateDate ? `${dayjs(objectDetail.drawingEstimateCreateDate).format('YYYY.MM.DD')}` : ''}
+
{/* 시스템용량 */}
{getMessage('simulator.title.sub3')}
-
{convertNumberToPriceDecimal(objectDetail.capacity)}kW
+
{objectDetail.capacity ? `${convertNumberToPriceDecimal(objectDetail.capacity)}kW` : ''}
{/* 연간예측발전량 */}
{getMessage('simulator.title.sub4')}
-
{convertNumberToPriceDecimal(objectDetail.anlFrcsGnrt)}
+
{objectDetail.anlFrcsGnrt ? convertNumberToPriceDecimal(objectDetail.anlFrcsGnrt) : ''}
diff --git a/src/hooks/common/useCanvasConfigInitialize.js b/src/hooks/common/useCanvasConfigInitialize.js
index a07d4a00..18d1a052 100644
--- a/src/hooks/common/useCanvasConfigInitialize.js
+++ b/src/hooks/common/useCanvasConfigInitialize.js
@@ -40,19 +40,19 @@ export function useCanvasConfigInitialize() {
const flowTexts = canvas.getObjects().filter((obj) => obj.name === 'flowText')
if (basicSetting.roofAngleSet === 'slope') {
offsetTexts.forEach((obj) => {
- obj.set({ text: `${obj.originText}-∠${obj.pitch}${angleUnit}` })
+ obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}∠${obj.pitch}${angleUnit}` })
})
flowTexts.forEach((obj) => {
- obj.set({ text: `${obj.originText}-∠${obj.pitch}${pitchText}` })
+ obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}∠${obj.pitch}${pitchText}` })
})
}
if (basicSetting.roofAngleSet === 'flat') {
offsetTexts.forEach((obj) => {
- obj.set({ text: `${obj.originText}-∠${getDegreeByChon(obj.pitch)}${angleUnit}` })
+ obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}∠${getDegreeByChon(obj.pitch)}${angleUnit}` })
})
flowTexts.forEach((obj) => {
- obj.set({ text: `${obj.originText}-∠${getDegreeByChon(obj.pitch)}${pitchText}` })
+ obj.set({ text: `${!obj.originText ? '' : obj.originText + '-'}∠${getDegreeByChon(obj.pitch)}${pitchText}` })
})
}
diff --git a/src/hooks/popup/useFlowDirectionSetting.js b/src/hooks/contextpopup/useFlowDirectionSetting.js
similarity index 100%
rename from src/hooks/popup/useFlowDirectionSetting.js
rename to src/hooks/contextpopup/useFlowDirectionSetting.js
diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js
index 4330a208..07f50ec8 100644
--- a/src/hooks/floorPlan/estimate/useEstimateController.js
+++ b/src/hooks/floorPlan/estimate/useEstimateController.js
@@ -59,6 +59,12 @@ export const useEstimateController = (planNo) => {
try {
await get({ url: `/api/estimate/${objectRecoil.floorPlanObjectNo}/${planNo}/detail` }).then((res) => {
if (isObjectNotEmpty(res)) {
+ if (res.itemList.length > 0) {
+ res.itemList.map((item) => {
+ item.delFlg = '0'
+ })
+ }
+
setState(res)
}
})
@@ -76,7 +82,9 @@ export const useEstimateController = (planNo) => {
}
const addItem = () => {
- const newItemDispOrder = Math.max(...state.itemList.map((item) => item.dispOrder)) + 1
+ // const newItemDispOrder = (Math.max(...state.itemList.map((item) => item.dispOrder)) / 100 + 1) * 100
+ let newItemDispOrder = Math.max(...state.itemList.map((item) => item.dispOrder))
+ newItemDispOrder = (Math.floor(newItemDispOrder / 100) + 1) * 100
setState({
itemList: [
...state.itemList,
@@ -90,8 +98,8 @@ export const useEstimateController = (planNo) => {
amount: '', //수량
unitPrice: '0',
unit: '', //단위
- salePrice: '0', //단가
- saleTotPrice: '0', //금액(부가세별도)
+ salePrice: '', //단가
+ saleTotPrice: '', //금액(부가세별도)
itemChangeFlg: '1', //추가시 체인지플래그 1로
partAdd: '1', //NEW 체인지 플래그
delFlg: '0', //삭제 플래그 0 삭제하면 1
@@ -133,7 +141,7 @@ export const useEstimateController = (planNo) => {
const handleEstimateSubmit = async () => {
//0. 필수체크
let flag = true
- console.log('::담긴 estimateData:::', estimateData)
+
// console.log('첨부파일:::::', estimateData.fileList)
//첨부파일을 첨부안했는데
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
@@ -151,9 +159,8 @@ export const useEstimateController = (planNo) => {
}
if (flag) {
- //1. 첨부파일 저장
+ //1. 첨부파일 저장시작
const formData = new FormData()
- console.log('첨부파일:!!!', estimateData.fileList)
formData.append('file', estimateData.fileList)
formData.append('objectNo', estimateData.objectNo)
formData.append('planNo', estimateData.planNo)
@@ -161,26 +168,30 @@ export const useEstimateController = (planNo) => {
formData.append('userId', estimateData.userId)
await post({ url: '/api/file/fileUpload', data: formData })
+ //첨부파일저장끝
+ //제품라인 추가했는데 아이템 안고르고 저장하면itemId=''은 날리고 나머지 저장하기
+ estimateData.itemList = estimateData.itemList.filter((item) => item.itemId !== '')
+
+ let delCnt = 0
+ estimateData.itemList.map((item) => {
+ if (item.delFlg === '1') {
+ delCnt++
+ }
+ })
+ if (delCnt === estimateData.itemList.length) {
+ return alert(getMessage('estimate.detail.save.requiredItem'))
+ }
+
+ console.log('최종 정보::;', estimateData)
+ console.log('최종 남은 아이템정보:::', estimateData.itemList)
//2. 상세데이터 저장
- return
+ // return
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
if (res) {
alert(getMessage('estimate.detail.save.alertMsg'))
}
})
-
- // try {
- // const result = await promisePost({
- // url: ESTIMATE_API_ENDPOINT,
- // data: estimateData,
- // })
- // alert(getMessage('estimate.detail.save.alertMsg'))
- // return result
- // } catch (error) {
- // console.error('Failed to submit estimate:', error)
- // throw error
- // }
}
}
diff --git a/src/hooks/popup/useOrientation.js b/src/hooks/module/useOrientation.js
similarity index 74%
rename from src/hooks/popup/useOrientation.js
rename to src/hooks/module/useOrientation.js
index 4b8f4574..b64fc171 100644
--- a/src/hooks/popup/useOrientation.js
+++ b/src/hooks/module/useOrientation.js
@@ -3,6 +3,7 @@ import { canvasState } from '@/store/canvasAtom'
import { usePolygon } from '@/hooks/usePolygon'
import { POLYGON_TYPE } from '@/common/common'
import { compasDegAtom } from '@/store/orientationAtom'
+import { useEffect } from 'react'
// 모듈,회로 구성 탭 기본설정 > 방위설정 탭
export function useOrientation() {
@@ -11,6 +12,16 @@ export function useOrientation() {
const { drawDirectionArrow } = usePolygon()
+ useEffect(() => {
+ const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+ roofs.forEach((roof) => {
+ roof.set({
+ moduleCompass: null,
+ })
+ drawDirectionArrow(roof)
+ })
+ }, [])
+
const nextStep = () => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js
index a585109a..6cb1d09c 100644
--- a/src/hooks/option/useCanvasSetting.js
+++ b/src/hooks/option/useCanvasSetting.js
@@ -277,7 +277,7 @@ export function useCanvasSetting() {
optionName = ['outerLine', POLYGON_TYPE.WALL]
break
case 'gridDisplay': //그리드 표시
- optionName = ['lindGrid', 'dotGrid']
+ optionName = ['lindGrid', 'dotGrid', 'tempGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', POLYGON_TYPE.ROOF]
diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js
deleted file mode 100644
index 8757040a..00000000
--- a/src/hooks/option/useFirstOption.js
+++ /dev/null
@@ -1,81 +0,0 @@
-import { useRecoilState, useRecoilValue } from 'recoil'
-import { canvasState } from '@/store/canvasAtom'
-import { useEffect } from 'react'
-import { settingModalFirstOptionsState } from '@/store/settingAtom'
-import { POLYGON_TYPE } from '@/common/common'
-
-export function useFirstOption() {
- const canvas = useRecoilValue(canvasState)
-
- const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
-
- useEffect(() => {
- const option1 = settingModalFirstOptions.option1
-
- // 'allocDisplay' 할당 표시
- // 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
- // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
- // 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
- // 'wordDisplay' 문자 표시
- // 'circuitNumDisplay' 회로번호 표시
- // 'flowDisplay' 흐름방향 표시 'arrow'
- // 'trestleDisplay' 가대 표시
- // 'totalDisplay' 집계표 표시
-
- let optionName //옵션명
- let optionSelected //옵션상태
-
- for (let i = 0; i < option1.length; i++) {
- switch (option1[i].column) {
- case 'allocDisplay': //할당 표시
- optionName = ['1']
- break
- case 'outlineDisplay': //외벽선 표시
- optionName = ['outerLine', POLYGON_TYPE.WALL]
- break
- case 'gridDisplay': //그리드 표시
- optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid']
- break
- case 'lineDisplay': //지붕선 표시
- optionName = ['roof', POLYGON_TYPE.ROOF]
- break
- case 'wordDisplay': //문자 표시
- optionName = ['commonText']
- break
- case 'circuitNumDisplay': //회로번호 표시
- optionName = ['7']
- break
- case 'flowDisplay': //흐름방향 표시
- optionName = ['arrow', 'flowText']
- break
- case 'trestleDisplay': //가대 표시
- optionName = ['8']
- break
- case 'totalDisplay': //집계표 표시
- optionName = ['9']
- break
- }
- // 표시 선택 상태(true/false)
- optionSelected = option1[i].selected
-
- canvas
- .getObjects()
- .filter((obj) => optionName.includes(obj.name))
- //.filter((obj) => obj.name === optionName)
- .forEach((obj) => {
- obj.set({ visible: optionSelected })
- //obj.set({ visible: !obj.visible })
- })
-
- canvas.renderAll()
-
- // console.log(
- // 'optionName',
- // optionName,
- // canvas.getObjects().filter((obj) => optionName.includes(obj.name)),
- // )
- }
- }, [settingModalFirstOptions])
-
- return { settingModalFirstOptions, setSettingModalFirstOptions }
-}
diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js
index 6e95e79c..1a0d87bd 100644
--- a/src/hooks/roofcover/useAuxiliaryDrawing.js
+++ b/src/hooks/roofcover/useAuxiliaryDrawing.js
@@ -455,9 +455,24 @@ export function useAuxiliaryDrawing(id) {
name: 'auxiliaryLine',
})
- lineHistory.current.push(line)
+ const historyLines = [...lineHistory.current]
+
+ const hasSameLine = historyLines.some((history) => {
+ return (
+ (isSamePoint(history.startPoint, line.startPoint) && isSamePoint(history.endPoint, line.endPoint)) ||
+ (isSamePoint(history.startPoint, line.endPoint) && isSamePoint(history.endPoint, line.startPoint))
+ )
+ })
+
mousePointerArr.current = []
clear()
+
+ if (hasSameLine) {
+ canvas.remove(line)
+ return
+ }
+
+ lineHistory.current.push(line)
}
const mouseDown = (e) => {
diff --git a/src/hooks/roofcover/usePropertiesSetting.js b/src/hooks/roofcover/usePropertiesSetting.js
index 3a1535a3..73a72e5a 100644
--- a/src/hooks/roofcover/usePropertiesSetting.js
+++ b/src/hooks/roofcover/usePropertiesSetting.js
@@ -125,6 +125,12 @@ export function usePropertiesSetting(id) {
}
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
+ const notSetAttributes = lines.filter((line) => !line.attributes?.type)
+ if (notSetAttributes.length > 0) {
+ alert('설정되지 않은 외벽선이 있습니다.')
+ return
+ }
+
lines.forEach((line) => {
line.set({
attributes: line.attributes ? line.attributes : { offset: 0, type: LINE_TYPE.WALLLINE.WALL },
diff --git a/src/hooks/roofcover/useRoofShapeSetting.js b/src/hooks/roofcover/useRoofShapeSetting.js
index af55e557..c26c61ec 100644
--- a/src/hooks/roofcover/useRoofShapeSetting.js
+++ b/src/hooks/roofcover/useRoofShapeSetting.js
@@ -377,20 +377,20 @@ export function useRoofShapeSetting(id) {
}
// 기존 wallLine, roofBase 제거
- /*canvas
+ canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.WALL)
.forEach((line) => {
canvas.remove(line)
- })*/
+ })
- /*canvas
+ canvas
.getObjects()
- .filter((obj) => obj.name === POLYGON_TYPE.ROOF)
+ .filter((obj) => obj.name === POLYGON_TYPE.ROOF && !obj.isFixed)
.forEach((obj) => {
canvas.remove(...obj.innerLines)
canvas.remove(obj)
- })*/
+ })
const polygon = addPolygonByLines(outerLines, { name: POLYGON_TYPE.WALL, direction })
polygon.lines = [...outerLines]
diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js
index 5dae113c..8e7028d4 100644
--- a/src/hooks/useContextMenu.js
+++ b/src/hooks/useContextMenu.js
@@ -446,19 +446,24 @@ export function useContextMenu() {
])
break
case 'lineGrid':
+ case 'dotGrid':
+ case 'tempGrid':
setContextMenu([
[
{
id: 'gridMove',
name: getMessage('modal.grid.move'),
+ component: ,
},
{
id: 'gridCopy',
name: getMessage('modal.grid.copy'),
+ component: ,
},
{
id: 'gridColorEdit',
name: getMessage('contextmenu.grid.color.edit'),
+ component: ,
},
{
id: 'remove',
diff --git a/src/locales/ja.json b/src/locales/ja.json
index 64902f47..d5721a78 100644
--- a/src/locales/ja.json
+++ b/src/locales/ja.json
@@ -284,7 +284,6 @@
"modal.panel.batch.statistic.total": "合計",
"modal.flow.direction.setting": "流れ方向の設定",
"modal.flow.direction.setting.info": "流れ方向を選択してください。",
- "modal.image.size.setting": "画像のサイズ変更",
"modal.actual.size.setting": "実測値設定",
"modal.actual.size.setting.info": "※隅棟・谷・棟の実際の寸法を入力してください。",
"modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요(JA)",
@@ -733,7 +732,7 @@
"stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー",
"stuff.detail.planGridHeader.management": "管理",
"stuff.detail.planGrid.btn1": "見積書の照会",
- "stuff.detail.planGrid.btn2": "Excel",
+ "stuff.detail.planGrid.docDownload": "文書のダウンロード",
"stuff.grid.noData": "照会されたデータがありません",
"length": "長さ",
"height": "高さ",
@@ -844,6 +843,7 @@
"estimate.detail.header.showPrice": "価格表示",
"estimate.detail.header.unitPrice": "定価",
"estimate.detail.showPrice.pricingBtn": "Pricing",
+ "estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります。 Pricingを進めてください.",
"estimate.detail.showPrice.description1": "製品価格 OPEN",
"estimate.detail.showPrice.description2": "追加, 変更資材",
"estimate.detail.showPrice.description3": "添付必須",
@@ -860,25 +860,26 @@
"estimate.detail.docPopup.title": "ドキュメントダウンロードオプションの設定",
"estimate.detail.docPopup.explane": "ダウンロードする文書のオプションを選択したら、 [文書のダウンロード]ボタンをクリックします.",
"estimate.detail.docPopup.schUnitPriceFlg": "ダウンロードファイル",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg0": "見積もり Excel",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg1": "定価用 Excel",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg2": "見積もり PDF",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg3": "定価用 PDF",
+ "estimate.detail.docPopup.schUnitPriceFlg.excelFlg0": "見積もり Excel",
+ "estimate.detail.docPopup.schUnitPriceFlg.excelFlg1": "定価用 Excel",
+ "estimate.detail.docPopup.schUnitPriceFlg.pdfFlg0": "見積もり PDF",
+ "estimate.detail.docPopup.schUnitPriceFlg.pdfFlg1": "定価用 PDF",
"estimate.detail.docPopup.schDisplayFlg": "見積提出先表示名",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0": "販売店名",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1": "案件名",
"estimate.detail.docPopup.schWeightFlg": "架台重量表を含む",
- "estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "含む",
- "estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "含まない",
+ "estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "含む",
+ "estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "含まない",
"estimate.detail.docPopup.schDrawingFlg": "図面/シミュレーションファイルを含む",
- "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "含む",
- "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "含まない",
+ "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "含む",
+ "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "含まない",
"estimate.detail.docPopup.close": "閉じる",
"estimate.detail.docPopup.docDownload": "文書のダウンロード",
"estimate.detail.productFeaturesPopup.title": "製品特異事項",
"estimate.detail.productFeaturesPopup.close": "閉じる",
"estimate.detail.save.alertMsg": "保存されている見積書で製品を変更した場合、図面や回路には反映されません.",
"estimate.detail.save.requiredMsg": "ファイル添付が必須のアイテムがあります。ファイルを添付するか、後日添付をチェックしてください.",
+ "estimate.detail.save.requiredItem": "製品は1つ以上登録する必要があります.",
"estimate.detail.reset.confirmMsg": "保存した見積書情報が初期化され、図面情報が反映されます。本当に初期化しますか?",
"simulator.title.sub1": "物件番号",
"simulator.title.sub2": "作成日",
diff --git a/src/locales/ko.json b/src/locales/ko.json
index 5b47e7fd..fe4df330 100644
--- a/src/locales/ko.json
+++ b/src/locales/ko.json
@@ -289,7 +289,6 @@
"modal.panel.batch.statistic.total": "합계",
"modal.flow.direction.setting": "흐름 방향 설정",
"modal.flow.direction.setting.info": "흐름방향을 선택하세요.",
- "modal.image.size.setting": "이미지 크기 조절",
"modal.actual.size.setting": "실측치 설정",
"modal.actual.size.setting.info": "※隅棟・谷・棟의 실제 치수를 입력해주세요.",
"modal.actual.size.setting.not.exist.auxiliary.line": "실측치 입력할 보조선을 선택해 주세요",
@@ -743,7 +742,7 @@
"stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너",
"stuff.detail.planGridHeader.management": "관리",
"stuff.detail.planGrid.btn1": "견적서 조회",
- "stuff.detail.planGrid.btn2": "Excel",
+ "stuff.detail.planGrid.docDownload": "문서 다운로드",
"stuff.grid.noData": "조회된 데이터가 없습니다",
"length": "길이",
"height": "높이",
@@ -849,11 +848,12 @@
"estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "주택PKG단가 (W)",
"estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG 용량 (Kw)",
"estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액",
- "estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈수량 * 수량)÷100",
+ "estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈용량 * 수량)÷100",
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
"estimate.detail.header.showPrice": "가격표시",
"estimate.detail.header.unitPrice": "정가",
"estimate.detail.showPrice.pricingBtn": "Pricing",
+ "estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. Pricing을 진행해주세요.",
"estimate.detail.showPrice.description1": "제품 가격 OPEN",
"estimate.detail.showPrice.description2": "추가, 변경 자재",
"estimate.detail.showPrice.description3": "첨부필수",
@@ -870,25 +870,26 @@
"estimate.detail.docPopup.title": "문서다운로드 옵션설정",
"estimate.detail.docPopup.explane": "다운로드할 문서 옵션을 선택한 후 문서 다운로드 버튼을 클릭합니다.",
"estimate.detail.docPopup.schUnitPriceFlg": "다운로드 파일",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg0": "견적가 Excel",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg1": "정가용 Excel",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg2": "견적가 PDF",
- "estimate.detail.docPopup.schUnitPriceFlg.schUnitPriceFlg3": "정가용 PDF",
+ "estimate.detail.docPopup.schUnitPriceFlg.excelFlg0": "견적가 Excel",
+ "estimate.detail.docPopup.schUnitPriceFlg.excelFlg1": "정가용 Excel",
+ "estimate.detail.docPopup.schUnitPriceFlg.pdfFlg0": "견적가 PDF",
+ "estimate.detail.docPopup.schUnitPriceFlg.pdfFlg1": "정가용 PDF",
"estimate.detail.docPopup.schDisplayFlg": "견적제출서 표시명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg0": "판매점명",
"estimate.detail.docPopup.schDisplayFlg.schDisplayFlg1": "안건명",
"estimate.detail.docPopup.schWeightFlg": "가대 중량표 포함",
- "estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "포함",
- "estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "미포함",
+ "estimate.detail.docPopup.schWeightFlg.schWeightFlg1": "포함",
+ "estimate.detail.docPopup.schWeightFlg.schWeightFlg0": "미포함",
"estimate.detail.docPopup.schDrawingFlg": "도면/시뮬레이션 파일 포함",
- "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "포함",
- "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "미포함",
+ "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg1": "포함",
+ "estimate.detail.docPopup.schDrawingFlg.schDrawingFlg0": "미포함",
"estimate.detail.docPopup.close": "닫기",
"estimate.detail.docPopup.docDownload": "문서 다운로드",
"estimate.detail.productFeaturesPopup.title": "제품특이사항",
"estimate.detail.productFeaturesPopup.close": "닫기",
"estimate.detail.save.alertMsg": "저장되었습니다. 견적서에서 제품을 변경할 경우, 도면 및 회로에 반영되지 않습니다.",
"estimate.detail.save.requiredMsg": "파일첨부가 필수인 아이템이 있습니다. 파일을 첨부하거나 후일첨부를 체크해주십시오.",
+ "estimate.detail.save.requiredItem": "제품은 1개이상 등록해야 됩니다.",
"estimate.detail.reset.confirmMsg": "저장된 견적서 정보가 초기화되고, 도면정보가 반영됩니다. 정말로 초기화 하시겠습니까?",
"simulator.title.sub1": "물건번호",
"simulator.title.sub2": "작성일",
diff --git a/src/styles/_contents.scss b/src/styles/_contents.scss
index 441fccb4..446e003f 100644
--- a/src/styles/_contents.scss
+++ b/src/styles/_contents.scss
@@ -28,6 +28,7 @@
background-color: #383838;
transition: padding 0.17s ease-in-out;
z-index: 999;
+
.canvas-menu-inner {
position: relative;
display: flex;
@@ -36,14 +37,17 @@
background-color: #2c2c2c;
height: 46.8px;
z-index: 999;
+
.canvas-menu-list {
display: flex;
align-items: center;
height: 100%;
+
.canvas-menu-item {
display: flex;
align-items: center;
height: 100%;
+
button {
display: flex;
align-items: center;
@@ -54,6 +58,7 @@
padding: 15px 20px;
opacity: 0.55;
transition: all 0.17s ease-in-out;
+
.menu-icon {
display: block;
width: 14px;
@@ -62,53 +67,67 @@
background-position: center;
background-size: contain;
margin-right: 10px;
+
&.con00 {
background-image: url(/static/images/canvas/menu_icon00.svg);
}
+
&.con01 {
background-image: url(/static/images/canvas/menu_icon01.svg);
}
+
&.con02 {
background-image: url(/static/images/canvas/menu_icon02.svg);
}
+
&.con03 {
background-image: url(/static/images/canvas/menu_icon03.svg);
}
+
&.con04 {
background-image: url(/static/images/canvas/menu_icon04.svg);
}
+
&.con05 {
background-image: url(/static/images/canvas/menu_icon05.svg);
}
+
&.con06 {
background-image: url(/static/images/canvas/menu_icon06.svg);
}
}
}
+
&.active {
background-color: #383838;
+
button {
opacity: 1;
}
}
}
}
+
.canvas-side-btn-wrap {
display: flex;
align-items: center;
margin-left: auto;
+
.select-box {
width: 124px;
margin: 0 5px;
height: 30px;
+
> div {
width: 100%;
}
}
+
.btn-from {
display: flex;
align-items: center;
gap: 5px;
+
button {
display: block;
width: 30px;
@@ -119,49 +138,63 @@
background-repeat: no-repeat;
background-size: 15px 15px;
transition: all 0.17s ease-in-out;
+
&.btn01 {
background-image: url(../../public/static/images/canvas/side_icon03.svg);
}
+
&.btn02 {
background-image: url(../../public/static/images/canvas/side_icon02.svg);
}
+
&.btn03 {
background-image: url(../../public/static/images/canvas/side_icon01.svg);
}
+
&.btn04 {
background-image: url(../../public/static/images/canvas/side_icon04.svg);
}
+
&.btn05 {
background-image: url(../../public/static/images/canvas/side_icon05.svg);
}
+
&.btn06 {
background-image: url(../../public/static/images/canvas/side_icon06.svg);
}
+
&.btn07 {
background-image: url(../../public/static/images/canvas/side_icon07.svg);
}
+
&.btn08 {
background-image: url(../../public/static/images/canvas/side_icon08.svg);
}
+
&.btn09 {
background-image: url(../../public/static/images/canvas/side_icon09.svg);
}
+
&.btn10 {
background-image: url(../../public/static/images/canvas/side_icon10.svg);
background-size: 15px 14px;
}
+
&:hover {
background-color: #1083e3;
}
+
&.active {
background-color: #1083e3;
}
}
}
+
.ico-btn-from {
display: flex;
align-items: center;
gap: 5px;
+
button {
.ico {
display: block;
@@ -170,30 +203,37 @@
background-repeat: no-repeat;
background-position: center;
background-size: contain;
+
&.ico01 {
background-image: url(../../public/static/images/canvas/ico-flx01.svg);
}
+
&.ico02 {
background-image: url(../../public/static/images/canvas/ico-flx02.svg);
}
+
&.ico03 {
background-image: url(../../public/static/images/canvas/ico-flx03.svg);
}
+
&.ico04 {
background-image: url(../../public/static/images/canvas/ico-flx04.svg);
}
}
+
.name {
font-size: 12px;
color: #fff;
}
}
+
&.form06 {
.name {
font-size: 13px;
}
}
}
+
.vertical-horizontal {
display: flex;
min-width: 170px;
@@ -203,11 +243,13 @@
background: #373737;
line-height: 28px;
overflow: hidden;
+
span {
padding: 0 10px;
font-size: 13px;
color: #fff;
}
+
button {
margin-left: auto;
height: 100%;
@@ -218,12 +260,14 @@
padding: 0 7.5px;
transition: all 0.17s ease-in-out;
}
+
&.on {
button {
background-color: #1083e3;
}
}
}
+
.size-control {
display: flex;
align-items: center;
@@ -234,10 +278,13 @@
width: 100px;
height: 30px;
margin: 0 5px;
+
span {
font-size: 13px;
color: #fff;
+ cursor: pointer;
}
+
.control-btn {
display: block;
width: 12px;
@@ -245,9 +292,11 @@
background-repeat: no-repeat;
background-size: cover;
background-position: center;
+
&.minus {
background-image: url(../../public/static/images/canvas/minus.svg);
}
+
&.plus {
background-image: url(../../public/static/images/canvas/plus.svg);
}
@@ -255,6 +304,7 @@
}
}
}
+
.canvas-depth2-wrap {
position: absolute;
top: -100%;
@@ -263,20 +313,24 @@
width: 100%;
height: 50px;
transition: all 0.17s ease-in-out;
+
.canvas-depth2-inner {
display: flex;
align-items: center;
padding: 0 40px;
height: 100%;
+
.canvas-depth2-list {
display: flex;
align-items: center;
height: 100%;
+
.canvas-depth2-item {
display: flex;
align-items: center;
margin-right: 26px;
height: 100%;
+
button {
position: relative;
opacity: 0.55;
@@ -286,10 +340,12 @@
height: 100%;
padding-right: 12px;
}
+
&.active {
button {
opacity: 1;
font-weight: 600;
+
&:after {
content: '';
position: absolute;
@@ -304,17 +360,20 @@
}
}
}
+
.canvas-depth2-btn-list {
display: flex;
align-items: center;
margin-left: auto;
height: 100%;
+
.depth2-btn-box {
display: flex;
align-items: center;
margin-right: 34px;
height: 100%;
transition: all 0.17s ease-in-out;
+
button {
position: relative;
font-size: 12px;
@@ -322,6 +381,7 @@
height: 100%;
color: #fff;
padding-right: 12px;
+
&:after {
content: '';
position: absolute;
@@ -333,19 +393,23 @@
background: url(../../public/static/images/canvas/depth2-arr.svg) no-repeat center;
}
}
+
&:last-child {
margin-right: 0;
}
+
&.mouse {
opacity: 0.55;
}
}
}
}
+
&.active {
top: 47px;
}
}
+
&.active {
padding-bottom: 50px;
}
@@ -355,18 +419,23 @@
.canvas-content {
padding-top: 46.8px;
transition: all 0.17s ease-in-out;
+
.canvas-frame {
height: calc(100vh - 129.3px);
}
+
&.active {
padding-top: calc(46.8px + 50px);
+
.canvas-frame {
height: calc(100vh - 179.4px);
}
}
}
+
.canvas-layout {
padding-top: 37px;
+
.canvas-page-list {
position: fixed;
top: 92.8px;
@@ -378,13 +447,16 @@
min-width: 1280px;
transition: all 0.17s ease-in-out;
z-index: 99;
+
&.active {
top: calc(92.8px + 50px);
}
+
.canvas-plane-wrap {
display: flex;
align-items: center;
max-width: calc(100% - 45px);
+
.canvas-page-box {
display: flex;
align-items: center;
@@ -393,6 +465,7 @@
border-right: 1px solid #000;
min-width: 0;
transition: all 0.17s ease-in-out;
+
span {
display: flex;
align-items: center;
@@ -404,6 +477,7 @@
text-overflow: ellipsis;
overflow: hidden;
}
+
.close {
flex: none;
display: block;
@@ -413,24 +487,30 @@
background: url(../../public/static/images/canvas/plan_close_gray.svg) no-repeat center;
background-size: cover;
}
+
&.on {
background-color: #fff;
+
span {
font-weight: 600;
color: #101010;
}
+
.close {
background: url(../../public/static/images/canvas/plan_close_black.svg) no-repeat center;
}
+
&:hover {
background-color: #fff;
}
}
+
&:hover {
background-color: #000;
}
}
}
+
.plane-add {
display: flex;
align-items: center;
@@ -440,6 +520,7 @@
background-color: #1c1c1c;
border-right: 1px solid #000;
transition: all 0.17s ease-in-out;
+
span {
display: block;
width: 9px;
@@ -447,6 +528,7 @@
background: url(../../public/static/images/canvas/plane_add.svg) no-repeat center;
background-size: cover;
}
+
&:hover {
background-color: #000;
}
@@ -476,6 +558,7 @@
margin: 0 auto;
background-color: #fff;
}
+
canvas {
position: absolute;
top: 0;
@@ -496,20 +579,25 @@
border-bottom: 1px solid #000;
background: #2c2c2c;
z-index: 999;
+
.sub-header-inner {
display: flex;
align-items: center;
height: 100%;
padding: 0 100px;
+
.sub-header-title-wrap {
display: flex;
align-items: center;
+
.title-item {
position: relative;
padding: 0 24px;
+
a {
display: flex;
align-items: center;
+
.icon {
width: 22px;
height: 22px;
@@ -517,11 +605,13 @@
background-repeat: no-repeat;
background-position: center;
background-size: cover;
+
&.drawing {
background-image: url(../../public/static/images/main/drawing_icon.svg);
}
}
}
+
&:after {
content: '';
position: absolute;
@@ -532,31 +622,38 @@
height: 16px;
background-color: #d9d9d9;
}
+
&:first-child {
padding-left: 0;
}
+
&:last-child {
padding-right: 0;
+
&:after {
display: none;
}
}
}
}
+
.sub-header-title {
font-size: 16px;
color: #fff;
font-weight: 600;
}
+
.sub-header-location {
margin-left: auto;
display: flex;
align-items: center;
+
.location-item {
position: relative;
display: flex;
align-items: center;
padding: 0 10px;
+
span {
display: flex;
font-size: 12px;
@@ -564,6 +661,7 @@
font-weight: normal;
cursor: default;
}
+
&:after {
content: '';
position: absolute;
@@ -574,14 +672,18 @@
height: 6px;
background: url(../../public/static/images/main/loaction_arr.svg) no-repeat center;
}
+
&:first-child {
padding-left: 0;
}
+
&:last-child {
padding-right: 0;
+
span {
color: #fff;
}
+
&:after {
display: none;
}
@@ -594,56 +696,68 @@
// sub content
.sub-content {
padding-top: 46px;
+
.sub-content-inner {
max-width: 1760px;
margin: 0 auto;
padding: 20px 20px 0;
+
.sub-content-box {
margin-bottom: 20px;
+
&:last-child {
margin-bottom: 0;
}
}
}
+
&.estimate {
display: flex;
flex-direction: column;
padding-top: 0;
+
.sub-content-inner {
flex: 1;
width: 100%;
}
}
}
+
.sub-table-box {
padding: 20px;
border-radius: 6px;
border: 1px solid #e9eaed;
background: #fff;
box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02);
+
.table-box-title-wrap {
display: flex;
align-items: center;
margin-bottom: 15px;
+
.title-wrap {
display: flex;
align-items: center;
+
h3 {
display: block;
font-size: 15px;
color: #101010;
font-weight: 600;
margin-right: 14px;
+
&.product {
margin-right: 10px;
}
}
+
.product_tit {
position: relative;
font-size: 15px;
font-weight: 600;
color: #1083e3;
padding-left: 10px;
+
&::before {
content: '';
position: absolute;
@@ -655,27 +769,33 @@
background-color: #d9d9d9;
}
}
+
.option {
padding-left: 5px;
font-size: 13px;
color: #101010;
font-weight: 400;
}
+
.info-wrap {
display: flex;
align-items: center;
+
li {
position: relative;
padding: 0 6px;
font-size: 12px;
color: #101010;
font-weight: normal;
+
span {
font-weight: 600;
+
&.red {
color: #e23d70;
}
}
+
&:after {
content: '';
position: absolute;
@@ -686,11 +806,14 @@
height: 11px;
background-color: #d9d9d9;
}
+
&:first-child {
padding-left: 0;
}
+
&:last-child {
padding-right: 0;
+
&::after {
display: none;
}
@@ -699,11 +822,13 @@
}
}
}
+
.left-unit-box {
margin-left: auto;
display: flex;
align-items: center;
}
+
.promise-gudie {
display: block;
font-size: 13px;
@@ -711,15 +836,18 @@
color: #101010;
margin-bottom: 20px;
}
+
.important {
color: #f00;
}
+
.sub-center-footer {
display: flex;
align-items: center;
justify-content: center;
margin-top: 20px;
}
+
.sub-right-footer {
display: flex;
align-items: center;
@@ -727,6 +855,7 @@
margin-top: 20px;
}
}
+
.pagination-wrap {
margin-top: 24px;
}
@@ -738,19 +867,23 @@
.infomation-box-wrap {
display: flex;
gap: 10px;
+
.sub-table-box {
flex: 1;
}
+
.info-title {
font-size: 14px;
font-weight: 500;
color: #344356;
margin-bottom: 10px;
}
+
.info-inner {
position: relative;
font-size: 13px;
color: #344356;
+
.copy-ico {
position: absolute;
bottom: 0;
@@ -768,6 +901,7 @@
display: flex;
align-items: center;
margin-bottom: 10px;
+
&.one {
.estimate-box {
&:last-child {
@@ -775,14 +909,17 @@
}
}
}
+
.estimate-box {
flex: 1;
display: flex;
align-items: center;
+
&:last-child {
flex: none;
min-width: 220px;
}
+
.estimate-tit {
width: 105px;
height: 30px;
@@ -794,16 +931,19 @@
font-weight: 500;
color: #344356;
}
+
.estimate-name {
font-size: 13px;
color: #344356;
margin-left: 14px;
font-weight: 400;
+
&.blue {
font-size: 16px;
font-weight: 700;
color: #1083e3;
}
+
&.red {
font-size: 16px;
font-weight: 700;
@@ -811,6 +951,7 @@
}
}
}
+
&:last-child {
margin-bottom: 0;
}
@@ -819,9 +960,11 @@
// file drag box
.drag-file-box {
padding: 10px;
+
.btn-area {
padding-bottom: 15px;
border-bottom: 1px solid #ecf0f4;
+
.file-upload {
display: inline-block;
height: 30px;
@@ -834,14 +977,17 @@
font-weight: 500;
cursor: pointer;
transition: background 0.15s ease-in-out;
+
&:hover {
background-color: #607f9a;
}
}
}
+
.drag-file-area {
position: relative;
margin-top: 15px;
+
p {
position: absolute;
top: 50%;
@@ -853,9 +999,11 @@
cursor: default;
}
}
+
.file-list {
.file-item {
margin-bottom: 15px;
+
span {
position: relative;
font-size: 13px;
@@ -863,6 +1011,7 @@
font-weight: 400;
white-space: nowrap;
padding-right: 55px;
+
button {
position: absolute;
top: 50%;
@@ -874,6 +1023,7 @@
background-size: cover;
}
}
+
&:last-child {
margin-bottom: 0;
}
@@ -892,22 +1042,27 @@
background-image: url(../../public/static/images/canvas/estiment_arr.svg);
background-size: 11px 7px;
border-radius: 2px;
+
&.up {
rotate: 180deg;
}
+
&.on {
background-color: #fff;
border-color: #c2d0dd;
background-image: url(../../public/static/images/canvas/estiment_arr_color.svg);
}
}
+
.estimate-check-wrap {
.estimate-check-inner {
display: block;
}
+
&.hide {
border-bottom: 1px solid #ecf0f4;
margin-bottom: 15px;
+
.estimate-check-inner {
display: none;
}
@@ -919,11 +1074,13 @@
grid-template-columns: repeat(5, 1fr);
border-radius: 3px;
margin-bottom: 30px;
+
.special-note-check-item {
padding: 14px 10px;
border: 1px solid #ecf0f4;
margin-top: -1px;
margin-right: -1px;
+
&.act {
background-color: #f7f9fa;
}
@@ -937,38 +1094,47 @@
max-height: 350px;
overflow-y: auto;
margin-bottom: 30px;
+
dl {
margin-bottom: 35px;
+
&:last-child {
margin-bottom: 0;
}
+
dt {
font-size: 13px;
font-weight: 600;
color: #1083e3;
margin-bottom: 15px;
}
+
dd {
font-size: 12px;
font-weight: 400;
color: #45576f;
margin-bottom: 8px;
+
&:last-child {
margin-bottom: 0;
}
}
}
+
&::-webkit-scrollbar {
width: 4px;
background-color: transparent;
}
+
&::-webkit-scrollbar-thumb {
background-color: #d9dee2;
}
+
&::-webkit-scrollbar-track {
background-color: transparent;
}
}
+
.esimate-wrap {
margin-bottom: 20px;
}
@@ -977,27 +1143,33 @@
display: flex;
align-items: center;
margin-bottom: 15px;
+
.product-price-wrap {
display: flex;
align-items: center;
+
.product-price-tit {
font-size: 13px;
font-weight: 400;
color: #45576f;
margin-right: 10px;
}
+
.select-wrap {
width: 110px;
}
}
+
.product-edit-wrap {
display: flex;
align-items: center;
margin-left: auto;
+
.product-edit-explane {
display: flex;
align-items: center;
margin-right: 15px;
+
.explane-item {
position: relative;
display: flex;
@@ -1005,6 +1177,7 @@
padding: 0 10px;
font-size: 12px;
font-weight: 400;
+
span {
width: 20px;
height: 20px;
@@ -1013,6 +1186,7 @@
background-repeat: no-repeat;
background-position: center;
}
+
&:before {
content: '';
position: absolute;
@@ -1023,55 +1197,71 @@
height: 12px;
background-color: #d9d9d9;
}
+
&:first-child {
padding-left: 0;
+
&::before {
display: none;
}
}
+
&:last-child {
padding-right: 0;
}
+
&.item01 {
color: #3bbb48;
+
span {
background-image: url(../../public/static/images/sub/open_ico.svg);
}
}
+
&.item02 {
color: #909000;
+
span {
background-image: url(../../public/static/images/sub/change_ico.svg);
}
}
+
&.item03 {
color: #0191c9;
+
span {
background-image: url(../../public/static/images/sub/attachment_ico.svg);
}
}
+
&.item04 {
color: #f16a6a;
+
span {
background-image: url(../../public/static/images/sub/click_check_ico.svg);
}
}
}
}
+
.product-edit-btn {
display: flex;
align-items: center;
+
button {
display: flex;
align-items: center;
+
span {
width: 13px;
height: 13px;
margin-right: 5px;
background-size: cover;
+
&.plus {
background: url(../../public/static/images/sub/plus_btn.svg) no-repeat center;
}
+
&.minus {
background: url(../../public/static/images/sub/minus_btn.svg) no-repeat center;
}
@@ -1086,22 +1276,28 @@
display: flex;
gap: 20px;
width: 100%;
+
.sub-table-box {
height: 100%;
}
+
.chart-inner {
flex: 1;
+
.chart-box {
margin-bottom: 30px;
}
}
+
.chart-table-wrap {
display: flex;
flex-direction: column;
flex: none;
width: 650px;
+
.sub-table-box {
flex: 1;
+
&:first-child {
margin-bottom: 20px;
}
@@ -1115,6 +1311,7 @@
border-collapse: collapse;
border: 1px solid #ecf0f4;
border-radius: 4px;
+
thead {
th {
padding: 4.5px 0;
@@ -1126,6 +1323,7 @@
background-color: #f8f9fa;
}
}
+
tbody {
td {
font-size: 13px;
@@ -1140,10 +1338,12 @@
.simulation-guide-wrap {
display: flex;
padding: 20px;
+
.simulation-tit-wrap {
flex: none;
padding-right: 40px;
border-right: 1px solid #eeeeee;
+
span {
display: block;
position: relative;
@@ -1151,6 +1351,7 @@
font-size: 15px;
color: #14324f;
font-weight: 600;
+
&::before {
content: '';
position: absolute;
@@ -1164,27 +1365,33 @@
}
}
}
+
.simulation-guide-box {
flex: 1;
padding-left: 40px;
+
dl {
margin-bottom: 25px;
+
dt {
font-size: 13px;
color: #101010;
font-weight: 600;
margin-bottom: 5px;
}
+
dd {
font-size: 12px;
color: #45576f;
font-weight: 400;
line-height: 24px;
}
+
&:last-child {
margin-bottom: 0;
}
}
+
ul,
ol {
list-style: unset;
@@ -1200,6 +1407,7 @@
margin-right: 4px;
border: 1px solid #ecf0f4;
border-top: none;
+
.total-title {
flex: 1;
text-align: center;
@@ -1207,6 +1415,7 @@
color: #344356;
font-weight: 500;
}
+
.total-num {
flex: none;
width: 121px;
@@ -1224,12 +1433,14 @@
background-color: #f4f4f4;
border-radius: 4px;
margin-bottom: 15px;
+
.information-help-tit-wrap {
position: relative;
display: flex;
align-items: center;
padding-right: 40px;
border-right: 1px solid #e0e0e3;
+
.help-tit-icon {
width: 40px;
height: 40px;
@@ -1238,20 +1449,24 @@
background: #fff url(../../public/static/images/sub/information_help.svg) no-repeat center;
background-size: 20px 20px;
}
+
.help-tit {
font-size: 13px;
font-weight: 600;
color: #45576f;
}
}
+
.information-help-guide {
padding-left: 40px;
+
span {
display: block;
font-size: 12px;
font-weight: 400;
color: #45576f;
margin-bottom: 7px;
+
&:last-child {
margin-bottom: 0;
}
@@ -1266,6 +1481,7 @@
padding: 10px 0 30px 0;
border-bottom: 1px solid #e5e5e5;
margin-bottom: 24px;
+
.community-search-box {
position: relative;
display: flex;
@@ -1276,16 +1492,19 @@
margin-bottom: 20px;
border-radius: 2px;
border: 1px solid #101010;
+
.community-input {
width: 100%;
height: 100%;
font-size: 13px;
font-weight: 400;
color: #101010;
+
&::placeholder {
color: #c8c8c8;
}
}
+
.community-search-ico {
position: absolute;
top: 50%;
@@ -1299,10 +1518,12 @@
z-index: 3;
}
}
+
.community-search-keyword {
font-size: 13px;
font-weight: 400;
color: #45576f;
+
span {
font-weight: 600;
color: #f16a6a;
@@ -1315,6 +1536,7 @@
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px;
+
.file-down-item {
display: flex;
align-items: center;
@@ -1323,6 +1545,7 @@
border: 1px solid #e5e5e5;
background: #fff;
transition: all 0.15s ease-in-out;
+
.file-item-info {
.item-num {
display: inline-block;
@@ -1334,24 +1557,28 @@
color: #101010;
margin-bottom: 15px;
}
+
.item-name {
font-size: 16px;
color: #101010;
font-weight: 500;
margin-bottom: 13px;
}
+
.item-date {
font-size: 13px;
font-weight: 400;
color: #344356;
}
}
+
.file-down-box {
display: flex;
align-items: center;
flex: none;
margin-left: auto;
height: 100%;
+
.file-down-btn {
width: 36px;
height: 36px;
@@ -1359,6 +1586,7 @@
background-size: cover;
}
}
+
&:hover {
background-color: #f4f4f7;
}
@@ -1388,6 +1616,7 @@
background-color: #fafafa;
border: 1px solid #eee;
padding: 0 10px;
+
input {
font-size: 13px;
font-weight: 400;
@@ -1398,6 +1627,7 @@
flex: 1;
background-color: inherit;
}
+
.product-delete {
flex: none;
display: block;
@@ -1417,6 +1647,7 @@
margin-right: 5px;
}
}
+
.canvas-menu-item {
button {
padding: 15px 15px;
@@ -1425,6 +1656,7 @@
}
}
}
+
.canvas-depth2-wrap {
.canvas-depth2-inner {
.canvas-depth2-list {
@@ -1455,6 +1687,7 @@
.canvas-frame {
height: calc(100vh - 129.5px);
}
+
&.active {
.canvas-frame {
height: calc(100vh - 179.5px);
@@ -1474,18 +1707,22 @@
}
}
}
+
.canvas-side-btn-wrap {
.btn-from {
gap: 3px;
}
+
.vertical-horizontal {
margin-right: 3px;
min-width: 150px;
}
+
.select-box {
width: 100px;
margin: 0 3px;
}
+
.size-control {
width: 90px;
margin: 0 3px;
@@ -1498,6 +1735,7 @@
.sub-header-title {
font-size: 15px;
}
+
.sub-header-title-wrap {
.title-item {
a {
diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js
index 3ed8f9a1..9a12e4b3 100644
--- a/src/util/qpolygon-utils.js
+++ b/src/util/qpolygon-utils.js
@@ -1201,7 +1201,7 @@ export function removeDuplicatePolygons(polygons) {
}
export const isSamePoint = (a, b) => {
- return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 1 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 1
+ return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2
}
/**