Merge branch 'dev' into dev-yj

# Conflicts:
#	src/components/floor-plan/CanvasMenu.jsx
#	src/hooks/useContextMenu.js
This commit is contained in:
yjnoh 2024-10-30 11:20:54 +09:00
commit 50cc0f9687
58 changed files with 1664 additions and 919 deletions

View File

@ -0,0 +1,6 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="elements">
<path id="Vector" d="M6.73735 6.73726L11.2628 11.2627M11.2628 6.73726L6.73735 11.2627" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Ellipse 1334" d="M17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17C13.4183 17 17 13.4183 17 9Z" stroke="white"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 431 B

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 9.5L7.5 12L13 6" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17C13.4183 17 17 13.4183 17 9Z" stroke="white"/>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@ -0,0 +1,4 @@
<svg width="18" height="18" viewBox="0 0 18 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.00078 5.7998V12.1998M12.2008 8.9998L5.80078 8.9998" stroke="#141B34" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17 9C17 4.58172 13.4183 1 9 1C4.58172 1 1 4.58172 1 9C1 13.4183 4.58172 17 9 17C13.4183 17 17 13.4183 17 9Z" stroke="#141B34"/>
</svg>

After

Width:  |  Height:  |  Size: 371 B

View File

@ -1,11 +1,5 @@
<svg width="23" height="24" viewBox="0 0 23 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="ico">
<circle id="Ellipse 2012" cx="11.5" cy="12" r="11.5" fill="#45576F"/>
<g id="elements">
<path id="Vector" d="M9.66678 12.8193C9.7612 12.9739 9.87323 13.1202 10.0029 13.2552C10.8079 14.093 12.0349 14.224 12.9718 13.6481C13.1454 13.5414 13.3091 13.4104 13.4582 13.2552L15.6178 11.0076C16.572 10.0145 16.572 8.40447 15.6178 7.41141C14.6637 6.41836 13.1166 6.41836 12.1625 7.41142L11.6868 7.90648" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<path id="Vector_2" d="M10.313 16.0933L9.83718 16.5885C8.88301 17.5816 7.33598 17.5816 6.3818 16.5885C5.42762 15.5955 5.42762 13.9854 6.3818 12.9924L8.54141 10.7448C9.49559 9.75174 11.0426 9.75174 11.9968 10.7448C12.1264 10.8797 12.2384 11.026 12.3328 11.1806" stroke="white" stroke-width="1.5" stroke-linecap="round"/>
<path id="Vector_3" d="M17.0003 14.6666H15.6143M13.6669 18L13.6669 16.614" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Vector_4" d="M5 9.33333H6.38593M8.33333 6L8.33333 7.38593" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</g>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" fill="white"/>
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" stroke="#0191C9"/>
<path d="M13.186 5.7898C12.6312 5.20223 11.7307 5.20223 11.1759 5.7898L6.99193 10.2206C6.03462 11.2344 6.03462 12.8767 6.99193 13.8905C7.94924 14.9043 9.50003 14.9043 10.4573 13.8905L13.9136 10.2303C14.1615 9.96779 14.5663 9.96779 14.8141 10.2303C15.062 10.4928 15.062 10.9214 14.8141 11.1839L11.3578 14.8441C9.90251 16.3853 7.54676 16.3853 6.09147 14.8441C4.63618 13.303 4.63618 10.8082 6.09147 9.26705L10.2754 4.8362C11.3282 3.72127 13.0337 3.72127 14.0865 4.8362C15.1393 5.95114 15.1393 7.75719 14.0865 8.87212L10.0844 13.1103C9.43409 13.799 8.379 13.799 7.72867 13.1103C7.07834 12.4216 7.07834 11.3043 7.72867 10.6156L11.0031 7.14795C11.2509 6.88547 11.6557 6.88547 11.9035 7.14795C12.1514 7.41042 12.1514 7.83906 11.9035 8.10154L8.62913 11.5692C8.47678 11.7305 8.47678 11.9954 8.62913 12.1567C8.78148 12.3181 9.03161 12.3181 9.18396 12.1567L13.186 7.91853C13.7408 7.33096 13.7408 6.37736 13.186 5.7898Z" fill="#0191C9" stroke="white" stroke-width="0.5"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,7 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" fill="white"/>
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" stroke="#909000"/>
<path d="M4 10C4 13.3137 6.68629 16 10 16C13.3137 16 16 13.3137 16 10C16 6.68629 13.3137 4 10 4" stroke="#909000" stroke-linecap="round"/>
<path d="M5.58914 5.8473C5.67215 5.75932 5.75769 5.67375 5.84566 5.59071M7.5684 4.43768C7.67731 4.38873 7.78788 4.34282 7.9 4.30005M4.3 7.90005C4.34317 7.78681 4.38955 7.67516 4.43904 7.5652" stroke="#909000" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M9.99999 7.59961V12.3996M12.4 9.99961L7.59999 9.99961" stroke="#909000" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 772 B

View File

@ -1,4 +1,5 @@
<svg width="15" height="16" viewBox="0 0 15 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="7" cy="7.5" r="6.5" fill="white" stroke="#F16A6A"/>
<path d="M6.507 9.228L6.276 5.169L6.221 3.629H7.849L7.794 5.169L7.563 9.228H6.507ZM7.035 12.154C6.74167 12.154 6.49967 12.0513 6.309 11.846C6.12567 11.6407 6.034 11.3913 6.034 11.098C6.034 10.79 6.12567 10.537 6.309 10.339C6.49967 10.141 6.74167 10.042 7.035 10.042C7.32833 10.042 7.56667 10.141 7.75 10.339C7.94067 10.537 8.036 10.79 8.036 11.098C8.036 11.3913 7.94067 11.6407 7.75 11.846C7.56667 12.0513 7.32833 12.154 7.035 12.154Z" fill="#F16A6A"/>
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" fill="white"/>
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" stroke="#F16A6A"/>
<path d="M9.47136 11.228L9.24036 7.169L9.18536 5.629H10.8134L10.7584 7.169L10.5274 11.228H9.47136ZM9.99936 14.154C9.70602 14.154 9.46402 14.0513 9.27336 13.846C9.09002 13.6407 8.99836 13.3913 8.99836 13.098C8.99836 12.79 9.09002 12.537 9.27336 12.339C9.46402 12.141 9.70602 12.042 9.99936 12.042C10.2927 12.042 10.531 12.141 10.7144 12.339C10.905 12.537 11.0004 12.79 11.0004 13.098C11.0004 13.3913 10.905 13.6407 10.7144 13.846C10.531 14.0513 10.2927 14.154 9.99936 14.154Z" fill="#F16A6A"/>
</svg>

Before

Width:  |  Height:  |  Size: 620 B

After

Width:  |  Height:  |  Size: 738 B

View File

@ -0,0 +1,6 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" fill="white"/>
<rect x="0.5" y="0.5" width="19" height="19" rx="9.5" stroke="#3BBB48"/>
<path d="M11.3571 4.95962C10.7174 4.31987 10.3975 4 10 4C9.60251 4 9.28264 4.31987 8.64289 4.95962C8.25899 5.34352 7.87857 5.52175 7.33125 5.52175C6.85336 5.52175 6.17346 5.42907 5.8 5.80567C5.4295 6.17929 5.52177 6.85639 5.52177 7.33123C5.52177 7.87857 5.34352 8.25899 4.95961 8.6429C4.31987 9.28264 4.00001 9.60251 4 9.99999C4.00001 10.3975 4.31988 10.7174 4.95963 11.3571C5.38969 11.7872 5.52177 12.0649 5.52177 12.6687C5.52177 13.1466 5.42908 13.8265 5.80569 14.2C6.17931 14.5705 6.85641 14.4782 7.33124 14.4782C7.91409 14.4782 8.19477 14.5922 8.61074 15.0082C8.96495 15.3624 9.43978 16 10 16C10.5602 16 11.0351 15.3624 11.3893 15.0082C11.8052 14.5922 12.0859 14.4782 12.6688 14.4782C13.1436 14.4782 13.8207 14.5705 14.1943 14.2M15.0404 8.6429C15.6801 9.28264 16 9.60251 16 9.99999C16 10.3975 15.6801 10.7174 15.0404 11.3571C14.6103 11.7871 14.4782 12.0649 14.4782 12.6687C14.4782 13.1466 14.5709 13.8265 14.1943 14.2M14.1943 14.2H14.2" stroke="#3BBB48" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7.9 8.49998L10 10.6L15.4002 4.59998" stroke="#3BBB48" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,9 +0,0 @@
import Estimate from '@/components/estimate/Estimate'
export default function EstimatePage() {
return (
<>
<Estimate />
</>
)
}

View File

@ -0,0 +1,12 @@
import Estimate from '@/components/estimate/Estimate'
export default function EstimatePage({ params }) {
//floor-plan/estimate/mid/pid
//mid :5
//pid :
return (
<>
<Estimate params={params} />
</>
)
}

View File

@ -46,6 +46,7 @@ export default async function RootLayout({ children }) {
storeLvl: session.storeLvl,
groupId: session.groupId,
pwdInitYn: session.pwdInitYn,
custCd: session.custCd,
isLoggedIn: session.isLoggedIn,
}
}

View File

@ -1,3 +1,5 @@
import { fabric } from 'fabric'
export const MENU = {
PLAN_DRAWING: 'planDrawing',
INITIAL_CANVAS_SETTING: 'initialCanvasSetting', // 배치면 초기설정
@ -116,3 +118,41 @@ export const POLYGON_TYPE = {
ROOF: 'roof',
TRESTLE: 'trestle',
}
export const SAVE_KEY = [
'selectable',
'name',
'parentId',
'id',
'length',
'idx',
'direction',
'parentDirection',
'lines',
'points',
'lockMovementX',
'lockMovementY',
'lockRotation',
'lockScalingX',
'lockScalingY',
'opacity',
'cells',
'maxX',
'maxY',
'minX',
'minY',
'x',
'y',
'x1',
'x2',
'y1',
'y2',
'attributes',
'stickeyPoint',
'text',
'pitch',
'uuid',
'originText',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]

View File

@ -98,6 +98,7 @@ export default function Login() {
pwdInitYn: 'Y',
storeLvl: '1',
groupId: '60000',
custCd: '100000',
})
setSessionState({
userId: 'NEW016610',
@ -115,6 +116,7 @@ export default function Login() {
pwdInitYn: 'Y',
storeLvl: '1',
groupId: '60000',
custCd: '100000',
})
if (chkLoginId) {
Cookies.set('chkLoginId', formData.get('id'), { expires: 7 })

View File

@ -1,14 +1,59 @@
'use client'
import { useEffect, useState } from 'react'
import { useEffect, useState, useRef } from 'react'
import { useMessage } from '@/hooks/useMessage'
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import { useRecoilValue } from 'recoil'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { Button } from '@nextui-org/react'
import { sessionStore } from '@/store/commonAtom'
export default function Estimate() {
export default function Estimate({ params }) {
const sessionState = useRecoilValue(sessionStore)
const { getMessage } = useMessage()
const objectRecoil = useRecoilValue(floorPlanObjectState)
console.log('견적서화면이군요', objectRecoil.floorPlanObjectNo)
const [objectNo, setObjectNo] = useState('')
const fileInputRef = useRef(null)
const [files, setFiles] = useState([]) //
const fileId = useRef(0)
useEffect(() => {
setObjectNo(objectRecoil.floorPlanObjectNo)
}, [objectRecoil])
useEffect(() => {
if (objectNo) {
//Q101X278191023001
console.log('세션정보::::', sessionState)
//API
}
}, [objectNo])
const handleButtonClick = () => {
fileInputRef.current.click()
}
const onChangeFiles = (e) => {
// e.preventDefault()
// e.persist()
// console.log('::', e.target.files[0])
// console.log('::', e.target.files)
// let selectFiles = []
// let tempFiles = files
// selectFiles = e.target.files
// for (const file of selectFiles) {
// tempFiles = [
// ...tempFiles,
// {
// id: fileId.current++,
// object: file,
// },
// ]
// }
// setFiles(tempFiles)
// const formData = new FormData()
// formData.append('file', e.target.files[0])
}
return (
<div className="sub-content estimate">
<div className="sub-content-inner">
@ -18,7 +63,9 @@ export default function Estimate() {
<div className="estimate-list-wrap one">
<div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
<div className="estimate-name">RX524231020006 (Plan No: 1)</div>
<div className="estimate-name">
{objectNo} (Plan No: {params.pid})
</div>
</div>
<div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.estimateNo')}</div>
@ -105,7 +152,7 @@ export default function Estimate() {
<tr>
{/* 주문분류 */}
<th>
注文分類/주문분류 <span className="important">*</span>
{getMessage('estimate.detail.orderType')} <span className="important">*</span>
</th>
<td colSpan={3}>
<div className="radio-wrap"></div>
@ -113,7 +160,7 @@ export default function Estimate() {
</tr>
<tr>
{/* 지붕재・사양시공 최대4개*/}
<th>屋根材仕様施工 / 지붕재사양시공</th>
<th>{getMessage('estimate.detail.roofCns')}</th>
<td colSpan={3}>
<div className="form-flex-wrap mb5">
<div className="input-wrap mr5" style={{ width: '610px' }}>
@ -131,7 +178,7 @@ export default function Estimate() {
</tr>
<tr>
{/* 비고 */}
<th>備考 /비고</th>
<th>{getMessage('estimate.detail.note')}</th>
<td colSpan={3}>
<div className="input-wrap">
<input type="text" className="input-light" />
@ -146,9 +193,9 @@ export default function Estimate() {
<div className="title-wrap">
<h3>{getMessage('estimate.detail.header.fileList1')}</h3>
<div className="d-check-box light mr5">
<input type="checkbox" id="" />
<label htmlFor="" style={{ color: '#101010' }}>
後日資料提出 / 후일자료제출
<input type="checkbox" id="next" />
<label htmlFor="next" style={{ color: '#101010' }}>
{getMessage('estimate.detail.nextSubmit')}
</label>
</div>
</div>
@ -165,7 +212,17 @@ export default function Estimate() {
<td>
<div className="drag-file-box">
<div className="btn-area">
<button className="btn-origin grey">{getMessage('estimate.detail.fileList.btn')}</button>
<Button type="button" className="btn-origin grey" onClick={handleButtonClick}>
{getMessage('estimate.detail.fileList.btn')}
</Button>
<input
type="file"
id="fileUpload"
name="fileUpload"
ref={fileInputRef}
onChange={onChangeFiles}
style={{ display: 'none' }}
/>
</div>
<div className="drag-file-area">
<p>Drag file here</p>
@ -216,23 +273,23 @@ export default function Estimate() {
<div className="estimate-wrap">
<div className="estimate-list-wrap one">
<div className="estimate-box">
<div className="estimate-tit">수량 (PCS)</div>
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPcs')}</div>
<div className="estimate-name blue">74</div>
</div>
<div className="estimate-box">
<div className="estimate-tit">용량 (Kw)</div>
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.vol')}</div>
<div className="estimate-name blue">8300</div>
</div>
<div className="estimate-box">
<div className="estimate-tit">공급가액</div>
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.netAmt')}</div>
<div className="estimate-name blue">6,798,900</div>
</div>
<div className="estimate-box">
<div className="estimate-tit">부가세 (10)</div>
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.vat')}</div>
<div className="estimate-name blue">679,890</div>
</div>
<div className="estimate-box">
<div className="estimate-tit">총액</div>
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPrice')}</div>
<div className="estimate-name red">7,478,790</div>
</div>
</div>
@ -260,9 +317,9 @@ export default function Estimate() {
</div>
</td>
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgWeight')}</th>
<td>(모듈수량 * 수량) / 100)</td>
<td>{getMessage('estimate.detail.sepcialEstimateProductInfo.calcFormula1')}</td>
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgPrice')}</th>
<td>PKG단가(W) * PKG용량(W)</td>
<td>{getMessage('estimate.detail.sepcialEstimateProductInfo.calcFormula2')}</td>
</tr>
</tbody>
</table>

View File

@ -21,9 +21,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
}
this.line = this
// 소수점 전부 제거
points.forEach((point) => {
point = Math.round(point)
})
points = points.map((point) => Math.round(point))
this.idx = options.idx ?? 0
this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
@ -41,12 +39,6 @@ export const QLine = fabric.util.createClass(fabric.Line, {
}
},
toObject: function (propertiesToInclude) {
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
type: this.type,
text: this.text,
})
},
init: function () {
this.addLengthText()

View File

@ -24,8 +24,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
initialize: function (points, options, canvas) {
// 소수점 전부 제거
points.forEach((point) => {
point.x = Math.round(point.x)
point.y = Math.round(point.y)
point.x = Number(point.x.toFixed(1))
point.y = Number(point.y.toFixed(1))
})
options.selectable = options.selectable ?? true
options.sort = options.sort ?? true
@ -101,17 +101,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.shape = shape
},
toObject: function (propertiesToInclude) {
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), {
id: this.id,
type: this.type,
text: this.text,
hips: this.hips,
ridges: this.ridges,
connectRidges: this.connectRidges,
})
},
init: function () {
this.addLengthText()

View File

@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { usePathname, useRouter } from 'next/navigation'
import MenuDepth01 from './MenuDepth01'
import QSelectBox from '@/components/common/select/QSelectBox'
import { v4 as uuidv4 } from 'uuid'
@ -11,52 +12,53 @@ import { useMessage } from '@/hooks/useMessage'
import { usePlan } from '@/hooks/usePlan'
import { useSwal } from '@/hooks/useSwal'
import { useEvent } from '@/hooks/useEvent'
import { canvasState, canvasZoomState, currentCanvasPlanState, currentMenuState, verticalHorizontalModeState } from '@/store/canvasAtom'
import {
canvasSettingState,
canvasState,
canvasZoomState,
currentCanvasPlanState,
currentMenuState,
verticalHorizontalModeState,
} from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
import { settingModalFirstOptionsState, wordDisplaySelector } from '@/store/settingAtom'
import { MENU } from '@/common/common'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { popupState } from '@/store/popupAtom'
import SettingModal01 from '@/components/floor-plan/modal/setting01/SettingModal01'
import { usePopup } from '@/hooks/usePopup'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import PlacementShapeSetting from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { useCommonUtils } from '@/hooks/common/useCommonUtils'
import { commonUtilsState } from '@/store/commonUtilsAtom'
const canvasMenus = [
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
{ index: 1, name: 'plan.menu.placement.surface.initial.setting', icon: 'con01', title: MENU.INITIAL_CANVAS_SETTING },
{ index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT },
{ index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT },
{ index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT },
{ index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT },
{ index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT },
]
import { commonUtilsState } from '@/store/commonUtilsAtom'
import { menusState, menuTypeState } from '@/store/menuAtom'
import useMenu from '@/hooks/common/useMenu'
import { MENU } from '@/common/common'
export default function CanvasMenu(props) {
const { menuNumber, setMenuNumber } = props
const { addPopup, closePopup } = usePopup()
const [type, setType] = useState('')
const pathname = usePathname()
const router = useRouter()
const { addPopup } = usePopup()
const canvasMenus = useRecoilValue(menusState)
const [type, setType] = useRecoilState(menuTypeState)
const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState)
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore)
const setCurrentMenu = useSetRecoilState(currentMenuState)
const setOuterLinePoints = useSetRecoilState(outerLinePointsState)
const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState)
const canvasSetting = useRecoilValue(canvasSettingState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const { handleZoomClear } = useCanvasEvent()
const sessionState = useRecoilValue(sessionStore)
const globalLocale = useRecoilValue(globalLocaleStore)
const canvas = useRecoilValue(canvasState)
const sessionState = useRecoilValue(sessionStore)
const { handleZoomClear } = useCanvasEvent()
const { handleMenu } = useMenu()
const { getMessage } = useMessage()
const { saveCanvas } = usePlan()
@ -64,9 +66,6 @@ export default function CanvasMenu(props) {
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
const commonUtils = useRecoilValue(commonUtilsState)
const { commonFunctions } = useCommonUtils()
const [popup, setPopup] = useRecoilState(popupState)
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
const onClickNav = (menu) => {
@ -88,9 +87,8 @@ export default function CanvasMenu(props) {
setType('module')
break
}
}
const menuProps = {
type,
if (pathname !== '/floor-plan') router.push('/floor-plan')
}
const settingsModalOptions = useRecoilState(settingModalFirstOptionsState)
@ -122,7 +120,6 @@ export default function CanvasMenu(props) {
}
const onClickPlacementInitialMenu = () => {
addPopup(placementInitialId, 1, <PlacementShapeSetting {...placementInitialProps} />)
// setShowPlaceShapeModal(true)
}
const handleClear = () => {
@ -149,7 +146,19 @@ export default function CanvasMenu(props) {
} else {
setAppMessageState(JA)
}
}, [menuNumber, type, globalLocale])
}, [type, globalLocale])
useEffect(() => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString())) {
setMenuNumber(3)
setType('surface')
setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
} else {
setMenuNumber(2)
setType('outline')
setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
}
}, [canvasSetting])
return (
<div className={`canvas-menu-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
@ -160,9 +169,12 @@ export default function CanvasMenu(props) {
<li
key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
onClick={() => onClickNav(menu)}
onClick={() => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2) return
onClickNav(menu)
}}
>
<button>
<button className={['2', '3'].includes(canvasSetting?.roofSizeSet?.toString()) && menu.index === 2 ? 'no-click' : ''}>
<span className={`menu-icon ${menu.icon}`}></span>
{getMessage(menu.name)}
</button>
@ -250,7 +262,7 @@ export default function CanvasMenu(props) {
</div>
</div>
<div className={`canvas-depth2-wrap ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
{(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && <MenuDepth01 {...menuProps} />}
{(menuNumber === 2 || menuNumber === 3 || menuNumber === 4) && <MenuDepth01 />}
</div>
</div>
)

View File

@ -2,28 +2,26 @@
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
import CanvasMenu from '@/components/floor-plan/CanvasMenu'
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import '@/styles/contents.scss'
export default function FloorPlan({ children }) {
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get } = useAxios(globalLocaleState)
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
const [objectNo, setObjectNo] = useState('test123240912001') //
// const [menuNumber, setMenuNumber] = useState(null)
const { menuNumber, setMenuNumber } = useCanvasMenu()
const { fetchSettings } = useCanvasSetting()
const modalProps = {
menuNumber,
setMenuNumber,
}
useEffect(() => {
fetchSettings()
}, [objectNo])
@ -32,32 +30,6 @@ export default function FloorPlan({ children }) {
setMenuNumber(1)
}, [])
// Canvas Setting
const fetchSettings = async () => {
try {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({
...item,
}))
//
setSettingModalFirstOptions({
option1: optionData1,
option2: optionData2,
dimensionDisplay: optionData5,
})
setSettingModalSecondOptions({
option3: optionData3,
option4: optionData4,
})
} catch (error) {
console.error('Data fetching error:', error)
}
}
return (
<>
<div className="canvas-wrap">

View File

@ -1,150 +1,32 @@
'use client'
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react'
import { MENU } from '@/common/common'
import { currentMenuState } from '@/store/canvasAtom'
import { useSetRecoilState } from 'recoil'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { usePopup } from '@/hooks/usePopup'
import { v4 as uuidv4 } from 'uuid'
import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting'
import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing'
import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit'
import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting'
import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import Slope from '@/components/floor-plan/modal/Slope'
import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting'
import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing'
import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting'
import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting'
import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting'
import { useRecoilState, useRecoilValue } from 'recoil'
import { menuTypeState, subMenusState } from '@/store/menuAtom'
import useMenu from '@/hooks/common/useMenu'
import { useEffect } from 'react'
export default function MenuDepth01(props) {
const { type } = props
export default function MenuDepth01() {
const type = useRecoilValue(menuTypeState)
const { getMessage } = useMessage()
const [activeMenu, setActiveMenu] = useState()
const setCurrentMenu = useSetRecoilState(currentMenuState)
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch()
const { addPopup } = usePopup()
const [outlineId, setOutlineId] = useState(uuidv4())
const onClickMenu = ({ id, menu, name }) => {
setActiveMenu(menu)
const { handleMenu } = useMenu()
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
const subMenus = useRecoilValue(subMenusState)
const onClickMenu = ({ id, menu }) => {
setCurrentMenu(menu)
if (type === 'outline') {
switch (id) {
case 0:
addPopup(outlineId, 1, <WallLineSetting id={outlineId} />)
break
case 1:
addPopup(outlineId, 1, <RoofShapeSetting id={outlineId} />)
break
case 2:
addPopup(outlineId, 1, <RoofShapePassivitySetting id={outlineId} />)
break
case 3:
addPopup(outlineId, 1, <AuxiliaryDrawing id={outlineId} />)
break
case 4:
addPopup(outlineId, 1, <EavesGableEdit id={outlineId} />)
break
case 5:
addPopup(outlineId, 1, <MovementSetting id={outlineId} />)
break
case 6:
addPopup(outlineId, 1, <WallLineOffsetSetting id={outlineId} />)
break
case 7:
addPopup(outlineId, 1, <RoofAllocationSetting id={outlineId} />)
break
}
}
if (type === 'surface') {
switch (id) {
case 0:
addPopup(outlineId, 1, <Slope id={outlineId} />)
break
case 1:
addPopup(outlineId, 1, <PlacementShapeDrawing id={outlineId} />)
break
case 2:
addPopup(outlineId, 1, <PlacementSurfaceSetting id={outlineId} />)
break
case 3:
addPopup(outlineId, 1, <ObjectSetting id={outlineId} />)
break
case 4:
deleteAllSurfacesAndObjects()
break
}
}
if (type === 'module') {
switch (id) {
case 0:
addPopup(outlineId, 1, <BasicSetting id={outlineId} />)
break
case 1:
addPopup(outlineId, 1, <CircuitTrestleSetting id={outlineId} />)
break
}
}
}
useEffect(() => {
setActiveMenu(null)
}, [type])
const menuInfo = {
outline: [
//
{ id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE },
{ id: 1, name: 'plan.menu.roof.cover.roof.shape.setting', menu: MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS },
{
id: 2,
name: 'plan.menu.roof.cover.roof.shape.passivity.setting',
menu: MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS,
},
{ id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing', menu: MENU.ROOF_COVERING.HELP_LINE_DRAWING },
{ id: 4, name: 'plan.menu.roof.cover.eaves.kerava.edit', menu: MENU.ROOF_COVERING.EAVES_KERAVA_EDIT },
{ id: 5, name: 'plan.menu.roof.cover.movement.shape.updown', menu: MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN },
{ id: 6, name: 'plan.menu.roof.cover.outline.edit.offset', menu: MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET },
{ id: 7, name: 'plan.menu.roof.cover.roof.surface.alloc', menu: MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC },
],
surface: [
//
{ id: 0, name: 'plan.menu.placement.surface.slope.setting', menu: MENU.BATCH_CANVAS.SLOPE_SETTING },
{ id: 1, name: 'plan.menu.placement.surface.drawing', menu: MENU.BATCH_CANVAS.BATCH_DRAWING },
{ id: 2, name: 'plan.menu.placement.surface.arrangement', menu: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH },
{ id: 3, name: 'plan.menu.placement.surface.object', menu: MENU.BATCH_CANVAS.OBJECT_BATCH },
{ id: 4, name: 'plan.menu.placement.surface.all.remove', menu: MENU.BATCH_CANVAS.ALL_REMOVE },
],
module: [
// ,
{ id: 0, name: 'plan.menu.module.circuit.setting.default', menu: MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING },
{
id: 1,
name: 'plan.menu.module.circuit.setting.circuit.trestle.setting',
menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING,
},
{
id: 2,
name: 'plan.menu.module.circuit.setting.plan.orientation',
menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION,
},
],
}
handleMenu(type)
}, [currentMenu])
return (
<div className="canvas-depth2-inner">
<ul className="canvas-depth2-list">
{menuInfo[type].map((menu) => {
{subMenus[type]?.map((menu) => {
return (
<li key={menu.id} className={`canvas-depth2-item ${menu.menu === activeMenu ? 'active' : ''}`}>
<li key={menu.id} className={`canvas-depth2-item ${menu.menu === currentMenu ? 'active' : ''}`}>
<button onClick={() => onClickMenu(menu)}>{getMessage(menu.name)}</button>
</li>
)

View File

@ -1,3 +1,5 @@
'use client'
import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useRecoilValue } from 'recoil'

View File

@ -1,15 +1,17 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom'
import QSelectBox from '@/components/common/select/QSelectBox'
import { pitchTextSelector } from '@/store/canvasAtom'
export default function DimensionLineSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, setIsShow, pos = contextPopupPosition } = props
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const pitchText = useRecoilState(pitchTextSelector)
const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }]
return (
<WithDraggable isShow={true} pos={pos}>
@ -52,14 +54,14 @@ export default function DimensionLineSetting(props) {
<div className="grid-select mr10">
<QSelectBox title={'0'} option={SelectOption01} />
</div>
<span className="thin">寸法</span>
<span className="thin">{pitchText}</span>
</div>
<div className="outline-form">
<span className="mr10">傾斜</span>
<div className="grid-select mr10">
<QSelectBox title={'0'} option={SelectOption01} />
</div>
<span className="thin">寸法</span>
<span className="thin">{pitchText}</span>
</div>
</div>
<div className="warning">傾き設定されている場合入力した数値に傾き計算をした数値が表示されます</div>

View File

@ -71,7 +71,7 @@ export default function DotLineGrid(props) {
//
useEffect(() => {
console.log('DotLineGrid useEffect 실행')
// fetchGridSettings()
fetchGridSettings()
}, [objectNo])
const HandleClickClose = () => {
@ -100,9 +100,9 @@ export default function DotLineGrid(props) {
const patternData = {
INTERVAL: {
type: res.gridType,
horizontalInterval: res.gridHorizon,
verticalInterval: res.gridVertical,
ratioInterval: res.gridRatio,
horizontalInterval: res.gridHorizon * 10,
verticalInterval: res.gridVertical * 10,
ratioInterval: res.gridRatio * 10,
},
dimension: res.gridDimen,
DOT: res.dotGridDisplay,

View File

@ -0,0 +1,42 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState } from 'react'
import { usePopup } from '@/hooks/usePopup'
import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom'
import { useMessage } from '@/hooks/useMessage'
export default function ImageSizeSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition, size, setSize } = props
const [sizeValue, setSizeValue] = useState(100)
const { getMessage } = useMessage()
const { closePopup } = usePopup()
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head">
<h1 className="title">{getMessage('modal.image.size.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="range-wrap">
<input
type="range"
id="size"
name="volume"
min="20"
max="200"
step={10}
value={sizeValue}
onChange={(e) => setSizeValue(e.target.value)}
/>
<label htmlFor="size">{sizeValue}%</label>
</div>
</div>
</div>
</WithDraggable>
)
}

View File

@ -4,15 +4,18 @@ import { useState } from 'react'
import FlowLine from '@/components/floor-plan/modal/movement/type/FlowLine'
import Updown from '@/components/floor-plan/modal/movement/type/Updown'
import { usePopup } from '@/hooks/usePopup'
import { useMovementSetting } from '@/hooks/roofcover/useMovementSetting'
export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const [buttonAct, setButtonAct] = useState(1)
const buttonMenu = [
{ id: 1, name: getMessage('modal.movement.flow.line.move') },
{ id: 2, name: getMessage('modal.movement.flow.line.updown') },
]
const { TYPE, closePopup, buttonType, type, setType, FLOW_LINE_REF, UP_DOWN_REF, handleSave } = useMovementSetting(id)
const flowLineProps = {
FLOW_LINE_REF,
}
const updownProps = {
UP_DOWN_REF,
}
return (
<WithDraggable isShow={true} pos={pos}>
@ -25,19 +28,21 @@ export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
{buttonMenu.map((item) => (
<button key={item.id} className={`btn-frame modal ${buttonAct === item.id ? 'act' : ''}`} onClick={() => setButtonAct(item.id)}>
{buttonType.map((item) => (
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{buttonAct === 1 && <FlowLine />}
{buttonAct === 2 && <Updown />}
{type === TYPE.FLOW_LINE && <FlowLine {...flowLineProps} />}
{type === TYPE.UP_DOWN && <Updown {...updownProps} />}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
</div>

View File

@ -1,7 +1,24 @@
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react'
export default function FlowLine({}) {
const FLOW_LINE_TYPE = {
DOWN_LEFT: 'downLeft',
UP_RIGHT: 'upRight',
}
export default function FlowLine({ FLOW_LINE_REF }) {
const { getMessage } = useMessage()
const [type, setType] = useState(FLOW_LINE_TYPE.DOWN_LEFT)
useEffect(() => {
if (type === FLOW_LINE_TYPE.DOWN_LEFT) {
FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = ''
FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.focus()
} else {
FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = ''
FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.focus()
}
}, [type])
return (
<>
@ -11,14 +28,28 @@ export default function FlowLine({}) {
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra01" />
<input
type="radio"
name="radio01"
id="ra01"
defaultChecked={true}
ref={FLOW_LINE_REF.DOWN_LEFT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.DOWN_LEFT)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.bottom.left')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={100} />
<input
type="text"
className="input-origin block"
readOnly={type !== FLOW_LINE_TYPE.DOWN_LEFT}
ref={FLOW_LINE_REF.DOWN_LEFT_INPUT_REF}
/>
</div>
</div>
</div>
@ -26,14 +57,27 @@ export default function FlowLine({}) {
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra02" />
<input
type="radio"
name="radio01"
id="ra02"
ref={FLOW_LINE_REF.UP_RIGHT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.UP_RIGHT)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.top.right')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={100} />
<input
type="text"
className="input-origin block"
readOnly={type !== FLOW_LINE_TYPE.UP_RIGHT}
ref={FLOW_LINE_REF.UP_RIGHT_INPUT_REF}
/>
</div>
<span className="thin">mm</span>
</div>

View File

@ -1,7 +1,24 @@
import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react'
export default function Updown({}) {
const UP_DOWN_TYPE = {
UP: 'up',
DOWN: 'down',
}
export default function Updown({ UP_DOWN_REF }) {
const { getMessage } = useMessage()
const [type, setType] = useState(UP_DOWN_TYPE.UP)
useEffect(() => {
if (type === UP_DOWN_TYPE.UP) {
UP_DOWN_REF.DOWN_INPUT_REF.current.value = ''
UP_DOWN_REF.UP_INPUT_REF.current.focus()
} else {
UP_DOWN_REF.UP_INPUT_REF.current.value = ''
UP_DOWN_REF.DOWN_INPUT_REF.current.focus()
}
}, [type])
return (
<>
@ -11,14 +28,23 @@ export default function Updown({}) {
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra01" />
<input
type="radio"
name="radio01"
id="ra01"
ref={UP_DOWN_REF.UP_RADIO_REF}
defaultChecked={true}
onChange={() => {
setType(UP_DOWN_TYPE.UP)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.updown.up')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={100} />
<input type="text" className="input-origin block" readOnly={type !== UP_DOWN_TYPE.UP} ref={UP_DOWN_REF.UP_INPUT_REF} />
</div>
</div>
</div>
@ -26,14 +52,22 @@ export default function Updown({}) {
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input type="radio" name="radio01" id="ra02" />
<input
type="radio"
name="radio01"
id="ra02"
ref={UP_DOWN_REF.DOWN_RADIO_REF}
onChange={() => {
setType(UP_DOWN_TYPE.DOWN)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.updown.down')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" defaultValue={100} />
<input type="text" className="input-origin block" readOnly={type !== UP_DOWN_TYPE.DOWN} ref={UP_DOWN_REF.DOWN_INPUT_REF} />
</div>
<span className="thin">mm</span>
</div>

View File

@ -1,6 +1,8 @@
import WithDraggable from '@/components/common/draggable/withDraggable'
'use client'
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/withDraggable'
export default function PanelBatchStatistics() {
const { getMessage } = useMessage()

View File

@ -18,6 +18,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
const { closePopup } = usePopup()
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
const [image, setImage] = useState(null)
const { getMessage } = useMessage()
const { get, post } = useAxios()
@ -479,6 +480,24 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
</div>
</td>
</tr>
<tr>
<th>{getMessage('common.input.file')}</th>
<td>
<div className="flex-box">
<div className="img-edit-wrap">
<label className="img-edit-btn" htmlFor="img_file">
<span className="img-edit"></span>
{getMessage('common.input.file.load')}
</label>
<input type="file" id="img_file" style={{ display: 'none' }} onChange={(e) => setImage(e.target.files[0])} />
</div>
<div className="img-name-wrap">
<input type="text" className="input-origin al-l" defaultValue={''} value={image ? image.name : ''} readOnly />
{image && <button className="img-check" onClick={() => setImage(null)}></button>}
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -1,211 +1,20 @@
import { useRecoilState, useRecoilValue } from 'recoil'
import { settingModalSecondOptionsState } from '@/store/settingAtom'
import { useMessage } from '@/hooks/useMessage'
import React, { useEffect, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { useFirstOption } from '@/hooks/option/useFirstOption'
import { setSurfaceShapePattern } from '@/util/canvas-util'
import { canvasState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useMessage } from '@/hooks/useMessage'
export default function FirstOption() {
const [objectNo, setObjectNo] = useState('test123240912001') //
const { settingModalFirstOptions, setSettingModalFirstOptions } = useFirstOption()
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
const { option1, option2, dimensionDisplay } = settingModalFirstOptions
const { option3, option4 } = settingModalSecondOptions
const { settingModalFirstOptions, setSettingModalFirstOptions } = useCanvasSetting()
const { settingModalSecondOptions, setSettingModalSecondOptions } = useCanvasSetting()
const { getMessage } = useMessage()
const { get, post } = useAxios()
const { swalFire } = useSwal()
const canvas = useRecoilValue(canvasState)
const { fetchSettings, frontSettings, onClickOption } = useCanvasSetting()
//
useEffect(() => {
console.log('FirstOption useEffect 실행')
fetchSettings()
}, [objectNo])
// Canvas Setting
const fetchSettings = async () => {
try {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item, selected: res[item.column] }))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
//
setSettingModalFirstOptions({
option1: optionData1,
option2: optionData2,
dimensionDisplay: optionData5,
})
setSettingModalSecondOptions({
option3: optionData3,
option4: optionData4,
})
} catch (error) {
console.error('Data fetching error:', error)
}
}
const onClickOption = async (option) => {
option.selected = !option.selected
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
setSettingModalSecondOptions({ option3, option4 })
try {
//
const dataToSend = {
firstOption1: option1.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption2: option2.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption3: dimensionDisplay.map((item) => ({
column: item.column,
selected: item.selected,
})),
// secondOption1: secondOptions[0].option1.map((item) => ({
// name: item.id,
// name: item.name,
// //
// })),
secondOption2: option4.map((item) => ({
column: item.column,
selected: item.selected,
})),
}
const patternData = {
objectNo,
// ()
allocDisplay: dataToSend.firstOption1[0].selected,
outlineDisplay: dataToSend.firstOption1[1].selected,
gridDisplay: dataToSend.firstOption1[2].selected,
lineDisplay: dataToSend.firstOption1[3].selected,
wordDisplay: dataToSend.firstOption1[4].selected,
circuitNumDisplay: dataToSend.firstOption1[5].selected,
flowDisplay: dataToSend.firstOption1[6].selected,
trestleDisplay: dataToSend.firstOption1[7].selected,
totalDisplay: dataToSend.firstOption1[8].selected,
// ()
corridorDimension: dataToSend.firstOption3[0].selected,
realDimension: dataToSend.firstOption3[1].selected,
noneDimension: dataToSend.firstOption3[2].selected,
// ()
onlyBorder: dataToSend.firstOption2[0].selected,
lineHatch: dataToSend.firstOption2[1].selected,
allPainted: dataToSend.firstOption2[2].selected,
// ()
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
}
// HTTP POST
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
swalFire({ text: getMessage(res.returnMessage) })
})
} catch (error) {
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
}
}
const onClickOnlyOne = async (item) => {
//
if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') {
const options2 = settingModalFirstOptions?.option2.map((option2) => {
option2.selected = option2.id === item.id
return option2
})
const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
polygons.forEach((polygon) => {
setSurfaceShapePattern(polygon, item.column)
})
//
} else {
const options = settingModalFirstOptions?.dimensionDisplay.map((option) => {
option.selected = option.id === item.id
return option
})
}
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
try {
//
const dataToSend = {
firstOption1: option1.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption2: option2.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption3: dimensionDisplay.map((item) => ({
column: item.column,
selected: item.selected,
})),
// secondOption1: secondOptions[0].option1.map((item) => ({
// name: item.id,
// name: item.name,
// //
// })),
secondOption2: option4.map((item) => ({
column: item.column,
selected: item.selected,
})),
}
const patternData = {
objectNo,
// ()
allocDisplay: dataToSend.firstOption1[0].selected,
outlineDisplay: dataToSend.firstOption1[1].selected,
gridDisplay: dataToSend.firstOption1[2].selected,
lineDisplay: dataToSend.firstOption1[3].selected,
wordDisplay: dataToSend.firstOption1[4].selected,
circuitNumDisplay: dataToSend.firstOption1[5].selected,
flowDisplay: dataToSend.firstOption1[6].selected,
trestleDisplay: dataToSend.firstOption1[7].selected,
totalDisplay: dataToSend.firstOption1[8].selected,
// ()
corridorDimension: dataToSend.firstOption3[0].selected,
realDimension: dataToSend.firstOption3[1].selected,
noneDimension: dataToSend.firstOption3[2].selected,
// ()
onlyBorder: dataToSend.firstOption2[0].selected,
lineHatch: dataToSend.firstOption2[1].selected,
allPainted: dataToSend.firstOption2[2].selected,
// ()
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
}
// HTTP POST
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
swalFire({ text: getMessage(res.returnMessage) })
})
} catch (error) {
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
}
}
return (
<>
<div className="modal-check-btn-wrap">
@ -225,7 +34,7 @@ export default function FirstOption() {
<div className="flex-check-box for-line">
{settingModalFirstOptions &&
settingModalFirstOptions.dimensionDisplay.map((item) => (
<button key={item.id} className={`check-btn ${item.selected ? 'act' : ''}`} onClick={(e) => onClickOnlyOne(item)}>
<button key={item.id} className={`check-btn ${item.selected ? 'act' : ''}`} onClick={(e) => onClickOption(item)}>
<span className="check-area"></span>
<span className="title-area">{getMessage(item.name)}</span>
</button>
@ -237,7 +46,7 @@ export default function FirstOption() {
<div className="flex-check-box for-line">
{settingModalFirstOptions &&
settingModalFirstOptions.option2.map((item) => (
<button key={item.id} className={`check-btn ${item.selected ? 'act' : ''}`} onClick={(e) => onClickOnlyOne(item)}>
<button key={item.id} className={`check-btn ${item.selected ? 'act' : ''}`} onClick={(e) => onClickOption(item)}>
<span className="check-area"></span>
<span className="title-area">{getMessage(item.name)}</span>
</button>

View File

@ -1,143 +1,34 @@
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
import { useMessage } from '@/hooks/useMessage'
import React, { useEffect, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom'
import DimensionLineSetting from '@/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting'
import { usePopup } from '@/hooks/usePopup'
import { v4 as uuidv4 } from 'uuid'
import FontSetting from '@/components/common/font/FontSetting'
import PlanSizeSetting from '@/components/floor-plan/modal/setting01/planSize/PlanSizeSetting'
import { dimensionLineSettingsState } from '@/store/commonUtilsAtom'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
export default function SecondOption() {
const [objectNo, setObjectNo] = useState('test123240912001') //
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState)
const setAdsorptionRange = useSetRecoilState(adsorptionRangeState)
const { option1, option2, dimensionDisplay } = settingModalFirstOptions
const { option3, option4 } = settingModalSecondOptions
const { getMessage } = useMessage()
const { get, post } = useAxios()
const { swalFire } = useSwal()
const { addPopup, closePopup, closePopups } = usePopup()
const [showFontSettingModal, setShowFontSettingModal] = useState(false)
const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false)
const [showPlanSizeSettingModal, setShowPlanSizeSettingModal] = useState(false)
const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
const [objectNo, setObjectNo] = useState('test123240912001') //
const { settingModalFirstOptions, setSettingModalFirstOptions } = useCanvasSetting()
const { settingModalSecondOptions, setSettingModalSecondOptions } = useCanvasSetting()
const { adsorptionPointMode, setAdsorptionPointMode } = useCanvasSetting()
const { fetchSettings, frontSettings, onClickOption } = useCanvasSetting()
//
useEffect(() => {
console.log('SecondOption useEffect 실행')
fetchSettings()
//fetchSettings()
}, [objectNo])
// Canvas Setting
const fetchSettings = async () => {
try {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({
...item,
selected: res[item.column],
}))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
setSettingModalFirstOptions({
option1: optionData1,
option2: optionData2,
dimensionDisplay: optionData5,
})
setSettingModalSecondOptions({
option3: optionData3,
option4: optionData4,
})
} catch (error) {
console.error('Data fetching error:', error)
}
}
const onClickOption = async (option) => {
// option4
const updatedOption4 = option4.map((item) =>
item.id === option.id
? { ...item, selected: true }
: {
...item,
selected: false,
},
)
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
setSettingModalSecondOptions({ option3, option4: updatedOption4 })
try {
//
const dataToSend = {
firstOption1: option1.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption2: option2.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption3: dimensionDisplay.map((item) => ({
column: item.column,
selected: item.selected,
})),
// secondOption1: secondOptions[0].option3.map((item) => ({
// name: item.id,
// name: item.name,
// //
// })),
secondOption2: updatedOption4.map((item) => ({
column: item.column,
selected: item.selected,
})),
}
const patternData = {
objectNo,
// ()
allocDisplay: dataToSend.firstOption1[0].selected,
outlineDisplay: dataToSend.firstOption1[1].selected,
gridDisplay: dataToSend.firstOption1[2].selected,
lineDisplay: dataToSend.firstOption1[3].selected,
wordDisplay: dataToSend.firstOption1[4].selected,
circuitNumDisplay: dataToSend.firstOption1[5].selected,
flowDisplay: dataToSend.firstOption1[6].selected,
trestleDisplay: dataToSend.firstOption1[7].selected,
totalDisplay: dataToSend.firstOption1[8].selected,
// ()
corridorDimension: dataToSend.firstOption3[0].selected,
realDimension: dataToSend.firstOption3[1].selected,
noneDimension: dataToSend.firstOption3[2].selected,
// ()
onlyBorder: dataToSend.firstOption2[0].selected,
lineHatch: dataToSend.firstOption2[1].selected,
allPainted: dataToSend.firstOption2[2].selected,
// ()
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
}
// HTTP POST
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
swalFire({ text: getMessage(res.returnMessage) })
})
} catch (error) {
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
}
setAdsorptionRange(option.range)
}
let dimensionId = null
let fontId = null
let planSizeId = null
@ -192,16 +83,6 @@ export default function SecondOption() {
setShowFontSettingModal(false)
switch (type) {
case 'dimensionLine':
if (!showDimensionLineSettingModal) {
setShowDimensionLineSettingModal(true)
addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />)
} else {
setShowDimensionLineSettingModal(false)
closePopup(dimensionId)
}
break
case 'font1': {
//
setShowFontSettingModal(true)
@ -210,6 +91,7 @@ export default function SecondOption() {
addPopup(fontId + 1, 2, <FontSetting {...fontProps} />)
break
}
case 'font2': {
//
setShowFontSettingModal(true)
@ -218,6 +100,7 @@ export default function SecondOption() {
addPopup(fontId + 2, 2, <FontSetting {...fontProps} />)
break
}
case 'font3': {
//
setShowFontSettingModal(true)
@ -226,17 +109,34 @@ export default function SecondOption() {
addPopup(fontId + 3, 2, <FontSetting {...fontProps} />)
break
}
case 'font4': //
case 'font4': {
//
setShowFontSettingModal(true)
fontProps.type = 'circuitNumberText'
fontProps.id = fontId
addPopup(fontId, 2, <FontSetting {...fontProps} />)
break
case 'planSize':
setShowPlanSizeSettingModal(true)
}
case 'dimensionLine': {
//
if (!showDimensionLineSettingModal) {
setShowDimensionLineSettingModal(true)
addPopup(dimensionId, 2, <DimensionLineSetting {...dimensionProps} />)
} else {
setShowDimensionLineSettingModal(false)
closePopup(dimensionId)
}
break
}
case 'planSize': {
//
setShowPlanSizeSettingModal(true)
addPopup(planSizeId, 2, <PlanSizeSetting {...planSizeProps} />)
break
}
}
}

View File

@ -89,8 +89,8 @@ export default function Header(props) {
name: 'header.menus.management',
url: '',
children: [
{ id: 3, name: 'header.menus.management.stuff', url: '/management/stuff', children: [] },
{ id: 4, name: 'header.menus.management.plan', url: '/floor-plan', children: [] },
{ id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempdetail', children: [] },
{ id: 4, name: 'header.menus.management.stuffList', url: '/management/stuff', children: [] },
],
},
{

View File

@ -43,9 +43,9 @@ export default function Stuff() {
const copyNo = async (value) => {
try {
await navigator.clipboard.writeText(value)
alert('물건번호가 복사되었습니다.')
alert(getMessage('stuff.detail.header.message2'))
} catch (error) {
alert('물건번호 복사에 실패했습니다.')
alert(getMessage('stuff.detail.header.message3'))
}
}
@ -71,7 +71,7 @@ export default function Stuff() {
// headerCheckboxSelectionCurrentPageOnly: true, //
// checkboxSelection: true,
// showDisabledCheckboxes: true,
cellStyle: { textAlign: 'center' },
cellStyle: { justifyContent: 'center' },
valueFormatter: function (params) {
if (params.value) {
return dayjs(params?.value).format('YYYY.MM.DD HH:mm:ss')
@ -85,31 +85,32 @@ export default function Stuff() {
minWidth: 230,
headerName: getMessage('stuff.gridHeader.objectNo'),
cellRenderer: function (params) {
let objectNo = params.value.substring(0, 1)
if (params.data.objectNo) {
return (
<div>
<Button
size="sm"
color="default"
onPress={() => {
copyNo(params.value)
}}
>
복사
</Button>
<span onDoubleClick={onDoubleClick}>{params.value}</span>
<div className="copy-ico-wrap" onDoubleClick={onDoubleClick}>
{params.value.toLocaleString()}
{objectNo === 'R' && (
<button
type="button"
className="copy_ico"
onClick={() => {
copyNo(params.value)
}}
></button>
)}
</div>
)
}
},
cellRendererParams: {
onPress: copyNo,
onClick: copyNo,
},
},
{
field: 'planTotCnt',
headerName: getMessage('stuff.gridHeader.planTotCnt'),
cellStyle: { textAlign: 'right' },
cellStyle: { justifyContent: 'center' },
},
{ field: 'objectName', headerName: getMessage('stuff.gridHeader.objectName'), cellStyle: { textAlign: 'left' } },
{
@ -131,7 +132,7 @@ export default function Stuff() {
return null
}
},
cellStyle: { textAlign: 'center' },
cellStyle: { justifyContent: 'center' },
},
{
field: 'createDatetime',
@ -143,7 +144,7 @@ export default function Stuff() {
return null
}
},
cellStyle: { textAlign: 'center' },
cellStyle: { justifyContent: 'center' },
},
],
gridCount: 0,

View File

@ -22,12 +22,12 @@ import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
export default function StuffDetail() {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //
const inputReceiveUserEl = useRef(null) //ref
const inputObjectNameEl = useRef(null) //ref
const inputZipNoEl = useRef(null) //ref
const inputAddressEl = useRef(null) //ref
const inputVerticalSnowCoverEl = useRef(null) //ref
const inputInstallHeightEl = useRef(null) //ref
// const inputReceiveUserEl = useRef(null) //ref
// const inputObjectNameEl = useRef(null) //ref
// const inputZipNoEl = useRef(null) //ref
// const inputAddressEl = useRef(null) //ref
// const inputVerticalSnowCoverEl = useRef(null) //ref
// const inputInstallHeightEl = useRef(null) //ref
//
const { commonCode, findCommonCode } = useCommonCode()
@ -88,6 +88,9 @@ export default function StuffDetail() {
const [prefCodeList, setPrefCodeList] = useState([]) //
const [prefValue, setPrefValue] = useState('')
const [saleStoreList, setSaleStoreList] = useState([]) //
const [favoriteStoreList, setFavoriteStoreList] = useState([]) //
const [showSaleStoreList, setShowSaleStoreList] = useState([]) //
const [otherSaleStoreList, setOtherSaleStoreList] = useState([])
const [originOtherSaleStoreList, setOriginOtherSaleStoreList] = useState([])
@ -259,7 +262,7 @@ export default function StuffDetail() {
onClick={() => {
//mid:5(), /pid:
setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo })
router.push(`/floor-plan/5/${params.data.planNo}`)
router.push(`/floor-plan/estimate/5/${params.data.planNo}`)
}}
>
<span className="file"></span>
@ -318,21 +321,37 @@ export default function StuffDetail() {
//1 : X167 T01
//2 : 10X22, 201X112
get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => {
let url
if (sessionState?.storeId === 'T01') {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1`
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}`
} else {
url = `/api/object/saleStore/${sessionState?.storeId}/list`
}
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
const firstList = res.filter((row) => row.saleStoreLevel === '1')
let favList
if (sessionState?.storeId === 'T01') {
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSaleStoreList(firstList)
setFavoriteStoreList(favList)
setShowSaleStoreList(favList)
} else {
//1
setSaleStoreList(firstList)
}
const otherList = res.filter((row) => row.saleStoreLevel !== '1')
//1
setSaleStoreList(firstList)
let filterOtherList
if (sessionState?.storeId === 'T01') {
filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01')
setOriginOtherSaleStoreList(filterOtherList)
setOtherSaleStoreList(filterOtherList)
} else {
//1
//T01 2
setOriginOtherSaleStoreList(otherList)
setOtherSaleStoreList(otherList)
}
@ -380,13 +399,29 @@ export default function StuffDetail() {
//1 : X167 T01
//2 : 10X22, 201X112
get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => {
let url
if (sessionState?.storeId === 'T01') {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1`
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}`
} else {
url = `/api/object/saleStore/${sessionState?.storeId}/list`
}
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
const firstList = res.filter((row) => row.saleStoreLevel === '1')
const otherList = res.filter((row) => row.saleStoreLevel !== '1')
let favList
//1
setSaleStoreList(firstList)
if (sessionState?.storeId === 'T01') {
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSaleStoreList(firstList)
setFavoriteStoreList(favList)
setShowSaleStoreList(favList)
} else {
//1
setSaleStoreList(firstList)
}
let filterOtherList
if (sessionState?.storeId === 'T01') {
@ -495,6 +530,16 @@ export default function StuffDetail() {
const onRadioChange = (key) => {
setSelectObjectStatusId(key.target.value)
}
//1 input
const onInputChange = (key) => {
if (key !== '') {
setShowSaleStoreList(saleStoreList)
} else {
setShowSaleStoreList(favoriteStoreList)
}
}
//1
const onSelectionChange = (key) => {
if (isObjectNotEmpty(key)) {
@ -516,7 +561,7 @@ export default function StuffDetail() {
}
} else {
// EDIT
if (planReqNo !== null) {
if (planReqNo !== null && planReqNo !== '') {
if (confirm(getMessage('stuff.detail.confirm.message1'))) {
delFlg = true
} else {
@ -629,7 +674,7 @@ export default function StuffDetail() {
}
} else {
//EDIT
if (planReqNo !== null) {
if (planReqNo !== null && planReqNo !== '') {
if (confirm(getMessage('stuff.detail.confirm.message1'))) {
delFlg = true
} else {
@ -849,7 +894,6 @@ export default function StuffDetail() {
errors.installHeight = true
}
// console.log(':::::', errors)
setIsFormValid(Object.keys(errors).length === 0 ? true : false)
}
}, [
@ -906,20 +950,17 @@ export default function StuffDetail() {
//
const onValid = async () => {
const formData = form.getValues()
let errors = {}
let fieldNm
//
if (!formData.receiveUser || formData.receiveUser.trim().length === 0) {
fieldNm = getMessage('stuff.detail.receiveUser')
errors = fieldNm
inputReceiveUserEl.current.focus()
}
//
if (!formData.objectName || formData.objectName.trim().length === 0) {
fieldNm = getMessage('stuff.detail.objectStatusId')
errors = fieldNm
inputObjectNameEl.current.focus()
}
//
if (!formData.objectNameOmit) {
@ -935,13 +976,11 @@ export default function StuffDetail() {
if (!formData.zipNo) {
fieldNm = getMessage('stuff.detail.zipNo')
errors = fieldNm
inputZipNoEl.current.focus()
}
//
if (!formData.address) {
fieldNm = getMessage('stuff.detail.address')
errors = fieldNm
inputAddressEl.current.focus()
}
//
if (!formData.prefId || formData.prefId === '0') {
@ -962,7 +1001,6 @@ export default function StuffDetail() {
if (!formData.verticalSnowCover) {
fieldNm = getMessage('stuff.detail.verticalSnowCover')
errors = fieldNm
inputVerticalSnowCoverEl.current.focus()
}
//
@ -974,7 +1012,6 @@ export default function StuffDetail() {
if (!formData.installHeight) {
fieldNm = getMessage('stuff.detail.installHeight')
errors = fieldNm
inputInstallHeightEl.current.focus()
}
if (Object.keys(errors).length > 0) {
@ -1091,9 +1128,10 @@ export default function StuffDetail() {
// PUT
await promisePut({ url: apiUrl, data: params }).then((res) => {
if (res.status === 201) {
setFloorPlanObjectNo({ floorPlanObjectNo: res.data.objectNo })
alert(getMessage('stuff.detail.save'))
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
router.refresh()
// router.refresh()
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`)
}
})
}
@ -1136,16 +1174,15 @@ export default function StuffDetail() {
params.saleStoreLevel = sessionState.storeLvl
}
//, 0
let snow = params.verticalSnowCover
let height = params.installHeight
if (snow === '0') {
return alert(getMessage('stuff.detail.save.valierror1'))
}
if (height === '0') {
return alert(getMessage('stuff.detail.save.valierror2'))
}
// let snow = params.verticalSnowCover
// let height = params.installHeight
// if (snow === '0') {
// return alert(getMessage('stuff.detail.save.valierror1'))
// }
// if (height === '0') {
// return alert(getMessage('stuff.detail.save.valierror2'))
// }
await promisePost({ url: '/api/object/save-object', data: params }).then((res) => {
if (res.status === 201) {
alert(getMessage('stuff.detail.tempSave.message1'))
@ -1231,7 +1268,7 @@ export default function StuffDetail() {
</th>
<td>
<div className="input-wrap" style={{ width: '500px' }}>
<input type="text" className="input-light" {...form.register('receiveUser')} ref={inputReceiveUserEl} />
<input type="text" className="input-light" {...form.register('receiveUser')} />
</div>
</td>
</tr>
@ -1260,7 +1297,7 @@ export default function StuffDetail() {
})}
{/* 라디오끝 */}
<div className="input-wrap mr5" style={{ width: '545px' }}>
<input type="text" className="input-light" {...form.register('objectName')} ref={inputObjectNameEl} />
<input type="text" className="input-light" {...form.register('objectName')} />
</div>
<div className="select-wrap" style={{ width: '120px' }}>
<Select
@ -1306,33 +1343,68 @@ export default function StuffDetail() {
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
{(sessionState?.storeId === 'T01' && (
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={showSaleStoreList}
onInputChange={onInputChange}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
></Select>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</>
)) || (
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
></Select>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</>
)}
</div>
</td>
</tr>
@ -1386,7 +1458,7 @@ export default function StuffDetail() {
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} ref={inputZipNoEl} />
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div>
<Button className="btn-origin grey" onPress={onSearchPostNumberPopOpen}>
{getMessage('stuff.detail.btn.addressPop')}
@ -1422,13 +1494,7 @@ export default function StuffDetail() {
)}
</div>
<div className="input-wrap mr5" style={{ width: '580px' }}>
<input
type="text"
className="input-light"
value={form.watch('address') || ''}
{...form.register('address')}
ref={inputAddressEl}
/>
<input type="text" className="input-light" value={form.watch('address') || ''} {...form.register('address')} />
</div>
</div>
</td>
@ -1503,7 +1569,6 @@ export default function StuffDetail() {
onKeyUp={handleKeyUp}
value={form.watch('verticalSnowCover') || ''}
{...register('verticalSnowCover')}
ref={inputVerticalSnowCoverEl}
/>
</div>
<span className="mr10">cm</span>
@ -1551,7 +1616,6 @@ export default function StuffDetail() {
onKeyUp={handleKeyUp}
value={form.watch('installHeight') || ''}
{...register('installHeight')}
ref={inputInstallHeightEl}
/>
</div>
<span>m</span>
@ -1651,13 +1715,7 @@ export default function StuffDetail() {
</th>
<td>
<div className="input-wrap" style={{ width: '500px' }}>
<input
type="text"
className="input-light"
{...form.register('receiveUser')}
value={form.watch('receiveUser') || ''}
ref={inputReceiveUserEl}
/>
<input type="text" className="input-light" {...form.register('receiveUser')} value={form.watch('receiveUser') || ''} />
</div>
</td>
</tr>
@ -1686,7 +1744,7 @@ export default function StuffDetail() {
})}
{/* 상세라디오끝 */}
<div className="input-wrap mr5" style={{ width: '545px' }}>
<input type="text" className="input-light" {...form.register('objectName')} ref={inputObjectNameEl} />
<input type="text" className="input-light" {...form.register('objectName')} />
</div>
<div className="select-wrap" style={{ width: '120px' }}>
<Select
@ -1732,33 +1790,68 @@ export default function StuffDetail() {
</th>
<td>
<div className="flx-box">
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
{(sessionState?.storeId === 'T01' && (
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={showSaleStoreList}
onInputChange={onInputChange}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</>
)) || (
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</>
)}
</div>
</td>
</tr>
@ -1811,7 +1904,7 @@ export default function StuffDetail() {
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} ref={inputZipNoEl} />
<input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div>
<Button className="btn-origin grey" onPress={onSearchPostNumberPopOpen}>
{getMessage('stuff.detail.btn.addressPop')}
@ -1848,13 +1941,7 @@ export default function StuffDetail() {
)}
</div>
<div className="input-wrap mr5" style={{ width: '580px' }}>
<input
type="text"
className="input-light"
value={form.watch('address') || ''}
{...form.register('address')}
ref={inputAddressEl}
/>
<input type="text" className="input-light" value={form.watch('address') || ''} {...form.register('address')} />
</div>
</div>
</td>
@ -1935,7 +2022,6 @@ export default function StuffDetail() {
onKeyUp={handleKeyUp}
value={form.watch('verticalSnowCover') || ''}
{...register('verticalSnowCover')}
ref={inputVerticalSnowCoverEl}
/>
</div>
<span className="mr10">cm</span>
@ -1987,7 +2073,6 @@ export default function StuffDetail() {
onKeyUp={handleKeyUp}
value={form.watch('installHeight') || ''}
{...register('installHeight')}
ref={inputInstallHeightEl}
/>
</div>
<span>m</span>
@ -2017,7 +2102,7 @@ export default function StuffDetail() {
<th>{getMessage('stuff.detail.remarks')}</th>
<td>
<div className="input-wrap">
<input type="text" className="input-light" {...form.register('remarks')} />
<input type="text" className="input-light" {...form.register('remarks')} value={form.watch('remarks') || ''} />
</div>
</td>
</tr>

View File

@ -39,7 +39,7 @@ export default function StuffQGrid(props) {
return {
filter: false,
flex: 1,
sortable: false,
sortable: true,
suppressMovable: true,
resizable: true,
suppressSizeToFit: false,

View File

@ -4,7 +4,6 @@ import React, { useEffect, useRef, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
// import Select from 'react-dropdown-select'
import Select from 'react-select'
import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
@ -57,7 +56,9 @@ export default function StuffSearchCondition() {
const [receiveUser, setReceiveUser] = useState('') //
const [dateType, setDateType] = useState('U') //(U)/(R)
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT
const [favoriteStoreList, setFavoriteStoreList] = useState([]) //
const [showSaleStoreList, setShowSaleStoreList] = useState([]) //
//
const onSubmit = () => {
let diff = dayjs(endDate).diff(startDate, 'day')
@ -128,13 +129,25 @@ export default function StuffSearchCondition() {
useEffect(() => {
if (isObjectNotEmpty(sessionState)) {
// storeId T01 1
get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => {
let url
if (sessionState?.storeId === 'T01') {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1`
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}`
} else {
url = `/api/object/saleStore/${sessionState?.storeId}/list`
}
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
setSchSelSaleStoreList(res)
const allList = res
const favList = res.filter((row) => row.priority !== 'B')
setSchSelSaleStoreList(allList)
setFavoriteStoreList(favList)
setShowSaleStoreList(favList)
}
})
}
@ -147,6 +160,15 @@ export default function StuffSearchCondition() {
}
}
//
const onInputChange = (key) => {
if (key !== '') {
setShowSaleStoreList(schSelSaleStoreList)
} else {
setShowSaleStoreList(favoriteStoreList)
}
}
//
const onSelectionChange = (key) => {
if (isObjectNotEmpty(key)) {
@ -242,6 +264,7 @@ export default function StuffSearchCondition() {
onChange={(e) => {
setSaleStoreName(saleStoreNameRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
@ -256,6 +279,7 @@ export default function StuffSearchCondition() {
onChange={(e) => {
setAddress(addressRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
@ -272,6 +296,7 @@ export default function StuffSearchCondition() {
onChange={(e) => {
setobjectName(objectNameRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
@ -286,6 +311,7 @@ export default function StuffSearchCondition() {
onChange={(e) => {
setDispCompanyName(dispCompanyNameRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
@ -300,11 +326,15 @@ export default function StuffSearchCondition() {
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={schSelSaleStoreList}
// options={schSelSaleStoreList}
options={showSaleStoreList}
onInputChange={onInputChange}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
value={schSelSaleStoreList.filter(function (option) {
// value={schSelSaleStoreList.filter(function (option) {
value={showSaleStoreList.filter(function (option) {
// console.log(' value::::', option)
if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') {
return false
} else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') {
@ -338,6 +368,7 @@ export default function StuffSearchCondition() {
onChange={(e) => {
setReceiveUser(receiveUserRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>

View File

@ -25,58 +25,90 @@ export default function StuffSubHeader({ type }) {
const moveFloorPlan = () => {
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
router.push('/floor-plan')
//
router.push('/floor-plan/estimate/5/1')
}
return (
<div className="sub-header">
<div className="sub-header-inner">
{type === 'list' && (
<Link href={'#'}>
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
</Link>
)}
{type === 'temp' && (
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
<>
<div className="sub-header">
<div className="sub-header-inner">
{type === 'list' && (
<>
<Link href={'#'}>
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
</Link>
</li>
</ul>
)}
{type === 'detail' && (
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
<li className="title-item">
<a className="sub-header-title" onClick={moveFloorPlan}>
<span className="icon drawing"></span>
{getMessage('plan.menu.plan.drawing')}
</a>
</li>
</ul>
)}
{type !== 'detail' && (
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.stuff')}</span>
</li>
</ul>
)}
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.stuffList')}</span>
</li>
</ul>
</>
)}
{type === 'temp' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.newStuff')}</span>
</li>
</ul>
</>
)}
{type === 'detail' && (
<>
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('stuff.temp.subTitle')}
</Link>
</li>
<li className="title-item">
<a className="sub-header-title" onClick={moveFloorPlan}>
<span className="icon drawing"></span>
{getMessage('plan.menu.plan.drawing')}
</a>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management')}</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.management.newStuff')}</span>
</li>
</ul>
</>
)}
</div>
</div>
</div>
</>
)
}

View File

@ -0,0 +1,95 @@
import WallLineSetting from '@/components/floor-plan/modal/outerlinesetting/WallLineSetting'
import RoofShapeSetting from '@/components/floor-plan/modal/roofShape/RoofShapeSetting'
import RoofShapePassivitySetting from '@/components/floor-plan/modal/roofShape/RoofShapePassivitySetting'
import AuxiliaryDrawing from '@/components/floor-plan/modal/auxiliary/AuxiliaryDrawing'
import EavesGableEdit from '@/components/floor-plan/modal/eavesGable/EavesGableEdit'
import MovementSetting from '@/components/floor-plan/modal/movement/MovementSetting'
import WallLineOffsetSetting from '@/components/floor-plan/modal/wallLineOffset/WallLineOffsetSetting'
import RoofAllocationSetting from '@/components/floor-plan/modal/roofAllocation/RoofAllocationSetting'
import Slope from '@/components/floor-plan/modal/Slope'
import PlacementShapeDrawing from '@/components/floor-plan/modal/placementShape/PlacementShapeDrawing'
import PlacementSurfaceSetting from '@/components/floor-plan/modal/placementSurface/PlacementSurfaceSetting'
import ObjectSetting from '@/components/floor-plan/modal/object/ObjectSetting'
import BasicSetting from '@/components/floor-plan/modal/basic/BasicSetting'
import CircuitTrestleSetting from '@/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting'
import { usePopup } from '@/hooks/usePopup'
import { useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { useRecoilValue } from 'recoil'
import { currentMenuState } from '@/store/canvasAtom'
import { MENU } from '@/common/common'
export default function useMenu() {
const menus = []
const currentMenu = useRecoilValue(currentMenuState)
const [popupId, setPopupId] = useState(uuidv4())
const { addPopup } = usePopup()
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch()
const handleMenu = (type) => {
if (type === 'outline') {
switch (currentMenu) {
case MENU.ROOF_COVERING.EXTERIOR_WALL_LINE:
addPopup(popupId, 1, <WallLineSetting id={popupId} />)
break
case MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS:
addPopup(popupId, 1, <RoofShapeSetting id={popupId} />)
break
case MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS:
addPopup(popupId, 1, <RoofShapePassivitySetting id={popupId} />)
break
case MENU.ROOF_COVERING.HELP_LINE_DRAWING:
addPopup(popupId, 1, <AuxiliaryDrawing id={popupId} />)
break
case MENU.ROOF_COVERING.EAVES_KERAVA_EDIT:
addPopup(popupId, 1, <EavesGableEdit id={popupId} />)
break
case MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN:
addPopup(popupId, 1, <MovementSetting id={popupId} />)
break
case MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET:
addPopup(popupId, 1, <WallLineOffsetSetting id={popupId} />)
break
case MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC:
addPopup(popupId, 1, <RoofAllocationSetting id={popupId} />)
break
}
}
if (type === 'surface') {
switch (currentMenu) {
case MENU.BATCH_CANVAS.SLOPE_SETTING:
addPopup(popupId, 1, <Slope id={popupId} />)
break
case MENU.BATCH_CANVAS.BATCH_DRAWING:
addPopup(popupId, 1, <PlacementShapeDrawing id={popupId} />)
break
case MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH:
addPopup(popupId, 1, <PlacementSurfaceSetting id={popupId} />)
break
case MENU.BATCH_CANVAS.OBJECT_BATCH:
addPopup(popupId, 1, <ObjectSetting id={popupId} />)
break
case MENU.BATCH_CANVAS.ALL_REMOVE:
deleteAllSurfacesAndObjects()
break
}
}
if (type === 'module') {
switch (currentMenu) {
case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING:
addPopup(popupId, 1, <BasicSetting id={popupId} />)
break
case MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING:
addPopup(popupId, 1, <CircuitTrestleSetting id={popupId} />)
break
}
}
}
return {
menus,
handleMenu,
}
}

View File

@ -0,0 +1,305 @@
import { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { globalLocaleStore } from '@/store/localeAtom'
import { useMessage } from '@/hooks/useMessage'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
import { setSurfaceShapePattern } from '@/util/canvas-util'
import { POLYGON_TYPE } from '@/common/common'
import { adsorptionPointModeState, adsorptionRangeState } from '@/store/canvasAtom'
export function useCanvasSetting() {
const canvas = useRecoilValue(canvasState)
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
const { option1, option2, dimensionDisplay } = settingModalFirstOptions
const { option3, option4 } = settingModalSecondOptions
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get, post } = useAxios(globalLocaleState)
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const [adsorptionPointMode, setAdsorptionPointMode] = useRecoilState(adsorptionPointModeState)
const setAdsorptionRange = useSetRecoilState(adsorptionRangeState)
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
useEffect(() => {
console.log('useCanvasSetting useEffect 실행1')
fetchSettings()
}, [objectNo])
useEffect(() => {
console.log('useCanvasSetting useEffect 실행2')
//fetchSettings()
//onClickOption()
//fetchSettings()
}, [adsorptionPointMode])
useEffect(() => {
console.log('useCanvasSetting useEffect 실행3')
//fetchSettings()
//onClickOption()
//fetchSettings()
}, [settingModalFirstOptions, settingModalSecondOptions])
const fetchSettings = async () => {
try {
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
console.log('res', res)
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item }))
const patternData = {
adsorpPoint: res.adsorpPoint,
}
// 데이터 설정
setSettingModalFirstOptions({
option1: optionData1,
option2: optionData2,
dimensionDisplay: optionData5,
})
setSettingModalSecondOptions({
option3: optionData3,
option4: optionData4,
})
setAdsorptionPointMode(patternData.adsorpPoint)
console.log('adsorptionPointMode', adsorptionPointMode)
} catch (error) {
console.error('Data fetching error:', error)
}
}
// 옵션 클릭 후 저장
const onClickOption = async (item) => {
//치수 표시(단 건 선택)
if (item.column === 'corridorDimension' || item.column === 'realDimension' || item.column === 'noneDimension') {
console.log('치수 표시 ', item)
const options = settingModalFirstOptions?.dimensionDisplay.map((option) => {
option.selected = option.id === item.id
return option
})
//화면 표시(단 건 선택)
} else if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') {
console.log('화면 표시 ', item)
const options2 = settingModalFirstOptions?.option2.map((option2) => {
option2.selected = option2.id === item.id
return option2
})
const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
polygons.forEach((polygon) => {
setSurfaceShapePattern(polygon, item.column)
})
//흡착범위 설정(단 건 선택)
} else if (
item.column === 'adsorpRangeSmall' ||
item.column === 'adsorpRangeSmallSemi' ||
item.column === 'adsorpRangeMedium' ||
item.column === 'adsorpRangeLarge'
) {
console.log('화면 표시2 ', item, option4)
// option4에서 한 개만 선택 가능하도록 처리
const updatedOption4 = option4.map((option) =>
option.id === item.id
? { ...option, selected: true }
: {
...option,
selected: false,
},
)
setSettingModalSecondOptions({ option3, option4: updatedOption4 })
//흡착점 ON / OFF
} else if (item === 'adsorpPoint') {
console.log('흡착점 ON / OFF ', item)
const options2 = settingModalFirstOptions?.option2.map((option2) => {
option2.selected = option2.id === item.id
return option2
})
const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
polygons.forEach((polygon) => {
setSurfaceShapePattern(polygon, item.column)
})
//디스플레이 설정(다 건 선택)
} else {
//console.log('디스플레이 설정1 ', item.column)
console.log('디스플레이 설정 ', item)
item.selected = !item.selected
}
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
try {
// 서버에 전송할 데이터
const dataToSend = {
firstOption1: option1.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption2: option2.map((item) => ({
column: item.column,
selected: item.selected,
})),
firstOption3: dimensionDisplay.map((item) => ({
column: item.column,
selected: item.selected,
})),
// secondOption1: secondOptions[0].option1.map((item) => ({
// name: item.id,
// name: item.name,
// // 필요한 경우 데이터 항목 추가
// })),
secondOption2: option4.map((item) => ({
column: item.column,
selected: item.selected,
})),
}
const patternData = {
objectNo,
//디스플레이 설정(다중)
allocDisplay: dataToSend.firstOption1[0].selected,
outlineDisplay: dataToSend.firstOption1[1].selected,
gridDisplay: dataToSend.firstOption1[2].selected,
lineDisplay: dataToSend.firstOption1[3].selected,
wordDisplay: dataToSend.firstOption1[4].selected,
circuitNumDisplay: dataToSend.firstOption1[5].selected,
flowDisplay: dataToSend.firstOption1[6].selected,
trestleDisplay: dataToSend.firstOption1[7].selected,
imageDisplay: dataToSend.firstOption1[8].selected,
totalDisplay: dataToSend.firstOption1[9].selected,
//차수 표시(단 건)
corridorDimension: dataToSend.firstOption3[0].selected,
realDimension: dataToSend.firstOption3[1].selected,
noneDimension: dataToSend.firstOption3[2].selected,
//화면 표시(단 건)
onlyBorder: dataToSend.firstOption2[0].selected,
lineHatch: dataToSend.firstOption2[1].selected,
allPainted: dataToSend.firstOption2[2].selected,
//흡착범위 설정(단 건)
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
//흡착점 ON/OFF
adsorpPoint: adsorptionPointMode,
}
console.log('patternData ', patternData)
// HTTP POST 요청 보내기
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
swalFire({ text: getMessage(res.returnMessage) })
// Canvas 디스플레이 설정 시 해당 옵션 적용
frontSettings()
})
} catch (error) {
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
}
setAdsorptionRange(item.range)
}
// Canvas 디스플레이 설정 시 해당 옵션 적용
const frontSettings = async () => {
const option1 = settingModalFirstOptions.option1
// 'allocDisplay' 할당 표시
// 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine'
// 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid'
// 'lineDisplay' 지붕선 표시 'roof', 'roofBase'
// 'wordDisplay' 문자 표시
// 'circuitNumDisplay' 회로번호 표시
// 'flowDisplay' 흐름방향 표시 'arrow'
// 'trestleDisplay' 가대 표시
// 'imageDisplay' 이미지 표시
// 'totalDisplay' 집계표 표시
let optionName //옵션명
let optionSelected //옵션상태
for (let i = 0; i < option1.length; i++) {
switch (option1[i].column) {
case 'allocDisplay': //할당 표시
optionName = ['1']
break
case 'outlineDisplay': //외벽선 표시
optionName = ['outerLine', 'wallLine']
break
case 'gridDisplay': //그리드 표시
optionName = ['lindGrid', 'dotGrid']
break
case 'lineDisplay': //지붕선 표시
optionName = ['roof', 'roofBase']
break
case 'wordDisplay': //문자 표시
optionName = ['6']
break
case 'circuitNumDisplay': //회로번호 표시
optionName = ['7']
break
case 'flowDisplay': //흐름방향 표시
optionName = ['arrow']
break
case 'trestleDisplay': //가대 표시
optionName = ['8']
break
case 'imageDisplay': //이미지 표시
optionName = ['9']
break
case 'totalDisplay': //집계표 표시
optionName = ['10']
break
}
// 표시 선택 상태(true/false)
optionSelected = option1[i].selected
canvas
.getObjects()
.filter((obj) => optionName.includes(obj.name))
//.filter((obj) => obj.name === optionName)
.forEach((obj) => {
obj.set({ visible: optionSelected })
//obj.set({ visible: !obj.visible })
})
// console.log(
// 'optionName',
// optionName,
// canvas.getObjects().filter((obj) => optionName.includes(obj.name)),
// )
}
}
return {
settingModalFirstOptions,
setSettingModalFirstOptions,
settingModalSecondOptions,
setSettingModalSecondOptions,
adsorptionPointMode,
setAdsorptionPointMode,
fetchSettings,
onClickOption,
frontSettings,
}
}

View File

@ -46,6 +46,7 @@ export const useCanvasSettingController = () => {
}
}
//
const onClickOption = async (option) => {
option.selected = !option.selected

View File

@ -170,7 +170,10 @@ export function useEavesGableEdit(id) {
})
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'pitchText')
removeTargets.forEach((obj) => {
canvas.remove(obj)
})
wallLines.forEach((wallLine) => {
addPitchTextsByOuterLines()
const roof = drawRoofPolygon(wallLine)

View File

@ -0,0 +1,48 @@
import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage'
import { useRef, useState } from 'react'
//동선이동 형 올림 내림
export function useMovementSetting(id) {
const TYPE = {
FLOW_LINE: 'flowLine', // 동선이동
UP_DOWN: 'updown', //형 올림내림
}
const canvas = useRecoilValue(canvasState)
const { closePopup } = usePopup()
const { getMessage } = useMessage()
const buttonType = [
{ id: 1, name: getMessage('modal.movement.flow.line.move'), type: TYPE.FLOW_LINE },
{ id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN },
]
const [type, setType] = useState(TYPE.FLOW_LINE)
const FLOW_LINE_REF = {
DOWN_LEFT_INPUT_REF: useRef(null),
UP_RIGHT_INPUT_REF: useRef(null),
DOWN_LEFT_RADIO_REF: useRef(null),
UP_RIGHT_RADIO_REF: useRef(null),
}
const UP_DOWN_REF = {
UP_INPUT_REF: useRef(null),
DOWN_INPUT_REF: useRef(null),
UP_RADIO_REF: useRef(null),
DOWN_RADIO_REF: useRef(null),
}
const handleSave = () => {}
return {
TYPE,
closePopup,
buttonType,
type,
setType,
FLOW_LINE_REF,
UP_DOWN_REF,
handleSave,
}
}

View File

@ -130,6 +130,12 @@ export function useRoofAllocationSetting(id) {
setSurfaceShapePattern(roof, roofDisplay.column)
drawDirectionArrow(roof)
})
const removeTargets = canvas.getObjects().filter((obj) => obj.name === 'outerLinePoint' || obj.name === 'outerLine')
removeTargets.forEach((obj) => {
canvas.remove(obj)
})
closePopup(id)
}

View File

@ -13,6 +13,7 @@ import { writeImage } from '@/lib/canvas'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { useAxios } from '@/hooks/useAxios'
import { useFont } from '@/hooks/common/useFont'
import { OBJECT_PROTOTYPE, RELOAD_TYPE_PROTOTYPE, SAVE_KEY } from '@/common/common'
export function useCanvas(id) {
const [canvas, setCanvas] = useRecoilState(canvasState)
@ -103,6 +104,20 @@ export function useCanvas(id) {
fabric.Object.prototype.cornerStyle = 'rect'
fabric.Object.prototype.cornerStrokeColor = '#2BEBC8'
fabric.Object.prototype.cornerSize = 6
// 해당 오브젝트 타입의 경우 저장한 값 그대로 불러와야함
OBJECT_PROTOTYPE.forEach((type) => {
type.toObject = function (propertiesToInclude) {
let source = {}
for (let key in this) {
if (typeof this[key] !== 'function' && SAVE_KEY.includes(key)) {
source.key = this[key]
}
}
return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), source)
}
})
fabric.QLine = QLine
fabric.QPolygon = QPolygon
QPolygon.prototype.canvas = canvas

View File

@ -25,6 +25,7 @@ import { useCommonUtils } from './common/useCommonUtils'
import { useMessage } from '@/hooks/useMessage'
import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { contextMenuState } from '@/store/contextMenu'
import ImageSizeSetting from '@/components/floor-plan/modal/image/ImageSizeSetting'
export function useContextMenu() {
const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴
@ -40,7 +41,7 @@ export function useContextMenu() {
const [qContextMenu, setQContextMenu] = useRecoilState(contextMenuState)
const { handleZoomClear } = useCanvasEvent()
const currentMenuSetting = (position) => {
const currentMenuSetting = () => {
switch (currentMenu) {
case MENU.PLAN_DRAWING:
setContextMenu([
@ -108,6 +109,11 @@ export function useContextMenu() {
id: 'wallLineRemove',
name: getMessage('contextmenu.wallline.remove'),
},
{
id: 'imageSizeEdit',
name: getMessage('modal.image.size.setting'),
component: <ImageSizeSetting id={popupId} />,
},
],
[
{
@ -174,6 +180,11 @@ export function useContextMenu() {
shortcut: ['c', 'C'],
name: `${getMessage('contextmenu.copy')}(C)`,
},
{
id: 'imageSizeEdit',
name: getMessage('modal.image.size.setting'),
component: <ImageSizeSetting id={popupId} />,
},
],
[
{

View File

@ -5,6 +5,7 @@ import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState,
import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
import { SAVE_KEY } from '@/common/common'
export function usePlan() {
const [planNum, setPlanNum] = useState(0)
@ -33,41 +34,7 @@ export function usePlan() {
}
const addCanvas = () => {
const objs = canvas?.toJSON([
'selectable',
'name',
'parentId',
'id',
'length',
'idx',
'direction',
'parentDirection',
'lines',
'points',
'lockMovementX',
'lockMovementY',
'lockRotation',
'lockScalingX',
'lockScalingY',
'opacity',
'cells',
'maxX',
'maxY',
'minX',
'minY',
'x',
'y',
'x1',
'x2',
'y1',
'y2',
'attributes',
'stickeyPoint',
'text',
'pitch',
'uuid',
'originText',
])
const objs = canvas?.toJSON(SAVE_KEY)
const str = JSON.stringify(objs)

View File

@ -52,6 +52,7 @@ export async function setSession(data) {
session.storeLvl = data.storeLvl
session.groupId = data.groupId
session.pwdInitYn = data.pwdInitYn
session.custCd = data.custCd
session.isLoggedIn = true
// console.log('session:', session)

View File

@ -3,8 +3,8 @@
"welcome": "환영합니다. {0}님",
"header.menus.home": "ホームへv",
"header.menus.management": "物品及び図面管理",
"header.menus.management.stuff": "新規物件登録",
"header.menus.management.plan": "モノ/図面管理",
"header.menus.management.newStuff": "新規 物件 登録",
"header.menus.management.stuffList": "物件の状況",
"header.menus.community": "コミュニティ",
"header.menus.community.notice": "お知らせ",
"header.menus.community.faq": "FAQ",
@ -214,20 +214,20 @@
"modal.canvas.setting.font.plan.absorption.dimension.display": "見る",
"modal.canvas.setting.font.plan.absorption.plan.size.setting": "図面サイズの設定",
"modal.canvas.setting.first.option.info": "※図面に表示する項目をクリックすると適用されます。",
"modal.canvas.setting.first.option.alloc": "할당표시",
"modal.canvas.setting.first.option.outline": "외벽선표시",
"modal.canvas.setting.first.option.plan": "도면표시",
"modal.canvas.setting.first.option.roof.line": "지붕선표시",
"modal.canvas.setting.first.option.grid": "그리드표시",
"modal.canvas.setting.first.option.circuit.num": "회로 번호 표시",
"modal.canvas.setting.first.option.word": "문자 표시",
"modal.canvas.setting.first.option.trestle": "가대 표시",
"modal.canvas.setting.first.option.flow": "흐름방향 표시",
"modal.canvas.setting.first.option.total": "집계표 표시",
"modal.canvas.setting.first.option.dimension": "치수 표시(JA)",
"modal.canvas.setting.first.option.corridor.dimension": "복도치수 표시(JA)",
"modal.canvas.setting.first.option.real.dimension": "실제치수 표시(JA)",
"modal.canvas.setting.first.option.none.dimension": "치수표시없음(JA)",
"modal.canvas.setting.first.option.alloc": "割り当て表示",
"modal.canvas.setting.first.option.outline": "外壁線表示",
"modal.canvas.setting.first.option.grid": "グリッド表示",
"modal.canvas.setting.first.option.roof.line": "屋根線標示",
"modal.canvas.setting.first.option.word": "文字表示",
"modal.canvas.setting.first.option.circuit.num": "回路番号表示",
"modal.canvas.setting.first.option.flow": "流れ方向表示",
"modal.canvas.setting.first.option.trestle": "架台表示",
"modal.canvas.setting.first.option.image": "画像表示",
"modal.canvas.setting.first.option.total": "集計表表示",
"modal.canvas.setting.first.option.dimension": "寸法表示",
"modal.canvas.setting.first.option.corridor.dimension": "廊下寸法表示",
"modal.canvas.setting.first.option.real.dimension": "実際の寸法表示",
"modal.canvas.setting.first.option.none.dimension": "寸法表示なし",
"modal.canvas.setting.first.option.display": "画面表示",
"modal.canvas.setting.first.option.border": "ボーダーのみ",
"modal.canvas.setting.first.option.line": "ラインハッチ",
@ -274,6 +274,7 @@
"modal.panel.batch.statistic.total": "合計",
"modal.flow.direction.setting": "流れ方向の設定",
"modal.flow.direction.setting.info": "流れ方向を選択してください。",
"modal.image.size.setting": "画像のサイズ変更",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
@ -298,6 +299,14 @@
"contextmenu.auxiliary.cut": "보조선 절삭(JA)",
"contextmenu.auxiliary.remove.all": "보조선 전체 삭제(JA)",
"contextmenu.line.property.edit": "各辺属性の変更",
"contextmenu.column.move": "열 이동(JA)",
"contextmenu.column.copy": "열 복사(JA)",
"contextmenu.column.remove": "コピー設定",
"contextmenu.column.insert": "열 삽입(JA)",
"contextmenu.row.move": "단 이동(JA)",
"contextmenu.row.copy": "단 복사(JA)",
"contextmenu.row.remove": "단 삭제(JA)",
"contextmenu.row.insert": "단 삽입(JA)",
"modal.line.property.edit.info": "属性を変更する辺を選択してください。",
"modal.line.property.edit.selected": "選択した値",
"contextmenu.flow.direction.edit": "흐름 방향 변경(JA)",
@ -398,6 +407,8 @@
"common.message.writeToConfirm": "作成解除を実行しますか?",
"common.message.password.init.success": "パスワード [{0}] に初期化されました。",
"common.message.no.edit.save": "この文書は変更できません。",
"common.input.file": "ファイルを読み込む",
"common.input.file.load": "ファイルの追加",
"common.require": "必須",
"commons.west": "立つ",
"commons.east": "ドン",
@ -595,7 +606,7 @@
"stuff.planReqPopup.search.schDateGbnR": "受付日",
"stuff.planReqPopup.error.message1": "設計依頼を選択してください。",
"stuff.search.title": "物件状況",
"stuff.search.btn1": "物件登録",
"stuff.search.btn1": "新規 物件 登録",
"stuff.search.btn2": "照会",
"stuff.search.btn3": "初期化",
"stuff.search.schObjectNo": "品番",
@ -719,14 +730,25 @@
"estimate.detail.receiveUser": "担当者 ",
"estimate.detail.title": "案件名",
"estimate.detail.remarks": "メモ",
"estimate.detail.orderType": "注文分類",
"estimate.detail.roofCns": "屋根材・仕様施工",
"estimate.detail.note": "備考",
"estimate.detail.nextSubmit": "後日資料提出",
"estimate.detail.header.fileList1": "ファイル添付",
"estimate.detail.fileList.btn": "ファイル選択",
"estimate.detail.header.fileList2": "添付ファイル一覧",
"estimate.detail.header.specialEstimate": "見積もりの具体的な",
"estimate.detail.header.specialEstimateProductInfo": "製品情報",
"estimate.detail.sepcialEstimateProductInfo.totPcs": "数量 (PCS)",
"estimate.detail.sepcialEstimateProductInfo.vol": "容量 (Kw)",
"estimate.detail.sepcialEstimateProductInfo.netAmt": "供給価格",
"estimate.detail.sepcialEstimateProductInfo.vat": "付加価値税 (10%)",
"estimate.detail.sepcialEstimateProductInfo.totPrice": "総額",
"estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "住宅PKG単価 (W)",
"estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG容量 (Kw)",
"estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG金額",
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(モジュール容量 × 数量)÷1000",
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG単価 (W)×PKG容量(W)",
"estimate.detail.header.showPrice": "価格表示",
"estimate.detail.showPrice.btn1": "Pricing",
"estimate.detail.showPrice.description": "クリックして製品の特異性を確認する",

View File

@ -3,8 +3,8 @@
"welcome": "환영합니다. {0}님",
"header.menus.home": "Home",
"header.menus.management": "물건 및 도면 관리",
"header.menus.management.stuff": "신규 물건 등록",
"header.menus.management.plan": "사물/도면 관리",
"header.menus.management.newStuff": "신규 물건 등록",
"header.menus.management.stuffList": "물건 현황",
"header.menus.community": "커뮤니티",
"header.menus.community.notice": "공지",
"header.menus.community.faq": "FAQ",
@ -221,13 +221,13 @@
"modal.canvas.setting.first.option.info": "※도면에 표시하는 항목을 클릭하면 적용됩니다.",
"modal.canvas.setting.first.option.alloc": "할당표시",
"modal.canvas.setting.first.option.outline": "외벽선표시",
"modal.canvas.setting.first.option.plan": "도면표시",
"modal.canvas.setting.first.option.roof.line": "지붕선표시",
"modal.canvas.setting.first.option.grid": "그리드표시",
"modal.canvas.setting.first.option.circuit.num": "회로 번호 표시",
"modal.canvas.setting.first.option.roof.line": "지붕선표시",
"modal.canvas.setting.first.option.word": "문자 표시",
"modal.canvas.setting.first.option.trestle": "가대 표시",
"modal.canvas.setting.first.option.circuit.num": "회로 번호 표시",
"modal.canvas.setting.first.option.flow": "흐름방향 표시",
"modal.canvas.setting.first.option.trestle": "가대 표시",
"modal.canvas.setting.first.option.image": "이미지 표시",
"modal.canvas.setting.first.option.total": "집계표 표시",
"modal.canvas.setting.first.option.dimension": "치수 표시",
"modal.canvas.setting.first.option.corridor.dimension": "복도치수 표시",
@ -279,6 +279,7 @@
"modal.panel.batch.statistic.total": "합계",
"modal.flow.direction.setting": "흐름 방향 설정",
"modal.flow.direction.setting.info": "흐름방향을 선택하세요.",
"modal.image.size.setting": "이미지 크기 조절",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
@ -303,6 +304,14 @@
"contextmenu.auxiliary.cut": "보조선 절삭",
"contextmenu.auxiliary.remove.all": "보조선 전체 삭제",
"contextmenu.line.property.edit": "각 변 속성 변경",
"contextmenu.column.move": "열 이동",
"contextmenu.column.copy": "열 복사",
"contextmenu.column.remove": "열 삭제",
"contextmenu.column.insert": "열 삽입",
"contextmenu.row.move": "단 이동",
"contextmenu.row.copy": "단 복사",
"contextmenu.row.remove": "단 삭제",
"contextmenu.row.insert": "단 삽입",
"modal.line.property.edit.info": "속성을 변경할 변을 선택해주세요.",
"modal.line.property.edit.selected": "선택한 값",
"contextmenu.flow.direction.edit": "흐름 방향 변경",
@ -403,6 +412,8 @@
"common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?",
"common.message.password.init.success": "비밀번호 [{0}]로 초기화 되었습니다.",
"common.message.no.edit.save": "This document cannot be changed.",
"common.input.file": "파일 불러오기",
"common.input.file.load": "불러오기",
"common.require": "필수",
"commons.west": "서",
"commons.east": "동",
@ -600,7 +611,7 @@
"stuff.planReqPopup.search.schDateGbnR": "접수일",
"stuff.planReqPopup.error.message1": "설계의뢰를 선택해주세요.",
"stuff.search.title": "물건현황",
"stuff.search.btn1": "신규등록",
"stuff.search.btn1": "신규 물건 등록",
"stuff.search.btn2": "조회",
"stuff.search.btn3": "초기화",
"stuff.search.schObjectNo": "물건번호",
@ -724,14 +735,25 @@
"estimate.detail.receiveUser": "담당자",
"estimate.detail.title": "안건명",
"estimate.detail.remarks": "메모",
"estimate.detail.orderType": "주문분류",
"estimate.detail.roofCns": "지붕재・사양시공",
"estimate.detail.note": "비고",
"estimate.detail.nextSubmit": "후일자료제출",
"estimate.detail.header.fileList1": "파일첨부",
"estimate.detail.fileList.btn": "파일선택",
"estimate.detail.header.fileList2": "첨부파일 목록",
"estimate.detail.header.specialEstimate": "견적특이사항",
"estimate.detail.header.specialEstimateProductInfo": "제품정보",
"estimate.detail.sepcialEstimateProductInfo.totPcs": "수량 (PCS)",
"estimate.detail.sepcialEstimateProductInfo.vol": "용량 (Kw)",
"estimate.detail.sepcialEstimateProductInfo.netAmt": "공급가액",
"estimate.detail.sepcialEstimateProductInfo.vat": "부가세 (10)",
"estimate.detail.sepcialEstimateProductInfo.totPrice": "총액",
"estimate.detail.sepcialEstimateProductInfo.pkgUnitPrice": "주택PKG단가 (W)",
"estimate.detail.sepcialEstimateProductInfo.pkgWeight": "PKG 용량 (Kw)",
"estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액",
"estimate.detail.sepcialEstimateProductInfo.calcFormula1": "(모듈수량 * 수량)÷100",
"estimate.detail.sepcialEstimateProductInfo.calcFormula2": "PKG단가(W) * PKG용량(W)",
"estimate.detail.header.showPrice": "가격표시",
"estimate.detail.showPrice.btn1": "Pricing",
"estimate.detail.showPrice.description": "클릭하여 제품 특이사항 확인",

View File

@ -323,7 +323,6 @@ export const pitchSelector = selector({
set: ({ get, set }, newValue) => {
const basicSettingStateValue = get(basicSettingState)
const roofAngleSet = basicSettingStateValue.roofAngleSet
console.log(newValue)
if (roofAngleSet === 'slope') {
set(globalPitchState, newValue)
} else {

View File

@ -3,7 +3,7 @@ import { v1 } from 'uuid'
export const floorPlanObjectState = atom({
key: `floorPlanObjectState/${v1()}`,
default: {
objectNo: '', //물건번호
floorPlanObjectNo: '', //물건번호
},
dangerouslyAllowMutability: true,
})

View File

@ -1,6 +1,74 @@
import { atom } from 'recoil'
import { MENU } from '@/common/common'
export const menuNumberState = atom({
key: 'menuNumberState',
default: null,
})
export const menuTypeState = atom({
key: 'menuTypeState',
default: null,
})
export const menusState = atom({
key: 'menusState',
default: [
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
{
index: 1,
name: 'plan.menu.placement.surface.initial.setting',
icon: 'con01',
title: MENU.INITIAL_CANVAS_SETTING,
},
{ index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT },
{ index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT },
{ index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT },
{ index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT },
{ index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT },
],
})
export const subMenusState = atom({
key: 'subMenusState',
default: {
outline: [
// 지붕덮개
{ id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE },
{ id: 1, name: 'plan.menu.roof.cover.roof.shape.setting', menu: MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS },
{
id: 2,
name: 'plan.menu.roof.cover.roof.shape.passivity.setting',
menu: MENU.ROOF_COVERING.ROOF_SHAPE_PASSIVITY_SETTINGS,
},
{ id: 3, name: 'plan.menu.roof.cover.auxiliary.line.drawing', menu: MENU.ROOF_COVERING.HELP_LINE_DRAWING },
{ id: 4, name: 'plan.menu.roof.cover.eaves.kerava.edit', menu: MENU.ROOF_COVERING.EAVES_KERAVA_EDIT },
{ id: 5, name: 'plan.menu.roof.cover.movement.shape.updown', menu: MENU.ROOF_COVERING.MOVEMENT_SHAPE_UPDOWN },
{ id: 6, name: 'plan.menu.roof.cover.outline.edit.offset', menu: MENU.ROOF_COVERING.OUTLINE_EDIT_OFFSET },
{ id: 7, name: 'plan.menu.roof.cover.roof.surface.alloc', menu: MENU.ROOF_COVERING.ROOF_SHAPE_ALLOC },
],
surface: [
// 배치면
{ id: 0, name: 'plan.menu.placement.surface.slope.setting', menu: MENU.BATCH_CANVAS.SLOPE_SETTING },
{ id: 1, name: 'plan.menu.placement.surface.drawing', menu: MENU.BATCH_CANVAS.BATCH_DRAWING },
{ id: 2, name: 'plan.menu.placement.surface.arrangement', menu: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH },
{ id: 3, name: 'plan.menu.placement.surface.object', menu: MENU.BATCH_CANVAS.OBJECT_BATCH },
{ id: 4, name: 'plan.menu.placement.surface.all.remove', menu: MENU.BATCH_CANVAS.ALL_REMOVE },
],
module: [
// 모듈, 회로 구성
{ id: 0, name: 'plan.menu.module.circuit.setting.default', menu: MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING },
{
id: 1,
name: 'plan.menu.module.circuit.setting.circuit.trestle.setting',
menu: MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING,
},
{
id: 2,
name: 'plan.menu.module.circuit.setting.plan.orientation',
menu: MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION,
},
],
},
})

View File

@ -12,10 +12,16 @@ export const settingModalFirstOptionsState = atom({
{ id: 6, column: 'circuitNumDisplay', name: 'modal.canvas.setting.first.option.circuit.num', selected: false },
{ id: 7, column: 'flowDisplay', name: 'modal.canvas.setting.first.option.flow', selected: false },
{ id: 8, column: 'trestleDisplay', name: 'modal.canvas.setting.first.option.trestle', selected: false },
{ id: 9, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: false },
{ id: 9, column: 'imageDisplay', name: 'modal.canvas.setting.first.option.image', selected: false },
{ id: 10, column: 'totalDisplay', name: 'modal.canvas.setting.first.option.total', selected: false },
],
dimensionDisplay: [
{ id: 1, column: 'corridorDimension', name: 'modal.canvas.setting.first.option.corridor.dimension', selected: true },
{
id: 1,
column: 'corridorDimension',
name: 'modal.canvas.setting.first.option.corridor.dimension',
selected: true,
},
{ id: 2, column: 'realDimension', name: 'modal.canvas.setting.first.option.real.dimension', selected: false },
{ id: 3, column: 'noneDimension', name: 'modal.canvas.setting.first.option.none.dimension', selected: false },
],
@ -38,10 +44,34 @@ export const settingModalSecondOptionsState = atom({
{ id: 4, name: 'modal.canvas.setting.font.plan.edit.circuit.num' },
],
option4: [
{ id: 1, column: 'adsorpRangeSmall', name: 'modal.canvas.setting.font.plan.absorption.small', selected: true, range: 10 },
{ id: 2, column: 'adsorpRangeSmallSemi', name: 'modal.canvas.setting.font.plan.absorption.small.semi', selected: false, range: 30 },
{ id: 3, column: 'adsorpRangeMedium', name: 'modal.canvas.setting.font.plan.absorption.medium', selected: false, range: 50 },
{ id: 4, column: 'adsorpRangeLarge', name: 'modal.canvas.setting.font.plan.absorption.large', selected: false, range: 70 },
{
id: 1,
column: 'adsorpRangeSmall',
name: 'modal.canvas.setting.font.plan.absorption.small',
selected: true,
range: 10,
},
{
id: 2,
column: 'adsorpRangeSmallSemi',
name: 'modal.canvas.setting.font.plan.absorption.small.semi',
selected: false,
range: 30,
},
{
id: 3,
column: 'adsorpRangeMedium',
name: 'modal.canvas.setting.font.plan.absorption.medium',
selected: false,
range: 50,
},
{
id: 4,
column: 'adsorpRangeLarge',
name: 'modal.canvas.setting.font.plan.absorption.large',
selected: false,
range: 70,
},
],
},
dangerouslyAllowMutability: true,
@ -130,6 +160,15 @@ export const trestleDisplaySelector = selector({
},
})
// 디스플레이 설정 - 이미지 표시
export const imageDisplaySelector = selector({
key: 'imageDisplaySelector',
get: ({ get }) => {
const settingModalFirstOptions = get(settingModalFirstOptionsState)
return settingModalFirstOptions.option1.find((option) => option.column === 'imageDisplay').selected
},
})
// 디스플레이 설정 - 집계표 표시
export const totalDisplaySelector = selector({
key: 'totalDisplaySelector',

View File

@ -23,6 +23,7 @@
left: 0;
display: block;
width: 100%;
height: 46.8px;
padding-bottom: 0;
background-color: #383838;
transition: padding .17s ease-in-out;
@ -329,7 +330,7 @@
border-top: 1px solid #000;
width: 100%;
transition: all .17s ease-in-out;
z-index: 999;
z-index: 99;
&.active{
top: calc(92.8px + 50px);
}
@ -544,9 +545,9 @@
.sub-content{
padding-top: 46px;
.sub-content-inner{
max-width: 1720px;
max-width: 1760px;
margin: 0 auto;
padding-top: 20px;
padding: 20px 20px 0;
.sub-content-box{
margin-bottom: 20px;
&:last-child{
@ -897,45 +898,63 @@
display: flex;
align-items: center;
margin-right: 15px;
.attachment-required{
.explane-item{
position: relative;
display: flex;
align-items: center;
padding: 0 10px;
font-size: 12px;
font-weight: 400;
color: #45576F;
padding-right: 10px;
.ico{
width: 23px;
height: 23px;
span{
width: 20px;
height: 20px;
margin-right: 5px;
background: url(../../public/static/images/sub/attachment_ico.svg)no-repeat center;
background-size: cover;
background-repeat: no-repeat;
background-position: center;
}
&::before{
&:before{
content: '';
position: absolute;
top: 50%;
right: 0;
left: 0;
transform: translateY(-50%);
width: 1px;
height: 12px;
background-color: #D9D9D9;
}
}
.click-check{
display: flex;
align-items: center;
font-size: 12px;
font-weight: 400;
color: #F16A6A ;
padding-left: 10px;
.ico{
width: 14px;
height: 14px;
margin-right: 5px;
background: url(../../public/static/images/sub/click_check_ico.svg)no-repeat center;
background-size: cover;
&:first-child{
padding-left: 0;
&::before{
display: none;
}
}
&:last-child{
padding-right: 0;
}
&.item01{
color: #3BBB48;
span{
background-image: url(../../public/static/images/sub/open_ico.svg);
}
}
&.item02{
color: #909000;
span{
background-image: url(../../public/static/images/sub/change_ico.svg);
}
}
&.item03{
color: #0191C9;
span{
background-image: url(../../public/static/images/sub/attachment_ico.svg);
}
}
&.item04{
color: #F16A6A;
span{
background-image: url(../../public/static/images/sub/click_check_ico.svg);
}
}
}
}
@ -960,7 +979,6 @@
}
}
}
}
// 발전시물레이션

View File

@ -128,10 +128,3 @@
}
}
.grid-tip{
display: block;
width: 15px;
height: 15px;
background: url(../../public/static/images/sub/grid_tip.svg)no-repeat center;
background-size: cover;
}

View File

@ -1,7 +1,7 @@
.wrap{
display: flex;
flex-direction: column;
min-width: 1600px;
min-width: 1280px;
min-height: 100vh;
overflow-x: hidden;
}

View File

@ -399,6 +399,12 @@ $alert-color: #101010;
color: $pop-color;
border-bottom: 1px solid #424242;
padding-left: 20px;
vertical-align: middle;
.flex-box{
display: flex;
align-items: center;
height: 100%;
}
}
&:first-child{
td,
@ -470,6 +476,52 @@ $alert-color: #101010;
}
}
.img-edit-wrap{
flex: none;
.img-edit-btn{
display: flex;
align-items: center;
height: 30px;
padding: 0 10px;
font-size: 12px;
font-weight: 400;
color: #101010;
background-color: #fff;
border-radius: 2px;
transition: all .15s ease-in-out;
.img-edit{
width: 16px;
height: 16px;
background: url(../../public/static/images/canvas/img_edit_ico.svg)no-repeat center;
background-size: cover;
margin-right: 5px;
}
&:hover{
background-color: #ebebeb;
}
}
}
.img-name-wrap{
display: flex;
align-items: center;
width: 100%;
margin-left: 10px;
input{
flex: 1;
}
.img-check{
flex: none;
width: 18px;
height: 18px;
margin-left: 5px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
background-image: url(../../public/static/images/canvas/img_check_fail.svg);
}
}
// 외벽선 그리기
.outline-wrap{
padding: 24px 0;
@ -1788,4 +1840,22 @@ $alert-color: #101010;
flex: none;
}
}
}
//이미지 크기 설정
.range-wrap{
display: flex;
align-items: center;
input{
flex: 1;
margin-right: 10px;
}
label{
flex: none;
text-align: right;
width: 38px;
font-size: 13px;
color: #fff;
font-weight: 500;
}
}

View File

@ -130,6 +130,10 @@ button{
font-family: 'Pretendard', sans-serif !important;
}
.no-click{
cursor: no-drop !important;
}
// margin
.mt5{margin-top: 5px !important;}
.mt10{margin-top: 10px !important;}

View File

@ -430,4 +430,82 @@ table{
}
}
}
}
// 견적서 테이블
.esimate-table{
table{
table-layout: fixed;
border-collapse: separate;
thead{
tr{
th{
text-align: center;
font-size: 13px;
color: #fff;
font-weight: 600;
padding: 11px 5px;
background-color: #5D6A76;
&:first-child{
border-radius: 4px 0 0 4px;
}
&:last-child{
border-radius: 0 4px 4px 0;
}
}
}
}
tbody{
tr{
td{
padding: 5px 10px;
font-size: 13px;
color: #45576F;
font-weight: 400;
border-bottom: 1px solid #ECF0F4;
.form-flex-wrap{
display: flex;
align-items: center;
.input-wrap,
.select-wrap{
flex: 1;
}
.btn-area{
flex: none;
}
.icon-wrap{
margin-left: auto;
display: flex;
align-items: center;
gap: 5px;
}
}
.tb_ico{
display: block;
width: 20px;
height: 20px;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
&.change_check{
background-image: url(../../public/static/images/sub/change_ico.svg);
}
&.file_check{
background-image: url(../../public/static/images/sub/attachment_ico.svg);
}
&.open_check{
background-image: url(../../public/static/images/sub/open_ico.svg);
}
}
.grid-tip{
display: block;
width: 20px;
height: 20px;
background: url(../../public/static/images/sub/click_check_ico.svg)no-repeat center;
background-size: cover;
}
}
}
}
}
}

View File

@ -268,7 +268,7 @@ export const getDegreeByChon = (chon) => {
export const getChonByDegree = (degree) => {
// tan(theta) = height / base
const radians = (degree * Math.PI) / 180
return Number(Number(Math.tan(radians) * 10).toFixed(1))
return Number(Number(Math.tan(radians) * 10).toFixed(2))
}
/**