# Conflicts:
#	src/hooks/useContextMenu.js
This commit is contained in:
minsik 2024-11-04 09:23:48 +09:00
commit 44e5041b4d
31 changed files with 1544 additions and 436 deletions

View File

@ -1,5 +1,4 @@
import CanvasFrame from '@/components/floor-plan/CanvasFrame' import CanvasFrame from '@/components/floor-plan/CanvasFrame'
import FloorPlan from '@/components/floor-plan/FloorPlan'
export default function FloorPlanPage() { export default function FloorPlanPage() {
return ( return (

View File

@ -1,14 +1,14 @@
import Roof2 from '@/components/Roof2' import Roof2 from '@/components/Roof2'
import { initCheck } from '@/util/session-util' // import { initCheck } from '@/util/session-util'
import RoofSelect from '@/app/roof2/RoofSelect' import RoofSelect from '@/app/roof2/RoofSelect'
export default async function Roof2Page() { export default async function Roof2Page() {
const session = await initCheck() // const session = await initCheck()
const roof2Props = { const roof2Props = {
name: session.name || '', // name: session.name || '',
userId: session.userId || '', // userId: session.userId || '',
email: session.email || '', // email: session.email || '',
isLoggedIn: session.isLoggedIn, // isLoggedIn: session.isLoggedIn,
} }
return ( return (

View File

@ -156,6 +156,7 @@ export const SAVE_KEY = [
'groupYn', 'groupYn',
'groupName', 'groupName',
'lineDirection', 'lineDirection',
'groupId',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]

View File

@ -1,20 +1,31 @@
'use client' 'use client'
import { useEffect, useState, useRef } from 'react' import { useEffect, useState, useRef } from 'react'
import { useMessage } from '@/hooks/useMessage'
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { Button } from '@nextui-org/react'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { useMessage } from '@/hooks/useMessage'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import EstimateFileUploader from './EstimateFileUploader'
export default function Estimate({ params }) { export default function Estimate({ params }) {
const sessionState = useRecoilValue(sessionStore)
const { getMessage } = useMessage()
const objectRecoil = useRecoilValue(floorPlanObjectState)
const [objectNo, setObjectNo] = useState('') const [objectNo, setObjectNo] = useState('')
const fileInputRef = useRef(null)
const [files, setFiles] = useState([]) // const [files, setFiles] = useState([]) //
const fileId = useRef(0)
const sessionState = useRecoilValue(sessionStore)
const objectRecoil = useRecoilValue(floorPlanObjectState)
const { getMessage } = useMessage()
const { setMenuNumber } = useCanvasMenu()
const fileUploadProps = {
// objectNo: '',
// planNo: params.pid,
// category: '10',
uploadFiles: files,
setUploadFiles: setFiles,
}
useEffect(() => { useEffect(() => {
setObjectNo(objectRecoil.floorPlanObjectNo) setObjectNo(objectRecoil.floorPlanObjectNo)
@ -28,31 +39,9 @@ export default function Estimate({ params }) {
} }
}, [objectNo]) }, [objectNo])
const handleButtonClick = () => { useEffect(() => {
fileInputRef.current.click() setMenuNumber(5)
} }, [])
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 ( return (
<div className="sub-content estimate"> <div className="sub-content estimate">
@ -210,7 +199,8 @@ export default function Estimate({ params }) {
<tr> <tr>
<th>{getMessage('estimate.detail.header.fileList1')}</th> <th>{getMessage('estimate.detail.header.fileList1')}</th>
<td> <td>
<div className="drag-file-box"> <EstimateFileUploader {...fileUploadProps} />
{/* <div className="drag-file-box">
<div className="btn-area"> <div className="btn-area">
<Button type="button" className="btn-origin grey" onClick={handleButtonClick}> <Button type="button" className="btn-origin grey" onClick={handleButtonClick}>
{getMessage('estimate.detail.fileList.btn')} {getMessage('estimate.detail.fileList.btn')}
@ -228,7 +218,7 @@ export default function Estimate({ params }) {
<p>Drag file here</p> <p>Drag file here</p>
<ul className="file-list"></ul> <ul className="file-list"></ul>
</div> </div>
</div> </div> */}
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -0,0 +1,91 @@
'use client'
import { useContext, useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMessage } from '@/hooks/useMessage'
import { SessionContext } from '@/app/SessionProvider'
export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
const fileInputRef = useRef(null)
const { getMessage } = useMessage()
const { session } = useContext(SessionContext)
const handleButtonClick = (e) => {
e.preventDefault()
fileInputRef.current.click()
}
const onChangeFiles = async (e) => {
// const formData = new FormData()
// formData.append('file', e.target.files[0])
// formData.append('objectNo', objectNo) //
// formData.append('planNo', planNo) //
// formData.append('category', category) //
// formData.append('userId', session.userId)
// await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => {
// if (res.data > 0) setUploadFiles([...files, { name: e.target.files[0].name, id: uuidv4() }])
// })
setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }])
}
const deleteFile = (id) => {
setUploadFiles(uploadFiles.filter((file) => file.id !== id))
}
const handleDrop = (e) => {
e.preventDefault()
e.stopPropagation()
const fileList = []
Array.from(e.dataTransfer.files).forEach((file) => {
fileList.push({ data: file, id: uuidv4() })
})
setUploadFiles([...uploadFiles, ...fileList])
}
const handleDragOver = (e) => {
e.preventDefault()
e.stopPropagation()
}
const handleDragEnd = (e) => {
e.preventDefault()
e.stopPropagation()
}
const handleDragLeave = (e) => {
e.preventDefault()
e.stopPropagation()
}
return (
<div className="drag-file-box">
<div className="btn-area">
<label className="file-upload" htmlFor="img" onClick={handleButtonClick}>
{getMessage('estimate.detail.fileList.btn')}
</label>
<input type="file" name="file" id="img" ref={fileInputRef} style={{ display: 'none' }} onChange={(e) => onChangeFiles(e)} />
</div>
<div
className="drag-file-area"
draggable
onDrop={(e) => handleDrop(e)}
onDragOver={(e) => handleDragOver(e)}
onDragEnd={(e) => handleDragEnd(e)}
onDragLeave={(e) => handleDragLeave(e)}
>
<p>Drag file here</p>
<ul className="file-list">
{uploadFiles.length > 0 &&
uploadFiles.map((file) => (
<li className="file-item" key={file.id}>
<span>
{file.data.name} <button className="delete" onClick={() => deleteFile(file.id)}></button>
</span>
</li>
))}
</ul>
</div>
</div>
)
}

View File

@ -224,7 +224,7 @@ export default function CanvasMenu(props) {
<div className="ico-btn-from"> <div className="ico-btn-from">
<button className="btn-frame gray ico-flx act"> <button className="btn-frame gray ico-flx act">
<span className="ico ico01"></span> <span className="ico ico01"></span>
<span>{getMessage('plan.menu.estimate.roof.alloc')}</span> <span>{getMessage('plan.menu.estimate.docDown')}</span>
</button> </button>
<button className="btn-frame gray ico-flx"> <button className="btn-frame gray ico-flx">
<span className="ico ico02"></span> <span className="ico ico02"></span>

View File

@ -26,10 +26,6 @@ export default function FloorPlan({ children }) {
fetchSettings() fetchSettings()
}, [objectNo]) }, [objectNo])
useEffect(() => {
setMenuNumber(1)
}, [])
return ( return (
<> <>
<div className="canvas-wrap"> <div className="canvas-wrap">

View File

@ -49,9 +49,8 @@ export default function DimensionLineSetting(props) {
resultText = calculateLength(basicLength, slopeInput1.angleValue).toFixed(0) resultText = calculateLength(basicLength, slopeInput1.angleValue).toFixed(0)
if (slopeInput2) { if (slopeInput2) {
const angle = slopeInput1 + slopeInput2 const length = calculateLength(basicLength, slopeInput1.angleValue, slopeInput2.angleValue)
const length = calculateLength(basicLength, angle) resultText = length.toFixed(0)
resultText = length.toFixed(2)
} }
} }
} }
@ -71,11 +70,18 @@ export default function DimensionLineSetting(props) {
} }
function calculateLength(originalLength, angle) { function calculateLength(originalLength, angle) {
const angleInRadians = angle * (Math.PI / 180) // const angleInRadians = angle * (Math.PI / 180)
const result = Math.sqrt(Math.pow(originalLength * Math.tan(angleInRadians), 2) + Math.pow(originalLength, 2)) const result = Math.sqrt(Math.pow(originalLength * Math.tan(angleInRadians), 2) + Math.pow(originalLength, 2))
return result return result
} }
function calculateLength(originalLength, angle1, angle2) {
const numerator = Math.sqrt(Math.pow(angle1, 2) + 100 + Math.pow((10 * angle1) / angle2, 2)) * originalLength
const denominator = Math.sqrt(Math.pow((10 * angle1) / angle2, 2) + 100)
const result = numerator / denominator
return result
}
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}> <div className={`modal-pop-wrap xm mount`}>

View File

@ -1,5 +1,6 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
const FLOW_LINE_TYPE = { const FLOW_LINE_TYPE = {
DOWN_LEFT: 'downLeft', DOWN_LEFT: 'downLeft',
@ -44,12 +45,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}> <div className="input-grid mr5" style={{ width: '100px' }}>
<input <input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.DOWN_LEFT_INPUT_REF} />
type="text"
className="input-origin block"
readOnly={type !== FLOW_LINE_TYPE.DOWN_LEFT}
ref={FLOW_LINE_REF.DOWN_LEFT_INPUT_REF}
/>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,8 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
import { canvasState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
const UP_DOWN_TYPE = { const UP_DOWN_TYPE = {
UP: 'up', UP: 'up',
@ -9,6 +12,7 @@ const UP_DOWN_TYPE = {
export default function Updown({ UP_DOWN_REF }) { export default function Updown({ UP_DOWN_REF }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [type, setType] = useState(UP_DOWN_TYPE.UP) const [type, setType] = useState(UP_DOWN_TYPE.UP)
const canvas = useRecoilValue(canvasState)
useEffect(() => { useEffect(() => {
if (type === UP_DOWN_TYPE.UP) { if (type === UP_DOWN_TYPE.UP) {
@ -44,7 +48,7 @@ export default function Updown({ UP_DOWN_REF }) {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}> <div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" readOnly={type !== UP_DOWN_TYPE.UP} ref={UP_DOWN_REF.UP_INPUT_REF} /> <input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.UP_INPUT_REF} />
</div> </div>
</div> </div>
</div> </div>

View File

@ -5,7 +5,9 @@ import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { contextPopupPositionState } from '@/store/popupAtom' import { contextPopupPositionState } from '@/store/popupAtom'
import { useState } from 'react' import { useRef, useState, useEffect } from 'react'
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
import { useEvent } from '@/hooks/useEvent'
export default function SizeSetting(props) { export default function SizeSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState) const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@ -13,6 +15,23 @@ export default function SizeSetting(props) {
const { id, pos = contextPopupPosition, target } = props const { id, pos = contextPopupPosition, target } = props
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { reSizeObjectBatch } = useObjectBatch({})
const widthRef = useRef(null)
const heightRef = useRef(null)
const { initEvent } = useEvent()
useEffect(() => {
initEvent()
}, [])
const handleReSizeObject = () => {
const width = widthRef.current.value
const height = heightRef.current.value
reSizeObjectBatch(settingTarget, target, width, height)
}
return ( return (
<WithDraggable isShow={true} pos={pos}> <WithDraggable isShow={true} pos={pos}>
@ -28,11 +47,11 @@ export default function SizeSetting(props) {
<div className="size-option-top"> <div className="size-option-top">
<div className="size-option-wrap"> <div className="size-option-wrap">
<div className="size-option mb5"> <div className="size-option mb5">
<input type="text" className="input-origin mr5" defaultValue={1000} readOnly value={target?.width * 10 * 2} /> <input type="text" className="input-origin mr5" value={target?.width.toFixed(0) * 10} readOnly={true} />
<span className="normal-font">mm</span> <span className="normal-font">mm</span>
</div> </div>
<div className="size-option"> <div className="size-option">
<input type="text" className="input-origin mr5" defaultValue={1000} value={target?.width * 10 * 2} /> <input type="text" className="input-origin mr5" defaultValue={target?.width.toFixed(0) * 10} ref={widthRef} />
<span className="normal-font">mm</span> <span className="normal-font">mm</span>
</div> </div>
</div> </div>
@ -41,11 +60,11 @@ export default function SizeSetting(props) {
<div className="size-option-side"> <div className="size-option-side">
<div className="size-option-wrap"> <div className="size-option-wrap">
<div className="size-option mb5"> <div className="size-option mb5">
<input type="text" className="input-origin mr5" defaultValue={1000} readOnly value={target?.height * 10} /> <input type="text" className="input-origin mr5" value={target?.height.toFixed(0) * 10} readOnly={true} />
<span className="normal-font">mm</span> <span className="normal-font">mm</span>
</div> </div>
<div className="size-option"> <div className="size-option">
<input type="text" className="input-origin mr5" defaultValue={1000} value={target?.height * 10} /> <input type="text" className="input-origin mr5" defaultValue={target?.height.toFixed(0) * 10} ref={heightRef} />
<span className="normal-font">mm</span> <span className="normal-font">mm</span>
</div> </div>
</div> </div>
@ -60,7 +79,9 @@ export default function SizeSetting(props) {
</div> </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('write')}</button> <button className="btn-frame modal act" onClick={() => handleReSizeObject()}>
{getMessage('write')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -38,7 +38,7 @@ const PentagonDormer = forwardRef((props, refs) => {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" placeholder={0} ref={refs.offsetRef} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.offsetRef} defaultValue={400} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>
@ -60,7 +60,7 @@ const PentagonDormer = forwardRef((props, refs) => {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" placeholder={0} ref={refs.offsetWidthRef} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.offsetWidthRef} defaultValue={300} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>

View File

@ -38,7 +38,7 @@ const TriangleDormer = forwardRef((props, refs) => {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" placeholder={0} ref={refs.offsetRef} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.offsetRef} defaultValue={400} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>

View File

@ -15,7 +15,7 @@ export default function MainContents() {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const router = useRouter() const router = useRouter()
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { promiseGet, get } = useAxios(globalLocaleState) const { promiseGet } = useAxios(globalLocaleState)
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
@ -118,7 +118,7 @@ export default function MainContents() {
key={row.objectNo} key={row.objectNo}
className="recently-item" className="recently-item"
onClick={() => { onClick={() => {
if (row.objectNo.substring(0, 1) === 'R') { if (row.tempFlg === '0') {
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`) router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`)
} else { } else {
router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`) router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`)

View File

@ -1,12 +1,11 @@
'use client' 'use client'
import React, { useEffect, useState, useRef } from 'react' import { useEffect, useState, useRef, useContext } from 'react'
import { useRouter, usePathname } from 'next/navigation' import { useRouter, usePathname } from 'next/navigation'
import { Button } from '@nextui-org/react'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import StuffQGrid from './StuffQGrid' import StuffQGrid from './StuffQGrid'
import { useRecoilValue, useRecoilState } from 'recoil' import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil'
import { stuffSearchState } from '@/store/stuffAtom' import { stuffSearchState } from '@/store/stuffAtom'
import { queryStringFormatter, isEmptyArray } from '@/util/common-utils' import { queryStringFormatter, isEmptyArray } from '@/util/common-utils'
import dayjs from 'dayjs' import dayjs from 'dayjs'
@ -17,10 +16,12 @@ import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json' import JA from '@/locales/ja.json'
import QPagination from '../common/pagination/QPagination' import QPagination from '../common/pagination/QPagination'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { SessionContext } from '@/app/SessionProvider'
export default function Stuff() { export default function Stuff() {
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) const { session } = useContext(SessionContext)
const setAppMessageState = useSetRecoilState(appMessageStore)
const stuffSearchParams = useRecoilValue(stuffSearchState) const stuffSearchParams = useRecoilValue(stuffSearchState)
const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState) const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState)
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -224,11 +225,10 @@ export default function Stuff() {
// //
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(sessionState)) { if (isObjectNotEmpty(session)) {
// sessionState
if (stuffSearchParams?.code === 'S') { if (stuffSearchParams?.code === 'S') {
const params = { const params = {
saleStoreId: sessionState?.storeId, saleStoreId: stuffSearchParams.schSelSaleStoreId,
schObjectNo: stuffSearchParams?.schObjectNo, schObjectNo: stuffSearchParams?.schObjectNo,
schAddress: stuffSearchParams?.schAddress, schAddress: stuffSearchParams?.schAddress,
schObjectName: stuffSearchParams?.schObjectName, schObjectName: stuffSearchParams?.schObjectName,
@ -240,7 +240,9 @@ export default function Stuff() {
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: (pageNo - 1) * pageSize + 1, startRow: (pageNo - 1) * pageSize + 1,
endRow: pageNo * pageSize, endRow: pageNo * pageSize,
schSelSaleStoreId: '', schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId
? stuffSearchParams.schOtherSelSaleStoreId
: stuffSearchParams.schSelSaleStoreId,
schSortType: stuffSearchParams.schSortType, schSortType: stuffSearchParams.schSortType,
} }
@ -255,11 +257,13 @@ export default function Stuff() {
} }
}) })
} }
fetchData() if (stuffSearchParams?.schSelSaleStoreId !== '') {
} else { fetchData()
}
} else if (stuffSearchParams?.code === 'M') {
// //
const params = { const params = {
saleStoreId: sessionState?.storeId, saleStoreId: session?.storeId,
schObjectNo: stuffSearchParams.schObjectNo, schObjectNo: stuffSearchParams.schObjectNo,
schAddress: '', schAddress: '',
schObjectName: '', schObjectName: '',
@ -271,25 +275,17 @@ export default function Stuff() {
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), schToDt: dayjs(new Date()).format('YYYY-MM-DD'),
startRow: (pageNo - 1) * pageSize + 1, startRow: (pageNo - 1) * pageSize + 1,
endRow: pageNo * pageSize, endRow: pageNo * pageSize,
schSelSaleStoreId: '', schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId
? stuffSearchParams.schOtherSelSaleStoreId
: stuffSearchParams.schSelSaleStoreId,
schSortType: 'R', schSortType: 'R',
} }
setStuffSearch({
async function fetchData() { ...params,
const apiUrl = `/api/object/list?${queryStringFormatter(params)}` })
await get({
url: apiUrl,
}).then((res) => {
if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
setTotalCount(res[0].totCnt)
}
})
}
fetchData()
} }
} }
}, [pageNo, sessionState]) }, [pageNo, session, stuffSearchParams])
useEffect(() => { useEffect(() => {
if (stuffSearchParams?.code === 'E') { if (stuffSearchParams?.code === 'E') {
@ -298,9 +294,13 @@ export default function Stuff() {
stuffSearchParams.schSortType = defaultSortType stuffSearchParams.schSortType = defaultSortType
setPageNo(1) setPageNo(1)
// //
async function fetchData() { async function fetchData() {
const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` let saleStoreId
saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId
// const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}`
const apiUrl = `/api/object/list?saleStoreId=${saleStoreId}&${queryStringFormatter(stuffSearchParams)}`
await get({ url: apiUrl }).then((res) => { await get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -320,16 +320,21 @@ export default function Stuff() {
let startRow = (1 - 1) * e.target.value + 1 let startRow = (1 - 1) * e.target.value + 1
stuffSearchParams.startRow = startRow stuffSearchParams.startRow = startRow
stuffSearchParams.endRow = 1 * e.target.value stuffSearchParams.endRow = 1 * e.target.value
stuffSearchParams.schSelSaleStoreId = stuffSearchParams?.schOtherSelSaleStoreId
? stuffSearchParams.schOtherSelSaleStoreId
: stuffSearchParams.schSelSaleStoreId
setPageSize(e.target.value) setPageSize(e.target.value)
setStuffSearch({ setStuffSearch({
...stuffSearch, ...stuffSearchParams,
code: 'S',
startRow: startRow, startRow: startRow,
endRow: 1 * e.target.value, endRow: 1 * e.target.value,
}) })
setPageNo(1) setPageNo(1)
const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` let saleStoreId
saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId
// const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}`
const apiUrl = `/api/object/list?saleStoreId=${saleStoreId}&${queryStringFormatter(stuffSearchParams)}`
get({ url: apiUrl }).then((res) => { get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -348,6 +353,9 @@ export default function Stuff() {
stuffSearchParams.endRow = 1 * pageSize stuffSearchParams.endRow = 1 * pageSize
stuffSearchParams.schSortType = e.target.value stuffSearchParams.schSortType = e.target.value
stuffSearchParams.schSelSaleStoreId = stuffSearchParams?.schOtherSelSaleStoreId
? stuffSearchParams.schOtherSelSaleStoreId
: stuffSearchParams.schSelSaleStoreId
setDefaultSortType(e.target.value) setDefaultSortType(e.target.value)
setStuffSearch({ setStuffSearch({
...stuffSearch, ...stuffSearch,
@ -358,8 +366,10 @@ export default function Stuff() {
}) })
setPageNo(1) setPageNo(1)
let saleStoreId
const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` saleStoreId = stuffSearchParams?.schSelSaleStoreId ? stuffSearchParams.schSelSaleStoreId : session?.storeId
// const apiUrl = `/api/object/list?saleStoreId=${session?.storeId}&${queryStringFormatter(stuffSearchParams)}`
const apiUrl = `/api/object/list?saleStoreId=${saleStoreId}&${queryStringFormatter(stuffSearchParams)}`
get({ url: apiUrl }).then((res) => { get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -382,7 +392,9 @@ export default function Stuff() {
// //
const handleChangePage = (page) => { const handleChangePage = (page) => {
stuffSearchParams.code = 'S' stuffSearchParams.code = 'S'
stuffSearchParams.schSelSaleStoreId = stuffSearchParams?.schOtherSelSaleStoreId
? stuffSearchParams.schOtherSelSaleStoreId
: stuffSearchParams.schSelSaleStoreId
setStuffSearch({ setStuffSearch({
...stuffSearch, ...stuffSearch,
code: 'S', code: 'S',
@ -405,10 +417,7 @@ export default function Stuff() {
{getMessage('stuff.search.grid.all')} {getMessage('stuff.search.grid.all')}
<span>{convertNumberToPriceDecimal(totalCount)}</span> <span>{convertNumberToPriceDecimal(totalCount)}</span>
</li> </li>
<li> <li></li>
{/* {getMessage('stuff.search.grid.selected')} */}
{/* <span className="red">{convertNumberToPriceDecimal(selectedRowDataCount)}</span> */}
</li>
</ul> </ul>
</div> </div>
<div className="left-unit-box"> <div className="left-unit-box">

View File

@ -1,6 +1,6 @@
'use client' 'use client'
import React, { useState, useEffect, useRef } from 'react' import { useState, useEffect, useRef, useContext } from 'react'
import { useRouter, useSearchParams, usePathname } from 'next/navigation' import { useRouter, useSearchParams, usePathname } from 'next/navigation'
import { Button } from '@nextui-org/react' import { Button } from '@nextui-org/react'
import Select, { components } from 'react-select' import Select, { components } from 'react-select'
@ -12,6 +12,7 @@ import { useMessage } from '@/hooks/useMessage'
import { useForm } from 'react-hook-form' import { useForm } from 'react-hook-form'
import { useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilValue, useSetRecoilState } from 'recoil'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { SessionContext } from '@/app/SessionProvider'
import FindAddressPop from './popup/FindAddressPop' import FindAddressPop from './popup/FindAddressPop'
import PlanRequestPop from './popup/PlanRequestPop' import PlanRequestPop from './popup/PlanRequestPop'
import WindSelectPop from './popup/WindSelectPop' import WindSelectPop from './popup/WindSelectPop'
@ -22,19 +23,13 @@ import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
export default function StuffDetail() { export default function StuffDetail() {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) // 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 { commonCode, findCommonCode } = useCommonCode() const { commonCode, findCommonCode } = useCommonCode()
const [selOptions, setSelOptions] = useState('') // 1 const [selOptions, setSelOptions] = useState('') // 1
const [otherSelOptions, setOtherSelOptions] = useState('') // 1 const [otherSelOptions, setOtherSelOptions] = useState('') // 1
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const { session } = useContext(SessionContext)
const router = useRouter() const router = useRouter()
const pathname = usePathname() const pathname = usePathname()
@ -322,55 +317,91 @@ export default function StuffDetail() {
//1 : X167 T01 //1 : X167 T01
//2 : 10X22, 201X112 //2 : 10X22, 201X112
let url let url
if (sessionState?.storeId === 'T01') { let firstList
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` let otherList
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` let favList
// if (sessionState?.storeId === 'T01') {
if (session?.storeId === 'T01') {
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
url = `/api/object/saleStore/${sessionState?.storeId}/list` if (session.storeLvl === '1') {
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
} else {
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
const firstList = res.filter((row) => row.saleStoreLevel === '1') res.map((row) => {
let favList row.value = row.saleStoreId
if (sessionState?.storeId === 'T01') { row.label = row.saleStoreName
})
if (session?.storeId === 'T01') {
firstList = res
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B') favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSaleStoreList(firstList) setSaleStoreList(firstList)
setFavoriteStoreList(favList) setFavoriteStoreList(favList)
setShowSaleStoreList(favList) setShowSaleStoreList(favList)
} else { setSelOptions(session?.storeId)
//1 form.setValue('saleStoreId', session?.storeId)
setSaleStoreList(firstList) form.setValue('saleStoreLevel', session?.storeLvl)
} //T01 1 2
const otherList = res.filter((row) => row.saleStoreLevel !== '1') // (T01) 2
let filterOtherList url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=0&userId=${session?.userId}`
if (sessionState?.storeId === 'T01') { get({ url: url }).then((res) => {
filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01') if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
setOriginOtherSaleStoreList(filterOtherList) otherList = res
setOtherSaleStoreList(filterOtherList) setOtherSaleStoreList(otherList)
} else {
setOtherSaleStoreList([])
}
})
} else { } else {
//T01 2 if (session?.storeLvl === '1') {
setOriginOtherSaleStoreList(otherList) firstList = res
setOtherSaleStoreList(otherList) favList = res.filter((row) => row.priority !== 'B')
} otherList = res.filter((row) => row.firstAgentYn === 'N')
if (sessionState?.storeLvl === '1') { setSaleStoreList(firstList)
setSelOptions(sessionState?.storeId) setFavoriteStoreList(firstList)
form.setValue('saleStoreId', sessionState?.storeId) setShowSaleStoreList(firstList)
form.setValue('saleStoreLevel', sessionState?.storeLvl) setSelOptions(firstList[0].saleStoreId)
} else { form.setValue('saleStoreId', session?.storeId)
setSelOptions(firstList[0].saleStoreId) form.setValue('saleStoreLevel', session?.storeLvl)
setOtherSelOptions(sessionState?.storeId)
form.setValue('saleStoreId', firstList[0].saleStoreId) setOtherSaleStoreList(otherList)
form.setValue('otherSaleStoreId', sessionState?.storeId) } else {
form.setValue('otherSaleStoreLevel', sessionState?.storeLvl) //10X22, 201X112,202X217
firstList = res.filter((row) => row.firstAgentYn === 'Y')
setSaleStoreList(firstList)
setFavoriteStoreList(firstList)
setShowSaleStoreList(firstList)
setSelOptions(firstList[0].saleStoreId)
form.setValue('saleStoreId', firstList[0].saleStoreId)
form.setValue('saleStoreLevel', firstList[0].saleStoreLevel)
otherList = res.filter((row) => row.firstAgentYn === 'N')
setOtherSaleStoreList(otherList)
//2 /ID
setOtherSelOptions(session?.storeId)
form.setValue('otherSaleStoreId', session?.storeId)
form.setValue('otherSaleStoreLevel', session?.storeLvl)
}
} }
} }
}) })
} }
}, [objectNo, sessionState]) // }, [objectNo, sessionState])
}, [objectNo, session])
useEffect(() => { useEffect(() => {
const code1 = findCommonCode(200800) // const code1 = findCommonCode(200800) //
@ -400,38 +431,78 @@ export default function StuffDetail() {
//1 : X167 T01 //1 : X167 T01
//2 : 10X22, 201X112 //2 : 10X22, 201X112
let url let url
if (sessionState?.storeId === 'T01') { let firstList
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` let otherList
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` let favList
// if (sessionState?.storeId === 'T01') {
if (session?.storeId === 'T01') {
// url = `/api/object/saleStore/${sessionState?.storeId}/firstList?userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
url = `/api/object/saleStore/${sessionState?.storeId}/list` // if (sessionState.storeLvl === '1') {
if (session.storeLvl === '1') {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
} else {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
const firstList = res.filter((row) => row.saleStoreLevel === '1') // if (sessionState?.storeId === 'T01') {
const otherList = res.filter((row) => row.saleStoreLevel !== '1') if (session?.storeId === 'T01') {
let favList firstList = res.filter((row) => row.saleStoreLevel === '1')
if (sessionState?.storeId === 'T01') {
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B') favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSaleStoreList(firstList) setSaleStoreList(firstList)
setFavoriteStoreList(favList) setFavoriteStoreList(favList)
setShowSaleStoreList(favList) setShowSaleStoreList(favList)
form.setValue('saleStoreId', firstList[0].saleStoreId)
form.setValue('saleStoreName', firstList[0].saleStoreName)
form.setValue('saleStoreLevel', firstList[0].saleStoreLevel)
setSelOptions(firstList[0].saleStoreId)
// 1 2
// url = `/api/object/saleStore/${detailData?.saleStoreId}/list?firstFlg=0&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${detailData?.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOriginOtherSaleStoreList(otherList)
setOtherSaleStoreList(otherList)
}
})
} else { } else {
//1 //1
setSaleStoreList(firstList) // if (sessionState?.storeLvl === '1') {
} if (session?.storeLvl === '1') {
firstList = res
favList = res.filter((row) => row.priority !== 'B')
otherList = res.filter((row) => row.firstAgentYn === 'N')
let filterOtherList setSaleStoreList(firstList)
if (sessionState?.storeId === 'T01') { setFavoriteStoreList(firstList)
filterOtherList = otherList.filter((row) => row.firstAgentId === 'T01') setShowSaleStoreList(firstList)
setOriginOtherSaleStoreList(filterOtherList)
setOtherSaleStoreList(filterOtherList) setOtherSaleStoreList(otherList)
} else { } else {
//1 setSelOptions(res[0].saleStoreId)
setOriginOtherSaleStoreList(otherList) form.setValue('saleStoreId', res[0].saleStoreId)
setOtherSaleStoreList(otherList) form.setValue('saleStoreLevel', res[0].storeLvl)
setSaleStoreList(res)
setFavoriteStoreList(res)
setShowSaleStoreList(res)
otherList = res.filter((row) => row.firstAgentYn === 'N')
setOtherSaleStoreList(otherList)
}
} }
} }
@ -442,9 +513,6 @@ export default function StuffDetail() {
form.setValue('saleStoreId', detailData.saleStoreId) form.setValue('saleStoreId', detailData.saleStoreId)
form.setValue('saleStoreLevel', detailData.saleStoreLevel) form.setValue('saleStoreLevel', detailData.saleStoreLevel)
} else { } else {
setSelOptions(sessionState?.storeId)
form.setValue('saleStoreId', sessionState?.storeId)
form.setValue('saleStoreLevel', sessionState?.storeLvl)
setOtherSelOptions(detailData.saleStoreId) setOtherSelOptions(detailData.saleStoreId)
form.setValue('otherSaleStoreId', detailData.saleStoreId) form.setValue('otherSaleStoreId', detailData.saleStoreId)
form.setValue('otherSaleStoreLevel', detailData.saleStoreLevel) form.setValue('otherSaleStoreLevel', detailData.saleStoreLevel)
@ -504,7 +572,8 @@ export default function StuffDetail() {
form.setValue('remarks', detailData.remarks) form.setValue('remarks', detailData.remarks)
}) })
} }
}, [detailData, sessionState]) // }, [detailData, sessionState])
}, [detailData, session])
// //
const onChangeHonorificCode = (key) => { const onChangeHonorificCode = (key) => {
@ -574,6 +643,7 @@ export default function StuffDetail() {
if (objectNo) { if (objectNo) {
tempObjectNo = objectNo.substring(0, 1) tempObjectNo = objectNo.substring(0, 1)
} }
if (tempObjectNo === 'T') { if (tempObjectNo === 'T') {
if (planReqNo) { if (planReqNo) {
if (delFlg) { if (delFlg) {
@ -584,10 +654,21 @@ export default function StuffDetail() {
form.setValue('saleStoreName', key.saleStoreName) form.setValue('saleStoreName', key.saleStoreName)
form.setValue('saleStoreLevel', key.saleStoreLevel) form.setValue('saleStoreLevel', key.saleStoreLevel)
setSelOptions(key.saleStoreId) setSelOptions(key.saleStoreId)
// 1 2 list let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
//  let otherList
let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) get({ url: url }).then((res) => {
setOtherSaleStoreList(newOtherSaleStoreList) if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOtherSaleStoreList(otherList)
} else {
setOtherSaleStoreList([])
}
})
} else { } else {
//X //X
setSelOptions('') setSelOptions('')
@ -604,15 +685,34 @@ export default function StuffDetail() {
} }
} else { } else {
if (isObjectNotEmpty(key)) { if (isObjectNotEmpty(key)) {
setOtherSaleStoreList(otherSaleStoreList) setSelOptions(key.saleStoreId)
form.setValue('saleStoreId', key.saleStoreId) form.setValue('saleStoreId', key.saleStoreId)
form.setValue('saleStoreName', key.saleStoreName) form.setValue('saleStoreName', key.saleStoreName)
form.setValue('saleStoreLevel', key.saleStoreLevel) form.setValue('saleStoreLevel', key.saleStoreLevel)
setSelOptions(key.saleStoreId) // 1 2
// 1 2 list let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
//  let otherList
let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) get({ url: url }).then((res) => {
setOtherSaleStoreList(newOtherSaleStoreList) if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOtherSaleStoreList(otherList)
setOtherSelOptions('')
form.setValue('otherSaleStoreId', '')
form.setValue('otherSaleStoreName', '')
form.setValue('otherSaleStoreLevel', '')
} else {
setOtherSelOptions('')
form.setValue('otherSaleStoreId', '')
form.setValue('otherSaleStoreName', '')
form.setValue('otherSaleStoreLevel', '')
setOtherSaleStoreList([])
}
})
} else { } else {
//X //X
setSelOptions('') setSelOptions('')
@ -634,10 +734,21 @@ export default function StuffDetail() {
form.setValue('saleStoreName', key.saleStoreName) form.setValue('saleStoreName', key.saleStoreName)
form.setValue('saleStoreLevel', key.saleStoreLevel) form.setValue('saleStoreLevel', key.saleStoreLevel)
setSelOptions(key.saleStoreId) setSelOptions(key.saleStoreId)
// 1 2 list let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
//  let otherList
let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) get({ url: url }).then((res) => {
setOtherSaleStoreList(newOtherSaleStoreList) if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOtherSaleStoreList(otherList)
} else {
setOtherSaleStoreList([])
}
})
} else { } else {
//X //X
setSelOptions('') setSelOptions('')
@ -687,6 +798,7 @@ export default function StuffDetail() {
if (objectNo) { if (objectNo) {
tempObjectNo = objectNo.substring(0, 1) tempObjectNo = objectNo.substring(0, 1)
} }
if (tempObjectNo === 'T') { if (tempObjectNo === 'T') {
if (planReqNo) { if (planReqNo) {
if (delFlg) { if (delFlg) {
@ -1170,19 +1282,12 @@ export default function StuffDetail() {
//1 or 2 //1 or 2
if (params.saleStoreId == '') { if (params.saleStoreId == '') {
params.saleStoreId = sessionState.storeId // params.saleStoreId = sessionState.storeId
params.saleStoreLevel = sessionState.storeLvl params.saleStoreId = session.storeId
// params.saleStoreLevel = sessionState.storeLvl
params.saleStoreLevel = session.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'))
// }
await promisePost({ url: '/api/object/save-object', data: params }).then((res) => { await promisePost({ url: '/api/object/save-object', data: params }).then((res) => {
if (res.status === 201) { if (res.status === 201) {
alert(getMessage('stuff.detail.tempSave.message1')) alert(getMessage('stuff.detail.tempSave.message1'))
@ -1256,7 +1361,7 @@ export default function StuffDetail() {
)) || )) ||
null} null}
</div> </div>
<Button className="btn-origin grey" onPress={onSearchDesignRequestPopOpen}> <Button type="button" className="btn-origin grey" onPress={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
</Button> </Button>
</div> </div>
@ -1343,7 +1448,8 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="flx-box"> <div className="flx-box">
{(sessionState?.storeId === 'T01' && ( {/* {sessionState?.storeId === 'T01' && ( */}
{session?.storeId === 'T01' && (
<> <>
<div className="select-wrap mr5" style={{ width: '567px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
@ -1357,8 +1463,41 @@ export default function StuffDetail() {
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false} isClearable={true}
isDisabled={sessionState?.storeLvl !== '1' ? true : false} isDisabled={session?.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>
</>
)}
{/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl === '1' && ( */}
{session?.storeId !== 'T01' && session?.storeLvl === '1' && (
<>
<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[0]}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={false}
isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false}
value={showSaleStoreList.filter(function (option) { value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions return option.saleStoreId === selOptions
})} })}
@ -1374,7 +1513,9 @@ export default function StuffDetail() {
/> />
</div> </div>
</> </>
)) || ( )}
{/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl !== '1' && ( */}
{session?.storeId !== 'T01' && session?.storeLvl !== '1' && (
<> <>
<div className="select-wrap mr5" style={{ width: '567px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
@ -1383,13 +1524,13 @@ export default function StuffDetail() {
className="react-select-custom" className="react-select-custom"
classNamePrefix="custom" classNamePrefix="custom"
placeholder="Select" placeholder="Select"
options={saleStoreList} options={showSaleStoreList}
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false} isClearable={false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false} isDisabled={true}
value={saleStoreList.filter(function (option) { value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions return option.saleStoreId === selOptions
})} })}
></Select> ></Select>
@ -1432,8 +1573,8 @@ export default function StuffDetail() {
onChange={onSelectionChange2} onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true} isDisabled={otherSaleStoreList.length > 1 ? false : true}
isClearable={sessionState?.storeLvl === '1' ? true : false} isClearable={true}
value={otherSaleStoreList.filter(function (option) { value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions return option.saleStoreId === otherSelOptions
})} })}
@ -1688,7 +1829,7 @@ export default function StuffDetail() {
<div className="product-input-wrap mr5"> <div className="product-input-wrap mr5">
<input type="text" className="product-input" readOnly value={form.watch('planReqNo') || ''} /> <input type="text" className="product-input" readOnly value={form.watch('planReqNo') || ''} />
{/* {detailData?.tempFlg === '1' && form.watch('planReqNo') ? ( */} {/* {detailData?.tempFlg === '1' && form.watch('planReqNo') ? ( */}
{objectNo.substring(0, 1) === 'T' && form.watch('planReqNo') ? ( {detailData?.tempFlg === '1' && form.watch('planReqNo') ? (
<button <button
type="button" type="button"
className="product-delete" className="product-delete"
@ -1699,7 +1840,7 @@ export default function StuffDetail() {
) : null} ) : null}
</div> </div>
{/* {detailData?.tempFlg === '1' ? ( */} {/* {detailData?.tempFlg === '1' ? ( */}
{objectNo.substring(0, 1) === 'T' ? ( {detailData?.tempFlg === '1' ? (
<> <>
<Button className="btn-origin grey" onPress={onSearchDesignRequestPopOpen}> <Button className="btn-origin grey" onPress={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
@ -1790,10 +1931,12 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="flx-box"> <div className="flx-box">
{(sessionState?.storeId === 'T01' && ( {/* {sessionState?.storeId === 'T01' && ( */}
{session?.storeId === 'T01' && (
<> <>
<div className="select-wrap mr5" style={{ width: '567px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
menuPlacement={'auto'}
id="long-value-select1" id="long-value-select1"
instanceId="long-value-select1" instanceId="long-value-select1"
className="react-select-custom" className="react-select-custom"
@ -1804,8 +1947,10 @@ export default function StuffDetail() {
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false} // isClearable={sessionState?.storeLvl === '1' ? true : false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false} isClearable={session?.storeLvl === '1' ? true : false}
// isDisabled={sessionState?.storeLvl !== '1' ? true : false}
isDisabled={session?.storeLvl !== '1' ? true : false}
value={saleStoreList.filter(function (option) { value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions return option.saleStoreId === selOptions
})} })}
@ -1821,22 +1966,26 @@ export default function StuffDetail() {
/> />
</div> </div>
</> </>
)) || ( )}
{/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl === '1' && ( */}
{session?.storeId !== 'T01' && session?.storeLvl === '1' && (
<> <>
<div className="select-wrap mr5" style={{ width: '567px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
menuPlacement={'auto'}
id="long-value-select1" id="long-value-select1"
instanceId="long-value-select1" instanceId="long-value-select1"
className="react-select-custom" className="react-select-custom"
classNamePrefix="custom" classNamePrefix="custom"
placeholder="Select" placeholder="Select"
options={saleStoreList} options={showSaleStoreList[0]}
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isClearable={sessionState?.storeLvl === '1' ? true : false} isClearable={false}
isDisabled={sessionState?.storeLvl !== '1' ? true : false} // isDisabled={sessionState?.storeLvl !== '1' ? true : sessionState?.storeId !== 'T01' ? true : false}
value={saleStoreList.filter(function (option) { isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false}
value={showSaleStoreList.filter(function (option) {
return option.saleStoreId === selOptions return option.saleStoreId === selOptions
})} })}
/> />
@ -1852,6 +2001,41 @@ export default function StuffDetail() {
</div> </div>
</> </>
)} )}
{/* {sessionState?.storeId !== 'T01' && sessionState?.storeLvl !== '1' && ( */}
{session?.storeId !== 'T01' && session?.storeLvl !== '1' && (
<>
<div className="select-wrap mr5" style={{ width: '567px' }}>
<Select
menuPlacement={'auto'}
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={showSaleStoreList[0]}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isClearable={false}
isDisabled={true}
value={showSaleStoreList.filter(function (option) {
if (option.firstAgentYn === 'Y') {
return option.saleStoreId
}
})}
/>
</div>
<div className="input-wrap" style={{ width: '216px' }}>
<input
type="text"
className="input-light"
value={form.watch('saleStoreId') || ''}
{...form.register('saleStoreId')}
readOnly
/>
</div>
</>
)}
</div> </div>
</td> </td>
</tr> </tr>
@ -1878,8 +2062,10 @@ export default function StuffDetail() {
onChange={onSelectionChange2} onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true} // isDisabled={sessionState?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true}
isClearable={sessionState?.storeLvl === '1' ? true : false} isDisabled={session?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true}
// isClearable={sessionState?.storeLvl === '1' ? true : false}
isClearable={session?.storeLvl === '1' ? true : false}
value={otherSaleStoreList.filter(function (option) { value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSelOptions return option.saleStoreId === otherSelOptions
})} })}
@ -2112,7 +2298,7 @@ export default function StuffDetail() {
</div> </div>
</div> </div>
{/* {detailData?.tempFlg === '0' ? ( */} {/* {detailData?.tempFlg === '0' ? ( */}
{objectNo.substring(0, 1) !== 'T' ? ( {detailData?.tempFlg === '0' ? (
<> <>
{/* 진짜R 플랜시작 */} {/* 진짜R 플랜시작 */}
<div className="table-box-title-wrap"> <div className="table-box-title-wrap">

View File

@ -1,8 +1,8 @@
'use client' 'use client'
import React, { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState, useContext } from 'react'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import { appMessageStore, globalLocaleStore } from '@/store/localeAtom'
import Select from 'react-select' import Select from 'react-select'
import KO from '@/locales/ko.json' import KO from '@/locales/ko.json'
@ -15,12 +15,17 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
import { SessionContext } from '@/app/SessionProvider'
export default function StuffSearchCondition() { export default function StuffSearchCondition() {
const { session } = useContext(SessionContext)
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) const setAppMessageState = useSetRecoilState(appMessageStore)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const ref = useRef() const ref = useRef()
const ref2 = useRef()
const { get } = useAxios(globalLocaleState) const { get } = useAxios(globalLocaleState)
const objectNoRef = useRef(null) const objectNoRef = useRef(null)
@ -59,6 +64,10 @@ export default function StuffSearchCondition() {
const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT const [schSelSaleStoreList, setSchSelSaleStoreList] = useState([]) // SELECT
const [favoriteStoreList, setFavoriteStoreList] = useState([]) // const [favoriteStoreList, setFavoriteStoreList] = useState([]) //
const [showSaleStoreList, setShowSaleStoreList] = useState([]) // const [showSaleStoreList, setShowSaleStoreList] = useState([]) //
const [otherSaleStoreList, setOtherSaleStoreList] = useState([]) //1
const [otherSaleStoreId, setOtherSaleStoreId] = useState('')
// //
const onSubmit = () => { const onSubmit = () => {
let diff = dayjs(endDate).diff(startDate, 'day') let diff = dayjs(endDate).diff(startDate, 'day')
@ -68,14 +77,14 @@ export default function StuffSearchCondition() {
if (stuffSearch.code === 'S') { if (stuffSearch.code === 'S') {
setStuffSearch({ setStuffSearch({
schObjectNo: objectNo ? objectNo : stuffSearch?.schObjectNo, schObjectNo: objectNo ? objectNo : stuffSearch.schObjectNo,
schSaleStoreName: stuffSearch?.schSaleStoreName ? stuffSearch?.schSaleStoreName : saleStoreName, schSaleStoreName: saleStoreName ? saleStoreName : '',
schAddress: address ? address : stuffSearch?.schAddress, schAddress: address ? address : '',
schObjectName: objectName ? objectName : stuffSearch?.schObjectName, schObjectName: objectName ? objectName : '',
schDispCompanyName: dispCompanyName ? dispCompanyName : stuffSearch?.schDispCompanyName, schDispCompanyName: dispCompanyName ? dispCompanyName : '',
schSelSaleStoreId: stuffSearch?.schSelSaleStoreId ? stuffSearch.schSelSaleStoreId : schSelSaleStoreId, schSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : stuffSearch.schSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser : stuffSearch?.schReceiveUser, schReceiveUser: receiveUser ? receiveUser : '',
schDateType: stuffSearch?.schDateType ? stuffSearch.schDateType : dateType, schDateType: dateType,
schFromDt: dayjs(startDate).format('YYYY-MM-DD'), schFromDt: dayjs(startDate).format('YYYY-MM-DD'),
schToDt: dayjs(endDate).format('YYYY-MM-DD'), schToDt: dayjs(endDate).format('YYYY-MM-DD'),
code: 'E', code: 'E',
@ -90,7 +99,7 @@ export default function StuffSearchCondition() {
schAddress: address ? address : '', schAddress: address ? address : '',
schObjectName: objectName ? objectName : '', schObjectName: objectName ? objectName : '',
schDispCompanyName: dispCompanyName ? dispCompanyName : '', schDispCompanyName: dispCompanyName ? dispCompanyName : '',
schSelSaleStoreId: schSelSaleStoreId ? schSelSaleStoreId : '', schSelSaleStoreId: stuffSearch?.schOtherSelSaleStoreId ? stuffSearch.schOtherSelSaleStoreId : stuffSearch.schSelSaleStoreId,
schReceiveUser: receiveUser ? receiveUser : '', schReceiveUser: receiveUser ? receiveUser : '',
schDateType: dateType, schDateType: dateType,
schFromDt: dayjs(startDate).format('YYYY-MM-DD'), schFromDt: dayjs(startDate).format('YYYY-MM-DD'),
@ -105,6 +114,7 @@ export default function StuffSearchCondition() {
// //
const resetRecoil = () => { const resetRecoil = () => {
//T01
objectNoRef.current.value = '' objectNoRef.current.value = ''
saleStoreNameRef.current.value = '' saleStoreNameRef.current.value = ''
addressRef.current.value = '' addressRef.current.value = ''
@ -121,49 +131,158 @@ export default function StuffSearchCondition() {
setDateType('U') setDateType('U')
setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')) setStartDate(dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'))
setEndDate(dayjs(new Date()).format('YYYY-MM-DD')) setEndDate(dayjs(new Date()).format('YYYY-MM-DD'))
setSchSelSaleStoreId('') // if (sessionState?.storeId === 'T01') {
handleClear() // if (session?.storeId === 'T01') {
resetStuffRecoil() setSchSelSaleStoreId('')
handleClear1() //
resetStuffRecoil()
setStuffSearch({
...stuffSearch,
code: 'C',
schSelSaleStoreId: '',
schOtherSelSaleStoreId: '',
})
} else {
if (otherSaleStoreList.length > 1) {
handleClear2()
setOtherSaleStoreId('')
stuffSearch.schObjectNo = ''
stuffSearch.schDateType = 'U'
} else {
stuffSearch.schObjectNo = ''
stuffSearch.schDateType = 'U'
}
}
} }
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(sessionState)) { // if (isObjectNotEmpty(sessionState)) {
// storeId T01 1 if (isObjectNotEmpty(session)) {
// storeId T01 storeLvl 1
let url let url
if (sessionState?.storeId === 'T01') { // if (sessionState?.storeId === 'T01') {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=an1` if (session?.storeId === 'T01') {
url = `/api/object/saleStore/${sessionState?.storeId}/list?userId=${sessionState?.userId}` //T01
// url = `/api/object/saleStore/${sessionState?.storeId}/firstList?userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/firstList?userId=${session?.userId}`
} else { } else {
url = `/api/object/saleStore/${sessionState?.storeId}/list` // if (sessionState.storeLvl === '1') {
if (session.storeLvl === '1') {
//T01 1
// url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
} else {
// url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=1&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=1&userId=${session?.userId}`
}
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
res.map((row) => { res.map((row) => {
row.value = row.saleStoreId row.value = row.saleStoreId
row.label = row.saleStoreName row.label = row.saleStoreName
}) })
const allList = res
const favList = res.filter((row) => row.priority !== 'B')
setSchSelSaleStoreList(allList) let allList
setFavoriteStoreList(favList) let favList
setShowSaleStoreList(favList) let otherList
// if (sessionState?.storeId === 'T01') {
if (session?.storeId === 'T01') {
allList = res
allList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = res.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
setSchSelSaleStoreList(allList)
setFavoriteStoreList(favList)
setShowSaleStoreList(favList)
// setSchSelSaleStoreId(sessionState?.storeId)
setSchSelSaleStoreId(session?.storeId)
setStuffSearch({
...stuffSearch,
code: 'S',
// schSelSaleStoreId: sessionState?.storeId,
schSelSaleStoreId: session?.storeId,
})
//T01 2 1 storeId
// url = `/api/object/saleStore/${sessionState?.storeId}/list?firstFlg=0&userId=${sessionState?.userId}`
url = `/api/object/saleStore/${session?.storeId}/list?firstFlg=0&userId=${session?.userId}`
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOtherSaleStoreList(otherList)
} else {
setOtherSaleStoreList([])
}
})
} else {
// if (sessionState?.storeLvl === '1') {
if (session?.storeLvl === '1') {
allList = res
favList = res.filter((row) => row.priority !== 'B')
otherList = res.filter((row) => row.firstAgentYn === 'N')
setSchSelSaleStoreList(allList)
setFavoriteStoreList(allList)
setShowSaleStoreList(allList)
setSchSelSaleStoreId(allList[0].saleStoreId)
setOtherSaleStoreList(otherList)
setStuffSearch({
...stuffSearch,
code: 'S',
schSelSaleStoreId: allList[0].saleStoreId,
})
} else {
//10X22, 201X112 2
//2 34 202X217
setSchSelSaleStoreList(res)
setFavoriteStoreList(res)
setShowSaleStoreList(res)
setSchSelSaleStoreId(res[0].saleStoreId)
otherList = res.filter((row) => row.firstAgentYn === 'N')
setOtherSaleStoreList(otherList)
// 2
// setOtherSaleStoreId(sessionState?.storeId)
setOtherSaleStoreId(session?.storeId)
setStuffSearch({
...stuffSearch,
code: 'S',
schSelSaleStoreId: otherList[0].saleStoreId,
})
}
}
} }
}) })
} }
}, [sessionState]) // }, [sessionState])
}, [session])
// .. // 1 ..
const handleClear = () => { const handleClear1 = () => {
if (ref.current) { if (ref.current) {
ref.current.clearValue() ref.current.clearValue()
} }
} }
const handleClear2 = () => {
if (ref2.current) {
ref2.current.clearValue()
}
}
// //
const onInputChange = (key) => { const onInputChange = (key) => {
if (key !== '') { if (key !== '') {
setShowSaleStoreList(schSelSaleStoreList) setShowSaleStoreList(schSelSaleStoreList)
setOtherSaleStoreList([])
} else { } else {
setShowSaleStoreList(favoriteStoreList) setShowSaleStoreList(favoriteStoreList)
} }
@ -172,15 +291,48 @@ export default function StuffSearchCondition() {
// //
const onSelectionChange = (key) => { const onSelectionChange = (key) => {
if (isObjectNotEmpty(key)) { if (isObjectNotEmpty(key)) {
setOtherSaleStoreId('')
setSchSelSaleStoreId(key.saleStoreId) setSchSelSaleStoreId(key.saleStoreId)
setStuffSearch({ stuffSearch.schSelSaleStoreId = key.saleStoreId
...stuffSearch, //T01 1
code: 'S', // 1 saleStoreId 2 API
schSelSaleStoreId: key.saleStoreId, // let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${sessionState?.userId}`
let url = `/api/object/saleStore/${key.saleStoreId}/list?firstFlg=0&userId=${session?.userId}`
let otherList
get({ url: url }).then((res) => {
if (!isEmptyArray(res)) {
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
otherList = res
setOtherSaleStoreList(otherList)
} else {
setOtherSaleStoreList([])
}
}) })
} else { } else {
//X
setSchSelSaleStoreId('') setSchSelSaleStoreId('')
setStuffSearch({ ...stuffSearch, schSelSaleStoreId: '' }) stuffSearch.schSelSaleStoreId = ''
//2
setOtherSaleStoreList([])
}
}
//2
const onSelectionChange2 = (key) => {
if (isObjectNotEmpty(key)) {
setOtherSaleStoreId(key.saleStoreId)
stuffSearch.schOtherSelSaleStoreId = key.saleStoreId
} else {
//X 1
setOtherSaleStoreId('')
setSchSelSaleStoreId(schSelSaleStoreId)
stuffSearch.schOtherSelSaleStoreId = ''
stuffSearch.schSelSaleStoreId = schSelSaleStoreId
} }
} }
@ -200,6 +352,7 @@ export default function StuffSearchCondition() {
// //
const handleByOnKeyUp = (e) => { const handleByOnKeyUp = (e) => {
if (e.key === 'Enter') { if (e.key === 'Enter') {
stuffSearch.code = 'E'
onSubmit() onSubmit()
} }
} }
@ -235,6 +388,8 @@ export default function StuffSearchCondition() {
<col /> <col />
<col style={{ width: '160px' }} /> <col style={{ width: '160px' }} />
<col /> <col />
<col style={{ width: '160px' }} />
<col />
</colgroup> </colgroup>
<tbody> <tbody>
<tr> <tr>
@ -245,7 +400,7 @@ export default function StuffSearchCondition() {
type="text" type="text"
ref={objectNoRef} ref={objectNoRef}
className="input-light" className="input-light"
defaultValue={stuffSearch.code === 'E' || stuffSearch.code === 'M' ? stuffSearch?.schObjectNo : objectNo} defaultValue={stuffSearch?.schObjectNo ? stuffSearch.schObjectNo : objectNo}
onChange={(e) => { onChange={(e) => {
setObjectNo(objectNoRef.current.value) setObjectNo(objectNoRef.current.value)
}} }}
@ -260,7 +415,7 @@ export default function StuffSearchCondition() {
type="text" type="text"
ref={saleStoreNameRef} ref={saleStoreNameRef}
className="input-light" className="input-light"
defaultValue={stuffSearch.code === 'E' ? stuffSearch?.schSaleStoreName : saleStoreName} defaultValue={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName}
onChange={(e) => { onChange={(e) => {
setSaleStoreName(saleStoreNameRef.current.value) setSaleStoreName(saleStoreNameRef.current.value)
}} }}
@ -275,7 +430,7 @@ export default function StuffSearchCondition() {
type="text" type="text"
ref={addressRef} ref={addressRef}
className="input-light" className="input-light"
defaultValue={stuffSearch.code === 'E' ? stuffSearch?.schAddress : address} defaultValue={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
onChange={(e) => { onChange={(e) => {
setAddress(addressRef.current.value) setAddress(addressRef.current.value)
}} }}
@ -283,6 +438,21 @@ export default function StuffSearchCondition() {
/> />
</div> </div>
</td> </td>
<th>{getMessage('stuff.search.schDispCompanyName')}</th>
<td>
<div className="input-wrap">
<input
type="text"
ref={dispCompanyNameRef}
className="input-light"
defaultValue={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName}
onChange={(e) => {
setDispCompanyName(dispCompanyNameRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
</tr> </tr>
<tr> <tr>
<th>{getMessage('stuff.search.schObjectName')}</th> <th>{getMessage('stuff.search.schObjectName')}</th>
@ -292,7 +462,7 @@ export default function StuffSearchCondition() {
type="text" type="text"
ref={objectNameRef} ref={objectNameRef}
className="input-light" className="input-light"
defaultValue={stuffSearch.code === 'E' ? stuffSearch?.schObjectName : objectName} defaultValue={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName}
onChange={(e) => { onChange={(e) => {
setobjectName(objectNameRef.current.value) setobjectName(objectNameRef.current.value)
}} }}
@ -300,63 +470,6 @@ export default function StuffSearchCondition() {
/> />
</div> </div>
</td> </td>
<th>{getMessage('stuff.search.schDispCompanyName')}</th>
<td>
<div className="input-wrap">
<input
type="text"
ref={dispCompanyNameRef}
className="input-light"
defaultValue={stuffSearch.code === 'E' ? stuffSearch?.schDispCompanyName : dispCompanyName}
onChange={(e) => {
setDispCompanyName(dispCompanyNameRef.current.value)
}}
onKeyUp={handleByOnKeyUp}
/>
</div>
</td>
<th>{getMessage('stuff.search.schSelSaleStoreId')}</th>
<td>
<div className="select-wrap">
{schSelSaleStoreList?.length > 0 && (
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
// options={schSelSaleStoreList}
options={showSaleStoreList}
onInputChange={onInputChange}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
// 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 !== '') {
return option.saleStoreId === schSelSaleStoreId
} else if (stuffSearch?.code === 'E' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else {
if (stuffSearch?.schSelSaleStoreId !== '') {
return option.saleStoreId === stuffSearch.schSelSaleStoreId
} else {
return false
}
}
})}
isDisabled={sessionState?.storeLvl === '1' ? false : true}
isClearable={true}
/>
)}
</div>
</td>
</tr>
<tr>
<th>{getMessage('stuff.search.schReceiveUser')}</th> <th>{getMessage('stuff.search.schReceiveUser')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
@ -364,7 +477,7 @@ export default function StuffSearchCondition() {
type="text" type="text"
className="input-light" className="input-light"
ref={receiveUserRef} ref={receiveUserRef}
defaultValue={stuffSearch.code === 'E' ? stuffSearch?.schReceiveUser : receiveUser} defaultValue={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser}
onChange={(e) => { onChange={(e) => {
setReceiveUser(receiveUserRef.current.value) setReceiveUser(receiveUserRef.current.value)
}} }}
@ -372,8 +485,130 @@ export default function StuffSearchCondition() {
/> />
</div> </div>
</td> </td>
<th>{getMessage('stuff.search.period')}</th> <th>{getMessage('stuff.search.schSelSaleStoreId')}</th>
<td colSpan={3}> <td colSpan={3}>
<div className="form-flex-wrap">
<div className="select-wrap mr5" style={{ flex: 1 }}>
{session?.storeId === 'T01' && (
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={showSaleStoreList}
onInputChange={onInputChange}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
value={schSelSaleStoreList.filter(function (option) {
if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') {
return false
} else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else if (stuffSearch?.code === 'E' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else {
if (stuffSearch?.schSelSaleStoreId !== '') {
return option.saleStoreId === stuffSearch.schSelSaleStoreId
} else {
return false
}
}
})}
isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false}
isClearable={true}
/>
)}
{session?.storeId !== 'T01' && session?.storeLvl === '1' && (
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={showSaleStoreList[0]}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
value={showSaleStoreList.filter(function (option) {
if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') {
return false
} else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else if (stuffSearch?.code === 'E' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else {
if (stuffSearch?.schSelSaleStoreId !== '') {
return option.saleStoreId === stuffSearch.schSelSaleStoreId
} else {
return false
}
}
})}
isDisabled={session?.storeLvl !== '1' ? true : session?.storeId !== 'T01' ? true : false}
isClearable={false}
/>
)}
{session?.storeId !== 'T01' && session?.storeLvl !== '1' && (
<Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref}
options={showSaleStoreList[0]}
onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
value={showSaleStoreList.filter(function (option) {
if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') {
return false
} else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else if (stuffSearch?.code === 'E' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else {
if (stuffSearch?.schSelSaleStoreId !== '') {
return option.saleStoreId === stuffSearch.schSelSaleStoreId
} else {
return false
}
}
})}
isDisabled={true}
isClearable={false}
/>
)}
</div>
<div className="select-wrap" style={{ flex: 1 }}>
<Select
id="long-value-select2"
instanceId="long-value-select2"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref2}
options={otherSaleStoreList}
onChange={onSelectionChange2}
getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId}
isDisabled={otherSaleStoreList.length > 1 ? false : true}
isClearable={true}
value={otherSaleStoreList.filter(function (option) {
return option.saleStoreId === otherSaleStoreId
})}
/>
</div>
</div>
</td>
</tr>
<tr>
<th>{getMessage('stuff.search.period')}</th>
<td colSpan={7}>
<div className="form-flex-wrap"> <div className="form-flex-wrap">
<div className="radio-wrap mr10"> <div className="radio-wrap mr10">
<div className="d-check-radio light mr10"> <div className="d-check-radio light mr10">
@ -381,11 +616,11 @@ export default function StuffSearchCondition() {
type="radio" type="radio"
name="radio_ptype" name="radio_ptype"
id="radio_u" id="radio_u"
checked={stuffSearch?.schDateType === 'U' ? true : false} checked={dateType === 'U' ? true : false}
value={'U'} value={'U'}
onChange={(e) => { onChange={(e) => {
setDateType(e.target.value) setDateType(e.target.value)
setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value }) //setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value })
}} }}
/> />
<label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label> <label htmlFor="radio_u">{getMessage('stuff.search.schDateTypeU')}</label>
@ -395,11 +630,11 @@ export default function StuffSearchCondition() {
type="radio" type="radio"
name="radio_ptype" name="radio_ptype"
id="radio_r" id="radio_r"
checked={stuffSearch?.schDateType === 'R' ? true : false} checked={dateType === 'R' ? true : false}
value={'R'} value={'R'}
onChange={(e) => { onChange={(e) => {
setDateType(e.target.value) setDateType(e.target.value)
setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value }) //setStuffSearch({ ...stuffSearch, code: 'S', schDateType: e.target.value })
}} }}
/> />
<label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label> <label htmlFor="radio_r">{getMessage('stuff.search.schDateTypeR')}</label>

View File

@ -7,7 +7,7 @@ import { useMessage } from '@/hooks/useMessage'
import { useRouter, useSearchParams } from 'next/navigation' import { useRouter, useSearchParams } from 'next/navigation'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom' import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { useSetRecoilState } from 'recoil' import { useSetRecoilState } from 'recoil'
import { queryStringFormatter } from '@/util/common-utils'
export default function StuffSubHeader({ type }) { export default function StuffSubHeader({ type }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const router = useRouter() const router = useRouter()
@ -25,8 +25,13 @@ export default function StuffSubHeader({ type }) {
const moveFloorPlan = () => { const moveFloorPlan = () => {
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo }) setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
// const param = {
router.push('/floor-plan/estimate/5/1') pid: '1',
}
//
const url = `/floor-plan?${queryStringFormatter(param)}`
console.log(url)
router.push(url)
} }
return ( return (
@ -88,7 +93,7 @@ export default function StuffSubHeader({ type }) {
<li className="title-item"> <li className="title-item">
<a className="sub-header-title" onClick={moveFloorPlan}> <a className="sub-header-title" onClick={moveFloorPlan}>
<span className="icon drawing"></span> <span className="icon drawing"></span>
{getMessage('plan.menu.plan.drawing')} {getMessage('stuff.temp.subTitle2')}
</a> </a>
</li> </li>
</ul> </ul>

View File

@ -59,7 +59,8 @@ export function useCanvasConfigInitialize() {
const canvasLoadInit = () => { const canvasLoadInit = () => {
roofInit() //화면표시 초기화 roofInit() //화면표시 초기화
groupInit() groupDimensionInit()
reGroupInit() //그룹 객체 재그룹
} }
const gridInit = () => { const gridInit = () => {
@ -95,10 +96,12 @@ export function useCanvasConfigInitialize() {
}) })
} }
const groupInit = () => { const groupDimensionInit = () => {
const groups = canvas.getObjects().filter((obj) => obj.groupYn) const groups = canvas.getObjects().filter((obj) => obj.groupYn && obj.name === 'dimensionGroup')
const groupIds = [] const groupIds = []
console.log('groupDimensionInit', groups)
groups.forEach((group) => { groups.forEach((group) => {
if (!groupIds.includes(group.id)) { if (!groupIds.includes(group.id)) {
groupIds.push(group.id) groupIds.push(group.id)
@ -138,5 +141,50 @@ export function useCanvasConfigInitialize() {
}) })
} }
const reGroupInit = () => {
const excludeObjects = ['dimensionGroup', 'dimensionLineText']
const groups = canvas.getObjects().filter((obj) => obj.groupYn && !obj.name.includes(excludeObjects))
const groupIds = []
groups.forEach((group) => {
if (!groupIds.includes(group.groupId)) {
groupIds.push(group.groupId)
}
})
groupIds.forEach((id) => {
//그룹아이디로 캔버스의 객체를 조회함
const groupObjects = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)
const objectsName = canvas.getObjects().filter((obj) => obj.groupId === id || obj.id === id)[0].groupName
let objectArray = []
//그룹객체가 있으면 배열에 추가함
if (groupObjects) {
groupObjects.forEach((obj) => {
objectArray.push(obj)
})
}
//그룹객체를 캔버스에서 제거함
objectArray.forEach((obj) => {
canvas?.remove(obj)
})
//그룹 객체로 다시 만든다 (좌표때문에)
const group = new fabric.Group(objectArray, {
groupId: id,
name: objectsName,
selectable: true,
lockMovementX: true,
lockMovementY: true,
originX: 'center',
originY: 'center',
})
canvas.add(group)
})
}
return { canvasLoadInit, gridInit } return { canvasLoadInit, gridInit }
} }

View File

@ -20,7 +20,6 @@ export function useCommonUtils() {
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup() const { addPopup } = usePopup()
useEffect(() => { useEffect(() => {
@ -278,7 +277,7 @@ export function useCommonUtils() {
groupObjects.push(distanceText) groupObjects.push(distanceText)
const group = new fabric.Group(groupObjects, { const group = new fabric.Group(groupObjects, {
name: 'dimensionLine', name: 'dimensionGroup',
selectable: true, selectable: true,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
@ -522,10 +521,10 @@ export function useCommonUtils() {
if (object) { if (object) {
canvas?.remove(object) canvas?.remove(object)
if (object.id) { // if (object.id) {
const group = canvas.getObjects().filter((obj) => obj.id === object.id) // const group = canvas.getObjects().filter((obj) => obj.id === object.id)
group.forEach((obj) => canvas?.remove(obj)) // group.forEach((obj) => canvas?.remove(obj))
} // }
} }
} }
@ -547,7 +546,7 @@ export function useCommonUtils() {
initEvent() initEvent()
obj.setCoords() obj.setCoords()
updateGroupObjectCoords(obj, originLeft, originTop) updateGroupObjectCoords(obj, originLeft, originTop)
// canvas?.renderAll() canvas?.renderAll()
}) })
} }
} }
@ -585,6 +584,10 @@ export function useCommonUtils() {
editable: false, editable: false,
id: uuidv4(), //복사된 객체라 새로 따준다 id: uuidv4(), //복사된 객체라 새로 따준다
}) })
//객체가 그룹일 경우에는 그룹 아이디를 따로 넣어준다
if (clonedObj.type === 'group') clonedObj.set({ groupId: uuidv4() })
initEvent() initEvent()
}) })
} }
@ -720,41 +723,82 @@ export function useCommonUtils() {
} }
// 그룹 이동 시 라인 및 각 객체의 좌표를 절대 좌표로 업데이트하는 함수 // 그룹 이동 시 라인 및 각 객체의 좌표를 절대 좌표로 업데이트하는 함수
function updateGroupObjectCoords(group, originLeft, originTop) { function updateGroupObjectCoords(targetObj, originLeft, originTop) {
const diffrenceLeft = group.left - originLeft const diffrenceLeft = targetObj.left - originLeft
const diffrenceTop = group.top - originTop const diffrenceTop = targetObj.top - originTop
group.getObjects().forEach((obj) => { if (targetObj.type === 'group') {
// 그룹 내 객체의 절대 좌표를 계산 targetObj.getObjects().forEach((obj) => {
// 그룹 내 객체의 절대 좌표를 계산
const originObjLeft = obj.left const originObjLeft = obj.left
const originObjTop = obj.top const originObjTop = obj.top
if (obj.type === 'line') { if (obj.type === 'line') {
// Line 객체의 경우, x1, y1, x2, y2 절대 좌표 계산 // Line 객체의 경우, x1, y1, x2, y2 절대 좌표 계산
obj.set({ obj.set({
x1: obj.x1 + diffrenceLeft, x1: obj.x1 + diffrenceLeft,
y1: obj.y1 + diffrenceTop, y1: obj.y1 + diffrenceTop,
x2: obj.x2 + diffrenceLeft, x2: obj.x2 + diffrenceLeft,
y2: obj.y2 + diffrenceTop, y2: obj.y2 + diffrenceTop,
}) })
obj.set({ obj.set({
left: originObjLeft, left: originObjLeft,
top: originObjTop, top: originObjTop,
}) })
} else { obj.fire('modified')
// 다른 객체의 경우 left, top 절대 좌표 설정 } else {
obj.set({ // 다른 객체의 경우 left, top 절대 좌표 설정
...obj, obj.set({
left: obj.left, left: obj.left,
top: obj.top, top: obj.top,
}) })
obj.fire('modified')
}
obj.setCoords() // 좌표 반영
})
} else {
if (targetObj.type === 'line') {
const originObjLeft = obj.left
const originObjTop = obj.top
if (obj.type === 'line') {
// Line 객체의 경우, x1, y1, x2, y2 절대 좌표 계산
obj.set({
x1: obj.x1 + diffrenceLeft,
y1: obj.y1 + diffrenceTop,
x2: obj.x2 + diffrenceLeft,
y2: obj.y2 + diffrenceTop,
})
obj.set({
left: originObjLeft,
top: originObjTop,
})
obj.fire('modified')
} else {
targetObj.set({
...targetObj,
left: targetObj.left,
top: targetObj.top,
})
obj.fire('modified')
}
targetObj.setCoords()
} }
obj.setCoords() // 좌표 반영
canvas?.renderAll() canvas?.renderAll()
}) }
}
const deleteOuterLineObject = () => {
const selectedOuterLine = canvas.getActiveObject()
if (selectedOuterLine && selectedOuterLine.name === 'outerLine') {
canvas.remove(selectedOuterLine)
canvas.renderAll()
}
} }
return { return {
@ -767,5 +811,6 @@ export function useCommonUtils() {
copyObject, copyObject,
editText, editText,
changeDimensionExtendLine, changeDimensionExtendLine,
deleteOuterLineObject,
} }
} }

View File

@ -1,4 +1,5 @@
'use client' 'use client'
import { useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
@ -9,6 +10,8 @@ import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { usePolygon } from '@/hooks/usePolygon' import { usePolygon } from '@/hooks/usePolygon'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import { v4 as uuidv4 } from 'uuid'
import { fontSelector } from '@/store/fontAtom'
export function useObjectBatch({ isHidden, setIsHidden }) { export function useObjectBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -16,6 +19,48 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const { addCanvasMouseEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, initEvent } = useEvent()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
useEffect(() => {
if (canvas) {
dbClickEvent()
}
return () => {
initEvent()
if (canvas) canvas.off('mouse:dblclick')
}
}, [])
const dbClickEvent = () => {
const dormerObject = canvas.getObjects().filter((obj) => obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER)
if (dormerObject) {
canvas.on('mouse:dblclick', (e) => {
if (e.target && e.target instanceof fabric.Group) {
const pointer = canvas.getPointer(e.e)
const objects = e.target._objects
// 클릭한 위치에 있는 객체 찾기
const clickedObject = objects.find((obj) => {
if (obj.type === 'QPolygon') {
const polygon = pointsToTurfPolygon(obj.getCurrentPoints())
const turfPointer = turf.point([pointer.x, pointer.y])
return turf.booleanPointInPolygon(turfPointer, polygon)
} else {
return obj.containsPoint(pointer)
}
})
if (clickedObject) {
// 클릭된 객체 선택
canvas.setActiveObject(clickedObject)
canvas.renderAll()
}
}
})
}
}
const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => { const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => {
const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value
@ -232,6 +277,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
: 0 : 0
const directionRef = dormerPlacement.directionRef.current const directionRef = dormerPlacement.directionRef.current
let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
const id = uuidv4()
if (height === '' || pitch === '' || height <= 0 || pitch <= 0) { if (height === '' || pitch === '' || height <= 0 || pitch <= 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' }) swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
@ -310,6 +356,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
originX: 'center', originX: 'center',
originY: 'top', originY: 'top',
angle: angle, angle: angle,
objectId: id,
}) })
canvas?.add(dormerOffset) canvas?.add(dormerOffset)
} }
@ -322,7 +369,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//지붕 밖으로 그렸을때 //지붕 밖으로 그렸을때
if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) { if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) swalFire({ text: '도머를 배치할 수 없습니다.', icon: 'error' })
//일단 지워 //일단 지워
deleteTempObjects() deleteTempObjects()
return return
@ -358,7 +405,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}) //오프셋이 있을땐 같이 도머로 만든다 }) //오프셋이 있을땐 같이 도머로 만든다
const leftTriangle = new QPolygon(splitedTriangle[0], { const leftTriangle = new QPolygon(splitedTriangle[0], {
fill: 'transparent', fill: 'white',
stroke: 'black', stroke: 'black',
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,
@ -366,16 +413,18 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
lockMovementY: true, // Y 축 이동 잠금 lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금 lockRotation: true, // 회전 잠금
viewLengthText: true, viewLengthText: true,
fontSize: 14,
direction: direction, direction: direction,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: dormerName, name: dormerName,
pitch: pitch, pitch: pitch,
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
}) })
const rightTriangle = new QPolygon(splitedTriangle[1], { const rightTriangle = new QPolygon(splitedTriangle[1], {
fill: 'transparent', fill: 'white',
stroke: 'black', stroke: 'black',
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,
@ -383,26 +432,63 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
lockMovementY: true, // Y 축 이동 잠금 lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금 lockRotation: true, // 회전 잠금
viewLengthText: true, viewLengthText: true,
fontSize: 14,
direction: direction, direction: direction,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: dormerName, name: dormerName,
pitch: pitch, pitch: pitch,
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
}) })
canvas?.add(leftTriangle) // canvas?.add(leftTriangle)
canvas?.add(rightTriangle) // canvas?.add(rightTriangle)
//패턴 //패턴
setSurfaceShapePattern(leftTriangle) setSurfaceShapePattern(leftTriangle)
setSurfaceShapePattern(rightTriangle) setSurfaceShapePattern(rightTriangle)
//방향 //방향
drawDirectionArrow(leftTriangle) drawDirectionArrow(leftTriangle)
drawDirectionArrow(rightTriangle) drawDirectionArrow(rightTriangle)
let offsetPolygon
if (offsetRef > 0) {
canvas?.remove(dormer)
offsetPolygon = new QPolygon(triangleToPolygon(dormer), {
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
name: 'triangleDormerOffset',
id: id,
fill: 'rgba(255, 255, 255, 0.6)',
stroke: 'black',
strokeWidth: 1,
originX: 'center',
originY: 'center',
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
})
}
const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle]
const objectGroup = new fabric.Group(groupPolygon, {
subTargetCheck: true,
name: dormerName,
id: id,
})
canvas?.add(objectGroup)
isDown = false isDown = false
initEvent() initEvent()
dbClickEvent()
if (setIsHidden) setIsHidden(false) if (setIsHidden) setIsHidden(false)
} }
}) })
@ -498,8 +584,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
//지붕 밖으로 그렸을때 //지붕 밖으로 그렸을때
if (!turf.booleanWithin(pentagonPolygon, selectedSurfacePolygon)) { if (!turf.booleanWithin(pentagonPolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) swalFire({ text: '도머를 배치할 수 없습니다.', icon: 'error' })
//일단 지워 //일단 지워
deleteTempObjects() deleteTempObjects()
return return
@ -568,8 +653,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
pitch: pitch, pitch: pitch,
}) })
canvas?.add(leftPentagon) // canvas?.add(leftPentagon)
canvas?.add(rightPentagon) // canvas?.add(rightPentagon)
//패턴 //패턴
setSurfaceShapePattern(leftPentagon) setSurfaceShapePattern(leftPentagon)
@ -578,8 +663,43 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
drawDirectionArrow(leftPentagon) drawDirectionArrow(leftPentagon)
drawDirectionArrow(rightPentagon) drawDirectionArrow(rightPentagon)
let offsetPolygon
if (offsetRef > 0) {
canvas?.remove(dormer)
offsetPolygon = new QPolygon(dormer.points, {
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
name: 'pentagonDormerOffset',
id: id,
fill: 'rgba(255, 255, 255, 0.6)',
stroke: 'black',
strokeWidth: 1,
originX: 'center',
originY: 'center',
fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value,
})
}
const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon]
const objectGroup = new fabric.Group(groupPolygon, {
subTargetCheck: true,
name: dormerName,
id: id,
})
canvas?.add(objectGroup)
isDown = false isDown = false
initEvent() initEvent()
dbClickEvent()
if (setIsHidden) setIsHidden(false) if (setIsHidden) setIsHidden(false)
} }
}) })
@ -656,7 +776,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height }, { x: triangle.left + triangle.height, y: triangle.top - triangle.height },
] ]
} }
return [leftPoints, rightPoints] return [leftPoints, rightPoints]
} }
@ -739,10 +858,124 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
return [leftPoints, rightPoints] return [leftPoints, rightPoints]
} }
const reSizeObjectBatch = (side, target, width, height) => {
const targetObj = canvas.getActiveObject()
const objectWidth = target.width
const objectHeight = target.height
const changeWidth = (width / 10 / objectWidth).toFixed(2)
const changeHeight = (height / 10 / objectHeight).toFixed(2)
let sideX = 'left'
let sideY = 'top'
//그룹 중심점 변경
if (side === 2) {
sideX = 'right'
sideY = 'top'
} else if (side === 3) {
sideX = 'left'
sideY = 'bottom'
} else if (side === 4) {
sideX = 'right'
sideY = 'bottom'
}
//변경 전 좌표
const newCoords = target.getPointByOrigin(sideX, sideY)
target.set({
...target,
originX: sideX,
originY: sideY,
left: newCoords.x,
top: newCoords.y,
})
target.setCoords()
canvas?.renderAll() //변경 좌표를 한번 적용
target.scaleX = changeWidth === 0 ? 1 : changeWidth
target.scaleY = changeHeight === 0 ? 1 : changeHeight
//크기 변경후 좌표를 재 적용
const changedCoords = target.getPointByOrigin('center', 'center')
target.set({
...target,
originX: 'center',
originY: 'center',
left: changedCoords.x,
top: changedCoords.y,
})
if (target.name === 'roof') {
//얘는 일단 도머에 적용함
target._objects.forEach((obj) => {
setSurfaceShapePattern(obj)
})
}
// target.setCoords()
canvas.renderAll()
if (target.type === 'group') reGroupObject(target)
}
const reGroupObject = (groupObj) => {
groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨
const reGroupObjects = []
groupObj._objects.forEach((obj) => {
const newObj = new QPolygon(obj.getCurrentPoints(), {
...obj,
points: obj.getCurrentPoints(),
scaleX: 1,
scaleY: 1,
})
reGroupObjects.push(newObj)
canvas.remove(obj)
if (obj.direction) {
drawDirectionArrow(obj)
}
})
const reGroup = new fabric.Group(reGroupObjects, {
subTargetCheck: true,
name: groupObj.name,
id: groupObj.id,
groupYn: true,
})
canvas?.add(reGroup)
canvas?.remove(groupObj)
}
const moveObjectBatch = () => {
const obj = canvas.getActiveObject()
if (obj) {
obj.set({
lockMovementX: false,
lockMovementY: false,
})
addCanvasMouseEventListener('mouse:up', (e) => {
obj.set({
lockMovementX: true,
lockMovementY: true,
})
initEvent()
obj.setCoords()
reGroupObject(obj)
})
}
}
return { return {
applyOpeningAndShadow, applyOpeningAndShadow,
applyDormers, applyDormers,
splitDormerTriangle, splitDormerTriangle,
splitDormerPentagon, splitDormerPentagon,
reSizeObjectBatch,
moveObjectBatch,
} }
} }

View File

@ -22,6 +22,7 @@ import { useSwal } from '@/hooks/useSwal'
import { booleanPointInPolygon } from '@turf/turf' import { booleanPointInPolygon } from '@turf/turf'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { calculateAngle } from '@/util/qpolygon-utils' import { calculateAngle } from '@/util/qpolygon-utils'
import { QPolygon } from '@/components/fabric/QPolygon'
// 보조선 작성 // 보조선 작성
export function useAuxiliaryDrawing(id) { export function useAuxiliaryDrawing(id) {
@ -561,17 +562,62 @@ export function useAuxiliaryDrawing(id) {
} }
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
/*const allLines = [...auxiliaryLines]
const allLines = [...auxiliaryLines]
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
roofBase.lines.forEach((line) => { allLines.push(...roofBase.lines)
allLines.push(line) })*/
})
const innerLines = [...auxiliaryLines]
const roofLines = []
roofBases.forEach((roofBase) => {
innerLines.push(...roofBase.innerLines)
roofLines.push(...roofBase.lines)
}) })
auxiliaryLines.forEach((line1) => { auxiliaryLines.forEach((line1) => {
allLines.forEach((line2) => { let interSectionPointsWithRoofLines = []
//지붕선과 만나는 점을 찾는다.
roofLines.forEach((line2) => {
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint) {
return
}
// 기존 점과 겹치는지 확인
if (interSectionPointsWithRoofLines.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) {
return
}
interSectionPointsWithRoofLines.push(intersectionPoint)
})
//지붕선과 만나는 점이 두개일 경우 넘친 보조선을 잘라준다 (케라바로 만든 마루)
if (interSectionPointsWithRoofLines.length === 2) {
const newLine = addLine(
[
interSectionPointsWithRoofLines[0].x,
interSectionPointsWithRoofLines[0].y,
interSectionPointsWithRoofLines[1].x,
interSectionPointsWithRoofLines[1].y,
],
{
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
},
)
lineHistory.current.push(newLine)
removeLine(line1)
intersectionPoints.current.push(...interSectionPointsWithRoofLines)
return
}
//보조선과 만나는 점을 찾는다.
innerLines.forEach((line2) => {
if (line1 === line2) { if (line1 === line2) {
return return
} }
@ -615,6 +661,53 @@ export function useAuxiliaryDrawing(id) {
lineHistory.current.push(newLine) lineHistory.current.push(newLine)
removeLine(line1) removeLine(line1)
}) })
/*auxiliaryLines.forEach((line1) => {
allLines.forEach((line2) => {
if (line1 === line2) {
return
}
const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint) {
return
}
roofAdsorptionPoints.current.push(intersectionPoint)
intersectionPoints.current.push(intersectionPoint)
const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint)
const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint)
if (distance1 === 0 || distance2 === 0) {
return
}
//historyLine에서 기존 line을 제거한다.
lineHistory.current = lineHistory.current.filter((history) => history !== line1)
let newLine
if (distance1 >= distance2) {
newLine = addLine([line1.x1, line1.y1, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
intersectionPoint,
})
} else {
newLine = addLine([line1.x2, line1.y2, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black',
strokeWidth: 1,
selectable: false,
name: 'auxiliaryLine',
isFixed: true,
intersectionPoint,
})
}
lineHistory.current.push(newLine)
removeLine(line1)
})
})*/
}) })
addCanvasMouseEventListener('mouse:move', mouseMove) addCanvasMouseEventListener('mouse:move', mouseMove)
} }
@ -650,15 +743,38 @@ export function useAuxiliaryDrawing(id) {
} }
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const innerLines = [...lineHistory.current]
//lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거
// 겹치는 선 하나는 canvas에서 제거한다.
const tempLines = [...lineHistory.current]
lineHistory.current = []
tempLines.forEach((line) => {
if (
lineHistory.current.some(
(history) =>
JSON.stringify(history.startPoint) === JSON.stringify(line.startPoint) &&
JSON.stringify(history.endPoint) === JSON.stringify(line.endPoint),
)
) {
canvas.remove(line)
return
}
lineHistory.current.push(line)
})
const innerLines = lineHistory.current
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
const tempPolygonPoints = [...roofBase.points].map((obj) => {
return { x: Math.round(obj.x), y: Math.round(obj.y) }
})
const roofInnerLines = innerLines.filter((line) => { const roofInnerLines = innerLines.filter((line) => {
const turfPolygon = polygonToTurfPolygon(roofBase) const inPolygon1 =
tempPolygonPoints.some((point) => point.x === line.x1 && point.y === line.y1) || roofBase.inPolygon({ x: line.x1, y: line.y1 })
// innerLines의 두 점이 모두 polygon 안에 있는지 확인 const inPolygon2 =
const inPolygon1 = booleanPointInPolygon([line.x1, line.y1], turfPolygon) tempPolygonPoints.some((point) => point.x === line.x2 && point.y === line.y2) || roofBase.inPolygon({ x: line.x2, y: line.y2 })
const inPolygon2 = booleanPointInPolygon([line.x2, line.y2], turfPolygon)
if (inPolygon1 && inPolygon2) { if (inPolygon1 && inPolygon2) {
line.attributes = { ...line.attributes, roofId: roofBase.id } line.attributes = { ...line.attributes, roofId: roofBase.id }
@ -667,6 +783,8 @@ export function useAuxiliaryDrawing(id) {
}) })
roofBase.innerLines = [...roofInnerLines] roofBase.innerLines = [...roofInnerLines]
canvas.renderAll()
}) })
closePopup(id) closePopup(id)

View File

@ -2,7 +2,8 @@ import { useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { usePopup } from '@/hooks/usePopup' import { usePopup } from '@/hooks/usePopup'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useEvent } from '@/hooks/useEvent'
//동선이동 형 올림 내림 //동선이동 형 올림 내림
export function useMovementSetting(id) { export function useMovementSetting(id) {
@ -11,6 +12,7 @@ export function useMovementSetting(id) {
UP_DOWN: 'updown', //형 올림내림 UP_DOWN: 'updown', //형 올림내림
} }
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { initEvent, addCanvasMouseEventListener } = useEvent()
const { closePopup } = usePopup() const { closePopup } = usePopup()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const buttonType = [ const buttonType = [
@ -18,6 +20,7 @@ export function useMovementSetting(id) {
{ id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN }, { id: 2, name: getMessage('modal.movement.flow.line.updown'), type: TYPE.UP_DOWN },
] ]
const [type, setType] = useState(TYPE.FLOW_LINE) const [type, setType] = useState(TYPE.FLOW_LINE)
const typeRef = useRef(type)
const FLOW_LINE_REF = { const FLOW_LINE_REF = {
DOWN_LEFT_INPUT_REF: useRef(null), DOWN_LEFT_INPUT_REF: useRef(null),
@ -33,7 +36,100 @@ export function useMovementSetting(id) {
DOWN_RADIO_REF: useRef(null), DOWN_RADIO_REF: useRef(null),
} }
const handleSave = () => {} useEffect(() => {
typeRef.current = type
}, [type])
useEffect(() => {
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 wallLine의 visible false
wallLines.forEach((line) => {
line.set({ visible: false })
})
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true
outerLines.forEach((line) => {
line.bringToFront()
line.set({ selectable: true })
})
canvas.renderAll()
addCanvasMouseEventListener('mouse:move', mouseMoveEvent)
return () => {
initEvent()
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
wallLines.forEach((line) => {
line.set({ visible: true })
})
canvas.renderAll()
}
}, [])
const mouseMoveEvent = (e) => {
if (typeRef.current === TYPE.FLOW_LINE) {
flowLineEvent(e)
} else {
updownEvent(e)
}
}
const flowLineEvent = (e) => {}
const updownEvent = (e) => {
const target = canvas.getActiveObject()
if (!target) {
return
}
const direction = target.direction
const { top: targetTop, left: targetLeft } = target
const currentX = canvas.getPointer(e.e).x
const currentY = Math.floor(canvas.getPointer(e.e).y)
if (direction === 'left' || direction === 'right') {
if (targetTop > currentY) {
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
UP_DOWN_REF.UP_INPUT_REF.current.value = ''
UP_DOWN_REF.DOWN_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000)
} else {
UP_DOWN_REF.UP_RADIO_REF.current.checked = true
UP_DOWN_REF.DOWN_INPUT_REF.current.value = ''
UP_DOWN_REF.UP_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000)
}
} else {
if (targetLeft > currentX) {
UP_DOWN_REF.DOWN_RADIO_REF.current.checked = true
UP_DOWN_REF.UP_INPUT_REF.current.value = ''
UP_DOWN_REF.DOWN_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000)
} else {
UP_DOWN_REF.UP_RADIO_REF.current.checked = true
UP_DOWN_REF.DOWN_INPUT_REF.current.value = ''
UP_DOWN_REF.UP_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000)
}
}
canvas?.renderAll()
}
const handleSave = () => {
if (type === TYPE.FLOW_LINE) {
// 동선이동
if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) {
// 높이 변경: 아래, 왼쪽 체크
} else {
// 높이 변경: 위, 오른쪽 체크
}
} else {
// 형 올림내림
if (UP_DOWN_REF.UP_RADIO_REF.current.checked) {
// 자릿수를 올리다 체크
const length = Number(UP_DOWN_REF.UP_INPUT_REF.current.value)
} else {
// 자릿수를 내리다 체크
const length = Number(UP_DOWN_REF.DOWN_INPUT_REF.current.value)
}
}
}
return { return {
TYPE, TYPE,

View File

@ -32,6 +32,7 @@ import ColumnInsert from '@/components/floor-plan/modal/module/column/ColumnInse
import RowRemove from '@/components/floor-plan/modal/module/row/RowRemove' import RowRemove from '@/components/floor-plan/modal/module/row/RowRemove'
import RowInsert from '@/components/floor-plan/modal/module/row/RowInsert' import RowInsert from '@/components/floor-plan/modal/module/row/RowInsert'
import CircuitNumberEdit from '@/components/floor-plan/modal/module/CircuitNumberEdit' import CircuitNumberEdit from '@/components/floor-plan/modal/module/CircuitNumberEdit'
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
export function useContextMenu() { export function useContextMenu() {
const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴 const currentMenu = useRecoilValue(currentMenuState) // 현재 메뉴
@ -48,6 +49,8 @@ export function useContextMenu() {
const [cell, setCell] = useState(null) const [cell, setCell] = useState(null)
const [column, setColumn] = useState(null) const [column, setColumn] = useState(null)
const { handleZoomClear } = useCanvasEvent() const { handleZoomClear } = useCanvasEvent()
const { moveObjectBatch } = useObjectBatch({})
const currentMenuSetting = () => { const currentMenuSetting = () => {
switch (currentMenu) { switch (currentMenu) {
case MENU.PLAN_DRAWING: case MENU.PLAN_DRAWING:
@ -115,6 +118,7 @@ export function useContextMenu() {
{ {
id: 'wallLineRemove', id: 'wallLineRemove',
name: getMessage('contextmenu.wallline.remove'), name: getMessage('contextmenu.wallline.remove'),
fn: () => deleteOuterLineObject(),
}, },
{ {
id: 'imageSizeEdit', id: 'imageSizeEdit',
@ -171,7 +175,6 @@ export function useContextMenu() {
{ {
id: 'sizeEdit', id: 'sizeEdit',
name: getMessage('contextmenu.size.edit'), name: getMessage('contextmenu.size.edit'),
component: <SizeSetting id={popupId} target={currentObject} />,
}, },
{ {
id: 'remove', id: 'remove',
@ -207,7 +210,6 @@ export function useContextMenu() {
{ {
id: 'flowDirectionEdit', id: 'flowDirectionEdit',
name: getMessage('contextmenu.flow.direction.edit'), name: getMessage('contextmenu.flow.direction.edit'),
component: <FlowDirectionSetting id={popupId} />,
}, },
], ],
]) ])
@ -270,16 +272,19 @@ export function useContextMenu() {
id: 'dormerRemove', id: 'dormerRemove',
shortcut: ['d', 'D'], shortcut: ['d', 'D'],
name: `${getMessage('contextmenu.remove')}(D)`, name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(),
}, },
{ {
id: 'dormerMove', id: 'dormerMove',
shortcut: ['m', 'M'], shortcut: ['m', 'M'],
name: `${getMessage('contextmenu.move')}(M)`, name: `${getMessage('contextmenu.move')}(M)`,
fn: () => moveObjectBatch(),
}, },
{ {
id: 'dormerCopy', id: 'dormerCopy',
shortcut: ['c', 'C'], shortcut: ['c', 'C'],
name: `${getMessage('contextmenu.copy')}(C)`, name: `${getMessage('contextmenu.copy')}(C)`,
fn: () => copyObject(),
}, },
{ {
id: 'roofMaterialEdit', id: 'roofMaterialEdit',
@ -349,16 +354,19 @@ export function useContextMenu() {
id: 'openingRemove', id: 'openingRemove',
shortcut: ['d', 'D'], shortcut: ['d', 'D'],
name: `${getMessage('contextmenu.remove')}(D)`, name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(),
}, },
{ {
id: 'openingMove', id: 'openingMove',
shortcut: ['m', 'M'], shortcut: ['m', 'M'],
name: `${getMessage('contextmenu.move')}(M)`, name: `${getMessage('contextmenu.move')}(M)`,
fn: () => moveObject(),
}, },
{ {
id: 'openingCopy', id: 'openingCopy',
shortcut: ['c', 'C'], shortcut: ['c', 'C'],
name: `${getMessage('contextmenu.copy')}(C)`, name: `${getMessage('contextmenu.copy')}(C)`,
fn: () => copyObject(),
}, },
{ {
id: 'openingOffset', id: 'openingOffset',
@ -421,23 +429,19 @@ export function useContextMenu() {
]) ])
break break
case 'lineGrid': case 'lineGrid':
case 'tempGrid':
setContextMenu([ setContextMenu([
[ [
{ {
id: 'gridMove', id: 'gridMove',
name: getMessage('modal.grid.move'), name: getMessage('modal.grid.move'),
component: <GridMove id={popupId} />,
}, },
{ {
id: 'gridCopy', id: 'gridCopy',
name: getMessage('modal.grid.copy'), name: getMessage('modal.grid.copy'),
component: <GridCopy id={popupId} />,
}, },
{ {
id: 'gridColorEdit', id: 'gridColorEdit',
name: getMessage('contextmenu.grid.color.edit'), name: getMessage('contextmenu.grid.color.edit'),
component: <ColorPickerModal id={popupId} color={gridColor} setColor={setGridColor} />,
}, },
{ {
id: 'remove', id: 'remove',
@ -450,7 +454,7 @@ export function useContextMenu() {
], ],
]) ])
break break
case 'dimensionLine': case 'dimensionGroup':
setContextMenu([ setContextMenu([
[ [
{ {
@ -482,22 +486,25 @@ export function useContextMenu() {
{ {
id: 'sizeEdit', id: 'sizeEdit',
name: getMessage('contextmenu.size.edit'), name: getMessage('contextmenu.size.edit'),
component: <SizeSetting id={popupId} />, component: <SizeSetting id={popupId} target={currentObject} />,
}, },
{ {
id: 'remove', id: 'remove',
shortcut: ['d', 'D'], shortcut: ['d', 'D'],
name: `${getMessage('contextmenu.remove')}(D)`, name: `${getMessage('contextmenu.remove')}(D)`,
fn: () => deleteObject(),
}, },
{ {
id: 'move', id: 'move',
shortcut: ['m', 'M'], shortcut: ['m', 'M'],
name: `${getMessage('contextmenu.move')}(M)`, name: `${getMessage('contextmenu.move')}(M)`,
fn: () => moveObject(),
}, },
{ {
id: 'copy', id: 'copy',
shortcut: ['c', 'C'], shortcut: ['c', 'C'],
name: `${getMessage('contextmenu.copy')}(C)`, name: `${getMessage('contextmenu.copy')}(C)`,
fn: () => copyObject(),
}, },
], ],
]) ])
@ -567,6 +574,7 @@ export function useContextMenu() {
]) ])
break break
case 'module': case 'module':
case 'dimensionLineText':
setContextMenu([ setContextMenu([
[ [
{ {

View File

@ -55,31 +55,40 @@ export function usePlan() {
/** /**
* 현재 캔버스에 그려진 데이터를 추출 * 현재 캔버스에 그려진 데이터를 추출
*/ */
const currentCanvasData = () => { const currentCanvasData = (mode = '') => {
removeMouseLines() removeMouseLines()
const groups = canvas.getObjects().filter((obj) => obj.type === 'group') if (mode === 'save') {
const groups = canvas.getObjects().filter((obj) => obj.type === 'group')
if (groups.length > 0) { if (groups.length > 0) {
groups.forEach((group) => { groups.forEach((group) => {
canvas?.remove(group) canvas?.remove(group)
canvas?.renderAll()
const restore = group._restoreObjectsState()
restore._objects.forEach((obj) => {
obj.set({
...obj,
groupYn: true,
groupName: group.name,
lineDirection: group.lineDirection,
})
canvas?.add(obj)
obj.setCoords()
canvas?.requestRenderAll()
canvas?.renderAll() canvas?.renderAll()
const restore = group._restoreObjectsState() //그룹 좌표 복구
//그룹시 좌표가 틀어지는 이슈
restore._objects.forEach((obj) => {
obj.set({
...obj,
groupYn: true,
groupName: group.name,
groupId: group.id,
})
//디렉션이 있는 경우에만
if (group.lineDirection) {
obj.set({
lineDirection: group.lineDirection,
})
}
canvas?.add(obj)
obj.setCoords()
canvas?.renderAll()
})
}) })
}) }
} }
return addCanvas() return addCanvas()
@ -163,7 +172,7 @@ export function usePlan() {
* 페이지 캔버스를 저장 * 페이지 캔버스를 저장
*/ */
const saveCanvas = async (userId) => { const saveCanvas = async (userId) => {
const canvasStatus = currentCanvasData() const canvasStatus = currentCanvasData('save')
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id) initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)
? await putCanvasStatus(canvasStatus) ? await putCanvasStatus(canvasStatus)
: await postCanvasStatus(userId, canvasStatus) : await postCanvasStatus(userId, canvasStatus)

View File

@ -113,6 +113,12 @@ export const usePolygon = () => {
return return
} }
//동일 아이디가 있으면 일단 지우고 다시 그린다
const existArrow = polygon.canvas.getObjects().filter((obj) => obj.name === 'arrow' && obj.parentId === polygon.id)
if (existArrow.length > 0) {
polygon.canvas.remove(...existArrow)
}
polygon.canvas polygon.canvas
.getObjects() .getObjects()
.filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow) .filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow)

View File

@ -148,6 +148,7 @@
"modal.roof.alloc.select.parallel": "並列式", "modal.roof.alloc.select.parallel": "並列式",
"modal.roof.alloc.select.stairs": "カスケード", "modal.roof.alloc.select.stairs": "カスケード",
"modal.roof.alloc.apply": "選択した屋根材として割り当て", "modal.roof.alloc.apply": "選択した屋根材として割り当て",
"plan.menu.estimate.docDown": "文書のダウンロード",
"plan.menu.estimate.save": "保存", "plan.menu.estimate.save": "保存",
"plan.menu.estimate.reset": "初期化", "plan.menu.estimate.reset": "初期化",
"plan.menu.estimate.copy": "コピー", "plan.menu.estimate.copy": "コピー",
@ -586,6 +587,7 @@
"stuff.addressPopup.btn2": "住所適用", "stuff.addressPopup.btn2": "住所適用",
"stuff.planReqPopup.title": "設計依頼のインポート", "stuff.planReqPopup.title": "設計依頼のインポート",
"stuff.temp.subTitle": "商品情報", "stuff.temp.subTitle": "商品情報",
"stuff.temp.subTitle2": "作図",
"stuff.detail.header.message1": "存在しないものです。", "stuff.detail.header.message1": "存在しないものです。",
"stuff.detail.header.message2": "商品番号がコピーされました。", "stuff.detail.header.message2": "商品番号がコピーされました。",
"stuff.detail.header.message3": "存在しないものです。", "stuff.detail.header.message3": "存在しないものです。",
@ -782,18 +784,18 @@
"surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.",
"estimate.detail.header.title": "基本情報", "estimate.detail.header.title": "基本情報",
"estimate.detail.objectNo": "品番", "estimate.detail.objectNo": "品番",
"estimate.detail.estimateNo": "見積書番号", "estimate.detail.docNo": "見積書番号",
"estimate.detail.createDatetime": "登録日", "estimate.detail.drawingEstimateCreateDate": "登録日",
"estimate.detail.lastEditDatetime": "変更日時", "estimate.detail.lastEditDatetime": "変更日時",
"estimate.detail.saleStoreId": "一次販売店名", "estimate.detail.saleStoreId": "一次販売店名",
"estimate.detail.estimateDate": "見積日", "estimate.detail.estimateDate": "見積日",
"estimate.detail.otherSaleStoreId": "二次販売店名", "estimate.detail.otherSaleStoreId": "二次販売店名",
"estimate.detail.receiveUser": "担当者 ", "estimate.detail.receiveUser": "担当者 ",
"estimate.detail.title": "案件名", "estimate.detail.objectName": "案件名",
"estimate.detail.remarks": "メモ", "estimate.detail.objectRemarks": "メモ",
"estimate.detail.orderType": "注文分類", "estimate.detail.estimateType": "注文分類",
"estimate.detail.roofCns": "屋根材・仕様施工", "estimate.detail.roofCns": "屋根材・仕様施工",
"estimate.detail.note": "備考", "estimate.detail.remarks": "備考",
"estimate.detail.nextSubmit": "後日資料提出", "estimate.detail.nextSubmit": "後日資料提出",
"estimate.detail.header.fileList1": "ファイル添付", "estimate.detail.header.fileList1": "ファイル添付",
"estimate.detail.fileList.btn": "ファイル選択", "estimate.detail.fileList.btn": "ファイル選択",

View File

@ -152,6 +152,7 @@
"modal.roof.alloc.select.parallel": "병렬식", "modal.roof.alloc.select.parallel": "병렬식",
"modal.roof.alloc.select.stairs": "계단식", "modal.roof.alloc.select.stairs": "계단식",
"modal.roof.alloc.apply": "선택한 지붕재로 할당", "modal.roof.alloc.apply": "선택한 지붕재로 할당",
"plan.menu.estimate.docDown": "문서 다운로드",
"plan.menu.estimate.save": "저장", "plan.menu.estimate.save": "저장",
"plan.menu.estimate.reset": "초기화", "plan.menu.estimate.reset": "초기화",
"plan.menu.estimate.copy": "복사", "plan.menu.estimate.copy": "복사",
@ -592,6 +593,7 @@
"stuff.addressPopup.btn2": "주소적용", "stuff.addressPopup.btn2": "주소적용",
"stuff.planReqPopup.title": "설계의뢰 불러오기", "stuff.planReqPopup.title": "설계의뢰 불러오기",
"stuff.temp.subTitle": "물건정보", "stuff.temp.subTitle": "물건정보",
"stuff.temp.subTitle2": "도면작성",
"stuff.detail.header.message1": "존재하지 않는 물건입니다.", "stuff.detail.header.message1": "존재하지 않는 물건입니다.",
"stuff.detail.header.message2": "물건번호가 복사되었습니다.", "stuff.detail.header.message2": "물건번호가 복사되었습니다.",
"stuff.detail.header.message3": "물건번호 복사에 실패했습니다.", "stuff.detail.header.message3": "물건번호 복사에 실패했습니다.",
@ -788,18 +790,18 @@
"surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.", "surface.shape.validate.size.4to5": "④길이는 ⑤보다 큰 값을 넣어주세요.",
"estimate.detail.header.title": "기본정보", "estimate.detail.header.title": "기본정보",
"estimate.detail.objectNo": "물건번호", "estimate.detail.objectNo": "물건번호",
"estimate.detail.estimateNo": "견적서 번호", "estimate.detail.docNo": "견적서 번호",
"estimate.detail.createDatetime": "등록일", "estimate.detail.drawingEstimateCreateDate": "등록일",
"estimate.detail.lastEditDatetime": "변경일시", "estimate.detail.lastEditDatetime": "변경일시",
"estimate.detail.saleStoreId": "1차 판매점명", "estimate.detail.saleStoreId": "1차 판매점명",
"estimate.detail.estimateDate": "견적일", "estimate.detail.estimateDate": "견적일",
"estimate.detail.otherSaleStoreId": "2차 판매점명", "estimate.detail.otherSaleStoreId": "2차 판매점명",
"estimate.detail.receiveUser": "담당자", "estimate.detail.receiveUser": "담당자",
"estimate.detail.title": "안건명", "estimate.detail.objectName": "안건명",
"estimate.detail.remarks": "메모", "estimate.detail.objectRemarks": "메모",
"estimate.detail.orderType": "주문분류", "estimate.detail.estimateType": "주문분류",
"estimate.detail.roofCns": "지붕재・사양시공", "estimate.detail.roofCns": "지붕재・사양시공",
"estimate.detail.note": "비고", "estimate.detail.remarks": "비고",
"estimate.detail.nextSubmit": "후일자료제출", "estimate.detail.nextSubmit": "후일자료제출",
"estimate.detail.header.fileList1": "파일첨부", "estimate.detail.header.fileList1": "파일첨부",
"estimate.detail.fileList.btn": "파일선택", "estimate.detail.fileList.btn": "파일선택",

View File

@ -14,7 +14,8 @@ export const stuffSearchState = atom({
schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일 schFromDt: dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD'), //시작일
schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일 schToDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일
code: 'S', code: 'S',
schSelSaleStoreId: '', //판매대리점 선택 schSelSaleStoreId: '', //1차판매대리점 선택
schOtherSelSaleStoreId: '', //1차 이외 판매대리점 선택
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일) schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일)

View File

@ -766,9 +766,9 @@ export const triangleToPolygon = (triangle) => {
const halfWidth = triangle.width / 2 const halfWidth = triangle.width / 2
const height = triangle.height const height = triangle.height
points.push({ x: triangle.left + halfWidth, y: triangle.top }) points.push({ x: triangle.left, y: triangle.top })
points.push({ x: triangle.left, y: triangle.top + height }) points.push({ x: triangle.left - halfWidth, y: triangle.top + height })
points.push({ x: triangle.left + triangle.width, y: triangle.top + height }) points.push({ x: triangle.left + halfWidth, y: triangle.top + height })
return points return points
} }

View File

@ -1034,9 +1034,10 @@ export const splitPolygonWithLines = (polygon) => {
const routes = [] const routes = []
// 시작점은 시작 hip라인의 출발점 // 시작점은 시작 hip라인의 출발점
const startPoint = point const startPoint = { x: Math.round(point.x), y: Math.round(point.y) }
// 도착점은 마지막 hip라인의 끝나는 점 // 도착점은 마지막 hip라인의 끝나는 점
const endPoint = polygon.points[(index + 1) % polygon.points.length] let endPoint = polygon.points[(index + 1) % polygon.points.length]
endPoint = { x: Math.round(endPoint.x), y: Math.round(endPoint.y) }
const startLine = allLines.find((line) => line.startPoint.x === startPoint.x && line.startPoint.y === startPoint.y) const startLine = allLines.find((line) => line.startPoint.x === startPoint.x && line.startPoint.y === startPoint.y)
const endLine = allLines.find((line) => line.startPoint.x === endPoint.x && line.startPoint.y === endPoint.y) const endLine = allLines.find((line) => line.startPoint.x === endPoint.x && line.startPoint.y === endPoint.y)
@ -1166,7 +1167,7 @@ export const splitPolygonWithLines = (polygon) => {
} }
const isSamePoint = (a, b) => { const isSamePoint = (a, b) => {
return a.x === b.x && a.y === b.y return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 1 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 1
} }
/** /**