Merge branch 'dev' into feature/test-jy
# Conflicts: # src/hooks/roofcover/usePropertiesSetting.js # src/hooks/roofcover/useRoofAllocationSetting.js
This commit is contained in:
commit
57ee521410
3
public/static/images/canvas/estiment_arr.svg
Normal file
3
public/static/images/canvas/estiment_arr.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="11" height="7" viewBox="0 0 11 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M1 1L5.5 5.5L10 1" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 210 B |
3
public/static/images/canvas/estiment_arr_color.svg
Normal file
3
public/static/images/canvas/estiment_arr_color.svg
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
<svg width="11" height="7" viewBox="0 0 11 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path id="Vector 7174" d="M1 1L5.5 5.5L10 1" stroke="#C2D0DD" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 229 B |
@ -1,128 +0,0 @@
|
|||||||
'use client'
|
|
||||||
|
|
||||||
import { Select, SelectItem } from '@nextui-org/react'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
|
||||||
|
|
||||||
export default function RoofSelect() {
|
|
||||||
const [roofMaterials, setRoofMaterials] = useState([])
|
|
||||||
const [manufacturers, setManufacturers] = useState([])
|
|
||||||
const [trestles, setTrestles] = useState([])
|
|
||||||
const [modules, setModules] = useState([])
|
|
||||||
const [originTrestles, setOriginTrestles] = useState([])
|
|
||||||
|
|
||||||
const [roofMaterialId, setRoofMaterialId] = useState(null)
|
|
||||||
const [manufacturerId, setManufacturerId] = useState(null)
|
|
||||||
const [trestleId, setTrestleId] = useState(null)
|
|
||||||
|
|
||||||
const { get } = useAxios()
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
get({ url: '/api/roof-material/roof-material-infos' }).then((res) => {
|
|
||||||
//TODO: error handling
|
|
||||||
if (!res) return
|
|
||||||
|
|
||||||
setRoofMaterials(res)
|
|
||||||
})
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!roofMaterialId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
get({ url: `/api/roof-material/roof-material-infos/${roofMaterialId}/trestles` }).then((res) => {
|
|
||||||
if (res.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setOriginTrestles(res)
|
|
||||||
const manufactural = res.map((trestle) => {
|
|
||||||
return { id: trestle.manufacturerId, name: trestle.manufacturerName }
|
|
||||||
})
|
|
||||||
// Remove duplicates
|
|
||||||
const uniqueManufactural = Array.from(new Set(manufactural.map((a) => a.id))).map((id) => {
|
|
||||||
return manufactural.find((a) => a.id === id)
|
|
||||||
})
|
|
||||||
|
|
||||||
setManufacturers(uniqueManufactural)
|
|
||||||
})
|
|
||||||
}, [roofMaterialId])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!manufacturerId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const trestles = originTrestles.filter((trestle) => trestle.manufacturerId === manufacturerId)
|
|
||||||
setTrestles(trestles)
|
|
||||||
}, [manufacturerId])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!trestleId) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
get({ url: `/api/module/module-infos?roofMaterialId=${roofMaterialId}&trestleId=${trestleId}` }).then((res) => {
|
|
||||||
if (res.length === 0) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
setModules(res)
|
|
||||||
})
|
|
||||||
}, [trestleId])
|
|
||||||
|
|
||||||
const handleRoofMaterialOnChange = (e) => {
|
|
||||||
const roofMaterialId = e.target.value
|
|
||||||
setRoofMaterialId(roofMaterialId)
|
|
||||||
setManufacturers([])
|
|
||||||
setManufacturerId(null)
|
|
||||||
setTrestleId(null)
|
|
||||||
setTrestles([])
|
|
||||||
setModules([])
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleManufacturersOnChange = (e) => {
|
|
||||||
const manufacturerId = Number(e.target.value)
|
|
||||||
setTrestles([])
|
|
||||||
setManufacturerId(manufacturerId)
|
|
||||||
setTrestleId(null)
|
|
||||||
setModules([])
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleTrestlesOnChange = (e) => {
|
|
||||||
const trestleId = Number(e.target.value)
|
|
||||||
setTrestleId(trestleId)
|
|
||||||
setModules([])
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
|
|
||||||
{roofMaterials.length > 0 && (
|
|
||||||
<Select label="지붕재" className="max-w-xs" onChange={handleRoofMaterialOnChange}>
|
|
||||||
{roofMaterials.map((roofMaterial) => (
|
|
||||||
<SelectItem key={roofMaterial.id}>{roofMaterial.name}</SelectItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
{manufacturers.length > 0 && (
|
|
||||||
<Select label="제조 회사" className="max-w-xs" onChange={handleManufacturersOnChange}>
|
|
||||||
{manufacturers.map((manufacturer) => (
|
|
||||||
<SelectItem key={manufacturer.id}>{manufacturer.name}</SelectItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
{trestles.length > 0 && (
|
|
||||||
<Select label="가대" className="max-w-xs" onChange={handleTrestlesOnChange}>
|
|
||||||
{trestles.map((trestle) => (
|
|
||||||
<SelectItem key={trestle.id}>{trestle.name}</SelectItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
{modules.length > 0 && (
|
|
||||||
<Select label="설치가능 모듈" className="max-w-xs">
|
|
||||||
{modules.map((module) => (
|
|
||||||
<SelectItem key={module.id}>{module.name}</SelectItem>
|
|
||||||
))}
|
|
||||||
</Select>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@ -1,14 +1,8 @@
|
|||||||
import Roof2 from '@/components/Roof2'
|
import Roof2 from '@/components/Roof2'
|
||||||
import RoofSelect from '@/app/roof2/RoofSelect'
|
|
||||||
|
|
||||||
export default async function Roof2Page() {
|
export default async function Roof2Page() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div>
|
|
||||||
<div className="m-2">
|
|
||||||
<RoofSelect />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-col justify-center my-8 pt-20">
|
<div className="flex flex-col justify-center my-8 pt-20">
|
||||||
<Roof2 />
|
<Roof2 />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -29,13 +29,6 @@ export default function InitSettingsModal(props) {
|
|||||||
//const { get, post } = useAxios()
|
//const { get, post } = useAxios()
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
get({ url: '/api/roof-material/roof-material-infos' }).then((res) => {
|
|
||||||
//TODO: error handling
|
|
||||||
if (!res) return
|
|
||||||
|
|
||||||
setRoofMaterials(res)
|
|
||||||
})
|
|
||||||
|
|
||||||
get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
|
get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
|
||||||
if (res.length == 0) return
|
if (res.length == 0) return
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { contextPopupPositionState } from '@/store/popupAtom'
|
|||||||
|
|
||||||
export default function ColorPickerModal(props) {
|
export default function ColorPickerModal(props) {
|
||||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState) // 현재 메뉴
|
const contextPopupPosition = useRecoilValue(contextPopupPositionState) // 현재 메뉴
|
||||||
const { isShow, setIsShow, pos = contextPopupPosition, color = '#ff0000', setColor, id } = props
|
const { isShow, setIsShow, pos = contextPopupPosition, color = '#ff0000', setColor, id, isConfig = false } = props
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const [originColor, setOriginColor] = useState(color)
|
const [originColor, setOriginColor] = useState(color)
|
||||||
const { closePopup } = usePopup()
|
const { closePopup } = usePopup()
|
||||||
@ -29,7 +29,7 @@ export default function ColorPickerModal(props) {
|
|||||||
setIsShow(false)
|
setIsShow(false)
|
||||||
}
|
}
|
||||||
console.log(id)
|
console.log(id)
|
||||||
closePopup(id)
|
closePopup(id, isConfig)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
닫기
|
닫기
|
||||||
@ -49,7 +49,7 @@ export default function ColorPickerModal(props) {
|
|||||||
if (setColor) setColor(originColor)
|
if (setColor) setColor(originColor)
|
||||||
if (setIsShow) setIsShow(false)
|
if (setIsShow) setIsShow(false)
|
||||||
|
|
||||||
closePopup(id)
|
closePopup(id, isConfig)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{getMessage('common.message.save')}
|
{getMessage('common.message.save')}
|
||||||
|
|||||||
@ -3,12 +3,14 @@ import { useEffect } from 'react'
|
|||||||
import '@/styles/contents.scss'
|
import '@/styles/contents.scss'
|
||||||
import { useRecoilState } from 'recoil'
|
import { useRecoilState } from 'recoil'
|
||||||
import { contextMenuListState, contextMenuState } from '@/store/contextMenu'
|
import { contextMenuListState, contextMenuState } from '@/store/contextMenu'
|
||||||
|
import { useTempGrid } from '@/hooks/useTempGrid'
|
||||||
|
|
||||||
export default function QContextMenu(props) {
|
export default function QContextMenu(props) {
|
||||||
const { contextRef, canvasProps, handleKeyup } = props
|
const { contextRef, canvasProps, handleKeyup } = props
|
||||||
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState)
|
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState)
|
||||||
const [contextMenuList, setContextMenuList] = useRecoilState(contextMenuListState)
|
const [contextMenuList, setContextMenuList] = useRecoilState(contextMenuListState)
|
||||||
const activeObject = canvasProps?.getActiveObject() //액티브된 객체를 가져옴
|
const activeObject = canvasProps?.getActiveObject() //액티브된 객체를 가져옴
|
||||||
|
const { tempGridMode, setTempGridMode } = useTempGrid()
|
||||||
|
|
||||||
let contextType = ''
|
let contextType = ''
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ export default function QContextMenu(props) {
|
|||||||
|
|
||||||
const handleContextMenu = (e) => {
|
const handleContextMenu = (e) => {
|
||||||
// e.preventDefault() //기존 contextmenu 막고
|
// e.preventDefault() //기존 contextmenu 막고
|
||||||
|
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,
|
||||||
y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY,
|
y: window.innerHeight / 2 < e.pageY ? getYPosition(e) : e.pageY,
|
||||||
|
|||||||
@ -14,15 +14,7 @@ const fonts = [
|
|||||||
{ name: '@Yu Gothic UI', value: '@Yu Gothic UI' },
|
{ name: '@Yu Gothic UI', value: '@Yu Gothic UI' },
|
||||||
{ name: 'Yu Gothic UI', value: 'Yu Gothic UI' },
|
{ name: 'Yu Gothic UI', value: 'Yu Gothic UI' },
|
||||||
]
|
]
|
||||||
const fontOptions = [
|
|
||||||
{ name: '보통', value: 'normal' },
|
|
||||||
{ name: '기울임꼴', value: 'italic' },
|
|
||||||
{
|
|
||||||
name: '굵게',
|
|
||||||
value: 'bold',
|
|
||||||
},
|
|
||||||
{ name: '굵은 기울임꼴', value: 'boldAndItalic' },
|
|
||||||
]
|
|
||||||
const fontSizes = [
|
const fontSizes = [
|
||||||
...Array.from({ length: 4 }).map((_, index) => {
|
...Array.from({ length: 4 }).map((_, index) => {
|
||||||
return { name: index + 8, value: index + 8 }
|
return { name: index + 8, value: index + 8 }
|
||||||
@ -34,20 +26,10 @@ const fontSizes = [
|
|||||||
{ name: 48, value: 48 },
|
{ name: 48, value: 48 },
|
||||||
{ name: 72, value: 72 },
|
{ name: 72, value: 72 },
|
||||||
]
|
]
|
||||||
const fontColors = [
|
|
||||||
{ name: '검정색', value: 'black' },
|
|
||||||
{ name: '빨강색', value: 'red' },
|
|
||||||
{ name: '파랑색', value: 'blue' },
|
|
||||||
{ name: '회색', value: 'gray' },
|
|
||||||
{ name: '황색', value: 'yellow' },
|
|
||||||
{ name: '녹색', value: 'green' },
|
|
||||||
{ name: '분홍색', value: 'pink' },
|
|
||||||
{ name: '황금색', value: 'gold' },
|
|
||||||
{ name: '남색', value: 'darkblue' },
|
|
||||||
]
|
|
||||||
export default function FontSetting(props) {
|
export default function FontSetting(props) {
|
||||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
|
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
|
||||||
const { id, setIsShow, pos = contextPopupPosition, type } = props
|
const { id, setIsShow, pos = contextPopupPosition, type, isConfig = false } = props
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { closePopup } = usePopup()
|
const { closePopup } = usePopup()
|
||||||
const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom)
|
const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom)
|
||||||
@ -57,7 +39,26 @@ export default function FontSetting(props) {
|
|||||||
const [selectedFontWeight, setSelectedFontWeight] = useState(currentFont.fontWeight)
|
const [selectedFontWeight, setSelectedFontWeight] = useState(currentFont.fontWeight)
|
||||||
const [selectedFontSize, setSelectedFontSize] = useState(currentFont.fontSize)
|
const [selectedFontSize, setSelectedFontSize] = useState(currentFont.fontSize)
|
||||||
const [selectedFontColor, setSelectedFontColor] = useState(currentFont.fontColor)
|
const [selectedFontColor, setSelectedFontColor] = useState(currentFont.fontColor)
|
||||||
|
const fontOptions = [
|
||||||
|
{ name: getMessage('font.style.normal'), value: 'normal' },
|
||||||
|
{ name: getMessage('font.style.italic'), value: 'italic' },
|
||||||
|
{
|
||||||
|
name: getMessage('font.style.bold'),
|
||||||
|
value: 'bold',
|
||||||
|
},
|
||||||
|
{ name: getMessage('font.style.bold.italic'), value: 'boldAndItalic' },
|
||||||
|
]
|
||||||
|
const fontColors = [
|
||||||
|
{ name: getMessage('color.black'), value: 'black' },
|
||||||
|
{ name: getMessage('color.red'), value: 'red' },
|
||||||
|
{ name: getMessage('color.blue'), value: 'blue' },
|
||||||
|
{ name: getMessage('color.gray'), value: 'gray' },
|
||||||
|
{ name: getMessage('color.yellow'), value: 'yellow' },
|
||||||
|
{ name: getMessage('color.green'), value: 'green' },
|
||||||
|
{ name: getMessage('color.pink'), value: 'pink' },
|
||||||
|
{ name: getMessage('color.gold'), value: 'gold' },
|
||||||
|
{ name: getMessage('color.darkblue'), value: 'darkblue' },
|
||||||
|
]
|
||||||
const handleSaveBtn = () => {
|
const handleSaveBtn = () => {
|
||||||
setGlobalFont((prev) => {
|
setGlobalFont((prev) => {
|
||||||
return {
|
return {
|
||||||
@ -83,7 +84,7 @@ export default function FontSetting(props) {
|
|||||||
className="modal-close"
|
className="modal-close"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (setIsShow) setIsShow(false)
|
if (setIsShow) setIsShow(false)
|
||||||
closePopup(id)
|
closePopup(id, isConfig)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
닫기
|
닫기
|
||||||
|
|||||||
@ -5,5 +5,9 @@ import { Fragment } from 'react'
|
|||||||
|
|
||||||
export default function PopupManager() {
|
export default function PopupManager() {
|
||||||
const [popup, setPopup] = useRecoilState(popupState)
|
const [popup, setPopup] = useRecoilState(popupState)
|
||||||
return popup.children?.map((child) => <Fragment key={child.id}>{child.component}</Fragment>)
|
|
||||||
|
return [
|
||||||
|
...popup?.config.map((child) => <Fragment key={child.id}>{child.component}</Fragment>),
|
||||||
|
...popup?.other.map((child) => <Fragment key={child.id}>{child.component}</Fragment>),
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,13 +8,41 @@ import { useMessage } from '@/hooks/useMessage'
|
|||||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||||
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
||||||
import EstimateFileUploader from './EstimateFileUploader'
|
import EstimateFileUploader from './EstimateFileUploader'
|
||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { globalLocaleStore } from '@/store/localeAtom'
|
||||||
|
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||||
|
import dayjs from 'dayjs'
|
||||||
|
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||||
|
import Select from 'react-select'
|
||||||
|
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
||||||
|
|
||||||
export default function Estimate({ params }) {
|
export default function Estimate({ params }) {
|
||||||
const [objectNo, setObjectNo] = useState('')
|
const [objectNo, setObjectNo] = useState('') //물건번호
|
||||||
const [files, setFiles] = useState([]) //첨부파일
|
const [planNo, setPlanNo] = useState('') //플랜번호
|
||||||
|
const [files, setFiles] = useState([]) // 보내는 첨부파일
|
||||||
|
|
||||||
|
//견적특이사항 접고 펼치기
|
||||||
|
const [hidden, setHidden] = useState(false)
|
||||||
|
|
||||||
|
//공통코드
|
||||||
|
const { findCommonCode } = useCommonCode()
|
||||||
|
const [honorificCodeList, setHonorificCodeList] = useState([]) //경칭 공통코드
|
||||||
|
|
||||||
|
const [startDate, setStartDate] = useState(new Date())
|
||||||
|
const singleDatePickerProps = {
|
||||||
|
startDate,
|
||||||
|
setStartDate,
|
||||||
|
}
|
||||||
|
|
||||||
const sessionState = useRecoilValue(sessionStore)
|
const sessionState = useRecoilValue(sessionStore)
|
||||||
const objectRecoil = useRecoilValue(floorPlanObjectState)
|
const objectRecoil = useRecoilValue(floorPlanObjectState)
|
||||||
|
|
||||||
|
//견적서 상세데이터
|
||||||
|
const { state, setState } = useEstimateController(params.pid)
|
||||||
|
|
||||||
|
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||||
|
const { get, post } = useAxios(globalLocaleState)
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
|
|
||||||
const { setMenuNumber } = useCanvasMenu()
|
const { setMenuNumber } = useCanvasMenu()
|
||||||
@ -27,46 +55,54 @@ export default function Estimate({ params }) {
|
|||||||
setUploadFiles: setFiles,
|
setUploadFiles: setFiles,
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
setObjectNo(objectRecoil.floorPlanObjectNo)
|
|
||||||
}, [objectRecoil])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (objectNo) {
|
|
||||||
//Q101X278191023001
|
|
||||||
console.log('세션정보::::', sessionState)
|
|
||||||
//상세API호출
|
|
||||||
}
|
|
||||||
}, [objectNo])
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMenuNumber(5)
|
setMenuNumber(5)
|
||||||
|
setObjectNo(objectRecoil.floorPlanObjectNo)
|
||||||
|
setPlanNo(params.pid)
|
||||||
|
|
||||||
|
// 공통코드
|
||||||
|
const code1 = findCommonCode(200800)
|
||||||
|
if (code1 != null) {
|
||||||
|
setHonorificCodeList(code1)
|
||||||
|
}
|
||||||
|
|
||||||
|
//견적특이사항 API호출
|
||||||
|
//http://localhost:8080/api/estimate/special-note-list
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
//견적일 set
|
||||||
|
useEffect(() => {
|
||||||
|
let estimateDatej = dayjs(startDate).format('YYYY-MM-DD')
|
||||||
|
setState({ estimateDate: estimateDatej })
|
||||||
|
}, [startDate])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sub-content estimate">
|
<div className="sub-content estimate">
|
||||||
<div className="sub-content-inner">
|
<div className="sub-content-inner">
|
||||||
{/* 물건번호, 견적서번호, 등록일, 변경일시 시작 */}
|
{/* 물건번호, 견적서번호, 등록일, 변경일시 시작 */}
|
||||||
|
{/* <form onSubmit={handleSubmit(onValid)}> */}
|
||||||
<div className="sub-content-box">
|
<div className="sub-content-box">
|
||||||
<div className="sub-table-box">
|
<div className="sub-table-box">
|
||||||
<div className="estimate-list-wrap one">
|
<div className="estimate-list-wrap one">
|
||||||
<div className="estimate-box">
|
<div className="estimate-box">
|
||||||
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
|
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
|
||||||
<div className="estimate-name">
|
<div className="estimate-name">
|
||||||
{objectNo} (Plan No: {params.pid})
|
{objectNo} (Plan No: {planNo})
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="estimate-box">
|
<div className="estimate-box">
|
||||||
<div className="estimate-tit">{getMessage('estimate.detail.estimateNo')}</div>
|
<div className="estimate-tit">{getMessage('estimate.detail.docNo')}</div>
|
||||||
<div className="estimate-name">5242310200065242</div>
|
<div className="estimate-name">{state.docNo}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="estimate-box">
|
<div className="estimate-box">
|
||||||
<div className="estimate-tit">{getMessage('estimate.detail.createDatetime')}</div>
|
<div className="estimate-tit">{getMessage('estimate.detail.drawingEstimateCreateDate')}</div>
|
||||||
<div className="estimate-name">9999.09.28</div>
|
<div className="estimate-name">
|
||||||
|
{state?.drawingEstimateCreateDate ? `${dayjs(state.drawingEstimateCreateDate).format('YYYY.MM.DD')}` : ''}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="estimate-box">
|
<div className="estimate-box">
|
||||||
<div className="estimate-tit">{getMessage('estimate.detail.lastEditDatetime')}</div>
|
<div className="estimate-tit">{getMessage('estimate.detail.lastEditDatetime')}</div>
|
||||||
<div className="estimate-name">9999.09.28 06:36</div>
|
<div className="estimate-name">{state?.lastEditDatetime ? `${dayjs(state.lastEditDatetime).format('YYYY.MM.DD HH:mm')}` : ''}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -99,7 +135,7 @@ export default function Estimate({ params }) {
|
|||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<div className="date-picker" style={{ width: '350px' }}>
|
<div className="date-picker" style={{ width: '350px' }}>
|
||||||
<SingleDatePicker />
|
<SingleDatePicker {...singleDatePickerProps} />
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -113,64 +149,152 @@ export default function Estimate({ params }) {
|
|||||||
</th>
|
</th>
|
||||||
<td>
|
<td>
|
||||||
<div className="input-wrap" style={{ width: '350px' }}>
|
<div className="input-wrap" style={{ width: '350px' }}>
|
||||||
<input type="text" className="input-light" defaultValue={'물건정보에서 입력한 담당자명 표시'} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-light"
|
||||||
|
defaultValue={state?.charger}
|
||||||
|
onChange={(e) => {
|
||||||
|
//담당자 charger
|
||||||
|
// console.log('담당자:::::', e.target.value)
|
||||||
|
setState({ charger: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{/* 안건명 */}
|
{/* 안건명 */}
|
||||||
<th>
|
<th>
|
||||||
{getMessage('estimate.detail.title')} <span className="important">*</span>
|
{getMessage('estimate.detail.objectName')} <span className="important">*</span>
|
||||||
</th>
|
</th>
|
||||||
<td colSpan={3}>
|
<td colSpan={3}>
|
||||||
<div className="form-flex-wrap">
|
<div className="form-flex-wrap">
|
||||||
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
||||||
<input type="text" className="input-light" defaultValue={'안건명:::'} />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-light"
|
||||||
|
defaultValue={state?.objectName}
|
||||||
|
onChange={(e) => {
|
||||||
|
//안건명 objectName
|
||||||
|
// console.log('안건명::::', e.target.value)
|
||||||
|
setState({ objectName: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="input-wrap" style={{ width: '200px' }}>
|
<div className="select-wrap" style={{ width: '200px' }}>
|
||||||
<input type="text" className="input-light" defaultValue={'경칭?'} />
|
<Select
|
||||||
|
id="objectNameOmit"
|
||||||
|
instanceId="objectNameOmit"
|
||||||
|
className="react-select-custom"
|
||||||
|
classNamePrefix="custom"
|
||||||
|
placeholder="Select"
|
||||||
|
options={honorificCodeList}
|
||||||
|
onChange={(e) => {
|
||||||
|
if (isObjectNotEmpty(e)) {
|
||||||
|
setState({ objectNameOmit: e.clCodeNm })
|
||||||
|
} else {
|
||||||
|
// console.log('XXX')
|
||||||
|
setState({ objectNameOmit: '' })
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
getOptionLabel={(x) => x.clCodeNm}
|
||||||
|
getOptionValue={(x) => x.clCode}
|
||||||
|
isClearable={true}
|
||||||
|
isSearchable={false}
|
||||||
|
value={honorificCodeList.filter(function (option) {
|
||||||
|
return option.clCodeNm === state.objectNameOmit
|
||||||
|
})}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{/* 메모 */}
|
{/* 물건정보에서 입력한 메모 */}
|
||||||
<th>{getMessage('estimate.detail.remarks')}</th>
|
<th>{getMessage('estimate.detail.objectRemarks')}</th>
|
||||||
<td colSpan={3}>물건정보에서 입력한 메모 표시</td>
|
<td colSpan={3}>{state?.objectRemarks}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{/* 주문분류 */}
|
{/* 주문분류 */}
|
||||||
<th>
|
<th>
|
||||||
{getMessage('estimate.detail.orderType')} <span className="important">*</span>
|
{getMessage('estimate.detail.estimateType')} <span className="important">*</span>
|
||||||
</th>
|
</th>
|
||||||
<td colSpan={3}>
|
<td colSpan={3}>
|
||||||
<div className="radio-wrap"></div>
|
<div className="radio-wrap">
|
||||||
|
<div className="d-check-radio light mr10">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="estimateType"
|
||||||
|
id="YJSS"
|
||||||
|
value={'YJSS'}
|
||||||
|
checked={state?.estimateType === 'YJSS' ? true : false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setState({ estimateType: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label htmlFor="YJSS">住宅PKG</label>
|
||||||
|
</div>
|
||||||
|
<div className="d-check-radio light">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
name="estimateType"
|
||||||
|
id="YJOD"
|
||||||
|
value={'YJOD'}
|
||||||
|
checked={state?.estimateType === 'YJOD' ? true : false}
|
||||||
|
onChange={(e) => {
|
||||||
|
setState({ estimateType: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<label htmlFor="YJOD">積上げ( YJOD )</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{/* 지붕재・사양시공 최대4개*/}
|
{/* 지붕재・사양시공 최대4개*/}
|
||||||
<th>{getMessage('estimate.detail.roofCns')}</th>
|
<th>{getMessage('estimate.detail.roofCns')}</th>
|
||||||
<td colSpan={3}>
|
<td colSpan={3}>
|
||||||
<div className="form-flex-wrap mb5">
|
{state?.roofMaterialIdMulti?.split('、').map((row, index) => {
|
||||||
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
//지붕재
|
||||||
<input type="text" className="input-light" defaultValue={'ハゼ式折板(角ハゼ)'} readOnly />
|
let roofList = row
|
||||||
</div>
|
let roofListLength = state?.roofMaterialIdMulti?.split('、').length
|
||||||
<div className="input-wrap" style={{ width: '200px' }}>
|
let style = 'mb5'
|
||||||
<input type="text" className="input-light" defaultValue={'標準施工'} readOnly />
|
if (roofListLength == index + 1) {
|
||||||
</div>
|
style = ''
|
||||||
</div>
|
}
|
||||||
<div className="form-flex-wrap mb5"></div>
|
//사양시공
|
||||||
<div className="form-flex-wrap mb5"></div>
|
let constructSpecificationMulti = state?.constructSpecificationMulti?.split('、')
|
||||||
{/* 마지막div엔 mb5 제외 */}
|
|
||||||
<div className="form-flex-wrap"></div>
|
return (
|
||||||
|
<>
|
||||||
|
<div className={`form-flex-wrap ${style}`}>
|
||||||
|
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
||||||
|
<input type="text" className="input-light" defaultValue={roofList} readOnly />
|
||||||
|
</div>
|
||||||
|
<div className="input-wrap" style={{ width: '200px' }}>
|
||||||
|
<input type="text" className="input-light" defaultValue={constructSpecificationMulti[index]} readOnly />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
})}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
{/* 비고 */}
|
{/* 비고 */}
|
||||||
<th>{getMessage('estimate.detail.note')}</th>
|
<th>{getMessage('estimate.detail.remarks')}</th>
|
||||||
<td colSpan={3}>
|
<td colSpan={3}>
|
||||||
<div className="input-wrap">
|
<div className="input-wrap">
|
||||||
<input type="text" className="input-light" />
|
<input
|
||||||
|
type="text"
|
||||||
|
className="input-light"
|
||||||
|
defaultValue={state?.remarks}
|
||||||
|
onChange={(e) => {
|
||||||
|
//비고
|
||||||
|
// console.log('비고:::::', e.target.value)
|
||||||
|
setState({ remarks: e.target.value })
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -200,25 +324,6 @@ export default function Estimate({ params }) {
|
|||||||
<th>{getMessage('estimate.detail.header.fileList1')}</th>
|
<th>{getMessage('estimate.detail.header.fileList1')}</th>
|
||||||
<td>
|
<td>
|
||||||
<EstimateFileUploader {...fileUploadProps} />
|
<EstimateFileUploader {...fileUploadProps} />
|
||||||
{/* <div className="drag-file-box">
|
|
||||||
<div className="btn-area">
|
|
||||||
<Button type="button" className="btn-origin grey" onClick={handleButtonClick}>
|
|
||||||
{getMessage('estimate.detail.fileList.btn')}
|
|
||||||
</Button>
|
|
||||||
<input
|
|
||||||
type="file"
|
|
||||||
id="fileUpload"
|
|
||||||
name="fileUpload"
|
|
||||||
ref={fileInputRef}
|
|
||||||
onChange={onChangeFiles}
|
|
||||||
style={{ display: 'none' }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="drag-file-area">
|
|
||||||
<p>Drag file here</p>
|
|
||||||
<ul className="file-list"></ul>
|
|
||||||
</div>
|
|
||||||
</div> */}
|
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
@ -246,21 +351,40 @@ export default function Estimate({ params }) {
|
|||||||
<h3 className="product">{getMessage('estimate.detail.header.specialEstimate')}</h3>
|
<h3 className="product">{getMessage('estimate.detail.header.specialEstimate')}</h3>
|
||||||
<div className="product_tit">{getMessage('estimate.detail.header.specialEstimateProductInfo')}</div>
|
<div className="product_tit">{getMessage('estimate.detail.header.specialEstimateProductInfo')}</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="left-unit-box">
|
||||||
|
<button className={`estimate-arr-btn down mr5 ${hidden ? '' : 'on'}`} onClick={() => setHidden(false)}></button>
|
||||||
|
<button className={`estimate-arr-btn up ${hidden ? 'on' : ''}`} onClick={() => setHidden(true)}></button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 공통코드영역시작 */}
|
{/* 견적 특이사항 코드영역시작 */}
|
||||||
<div className="special-note-check-wrap"></div>
|
<div className={`estimate-check-wrap ${hidden ? 'hide' : ''}`}>
|
||||||
{/* 공통코드영역끝 */}
|
<div className="estimate-check-inner">
|
||||||
{/* 견적특이사항 내용영역시작 */}
|
<div className="special-note-check-wrap"></div>
|
||||||
<div className="calculation-estimate"></div>
|
{/* 견적특이사항 선택한 내용?영역시작 */}
|
||||||
{/* 견적특이사항 내용영역끝 */}
|
<div className="calculation-estimate">
|
||||||
{/* 견적특이사항 끝 */}
|
<dl>
|
||||||
|
<dt>제목11??</dt>
|
||||||
|
<dd>제목1 비고</dd>
|
||||||
|
</dl>
|
||||||
|
<dl>
|
||||||
|
<dt>제목22??</dt>
|
||||||
|
<dd>제목2 비고</dd>
|
||||||
|
</dl>
|
||||||
|
</div>
|
||||||
|
{/* 견적특이사항 선택한 내용?영역끝 */}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 견적 특이사항 코드영역 끝 */}
|
||||||
|
|
||||||
|
{/* 견적특이사항 영역끝 */}
|
||||||
{/* 제품정보 시작 */}
|
{/* 제품정보 시작 */}
|
||||||
<div className="table-box-title-wrap">
|
<div className="table-box-title-wrap">
|
||||||
<div className="title-wrap">
|
<div className="title-wrap">
|
||||||
<h3>{getMessage('estimate.detail.header.specialEstimateProductInfo')}</h3>
|
<h3>{getMessage('estimate.detail.header.specialEstimateProductInfo')}</h3>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="estimate-wrap">
|
<div className="esimate-wrap">
|
||||||
<div className="estimate-list-wrap one">
|
<div className="estimate-list-wrap one">
|
||||||
<div className="estimate-box">
|
<div className="estimate-box">
|
||||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPcs')}</div>
|
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPcs')}</div>
|
||||||
@ -285,7 +409,7 @@ export default function Estimate({ params }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* YJOD면 아래영역 숨김 */}
|
{/* YJOD면 아래영역 숨김 */}
|
||||||
<div className="common-table bt-able">
|
<div className="common-table bt-able" style={{ display: state?.estimateType === 'YJSS' ? '' : 'none' }}>
|
||||||
<table>
|
<table>
|
||||||
<colgroup>
|
<colgroup>
|
||||||
<col style={{ width: '160px' }} />
|
<col style={{ width: '160px' }} />
|
||||||
@ -319,18 +443,35 @@ export default function Estimate({ params }) {
|
|||||||
<div className="estimate-product-option">
|
<div className="estimate-product-option">
|
||||||
<div className="product-price-wrap">
|
<div className="product-price-wrap">
|
||||||
<div className="product-price-tit">{getMessage('estimate.detail.header.showPrice')}</div>
|
<div className="product-price-tit">{getMessage('estimate.detail.header.showPrice')}</div>
|
||||||
<div className="select-wrap"></div>
|
<div className="select-wrap">
|
||||||
|
<select className="select-light" name="" id="">
|
||||||
|
<option value="">111</option>
|
||||||
|
<option value="">222</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
<button className="btn-origin grey ml5">{getMessage('estimate.detail.showPrice.btn1')}</button>
|
<button className="btn-origin grey ml5">{getMessage('estimate.detail.showPrice.btn1')}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="product-edit-wrap">
|
<div className="product-edit-wrap">
|
||||||
<div className="product-edit-explane">
|
<ul className="product-edit-explane">
|
||||||
<div className="click-check">
|
<li className="explane-item item01">
|
||||||
<span className="ico"></span>
|
<span className="ico"></span>
|
||||||
{getMessage('estimate.detail.showPrice.description')}
|
{getMessage('estimate.detail.showPrice.description1')}
|
||||||
</div>
|
</li>
|
||||||
</div>
|
<li className="explane-item item02">
|
||||||
|
<span className="ico"></span>
|
||||||
|
{getMessage('estimate.detail.showPrice.description2')}
|
||||||
|
</li>
|
||||||
|
<li className="explane-item item03">
|
||||||
|
<span className="ico"></span>
|
||||||
|
{getMessage('estimate.detail.showPrice.description3')}
|
||||||
|
</li>
|
||||||
|
<li className="explane-item item04">
|
||||||
|
<span className="ico"></span>
|
||||||
|
{getMessage('estimate.detail.showPrice.description4')}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
<div className="product-edit-btn">
|
<div className="product-edit-btn">
|
||||||
<button className="btn-origin navy mr5">
|
<button className="btn-origin navy mr5" type="submit">
|
||||||
<span className="plus"></span>
|
<span className="plus"></span>
|
||||||
{getMessage('estimate.detail.showPrice.btn2')}
|
{getMessage('estimate.detail.showPrice.btn2')}
|
||||||
</button>
|
</button>
|
||||||
@ -348,6 +489,7 @@ export default function Estimate({ params }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/* 기본정보끝 */}
|
{/* 기본정보끝 */}
|
||||||
|
{/* </form> */}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -32,6 +32,8 @@ import { menusState, menuTypeState } from '@/store/menuAtom'
|
|||||||
import useMenu from '@/hooks/common/useMenu'
|
import useMenu from '@/hooks/common/useMenu'
|
||||||
import { MENU } from '@/common/common'
|
import { MENU } from '@/common/common'
|
||||||
|
|
||||||
|
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
||||||
|
|
||||||
export default function CanvasMenu(props) {
|
export default function CanvasMenu(props) {
|
||||||
const { menuNumber, setMenuNumber } = props
|
const { menuNumber, setMenuNumber } = props
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
@ -49,8 +51,9 @@ export default function CanvasMenu(props) {
|
|||||||
const sessionState = useRecoilValue(sessionStore)
|
const sessionState = useRecoilValue(sessionStore)
|
||||||
const globalLocale = useRecoilValue(globalLocaleStore)
|
const globalLocale = useRecoilValue(globalLocaleStore)
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const { handleZoomClear } = useCanvasEvent()
|
const { handleZoomClear, handleZoom } = useCanvasEvent()
|
||||||
const { handleMenu } = useMenu()
|
const { handleMenu } = useMenu()
|
||||||
|
const { handleEstimateSubmit } = useEstimateController()
|
||||||
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const { currentCanvasPlan, saveCanvas } = usePlan()
|
const { currentCanvasPlan, saveCanvas } = usePlan()
|
||||||
@ -129,7 +132,7 @@ export default function CanvasMenu(props) {
|
|||||||
|
|
||||||
const handlePopup = () => {
|
const handlePopup = () => {
|
||||||
const id = uuidv4()
|
const id = uuidv4()
|
||||||
addPopup(id, 0, <SettingModal01 id={id} />)
|
addPopup(id, 1, <SettingModal01 id={id} />, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -201,14 +204,18 @@ export default function CanvasMenu(props) {
|
|||||||
<button
|
<button
|
||||||
className="control-btn minus"
|
className="control-btn minus"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
canvas.setZoom(canvas.getZoom() - 0.1)
|
handleZoom(false)
|
||||||
}}
|
}}
|
||||||
></button>
|
></button>
|
||||||
<span>{canvasZoom}%</span>
|
<span>{canvasZoom}%</span>
|
||||||
<button className="control-btn plus" onClick={handleZoomClear}></button>
|
<button
|
||||||
|
className="control-btn plus"
|
||||||
|
onClick={() => {
|
||||||
|
handleZoom(true)
|
||||||
|
}}
|
||||||
|
></button>
|
||||||
</div>
|
</div>
|
||||||
<div className="btn-from">
|
<div className="btn-from">
|
||||||
<button className="btn07" onClick={handleClear}></button>
|
|
||||||
<button className="btn08" onClick={handleSaveCanvas}></button>
|
<button className="btn08" onClick={handleSaveCanvas}></button>
|
||||||
<button className="btn09"></button>
|
<button className="btn09"></button>
|
||||||
</div>
|
</div>
|
||||||
@ -222,7 +229,7 @@ export default function CanvasMenu(props) {
|
|||||||
<span className="ico ico01"></span>
|
<span className="ico ico01"></span>
|
||||||
<span>{getMessage('plan.menu.estimate.docDown')}</span>
|
<span>{getMessage('plan.menu.estimate.docDown')}</span>
|
||||||
</button>
|
</button>
|
||||||
<button className="btn-frame gray ico-flx">
|
<button className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||||
<span className="ico ico02"></span>
|
<span className="ico ico02"></span>
|
||||||
<span>{getMessage('plan.menu.estimate.save')}</span>
|
<span>{getMessage('plan.menu.estimate.save')}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -50,7 +50,11 @@ export default function CircuitTrestleSetting({ id }) {
|
|||||||
Next
|
Next
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
{tabNum === 3 && <button className="btn-frame modal act">保存 (仮割り当て)</button>}
|
{tabNum === 3 && (
|
||||||
|
<button className="btn-frame modal act">
|
||||||
|
{`${getMessage('modal.common.save')} (${getMessage('modal.circuit.trestle.setting.alloc.trestle')})`}
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -114,7 +114,7 @@ export default function PowerConditionalSelect({ setTabNum }) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-right-wrap mb10">
|
<div className="circuit-right-wrap mb10">
|
||||||
<button className="btn-frame self mr5">追加</button>
|
<button className="btn-frame self mr5">{getMessage('modal.common.add')}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-data-form">
|
<div className="circuit-data-form">
|
||||||
<span className="normal-font">
|
<span className="normal-font">
|
||||||
@ -132,12 +132,12 @@ export default function PowerConditionalSelect({ setTabNum }) {
|
|||||||
<div className="slope-wrap">
|
<div className="slope-wrap">
|
||||||
<div className="d-check-box pop mb15">
|
<div className="d-check-box pop mb15">
|
||||||
<input type="checkbox" id="ch03" />
|
<input type="checkbox" id="ch03" />
|
||||||
<label htmlFor="ch03">同一傾斜同一方面の面積の場合、同じ面として回路を分ける。</label>
|
<label htmlFor="ch03"> {getMessage('modal.circuit.trestle.setting.power.conditional.select.check1')}</label>
|
||||||
</div>
|
</div>
|
||||||
<div className="d-check-box pop">
|
<div className="d-check-box pop">
|
||||||
<input type="checkbox" id="ch04" />
|
<input type="checkbox" id="ch04" />
|
||||||
<label className="red" htmlFor="ch04">
|
<label className="red" htmlFor="ch04">
|
||||||
MAX接続(過積)で回路を分ける。
|
{getMessage('modal.circuit.trestle.setting.power.conditional.select.check2')}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -18,8 +18,8 @@ export default function StepUp({}) {
|
|||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>シリアル枚数</th>
|
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.serial.amount')}</th>
|
||||||
<th>総回路数</th>
|
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.total.amount')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -49,14 +49,14 @@ export default function StepUp({}) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="circuit-table-flx-wrap">
|
<div className="circuit-table-flx-wrap">
|
||||||
<div className="circuit-table-flx-box">
|
<div className="circuit-table-flx-box">
|
||||||
<div className="bold-font mb10">接続する</div>
|
<div className="bold-font mb10">{getMessage('modal.circuit.trestle.setting.step.up.allocation.connected')}</div>
|
||||||
<div className="roof-module-table mb10">
|
<div className="roof-module-table mb10">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th style={{ width: '140px' }}>名称</th>
|
<th style={{ width: '140px' }}>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
|
||||||
<th>回路数</th>
|
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.circuit.amount')}</th>
|
||||||
<th>昇圧回路数</th>
|
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -80,7 +80,7 @@ export default function StepUp({}) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="bottom-wrap">
|
<div className="bottom-wrap">
|
||||||
<div className="circuit-right-wrap mb10">
|
<div className="circuit-right-wrap mb10">
|
||||||
<button className="btn-frame self mr5">追加</button>
|
<button className="btn-frame self mr5">{getMessage('modal.common.add')}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-data-form">
|
<div className="circuit-data-form">
|
||||||
<span className="normal-font">
|
<span className="normal-font">
|
||||||
@ -90,13 +90,13 @@ export default function StepUp({}) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-table-flx-box">
|
<div className="circuit-table-flx-box">
|
||||||
<div className="bold-font mb10">昇圧オプション</div>
|
<div className="bold-font mb10">{getMessage('modal.circuit.trestle.setting.step.up.allocation.option')}</div>
|
||||||
<div className="roof-module-table mb10">
|
<div className="roof-module-table mb10">
|
||||||
<table>
|
<table>
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>名称</th>
|
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
|
||||||
<th>昇圧回路数</th>
|
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
@ -113,7 +113,7 @@ export default function StepUp({}) {
|
|||||||
</div>
|
</div>
|
||||||
<div className="bottom-wrap">
|
<div className="bottom-wrap">
|
||||||
<div className="circuit-right-wrap mb10">
|
<div className="circuit-right-wrap mb10">
|
||||||
<button className="btn-frame self mr5">追加</button>
|
<button className="btn-frame self mr5">{getMessage('modal.common.add')}</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-data-form">
|
<div className="circuit-data-form">
|
||||||
<span className="normal-font">
|
<span className="normal-font">
|
||||||
@ -124,7 +124,7 @@ export default function StepUp({}) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="circuit-count-input">
|
<div className="circuit-count-input">
|
||||||
<span className="normal-font">綿調道区分</span>
|
<span className="normal-font">{getMessage('modal.module.basic.setting.module.cotton.classification')}</span>
|
||||||
<div className="input-grid mr5" style={{ width: '40px' }}>
|
<div className="input-grid mr5" style={{ width: '40px' }}>
|
||||||
<input type="text" className="input-origin block" />
|
<input type="text" className="input-origin block" />
|
||||||
</div>
|
</div>
|
||||||
@ -395,7 +395,7 @@ export default function StepUp({}) {
|
|||||||
<div className="slope-wrap">
|
<div className="slope-wrap">
|
||||||
<div className="outline-form">
|
<div className="outline-form">
|
||||||
<span className="mr10" style={{ width: 'auto' }}>
|
<span className="mr10" style={{ width: 'auto' }}>
|
||||||
モニターの選択
|
{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
|
||||||
</span>
|
</span>
|
||||||
<div className="grid-select mr10">
|
<div className="grid-select mr10">
|
||||||
<QSelectBox title={'電力検出ユニット (モニター付き)'} option={SelectOption01} />
|
<QSelectBox title={'電力検出ユニット (モニター付き)'} option={SelectOption01} />
|
||||||
|
|||||||
@ -4,13 +4,13 @@ export default function PassivityCircuitAllocation() {
|
|||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const moduleData = {
|
const moduleData = {
|
||||||
header: [
|
header: [
|
||||||
{ name: getMessage('屋根面'), prop: 'roofShape' },
|
{ name: getMessage('modal.panel.batch.statistic.roof.shape'), prop: 'roofShape' },
|
||||||
{
|
{
|
||||||
name: getMessage('Q.TRON M-G2'),
|
name: getMessage('Q.TRON M-G2'),
|
||||||
prop: 'moduleName',
|
prop: 'moduleName',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: getMessage('発電量 (kW)'),
|
name: `${getMessage('modal.panel.batch.statistic.power.generation.amount')}(kW)`,
|
||||||
prop: 'powerGeneration',
|
prop: 'powerGeneration',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -5,9 +5,7 @@ import { useMessage } from '@/hooks/useMessage'
|
|||||||
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
|
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
|
||||||
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
||||||
import { onlyNumberInputChange } from '@/util/input-utils'
|
import { onlyNumberInputChange } from '@/util/input-utils'
|
||||||
import { fabric } from 'fabric'
|
import { settingModalGridOptionsState } from '@/store/settingAtom'
|
||||||
import { gridColorState } from '@/store/gridAtom'
|
|
||||||
import { gridDisplaySelector, settingModalGridOptionsState } from '@/store/settingAtom'
|
|
||||||
import { useAxios } from '@/hooks/useAxios'
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
@ -33,7 +31,7 @@ export default function DotLineGrid(props) {
|
|||||||
// const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state
|
// const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state
|
||||||
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
||||||
const [close, setClose] = useState(false)
|
const [close, setClose] = useState(false)
|
||||||
const { id, setIsShow, pos = { x: 840, y: -815 } } = props
|
const { id, setIsShow, pos = { x: 840, y: -815 }, isConfig = false } = props
|
||||||
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
|
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
|
||||||
|
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -142,7 +140,7 @@ export default function DotLineGrid(props) {
|
|||||||
await post({ url: `/api/canvas-management/canvas-grid-settings`, data: patternData }).then((res) => {
|
await post({ url: `/api/canvas-management/canvas-grid-settings`, data: patternData }).then((res) => {
|
||||||
swalFire({ text: getMessage(res.returnMessage) })
|
swalFire({ text: getMessage(res.returnMessage) })
|
||||||
setDotLineGridSettingState({ ...currentSetting })
|
setDotLineGridSettingState({ ...currentSetting })
|
||||||
closePopup(id)
|
closePopup(id, isConfig)
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||||
@ -213,7 +211,7 @@ export default function DotLineGrid(props) {
|
|||||||
className="modal-close"
|
className="modal-close"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsShow(false)
|
setIsShow(false)
|
||||||
closePopup(id)
|
closePopup(id, isConfig)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
닫기
|
닫기
|
||||||
|
|||||||
@ -78,14 +78,14 @@ export default function GridOption() {
|
|||||||
// 점 선 그리드 설정 모달
|
// 점 선 그리드 설정 모달
|
||||||
setShowDotLineGridModal(selectedOption.selected)
|
setShowDotLineGridModal(selectedOption.selected)
|
||||||
|
|
||||||
addPopup(dotLineId, 2, <DotLineGrid {...dotLineGridProps} />)
|
addPopup(dotLineId, 2, <DotLineGrid {...dotLineGridProps} />, true)
|
||||||
} else if (selectedOption.id === 3) {
|
} else if (selectedOption.id === 3) {
|
||||||
// 흡착점 모드
|
// 흡착점 모드
|
||||||
setAdsorptionPointAddMode(selectedOption.selected)
|
setAdsorptionPointAddMode(selectedOption.selected)
|
||||||
} else if (selectedOption.id === 4) {
|
} else if (selectedOption.id === 4) {
|
||||||
// 그리드 색 설정 모달
|
// 그리드 색 설정 모달
|
||||||
setShowColorPickerModal(selectedOption.selected)
|
setShowColorPickerModal(selectedOption.selected)
|
||||||
addPopup(colorId, 2, <ColorPickerModal {...colorPickerProps} />)
|
addPopup(colorId, 2, <ColorPickerModal {...colorPickerProps} />, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
setGridOptions(newGridOptions)
|
setGridOptions(newGridOptions)
|
||||||
@ -94,6 +94,7 @@ export default function GridOption() {
|
|||||||
const dotLineGridProps = {
|
const dotLineGridProps = {
|
||||||
id: dotLineId,
|
id: dotLineId,
|
||||||
setIsShow: setShowDotLineGridModal,
|
setIsShow: setShowDotLineGridModal,
|
||||||
|
isConfig: true,
|
||||||
pos: {
|
pos: {
|
||||||
x: 845,
|
x: 845,
|
||||||
y: 180,
|
y: 180,
|
||||||
@ -106,6 +107,7 @@ export default function GridOption() {
|
|||||||
setColor: setGridColor,
|
setColor: setGridColor,
|
||||||
isShow: showColorPickerModal,
|
isShow: showColorPickerModal,
|
||||||
setIsShow: setShowColorPickerModal,
|
setIsShow: setShowColorPickerModal,
|
||||||
|
isConfig: true,
|
||||||
pos: {
|
pos: {
|
||||||
x: 785,
|
x: 785,
|
||||||
y: 180,
|
y: 180,
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { useMessage } from '@/hooks/useMessage'
|
import { useMessage } from '@/hooks/useMessage'
|
||||||
import React, { useEffect, useState } from 'react'
|
import React, { useEffect, useState } from 'react'
|
||||||
import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting'
|
import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting'
|
||||||
@ -67,6 +67,7 @@ export default function SecondOption() {
|
|||||||
id: fontId,
|
id: fontId,
|
||||||
pos: { x: 745, y: 180 },
|
pos: { x: 745, y: 180 },
|
||||||
setIsShow: setShowFontSettingModal,
|
setIsShow: setShowFontSettingModal,
|
||||||
|
isConfig: true,
|
||||||
}
|
}
|
||||||
const planSizeProps = {
|
const planSizeProps = {
|
||||||
id: planSizeId,
|
id: planSizeId,
|
||||||
@ -86,36 +87,41 @@ export default function SecondOption() {
|
|||||||
case 'font1': {
|
case 'font1': {
|
||||||
//문자 글꼴변경
|
//문자 글꼴변경
|
||||||
setShowFontSettingModal(true)
|
setShowFontSettingModal(true)
|
||||||
|
setShowDimensionLineSettingModal(false)
|
||||||
fontProps.type = 'commonText'
|
fontProps.type = 'commonText'
|
||||||
fontProps.id = fontId + 1
|
fontProps.id = fontId + 1
|
||||||
addPopup(fontId + 1, 2, <FontSetting {...fontProps} />)
|
addPopup(fontId + 1, 2, <FontSetting {...fontProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'font2': {
|
case 'font2': {
|
||||||
//흐름 방향 글꼴 변경
|
//흐름 방향 글꼴 변경
|
||||||
setShowFontSettingModal(true)
|
setShowFontSettingModal(true)
|
||||||
|
setShowDimensionLineSettingModal(false)
|
||||||
fontProps.type = 'flowText'
|
fontProps.type = 'flowText'
|
||||||
fontProps.id = fontId + 2
|
fontProps.id = fontId + 2
|
||||||
addPopup(fontId + 2, 2, <FontSetting {...fontProps} />)
|
addPopup(fontId + 2, 2, <FontSetting {...fontProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'font3': {
|
case 'font3': {
|
||||||
//치수 글꼴변경
|
//치수 글꼴변경
|
||||||
setShowFontSettingModal(true)
|
setShowFontSettingModal(true)
|
||||||
|
|
||||||
|
setShowDimensionLineSettingModal(false)
|
||||||
fontProps.type = 'lengthText'
|
fontProps.type = 'lengthText'
|
||||||
fontProps.id = fontId + 3
|
fontProps.id = fontId + 3
|
||||||
addPopup(fontId + 3, 2, <FontSetting {...fontProps} />)
|
addPopup(fontId + 3, 2, <FontSetting {...fontProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'font4': {
|
case 'font4': {
|
||||||
//회로번호 글꼴변경
|
//회로번호 글꼴변경
|
||||||
setShowFontSettingModal(true)
|
setShowFontSettingModal(true)
|
||||||
|
setShowDimensionLineSettingModal(false)
|
||||||
fontProps.type = 'circuitNumberText'
|
fontProps.type = 'circuitNumberText'
|
||||||
fontProps.id = fontId
|
fontProps.id = fontId
|
||||||
addPopup(fontId, 2, <FontSetting {...fontProps} />)
|
addPopup(fontId, 2, <FontSetting {...fontProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,7 +129,7 @@ export default function SecondOption() {
|
|||||||
//치수선 설정
|
//치수선 설정
|
||||||
if (!showDimensionLineSettingModal) {
|
if (!showDimensionLineSettingModal) {
|
||||||
setShowDimensionLineSettingModal(true)
|
setShowDimensionLineSettingModal(true)
|
||||||
addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />)
|
addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />, true)
|
||||||
} else {
|
} else {
|
||||||
setShowDimensionLineSettingModal(false)
|
setShowDimensionLineSettingModal(false)
|
||||||
closePopup(dimensionId)
|
closePopup(dimensionId)
|
||||||
@ -134,7 +140,8 @@ export default function SecondOption() {
|
|||||||
case 'planSize': {
|
case 'planSize': {
|
||||||
//도면크기 설정
|
//도면크기 설정
|
||||||
setShowPlanSizeSettingModal(true)
|
setShowPlanSizeSettingModal(true)
|
||||||
addPopup(planSizeId, 2, <PlanSizeSetting {...planSizeProps} />)
|
setShowDimensionLineSettingModal(false)
|
||||||
|
addPopup(planSizeId, 2, <PlanSizeSetting {...planSizeProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import { useRecoilValue } from 'recoil'
|
|||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
|
|
||||||
export default function SettingModal01(props) {
|
export default function SettingModal01(props) {
|
||||||
const { setShowDotLineGridModal, setShowFontSettingModal, id } = props
|
const { setShowDotLineGridModal, setShowFontSettingModal, id, isConfig } = props
|
||||||
console.log(props)
|
console.log(props)
|
||||||
const [buttonAct, setButtonAct] = useState(1)
|
const [buttonAct, setButtonAct] = useState(1)
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
@ -27,7 +27,7 @@ export default function SettingModal01(props) {
|
|||||||
<div className={`modal-pop-wrap sm mount`}>
|
<div className={`modal-pop-wrap sm mount`}>
|
||||||
<div className="modal-head">
|
<div className="modal-head">
|
||||||
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
|
<h1 className="title">{getMessage('modal.canvas.setting')}</h1>
|
||||||
<button className="modal-close" onClick={() => closePopup(id)}>
|
<button className="modal-close" onClick={() => closePopup(id, true)}>
|
||||||
닫기
|
닫기
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -87,6 +87,7 @@ export default function DimensionLineSetting(props) {
|
|||||||
setFontColor: setOriginFontColor,
|
setFontColor: setOriginFontColor,
|
||||||
fontSize: originFontSize,
|
fontSize: originFontSize,
|
||||||
setFontSize: setOriginFontSize,
|
setFontSize: setOriginFontSize,
|
||||||
|
isConfig: true,
|
||||||
id: fontModalId,
|
id: fontModalId,
|
||||||
pos: {
|
pos: {
|
||||||
x: 455,
|
x: 455,
|
||||||
@ -97,17 +98,17 @@ export default function DimensionLineSetting(props) {
|
|||||||
const popupHandle = (type) => {
|
const popupHandle = (type) => {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'color':
|
case 'color':
|
||||||
addPopup(colorModalId, 3, <ColorPickerModal {...colorPickerProps} />)
|
addPopup(colorModalId, 3, <ColorPickerModal {...colorPickerProps} />, true)
|
||||||
break
|
break
|
||||||
case 'font':
|
case 'font':
|
||||||
addPopup(fontModalId, 3, <FontSetting {...fontProps} />)
|
addPopup(fontModalId, 3, <FontSetting {...fontProps} />, true)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WithDraggable isShow={true} pos={pos}>
|
<WithDraggable isShow={true} pos={pos}>
|
||||||
<div className={`modal-pop-wrap xxxm`}>
|
<div className={`modal-pop-wrap xxxm mount`}>
|
||||||
<div className="modal-head">
|
<div className="modal-head">
|
||||||
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')} </h1>
|
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.dimension.line')} </h1>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@ -15,14 +15,14 @@ export default function PlanSizeSetting(props) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<WithDraggable isShow={true} pos={pos}>
|
<WithDraggable isShow={true} pos={pos}>
|
||||||
<div className={`modal-pop-wrap xsm`}>
|
<div className={`modal-pop-wrap xsm mount`}>
|
||||||
<div className="modal-head">
|
<div className="modal-head">
|
||||||
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.plan.size.setting')}</h1>
|
<h1 className="title">{getMessage('modal.canvas.setting.font.plan.absorption.plan.size.setting')}</h1>
|
||||||
<button
|
<button
|
||||||
className="modal-close"
|
className="modal-close"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsShow(false)
|
setIsShow(false)
|
||||||
closePopup(id)
|
closePopup(id, true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
닫기
|
닫기
|
||||||
|
|||||||
153
src/hooks/floorPlan/estimate/useEstimateController.js
Normal file
153
src/hooks/floorPlan/estimate/useEstimateController.js
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
import { useAxios } from '@/hooks/useAxios'
|
||||||
|
import { useEffect, useReducer, useState } from 'react'
|
||||||
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
|
import { globalLocaleStore } from '@/store/localeAtom'
|
||||||
|
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||||
|
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||||
|
const reducer = (prevState, nextState) => {
|
||||||
|
return { ...prevState, ...nextState }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Constants
|
||||||
|
const ESTIMATE_API_ENDPOINT = '/api/estimates' // API 엔드포인트 정의
|
||||||
|
|
||||||
|
const defaultEstimateData = {
|
||||||
|
estimateDate: new Date(), //견적일
|
||||||
|
charger: '', //담당자
|
||||||
|
objectName: '', //안건명
|
||||||
|
objectNameOmit: '', //경칭코드
|
||||||
|
estimateType: 'YJOD', //주문분류
|
||||||
|
remarks: '', //비고
|
||||||
|
estimateOption: '', //견적특이사항
|
||||||
|
// itemList: [{ id: 1, name: '' }],
|
||||||
|
//아이템에 필요없는거 빼기
|
||||||
|
itemList: [
|
||||||
|
{
|
||||||
|
amount: '',
|
||||||
|
fileUploadFlg: '',
|
||||||
|
itemChangeFlg: '',
|
||||||
|
itemGroup: '',
|
||||||
|
itemId: '', //키값??
|
||||||
|
itemName: '',
|
||||||
|
itemNo: '',
|
||||||
|
moduleFlg: '',
|
||||||
|
objectNo: '',
|
||||||
|
pkgMaterialFlg: '',
|
||||||
|
planNo: '',
|
||||||
|
pnowW: '',
|
||||||
|
salePrice: '',
|
||||||
|
saleTotPrice: '',
|
||||||
|
specification: '',
|
||||||
|
unit: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper functions
|
||||||
|
// const updateItemInList = (itemList, id, updates) => {
|
||||||
|
const updateItemInList = (itemList, itemId, updates) => {
|
||||||
|
// return itemList.map((item) => (item.id === id ? { ...item, ...updates } : item))
|
||||||
|
return itemList.map((item) => (item.itemId === itemId ? { ...item, ...updates } : item))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useEstimateController = (planNo) => {
|
||||||
|
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||||
|
const objectRecoil = useRecoilValue(floorPlanObjectState)
|
||||||
|
const [estimateData, setEstimateData] = useRecoilState(estimateState)
|
||||||
|
|
||||||
|
const { get, post } = useAxios(globalLocaleState)
|
||||||
|
|
||||||
|
const [isLoading, setIsLoading] = useState(false)
|
||||||
|
const { promisePost } = useAxios()
|
||||||
|
const [state, setState] = useReducer(reducer, defaultEstimateData)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isLoading) {
|
||||||
|
if (objectRecoil.floorPlanObjectNo && planNo) {
|
||||||
|
fetchSetting()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
// 상세 조회
|
||||||
|
const fetchSetting = async () => {
|
||||||
|
try {
|
||||||
|
await get({ url: `/api/estimate/${objectRecoil.floorPlanObjectNo}/${planNo}/detail` }).then((res) => {
|
||||||
|
if (isObjectNotEmpty(res)) {
|
||||||
|
setState(res)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
setIsLoading(true)
|
||||||
|
} catch (error) {
|
||||||
|
console.error('견적서 상세조회 Error: ', error)
|
||||||
|
setIsLoading(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const updateItem = (id, updates) => {
|
||||||
|
const updateItem = (itemId, updates) => {
|
||||||
|
setState({
|
||||||
|
// itemList: updateItemInList(state.itemList, id, updates),
|
||||||
|
itemList: updateItemInList(state.itemList, itemId, updates),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const addItem = () => {
|
||||||
|
// const newId = Math.max(...state.itemList.map((item) => item.id)) + 1
|
||||||
|
const newItemId = Math.max(...state.itemList.map((item) => item.itemId)) + 1
|
||||||
|
setState({
|
||||||
|
// itemList: [...state.itemList, { id: newId, name: '' }],
|
||||||
|
//셋팅할필요없는거 빼기
|
||||||
|
itemList: [
|
||||||
|
...state.itemList,
|
||||||
|
{
|
||||||
|
itemId: newItemId,
|
||||||
|
amount: '',
|
||||||
|
fileUploadFlg: '',
|
||||||
|
itemChangeFlg: '',
|
||||||
|
itemGroup: '',
|
||||||
|
itemName: '',
|
||||||
|
itemNo: '',
|
||||||
|
moduleFlg: '',
|
||||||
|
objectNo: '',
|
||||||
|
pkgMaterialFlg: '',
|
||||||
|
planNo: '',
|
||||||
|
pnowW: '',
|
||||||
|
salePrice: '',
|
||||||
|
saleTotPrice: '',
|
||||||
|
specification: '',
|
||||||
|
unit: '',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setEstimateData({ ...state })
|
||||||
|
}, [state])
|
||||||
|
|
||||||
|
//견적서 저장
|
||||||
|
const handleEstimateSubmit = async () => {
|
||||||
|
console.log('::담긴 estimateData:::', estimateData)
|
||||||
|
return
|
||||||
|
try {
|
||||||
|
const result = await promisePost({
|
||||||
|
url: ESTIMATE_API_ENDPOINT,
|
||||||
|
data: estimateData,
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to submit estimate:', error)
|
||||||
|
throw error
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
state,
|
||||||
|
setState,
|
||||||
|
updateItem,
|
||||||
|
addItem,
|
||||||
|
handleEstimateSubmit,
|
||||||
|
fetchSetting,
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -223,9 +223,9 @@ export function useCanvasSetting() {
|
|||||||
const option1 = settingModalFirstOptions.option1
|
const option1 = settingModalFirstOptions.option1
|
||||||
|
|
||||||
// 'allocDisplay' 할당 표시
|
// 'allocDisplay' 할당 표시
|
||||||
// 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine'
|
// 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
|
||||||
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
|
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
|
||||||
// 'lineDisplay' 지붕선 표시 'roof', 'roofBase'
|
// 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
|
||||||
// 'wordDisplay' 문자 표시
|
// 'wordDisplay' 문자 표시
|
||||||
// 'circuitNumDisplay' 회로번호 표시
|
// 'circuitNumDisplay' 회로번호 표시
|
||||||
// 'flowDisplay' 흐름방향 표시 'arrow'
|
// 'flowDisplay' 흐름방향 표시 'arrow'
|
||||||
@ -248,7 +248,7 @@ export function useCanvasSetting() {
|
|||||||
optionName = ['lindGrid', 'dotGrid']
|
optionName = ['lindGrid', 'dotGrid']
|
||||||
break
|
break
|
||||||
case 'lineDisplay': //지붕선 표시
|
case 'lineDisplay': //지붕선 표시
|
||||||
optionName = ['roof', 'roofBase']
|
optionName = ['roof', POLYGON_TYPE.ROOF]
|
||||||
break
|
break
|
||||||
case 'wordDisplay': //문자 표시
|
case 'wordDisplay': //문자 표시
|
||||||
optionName = ['6']
|
optionName = ['6']
|
||||||
|
|||||||
@ -13,9 +13,9 @@ export function useFirstOption() {
|
|||||||
const option1 = settingModalFirstOptions.option1
|
const option1 = settingModalFirstOptions.option1
|
||||||
|
|
||||||
// 'allocDisplay' 할당 표시
|
// 'allocDisplay' 할당 표시
|
||||||
// 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine'
|
// 'outlineDisplay' 외벽선 표시 'outerLine', POLYGON_TYPE.WALL
|
||||||
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
|
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
|
||||||
// 'lineDisplay' 지붕선 표시 'roof', 'roofBase'
|
// 'lineDisplay' 지붕선 표시 'roof', POLYGON_TYPE.ROOF
|
||||||
// 'wordDisplay' 문자 표시
|
// 'wordDisplay' 문자 표시
|
||||||
// 'circuitNumDisplay' 회로번호 표시
|
// 'circuitNumDisplay' 회로번호 표시
|
||||||
// 'flowDisplay' 흐름방향 표시 'arrow'
|
// 'flowDisplay' 흐름방향 표시 'arrow'
|
||||||
@ -37,7 +37,7 @@ export function useFirstOption() {
|
|||||||
optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid']
|
optionName = ['lineGrid', 'dotGrid', 'adsorptionPoint', 'tempGrid']
|
||||||
break
|
break
|
||||||
case 'lineDisplay': //지붕선 표시
|
case 'lineDisplay': //지붕선 표시
|
||||||
optionName = ['roof', 'roofBase']
|
optionName = ['roof', POLYGON_TYPE.ROOF]
|
||||||
break
|
break
|
||||||
case 'wordDisplay': //문자 표시
|
case 'wordDisplay': //문자 표시
|
||||||
optionName = ['6']
|
optionName = ['6']
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import {
|
|||||||
outerLineLength2State,
|
outerLineLength2State,
|
||||||
outerLineTypeState,
|
outerLineTypeState,
|
||||||
} from '@/store/outerLineAtom'
|
} from '@/store/outerLineAtom'
|
||||||
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util'
|
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine, polygonToTurfPolygon } from '@/util/canvas-util'
|
||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
|
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
@ -23,6 +23,7 @@ import { booleanPointInPolygon } from '@turf/turf'
|
|||||||
import { usePopup } from '@/hooks/usePopup'
|
import { usePopup } from '@/hooks/usePopup'
|
||||||
import { calculateAngle } from '@/util/qpolygon-utils'
|
import { calculateAngle } from '@/util/qpolygon-utils'
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
|
import { POLYGON_TYPE } from '@/common/common'
|
||||||
|
|
||||||
// 보조선 작성
|
// 보조선 작성
|
||||||
export function useAuxiliaryDrawing(id) {
|
export function useAuxiliaryDrawing(id) {
|
||||||
@ -80,7 +81,7 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// innerLines가 있을경우 삭제
|
// innerLines가 있을경우 삭제
|
||||||
const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
if (roofs.length === 0) {
|
if (roofs.length === 0) {
|
||||||
swalFire({ text: '지붕형상이 없습니다.' })
|
swalFire({ text: '지붕형상이 없습니다.' })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
@ -561,7 +562,7 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
/*const allLines = [...auxiliaryLines]
|
/*const allLines = [...auxiliaryLines]
|
||||||
|
|
||||||
roofBases.forEach((roofBase) => {
|
roofBases.forEach((roofBase) => {
|
||||||
@ -611,9 +612,41 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
lineHistory.current.push(newLine)
|
lineHistory.current.push(newLine)
|
||||||
|
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
|
||||||
removeLine(line1)
|
removeLine(line1)
|
||||||
intersectionPoints.current.push(...interSectionPointsWithRoofLines)
|
intersectionPoints.current.push(...interSectionPointsWithRoofLines)
|
||||||
return
|
return
|
||||||
|
} else if (interSectionPointsWithRoofLines.length === 1) {
|
||||||
|
//지붕선과 만나는 점이 하나일 경우
|
||||||
|
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0])
|
||||||
|
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0])
|
||||||
|
|
||||||
|
if (!(distance1 === 0 || distance2 === 0)) {
|
||||||
|
if (distance1 >= distance2) {
|
||||||
|
const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'auxiliaryLine',
|
||||||
|
isFixed: true,
|
||||||
|
})
|
||||||
|
lineHistory.current.push(newLine)
|
||||||
|
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
|
||||||
|
removeLine(line1)
|
||||||
|
} else {
|
||||||
|
const newLine = addLine([line1.x2, line1.y2, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], {
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 1,
|
||||||
|
selectable: false,
|
||||||
|
name: 'auxiliaryLine',
|
||||||
|
isFixed: true,
|
||||||
|
})
|
||||||
|
lineHistory.current.push(newLine)
|
||||||
|
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
|
||||||
|
removeLine(line1)
|
||||||
|
}
|
||||||
|
intersectionPoints.current.push(interSectionPointsWithRoofLines[0])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//보조선과 만나는 점을 찾는다.
|
//보조선과 만나는 점을 찾는다.
|
||||||
@ -659,6 +692,7 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
lineHistory.current.push(newLine)
|
lineHistory.current.push(newLine)
|
||||||
|
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
|
||||||
removeLine(line1)
|
removeLine(line1)
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -742,7 +776,7 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
|
||||||
//lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거
|
//lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거
|
||||||
// 겹치는 선 하나는 canvas에서 제거한다.
|
// 겹치는 선 하나는 canvas에서 제거한다.
|
||||||
@ -772,9 +806,13 @@ export function useAuxiliaryDrawing(id) {
|
|||||||
})
|
})
|
||||||
const roofInnerLines = innerLines.filter((line) => {
|
const roofInnerLines = innerLines.filter((line) => {
|
||||||
const inPolygon1 =
|
const inPolygon1 =
|
||||||
tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) || roofBase.inPolygon({ x: line.x1, y: line.y1 })
|
tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) ||
|
||||||
|
roofBase.inPolygon({ x: line.x1, y: line.y1 }) ||
|
||||||
|
roofBase.lines.some((line) => isPointOnLine(line, { x: line.x1, y: line.y1 }))
|
||||||
const inPolygon2 =
|
const inPolygon2 =
|
||||||
tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) || roofBase.inPolygon({ x: line.x2, y: line.y2 })
|
tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) ||
|
||||||
|
roofBase.inPolygon({ x: line.x2, y: line.y2 }) ||
|
||||||
|
roofBase.lines.some((line) => isPointOnLine(line, { x: line.x2, y: line.y2 }))
|
||||||
|
|
||||||
if (inPolygon1 && inPolygon2) {
|
if (inPolygon1 && inPolygon2) {
|
||||||
line.attributes = { ...line.attributes, roofId: roofBase.id }
|
line.attributes = { ...line.attributes, roofId: roofBase.id }
|
||||||
|
|||||||
@ -160,7 +160,7 @@ export function useEavesGableEdit(id) {
|
|||||||
attributes,
|
attributes,
|
||||||
})
|
})
|
||||||
|
|
||||||
const roofBases = canvas?.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
|
|
||||||
roofBases.forEach((roof) => {
|
roofBases.forEach((roof) => {
|
||||||
roof.innerLines.forEach((line) => {
|
roof.innerLines.forEach((line) => {
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useRef } from 'react'
|
import { useEffect, useRef } from 'react'
|
||||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
import { useRecoilValue, useResetRecoilState } from 'recoil'
|
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
|
||||||
import { canvasState, currentObjectState } from '@/store/canvasAtom'
|
import { canvasState, currentObjectState } from '@/store/canvasAtom'
|
||||||
import { useMode } from '@/hooks/useMode'
|
import { useMode } from '@/hooks/useMode'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
|
|||||||
@ -82,12 +82,12 @@ export function useRoofAllocationSetting(id) {
|
|||||||
const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(roofMaterials[0])
|
const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(roofMaterials[0])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
if (roofBases.length === 0) {
|
if (roofBases.length === 0) {
|
||||||
swalFire({ text: '할당할 지붕이 없습니다.' })
|
swalFire({ text: '할당할 지붕이 없습니다.' })
|
||||||
closePopup(id)
|
closePopup(id)
|
||||||
}
|
}
|
||||||
// if (type === 'roofBase') {
|
// if (type === POLYGON_TYPE.ROOF) {
|
||||||
// // 지붕면 할당
|
// // 지붕면 할당
|
||||||
//
|
//
|
||||||
// } else if ('roof') {
|
// } else if ('roof') {
|
||||||
@ -105,7 +105,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
|
|
||||||
// 선택한 지붕재로 할당
|
// 선택한 지붕재로 할당
|
||||||
const handleSave = () => {
|
const handleSave = () => {
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
||||||
roofBases.forEach((roofBase) => {
|
roofBases.forEach((roofBase) => {
|
||||||
try {
|
try {
|
||||||
@ -118,7 +118,7 @@ export function useRoofAllocationSetting(id) {
|
|||||||
canvas.remove(line)
|
canvas.remove(line)
|
||||||
})
|
})
|
||||||
|
|
||||||
canvas.remove(roofBase)
|
// canvas.remove(roofBase)
|
||||||
})
|
})
|
||||||
|
|
||||||
wallLines.forEach((wallLine) => {
|
wallLines.forEach((wallLine) => {
|
||||||
|
|||||||
@ -185,7 +185,7 @@ export function useRoofShapePassivitySetting(id) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handleLineToPolygon = () => {
|
const handleLineToPolygon = () => {
|
||||||
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
|
const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
|
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
|
||||||
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
|
||||||
exceptObjs.forEach((obj) => {
|
exceptObjs.forEach((obj) => {
|
||||||
|
|||||||
@ -383,7 +383,7 @@ export function useRoofShapeSetting(id) {
|
|||||||
|
|
||||||
canvas
|
canvas
|
||||||
.getObjects()
|
.getObjects()
|
||||||
.filter((obj) => obj.name === 'roofBase')
|
.filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||||
.forEach((obj) => {
|
.forEach((obj) => {
|
||||||
canvas.remove(...obj.innerLines)
|
canvas.remove(...obj.innerLines)
|
||||||
canvas.remove(obj)
|
canvas.remove(obj)
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
|
import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom'
|
||||||
@ -18,6 +18,10 @@ export function useCanvasEvent() {
|
|||||||
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
||||||
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
canvas?.setZoom(canvasZoom / 100)
|
||||||
|
}, [canvasZoom])
|
||||||
|
|
||||||
// 기본적인 이벤트 필요시 추가
|
// 기본적인 이벤트 필요시 추가
|
||||||
const attachDefaultEventOnCanvas = () => {
|
const attachDefaultEventOnCanvas = () => {
|
||||||
removeEventOnCanvas()
|
removeEventOnCanvas()
|
||||||
@ -365,6 +369,14 @@ export function useCanvasEvent() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleZoom = (isZoom) => {
|
||||||
|
if (isZoom) {
|
||||||
|
setCanvasZoom(canvasZoom + 10)
|
||||||
|
} else {
|
||||||
|
setCanvasZoom(canvasZoom - 10)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const handleZoomClear = () => {
|
const handleZoomClear = () => {
|
||||||
setCanvasZoom(100)
|
setCanvasZoom(100)
|
||||||
canvas.set({ zoom: 1 })
|
canvas.set({ zoom: 1 })
|
||||||
@ -376,5 +388,6 @@ export function useCanvasEvent() {
|
|||||||
setCanvasForEvent,
|
setCanvasForEvent,
|
||||||
attachDefaultEventOnCanvas,
|
attachDefaultEventOnCanvas,
|
||||||
handleZoomClear,
|
handleZoomClear,
|
||||||
|
handleZoom,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -244,7 +244,7 @@ export function useContextMenu() {
|
|||||||
if (temp.length > 0) menu = temp
|
if (temp.length > 0) menu = temp
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClick(null, menu)
|
if (menu) handleClick(null, menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -256,8 +256,6 @@ export function useContextMenu() {
|
|||||||
}, [currentContextMenu])
|
}, [currentContextMenu])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
console.log('currentObject', currentObject)
|
|
||||||
|
|
||||||
if (currentObject?.name) {
|
if (currentObject?.name) {
|
||||||
console.log(currentObject?.name)
|
console.log(currentObject?.name)
|
||||||
switch (currentObject.name) {
|
switch (currentObject.name) {
|
||||||
@ -477,7 +475,7 @@ export function useContextMenu() {
|
|||||||
{
|
{
|
||||||
id: 'dimensionLineDisplayEdit',
|
id: 'dimensionLineDisplayEdit',
|
||||||
name: getMessage('contextmenu.display.edit'),
|
name: getMessage('contextmenu.display.edit'),
|
||||||
component: <DimensionLineSetting id={popupId} />,
|
component: <DimensionLineSetting id={popupId} isConfig={false} />,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
])
|
])
|
||||||
|
|||||||
@ -4,47 +4,90 @@ import { contextPopupState, popupState } from '@/store/popupAtom'
|
|||||||
export function usePopup() {
|
export function usePopup() {
|
||||||
const [popup, setPopup] = useRecoilState(popupState)
|
const [popup, setPopup] = useRecoilState(popupState)
|
||||||
const [contextMenuPopup, setContextMenuPopup] = useRecoilState(contextPopupState)
|
const [contextMenuPopup, setContextMenuPopup] = useRecoilState(contextPopupState)
|
||||||
const addPopup = (id, depth, component) => {
|
|
||||||
setPopup({ children: [...filterDepth(depth), { id: id, depth: depth, component: component }] })
|
const addPopup = (id, depth, component, isConfig = false) => {
|
||||||
|
setPopup({
|
||||||
|
config: isConfig ? [...filterDepth(depth, isConfig), { id, depth, component, isConfig }] : [...popup.config],
|
||||||
|
other: !isConfig ? [...filterDepth(depth, isConfig), { id, depth, component, isConfig }] : [...popup.other],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const closePopup = (id) => {
|
const closePopup = (id, isConfig = false) => {
|
||||||
if (contextMenuPopup) setContextMenuPopup(null)
|
if (contextMenuPopup) setContextMenuPopup(null)
|
||||||
setPopup({ children: [...filterChildrenPopup(id).filter((child) => child.id !== id)] })
|
if (isConfig) {
|
||||||
|
setPopup({
|
||||||
|
config: [...filterChildrenPopup(id, isConfig).filter((child) => child.id !== id)],
|
||||||
|
other: popup.other,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setPopup({
|
||||||
|
config: popup.config,
|
||||||
|
other: [...filterChildrenPopup(id, isConfig).filter((child) => child.id !== id)],
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterPopup = (depth) => {
|
const filterPopup = (depth) => {
|
||||||
setPopup({ children: [...filterDepth(depth)] })
|
setPopup({
|
||||||
|
config: [...filterDepth(depth)],
|
||||||
|
other: [],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterChildrenPopup = (id) => {
|
const filterChildrenPopup = (id, isConfig) => {
|
||||||
const target = popup.children.filter((child) => child.id === id)
|
let target = []
|
||||||
if (target.length !== 0) {
|
if (isConfig) {
|
||||||
return popup.children.filter((child) => child.depth <= target[0].depth)
|
target = popup?.config.filter((child) => child.id === id)
|
||||||
|
} else {
|
||||||
|
target = popup?.other.filter((child) => child.id === id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return popup.children
|
if (target.length !== 0) {
|
||||||
|
if (isConfig) {
|
||||||
|
return popup?.config.filter((child) => child.depth <= target[0].depth)
|
||||||
|
} else {
|
||||||
|
return popup?.other.filter((child) => child.depth <= target[0].depth)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (isConfig) {
|
||||||
|
return popup.config
|
||||||
|
} else {
|
||||||
|
return popup.other
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const closePopups = (ids) => {
|
const closePopups = (ids) => {
|
||||||
setPopup({ children: [...popup.children.filter((child) => !ids.includes(child.id))] })
|
setPopup({
|
||||||
|
config: [...popup?.config.filter((child) => !ids.includes(child.id))],
|
||||||
|
other: [...popup?.other.filter((child) => !ids.includes(child.id))],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const closeAll = () => {
|
const closeAll = () => {
|
||||||
setPopup({ children: [] })
|
setPopup({
|
||||||
|
other: [],
|
||||||
|
config: [],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const closePrevPopup = () => {
|
const closePrevPopup = () => {
|
||||||
setPopup({ children: [...popup.children.slice(popup.children.length - 1)] })
|
setPopup({
|
||||||
|
config: [...popup?.slice(popup?.length - 1)],
|
||||||
|
other: [],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterDepth = (depth) => {
|
const filterDepth = (depth, isConfig) => {
|
||||||
return [...popup.children.filter((child) => child.depth !== depth)]
|
if (isConfig) {
|
||||||
|
return [...popup?.config.filter((child) => child.depth < depth)]
|
||||||
|
} else {
|
||||||
|
return [...popup?.other.filter((child) => child.depth < depth)]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
popup,
|
popup,
|
||||||
setPopup,
|
|
||||||
addPopup,
|
addPopup,
|
||||||
closePopup,
|
closePopup,
|
||||||
closePopups,
|
closePopups,
|
||||||
|
|||||||
@ -123,6 +123,7 @@
|
|||||||
"modal.module.basic.setting.auto.placement": "設定値に自動配置",
|
"modal.module.basic.setting.auto.placement": "設定値に自動配置",
|
||||||
"plan.menu.module.circuit.setting.circuit.trestle.setting": "回路と架台の設定",
|
"plan.menu.module.circuit.setting.circuit.trestle.setting": "回路と架台の設定",
|
||||||
"modal.circuit.trestle.setting": "回路と架台設定",
|
"modal.circuit.trestle.setting": "回路と架台設定",
|
||||||
|
"modal.circuit.trestle.setting.alloc.trestle": "仮割り当て",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select": "パワーコンディショナーを選択",
|
"modal.circuit.trestle.setting.power.conditional.select": "パワーコンディショナーを選択",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.name": "名称",
|
"modal.circuit.trestle.setting.power.conditional.select.name": "名称",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.rated.output": "定格出力",
|
"modal.circuit.trestle.setting.power.conditional.select.rated.output": "定格出力",
|
||||||
@ -130,6 +131,8 @@
|
|||||||
"modal.circuit.trestle.setting.power.conditional.select.max.connection": "最大接続枚数",
|
"modal.circuit.trestle.setting.power.conditional.select.max.connection": "最大接続枚数",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.max.overload": "過積最大枚数",
|
"modal.circuit.trestle.setting.power.conditional.select.max.overload": "過積最大枚数",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.output.current": "出力電流",
|
"modal.circuit.trestle.setting.power.conditional.select.output.current": "出力電流",
|
||||||
|
"modal.circuit.trestle.setting.power.conditional.select.check1": "同一傾斜同一方面の面積の場合、同じ面として回路を分ける。",
|
||||||
|
"modal.circuit.trestle.setting.power.conditional.select.check2": "MAX接続(過積)で回路を分ける。",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation": "回路割り当て",
|
"modal.circuit.trestle.setting.circuit.allocation": "回路割り当て",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.auto": "自動回路割り当て",
|
"modal.circuit.trestle.setting.circuit.allocation.auto": "自動回路割り当て",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity": "手動回路割当",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity": "手動回路割当",
|
||||||
@ -140,6 +143,12 @@
|
|||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "すべての回路番号の初期化",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "すべての回路番号の初期化",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "番号確定",
|
||||||
"modal.circuit.trestle.setting.step.up.allocation": "昇圧設定",
|
"modal.circuit.trestle.setting.step.up.allocation": "昇圧設定",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.serial.amount": "シリアル枚数",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.total.amount": "総回路数",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.connected": "接続する",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "昇圧回路数",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.option": "昇圧オプション",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.select.monitor": "モニターの選択",
|
||||||
"plan.menu.module.circuit.setting.plan.orientation": "図面方位の適用",
|
"plan.menu.module.circuit.setting.plan.orientation": "図面方位の適用",
|
||||||
"plan.menu.estimate": "見積",
|
"plan.menu.estimate": "見積",
|
||||||
"plan.menu.estimate.roof.alloc": "屋根面の割り当て",
|
"plan.menu.estimate.roof.alloc": "屋根面の割り当て",
|
||||||
@ -474,6 +483,19 @@
|
|||||||
"commons.east": "ドン",
|
"commons.east": "ドン",
|
||||||
"commons.south": "南",
|
"commons.south": "南",
|
||||||
"commons.north": "北",
|
"commons.north": "北",
|
||||||
|
"font.style.normal": "보통(JA)",
|
||||||
|
"font.style.italic": "기울임꼴(JA)",
|
||||||
|
"font.style.bold": "굵게(JA)",
|
||||||
|
"font.style.bold.italic": "굵은 기울임꼴(JA)",
|
||||||
|
"color.black": "검정색(JA)",
|
||||||
|
"color.red": "빨강색(JA)",
|
||||||
|
"color.blue": "파랑색(JA)",
|
||||||
|
"color.gray": "회색(JA)",
|
||||||
|
"color.yellow": "황색(JA)",
|
||||||
|
"color.green": "녹색(JA)",
|
||||||
|
"color.pink": "분홍색(JA)",
|
||||||
|
"color.gold": "황금색(JA)",
|
||||||
|
"color.darkblue": "남색(JA)",
|
||||||
"site.name": "Q.CAST III",
|
"site.name": "Q.CAST III",
|
||||||
"site.sub_name": "太陽光発電システム図面管理サイト",
|
"site.sub_name": "太陽光発電システム図面管理サイト",
|
||||||
"board.notice.title": "お知らせ",
|
"board.notice.title": "お知らせ",
|
||||||
@ -814,7 +836,10 @@
|
|||||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)",
|
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)",
|
||||||
"estimate.detail.header.showPrice": "価格表示",
|
"estimate.detail.header.showPrice": "価格表示",
|
||||||
"estimate.detail.showPrice.btn1": "Pricing",
|
"estimate.detail.showPrice.btn1": "Pricing",
|
||||||
"estimate.detail.showPrice.description": "クリックして製品の特異性を確認する",
|
"estimate.detail.showPrice.description1": "製品価格 OPEN",
|
||||||
|
"estimate.detail.showPrice.description2": "追加, 変更資材",
|
||||||
|
"estimate.detail.showPrice.description3": "添付必須",
|
||||||
|
"estimate.detail.showPrice.description4": "クリックして製品の特異性を確認する",
|
||||||
"estimate.detail.showPrice.btn2": "製品を追加",
|
"estimate.detail.showPrice.btn2": "製品を追加",
|
||||||
"estimate.detail.showPrice.btn3": "製品削除"
|
"estimate.detail.showPrice.btn3": "製品削除"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,6 +127,7 @@
|
|||||||
"modal.module.basic.setting.auto.placement": "설정값으로 자동 배치",
|
"modal.module.basic.setting.auto.placement": "설정값으로 자동 배치",
|
||||||
"plan.menu.module.circuit.setting.circuit.trestle.setting": "회로 및 가대 설정",
|
"plan.menu.module.circuit.setting.circuit.trestle.setting": "회로 및 가대 설정",
|
||||||
"modal.circuit.trestle.setting": "회로 및 가대설정",
|
"modal.circuit.trestle.setting": "회로 및 가대설정",
|
||||||
|
"modal.circuit.trestle.setting.alloc.trestle": "가대할당",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select": "파워컨디셔너 선택",
|
"modal.circuit.trestle.setting.power.conditional.select": "파워컨디셔너 선택",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.name": "명칭",
|
"modal.circuit.trestle.setting.power.conditional.select.name": "명칭",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.rated.output": "정격출력",
|
"modal.circuit.trestle.setting.power.conditional.select.rated.output": "정격출력",
|
||||||
@ -134,6 +135,8 @@
|
|||||||
"modal.circuit.trestle.setting.power.conditional.select.max.connection": "최대접속매수",
|
"modal.circuit.trestle.setting.power.conditional.select.max.connection": "최대접속매수",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.max.overload": "과적최대매수",
|
"modal.circuit.trestle.setting.power.conditional.select.max.overload": "과적최대매수",
|
||||||
"modal.circuit.trestle.setting.power.conditional.select.output.current": "출력전류",
|
"modal.circuit.trestle.setting.power.conditional.select.output.current": "출력전류",
|
||||||
|
"modal.circuit.trestle.setting.power.conditional.select.check1": "동일경사 동일 방면의 면적인 경우, 같은 면으로서 회로를 나눈다.",
|
||||||
|
"modal.circuit.trestle.setting.power.conditional.select.check2": "MAX 접속(과적)으로 회로를 나눈다.",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation": "회로 할당",
|
"modal.circuit.trestle.setting.circuit.allocation": "회로 할당",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.auto": "자동 회로 할당",
|
"modal.circuit.trestle.setting.circuit.allocation.auto": "자동 회로 할당",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity": "수동 회로 할당",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity": "수동 회로 할당",
|
||||||
@ -144,6 +147,12 @@
|
|||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "모든 회로번호 초기화",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset": "모든 회로번호 초기화",
|
||||||
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정",
|
"modal.circuit.trestle.setting.circuit.allocation.passivity.circuit.num.fix": "번호 확정",
|
||||||
"modal.circuit.trestle.setting.step.up.allocation": "승압 설정",
|
"modal.circuit.trestle.setting.step.up.allocation": "승압 설정",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.serial.amount": "직렬매수",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.total.amount": "총 회로수",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.connected": "연결함",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.circuit.amount": "승압회로수",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.option": "승압옵션",
|
||||||
|
"modal.circuit.trestle.setting.step.up.allocation.select.monitor": "모니터 선택",
|
||||||
"plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용",
|
"plan.menu.module.circuit.setting.plan.orientation": "도면 방위 적용",
|
||||||
"plan.menu.estimate": "견적서",
|
"plan.menu.estimate": "견적서",
|
||||||
"plan.menu.estimate.roof.alloc": "지붕면 할당",
|
"plan.menu.estimate.roof.alloc": "지붕면 할당",
|
||||||
@ -480,6 +489,19 @@
|
|||||||
"commons.east": "동",
|
"commons.east": "동",
|
||||||
"commons.south": "남",
|
"commons.south": "남",
|
||||||
"commons.north": "북",
|
"commons.north": "북",
|
||||||
|
"font.style.normal": "보통",
|
||||||
|
"font.style.italic": "기울임꼴",
|
||||||
|
"font.style.bold": "굵게",
|
||||||
|
"font.style.bold.italic": "굵은 기울임꼴",
|
||||||
|
"color.black": "검정색",
|
||||||
|
"color.red": "빨강색",
|
||||||
|
"color.blue": "파랑색",
|
||||||
|
"color.gray": "회색",
|
||||||
|
"color.yellow": "황색",
|
||||||
|
"color.green": "녹색",
|
||||||
|
"color.pink": "분홍색",
|
||||||
|
"color.gold": "황금색",
|
||||||
|
"color.darkblue": "남색",
|
||||||
"site.name": "Q.CAST III",
|
"site.name": "Q.CAST III",
|
||||||
"site.sub_name": "태양광 발전 시스템 도면관리 사이트",
|
"site.sub_name": "태양광 발전 시스템 도면관리 사이트",
|
||||||
"board.notice.title": "공지사항",
|
"board.notice.title": "공지사항",
|
||||||
@ -820,7 +842,10 @@
|
|||||||
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
|
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
|
||||||
"estimate.detail.header.showPrice": "가격표시",
|
"estimate.detail.header.showPrice": "가격표시",
|
||||||
"estimate.detail.showPrice.btn1": "Pricing",
|
"estimate.detail.showPrice.btn1": "Pricing",
|
||||||
"estimate.detail.showPrice.description": "클릭하여 제품 특이사항 확인",
|
"estimate.detail.showPrice.description1": "제품 가격 OPEN",
|
||||||
|
"estimate.detail.showPrice.description2": "추가, 변경 자재",
|
||||||
|
"estimate.detail.showPrice.description3": "첨부필수",
|
||||||
|
"estimate.detail.showPrice.description4": "클릭하여 제품 특이사항 확인",
|
||||||
"estimate.detail.showPrice.btn2": "제품추가",
|
"estimate.detail.showPrice.btn2": "제품추가",
|
||||||
"estimate.detail.showPrice.btn3": "제품삭제"
|
"estimate.detail.showPrice.btn3": "제품삭제"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,3 +7,9 @@ export const floorPlanObjectState = atom({
|
|||||||
},
|
},
|
||||||
dangerouslyAllowMutability: true,
|
dangerouslyAllowMutability: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const estimateState = atom({
|
||||||
|
key: `estimateState`,
|
||||||
|
default: {},
|
||||||
|
dangerouslyAllowMutability: true,
|
||||||
|
})
|
||||||
|
|||||||
@ -7,7 +7,8 @@ import { atom } from 'recoil'
|
|||||||
export const popupState = atom({
|
export const popupState = atom({
|
||||||
key: 'popupState',
|
key: 'popupState',
|
||||||
default: {
|
default: {
|
||||||
children: [],
|
config: [],
|
||||||
|
other: [],
|
||||||
},
|
},
|
||||||
dangerouslyAllowMutability: true,
|
dangerouslyAllowMutability: true,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export const settingModalFirstOptionsState = atom({
|
|||||||
default: {
|
default: {
|
||||||
option1: [
|
option1: [
|
||||||
{ id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false },
|
{ id: 1, column: 'allocDisplay', name: 'modal.canvas.setting.first.option.alloc', selected: false },
|
||||||
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: false },
|
{ id: 2, column: 'outlineDisplay', name: 'modal.canvas.setting.first.option.outline', selected: true },
|
||||||
{ id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false },
|
{ id: 3, column: 'gridDisplay', name: 'modal.canvas.setting.first.option.grid', selected: false },
|
||||||
{ id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false },
|
{ id: 4, column: 'lineDisplay', name: 'modal.canvas.setting.first.option.roof.line', selected: false },
|
||||||
{ id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: false },
|
{ id: 5, column: 'wordDisplay', name: 'modal.canvas.setting.first.option.word', selected: false },
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -239,6 +239,7 @@ footer{
|
|||||||
nav{
|
nav{
|
||||||
.nav-list{
|
.nav-list{
|
||||||
.nav-item{
|
.nav-item{
|
||||||
|
a,
|
||||||
button{
|
button{
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,9 +37,10 @@
|
|||||||
top: 50%;
|
top: 50%;
|
||||||
left: 0;
|
left: 0;
|
||||||
transform: translateY(-50%);
|
transform: translateY(-50%);
|
||||||
width: 20px;
|
width: 22px;
|
||||||
height: 20px;
|
height: 22px;
|
||||||
background: url(../../public/static/images/main/id_icon.svg)no-repeat center;
|
background: url(../../public/static/images/main/id_icon.svg)no-repeat center;
|
||||||
|
background-size: cover;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.store-arr{
|
.store-arr{
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -521,9 +521,11 @@ export function isPointOnLine(line, point) {
|
|||||||
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
|
||||||
return a * point.x + b * point.y + c === 0
|
const result = Math.abs(a * point.x + b * point.y + c) / 100
|
||||||
}
|
|
||||||
|
|
||||||
|
// 점이 선 위에 있는지 확인
|
||||||
|
return result <= 10
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 점과 가까운 line 찾기
|
* 점과 가까운 line 찾기
|
||||||
* @param point
|
* @param point
|
||||||
|
|||||||
@ -1,6 +1,14 @@
|
|||||||
import { fabric } from 'fabric'
|
import { fabric } from 'fabric'
|
||||||
import { QLine } from '@/components/fabric/QLine'
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDegreeByChon, getDirectionByPoint } from '@/util/canvas-util'
|
import {
|
||||||
|
calculateIntersection,
|
||||||
|
distanceBetweenPoints,
|
||||||
|
findClosestPoint,
|
||||||
|
getDegreeByChon,
|
||||||
|
getDirectionByPoint,
|
||||||
|
isPointOnLine,
|
||||||
|
} from '@/util/canvas-util'
|
||||||
|
|
||||||
import { QPolygon } from '@/components/fabric/QPolygon'
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import * as turf from '@turf/turf'
|
import * as turf from '@turf/turf'
|
||||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
@ -958,10 +966,13 @@ export default function offsetPolygon(vertices, offset) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const splitPolygonWithLines = (polygon) => {
|
/*export const splitPolygonWithLines = (polygon) => {
|
||||||
const roofs = []
|
const roofs = []
|
||||||
const allLines = [...polygon.innerLines]
|
const allLines = [...polygon.innerLines]
|
||||||
|
|
||||||
|
const polygonLines = polygon.lines
|
||||||
|
const innerLines = polygon.innerLines
|
||||||
|
|
||||||
allLines.forEach((line) => {
|
allLines.forEach((line) => {
|
||||||
line.startPoint = { x: line.x1, y: line.y1 }
|
line.startPoint = { x: line.x1, y: line.y1 }
|
||||||
line.endPoint = { x: line.x2, y: line.y2 }
|
line.endPoint = { x: line.x2, y: line.y2 }
|
||||||
@ -984,10 +995,10 @@ export const splitPolygonWithLines = (polygon) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/!**
|
||||||
* 좌표 테스트용
|
* 좌표 테스트용
|
||||||
*/
|
*!/
|
||||||
/*allLines.forEach((line) => {
|
/!*allLines.forEach((line) => {
|
||||||
const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, {
|
const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, {
|
||||||
left: line.startPoint.x,
|
left: line.startPoint.x,
|
||||||
top: line.startPoint.y,
|
top: line.startPoint.y,
|
||||||
@ -1016,10 +1027,10 @@ export const splitPolygonWithLines = (polygon) => {
|
|||||||
|
|
||||||
polygon.canvas.add(text)
|
polygon.canvas.add(text)
|
||||||
polygon.canvas.renderAll()
|
polygon.canvas.renderAll()
|
||||||
})*/
|
})*!/
|
||||||
/**
|
/!**
|
||||||
* 좌표 테스트용 끝
|
* 좌표 테스트용 끝
|
||||||
*/
|
*!/
|
||||||
|
|
||||||
polygon.points.forEach((point, index) => {
|
polygon.points.forEach((point, index) => {
|
||||||
allLines.forEach((line) => {
|
allLines.forEach((line) => {
|
||||||
@ -1165,6 +1176,273 @@ export const splitPolygonWithLines = (polygon) => {
|
|||||||
polygon.canvas.add(roof)
|
polygon.canvas.add(roof)
|
||||||
polygon.canvas.renderAll()
|
polygon.canvas.renderAll()
|
||||||
})
|
})
|
||||||
|
}*/
|
||||||
|
export const splitPolygonWithLines = (polygon) => {
|
||||||
|
const canvas = polygon.canvas
|
||||||
|
polygon.set({ visible: false })
|
||||||
|
let innerLines = [...polygon.innerLines]
|
||||||
|
let polygonLines = [...polygon.lines]
|
||||||
|
const roofs = []
|
||||||
|
|
||||||
|
let delIndexs = []
|
||||||
|
let newLines = []
|
||||||
|
|
||||||
|
polygonLines.forEach((line, index) => {
|
||||||
|
line.tempIndex = index
|
||||||
|
innerLines.forEach((innerLine) => {
|
||||||
|
let newLine1, newLine2
|
||||||
|
if (isPointOnLine(line, innerLine.startPoint)) {
|
||||||
|
// 해당 line을 startPoint로 나눈 line2개를 canvas에 추가 하고 기존 line을 제거한다.
|
||||||
|
newLine1 = new QLine([line.x1, line.y1, innerLine.startPoint.x, innerLine.startPoint.y], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
newLine2 = new QLine([innerLine.startPoint.x, innerLine.startPoint.y, line.x2, line.y2], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
delIndexs.push(polygonLines.indexOf(line))
|
||||||
|
canvas.remove(polygonLines[polygonLines.indexOf(line)])
|
||||||
|
if (newLine1.length / 10 > 10) {
|
||||||
|
newLines.push(newLine1)
|
||||||
|
}
|
||||||
|
if (newLine2.length / 10 > 10) {
|
||||||
|
newLines.push(newLine2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isPointOnLine(line, innerLine.endPoint)) {
|
||||||
|
newLine1 = new QLine([line.x1, line.y1, innerLine.endPoint.x, innerLine.endPoint.y], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
|
||||||
|
newLine2 = new QLine([innerLine.endPoint.x, innerLine.endPoint.y, line.x2, line.y2], {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'black',
|
||||||
|
strokeWidth: 3,
|
||||||
|
})
|
||||||
|
delIndexs.push(polygonLines.indexOf(line))
|
||||||
|
canvas.remove(polygonLines[polygonLines.indexOf(line)])
|
||||||
|
if (newLine1.length / 10 > 10) {
|
||||||
|
newLines.push(newLine1)
|
||||||
|
}
|
||||||
|
if (newLine2.length / 10 > 10) {
|
||||||
|
newLines.push(newLine2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
polygonLines = polygonLines.filter((line) => !delIndexs.includes(line.tempIndex))
|
||||||
|
polygonLines = [...polygonLines, ...newLines]
|
||||||
|
|
||||||
|
const allLines = [...polygonLines, ...innerLines]
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 왼쪽 상단을 startPoint로 전부 변경
|
||||||
|
*/
|
||||||
|
allLines.forEach((line) => {
|
||||||
|
let startPoint // 시작점
|
||||||
|
let endPoint // 끝점
|
||||||
|
if (line.x1 < line.x2) {
|
||||||
|
startPoint = { x: line.x1, y: line.y1 }
|
||||||
|
endPoint = { x: line.x2, y: line.y2 }
|
||||||
|
} else if (line.x1 > line.x2) {
|
||||||
|
startPoint = { x: line.x2, y: line.y2 }
|
||||||
|
endPoint = { x: line.x1, y: line.y1 }
|
||||||
|
} else {
|
||||||
|
if (line.y1 < line.y2) {
|
||||||
|
startPoint = { x: line.x1, y: line.y1 }
|
||||||
|
endPoint = { x: line.x2, y: line.y2 }
|
||||||
|
} else {
|
||||||
|
startPoint = { x: line.x2, y: line.y2 }
|
||||||
|
endPoint = { x: line.x1, y: line.y1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line.startPoint = startPoint
|
||||||
|
line.endPoint = endPoint
|
||||||
|
})
|
||||||
|
|
||||||
|
polygonLines.forEach((line) => {
|
||||||
|
const startPoint = line.startPoint // 시작점
|
||||||
|
let arrivalPoint = line.endPoint // 도착점
|
||||||
|
|
||||||
|
let currentPoint = startPoint
|
||||||
|
const roofPoints = [startPoint]
|
||||||
|
|
||||||
|
const startLine = line
|
||||||
|
const visitPoints = [startPoint]
|
||||||
|
const visitLines = [startLine]
|
||||||
|
let cnt = 0
|
||||||
|
|
||||||
|
while (!isSamePoint(currentPoint, arrivalPoint)) {
|
||||||
|
line.set({ stroke: 'red' })
|
||||||
|
canvas.renderAll()
|
||||||
|
let nextLines = allLines.filter(
|
||||||
|
(line2) =>
|
||||||
|
(isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) &&
|
||||||
|
line !== line2 &&
|
||||||
|
innerLines.includes(line2) &&
|
||||||
|
!visitLines.includes(line2),
|
||||||
|
)
|
||||||
|
|
||||||
|
if (nextLines.length === 0) {
|
||||||
|
nextLines = allLines.filter(
|
||||||
|
(line2) =>
|
||||||
|
(isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) &&
|
||||||
|
line !== line2 &&
|
||||||
|
!visitLines.includes(line2),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!nextLines) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let comparisonPoints = []
|
||||||
|
|
||||||
|
nextLines.forEach((nextLine) => {
|
||||||
|
if (isSamePoint(nextLine.startPoint, currentPoint)) {
|
||||||
|
comparisonPoints.push(nextLine.endPoint)
|
||||||
|
} else {
|
||||||
|
comparisonPoints.push(nextLine.startPoint)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
comparisonPoints = comparisonPoints.filter((point) => !visitPoints.some((visitPoint) => isSamePoint(visitPoint, point)))
|
||||||
|
comparisonPoints = comparisonPoints.filter((point) => !isSamePoint(point, currentPoint))
|
||||||
|
|
||||||
|
const minDistancePoint = comparisonPoints.reduce((prev, current) => {
|
||||||
|
const prevDistance = Math.sqrt(Math.pow(prev.x - arrivalPoint.x, 2) + Math.pow(prev.y - arrivalPoint.y, 2))
|
||||||
|
const currentDistance = Math.sqrt(Math.pow(current.x - arrivalPoint.x, 2) + Math.pow(current.y - arrivalPoint.y, 2))
|
||||||
|
|
||||||
|
return prevDistance < currentDistance ? prev : current
|
||||||
|
}, comparisonPoints[0])
|
||||||
|
|
||||||
|
nextLines.forEach((nextLine) => {
|
||||||
|
if (isSamePoint(nextLine.startPoint, minDistancePoint) || isSamePoint(nextLine.endPoint, minDistancePoint)) {
|
||||||
|
visitLines.push(nextLine)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
currentPoint = { ...minDistancePoint }
|
||||||
|
roofPoints.push(currentPoint)
|
||||||
|
cnt++
|
||||||
|
if (cnt > 100) {
|
||||||
|
throw new Error('무한루프')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
roofs.push(roofPoints)
|
||||||
|
})
|
||||||
|
|
||||||
|
const newRoofs = removeDuplicatePolygons(roofs)
|
||||||
|
newRoofs.forEach((roofPoint, index) => {
|
||||||
|
let defense, pitch
|
||||||
|
const polygonLines = [...polygon.lines]
|
||||||
|
|
||||||
|
let representLines = []
|
||||||
|
let representLine
|
||||||
|
|
||||||
|
// 지붕을 그리면서 기존 polygon의 line중 연결된 line을 찾는다.
|
||||||
|
polygonLines.forEach((line) => {
|
||||||
|
let startFlag = false
|
||||||
|
let endFlag = false
|
||||||
|
const startPoint = line.startPoint
|
||||||
|
const endPoint = line.endPoint
|
||||||
|
roofPoint.forEach((point, index) => {
|
||||||
|
if (isSamePoint(point, startPoint)) {
|
||||||
|
startFlag = true
|
||||||
|
}
|
||||||
|
if (isSamePoint(point, endPoint)) {
|
||||||
|
endFlag = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
if (startFlag && endFlag) {
|
||||||
|
representLines.push(line)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// representLines중 가장 긴 line을 찾는다.
|
||||||
|
representLines.forEach((line) => {
|
||||||
|
if (!representLine) {
|
||||||
|
representLine = line
|
||||||
|
} else {
|
||||||
|
if (representLine.length < line.length) {
|
||||||
|
representLine = line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const direction = representLine.direction
|
||||||
|
|
||||||
|
switch (direction) {
|
||||||
|
case 'top':
|
||||||
|
defense = 'east'
|
||||||
|
break
|
||||||
|
case 'right':
|
||||||
|
defense = 'south'
|
||||||
|
break
|
||||||
|
case 'bottom':
|
||||||
|
defense = 'west'
|
||||||
|
break
|
||||||
|
case 'left':
|
||||||
|
defense = 'north'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
pitch = polygon.lines[index].attributes?.pitch ?? 0
|
||||||
|
|
||||||
|
const roof = new QPolygon(roofPoint, {
|
||||||
|
fontSize: polygon.fontSize,
|
||||||
|
stroke: 'black',
|
||||||
|
fill: 'transparent',
|
||||||
|
strokeWidth: 3,
|
||||||
|
name: POLYGON_TYPE.ROOF,
|
||||||
|
originX: 'center',
|
||||||
|
originY: 'center',
|
||||||
|
selectable: true,
|
||||||
|
defense: defense,
|
||||||
|
direction: defense,
|
||||||
|
pitch: pitch,
|
||||||
|
})
|
||||||
|
|
||||||
|
polygon.canvas.add(roof)
|
||||||
|
canvas.remove(polygon)
|
||||||
|
polygon.canvas.renderAll()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePoint(point) {
|
||||||
|
return {
|
||||||
|
x: Math.round(point.x),
|
||||||
|
y: Math.round(point.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function arePolygonsEqual(polygon1, polygon2) {
|
||||||
|
if (polygon1.length !== polygon2.length) return false
|
||||||
|
|
||||||
|
const normalizedPolygon1 = polygon1.map(normalizePoint).sort((a, b) => a.x - b.x || a.y - b.y)
|
||||||
|
const normalizedPolygon2 = polygon2.map(normalizePoint).sort((a, b) => a.x - b.x || a.y - b.y)
|
||||||
|
|
||||||
|
return normalizedPolygon1.every((point, index) => arePointsEqual(point, normalizedPolygon2[index]))
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeDuplicatePolygons(polygons) {
|
||||||
|
const uniquePolygons = []
|
||||||
|
|
||||||
|
polygons.forEach((polygon) => {
|
||||||
|
const isDuplicate = uniquePolygons.some((uniquePolygon) => arePolygonsEqual(polygon, uniquePolygon))
|
||||||
|
if (!isDuplicate) {
|
||||||
|
uniquePolygons.push(polygon)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return uniquePolygons
|
||||||
}
|
}
|
||||||
|
|
||||||
const isSamePoint = (a, b) => {
|
const isSamePoint = (a, b) => {
|
||||||
@ -3348,7 +3626,7 @@ function createRoofPaddingPolygon(polygon, lines, arcSegments = 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function arePointsEqual(point1, point2) {
|
function arePointsEqual(point1, point2) {
|
||||||
return point1.x === point2.x && point1.y === point2.y
|
return Math.abs(point1.x - point2.x) <= 1 && Math.abs(point1.y - point2.y) <= 1
|
||||||
}
|
}
|
||||||
|
|
||||||
function arraysHaveSamePoints(array1, array2) {
|
function arraysHaveSamePoints(array1, array2) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user