This commit is contained in:
yoosangwook 2025-01-07 15:50:42 +09:00
commit 82bc00e2aa
25 changed files with 1372 additions and 709 deletions

View File

@ -212,7 +212,7 @@ export default function CanvasMenu(props) {
}, [canvasSetting]) }, [canvasSetting])
const checkMenuState = (menu) => { const checkMenuState = (menu) => {
return ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2) return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && menu.index === 2)
} }
// Excel/PDF // Excel/PDF
@ -283,7 +283,7 @@ export default function CanvasMenu(props) {
key={`canvas-menu-${menu.index}`} key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`} className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => { onClick={() => {
if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet) && menu.index === 2) return if (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) return
if (menuNumber === 4 && menu.index === 2) return if (menuNumber === 4 && menu.index === 2) return
onClickNav(menu) onClickNav(menu)
}} }}

View File

@ -29,6 +29,8 @@ export default function DotLineGrid(props) {
const { SelectOptions, currentSetting, setCurrentSetting, dotLineGridSettingState, setSettingModalGridOptions, setDotLineGridSettingState } = const { SelectOptions, currentSetting, setCurrentSetting, dotLineGridSettingState, setSettingModalGridOptions, setDotLineGridSettingState } =
useCanvasSetting() useCanvasSetting()
const [copyCurrentSetting, setCopyCurrentSetting] = useState({ ...currentSetting })
// //
useEffect(() => { useEffect(() => {
console.log('DotLineGrid useEffect 실행') console.log('DotLineGrid useEffect 실행')
@ -57,7 +59,7 @@ export default function DotLineGrid(props) {
const handleCheckBoxChange = (e) => { const handleCheckBoxChange = (e) => {
const { value, checked } = e.target const { value, checked } = e.target
setCurrentSetting((prev) => { setCopyCurrentSetting((prev) => {
return { return {
...prev, ...prev,
[value]: checked, [value]: checked,
@ -66,23 +68,23 @@ export default function DotLineGrid(props) {
} }
const handleSave = async () => { const handleSave = async () => {
if (!currentSetting.DOT && !currentSetting.LINE) { /*if (!currentSetting.DOT && !currentSetting.LINE) {
swalFire({ text: '배치할 그리드를 설정해주세요.' }) swalFire({ text: '배치할 그리드를 설정해주세요.' })
return return
} }*/
setDotLineGridSettingState((prev) => { setDotLineGridSettingState((prev) => {
return { return {
...prev, ...prev,
INTERVAL: { INTERVAL: {
type: currentSetting.INTERVAL.type, type: copyCurrentSetting.INTERVAL.type,
horizontalInterval: currentSetting.INTERVAL.horizontalInterval, horizontalInterval: copyCurrentSetting.INTERVAL.horizontalInterval,
verticalInterval: currentSetting.INTERVAL.verticalInterval, verticalInterval: copyCurrentSetting.INTERVAL.verticalInterval,
ratioInterval: currentSetting.INTERVAL.ratioInterval, ratioInterval: copyCurrentSetting.INTERVAL.ratioInterval,
dimension: currentSetting.INTERVAL.dimension, dimension: copyCurrentSetting.INTERVAL.dimension,
}, },
DOT: currentSetting.DOT, DOT: copyCurrentSetting.DOT,
LINE: currentSetting.LINE, LINE: copyCurrentSetting.LINE,
} }
//setDotLineGridSettingState({ ...currentSetting }) //setDotLineGridSettingState({ ...currentSetting })
}) })
@ -90,16 +92,18 @@ export default function DotLineGrid(props) {
setSettingsData({ setSettingsData({
...settingsData, ...settingsData,
INTERVAL: { INTERVAL: {
type: currentSetting.INTERVAL.type, type: copyCurrentSetting.INTERVAL.type,
horizontalInterval: currentSetting.INTERVAL.horizontalInterval, horizontalInterval: copyCurrentSetting.INTERVAL.horizontalInterval,
verticalInterval: currentSetting.INTERVAL.verticalInterval, verticalInterval: copyCurrentSetting.INTERVAL.verticalInterval,
ratioInterval: currentSetting.INTERVAL.ratioInterval, ratioInterval: copyCurrentSetting.INTERVAL.ratioInterval,
dimension: currentSetting.INTERVAL.dimension, dimension: copyCurrentSetting.INTERVAL.dimension,
}, },
DOT: currentSetting.DOT, DOT: copyCurrentSetting.DOT,
LINE: currentSetting.LINE, LINE: copyCurrentSetting.LINE,
}) })
setCurrentSetting({ ...copyCurrentSetting })
setIsShow(false) setIsShow(false)
closePopup(id, isConfig) closePopup(id, isConfig)
} }
@ -107,7 +111,7 @@ export default function DotLineGrid(props) {
const handleRadioChange = (e) => { const handleRadioChange = (e) => {
const { value, name, checked, selected } = e.target const { value, name, checked, selected } = e.target
setCurrentSetting((prev) => { setCopyCurrentSetting((prev) => {
return { return {
...prev, ...prev,
INTERVAL: { INTERVAL: {
@ -120,7 +124,7 @@ export default function DotLineGrid(props) {
const changeInput = (value, e) => { const changeInput = (value, e) => {
const { name } = e.target const { name } = e.target
setCurrentSetting((prev) => { setCopyCurrentSetting((prev) => {
return { return {
...prev, ...prev,
INTERVAL: { INTERVAL: {
@ -133,7 +137,7 @@ export default function DotLineGrid(props) {
const changeDimension = (result) => { const changeDimension = (result) => {
const { value } = result const { value } = result
setCurrentSetting((prev) => { setCopyCurrentSetting((prev) => {
return { return {
...prev, ...prev,
INTERVAL: { INTERVAL: {
@ -146,7 +150,7 @@ export default function DotLineGrid(props) {
// //
const reset = () => { const reset = () => {
canvas /*canvas
?.getObjects() ?.getObjects()
.filter((obj) => obj.name === 'lineGrid') .filter((obj) => obj.name === 'lineGrid')
.forEach((obj) => canvas?.remove(obj)) .forEach((obj) => canvas?.remove(obj))
@ -154,9 +158,9 @@ export default function DotLineGrid(props) {
?.getObjects() ?.getObjects()
.filter((obj) => obj.name === 'dotGrid') .filter((obj) => obj.name === 'dotGrid')
.forEach((obj) => canvas?.remove(obj)) .forEach((obj) => canvas?.remove(obj))
*/
// resetDotLineGridSetting() // resetDotLineGridSetting()
setCurrentSetting({ setCopyCurrentSetting({
INTERVAL: { INTERVAL: {
type: 2, // 1: , , 2: type: 2, // 1: , , 2:
ratioInterval: 910, ratioInterval: 910,
@ -188,11 +192,11 @@ export default function DotLineGrid(props) {
<div className="modal-body"> <div className="modal-body">
<div className="grid-check-form"> <div className="grid-check-form">
<div className="d-check-box pop"> <div className="d-check-box pop">
<input type="checkbox" id="ch01" value={TYPE.DOT} onChange={handleCheckBoxChange} checked={currentSetting.DOT} /> <input type="checkbox" id="ch01" value={TYPE.DOT} onChange={handleCheckBoxChange} checked={copyCurrentSetting.DOT} />
<label htmlFor="ch01">{getMessage('modal.canvas.setting.grid.dot.line.setting.dot.display')}</label> <label htmlFor="ch01">{getMessage('modal.canvas.setting.grid.dot.line.setting.dot.display')}</label>
</div> </div>
<div className="d-check-box pop"> <div className="d-check-box pop">
<input type="checkbox" id="ch02" value={TYPE.LINE} onChange={handleCheckBoxChange} checked={currentSetting.LINE} /> <input type="checkbox" id="ch02" value={TYPE.LINE} onChange={handleCheckBoxChange} checked={copyCurrentSetting.LINE} />
<label htmlFor="ch02">{getMessage('modal.canvas.setting.grid.dot.line.setting.line.display')}</label> <label htmlFor="ch02">{getMessage('modal.canvas.setting.grid.dot.line.setting.line.display')}</label>
</div> </div>
</div> </div>
@ -205,8 +209,8 @@ export default function DotLineGrid(props) {
id="ra01" id="ra01"
value={1} value={1}
onChange={handleRadioChange} onChange={handleRadioChange}
checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 1} checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 1}
readOnly={!currentSetting.DOT && !currentSetting.LINE} readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/> />
<label htmlFor="ra01"></label> <label htmlFor="ra01"></label>
</div> </div>
@ -217,7 +221,7 @@ export default function DotLineGrid(props) {
type="text" type="text"
className="input-origin" className="input-origin"
name={`horizontalInterval`} name={`horizontalInterval`}
value={currentSetting.INTERVAL.horizontalInterval} value={copyCurrentSetting.INTERVAL.horizontalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)} onChange={(e) => onlyNumberInputChange(e, changeInput)}
/> />
</div> </div>
@ -230,7 +234,7 @@ export default function DotLineGrid(props) {
type="text" type="text"
className="input-origin" className="input-origin"
name={`verticalInterval`} name={`verticalInterval`}
value={currentSetting.INTERVAL.verticalInterval} value={copyCurrentSetting.INTERVAL.verticalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)} onChange={(e) => onlyNumberInputChange(e, changeInput)}
/> />
</div> </div>
@ -245,8 +249,8 @@ export default function DotLineGrid(props) {
id="ra02" id="ra02"
value={2} value={2}
onChange={handleRadioChange} onChange={handleRadioChange}
checked={(currentSetting.DOT || currentSetting.LINE) && currentSetting.INTERVAL.type === 2} checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 2}
readOnly={!currentSetting.DOT && !currentSetting.LINE} readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/> />
<label htmlFor="ra02"></label> <label htmlFor="ra02"></label>
</div> </div>
@ -257,14 +261,21 @@ export default function DotLineGrid(props) {
type="text" type="text"
className="input-origin" className="input-origin"
name={`ratioInterval`} name={`ratioInterval`}
value={currentSetting.INTERVAL.ratioInterval} value={copyCurrentSetting.INTERVAL.ratioInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)} onChange={(e) => onlyNumberInputChange(e, changeInput)}
/> />
</div> </div>
<span>mm</span> <span>mm</span>
</div> </div>
<div className="grid-select"> <div className="grid-select">
<QSelectBox options={SelectOptions} onChange={changeDimension} value={selectOption} /> <QSelectBox
options={SelectOptions}
onChange={changeDimension}
value={selectOption}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -14,7 +14,9 @@ import { useModule } from '@/hooks/module/useModule'
export const PANEL_EDIT_TYPE = { export const PANEL_EDIT_TYPE = {
MOVE: 'move', MOVE: 'move',
MOVE_ALL: 'moveAll',
COPY: 'copy', COPY: 'copy',
COPY_ALL: 'copyAll',
COLUMN_MOVE: 'columnMove', COLUMN_MOVE: 'columnMove',
COLUMN_COPY: 'columnCopy', COLUMN_COPY: 'columnCopy',
ROW_MOVE: 'rowMove', ROW_MOVE: 'rowMove',
@ -29,7 +31,7 @@ export default function PanelEdit(props) {
const [direction, setDirection] = useState('up') const [direction, setDirection] = useState('up')
const { getMessage } = useMessage() const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule() const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule()
useEffect(() => { useEffect(() => {
if (canvas) { if (canvas) {
@ -44,9 +46,15 @@ export default function PanelEdit(props) {
case PANEL_EDIT_TYPE.MOVE: case PANEL_EDIT_TYPE.MOVE:
moduleMove(length, direction) moduleMove(length, direction)
break break
case PANEL_EDIT_TYPE.MOVE_ALL:
moduleMoveAll(length, direction)
break
case PANEL_EDIT_TYPE.COPY: case PANEL_EDIT_TYPE.COPY:
moduleCopy(length, direction) moduleCopy(length, direction)
break break
case PANEL_EDIT_TYPE.COPY_ALL:
moduleCopyAll(length, direction)
break
case PANEL_EDIT_TYPE.COLUMN_MOVE: case PANEL_EDIT_TYPE.COLUMN_MOVE:
moduleMultiMove('column', length, direction) moduleMultiMove('column', length, direction)
break break

View File

@ -1,9 +1,7 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState } from 'react'
import FlowLine from '@/components/floor-plan/modal/movement/type/FlowLine' import FlowLine from '@/components/floor-plan/modal/movement/type/FlowLine'
import Updown from '@/components/floor-plan/modal/movement/type/Updown' import Updown from '@/components/floor-plan/modal/movement/type/Updown'
import { usePopup } from '@/hooks/usePopup'
import { useMovementSetting } from '@/hooks/roofcover/useMovementSetting' import { useMovementSetting } from '@/hooks/roofcover/useMovementSetting'
export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) { export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {

View File

@ -1,5 +1,7 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useState } from 'react' import { useState } from 'react'
import { currentObjectState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
const FLOW_LINE_TYPE = { const FLOW_LINE_TYPE = {
DOWN_LEFT: 'downLeft', DOWN_LEFT: 'downLeft',
@ -9,7 +11,18 @@ const FLOW_LINE_TYPE = {
export default function FlowLine({ FLOW_LINE_REF }) { export default function FlowLine({ FLOW_LINE_REF }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [type, setType] = useState(FLOW_LINE_TYPE.DOWN_LEFT) const [type, setType] = useState(FLOW_LINE_TYPE.DOWN_LEFT)
const [filledInput, setFilledInput] = useState('')
const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => {
if (currentObject === null) {
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.blur()
}
}
const handleInput = (e) => {
const value = e.target.value.replace(/^0+/, '')
setFilledInput(value.replace(/[^0-9]/g, ''))
}
return ( return (
<> <>
<div className="outline-wrap"> <div className="outline-wrap">
@ -57,7 +70,14 @@ export default function FlowLine({ FLOW_LINE_REF }) {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}> <div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" ref={FLOW_LINE_REF.FILLED_INPUT_REF} /> <input
type="text"
className="input-origin block"
ref={FLOW_LINE_REF.FILLED_INPUT_REF}
value={filledInput}
onFocus={handleFocus}
onChange={handleInput}
/>
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>

View File

@ -28,7 +28,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
const roofMaterials = useRecoilValue(roofMaterialsAtom) const roofMaterials = useRecoilValue(roofMaterialsAtom)
const globalLocale = useRecoilValue(globalLocaleStore) const globalLocale = useRecoilValue(globalLocaleStore)
const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave, addedRoofs, setAddedRoofs } = useCanvasSetting() const { basicSetting, setBasicSettings, basicSettingSave, addedRoofs, setAddedRoofs } = useCanvasSetting()
const { findCommonCode } = useCommonCode() const { findCommonCode } = useCommonCode()
const [raftCodes, setRaftCodes] = useState([]) // const [raftCodes, setRaftCodes] = useState([]) //
const [currentRoof, setCurrentRoof] = useState(addedRoofs[0]) // const [currentRoof, setCurrentRoof] = useState(addedRoofs[0]) //
@ -43,7 +43,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
// //
useEffect(() => { useEffect(() => {
//fetchBasicSettings()
const raftCodeList = findCommonCode('203800') const raftCodeList = findCommonCode('203800')
setRaftCodes(raftCodeList) setRaftCodes(raftCodeList)
}, []) }, [])

View File

@ -73,119 +73,121 @@ export default function RoofAllocationSetting(props) {
{getMessage('modal.common.add')} {getMessage('modal.common.add')}
</button> </button>
</div> </div>
<div className="grid-option-wrap"> <div className="grid-option-overflow">
{currentRoofList.map((roof, index) => { <div className="grid-option-wrap">
return ( {currentRoofList.map((roof, index) => {
<div className="grid-option-box" key={index}> return (
<div className="d-check-radio pop no-text"> <div className="grid-option-box" key={index}>
<input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} /> <div className="d-check-radio pop no-text">
<label <input type="radio" name="radio01" checked={roof.selected && 'checked'} readOnly={true} />
htmlFor="ra01" <label
onClick={(e) => { htmlFor="ra01"
handleDefaultRoofMaterial(index) onClick={(e) => {
}} handleDefaultRoofMaterial(index)
></label> }}
</div> ></label>
<div className="grid-option-block-form">
<div className="block-box">
<div className="flex-ment">
<div className="grid-select" style={{ width: '248px' }}>
<QSelectBox
options={roofMaterials}
value={roof}
showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div>
{index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
</div>
</div> </div>
{(roof.widAuth || roof.lenAuth) && ( <div className="grid-option-block-form">
<div className="block-box"> <div className="block-box">
{roof.widAuth && ( <div className="flex-ment">
<div className="flex-ment"> <div className="grid-select" style={{ width: '248px' }}>
<span>W</span> <QSelectBox
<div className="input-grid" style={{ width: '100px' }}> options={roofMaterials}
<input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} /> value={roof}
</div> showKey={'roofMatlNm'}
sourceKey={'roofMatlCd'}
targetKey={'roofMatlCd'}
onChange={(e) => handleChangeRoofMaterial(e, index)}
/>
</div> </div>
)} {index === 0 && <span className="dec">{getMessage('modal.roof.alloc.default.roof.material')}</span>}
{roof.lenAuth && ( {index !== 0 && <button className="delete" onClick={() => onDeleteRoofMaterial(index)}></button>}
<div className="flex-ment"> </div>
<span>L</span>
<div className="input-grid" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
</div>
</div>
)}
</div> </div>
)} {(roof.widAuth || roof.lenAuth) && (
{(roof.raftAuth || roof.roofPchAuth) && ( <div className="block-box">
<div className="block-box"> {roof.widAuth && (
{roof.raftAuth && (
<div className="block-box">
<div className="flex-ment"> <div className="flex-ment">
<span>{getMessage('modal.placement.initial.setting.rafter')}</span> <span>W</span>
{raftCodes.length > 0 && ( <div className="input-grid" style={{ width: '100px' }}>
<div className="grid-select" style={{ width: '160px' }}> <input type="text" className="input-origin block" defaultValue={roof.width} readOnly={roof.widAuth === 'R'} />
<QSelectBox
options={raftCodes}
value={roof}
showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
</div> </div>
</div> </div>
</div> )}
)} {roof.lenAuth && (
</div> <div className="flex-ment">
)} <span>L</span>
<div className="block-box"> <div className="input-grid" style={{ width: '100px' }}>
<div className="icon-btn-wrap"> <input type="text" className="input-origin block" defaultValue={roof.length} readOnly={roof.lenAuth === 'R'} />
<button </div>
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''} </div>
onClick={() => { )}
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index) </div>
}} )}
> {(roof.raftAuth || roof.roofPchAuth) && (
{getMessage('modal.roof.alloc.select.parallel')} <div className="block-box">
<i className="allocation01"></i> {roof.raftAuth && (
</button> <div className="block-box">
<button <div className="flex-ment">
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''} <span>{getMessage('modal.placement.initial.setting.rafter')}</span>
onClick={() => { {raftCodes.length > 0 && (
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index) <div className="grid-select" style={{ width: '160px' }}>
}} <QSelectBox
> options={raftCodes}
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i> value={roof}
</button> showKey={'clCodeNm'}
sourceKey={'clCode'}
targetKey={roof.raft ? 'raft' : 'raftBaseCd'}
onChange={(e) => handleChangeRaft(e, index)}
/>
</div>
)}
</div>
</div>
)}
{roof.roofPchAuth && (
<div className="block-box">
<div className="flex-ment">
<span>{getMessage('hajebichi')}</span>
<div className="input-grid" style={{ width: '84px' }}>
<input
type="text"
className="input-origin block"
value={parseInt(roof.hajebichi)}
readOnly={roof.roofPchAuth === 'R'}
/>
</div>
</div>
</div>
)}
</div>
)}
<div className="block-box">
<div className="icon-btn-wrap">
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.PARALLEL ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.PARALLEL, index)
}}
>
{getMessage('modal.roof.alloc.select.parallel')}
<i className="allocation01"></i>
</button>
<button
className={roof.layout === ROOF_MATERIAL_LAYOUT.STAIRS ? 'act' : ''}
onClick={() => {
handleChangeLayout(ROOF_MATERIAL_LAYOUT.STAIRS, index)
}}
>
{getMessage('modal.roof.alloc.select.stairs')} <i className="allocation02"></i>
</button>
</div>
</div> </div>
</div> </div>
</div> </div>
</div> )
) })}
})} </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}> <button className="btn-frame modal act" onClick={handleSave}>

View File

@ -7,15 +7,6 @@ export default function Gable({ offsetRef, pitchRef, pitchText }) {
const currentAngleType = useRecoilValue(currentAngleTypeSelector) const currentAngleType = useRecoilValue(currentAngleTypeSelector)
return ( return (
<> <>
<div className="outline-form mb10">
<span className="mr10" style={{ width: '63px' }}>
{getMessage('slope')}
</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={currentAngleType === ANGLE_TYPE.SLOPE ? 4 : 21.8} ref={pitchRef} />
</div>
<span className="thin">{pitchText}</span>
</div>
<div className="outline-form mb10"> <div className="outline-form mb10">
<span className="mr10" style={{ width: '63px' }}> <span className="mr10" style={{ width: '63px' }}>
{getMessage('gable.offset')} {getMessage('gable.offset')}

View File

@ -1,12 +1,10 @@
import React, { useState } from 'react' import React from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useForm } from 'react-hook-form' import { useForm } from 'react-hook-form'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { useRecoilValue, useRecoilState } from 'recoil' import { useRecoilValue, useRecoilState } from 'recoil'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { useRouter } from 'next/navigation'
import { setSession } from '@/lib/authActions'
import { logout } from '@/lib/authActions' import { logout } from '@/lib/authActions'
export default function ChangePasswordPop(props) { export default function ChangePasswordPop(props) {
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
@ -14,7 +12,6 @@ export default function ChangePasswordPop(props) {
const { patch } = useAxios(globalLocaleState) const { patch } = useAxios(globalLocaleState)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [sessionState, setSessionState] = useRecoilState(sessionStore) const [sessionState, setSessionState] = useRecoilState(sessionStore)
const router = useRouter()
const formInitValue = { const formInitValue = {
password1: '', password1: '',
password2: '', password2: '',
@ -56,6 +53,16 @@ export default function ChangePasswordPop(props) {
const _password1 = form.watch('password1') const _password1 = form.watch('password1')
const _password2 = form.watch('password2') const _password2 = form.watch('password2')
//
if (_password1.trim() === '') {
alert(getMessage('main.popup.login.validate3'))
return false
}
if (_password2.trim() === '') {
alert(getMessage('main.popup.login.validate3'))
return false
}
if (_password1 !== _password2) { if (_password1 !== _password2) {
alert(getMessage('main.popup.login.validate1')) alert(getMessage('main.popup.login.validate1'))
return false return false
@ -78,10 +85,6 @@ export default function ChangePasswordPop(props) {
if (res?.result?.resultCode === 'S') { if (res?.result?.resultCode === 'S') {
alert(getMessage('main.popup.login.success')) alert(getMessage('main.popup.login.success'))
logout() logout()
// setSessionState
// setSessionState({ ...sessionState, pwdInitYn: 'Y' })
//props.setChagePasswordPopOpen(false)
//router.push('/login')
} else { } else {
alert(res?.result?.resultMsg) alert(res?.result?.resultMsg)
} }
@ -110,10 +113,7 @@ export default function ChangePasswordPop(props) {
<div className="table-item"> <div className="table-item">
<div className="table-item-th"> <div className="table-item-th">
<div className="change-password-tit"> <div className="change-password-tit">
<div className="tit-b"> <div className="tit-b">{getMessage('main.popup.login.newPassword1')}</div>
{getMessage('main.popup.login.newPassword1')}
<span className="important">*</span>
</div>
<div className="tit-s">{getMessage('main.popup.login.placeholder')}</div> <div className="tit-s">{getMessage('main.popup.login.placeholder')}</div>
</div> </div>
</div> </div>
@ -133,10 +133,7 @@ export default function ChangePasswordPop(props) {
<div className="table-item"> <div className="table-item">
<div className="table-item-th"> <div className="table-item-th">
<div className="change-password-tit"> <div className="change-password-tit">
<div className="tit-b"> <div className="tit-b">{getMessage('main.popup.login.newPassword2')}</div>
{getMessage('main.popup.login.newPassword2')}
<span className="important">*</span>
</div>
<div className="tit-s">{getMessage('main.popup.login.placeholder')}</div> <div className="tit-s">{getMessage('main.popup.login.placeholder')}</div>
</div> </div>
</div> </div>
@ -169,7 +166,6 @@ export default function ChangePasswordPop(props) {
className="btn-origin grey" className="btn-origin grey"
onClick={() => { onClick={() => {
logout() logout()
// router.push('/login')
}} }}
> >
{getMessage('main.popup.login.btn2')} {getMessage('main.popup.login.btn2')}

View File

@ -11,11 +11,13 @@ import { useRouter } from 'next/navigation'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { queryStringFormatter } from '@/util/common-utils' import { queryStringFormatter } from '@/util/common-utils'
import MainSkeleton from '../ui/MainSkeleton' import MainSkeleton from '../ui/MainSkeleton'
import { SessionContext } from '@/app/SessionProvider'
import { useMainContentsController } from '@/hooks/main/useMainContentsController' import { useMainContentsController } from '@/hooks/main/useMainContentsController'
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
import { useSwal } from '@/hooks/useSwal'
export default function MainContents() { export default function MainContents() {
const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const router = useRouter() const router = useRouter()
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
@ -85,7 +87,6 @@ export default function MainContents() {
} }
} }
console.log('qcastState:::', qcastState?.businessCharger)
return ( return (
<div className="main-product-list-wrap"> <div className="main-product-list-wrap">
<div className="main-product-list"> <div className="main-product-list">
@ -116,67 +117,60 @@ export default function MainContents() {
})} })}
</ul> </ul>
) : ( ) : (
<></> <div className="recently-no-data">
// <MainSkeleton count={6} /> <h3>{getMessage('main.content.objectList.noData1')}</h3>
<p>{getMessage('main.content.objectList.noData2')}</p>
<button type="button" className="btn-origin navy" onClick={() => router.push('/management/stuff/tempReg')}>
+ {getMessage('stuff.search.btn.register')}
</button>
</div>
)} )}
</ProductItem> </ProductItem>
<ProductItem num={2} name={getMessage('main.content.notice')}> <ProductItem num={2} name={getMessage('main.content.notice')}>
<div className="notice-box"> {recentNoticeList.length > 0 ? (
{recentNoticeList.length > 0 ? ( <div className="notice-box">
<> <div className="notice-day pre">{dayjs(recentNoticeList[0]?.regDt).format('YYYY.MM.DD')}</div>
<div className="notice-day pre">{dayjs(recentNoticeList[0]?.regDt).format('YYYY.MM.DD')}</div> <div className="notice-title">{recentNoticeList[0]?.title}</div>
<div className="notice-title">{recentNoticeList[0]?.title}</div> <div
<div className="notice-contents"
className="notice-contents" dangerouslySetInnerHTML={{ __html: recentNoticeList[0]?.contents ? recentNoticeList[0].contents.replaceAll('\n', '<br/>') : '' }}
dangerouslySetInnerHTML={{ __html: recentNoticeList[0]?.contents ? recentNoticeList[0].contents.replaceAll('\n', '<br/>') : '' }} ></div>
></div> </div>
</> ) : (
) : ( <div className="recently-no-data">
<MainSkeleton count={5} /> <h3>{getMessage('main.content.noBusiness')}</h3>
)} </div>
</div> )}
</ProductItem> </ProductItem>
</div> </div>
<div className="main-product-list"> <div className="main-product-list">
<ProductItem num={3} name={getMessage('main.faq')}> <ProductItem num={3} name={getMessage('main.faq')}>
<ul className="faq-list"> {recentFaqList.length > 0 ? (
{recentFaqList.length > 0 ? ( <ul className="faq-list">
<> {recentFaqList.map((row) => {
{recentFaqList.map((row) => { return (
return ( <li key={row.rowNumber} className="faq-item">
<li key={row.rowNumber} className="faq-item"> <div className="faq-item-inner">
<div className="faq-item-inner"> <div className="faq-num pre">FAQ {row.totCnt - row.rowNumber}</div>
<div className="faq-num pre">FAQ {row.rowNumber}</div> <div className="faq-title pre">{row.title}</div>
<div className="faq-title pre">{row.title}</div> <div className="faq-day pre">{dayjs(row.regDt).format('YYYY.MM.DD')}</div>
<div className="faq-day pre">{dayjs(row.regDt).format('YYYY.MM.DD')}</div> </div>
</div> </li>
</li> )
) })}
})} </ul>
</> ) : (
) : ( <div className="recently-no-data">
<MainSkeleton count={2} /> <h3>{getMessage('main.content.noBusiness')}</h3>
)} </div>
</ul> )}
</ProductItem> </ProductItem>
<ProductItem num={4} name={'Data Download'}> <ProductItem num={4} name={'Data Download'}>
<div className="data-download-wrap"> <div className="data-download-wrap">
<button <button className="data-down" type="button" onClick={() => swalFire({ text: getMessage('main.content.alert.noFile'), type: 'alert' })}>
className="data-down"
type="button"
onClick={() => {
return alert(getMessage('main.content.alert.noFile'))
}}
>
<span>{getMessage('main.content.download1')}</span> <span>{getMessage('main.content.download1')}</span>
</button> </button>
<button <button className="data-down" type="button" onClick={() => swalFire({ text: getMessage('main.content.alert.noFile'), type: 'alert' })}>
className="data-down"
type="button"
onClick={() => {
return alert(getMessage('main.content.alert.noFile'))
}}
>
<span>{getMessage('main.content.download2')}</span> <span>{getMessage('main.content.download2')}</span>
</button> </button>
</div> </div>

View File

@ -30,7 +30,7 @@ export default function Stuff() {
const [pageNo, setPageNo] = useState(1) // const [pageNo, setPageNo] = useState(1) //
const [pageSize, setPageSize] = useState(100) // const [pageSize, setPageSize] = useState(100) //
const [totalCount, setTotalCount] = useState(0) // const [totalCount, setTotalCount] = useState(0) //
const [defaultSortType, setDefaultSortType] = useState('R') const [defaultSortType, setDefaultSortType] = useState('U')
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get } = useAxios(globalLocaleState) const { get } = useAxios(globalLocaleState)
@ -207,6 +207,7 @@ export default function Stuff() {
schReceiveUser: stuffSearchParams?.schReceiveUser, schReceiveUser: stuffSearchParams?.schReceiveUser,
schDispCompanyName: stuffSearchParams?.schDispCompanyName, schDispCompanyName: stuffSearchParams?.schDispCompanyName,
schDateType: stuffSearchParams.schDateType, schDateType: stuffSearchParams.schDateType,
schTempFlg: stuffSearchParams.schTempFlg, //
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1, startRow: (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1,
@ -249,12 +250,13 @@ export default function Stuff() {
schReceiveUser: '', schReceiveUser: '',
schDispCompanyName: '', schDispCompanyName: '',
schDateType: 'U', schDateType: 'U',
schTempFlg: '',
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: (pageNo - 1) * pageSize + 1, startRow: (pageNo - 1) * pageSize + 1,
endRow: pageNo * pageSize, endRow: pageNo * pageSize,
schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId, schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId,
schSortType: 'R', schSortType: 'U',
code: 'E', code: 'E',
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
@ -322,13 +324,14 @@ export default function Stuff() {
schReceiveUser: '', schReceiveUser: '',
schDispCompanyName: '', schDispCompanyName: '',
schDateType: 'U', schDateType: 'U',
schTempFlg: '',
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'),
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSelSaleStoreId: '', schSelSaleStoreId: '',
schOtherSelSaleStoreId: '', schOtherSelSaleStoreId: '',
schSortType: 'R', schSortType: 'U',
code: 'S', code: 'S',
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
@ -438,8 +441,8 @@ export default function Stuff() {
<div className="left-unit-box"> <div className="left-unit-box">
<div className="select-box mr5" style={{ width: '110px' }}> <div className="select-box mr5" style={{ width: '110px' }}>
<select className="select-light black" onChange={onChangeSortType} value={stuffSearch.schSortType}> <select className="select-light black" onChange={onChangeSortType} value={stuffSearch.schSortType}>
<option value="R">{getMessage('stuff.search.grid.schSortTypeR')}</option>
<option value="U">{getMessage('stuff.search.grid.schSortTypeU')}</option> <option value="U">{getMessage('stuff.search.grid.schSortTypeU')}</option>
<option value="R">{getMessage('stuff.search.grid.schSortTypeR')}</option>
</select> </select>
</div> </div>
<div className="select-box" style={{ width: '80px' }}> <div className="select-box" style={{ width: '80px' }}>

View File

@ -53,7 +53,7 @@ export default function StuffDetail() {
const formInitValue = { const formInitValue = {
// T...() R...() // T...() R...()
planReqNo: '', //No planReqNo: '', //No
receiveUser: '', // receiveUser: session?.userNm, //
objectStatusId: '0', //(:0 : 1) objectStatusId: '0', //(:0 : 1)
objectName: '', // objectName: '', //
objectNameOmit: '', // objectNameOmit: '', //
@ -1745,7 +1745,7 @@ export default function StuffDetail() {
onChange={onSelectionChange2} onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isDisabled={otherSaleStoreList.length > 1 ? false : true} isDisabled={otherSaleStoreList != null && otherSaleStoreList.length > 0 ? false : true}
isClearable={true} isClearable={true}
value={otherSaleStoreList.filter(function (option) { value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions return option.saleStoreId === otherSelOptions

View File

@ -60,6 +60,7 @@ export default function StuffSearchCondition() {
const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') // const [schSelSaleStoreId, setSchSelSaleStoreId] = useState('') //
const [receiveUser, setReceiveUser] = useState('') // const [receiveUser, setReceiveUser] = useState('') //
const [dateType, setDateType] = useState('U') //(U)/(R) const [dateType, setDateType] = useState('U') //(U)/(R)
const [tempFlg, setTempFlg] = useState('') //
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT
const [favoriteStoreList, setFavoriteStoreList] = useState([]) // const [favoriteStoreList, setFavoriteStoreList] = useState([]) //
@ -95,12 +96,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: 1, startRow: 1,
endRow: 1 * stuffSearch?.pageSize, endRow: 1 * stuffSearch?.pageSize,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: 1, pageNo: 1,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -115,12 +117,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo, pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -136,12 +139,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser.trim(), schReceiveUser: receiveUser.trim(),
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
}) })
} else if (stuffSearch.code === 'E') { } else if (stuffSearch.code === 'E') {
if (session.storeId !== 'T01' && session.storeLvl === '1') { if (session.storeId !== 'T01' && session.storeLvl === '1') {
@ -155,12 +159,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(), schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo, pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -176,12 +181,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '', schOtherSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : '',
schReceiveUser: receiveUser ? receiveUser.trim() : '', schReceiveUser: receiveUser ? receiveUser.trim() : '',
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: 1, startRow: 1,
endRow: 1 * stuffSearch?.pageSize, endRow: 1 * stuffSearch?.pageSize,
schSortType: 'R', schSortType: 'U',
pageNo: 1, pageNo: 1,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -196,12 +202,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(), schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo, pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -217,12 +224,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(), schReceiveUser: stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser.trim() : receiveUser.trim(),
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo, pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -238,12 +246,13 @@ export default function StuffSearchCondition() {
schOtherSelSaleStoreId: otherSaleStoreId, schOtherSelSaleStoreId: otherSaleStoreId,
schReceiveUser: receiveUser.trim(), schReceiveUser: receiveUser.trim(),
schDateType: dateType, schDateType: dateType,
schTempFlg: tempFlg, //
schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '', schFromDt: startDate ? dayjs(startDate).format('YYYY-MM-DD') : '',
schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '', schToDt: endDate ? dayjs(endDate).format('YYYY-MM-DD') : '',
code: 'E', code: 'E',
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'U',
pageNo: stuffSearch?.pageNo, pageNo: stuffSearch?.pageNo,
pageSize: stuffSearch?.pageSize, pageSize: stuffSearch?.pageSize,
}) })
@ -261,6 +270,7 @@ export default function StuffSearchCondition() {
dispCompanyNameRef.current.value = '' dispCompanyNameRef.current.value = ''
receiveUserRef.current.value = '' receiveUserRef.current.value = ''
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
setObjectNo('') setObjectNo('')
setAddress('') setAddress('')
setobjectName('') setobjectName('')
@ -268,6 +278,7 @@ export default function StuffSearchCondition() {
setReceiveUser('') setReceiveUser('')
setDispCompanyName('') setDispCompanyName('')
setDateType('U') setDateType('U')
setTempFlg('')
setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')) setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(dayjs(new Date()).format('YYYY-MM-DD')) setEndDate(dayjs(new Date()).format('YYYY-MM-DD'))
if (session?.storeId === 'T01') { if (session?.storeId === 'T01') {
@ -285,12 +296,12 @@ export default function StuffSearchCondition() {
schSelSaleStoreId: '', schSelSaleStoreId: '',
schOtherSelSaleStoreId: '', schOtherSelSaleStoreId: '',
schDateType: 'U', schDateType: 'U',
schTempFlg: '',
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSortType: 'R', schSortType: 'U',
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
// code: 'S',
}) })
} else { } else {
if (otherSaleStoreList.length > 1) { if (otherSaleStoreList.length > 1) {
@ -303,10 +314,11 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = '' stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = '' stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.startRow = 1 stuffSearch.startRow = 1
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSortType = 'R' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
} else { } else {
@ -317,10 +329,11 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = '' stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = '' stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.startRow = 1 stuffSearch.startRow = 1
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSortType = 'R' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
} }
@ -543,13 +556,14 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = '' stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = '' stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD') stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD') stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
stuffSearch.startRow = 1 stuffSearch.startRow = 1
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schSortType = 'R' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
@ -575,13 +589,14 @@ export default function StuffSearchCondition() {
stuffSearch.schReceiveUser = '' stuffSearch.schReceiveUser = ''
stuffSearch.schDispCompanyName = '' stuffSearch.schDispCompanyName = ''
stuffSearch.schDateType = 'U' stuffSearch.schDateType = 'U'
stuffSearch.schTempFlg = ''
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD') stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD') stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
stuffSearch.startRow = 1 stuffSearch.startRow = 1
stuffSearch.endRow = 100 stuffSearch.endRow = 100
stuffSearch.schSelSaleStoreId = '' stuffSearch.schSelSaleStoreId = ''
stuffSearch.schOtherSelSaleStoreId = '' stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schSortType = 'R' stuffSearch.schSortType = 'U'
stuffSearch.pageNo = 1 stuffSearch.pageNo = 1
stuffSearch.pageSize = 100 stuffSearch.pageSize = 100
setSchSelSaleStoreId('') setSchSelSaleStoreId('')
@ -597,6 +612,17 @@ export default function StuffSearchCondition() {
setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName) setDispCompanyName(stuffSearch.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName)
setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser) setReceiveUser(stuffSearch.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser)
setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType) setDateType(stuffSearch.schDateType ? stuffSearch.schDateType : dateType)
setTempFlg(stuffSearch.schTempFlg ? stuffSearch.schTempFlg : tempFlg)
}
if (stuffSearch.schDateType === 'R') {
setDateType('R')
}
if (stuffSearch.schTempFlg === '0') {
setTempFlg('0')
} else if (stuffSearch.schTempFlg === '1') {
setTempFlg('1')
} }
}, [stuffSearch]) }, [stuffSearch])
@ -648,8 +674,8 @@ export default function StuffSearchCondition() {
<col /> <col />
<col style={{ width: '160px' }} /> <col style={{ width: '160px' }} />
<col /> <col />
<col style={{ width: '160px' }} /> {/* <col style={{ width: '160px' }} />
<col /> <col /> */}
</colgroup> </colgroup>
<tbody> <tbody>
<tr> <tr>
@ -685,22 +711,7 @@ export default function StuffSearchCondition() {
/> />
</div> </div>
</td> </td>
<th>{getMessage('stuff.search.schAddress')}</th>
<td>
<div className="input-wrap">
<input
type="text"
ref={addressRef}
className="input-light"
defaultValue={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
onChange={() => {
stuffSearch.schAddress = addressRef.current.value
setAddress(addressRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
<th>{getMessage('stuff.search.schDispCompanyName')}</th> <th>{getMessage('stuff.search.schDispCompanyName')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
@ -751,8 +762,127 @@ export default function StuffSearchCondition() {
/> />
</div> </div>
</td> </td>
<th>{getMessage('stuff.search.schSelSaleStoreId')}</th> <th>{getMessage('stuff.search.schAddress')}</th>
<td>
<div className="input-wrap">
<input
type="text"
ref={addressRef}
className="input-light"
defaultValue={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
onChange={() => {
stuffSearch.schAddress = addressRef.current.value
setAddress(addressRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
</tr>
<tr>
<th>{getMessage('stuff.search.period')}</th>
<td colSpan={3}> <td colSpan={3}>
<div className="form-flex-wrap">
<div className="radio-wrap mr10">
<div className="d-check-radio light mr10">
<input
type="radio"
name="radio_ptype"
id="radio_u"
// checked={stuffSearch.schDateType === 'U' ? true : false}
checked={dateType === 'U' ? true : false}
value={'U'}
onChange={(e) => {
setDateType(e.target.value)
stuffSearch.schDateType = e.target.value
}}
/>
<label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="radio_ptype"
id="radio_r"
// checked={stuffSearch.schDateType === 'R' ? true : false}
checked={dateType === 'R' ? true : false}
value={'R'}
onChange={(e) => {
setDateType(e.target.value)
stuffSearch.schDateType = e.target.value
}}
/>
<label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label>
</div>
</div>
<div className="date-picker-wrap">
<div className="date-picker" style={{ flex: 1 }}>
<SingleDatePicker {...rangeDatePickerProps1} />
</div>
<span> ~ </span>
<div className="date-picker" style={{ flex: 1 }}>
<SingleDatePicker {...rangeDatePickerProps2} />
</div>
</div>
</div>
</td>
<th>{getMessage('stuff.search.schTempFlgT')}</th>
<td>
<div className="form-flex-wrap">
<div className="radio-wrap mr10">
<div className="d-check-radio light mr10">
<input
type="radio"
name="schTempFlg"
id="schTempFlg"
checked={stuffSearch.schTempFlg === '' ? true : false}
value={''}
onChange={(e) => {
// let tempFlg = e.target.value
// setTempFlg(tempFlg)
// console.log(' :::::11:::::::', e.target.value)
// console.log(' ::::22::::::::', tempFlg)
setTempFlg(e.target.value)
stuffSearch.schTempFlg = e.target.value
}}
/>
<label htmlFor="schTempFlg">{getMessage('stuff.search.schTempFlg')}</label>
</div>
<div className="d-check-radio light mr10">
<input
type="radio"
name="schTempFlg"
id="schTempFlg0"
checked={stuffSearch.schTempFlg === '0' ? true : false}
value={'0'}
onChange={(e) => {
setTempFlg(e.target.value)
stuffSearch.schTempFlg = e.target.value
}}
/>
<label htmlFor="schTempFlg0">{getMessage('stuff.search.schTempFlg0')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="schTempFlg"
id="schTempFlg1"
checked={stuffSearch.schTempFlg === '1' ? true : false}
value={'1'}
onChange={(e) => {
setTempFlg(e.target.value)
stuffSearch.schTempFlg = e.target.value
}}
/>
<label htmlFor="schTempFlg1">{getMessage('stuff.search.schTempFlg1')}</label>
</div>
</div>
</div>
</td>
</tr>
<tr>
<th>{getMessage('stuff.search.schSelSaleStoreId')}</th>
<td colSpan={5}>
<div className="form-flex-wrap"> <div className="form-flex-wrap">
<div className="select-wrap mr5" style={{ flex: 1 }}> <div className="select-wrap mr5" style={{ flex: 1 }}>
{session?.storeId === 'T01' && ( {session?.storeId === 'T01' && (
@ -876,52 +1006,6 @@ export default function StuffSearchCondition() {
</div> </div>
</td> </td>
</tr> </tr>
<tr>
<th>{getMessage('stuff.search.period')}</th>
<td colSpan={7}>
<div className="form-flex-wrap">
<div className="radio-wrap mr10">
<div className="d-check-radio light mr10">
<input
type="radio"
name="radio_ptype"
id="radio_u"
defaultChecked={stuffSearch.schDateType === 'U' ? true : false}
value={'U'}
onChange={(e) => {
setDateType(e.target.value)
stuffSearch.schDateType = e.target.value
}}
/>
<label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="radio_ptype"
id="radio_r"
defaultChecked={stuffSearch.schDateType === 'R' ? true : false}
value={'R'}
onChange={(e) => {
setDateType(e.target.value)
stuffSearch.schDateType = e.target.value
}}
/>
<label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label>
</div>
</div>
<div className="date-picker-wrap">
<div className="date-picker" style={{ flex: 1 }}>
<SingleDatePicker {...rangeDatePickerProps1} />
</div>
<span> ~ </span>
<div className="date-picker" style={{ flex: 1 }}>
<SingleDatePicker {...rangeDatePickerProps2} />
</div>
</div>
</div>
</td>
</tr>
</tbody> </tbody>
</table> </table>
</div> </div>

View File

@ -26,7 +26,8 @@ export const MODULE_INSERT_TYPE = {
} }
export const MODULE_ALIGN_TYPE = { export const MODULE_ALIGN_TYPE = {
TOP: 'top', VERTICAL: 'vertical',
HORIZONTAL: 'horizontal',
} }
export function useModule() { export function useModule() {
@ -83,6 +84,162 @@ export function useModule() {
} }
} }
} }
const moduleMultiMove = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
swalFire({
title: '여러 개의 모듈을 선택할 수 없습니다.',
icon: 'error',
type: 'alert',
})
canvas.discardActiveObject()
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
const otherModules = getOtherModules(modules)
const objects = getObjects()
const moduleSetupSurface = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (otherModules.length > 0) {
if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleMoveAll = (length, direction) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleCopyAll = (length, direction) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
const copyModules = []
let copyModule = null
let isWarning = false
let moduleLength = 0
if (['up', 'down'].includes(direction)) {
modules.sort((a, b) => a.top - b.top)
moduleLength = Number(modules[modules.length - 1].top) + Number(modules[modules.length - 1].height) - Number(modules[0].top)
} else if (['left', 'right'].includes(direction)) {
modules.sort((a, b) => a.left - b.left)
moduleLength = Number(modules[modules.length - 1].left) + Number(modules[modules.length - 1].width) - Number(modules[0].left)
}
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, Number(length) + Number(moduleLength), false)
module.clone((obj) => {
obj.set({
parentId: module.parentId,
initOptions: module.initOptions,
direction: module.direction,
arrow: module.arrow,
name: module.name,
type: module.type,
length: module.length,
points: module.points,
surfaceId: module.surfaceId,
left,
top,
id: uuidv4(),
})
copyModule = obj
canvas.add(obj)
copyModules.push(obj)
obj.setCoords()
})
if (isOverlapObjects(copyModule, objects) || isOutsideSurface(copyModule, moduleSetupSurface)) {
isWarning = true
copyModule.set({ fill: 'red' })
}
canvas.renderAll()
})
if (isWarning) {
swalFire({
title: getMessage('can.not.copy.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
canvas.remove(...copyModules)
canvas.renderAll()
},
})
}
}
const moduleCopy = (length, direction) => { const moduleCopy = (length, direction) => {
if (canvas.getActiveObjects().length === 0) return if (canvas.getActiveObjects().length === 0) return
@ -144,63 +301,6 @@ export function useModule() {
} }
} }
const moduleMultiMove = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) {
swalFire({
title: '여러 개의 모듈을 선택할 수 없습니다.',
icon: 'error',
type: 'alert',
})
canvas.discardActiveObject()
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule)
const otherModules = getOtherModules(modules)
const objects = getObjects()
const moduleSetupSurface = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0]
let isWarning = false
modules.forEach((module) => {
const { top, left } = getPosotion(module, direction, length, false)
module.originPos = {
top: module.top,
left: module.left,
fill: module.fill,
}
module.set({ top, left })
module.setCoords()
canvas.renderAll()
if (otherModules.length > 0) {
if (isOverlapOtherModules(module, otherModules) || isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.move.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const moduleMultiCopy = (type, length, direction) => { const moduleMultiCopy = (type, length, direction) => {
if (canvas.getActiveObjects().length === 0) return if (canvas.getActiveObjects().length === 0) return
if (canvas.getActiveObjects().length > 1) { if (canvas.getActiveObjects().length > 1) {
@ -694,7 +794,68 @@ export function useModule() {
} }
} }
const alignModule = (type) => {} const alignModule = (type) => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
const objects = getObjects()
let [top, bottom, left, right] = [0, 0, 0, 0]
top = Math.min(...modules.map((module) => module.top))
bottom = Math.max(...modules.map((module) => module.top + module.height))
left = Math.min(...modules.map((module) => module.left))
right = Math.max(...modules.map((module) => module.left + module.width))
const moduleSurfacePos = {
top: Math.min(...moduleSetupSurface.points.map((point) => point.y)),
left: Math.min(...moduleSetupSurface.points.map((point) => point.x)),
}
const [height, width] = [bottom - top, right - left]
const verticalCenterLength = moduleSurfacePos.top + moduleSetupSurface.height / 2 - (top + height / 2)
const horizontalCenterLength = moduleSurfacePos.left + moduleSetupSurface.width / 2 - (left + width / 2)
let isWarning = false
canvas.discardActiveObject()
modules.forEach((module) => {
module.originPos = {
left: module.left,
top: module.top,
fill: module.fill,
}
if (type === MODULE_ALIGN_TYPE.VERTICAL) {
module.set({ top: module.top + verticalCenterLength })
} else if (type === MODULE_ALIGN_TYPE.HORIZONTAL) {
module.set({ left: module.left + horizontalCenterLength })
}
canvas.renderAll()
module.setCoords()
if (isOverlapObjects(module, objects) || isOutsideSurface(module, moduleSetupSurface)) {
isWarning = true
module.set({ fill: 'red' })
}
})
canvas.renderAll()
if (isWarning) {
swalFire({
title: getMessage('can.not.align.module'),
icon: 'error',
type: 'alert',
confirmFn: () => {
modules.forEach((module) => {
module.set({ top: module.originPos.top, left: module.originPos.left, fill: module.originPos.fill })
module.setCoords()
})
canvas.renderAll()
},
})
}
}
const modulesRemove = () => {
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === activeModule.surfaceId && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules)
canvas.renderAll()
}
const isOverlapOtherModules = (module, otherModules) => { const isOverlapOtherModules = (module, otherModules) => {
return otherModules.some( return otherModules.some(
@ -765,11 +926,15 @@ export function useModule() {
return { return {
moduleMove, moduleMove,
moduleMultiMove, moduleMultiMove,
moduleMoveAll,
moduleCopy, moduleCopy,
moduleMultiCopy, moduleMultiCopy,
moduleCopyAll,
moduleColumnRemove, moduleColumnRemove,
moduleRowRemove, moduleRowRemove,
moduleColumnInsert, moduleColumnInsert,
muduleRowInsert, muduleRowInsert,
modulesRemove,
alignModule,
} }
} }

View File

@ -272,7 +272,7 @@ export function useCanvasSetting() {
// 기본설정(PlacementShapeSetting) 조회 및 초기화 // 기본설정(PlacementShapeSetting) 조회 및 초기화
const fetchBasicSettings = async () => { const fetchBasicSettings = async () => {
try { try {
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => { await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/0/${correntObjectNo}` }).then((res) => {
let roofsRow = {} let roofsRow = {}
let roofsArray = {} let roofsArray = {}
@ -762,7 +762,6 @@ export function useCanvasSetting() {
setCanvasSetting, setCanvasSetting,
basicSetting, basicSetting,
setBasicSettings, setBasicSettings,
fetchBasicSettings,
basicSettingSave, basicSettingSave,
settingsData, settingsData,
setSettingsData, setSettingsData,

View File

@ -5,6 +5,8 @@ import { useMessage } from '@/hooks/useMessage'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { QPolygon } from '@/components/fabric/QPolygon'
import { getDegreeByChon } from '@/util/canvas-util' import { getDegreeByChon } from '@/util/canvas-util'
//동선이동 형 올림 내림 //동선이동 형 올림 내림
@ -26,6 +28,7 @@ export function useMovementSetting(id) {
] ]
const [type, setType] = useState(TYPE.FLOW_LINE) const [type, setType] = useState(TYPE.FLOW_LINE)
const typeRef = useRef(type) const typeRef = useRef(type)
const { swalFire } = useSwal()
const FLOW_LINE_REF = { const FLOW_LINE_REF = {
POINTER_INPUT_REF: useRef(null), POINTER_INPUT_REF: useRef(null),
@ -69,6 +72,7 @@ export function useMovementSetting(id) {
roof.innerLines.forEach((line) => { roof.innerLines.forEach((line) => {
if (line.name === LINE_TYPE.SUBLINE.RIDGE) { if (line.name === LINE_TYPE.SUBLINE.RIDGE) {
line.bringToFront() line.bringToFront()
line.set({ visible: true })
line.set({ selectable: true }) line.set({ selectable: true })
line.set({ strokeWidth: 4 }) line.set({ strokeWidth: 4 })
line.set({ stroke: '#1083E3' }) line.set({ stroke: '#1083E3' })
@ -89,7 +93,6 @@ export function useMovementSetting(id) {
canvas.renderAll() canvas.renderAll()
addCanvasMouseEventListener('mouse:move', mouseMoveEvent) addCanvasMouseEventListener('mouse:move', mouseMoveEvent)
addCanvasMouseEventListener('mouse:down', mouseDownEvent) addCanvasMouseEventListener('mouse:down', mouseDownEvent)
return () => { return () => {
initEvent() initEvent()
@ -178,6 +181,36 @@ export function useMovementSetting(id) {
updownMoveEvent(e) updownMoveEvent(e)
} }
} }
function edgesIntersection(edgeA, edgeB) {
const den =
(edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) -
(edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y)
if (den === 0) {
return null // lines are parallel or coincident
}
const ua =
((edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
(edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
den
const ub =
((edgeA.vertex2.x - edgeA.vertex1.x) * (edgeA.vertex1.y - edgeB.vertex1.y) -
(edgeA.vertex2.y - edgeA.vertex1.y) * (edgeA.vertex1.x - edgeB.vertex1.x)) /
den
// Edges are not intersecting but the lines defined by them are
const isIntersectionOutside = ua < 0 || ub < 0 || ua > 1 || ub > 1
return {
x: edgeA.vertex1.x + ua * (edgeA.vertex2.x - edgeA.vertex1.x),
y: edgeA.vertex1.y + ua * (edgeA.vertex2.y - edgeA.vertex1.y),
isIntersectionOutside,
}
}
//동선 이동 마우스 클릭 이벤트 //동선 이동 마우스 클릭 이벤트
const saveFlowLine = (e) => { const saveFlowLine = (e) => {
const target = selectedObject.current const target = selectedObject.current
@ -187,22 +220,23 @@ export function useMovementSetting(id) {
let newPoint = [] let newPoint = []
if (Math.sign(target.x1 - target.x2) !== 0) { if (Math.sign(target.x1 - target.x2) !== 0) {
const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? 1 : -1
newPoint = [ newPoint = [
target.x1, target.x1,
target.y1 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.y1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.x2, target.x2,
target.y2 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.y2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
] ]
} else { } else {
const sign = FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked ? -1 : 1
newPoint = [ newPoint = [
target.x1 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.x1 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.y1, target.y1,
target.x2 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), target.x2 - sign * Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10),
target.y2, target.y2,
] ]
} }
newPoint = newPoint.map((point) => Math.round(point * 10) / 10)
clearRef()
const cloned = new fabric.Line(newPoint, {}) const cloned = new fabric.Line(newPoint, {})
let currentObject = selectedObject.current let currentObject = selectedObject.current
const currentX1 = currentObject.x1, const currentX1 = currentObject.x1,
@ -210,39 +244,94 @@ export function useMovementSetting(id) {
currentX2 = currentObject.x2, currentX2 = currentObject.x2,
currentY2 = currentObject.y2 currentY2 = currentObject.y2
const currentMidX = (currentX1 + currentX2) / 2
const currentMidY = (currentY1 + currentY2) / 2
const clonedMidX = (cloned.x1 + cloned.x2) / 2
const clonedMidY = (cloned.y1 + cloned.y2) / 2
const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId) const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId)
if (roof.separatePolygon.length > 0) { let isOutside = false
const separatePolygon = roof.separatePolygon roof.lines.forEach((line) => {
separatePolygon const intersection = edgesIntersection(
.filter((polygon) => { vertex1: { x: currentMidX, y: currentMidY }, vertex2: { x: clonedMidX, y: clonedMidY } },
polygon.points.some((point) => (point.x === currentX1 && point.y === currentY1) || (point.x === currentX2 && point.y === currentY2)), { vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
) )
.forEach((polygon) => { if (intersection && !intersection.isIntersectionOutside) {
const newPoints = polygon.points.map((point) => { isOutside = true
if (point.x === currentX1 && point.y === currentY1) { }
return { x: newPoint[0], y: newPoint[1] } })
} else if (point.x === currentX2 && point.y === currentY2) { if (isOutside) {
return { x: newPoint[2], y: newPoint[3] } swalFire({ text: getMessage('modal.movement.flow.line.move.alert'), icon: 'error' })
} else { return
return point }
} currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 })
}) currentObject.setCoords()
polygon.set({ points: newPoints }) const otherRidges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE && line.id !== currentObject.id)
polygon.setCoords() const overlapRidges = otherRidges.filter((line) => {
polygon.addLengthText() if (currentObject.x1 === currentObject.x2 && line.x1 === line.x2 && 0 < Math.abs(currentObject.x1 - line.x1) < 1) {
polygon.initLines() if (
const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1)) currentObject.y1 <= line.y1 <= currentObject.y2 ||
const currentDegree = polygon.attributes.pitch > 0 ? getDegreeByChon(polygon.attributes.pitch) : polygon.attributes.degree currentObject.y1 >= line.y1 >= currentObject.y2 ||
polygon.lines.forEach((line) => { currentObject.y1 <= line.y2 <= currentObject.y2 ||
line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10) currentObject.y1 >= line.y2 >= currentObject.y2
if (currentDegree > 0 && slope(line) !== slope(currentObject)) { ) {
const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize return true
line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2))) }
} else { }
line.attributes.actualSize = line.attributes.planeSize if (currentObject.y1 === currentObject.y2 && line.y1 === line.y2 && 0 < Math.abs(currentObject.y1 - line.y1) < 1) {
} if (
}) currentObject.x1 <= line.x1 <= currentObject.x2 ||
currentObject.x1 >= line.x1 >= currentObject.x2 ||
currentObject.x1 <= line.x2 <= currentObject.x2 ||
currentObject.x1 >= line.x2 >= currentObject.x2
) {
return true
}
}
})
if (overlapRidges.length > 0) {
const minX = Math.min(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
const maxX = Math.max(...overlapRidges.flatMap((line) => [line.x1, line.x2]), currentObject.x1, currentObject.x2)
const minY = Math.min(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
const maxY = Math.max(...overlapRidges.flatMap((line) => [line.y1, line.y2]), currentObject.y1, currentObject.y2)
const newRidge = new fabric.Line([minX, minY, maxX, maxY], {
name: LINE_TYPE.SUBLINE.RIDGE,
selectable: true,
stroke: '#1083E3',
strokeWidth: 4,
attributes: { roofId: roof.id, currentRoof: currentObject.attributes.currentRoof },
})
overlapRidges.forEach((line) =>
line.attributes.currentRoof.forEach((id) => {
if (!newRidge.attributes.currentRoof.includes(id)) {
newRidge.attributes.currentRoof.push(id)
}
}),
)
canvas.add(newRidge)
newRidge.bringToFront()
roof.innerLines.push(newRidge)
canvas.remove(currentObject)
roof.innerLines.forEach((innerLine, index) => {
if (innerLine.id === currentObject.id) {
roof.innerLines.splice(index, 1)
}
})
overlapRidges.forEach((line) => {
canvas.remove(line)
roof.innerLines.forEach((innerLine, index) => {
if (innerLine.id === line.id) {
roof.innerLines.splice(index, 1)
}
}) })
})
}
if (roof.separatePolygon.length > 0) {
redrawSeparatePolygon(roof)
} else { } else {
roof.innerLines roof.innerLines
.filter((line) => currentObject !== line) .filter((line) => currentObject !== line)
@ -277,6 +366,390 @@ export function useMovementSetting(id) {
canvas.renderAll() canvas.renderAll()
canvas.discardActiveObject() canvas.discardActiveObject()
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
}
const redrawSeparatePolygon = (roof) => {
roof.separatePolygon.forEach((polygon) => canvas.remove(polygon))
roof.separatePolygon = []
const roofLines = roof.lines
const wallLines = roof.wall.lines
const eaves = []
roofLines.forEach((currentRoof, index) => {
if (currentRoof.attributes?.type === LINE_TYPE.WALLLINE.EAVES) {
eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
}
})
const ridges = roof.innerLines.filter((line) => line.name === LINE_TYPE.SUBLINE.RIDGE)
eaves.sort((a, b) => a.length - b.length)
const ridgeCount = eaves.length - 1
console.log('ridgeCount', ridgeCount, 'ridges', ridges.length)
const duplicatedEaves = []
ridges.forEach((ridge) => {
const positiveLines = []
const negativeLines = []
ridge.attributes.currentRoof.forEach((id) => {
console.log('id : ', id)
const eave = roofLines.find((obj) => obj.id === id)
console.log('roof : ', eave)
if (ridge.x1 === ridge.x2) {
if (eave.y1 < eave.y2) {
positiveLines.push(eave)
} else {
negativeLines.push(eave)
}
} else {
if (eave.x1 < eave.x2) {
positiveLines.push(eave)
} else {
negativeLines.push(eave)
}
}
})
if (positiveLines.length > 1) {
duplicatedEaves.push(positiveLines)
}
if (negativeLines.length > 1) {
duplicatedEaves.push(negativeLines)
}
})
console.log('duplicatedEaves', duplicatedEaves)
duplicatedEaves.forEach((duplicatedEave) => {
duplicatedEave.forEach((eave) => {
const index = eaves.findIndex((item) => item.roof.id === eave.id)
eaves.splice(index, 1)
})
})
// if (ridgeCount === ridges.length) {
eaves.forEach((eave, i) => {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.roof.id))
let points = []
const signX = Math.sign(currentRoof.x1 - currentRoof.x2)
let currentX1 = currentRoof.x1,
currentY1 = currentRoof.y1,
currentX2 = currentRoof.x2,
currentY2 = currentRoof.y2
let changeX1 = [Math.min(currentRoof.x1, currentRoof.x2), Math.min(currentRoof.x1, currentRoof.x2)],
changeY1 = [Math.min(currentRoof.y1, currentRoof.y2), Math.min(currentRoof.y1, currentRoof.y2)],
changeX2 = [Math.max(currentRoof.x2, currentRoof.x1), Math.max(currentRoof.x2, currentRoof.x1)],
changeY2 = [Math.max(currentRoof.y2, currentRoof.y1), Math.max(currentRoof.y2, currentRoof.y1)]
if (signX === 0) {
currentY1 = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
changeY1[1] = currentY1
currentY2 = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
changeY2[1] = currentY2
} else {
currentX1 = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
changeX1[1] = currentX1
currentX2 = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
changeX2[1] = currentX2
}
points.push({ x: currentX1, y: currentY1 }, { x: currentX2, y: currentY2 })
currentRidges.forEach((ridge) => {
let ridgeX1 = ridge.x1,
ridgeY1 = ridge.y1,
ridgeX2 = ridge.x2,
ridgeY2 = ridge.y2
if (signX === 0) {
ridgeY1 = Math.min(ridge.y1, ridge.y2)
ridgeY2 = Math.max(ridge.y1, ridge.y2)
} else {
ridgeX1 = Math.min(ridge.x1, ridge.x2)
ridgeX2 = Math.max(ridge.x1, ridge.x2)
}
points.push({ x: ridgeX1, y: ridgeY1 }, { x: ridgeX2, y: ridgeY2 })
})
points.forEach((point) => {
if (point.x === changeX1[0] && changeX1[0] !== changeX1[1]) {
point.x = changeX1[1]
}
if (point.x === changeX2[0] && changeX2[0] !== changeX2[1]) {
point.x = changeX2[1]
}
if (point.y === changeY1[0] && changeY1[0] !== changeY1[1]) {
point.y = changeY1[1]
}
if (point.y === changeY2[0] && changeY2[0] !== changeY2[1]) {
point.y = changeY2[1]
}
})
//중복된 point 제거
points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
//point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
const startPoint = points
.filter((point) => point.x === Math.min(...points.map((point) => point.x)))
.reduce((prev, current) => {
return prev.y < current.y ? prev : current
})
const sortedPoints = []
sortedPoints.push(startPoint)
points.forEach((p, index) => {
if (index === 0) {
//시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
const underStartPoint = points.filter((point) => point.y > startPoint.y)
const nextPoint = underStartPoint
.filter((point) => point.x === startPoint.x)
.reduce((prev, current) => {
if (prev === undefined) {
return current
}
return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = underStartPoint.reduce((prev, current) => {
const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
return prevHypos < currentHypos ? prev : current
}, undefined)
sortedPoints.push(nextPoint)
}
} else {
const lastPoint = sortedPoints[sortedPoints.length - 1]
console.log('lastPoint', lastPoint)
const prevPoint = sortedPoints[sortedPoints.length - 2]
const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev === undefined) {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
const angle = Math.round(
Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
)
if (angle === 90) {
return current
}
} else {
return prev
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev !== undefined) {
const height = Math.abs(
Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
)
const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuseC = Math.abs(
Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
)
const angleC = Math.round(
Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
)
const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
const angleP = Math.round(
Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
)
if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
return current
} else {
return prev
}
} else {
return current
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
}
}
}
})
if (sortedPoints.length > 0) {
const roofPolygon = new QPolygon(sortedPoints, {
fill: 'transparent',
stroke: '#000000',
strokeWidth: 1,
selectable: false,
fontSize: roof.fontSize,
name: 'roofPolygon',
attributes: {
roofId: roof.id,
currentRoof: currentRoof.id,
pitch: currentRoof.attributes.pitch,
degree: currentRoof.attributes.degree,
direction: currentRoof.direction,
},
})
const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
//지붕 각도에 따른 실측치 조정
roofPolygon.lines.forEach((line) => {
line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
} else {
line.attributes.actualSize = line.attributes.planeSize
}
})
roof.separatePolygon.push(roofPolygon)
canvas.add(roofPolygon)
canvas.renderAll()
}
})
duplicatedEaves.forEach((duplicatedEave) => {
const currentRoof = duplicatedEave[0]
let points = []
duplicatedEave.forEach((eave) => {
points.push({ x: eave.x1, y: eave.y1 }, { x: eave.x2, y: eave.y2 })
const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.id))
currentRidges.forEach((ridge) => {
points.push({ x: ridge.x1, y: ridge.y1 }, { x: ridge.x2, y: ridge.y2 })
})
})
console.log('points', points)
points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
//point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
const startPoint = points
.filter((point) => point.x === Math.min(...points.map((point) => point.x)))
.reduce((prev, current) => {
return prev.y < current.y ? prev : current
})
const sortedPoints = []
sortedPoints.push(startPoint)
points.forEach((p, index) => {
if (index === 0) {
//시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
const underStartPoint = points.filter((point) => point.y > startPoint.y)
const nextPoint = underStartPoint
.filter((point) => point.x === startPoint.x)
.reduce((prev, current) => {
if (prev === undefined) {
return current
}
return Math.abs(prev.y - startPoint.y) < Math.abs(current.y - startPoint.y) ? prev : current
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = underStartPoint.reduce((prev, current) => {
const prevHypos = Math.sqrt(Math.abs(Math.pow(prev.x - startPoint.x, 2)) + Math.abs(Math.pow(prev.y - startPoint.y, 2)))
const currentHypos = Math.sqrt(Math.abs(Math.pow(current.x - startPoint.x, 2)) + Math.abs(Math.pow(current.y - startPoint.y, 2)))
return prevHypos < currentHypos ? prev : current
}, undefined)
sortedPoints.push(nextPoint)
}
} else {
const lastPoint = sortedPoints[sortedPoints.length - 1]
console.log('lastPoint', lastPoint)
const prevPoint = sortedPoints[sortedPoints.length - 2]
const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev === undefined) {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacent = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuse = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
const angle = Math.round(
Math.acos((Math.pow(adjacent, 2) + Math.pow(height, 2) - Math.pow(hypotenuse, 2)) / (2 * adjacent * height)) * (180 / Math.PI),
)
if (angle === 90) {
return current
}
} else {
return prev
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
} else {
const nextPoint = otherPoints.reduce((prev, current) => {
if (prev !== undefined) {
const height = Math.abs(
Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))),
)
const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuseC = Math.abs(
Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))),
)
const angleC = Math.round(
Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
)
const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
const angleP = Math.round(
Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
)
if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
return current
} else {
return prev
}
} else {
return current
}
}, undefined)
if (nextPoint) {
sortedPoints.push(nextPoint)
}
}
}
})
if (sortedPoints.length > 0) {
const roofPolygon = new QPolygon(sortedPoints, {
fill: 'transparent',
stroke: '#000000',
strokeWidth: 1,
selectable: false,
fontSize: roof.fontSize,
name: 'roofPolygon',
attributes: {
roofId: roof.id,
currentRoof: currentRoof.id,
pitch: currentRoof.attributes.pitch,
degree: currentRoof.attributes.degree,
direction: currentRoof.direction,
},
})
const currentDegree = currentRoof.attributes.pitch > 0 ? getDegreeByChon(currentRoof.attributes.pitch) : currentRoof.attributes.degree
//지붕 각도에 따른 실측치 조정
roofPolygon.lines.forEach((line) => {
line.attributes.planeSize = Math.round(Math.sqrt(Math.pow(line.x2 - line.x1, 2) + Math.pow(line.y2 - line.y1, 2)) * 10)
const slope = (line) => (line.x2 - line.x1 === 0 ? Infinity : (line.y2 - line.y1) / (line.x2 - line.x1))
if (currentDegree > 0 && slope(line) !== slope(currentRoof)) {
const height = Math.tan(currentDegree * (Math.PI / 180)) * line.attributes.planeSize
line.attributes.actualSize = Math.round(Math.sqrt(Math.pow(line.attributes.planeSize, 2) + Math.pow(height, 2)))
} else {
line.attributes.actualSize = line.attributes.planeSize
}
})
roof.separatePolygon.push(roofPolygon)
canvas.add(roofPolygon)
canvas.renderAll()
}
})
console.log('roof.separatePolygon : ', roof.separatePolygon)
ridges.forEach((ridge) => ridge.bringToFront())
console.log('ridges : ', ridges)
} }
//형 올림내림 마우스 클릭 이벤트 //형 올림내림 마우스 클릭 이벤트
@ -295,18 +768,18 @@ export function useMovementSetting(id) {
if (Math.sign(target.x1 - target.x2) !== 0) { if (Math.sign(target.x1 - target.x2) !== 0) {
if (targetTop > currentY) { if (targetTop > currentY) {
FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
} else { } else {
FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(targetTop - currentY))) / 10000).toFixed(5) * 100000)
} }
} else { } else {
if (targetLeft > currentX) { if (targetLeft < currentX) {
FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
} else { } else {
FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.abs(Math.round(currentX - targetLeft))) / 10000).toFixed(5) * 100000)
} }
} }

View File

@ -258,8 +258,6 @@ export function useRoofAllocationSetting(id) {
return roof return roof
}) })
newRoofList[selectedIndex].selected = true
setCurrentRoofList(newRoofList) setCurrentRoofList(newRoofList)
} }

View File

@ -1,7 +1,7 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { canvasState, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { MENU } from '@/common/common' import { MENU, POLYGON_TYPE } from '@/common/common'
import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize' import AuxiliarySize from '@/components/floor-plan/modal/auxiliary/AuxiliarySize'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
@ -40,6 +40,7 @@ import { useCanvasSetting } from './option/useCanvasSetting'
import { useGrid } from './common/useGrid' import { useGrid } from './common/useGrid'
import { useAdsorptionPoint } from './useAdsorptionPoint' import { useAdsorptionPoint } from './useAdsorptionPoint'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { MODULE_ALIGN_TYPE, useModule } from './module/useModule'
export function useContextMenu() { export function useContextMenu() {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
@ -66,6 +67,7 @@ export function useContextMenu() {
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const { settingsData, setSettingsDataSave } = useCanvasSetting() const { settingsData, setSettingsDataSave } = useCanvasSetting()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { alignModule } = useModule()
const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn() const { removeRoofMaterial, removeAllRoofMaterial } = useRoofFn()
const currentMenuSetting = () => { const currentMenuSetting = () => {
@ -691,36 +693,38 @@ export function useContextMenu() {
]) ])
break break
case 'moduleSetupSurface': case 'moduleSetupSurface':
case 'dimensionLineText': case 'roof':
setContextMenu([ setContextMenu([
[ [
{ {
id: 'moduleVerticalCenterAlign', id: 'moduleVerticalCenterAlign',
name: getMessage('contextmenu.module.vertical.align'), name: getMessage('contextmenu.module.vertical.align'),
fn: () => alignModule(MODULE_ALIGN_TYPE.VERTICAL),
}, },
{ {
id: 'moduleHorizonCenterAlign', id: 'moduleHorizonCenterAlign',
name: getMessage('contextmenu.module.horizon.align'), name: getMessage('contextmenu.module.horizon.align'),
}, fn: () => alignModule(MODULE_ALIGN_TYPE.HORIZONTAL),
{
id: 'moduleLeftAlign',
name: getMessage('contextmenu.module.left.align'),
},
{
id: 'moduleRightAlign',
name: getMessage('contextmenu.module.right.align'),
},
{
id: 'moduleUpAlign',
name: getMessage('contextmenu.module.up.align'),
},
{
id: 'moduleDownAlign',
name: getMessage('contextmenu.module.down.align'),
}, },
{ {
id: 'moduleRemove', id: 'moduleRemove',
name: getMessage('contextmenu.module.remove'), name: getMessage('contextmenu.module.remove'),
fn: () => {
const moduleSetupSurface = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const modules = canvas.getObjects().filter((obj) => obj.surfaceId === moduleSetupSurface.id && obj.name === POLYGON_TYPE.MODULE)
canvas.remove(...modules)
canvas.renderAll()
},
},
{
id: 'moduleMove',
name: getMessage('contextmenu.module.move'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.MOVE_ALL} />,
},
{
id: 'moduleCopy',
name: getMessage('contextmenu.module.copy'),
component: <PanelEdit id={popupId} type={PANEL_EDIT_TYPE.COPY_ALL} />,
}, },
{ {
id: 'moduleCircuitNumberEdit', id: 'moduleCircuitNumberEdit',

View File

@ -1719,6 +1719,25 @@ export function useMode() {
} }
const drawRoofPolygon = (wall) => { const drawRoofPolygon = (wall) => {
const startLine = wall.lines
.filter((line) => line.x1 === Math.min(...wall.lines.map((line) => line.x1)))
.reduce((prev, current) => {
return prev.y1 < current.y1 ? prev : current
})
const beforeLine = [],
afterLine = []
let startIndex = wall.lines.findIndex((line) => line === startLine)
wall.lines.forEach((line, index) => {
if (index < startIndex) {
beforeLine.push(line)
} else {
afterLine.push(line)
}
})
wall.lines = afterLine.concat(beforeLine)
const polygon = createRoofPolygon(wall.points) const polygon = createRoofPolygon(wall.points)
const originPolygon = new QPolygon(wall.points, { fontSize: 0 }) const originPolygon = new QPolygon(wall.points, { fontSize: 0 })
originPolygon.setViewLengthText(false) originPolygon.setViewLengthText(false)

View File

@ -44,6 +44,7 @@
"plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경", "plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경",
"plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림(JA)", "plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림(JA)",
"modal.movement.flow.line.move": "銅線の移動軒", "modal.movement.flow.line.move": "銅線の移動軒",
"modal.movement.flow.line.move.alert": "이동 할 수 없습니다.(JA)",
"modal.movement.flow.line.updown": "型上げ・降り", "modal.movement.flow.line.updown": "型上げ・降り",
"modal.movement.flow.line.updown.info": "を選択して幅を指定してください桁の異なる辺。", "modal.movement.flow.line.updown.info": "を選択して幅を指定してください桁の異なる辺。",
"modal.movement.flow.line.updown.up": "桁を上げる", "modal.movement.flow.line.updown.up": "桁を上げる",
@ -631,7 +632,7 @@
"stuff.detail.header.successCopy": "商品番号がコピーされました。", "stuff.detail.header.successCopy": "商品番号がコピーされました。",
"stuff.detail.header.failCopy": "存在しないものです。", "stuff.detail.header.failCopy": "存在しないものです。",
"stuff.detail.header.objectNo": "商品番号のコピーに失敗しました。", "stuff.detail.header.objectNo": "商品番号のコピーに失敗しました。",
"stuff.detail.header.specificationConfirmDate": "仕様拡張日", "stuff.detail.header.specificationConfirmDate": "仕様確認日",
"stuff.detail.header.lastEditDatetime": "更新日時", "stuff.detail.header.lastEditDatetime": "更新日時",
"stuff.detail.header.createDatetime": "登録日", "stuff.detail.header.createDatetime": "登録日",
"stuff.detail.required": "必須入力項目", "stuff.detail.required": "必須入力項目",
@ -723,11 +724,15 @@
"stuff.search.period": "期間検索", "stuff.search.period": "期間検索",
"stuff.search.schDateTypeU": "更新日", "stuff.search.schDateTypeU": "更新日",
"stuff.search.schDateTypeR": "登録日", "stuff.search.schDateTypeR": "登録日",
"stuff.search.schTempFlgT": "一時保存物",
"stuff.search.schTempFlg": "含む",
"stuff.search.schTempFlg0": "除外",
"stuff.search.schTempFlg1": "一時的なものだけを見る",
"stuff.search.grid.title": "商品リスト", "stuff.search.grid.title": "商品リスト",
"stuff.search.grid.all": "全体", "stuff.search.grid.all": "全体",
"stuff.search.grid.selected": "選択", "stuff.search.grid.selected": "選択",
"stuff.search.grid.schSortTypeR": "最近の登録日", "stuff.search.grid.schSortTypeR": "最近の登録日",
"stuff.search.grid.schSortTypeU": "最近の更新日", "stuff.search.grid.schSortTypeU": "最近修正日",
"stuff.windSelectPopup.title": "風速選択", "stuff.windSelectPopup.title": "風速選択",
"stuff.windSelectPopup.table.selected": "選択", "stuff.windSelectPopup.table.selected": "選択",
"stuff.windSelectPopup.table.windspeed": "風速", "stuff.windSelectPopup.table.windspeed": "風速",
@ -801,6 +806,8 @@
"main.storeName": "販売店名", "main.storeName": "販売店名",
"main.objectNo": "物件番号", "main.objectNo": "物件番号",
"main.faq": "FAQ", "main.faq": "FAQ",
"main.content.objectList.noData1": "登録された商品情報はありません.",
"main.content.objectList.noData2": "下のボタンをクリックして商品情報を登録してください.",
"main.content.objectList": "最近の更新物件一覧", "main.content.objectList": "最近の更新物件一覧",
"main.content.notice": "お知らせ", "main.content.notice": "お知らせ",
"main.content.download1": "操作マニュアル", "main.content.download1": "操作マニュアル",
@ -817,6 +824,7 @@
"main.popup.login.btn2": "変更しない", "main.popup.login.btn2": "変更しない",
"main.popup.login.validate1": "入力したパスワードが異なります。", "main.popup.login.validate1": "入力したパスワードが異なります。",
"main.popup.login.validate2": "半角10文字以内で入力してください。", "main.popup.login.validate2": "半角10文字以内で入力してください。",
"main.popup.login.validate3": "비밀번호를 입력해주세요.",
"main.popup.login.success": "パスワードが変更されました。", "main.popup.login.success": "パスワードが変更されました。",
"common.canvas.validate.size": "寸法を入力してください.", "common.canvas.validate.size": "寸法を入力してください.",
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
@ -941,5 +949,6 @@
"can.not.move.module": "모듈을 이동할 수 없습니다.(JA)", "can.not.move.module": "모듈을 이동할 수 없습니다.(JA)",
"can.not.copy.module": "모듈을 복사할 수 없습니다.(JA)", "can.not.copy.module": "모듈을 복사할 수 없습니다.(JA)",
"can.not.remove.module": "모듈을 삭제할 수 없습니다.(JA)", "can.not.remove.module": "모듈을 삭제할 수 없습니다.(JA)",
"can.not.insert.module": "모듈을 삽입할 수 없습니다.(JA)" "can.not.insert.module": "모듈을 삽입할 수 없습니다.(JA)",
"can.not.align.module": "모듈을 정렬할 수 없습니다.(JA)"
} }

View File

@ -44,6 +44,7 @@
"plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경", "plan.menu.roof.cover.eaves.kerava.edit": "처마·케라바 변경",
"plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림", "plan.menu.roof.cover.movement.shape.updown": "동선이동·형올림내림",
"modal.movement.flow.line.move": "동선 이동", "modal.movement.flow.line.move": "동선 이동",
"modal.movement.flow.line.move.alert": "이동 할 수 없습니다.",
"modal.movement.flow.line.updown": "형 올림·내림", "modal.movement.flow.line.updown": "형 올림·내림",
"modal.movement.flow.line.updown.info": "자릿수가 다른 변을 선택하고 폭을 지정하십시오.", "modal.movement.flow.line.updown.info": "자릿수가 다른 변을 선택하고 폭을 지정하십시오.",
"modal.movement.flow.line.updown.up": "자릿수를 올리다", "modal.movement.flow.line.updown.up": "자릿수를 올리다",
@ -641,7 +642,7 @@
"stuff.detail.header.successCopy": "물건번호가 복사되었습니다.", "stuff.detail.header.successCopy": "물건번호가 복사되었습니다.",
"stuff.detail.header.failCopy": "물건번호 복사에 실패했습니다.", "stuff.detail.header.failCopy": "물건번호 복사에 실패했습니다.",
"stuff.detail.header.objectNo": "물건번호", "stuff.detail.header.objectNo": "물건번호",
"stuff.detail.header.specificationConfirmDate": "사양확일", "stuff.detail.header.specificationConfirmDate": "사양확일",
"stuff.detail.header.lastEditDatetime": "갱신일시", "stuff.detail.header.lastEditDatetime": "갱신일시",
"stuff.detail.header.createDatetime": "등록일", "stuff.detail.header.createDatetime": "등록일",
"stuff.detail.required": "필수 입력항목", "stuff.detail.required": "필수 입력항목",
@ -733,11 +734,15 @@
"stuff.search.period": "기간검색", "stuff.search.period": "기간검색",
"stuff.search.schDateTypeU": "갱신일", "stuff.search.schDateTypeU": "갱신일",
"stuff.search.schDateTypeR": "등록일", "stuff.search.schDateTypeR": "등록일",
"stuff.search.schTempFlgT": "임시저장 물건",
"stuff.search.schTempFlg": "포함",
"stuff.search.schTempFlg0": "제외",
"stuff.search.schTempFlg1": "임시물건만 조회",
"stuff.search.grid.title": "물건목록", "stuff.search.grid.title": "물건목록",
"stuff.search.grid.all": "전체", "stuff.search.grid.all": "전체",
"stuff.search.grid.selected": "선택", "stuff.search.grid.selected": "선택",
"stuff.search.grid.schSortTypeR": "최근 등록일", "stuff.search.grid.schSortTypeR": "최근 등록일",
"stuff.search.grid.schSortTypeU": "최근 갱신일", "stuff.search.grid.schSortTypeU": "최근 수정일",
"stuff.windSelectPopup.title": "풍속선택", "stuff.windSelectPopup.title": "풍속선택",
"stuff.windSelectPopup.table.selected": "선택", "stuff.windSelectPopup.table.selected": "선택",
"stuff.windSelectPopup.table.windspeed": "풍속", "stuff.windSelectPopup.table.windspeed": "풍속",
@ -811,6 +816,8 @@
"main.storeName": "판매점명", "main.storeName": "판매점명",
"main.objectNo": "물건번호", "main.objectNo": "물건번호",
"main.faq": "FAQ", "main.faq": "FAQ",
"main.content.objectList.noData1": "등록된 물건정보가 없습니다.",
"main.content.objectList.noData2": "아래 버튼을 클릭하여 물건정보를 등록하십시오.",
"main.content.objectList": "최근 갱신 물건목록", "main.content.objectList": "최근 갱신 물건목록",
"main.content.notice": "공지사항", "main.content.notice": "공지사항",
"main.content.download1": "조작메뉴얼", "main.content.download1": "조작메뉴얼",
@ -827,6 +834,7 @@
"main.popup.login.btn2": "변경안함", "main.popup.login.btn2": "변경안함",
"main.popup.login.validate1": "입력한 패스워드가 다릅니다.", "main.popup.login.validate1": "입력한 패스워드가 다릅니다.",
"main.popup.login.validate2": "반각 10자 이내로 입력해주세요.", "main.popup.login.validate2": "반각 10자 이내로 입력해주세요.",
"main.popup.login.validate3": "비밀번호를 입력해주세요.",
"main.popup.login.success": "비밀번호가 변경되었습니다.", "main.popup.login.success": "비밀번호가 변경되었습니다.",
"common.canvas.validate.size": "사이즈를 입력해 주세요.", "common.canvas.validate.size": "사이즈를 입력해 주세요.",
"surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.", "surface.shape.validate.size.1to2": "①길이는 ②보다 큰 값을 넣어주세요.",
@ -951,5 +959,6 @@
"can.not.move.module": "모듈을 이동할 수 없습니다.", "can.not.move.module": "모듈을 이동할 수 없습니다.",
"can.not.copy.module": "모듈을 복사할 수 없습니다.", "can.not.copy.module": "모듈을 복사할 수 없습니다.",
"can.not.remove.module": "모듈을 삭제할 수 없습니다.", "can.not.remove.module": "모듈을 삭제할 수 없습니다.",
"can.not.insert.module": "모듈을 삽입할 수 없습니다." "can.not.insert.module": "모듈을 삽입할 수 없습니다.",
"can.not.align.module": "모듈을 정렬할 수 없습니다."
} }

View File

@ -17,9 +17,10 @@ export const stuffSearchState = atom({
schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택 schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일) schSortType: 'U', //정렬조건 (R:최근등록일 U:최근수정일)
pageNo: 1, pageNo: 1,
pageSize: 100, pageSize: 100,
schTempFlg: '', //임시저장여부
}, },
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })

View File

@ -207,6 +207,7 @@ header{
.select-box{ .select-box{
min-width: 165px; min-width: 165px;
margin-right: 8px; margin-right: 8px;
height: 30px;
>div{ >div{
width: 100%; width: 100%;
} }

View File

@ -155,6 +155,7 @@
.product-item-content{ .product-item-content{
margin-top: 30px; margin-top: 30px;
overflow: hidden; overflow: hidden;
height: 100%;
.recently-list{ .recently-list{
.recently-item{ .recently-item{
border: 1px solid #F2F2F2; border: 1px solid #F2F2F2;
@ -208,6 +209,25 @@
} }
} }
} }
.recently-no-data{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100%;
h3{
font-size: 16px;
color: #101010;
font-weight: 600;
margin-bottom: 5px;
}
p{
font-size: 12px;
color: #666;
font-weight: 400;
margin-bottom: 10px;
}
}
.notice-box{ .notice-box{
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;

View File

@ -317,7 +317,7 @@ export const drawGabledRoof = (roofId, canvas) => {
// 처마라인의 기본속성 입력 // 처마라인의 기본속성 입력
const eaves = [] const eaves = []
roofLines.forEach((currentRoof, index) => { roofLines.forEach((currentRoof, index) => {
if (currentRoof.attributes !== undefined && currentRoof.attributes.type === LINE_TYPE.WALLLINE.EAVES) { if (currentRoof.attributes?.type === LINE_TYPE.WALLLINE.EAVES) {
eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize }) eaves.push({ index: index, roof: currentRoof, length: currentRoof.attributes.planeSize })
} }
}) })
@ -325,291 +325,147 @@ export const drawGabledRoof = (roofId, canvas) => {
const ridges = [] const ridges = []
eaves.sort((a, b) => a.length - b.length) eaves.sort((a, b) => a.length - b.length)
eaves.forEach((eave) => { eaves.forEach((eave, i) => {
if (ridges.length < ridgeCount) {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
//현재 지붕의 중심 좌표
const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10
const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10
const deltaX = currentWall.x2 - currentWall.x1
const deltaY = currentWall.y2 - currentWall.y1
const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
// currentWall 과 직각인 기울기 계산
const perpendicularDeltaX = deltaY / length
const perpendicularDeltaY = -deltaX / length
// midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산
const midWallX = midX + perpendicularDeltaX * length
const midWallY = midY + perpendicularDeltaY * length
const signX = Math.sign(midX - midWallX)
const signY = Math.sign(midY - midWallY)
const checkX = Math.round((midX - signX * checkLength) * 10) / 10
const checkY = Math.round((midY - signY * checkLength) * 10) / 10
const intersectLines = []
// 현재 지붕의 맞은편 지붕을 찾는다.
roofLines
.filter((line) => line !== currentRoof)
.forEach((line) => {
const intersect = edgesIntersection(
{ vertex1: { x: midX, y: midY }, vertex2: { x: checkX, y: checkY } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (intersect && !intersect.isIntersectionOutside) {
intersectLines.push({ x: intersect.x, y: intersect.y, line: line })
}
})
// 가장 가까운 지붕을 찾는다.
const intersect = intersectLines.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - midX, 2) + Math.pow(prev.y - midY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - midX, 2) + Math.pow(current.y - midY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
const linesCenterX = Math.round(((midX + intersect.x) / 2) * 10) / 10
const linesCenterY = Math.round(((midY + intersect.y) / 2) * 10) / 10
let addLength = currentRoof.attributes.planeSize / 2 / 10
let centerLineX1 = Math.sign(currentRoof.x1 - currentRoof.x2) * addLength + linesCenterX
let centerLineY1 = Math.sign(currentRoof.y1 - currentRoof.y2) * addLength + linesCenterY
let centerLineX2 = Math.sign(currentRoof.x2 - currentRoof.x1) * addLength + linesCenterX
let centerLineY2 = Math.sign(currentRoof.y2 - currentRoof.y1) * addLength + linesCenterY
const point1Intersect = []
const point2Intersect = []
roofLines.forEach((line) => {
const point1 = edgesIntersection(
{ vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX1, y: centerLineY1 } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (point1 && !point1.isIntersectionOutside) {
point1Intersect.push({ x: point1.x, y: point1.y })
}
const point2 = edgesIntersection(
{ vertex1: { x: linesCenterX, y: linesCenterY }, vertex2: { x: centerLineX2, y: centerLineY2 } },
{ vertex1: { x: line.x1, y: line.y1 }, vertex2: { x: line.x2, y: line.y2 } },
)
if (point2 && !point2.isIntersectionOutside) {
point2Intersect.push({ x: point2.x, y: point2.y })
}
})
point1Intersect.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
point2Intersect.reduce((prev, current) => {
if (prev !== undefined) {
const prevDistance = Math.sqrt(Math.pow(prev.x - linesCenterX, 2) + Math.pow(prev.y - linesCenterY, 2))
const currentDistance = Math.sqrt(Math.pow(current.x - linesCenterX, 2) + Math.pow(current.y - linesCenterY, 2))
return prevDistance >= currentDistance ? current : prev
} else {
return current
}
}, undefined)
if (point1Intersect.length > 0) {
centerLineX1 = point1Intersect[0].x
centerLineY1 = point1Intersect[0].y
}
if (point2Intersect.length > 0) {
centerLineX2 = point2Intersect[0].x
centerLineY2 = point2Intersect[0].y
}
const ridge = new QLine([centerLineX1, centerLineY1, centerLineX2, centerLineY2], {
fontSize: roof.fontSize,
stroke: '#1083E3',
strokeWidth: 2,
name: LINE_TYPE.SUBLINE.RIDGE,
attributes: { roofId: roof.id, currentRoof: currentRoof.id },
})
canvas.add(ridge)
canvas.renderAll()
ridges.push(ridge)
roof.innerLines.push(ridge)
}
})
eaves.forEach((eave) => {
const index = eave.index, const index = eave.index,
currentRoof = eave.roof currentRoof = eave.roof
const currentWall = wallLines[index] const currentWall = wallLines[index]
const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1]
const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1]
const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10 const oppositeLine = roofLines
const midY = Math.round(((currentRoof.y1 + currentRoof.y2) / 2) * 10) / 10 .filter((line) => line !== currentRoof) // 현재 벽라인을 제외한 나머지 벽라인
const deltaX = currentWall.x2 - currentWall.x1 .filter((line) => {
const deltaY = currentWall.y2 - currentWall.y1 if (currentRoof.x1 === currentRoof.x2) {
const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY) const vector = Math.sign(currentRoof.y1 - currentRoof.y2)
// currentWall 과 직각인 기울기 계산 const vector2 = Math.sign(currentRoof.x1 - currentWall.x1)
const perpendicularDeltaX = deltaY / length return line.x1 === line.x2 && Math.sign(line.y1 - line.y2) === -vector && Math.sign(currentRoof.x1 - line.x1) === vector2
const perpendicularDeltaY = -deltaX / length }
// midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산 if (currentRoof.y1 === currentRoof.y2) {
const midWallX = midX + perpendicularDeltaX * length const vector = Math.sign(currentRoof.x1 - currentRoof.x2)
const midWallY = midY + perpendicularDeltaY * length const vector2 = Math.sign(currentRoof.y1 - currentWall.y1)
const signX = Math.sign(midX - midWallX) return line.y1 === line.y2 && Math.sign(line.x1 - line.x2) === -vector && Math.sign(currentRoof.y1 - line.y1) === vector2
const signY = Math.sign(midY - midWallY) }
}) // 현재 벽라인과 직교하는 벽라인
console.log('oppositeLine', oppositeLine)
// 현재 벽라인과 직교하는 벽라인 사이에 마루를 그린다.
oppositeLine.forEach((line) => {
let points // 마루의 시작점과 끝점
if (currentRoof.x1 === currentRoof.x2) {
const currentRoofYRange = [Math.min(currentRoof.y1, currentRoof.y2), Math.max(currentRoof.y1, currentRoof.y2)]
const lineYRange = [Math.min(line.y1, line.y2), Math.max(line.y1, line.y2)]
const overlapYRange = [Math.max(currentRoofYRange[0], lineYRange[0]), Math.min(currentRoofYRange[1], lineYRange[1])]
if (overlapYRange[1] - overlapYRange[0] > 0) {
const centerX = Math.round(((currentRoof.x1 + line.x1) / 2) * 10) / 10
points = [centerX, overlapYRange[0], centerX, overlapYRange[1]]
}
}
if (currentRoof.y1 === currentRoof.y2) {
const currentRoofXRange = [Math.min(currentRoof.x1, currentRoof.x2), Math.max(currentRoof.x1, currentRoof.x2)]
const lineXRange = [Math.min(line.x1, line.x2), Math.max(line.x1, line.x2)]
const overlapXRange = [Math.max(currentRoofXRange[0], lineXRange[0]), Math.min(currentRoofXRange[1], lineXRange[1])]
if (overlapXRange[1] - overlapXRange[0] > 0) {
const centerY = Math.round(((currentRoof.y1 + line.y1) / 2) * 10) / 10
points = [overlapXRange[0], centerY, overlapXRange[1], centerY]
}
}
// 마루를 그린다.
if (points) {
const ridge = new QLine(points, {
fontSize: roof.fontSize,
stroke: '#1083E3',
strokeWidth: 1,
name: LINE_TYPE.SUBLINE.RIDGE,
attributes: { roofId: roof.id, currentRoof: [currentRoof.id] },
visible: false,
})
const duplicateRidge = ridges.find(
(ridge) => ridge.x1 === points[0] && ridge.y1 === points[1] && ridge.x2 === points[2] && ridge.y2 === points[3],
)
// 중복된 마루는 제외한다.
if (duplicateRidge) {
duplicateRidge.attributes.currentRoof.push(currentRoof.id)
} else {
canvas.add(ridge)
canvas.renderAll()
ridges.push(ridge)
}
}
})
})
// 처마마다 지붕 polygon 을 그린다.
eaves.forEach((eave, i) => {
const index = eave.index,
currentRoof = eave.roof
const currentWall = wallLines[index]
const currentRidges = ridges.filter((ridge) => ridge.attributes.currentRoof.includes(eave.roof.id))
let points = [] let points = []
const intersectRidge = [] const signX = Math.sign(currentRoof.x1 - currentRoof.x2)
// 현재 roof 가 wall 보다 작을때 이전, 다음 지붕의 offset 만큼 포인트를 조정한다. let currentX1 = currentRoof.x1,
if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) { currentY1 = currentRoof.y1,
points.push({ x: currentRoof.x1, y: currentRoof.y1 }, { x: currentRoof.x2, y: currentRoof.y2 }) currentX2 = currentRoof.x2,
} else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) { currentY2 = currentRoof.y2
const deltaX = currentRoof.x2 - currentRoof.x1 let changeX1 = [Math.min(currentRoof.x1, currentRoof.x2), Math.min(currentRoof.x1, currentRoof.x2)],
const deltaY = currentRoof.y2 - currentRoof.y1 changeY1 = [Math.min(currentRoof.y1, currentRoof.y2), Math.min(currentRoof.y1, currentRoof.y2)],
let x1 = currentRoof.x1, changeX2 = [Math.max(currentRoof.x2, currentRoof.x1), Math.max(currentRoof.x2, currentRoof.x1)],
y1 = currentRoof.y1, changeY2 = [Math.max(currentRoof.y2, currentRoof.y1), Math.max(currentRoof.y2, currentRoof.y1)]
x2 = currentRoof.x2,
y2 = currentRoof.y2
if (deltaX !== 0) { if (signX === 0) {
const minX = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2) currentY1 = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
const maxX = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2) changeY1[1] = currentY1
if (x1 > x2) { currentY2 = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
x1 = maxX changeY2[1] = currentY2
x2 = minX
} else {
x1 = minX
x2 = maxX
}
}
if (deltaY !== 0) {
const minY = Math.min(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
const maxY = Math.max(currentRoof.y1, currentRoof.y2, currentWall.y1, currentWall.y2)
if (y1 > y2) {
y1 = maxY
y2 = minY
} else {
y1 = minY
y2 = maxY
}
}
points.push({ x: x1, y: y1 }, { x: x2, y: y2 })
} else { } else {
const deltaX = currentRoof.x2 - currentRoof.x1 currentX1 = Math.min(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
const deltaY = currentRoof.y2 - currentRoof.y1 changeX1[1] = currentX1
points.push( currentX2 = Math.max(currentRoof.x1, currentRoof.x2, currentWall.x1, currentWall.x2)
{ x: currentRoof.x1 - Math.sign(deltaX) * prevRoof.attributes.offset, y: currentRoof.y1 - Math.sign(deltaY) * prevRoof.attributes.offset }, changeX2[1] = currentX2
{ x: currentRoof.x2 + Math.sign(deltaX) * nextRoof.attributes.offset, y: currentRoof.y2 + Math.sign(deltaY) * nextRoof.attributes.offset },
)
} }
ridges.forEach((ridge) => { points.push({ x: currentX1, y: currentY1 }, { x: currentX2, y: currentY2 })
const ridgeMidX = (ridge.x1 + ridge.x2) / 2
const ridgeMidY = (ridge.y1 + ridge.y2) / 2
if (midX === ridgeMidX || midY === ridgeMidY) {
const intersection = edgesIntersection(
{ vertex1: { x: midX, y: midY }, vertex2: { x: ridgeMidX, y: ridgeMidY } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
if (intersection && !intersection.isIntersectionOutside) {
intersectRidge.push({ line: ridge })
}
}
if (Math.sign(midX - ridgeMidX) === signX || Math.sign(midY - ridgeMidY) === signY) {
const prevIntersect = edgesIntersection(
{ vertex1: { x: prevRoof.x1, y: prevRoof.y1 }, vertex2: { x: prevRoof.x2, y: prevRoof.y2 } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
const nextIntersect = edgesIntersection(
{ vertex1: { x: nextRoof.x1, y: nextRoof.y1 }, vertex2: { x: nextRoof.x2, y: nextRoof.y2 } },
{ vertex1: { x: ridge.x1, y: ridge.y1 }, vertex2: { x: ridge.x2, y: ridge.y2 } },
)
if (prevIntersect && !prevIntersect.isIntersectionOutside) {
intersectRidge.push({ line: ridge })
}
if (nextIntersect && !nextIntersect.isIntersectionOutside) {
intersectRidge.push({ line: ridge })
}
}
})
intersectRidge.forEach((intersect) => { currentRidges.forEach((ridge) => {
const line = intersect.line let ridgeX1 = ridge.x1,
if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) { ridgeY1 = ridge.y1,
points.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }) ridgeX2 = ridge.x2,
} else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) { ridgeY2 = ridge.y2
const deltaX = currentRoof.x2 - currentRoof.x1 if (signX === 0) {
const deltaY = currentRoof.y2 - currentRoof.y1 ridgeY1 = Math.min(ridge.y1, ridge.y2)
let x1 = line.x1, ridgeY2 = Math.max(ridge.y1, ridge.y2)
y1 = line.y1,
x2 = line.x2,
y2 = line.y2
if (deltaX !== 0) {
const minX = Math.min(currentWall.x1, currentWall.x2, currentRoof.x1, currentRoof.x2, line.x1, line.x2)
const maxX = Math.max(currentWall.x1, currentWall.x2, currentRoof.x1, currentRoof.x2, line.x1, line.x2)
if (x1 > x2) {
x1 = maxX
x2 = minX
} else {
x1 = minX
x2 = maxX
}
}
if (deltaY !== 0) {
const minY = Math.min(currentWall.y1, currentWall.y2, currentRoof.y1, currentRoof.y2, line.y1, line.y2)
const maxY = Math.max(currentWall.y1, currentWall.y2, currentRoof.y1, currentRoof.y2, line.y1, line.y2)
if (y1 > y2) {
y1 = maxY
y2 = minY
} else {
y1 = minY
y2 = maxY
}
}
points.push({ x: x1, y: y1 }, { x: x2, y: y2 })
} else { } else {
let lineX1 = line.x1, ridgeX1 = Math.min(ridge.x1, ridge.x2)
lineY1 = line.y1, ridgeX2 = Math.max(ridge.x1, ridge.x2)
lineX2 = line.x2,
lineY2 = line.y2
const prevCheck1 = Math.sqrt(Math.pow(Math.round(lineX1 - currentRoof.x1), 2) + Math.pow(Math.round(lineY1 - currentRoof.y1), 2))
const prevCheck2 = Math.sqrt(Math.pow(Math.round(lineX2 - currentRoof.x1), 2) + Math.pow(Math.round(lineY2 - currentRoof.y1), 2))
const deltaX = currentRoof.x2 - currentRoof.x1
const deltaY = currentRoof.y2 - currentRoof.y1
if (prevCheck1 < prevCheck2) {
lineX1 = lineX1 - Math.sign(deltaX) * prevRoof.attributes.offset
lineY1 = lineY1 - Math.sign(deltaY) * prevRoof.attributes.offset
lineX2 = lineX2 + Math.sign(deltaX) * nextRoof.attributes.offset
lineY2 = lineY2 + Math.sign(deltaY) * nextRoof.attributes.offset
} else {
lineX1 = lineX1 + Math.sign(deltaX) * prevRoof.attributes.offset
lineY1 = lineY1 + Math.sign(deltaY) * prevRoof.attributes.offset
lineX2 = lineX2 - Math.sign(deltaX) * nextRoof.attributes.offset
lineY2 = lineY2 - Math.sign(deltaY) * nextRoof.attributes.offset
}
points.push({ x: lineX1, y: lineY1 }, { x: lineX2, y: lineY2 })
} }
points.push({ x: ridgeX1, y: ridgeY1 }, { x: ridgeX2, y: ridgeY2 })
// canvas.remove(ridge)
// canvas.renderAll()
}) })
points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
points.forEach((point) => {
if (point.x === changeX1[0] && changeX1[0] !== changeX1[1]) {
point.x = changeX1[1]
}
if (point.x === changeX2[0] && changeX2[0] !== changeX2[1]) {
point.x = changeX2[1]
}
if (point.y === changeY1[0] && changeY1[0] !== changeY1[1]) {
point.y = changeY1[1]
}
if (point.y === changeY2[0] && changeY2[0] !== changeY2[1]) {
point.y = changeY2[1]
}
})
//중복된 point 제거
points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y))
//point 정렬 (가장 좌측, 최상단의 점을 기준으로 삼는다.)
const startPoint = points const startPoint = points
.filter((point) => point.x === Math.min(...points.map((point) => point.x))) .filter((point) => point.x === Math.min(...points.map((point) => point.x)))
.reduce((prev, current) => { .reduce((prev, current) => {
return prev.y < current.y ? prev : current return prev.y < current.y ? prev : current
}) })
const sortedPoints = [startPoint]
const sortedPoints = []
sortedPoints.push(startPoint)
points.forEach((p, index) => { points.forEach((p, index) => {
const lastPoint = sortedPoints[sortedPoints.length - 1]
console.log('lastPoint', lastPoint)
if (index === 0) { if (index === 0) {
//시작점 다음 점 찾기, y좌표가 startPoint.y 보다 큰 점 중 x좌표가 가까운 점
const underStartPoint = points.filter((point) => point.y > startPoint.y) const underStartPoint = points.filter((point) => point.y > startPoint.y)
const nextPoint = underStartPoint const nextPoint = underStartPoint
.filter((point) => point.x === startPoint.x) .filter((point) => point.x === startPoint.x)
@ -630,6 +486,8 @@ export const drawGabledRoof = (roofId, canvas) => {
sortedPoints.push(nextPoint) sortedPoints.push(nextPoint)
} }
} else { } else {
const lastPoint = sortedPoints[sortedPoints.length - 1]
console.log('lastPoint', lastPoint)
const prevPoint = sortedPoints[sortedPoints.length - 2] const prevPoint = sortedPoints[sortedPoints.length - 2]
const otherPoints = points.filter((point) => sortedPoints.includes(point) === false) const otherPoints = points.filter((point) => sortedPoints.includes(point) === false)
const nextPoint = otherPoints.reduce((prev, current) => { const nextPoint = otherPoints.reduce((prev, current) => {
@ -656,18 +514,14 @@ export const drawGabledRoof = (roofId, canvas) => {
const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2)))) const height = Math.abs(Math.sqrt(Math.abs(Math.pow(prevPoint.x - lastPoint.x, 2)) + Math.abs(Math.pow(prevPoint.y - lastPoint.y, 2))))
const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2)))) const adjacentC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - lastPoint.x, 2)) + Math.abs(Math.pow(current.y - lastPoint.y, 2))))
const hypotenuseC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2)))) const hypotenuseC = Math.abs(Math.sqrt(Math.abs(Math.pow(current.x - prevPoint.x, 2)) + Math.abs(Math.pow(current.y - prevPoint.y, 2))))
const angleC = Math.round( const angleC = Math.round(
Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI), Math.acos((Math.pow(adjacentC, 2) + Math.pow(height, 2) - Math.pow(hypotenuseC, 2)) / (2 * adjacentC * height)) * (180 / Math.PI),
) )
const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2)))) const adjacentP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - lastPoint.x, 2)) + Math.abs(Math.pow(prev.y - lastPoint.y, 2))))
const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2)))) const hypotenuseP = Math.abs(Math.sqrt(Math.abs(Math.pow(prev.x - prevPoint.x, 2)) + Math.abs(Math.pow(prev.y - prevPoint.y, 2))))
const angleP = Math.round( const angleP = Math.round(
Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI), Math.acos((Math.pow(adjacentP, 2) + Math.pow(height, 2) - Math.pow(hypotenuseP, 2)) / (2 * adjacentP * height)) * (180 / Math.PI),
) )
if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) { if (Math.abs(90 - angleC) < Math.abs(90 - angleP)) {
return current return current
} else { } else {
@ -683,10 +537,11 @@ export const drawGabledRoof = (roofId, canvas) => {
} }
} }
}) })
if (sortedPoints.length > 0) { if (sortedPoints.length > 0) {
const roofPolygon = new QPolygon(sortedPoints, { const roofPolygon = new QPolygon(sortedPoints, {
fill: 'transparent', fill: 'transparent',
stroke: 'blue', stroke: '#1083E3',
strokeWidth: 2, strokeWidth: 2,
selectable: false, selectable: false,
fontSize: roof.fontSize, fontSize: roof.fontSize,
@ -717,6 +572,10 @@ export const drawGabledRoof = (roofId, canvas) => {
canvas.renderAll() canvas.renderAll()
} }
}) })
if (ridges.length > 0) {
ridges.forEach((ridge) => roof.innerLines.push(ridge))
}
//기준선 제거 //기준선 제거
// ridges.forEach((ridge) => canvas.remove(ridge)) // ridges.forEach((ridge) => canvas.remove(ridge))
} }
@ -1049,7 +908,7 @@ const isInnerLine = (prevLine, currentLine, nextLine, line) => {
* @param line2 * @param line2
* @returns {boolean} * @returns {boolean}
*/ */
const segmentsOverlap = (line1, line2) => { export const segmentsOverlap = (line1, line2) => {
if (line1.y1 === line1.y2 && line2.y1 === line2.y2 && line1.y1 === line2.y1) { if (line1.y1 === line1.y2 && line2.y1 === line2.y2 && line1.y1 === line2.y1) {
if ((line1.x1 <= line2.x1 && line1.x2 >= line2.x1) || (line1.x1 <= line2.x2 && line1.x2 >= line2.x2)) { if ((line1.x1 <= line2.x1 && line1.x2 >= line2.x1) || (line1.x1 <= line2.x2 && line1.x2 >= line2.x2)) {
return true return true