Merge branch 'dev' into feature/jaeyoung
This commit is contained in:
commit
453fb80fd4
@ -1,28 +0,0 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "sqlserver"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model M_USER {
|
||||
USER_ID String @id(map: "M_USER_pk") @db.VarChar(50)
|
||||
SALE_STORE_ID String @db.VarChar(10)
|
||||
PASSWORD String @db.VarChar(10)
|
||||
CATEGORY String? @db.NVarChar(20)
|
||||
NAME String @db.NVarChar(20)
|
||||
NAME_KANA String @db.NVarChar(20)
|
||||
TEL String? @db.VarChar(15)
|
||||
FAX String? @db.VarChar(15)
|
||||
MAIL String? @db.NVarChar(100)
|
||||
GROUP_ID String @db.VarChar(5)
|
||||
MODULE_SELECT_GROUP_ID String? @db.VarChar(5)
|
||||
VERSION_MANAGEMENT_ID String? @db.VarChar(20)
|
||||
DISP_COST_PRICE Boolean?
|
||||
DISP_SELLING_PRICE Boolean?
|
||||
REGIST_DATETIME DateTime? @db.DateTime
|
||||
LAST_EDIT_DATETIME DateTime? @db.DateTime
|
||||
LAST_EDIT_USER String? @db.VarChar(50)
|
||||
}
|
||||
5
public/static/images/canvas/ico-flx05.svg
Normal file
5
public/static/images/canvas/ico-flx05.svg
Normal file
@ -0,0 +1,5 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.19444 12.9993C6.09354 12.9998 5.99172 13 5.88889 13C4.92046 13 4.04106 12.9796 3.17535 12.9406C2.14652 12.8941 1.30109 12.109 1.16366 11.1069C1.07397 10.4528 1 9.78258 1 9.10001C1 8.41744 1.07397 7.7472 1.16366 7.09317C1.30109 6.09102 2.14652 5.30591 3.17535 5.25947C4.04106 5.22039 4.92046 5.20001 5.88889 5.20001C6.85732 5.20001 7.73672 5.22039 8.60243 5.25947C9.4922 5.29963 10.1961 5.89229 10.4722 6.70001" stroke="white" stroke-linecap="round"/>
|
||||
<path d="M3.13885 5.2V3.7C3.13885 2.20883 4.37007 1 5.88885 1C7.40764 1 8.63885 2.20883 8.63885 3.7V5.2" stroke="white" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M9.95286 10.4138C9.70279 10.2967 9.40511 10.4045 9.28798 10.6545C9.17085 10.9046 9.27862 11.2023 9.52869 11.3194L9.95286 10.4138ZM10.284 11.4L9.85526 11.6572C9.94961 11.8145 10.1224 11.9074 10.3056 11.8995C10.4888 11.8915 10.653 11.784 10.7334 11.6192L10.284 11.4ZM11.604 10.5087C11.8482 10.3796 11.9415 10.0771 11.8125 9.83297C11.6834 9.58883 11.3809 9.49553 11.1368 9.62457L11.604 10.5087ZM12.5 10.6C12.5 11.6407 11.6382 12.5 10.5556 12.5V13.5C12.1731 13.5 13.5 12.2102 13.5 10.6H12.5ZM10.5556 12.5C9.47301 12.5 8.61115 11.6407 8.61115 10.6H7.61115C7.61115 12.2102 8.93811 13.5 10.5556 13.5V12.5ZM8.61115 10.6C8.61115 9.55922 9.47301 8.69995 10.5556 8.69995V7.69995C8.93811 7.69995 7.61115 8.98972 7.61115 10.6H8.61115ZM10.5556 8.69995C11.6382 8.69995 12.5 9.55922 12.5 10.6H13.5C13.5 8.98972 12.1731 7.69995 10.5556 7.69995V8.69995ZM9.74077 10.8666C9.52869 11.3194 9.52853 11.3193 9.52837 11.3193C9.52832 11.3192 9.52816 11.3192 9.52805 11.3191C9.52785 11.319 9.52764 11.3189 9.52744 11.3188C9.52704 11.3186 9.52666 11.3185 9.5263 11.3183C9.52557 11.3179 9.52491 11.3176 9.52432 11.3173C9.52313 11.3168 9.52222 11.3163 9.52157 11.316C9.52026 11.3153 9.51999 11.3152 9.52066 11.3155C9.52202 11.3163 9.52708 11.319 9.53519 11.3239C9.55151 11.3337 9.57943 11.3518 9.6139 11.3792C9.68306 11.4342 9.77529 11.524 9.85526 11.6572L10.7127 11.1427C10.5599 10.888 10.3805 10.7111 10.2363 10.5964C10.164 10.539 10.0998 10.4965 10.0506 10.4669C10.026 10.4521 10.005 10.4405 9.98847 10.4317C9.9802 10.4273 9.97303 10.4237 9.96707 10.4207C9.96408 10.4192 9.9614 10.4179 9.95903 10.4168C9.95784 10.4162 9.95673 10.4157 9.9557 10.4152C9.95519 10.4149 9.95469 10.4147 9.95422 10.4145C9.95398 10.4144 9.95375 10.4142 9.95352 10.4141C9.95341 10.4141 9.95324 10.414 9.95319 10.414C9.95302 10.4139 9.95286 10.4138 9.74077 10.8666ZM10.284 11.4C10.7334 11.6192 10.7333 11.6192 10.7333 11.6193C10.7333 11.6193 10.7333 11.6194 10.7332 11.6194C10.7332 11.6195 10.7332 11.6196 10.7332 11.6196C10.7331 11.6197 10.7331 11.6197 10.7331 11.6196C10.7332 11.6196 10.7333 11.6192 10.7336 11.6187C10.7341 11.6176 10.7352 11.6156 10.7366 11.6127C10.7395 11.6069 10.7442 11.5976 10.7506 11.5852C10.7634 11.5605 10.7829 11.5237 10.8082 11.4781C10.8592 11.3863 10.9325 11.2614 11.0217 11.1288C11.215 10.8417 11.4284 10.6015 11.604 10.5087L11.1368 9.62457C10.725 9.84221 10.3952 10.2687 10.1921 10.5706C10.0831 10.7325 9.99497 10.8828 9.93403 10.9925C9.90342 11.0476 9.87932 11.0931 9.86253 11.1256C9.85413 11.1418 9.84754 11.1548 9.84286 11.1641C9.84051 11.1688 9.83865 11.1725 9.83727 11.1753C9.83658 11.1767 9.83601 11.1779 9.83557 11.1788C9.83534 11.1792 9.83515 11.1796 9.83499 11.1799C9.83491 11.1801 9.83484 11.1803 9.83477 11.1804C9.83474 11.1805 9.8347 11.1805 9.83468 11.1806C9.83464 11.1807 9.8346 11.1807 10.284 11.4Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.5 KiB |
3
public/static/images/canvas/return-btn.svg
Normal file
3
public/static/images/canvas/return-btn.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg width="14" height="14" viewBox="0 0 14 14" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M11.8055 1V2.87932C11.8055 3.05563 11.5851 3.13545 11.4722 3C10.3736 1.7725 8.777 1 7 1C3.68629 1 1 3.68629 1 7C1 10.3137 3.68629 13 7 13C10.3137 13 13 10.3137 13 7" stroke="#B0BCCD" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 344 B |
@ -34,7 +34,7 @@ export const QcastProvider = ({ children }) => {
|
||||
const targetElement = document.getElementById('canvas')
|
||||
if (!targetElement && currentCanvasPlan?.id && planSave) {
|
||||
setPlanSave((prev) => !prev)
|
||||
checkUnsavedCanvasPlan(currentCanvasPlan.userId)
|
||||
checkUnsavedCanvasPlan()
|
||||
} else if (targetElement && currentCanvasPlan?.id) {
|
||||
setPlanSave(true)
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import { writeImage, writeImageBuffer } from '@/lib/fileAction'
|
||||
|
||||
export async function GET(req) {
|
||||
const path = 'public/plan-map-images'
|
||||
@ -15,14 +16,7 @@ export async function GET(req) {
|
||||
const response = await fetch(decodeUrl)
|
||||
const data = await response.arrayBuffer()
|
||||
const buffer = Buffer.from(data)
|
||||
|
||||
try {
|
||||
await fs.readdir(path)
|
||||
} catch {
|
||||
await fs.mkdir(path)
|
||||
} finally {
|
||||
await fs.writeFile(`${path}/${fileNm}.png`, buffer)
|
||||
}
|
||||
await writeImage(fileNm, buffer)
|
||||
|
||||
return NextResponse.json({ fileNm: `${fileNm}.png` })
|
||||
}
|
||||
|
||||
@ -1,25 +1,15 @@
|
||||
'use server'
|
||||
|
||||
import fs from 'fs/promises'
|
||||
|
||||
import { NextResponse } from 'next/server'
|
||||
import { writeImage } from '@/lib/fileAction'
|
||||
|
||||
export async function POST(req) {
|
||||
const path = 'public/plan-bg-images'
|
||||
|
||||
const formData = await req.formData()
|
||||
const file = formData.get('file')
|
||||
const fileName = formData.get('fileName')
|
||||
const arrayBuffer = await file.arrayBuffer()
|
||||
const buffer = Buffer.from(arrayBuffer)
|
||||
// const buffer = new Uint8Array(arrayBuffer)
|
||||
await writeImage(fileName, buffer)
|
||||
|
||||
try {
|
||||
await fs.readdir(path)
|
||||
} catch {
|
||||
await fs.mkdir(path)
|
||||
} finally {
|
||||
await fs.writeFile(`${path}/${file.name}`, buffer)
|
||||
}
|
||||
|
||||
return NextResponse.json({ fileNm: `${file.name}` })
|
||||
return NextResponse.json({ fileNm: `${fileName}.png` })
|
||||
}
|
||||
|
||||
@ -1,34 +0,0 @@
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { createContext, useState } from 'react'
|
||||
|
||||
export const EventContext = createContext({})
|
||||
|
||||
const EventProvider = ({ children }) => {
|
||||
const {
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
addTargetMouseEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeDocumentEvent,
|
||||
removeMouseEvent,
|
||||
removeMouseLine,
|
||||
initEvent,
|
||||
} = useEvent()
|
||||
|
||||
const [value, setValue] = useState({
|
||||
addDocumentEventListener,
|
||||
addCanvasMouseEventListener,
|
||||
addTargetMouseEventListener,
|
||||
removeAllMouseEventListeners,
|
||||
removeAllDocumentEventListeners,
|
||||
removeDocumentEvent,
|
||||
removeMouseEvent,
|
||||
removeMouseLine,
|
||||
initEvent,
|
||||
})
|
||||
|
||||
return <EventContext.Provider value={value}>{children}</EventContext.Provider>
|
||||
}
|
||||
|
||||
export default EventProvider
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
import { correntObjectNoState } from '@/store/settingAtom'
|
||||
import { notFound, usePathname, useSearchParams } from 'next/navigation'
|
||||
// import { ErrorBoundary } from 'next/dist/client/components/error-boundary'
|
||||
// import ServerError from '../error'
|
||||
import { createContext, useReducer, useState } from 'react'
|
||||
import { useSetRecoilState } from 'recoil'
|
||||
|
||||
|
||||
@ -3,20 +3,25 @@
|
||||
import FloorPlanProvider from './FloorPlanProvider'
|
||||
import FloorPlan from '@/components/floor-plan/FloorPlan'
|
||||
import CanvasLayout from '@/components/floor-plan/CanvasLayout'
|
||||
import EventProvider from './EventProvider'
|
||||
import { usePathname } from 'next/navigation'
|
||||
|
||||
export default function FloorPlanLayout({ children }) {
|
||||
console.log('🚀 ~ FloorPlanLayout ~ FloorPlanLayout:')
|
||||
const pathname = usePathname()
|
||||
console.log('🚀 ~ FloorPlanLayout ~ pathname:', pathname)
|
||||
|
||||
return (
|
||||
<>
|
||||
<EventProvider>
|
||||
<FloorPlanProvider>
|
||||
<FloorPlan>
|
||||
<FloorPlanProvider>
|
||||
<FloorPlan>
|
||||
{pathname.includes('estimate') || pathname.includes('simulator') ? (
|
||||
<div className="canvas-layout">{children}</div>
|
||||
) : (
|
||||
<CanvasLayout>{children}</CanvasLayout>
|
||||
</FloorPlan>
|
||||
</FloorPlanProvider>
|
||||
</EventProvider>
|
||||
)}
|
||||
{/* <CanvasLayout>{children}</CanvasLayout> */}
|
||||
</FloorPlan>
|
||||
</FloorPlanProvider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
import StuffSearchCondition from '@/components/management/StuffSearchCondition'
|
||||
import Stuff from '@/components/management/Stuff'
|
||||
import StuffSearchCondition from '@/components/management/StuffSearchCondition'
|
||||
import StuffSubHeader from '@/components/management/StuffSubHeader'
|
||||
|
||||
import '@/styles/grid.scss'
|
||||
|
||||
export default async function ManagementStuffPage() {
|
||||
return (
|
||||
<>
|
||||
|
||||
18
src/app/management/stuff/tempReg/page.jsx
Normal file
18
src/app/management/stuff/tempReg/page.jsx
Normal file
@ -0,0 +1,18 @@
|
||||
import React from 'react'
|
||||
import StuffSubHeader from '@/components/management/StuffSubHeader'
|
||||
import '@/styles/contents.scss'
|
||||
import StuffDetail from '@/components/management/StuffDetail'
|
||||
export default function ManagementStuffRegPage() {
|
||||
return (
|
||||
<>
|
||||
<StuffSubHeader type={'temp'} />
|
||||
<div className="sub-content">
|
||||
<div className="sub-content-inner">
|
||||
<div className="sub-content-box">
|
||||
<StuffDetail />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -161,6 +161,7 @@ export const SAVE_KEY = [
|
||||
'surfaceCompass',
|
||||
'moduleCompass',
|
||||
'isFixed',
|
||||
'modules',
|
||||
]
|
||||
|
||||
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]
|
||||
|
||||
@ -15,6 +15,7 @@ import { SessionContext } from '@/app/SessionProvider'
|
||||
import { QcastContext } from '@/app/QcastProvider'
|
||||
|
||||
export default function MainPage() {
|
||||
const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false)
|
||||
const { session } = useContext(SessionContext)
|
||||
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
@ -27,37 +28,12 @@ export default function MainPage() {
|
||||
|
||||
const [searchRadioType, setSearchRadioType] = useState('object')
|
||||
|
||||
// const [saleStoreId, setSaleStoreId] = useState('')
|
||||
// const [saleStoreName, setSaleStoreName] = useState('')
|
||||
|
||||
const [stuffSearch, setStuffSearch] = useRecoilState(stuffSearchState)
|
||||
|
||||
const [searchForm, setSearchForm] = useRecoilState(searchState)
|
||||
|
||||
const { qcastState } = useContext(QcastContext)
|
||||
|
||||
// useEffect(() => {
|
||||
// if (session.pwdInitYn === 'Y') {
|
||||
// fetchObjectList()
|
||||
// }
|
||||
// }, [session])
|
||||
|
||||
const fetchObjectList = async () => {
|
||||
try {
|
||||
const apiUrl = `/api/main-page/object/${session?.storeId}/list`
|
||||
await promiseGet({
|
||||
url: apiUrl,
|
||||
}).then((res) => {
|
||||
if (res.status === 200) {
|
||||
setSaleStoreId(res.data.saleStoreId)
|
||||
setSaleStoreName(res.data.saleStoreName)
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('MAIN API fetching error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
// 엔터 이벤트
|
||||
const handleByOnKeyUp = (e) => {
|
||||
if (e.key === 'Enter') {
|
||||
@ -68,7 +44,7 @@ export default function MainPage() {
|
||||
schObjectNo: searchTxt,
|
||||
code: 'M',
|
||||
})
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
} else {
|
||||
setSearchForm({ ...searchForm, searchValue: searchTxt, mainFlag: 'Y' })
|
||||
router.push('/community/faq')
|
||||
@ -90,16 +66,22 @@ export default function MainPage() {
|
||||
code: 'M',
|
||||
})
|
||||
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
} else {
|
||||
setSearchForm({ ...searchForm, searchValue: searchTxt, mainFlag: 'Y' })
|
||||
router.push('/community/faq')
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (session?.pwdInitYn !== 'Y') {
|
||||
setChagePasswordPopOpen(true)
|
||||
}
|
||||
}, [session])
|
||||
|
||||
return (
|
||||
<>
|
||||
{(session?.pwdInitYn !== 'N' && (
|
||||
{(!chagePasswordPopOpen && (
|
||||
<>
|
||||
<div className="background-bord"></div>
|
||||
<div className="main-contents">
|
||||
@ -143,7 +125,7 @@ export default function MainPage() {
|
||||
</>
|
||||
)) || (
|
||||
<>
|
||||
<ChangePasswordPop />
|
||||
<ChangePasswordPop setChagePasswordPopOpen={setChagePasswordPopOpen} />
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -8,13 +8,13 @@ import { contextPopupPositionState } from '@/store/popupAtom'
|
||||
|
||||
export default function ColorPickerModal(props) {
|
||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState) // 현재 메뉴
|
||||
const { isShow, setIsShow, pos = contextPopupPosition, color = '#ff0000', setColor, id, isConfig = false } = props
|
||||
const { getMessage } = useMessage()
|
||||
const { isShow, setIsShow, pos = contextPopupPosition, color, setColor, id, isConfig = false } = props //color = '#ff0000'
|
||||
const [originColor, setOriginColor] = useState(color)
|
||||
const { getMessage } = useMessage()
|
||||
const { closePopup } = usePopup()
|
||||
|
||||
useEffect(() => {
|
||||
setOriginColor(color)
|
||||
setOriginColor(originColor)
|
||||
}, [isShow])
|
||||
|
||||
return (
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect, useState, useContext } from 'react'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil'
|
||||
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
|
||||
@ -9,7 +9,7 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker'
|
||||
import EstimateFileUploader from './EstimateFileUploader'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import dayjs from 'dayjs'
|
||||
import { useCommonCode } from '@/hooks/common/useCommonCode'
|
||||
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
|
||||
@ -18,8 +18,11 @@ import Select, { components } from 'react-select'
|
||||
import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from '@/util/common-utils'
|
||||
import ProductFeaturesPop from './popup/ProductFeaturesPop'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { correntObjectNoState } from '@/store/settingAtom'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
|
||||
export default function Estimate({ params }) {
|
||||
const [uniqueData, setUniqueData] = useState([])
|
||||
const [handlePricingFlag, setHandlePricingFlag] = useState(false)
|
||||
const [specialNoteFirstFlg, setSpecialNoteFirstFlg] = useState(false)
|
||||
const fixedKey = 'itemKey'
|
||||
@ -73,6 +76,15 @@ export default function Estimate({ params }) {
|
||||
|
||||
const { setMenuNumber } = useCanvasMenu()
|
||||
|
||||
/**
|
||||
* objectNo 셋팅
|
||||
* url로 넘어온 objectNo을 리코일에 세팅
|
||||
*/
|
||||
const setCurrentObjectNo = useSetRecoilState(correntObjectNoState)
|
||||
const searchParams = useSearchParams()
|
||||
const currentObjectNo = searchParams.get('objectNo')
|
||||
setCurrentObjectNo(currentObjectNo)
|
||||
|
||||
//새로 추가한 첨부파일 props
|
||||
const fileUploadProps = {
|
||||
uploadFiles: files,
|
||||
@ -119,11 +131,9 @@ export default function Estimate({ params }) {
|
||||
let url = `/api/estimate/special-note-title-list`
|
||||
get({ url: url }).then((res) => {
|
||||
if (isNotEmptyArray(res)) {
|
||||
//디테일 ATTR001、ATTR002、ATTR003、ATTR007、ATTR009、ATTR010、ATTR015、ATTR019
|
||||
if (estimateContextState?.estimateOption) {
|
||||
res.map((row) => {
|
||||
let estimateOption = estimateContextState?.estimateOption?.split('、')
|
||||
// console.log('최초:::', estimateOption)
|
||||
row.check = false
|
||||
estimateOption.map((row2) => {
|
||||
if (row.pkgYn === '0') {
|
||||
@ -140,10 +150,10 @@ export default function Estimate({ params }) {
|
||||
//detail과 상관없이 디폴트 체크목록
|
||||
//ATTR003,ATTR007
|
||||
if (row.code === 'ATTR003') {
|
||||
row.check = true
|
||||
//row.check = true
|
||||
}
|
||||
if (row.code === 'ATTR007') {
|
||||
row.check = true
|
||||
//row.check = true
|
||||
}
|
||||
})
|
||||
|
||||
@ -167,14 +177,20 @@ export default function Estimate({ params }) {
|
||||
|
||||
//견적일 set
|
||||
useEffect(() => {
|
||||
let estimateDate = dayjs(startDate).format('YYYY-MM-DD')
|
||||
if (begin === 1) {
|
||||
setEstimateContextState({ estimateDate: estimateDate })
|
||||
let estimateDate
|
||||
if (startDate) {
|
||||
estimateDate = dayjs(startDate).format('YYYY-MM-DD')
|
||||
if (begin === 1) {
|
||||
setEstimateContextState({ estimateDate: estimateDate })
|
||||
}
|
||||
} else {
|
||||
setEstimateContextState({ estimateDate: '' })
|
||||
}
|
||||
}, [startDate])
|
||||
|
||||
useEffect(() => {
|
||||
//선택된 견적특이사항 setEstimateContextState
|
||||
|
||||
if (isNotEmptyArray(specialNoteList)) {
|
||||
const liveCheckedData = specialNoteList.filter((row) => row.check === true)
|
||||
|
||||
@ -184,14 +200,14 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
|
||||
const newData = data.join('、')
|
||||
setEstimateContextState({ estimateOption: newData })
|
||||
//저장용 보내기
|
||||
setEstimateContextState({ estimateOption: newData, specialNoteList: specialNoteList, uniqueData: uniqueData })
|
||||
}
|
||||
}, [specialNoteList])
|
||||
|
||||
// 견적특이사항 remark 보여주기
|
||||
const settingShowContent = (code, event) => {
|
||||
const settingShowContent = (code) => {
|
||||
setShowContentCode(code)
|
||||
event.stopPropagation()
|
||||
}
|
||||
|
||||
// 추가한 첨부파일 estimateContextState에 넣기
|
||||
@ -200,10 +216,11 @@ export default function Estimate({ params }) {
|
||||
let fileList = []
|
||||
files.map((row) => {
|
||||
fileList.push(row.data)
|
||||
setEstimateContextState({ fileList: row.data, tempFileList: fileList })
|
||||
setEstimateContextState({ fileList: row.data, newFileList: fileList })
|
||||
// setEstimateContextState({ fileList: row.data })
|
||||
})
|
||||
} else {
|
||||
setEstimateContextState({ fileList: [] })
|
||||
setEstimateContextState({ fileList: [], newFileList: [] })
|
||||
}
|
||||
}, [files])
|
||||
|
||||
@ -213,26 +230,49 @@ export default function Estimate({ params }) {
|
||||
//드래그영역 비워주기
|
||||
setFiles([])
|
||||
setOriginFiles(estimateContextState.fileList)
|
||||
} else {
|
||||
if (originFiles.length > 0) {
|
||||
if (isEmptyArray(files)) {
|
||||
let file
|
||||
file = originFiles.filter((item) => item.delFlg === '0')
|
||||
setEstimateContextState({
|
||||
originFiles: file,
|
||||
})
|
||||
setOriginFiles(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [estimateContextState?.fileList])
|
||||
|
||||
// 기존첨부파일 삭제
|
||||
const deleteOriginFile = async (objectNo, no) => {
|
||||
const delParams = {
|
||||
userId: session.userId,
|
||||
objectNo: objectNo,
|
||||
no: no,
|
||||
}
|
||||
await promisePost({ url: 'api/file/fileDelete', data: delParams }).then((res) => {
|
||||
if (res.status === 204) {
|
||||
setOriginFiles(originFiles.filter((file) => file.objectNo === objectNo && file.no !== no))
|
||||
setEstimateContextState({
|
||||
fileList: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no),
|
||||
})
|
||||
|
||||
alert(getMessage('plan.message.delete'))
|
||||
// 삭제누른 첨부파일 복원
|
||||
const returnOriginFile = (no) => {
|
||||
originFiles.map((file) => {
|
||||
if (file.no === no) {
|
||||
file.delFlg = '0'
|
||||
}
|
||||
})
|
||||
setOriginFiles((prev) => {
|
||||
return [...prev]
|
||||
})
|
||||
setEstimateContextState({
|
||||
originFiles: originFiles,
|
||||
})
|
||||
}
|
||||
// 기존첨부파일 삭제 (플래그값 추가?) 저장할때 플래그값에 따라 진짜 삭제
|
||||
const deleteOriginFile = (no) => {
|
||||
originFiles.map((file) => {
|
||||
if (file.no === no) {
|
||||
file.delFlg = '1'
|
||||
}
|
||||
})
|
||||
|
||||
setOriginFiles((prev) => {
|
||||
return [...prev]
|
||||
})
|
||||
setEstimateContextState({
|
||||
originFiles: originFiles,
|
||||
})
|
||||
alert(getMessage('estimate.detail.alert.delFile'))
|
||||
}
|
||||
|
||||
//가격표시 option 목록 최초세팅 && 주문분류 변경시
|
||||
@ -291,22 +331,66 @@ export default function Estimate({ params }) {
|
||||
|
||||
//가격 표시 option 변경 이벤트
|
||||
const onChangeStorePriceList = (priceCd) => {
|
||||
const param = {
|
||||
saleStoreId: session.storeId,
|
||||
sapSalesStoreCd: session.custCd,
|
||||
docTpCd: priceCd,
|
||||
}
|
||||
|
||||
//프라이싱 했을때 priceCd setEstimateContextState
|
||||
//화면에 보여지는 값은 showPriceCd로 관리
|
||||
setShowPriceCd(priceCd)
|
||||
// return
|
||||
// const param = {
|
||||
// saleStoreId: session.storeId,
|
||||
// sapSalesStoreCd: session.custCd,
|
||||
// docTpCd: priceCd,
|
||||
// }
|
||||
|
||||
const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
if (isNotEmptyArray(res?.data)) {
|
||||
setStorePriceList(res.data)
|
||||
// const apiUrl = `/api/estimate/price/store-price-list?${queryStringFormatter(param)}`
|
||||
// get({ url: apiUrl }).then((res) => {
|
||||
// if (isNotEmptyArray(res?.data)) {
|
||||
// setStorePriceList(res.data)
|
||||
// }
|
||||
// })
|
||||
}
|
||||
|
||||
const makeUniqueSpecialNoteCd = (itemList) => {
|
||||
let pushData = []
|
||||
let uniquSet = new Set()
|
||||
|
||||
itemList.forEach((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
if (item.specialNoteCd) {
|
||||
let splitData = item.specialNoteCd.split('、')
|
||||
splitData.forEach((note) => {
|
||||
if (!uniquSet.has(note)) {
|
||||
uniquSet.add(note)
|
||||
pushData.push(note)
|
||||
}
|
||||
})
|
||||
|
||||
setSpecialNoteFirstFlg(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
setUniqueData(pushData)
|
||||
specialNoteList.map((item) => {
|
||||
if (item.pkgYn === '1') {
|
||||
let flg = '0'
|
||||
let codes = item.code
|
||||
for (let i = 0; i < pushData.length; i++) {
|
||||
if (codes.indexOf(pushData[i]) > -1) {
|
||||
flg = '1'
|
||||
}
|
||||
}
|
||||
|
||||
if (flg === '1') {
|
||||
item.check = true
|
||||
} else {
|
||||
item.check = false
|
||||
}
|
||||
}
|
||||
})
|
||||
setEstimateContextState({
|
||||
specialNoteList: specialNoteList,
|
||||
uniqueData: uniqueData,
|
||||
})
|
||||
}
|
||||
|
||||
//Pricing 버튼
|
||||
@ -351,23 +435,26 @@ export default function Estimate({ params }) {
|
||||
if (isNotEmptyArray(data.data2)) {
|
||||
estimateContextState.itemList.map((item) => {
|
||||
let checkYn = false
|
||||
data.data2.map((item2) => {
|
||||
if (item2) {
|
||||
if (item2.itemId === item.itemId) {
|
||||
for (let i = 0; i < data.data2.length; i++) {
|
||||
if (data.data2[i]) {
|
||||
if (data.data2[i].itemId === item.itemId) {
|
||||
updateList.push({
|
||||
...item,
|
||||
salePrice: item2.unitPrice === null ? '0' : item2.unitPrice,
|
||||
saleTotPrice: (item.amount * item2.unitPrice).toString(),
|
||||
openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
|
||||
salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
|
||||
saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
|
||||
})
|
||||
checkYn = true
|
||||
break
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (!checkYn) {
|
||||
updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' })
|
||||
}
|
||||
})
|
||||
|
||||
setEstimateContextState({
|
||||
priceCd: showPriceCd,
|
||||
itemList: updateList,
|
||||
@ -411,23 +498,41 @@ export default function Estimate({ params }) {
|
||||
setSelection(newSelection)
|
||||
}
|
||||
|
||||
function formatNumberWithComma(number) {
|
||||
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
|
||||
}
|
||||
|
||||
//주택PKG input 변경
|
||||
const onChangePkgAsp = (value) => {
|
||||
if (estimateContextState.estimateType === 'YJSS') {
|
||||
let pkgAsp = Number(value.replaceAll(',', ''))
|
||||
if (isNaN(pkgAsp)) {
|
||||
pkgAsp = 0
|
||||
} else {
|
||||
pkgAsp = pkgAsp.toLocaleString()
|
||||
let newValue = value.replace(/[^0-9.]/g, '')
|
||||
if (newValue.length > 1) {
|
||||
newValue = newValue.replace(/(^0+)/, '')
|
||||
if (newValue.length === 0) {
|
||||
newValue = '0'
|
||||
}
|
||||
}
|
||||
//현재 PKG용량값 가져오기
|
||||
|
||||
const parts = newValue.split('.')
|
||||
if (parts.length > 2) {
|
||||
newValue = parts[0] + '.' + parts.slice(1).join('')
|
||||
}
|
||||
|
||||
if (parts[1] && parts[1].length > 2) {
|
||||
newValue = parts[0] + '.' + parts[1].substring(0, 2)
|
||||
}
|
||||
|
||||
let pkgAsp = newValue || '0'
|
||||
|
||||
//현재 PKG용량값 가져오기
|
||||
let totVolKw = estimateContextState.totVolKw * 1000
|
||||
let pkgTotPrice = pkgAsp.replaceAll(',', '') * totVolKw * 1000
|
||||
let pkgTotPrice = parseFloat(pkgAsp?.replaceAll(',', '')) * totVolKw * 1000
|
||||
|
||||
// pkgAsp = formatNumberWithComma(parseFloat(pkgAsp).toFixed(2))
|
||||
|
||||
setEstimateContextState({
|
||||
pkgAsp: pkgAsp,
|
||||
pkgTotPrice: pkgTotPrice.toFixed(3),
|
||||
pkgTotPrice: pkgTotPrice.toFixed(2),
|
||||
})
|
||||
//아이템들 중 조건에 맞는애들 뽑아서 상단 공급가액 부가세 총액 수정
|
||||
setItemChangeYn(true)
|
||||
@ -438,6 +543,7 @@ export default function Estimate({ params }) {
|
||||
const onChangeAmount = (value, dispOrder, index) => {
|
||||
//itemChangeFlg = 1, partAdd = 0 셋팅
|
||||
let amount = Number(value.replace(/[^0-9]/g, '').replaceAll(',', ''))
|
||||
|
||||
if (isNaN(amount)) {
|
||||
amount = '0'
|
||||
} else {
|
||||
@ -511,7 +617,7 @@ export default function Estimate({ params }) {
|
||||
let updateList = []
|
||||
let updates = {}
|
||||
get({ url: apiUrl }).then((res) => {
|
||||
console.log('아이템디테일::::::::', res)
|
||||
// console.log('아이템디테일::::::::', res)
|
||||
updates.objectNo = objectNo
|
||||
updates.planNo = planNo
|
||||
updates.itemId = res.itemId
|
||||
@ -526,22 +632,27 @@ export default function Estimate({ params }) {
|
||||
updates.pkgMaterialFlg = res.pkgMaterialFlg
|
||||
updates.pnowW = res.pnowW
|
||||
updates.salePrice = res.salePrice
|
||||
// updates.salePrice = ''
|
||||
updates.specification = res.specification
|
||||
updates.unit = res.unit
|
||||
updates.specialNoteCd = res.spnAttrCds
|
||||
updates.itemGroup = res.itemGroup
|
||||
updates.delFlg = '0' // 삭제플래그 0
|
||||
updates.saleTotPrice = (res.salePrice * estimateContextState.itemList[index].amount).toString()
|
||||
// updates.saleTotPrice = ''
|
||||
updates.amount = ''
|
||||
updates.openFlg = res.openFlg
|
||||
|
||||
if (estimateContextState.estimateType === 'YJSS') {
|
||||
if (res.pkgMaterialFlg === '0') {
|
||||
updates.showSalePrice = '0'
|
||||
updates.showSaleTotPrice = '0'
|
||||
}
|
||||
} else {
|
||||
if (res.openFlg === '1') {
|
||||
updates.showSalePrice = '0'
|
||||
updates.showSaleTotPrice = '0'
|
||||
}
|
||||
}
|
||||
|
||||
//104671
|
||||
let bomList = res.itemBomList
|
||||
|
||||
@ -557,7 +668,6 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
}
|
||||
} else if (item.paDispOrder === dispOrder) {
|
||||
//봄제품을 바꿨을떄
|
||||
return { ...item, delFlg: '1' }
|
||||
} else {
|
||||
return item
|
||||
@ -574,19 +684,23 @@ export default function Estimate({ params }) {
|
||||
bomItem.salePrice = '0'
|
||||
bomItem.saleTotPrice = '0'
|
||||
bomItem.unitPrice = '0'
|
||||
bomItem.showSalePrice = '0'
|
||||
} else {
|
||||
bomItem.dispOrder = (index + 1 + Number(dispOrder)).toString()
|
||||
bomItem.paDispOrder = dispOrder
|
||||
bomItem.salePrice = '0'
|
||||
bomItem.saleTotPrice = '0'
|
||||
bomItem.unitPrice = '0'
|
||||
bomItem.showSalePrice = '0'
|
||||
}
|
||||
|
||||
bomItem.delFlg = '0'
|
||||
bomItem.objectNo = objectNo
|
||||
bomItem.planNo = planNo
|
||||
bomItem.addFlg = true //봄 추가시도 addFlg
|
||||
})
|
||||
|
||||
updateList = updateList.filter((item) => item.delFlg === '0')
|
||||
setEstimateContextState({
|
||||
itemList: [...updateList, ...bomList],
|
||||
})
|
||||
@ -603,6 +717,9 @@ export default function Estimate({ params }) {
|
||||
//제품 삭제
|
||||
const removeItem = () => {
|
||||
const array = [...selection]
|
||||
if (isEmptyArray(array)) {
|
||||
return alert(getMessage('estimate.detail.alert.selectDelItem'))
|
||||
}
|
||||
let delList = []
|
||||
estimateContextState.itemList.filter((row) => {
|
||||
array.map((row2) => {
|
||||
@ -644,135 +761,147 @@ export default function Estimate({ params }) {
|
||||
|
||||
useEffect(() => {
|
||||
if (itemChangeYn) {
|
||||
let totAmount = 0
|
||||
let totVolKw = 0
|
||||
let supplyPrice = 0
|
||||
let vatPrice = 0
|
||||
let totPrice = 0
|
||||
let addSupplyPrice = 0
|
||||
if (estimateContextState.estimateType === 'YJOD') {
|
||||
estimateContextState.itemList.sort((a, b) => {
|
||||
return a.dispOrder - b.dispOrder
|
||||
})
|
||||
console.log('YJOD 토탈만들어주기::::::::::', estimateContextState.itemList)
|
||||
let totals = {
|
||||
totAmount: 0,
|
||||
totVolKw: 0,
|
||||
supplyPrice: 0,
|
||||
vatPrice: 0,
|
||||
totPrice: 0,
|
||||
addSupplyPrice: 0,
|
||||
pkgTotPrice: 0,
|
||||
}
|
||||
|
||||
let pushData = []
|
||||
let uniquSet = new Set()
|
||||
const calculateYJODTotals = (itemList) => {
|
||||
itemList.sort((a, b) => a.dispOrder - b.dispOrder)
|
||||
makeUniqueSpecialNoteCd(itemList)
|
||||
|
||||
estimateContextState.itemList.forEach((item) => {
|
||||
if (item.delFlg === '1') {
|
||||
if (item.specialNoteCd) {
|
||||
let splitData = item.specialNoteCd.split('、')
|
||||
splitData.forEach((note) => {
|
||||
if (!uniquSet.has(note)) {
|
||||
uniquSet.add(note)
|
||||
pushData.push(note)
|
||||
}
|
||||
})
|
||||
|
||||
setSpecialNoteFirstFlg(false)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
estimateContextState.itemList.map((item) => {
|
||||
itemList.forEach((item) => {
|
||||
delete item.showSalePrice
|
||||
delete item.showSaleTotPrice
|
||||
if (item.delFlg === '0') {
|
||||
let amount = Number(item?.amount?.replace(/[^0-9]/g, '').replaceAll(',', ''))
|
||||
if (isNaN(amount)) {
|
||||
amount = '0'
|
||||
}
|
||||
let price = Number(item?.saleTotPrice?.replaceAll(',', ''))
|
||||
if (isNaN(price)) {
|
||||
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
|
||||
let price
|
||||
if (amount === 0) {
|
||||
price = 0
|
||||
} else {
|
||||
price = Number(item.saleTotPrice?.replaceAll(',', '')) || 0
|
||||
}
|
||||
|
||||
if (item.moduleFlg === '1') {
|
||||
//용량(Kw)은 모듈플래그 1만 합산
|
||||
const volKw = (item.pnowW * amount) / 1000
|
||||
// const volKw = item.pnowW * amount
|
||||
totVolKw += volKw
|
||||
totals.totVolKw += volKw
|
||||
}
|
||||
totals.supplyPrice += price
|
||||
totals.totAmount += amount
|
||||
|
||||
if (item.paDispOrder) {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
if (item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
// const price
|
||||
totAmount += amount
|
||||
supplyPrice += price
|
||||
}
|
||||
})
|
||||
|
||||
vatPrice = supplyPrice * 0.1
|
||||
totPrice = supplyPrice + vatPrice
|
||||
totals.vatPrice = totals.supplyPrice * 0.1
|
||||
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
||||
}
|
||||
|
||||
setEstimateContextState({
|
||||
totAmount: totAmount,
|
||||
totVolKw: totVolKw.toFixed(3),
|
||||
supplyPrice: supplyPrice.toFixed(3),
|
||||
vatPrice: vatPrice.toFixed(3),
|
||||
totPrice: totPrice.toFixed(3),
|
||||
})
|
||||
} else {
|
||||
//YJSS
|
||||
console.log('YJSS 토탈만들어주기::::::::::', estimateContextState.itemList)
|
||||
estimateContextState.itemList.sort((a, b) => {
|
||||
return a.dispOrder - b.dispOrder
|
||||
})
|
||||
estimateContextState.itemList.map((item) => {
|
||||
const calculateYJSSTotals = (itemList) => {
|
||||
itemList.sort((a, b) => a.dispOrder - b.dispOrder)
|
||||
makeUniqueSpecialNoteCd(itemList)
|
||||
itemList.forEach((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', ''))
|
||||
let salePrice = Number(item.salePrice?.replaceAll(',', ''))
|
||||
let saleTotPrice = Number(item.saleTotPrice?.replaceAll(',', ''))
|
||||
|
||||
if (isNaN(amount)) {
|
||||
amount = '0'
|
||||
}
|
||||
|
||||
if (isNaN(saleTotPrice)) {
|
||||
saleTotPrice = 0
|
||||
}
|
||||
|
||||
if (isNaN(salePrice)) {
|
||||
salePrice = 0
|
||||
}
|
||||
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
|
||||
let salePrice
|
||||
if (item.moduleFlg === '1') {
|
||||
//용량(Kw)은 모듈플래그 1만 합산
|
||||
const volKw = (item.pnowW * amount) / 1000
|
||||
// const volKw = item.pnowW * amount
|
||||
totVolKw += volKw
|
||||
totals.totVolKw += volKw
|
||||
}
|
||||
setEstimateContextState({
|
||||
pkgTotPrice: estimateContextState.pkgAsp.replaceAll(',', '') * totVolKw * 1000,
|
||||
})
|
||||
//pkgTotPrice
|
||||
// const saleTotPrice
|
||||
totAmount += amount
|
||||
if (amount === 0) {
|
||||
salePrice = 0
|
||||
} else {
|
||||
salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
|
||||
}
|
||||
|
||||
totals.totAmount += amount
|
||||
if (item.pkgMaterialFlg === '1') {
|
||||
const pkgPrice = amount * salePrice
|
||||
//다시계산하기
|
||||
//YJSS는 PKG제외상품들만(1) 모아서 수량 * 단가를 공급가액(supplyPrice)에 추가로 더해줌
|
||||
addSupplyPrice += pkgPrice
|
||||
const saleTotPrice = amount * salePrice
|
||||
totals.addSupplyPrice += saleTotPrice
|
||||
}
|
||||
|
||||
if (!item.paDispOrder) {
|
||||
//paDispOrder
|
||||
if (item.pkgMaterialFlg === '0') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
} else {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
|
||||
if (item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
}
|
||||
})
|
||||
supplyPrice = addSupplyPrice + Number(estimateContextState.pkgTotPrice / 1000)
|
||||
vatPrice = supplyPrice * 0.1
|
||||
totPrice = supplyPrice + vatPrice
|
||||
let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
|
||||
|
||||
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
|
||||
totals.supplyPrice = totals.addSupplyPrice + totals.pkgTotPrice
|
||||
totals.vatPrice = totals.supplyPrice * 0.1
|
||||
totals.totPrice = totals.supplyPrice + totals.vatPrice
|
||||
}
|
||||
if (estimateContextState.estimateType === 'YJOD') {
|
||||
calculateYJODTotals(estimateContextState.itemList)
|
||||
setEstimateContextState({
|
||||
totAmount: totAmount,
|
||||
totVolKw: totVolKw.toFixed(3),
|
||||
supplyPrice: supplyPrice.toFixed(3),
|
||||
vatPrice: vatPrice.toFixed(3),
|
||||
totPrice: totPrice.toFixed(3),
|
||||
totAmount: totals.totAmount,
|
||||
totVolKw: totals.totVolKw.toFixed(2),
|
||||
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
})
|
||||
} else if (estimateContextState.estimateType === 'YJSS') {
|
||||
calculateYJSSTotals(estimateContextState.itemList)
|
||||
setEstimateContextState({
|
||||
pkgTotPrice: totals.pkgTotPrice,
|
||||
totAmount: totals.totAmount,
|
||||
totVolKw: totals.totVolKw.toFixed(2),
|
||||
supplyPrice: totals.supplyPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
vatPrice: totals.vatPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
totPrice: totals.totPrice.toFixed(0), //소수첫자리에서 반올림
|
||||
})
|
||||
}
|
||||
|
||||
setItemChangeYn(false)
|
||||
} else {
|
||||
estimateContextState.itemList.forEach((item) => {
|
||||
if (estimateContextState.estimateType === 'YJSS' && !item.paDispOrder && item.pkgMaterialFlg === '0') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
if (estimateContextState.estimateType === 'YJSS' && item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
if (estimateContextState.estimateType === 'YJSS' && item.paDispOrder) {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
})
|
||||
estimateContextState.itemList.forEach((item) => {
|
||||
if (estimateContextState.estimateType === 'YJOD' && item.openFlg === '1') {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
if (estimateContextState.estimateType === 'YJOD' && item.paDispOrder) {
|
||||
item.showSalePrice = '0'
|
||||
item.showSaleTotPrice = '0'
|
||||
}
|
||||
})
|
||||
}
|
||||
}, [itemChangeYn, estimateContextState.itemList])
|
||||
|
||||
@ -966,18 +1095,15 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
//사양시공
|
||||
let constructSpecificationMulti = estimateContextState?.constructSpecificationMulti?.split('、')
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`form-flex-wrap ${style}`} key={fixedKey}>
|
||||
<div className="input-wrap mr5" style={{ width: '610px' }} key={`roof${index}`}>
|
||||
<input type="text" className="input-light" value={roofList} readOnly />
|
||||
</div>
|
||||
<div className="input-wrap" style={{ width: '200px' }}>
|
||||
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly />
|
||||
</div>
|
||||
<div className={`form-flex-wrap ${style}`} key={`roof_${row}`}>
|
||||
<div className="input-wrap mr5" style={{ width: '610px' }}>
|
||||
<input type="text" className="input-light" value={roofList} readOnly />
|
||||
</div>
|
||||
</>
|
||||
<div className="input-wrap" style={{ width: '200px' }}>
|
||||
<input type="text" className="input-light" value={constructSpecificationMulti[index]} readOnly />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</td>
|
||||
@ -987,7 +1113,7 @@ export default function Estimate({ params }) {
|
||||
<th>{getMessage('estimate.detail.remarks')}</th>
|
||||
<td colSpan={3}>
|
||||
<div className="input-wrap">
|
||||
<input type="text" className="input-light" defaultValue={estimateContextState?.remarks} onBlur={handleBlurRemarks} />
|
||||
<input type="text" className="input-light" defaultValue={estimateContextState?.remarks || ''} onBlur={handleBlurRemarks} />
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@ -1064,18 +1190,38 @@ export default function Estimate({ params }) {
|
||||
<ul className="file-list">
|
||||
{originFiles.map((originFile) => {
|
||||
return (
|
||||
<li className="file-item" key={uuidv4()}>
|
||||
<span onClick={() => handleEstimateFileDownload(originFile)}>
|
||||
{originFile.faileName}
|
||||
<button
|
||||
type="button"
|
||||
className="delete"
|
||||
onClick={(e) => {
|
||||
deleteOriginFile(originFile.objectNo, originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
></button>
|
||||
</span>
|
||||
<li className="file-item" key={originFile.no}>
|
||||
{/* <li className="file-item" key={uuidv4()}> */}
|
||||
<div className="file-item-wrap">
|
||||
<span
|
||||
style={{ display: originFile.delFlg === '0' ? '' : 'none' }}
|
||||
onClick={() => handleEstimateFileDownload(originFile)}
|
||||
>
|
||||
{originFile.faileName}
|
||||
<button
|
||||
type="button"
|
||||
className="delete"
|
||||
onClick={(e) => {
|
||||
deleteOriginFile(originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
></button>
|
||||
</span>
|
||||
<div className="return-wrap" style={{ display: originFile.delFlg !== '0' ? '' : 'none' }}>
|
||||
<span className="return">{originFile.faileName}</span>
|
||||
<button
|
||||
type="button"
|
||||
className="return-btn"
|
||||
onClick={(e) => {
|
||||
returnOriginFile(originFile.no)
|
||||
e.stopPropagation()
|
||||
}}
|
||||
>
|
||||
<i className="return-ico"></i>
|
||||
{getMessage('estimate.detail.fileList2.btn.return')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
@ -1108,29 +1254,31 @@ export default function Estimate({ params }) {
|
||||
{specialNoteList.length > 0 &&
|
||||
specialNoteList.map((row) => {
|
||||
return (
|
||||
<div
|
||||
key={uuidv4()}
|
||||
className="special-note-check-item"
|
||||
onClick={(event) => {
|
||||
// settingShowContent(row.code, event)
|
||||
}}
|
||||
>
|
||||
<div className="d-check-box light">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={row.code}
|
||||
checked={!!row.check}
|
||||
disabled={row.code === 'ATTR001' ? true : false}
|
||||
onChange={(event) => {
|
||||
setSpecialNoteList((specialNote) =>
|
||||
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
|
||||
)
|
||||
settingShowContent(row.code, event)
|
||||
// <div key={uuidv4()} className="special-note-check-item">
|
||||
<div key={row.code} className="special-note-check-item">
|
||||
<div className="special-note-check-box">
|
||||
<div className="d-check-box light">
|
||||
<input
|
||||
type="checkbox"
|
||||
id={row.code}
|
||||
checked={!!row.check}
|
||||
disabled={row.code === 'ATTR001' || row.pkgYn === '1' ? true : false}
|
||||
onChange={() => {
|
||||
setSpecialNoteList((specialNote) =>
|
||||
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
|
||||
)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={row.code}></label>
|
||||
</div>
|
||||
<span
|
||||
className="check-name"
|
||||
onClick={() => {
|
||||
settingShowContent(row.code)
|
||||
}}
|
||||
/>
|
||||
<label htmlFor={row.code}>
|
||||
{row.codeNm} / {row.code}
|
||||
</label>
|
||||
>
|
||||
{row.codeNm}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -1146,7 +1294,7 @@ export default function Estimate({ params }) {
|
||||
|
||||
if (isObjectNotEmpty(showcontent)) {
|
||||
return (
|
||||
<dl key={uuidv4()}>
|
||||
<dl key={row.code}>
|
||||
<dt>{showcontent.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: showcontent.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
@ -1161,12 +1309,23 @@ export default function Estimate({ params }) {
|
||||
}
|
||||
})
|
||||
})
|
||||
return pushData.map((item) => (
|
||||
<dl key={uuidv4()}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
//제품에 있는 특이사항만 보여주기 제품에 특이사항이 없으면 전부
|
||||
let filterData = pushData.filter((item) => uniqueData.includes(item.code))
|
||||
if (filterData.length > 0) {
|
||||
return filterData.map((item) => (
|
||||
<dl key={item.code}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
} else {
|
||||
return pushData.map((item) => (
|
||||
<dl key={item.code}>
|
||||
<dt>{item.codeNm}</dt>
|
||||
<dd dangerouslySetInnerHTML={{ __html: item.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
})}
|
||||
@ -1192,19 +1351,19 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totVolKw')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 3)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.supplyPrice')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimal(estimateContextState?.supplyPrice)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.supplyPrice, 0)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.vatPrice')}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimal(estimateContextState?.vatPrice)}</div>
|
||||
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.vatPrice, 0)}</div>
|
||||
</div>
|
||||
<div className="estimate-box">
|
||||
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totPrice')}</div>
|
||||
<div className="estimate-name red">{convertNumberToPriceDecimal(estimateContextState?.totPrice)}</div>
|
||||
<div className="estimate-name red">{convertNumberToPriceDecimalToFixed(estimateContextState?.totPrice, 0)}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1238,7 +1397,7 @@ export default function Estimate({ params }) {
|
||||
</div>
|
||||
</td>
|
||||
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgWeight')}</th>
|
||||
<td>{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 3)}</td>
|
||||
<td>{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</td>
|
||||
<th>{getMessage('estimate.detail.sepcialEstimateProductInfo.pkgPrice')}</th>
|
||||
<td>{convertNumberToPriceDecimal(estimateContextState?.pkgTotPrice)}</td>
|
||||
</tr>
|
||||
@ -1253,14 +1412,18 @@ export default function Estimate({ params }) {
|
||||
<div className="select-wrap">
|
||||
{session?.storeLvl === '1' ? (
|
||||
<select
|
||||
key={uuidv4()}
|
||||
className="select-light"
|
||||
onChange={(e) => {
|
||||
onChangeStorePriceList(e.target.value)
|
||||
}}
|
||||
value={showPriceCd}
|
||||
>
|
||||
{storePriceList.length > 0 && storePriceList.map((row) => <option value={row.priceCd}>{row.priceNm}</option>)}
|
||||
{storePriceList.length > 0 &&
|
||||
storePriceList.map((row) => (
|
||||
<option key={row.priceCd} value={row.priceCd}>
|
||||
{row.priceNm}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
) : (
|
||||
<select key={uuidv4()} className="select-light">
|
||||
@ -1322,9 +1485,9 @@ export default function Estimate({ params }) {
|
||||
<table>
|
||||
<colgroup>
|
||||
<col width={50} />
|
||||
<col width={50} />
|
||||
<col width={60} />
|
||||
<col />
|
||||
<col width={250} />
|
||||
<col width={300} />
|
||||
<col width={90} />
|
||||
<col width={80} />
|
||||
<col width={170} />
|
||||
@ -1333,7 +1496,6 @@ export default function Estimate({ params }) {
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
{/* <div className="d-check-box pop no-text" style={{ display: 'none' }}> */}
|
||||
<div className="d-check-box pop no-text">
|
||||
<input type="checkbox" id="ch97" checked={isSelectedAll()} onChange={onChangeSelectAll} />
|
||||
<label htmlFor="ch97"></label>
|
||||
@ -1371,7 +1533,7 @@ export default function Estimate({ params }) {
|
||||
<div className="form-flex-wrap">
|
||||
<div className="select-wrap mr5">
|
||||
<Select
|
||||
id="long-value-select1"
|
||||
name="long-value-select1"
|
||||
instanceId="long-value-select1"
|
||||
className="react-select-custom"
|
||||
classNamePrefix="custom"
|
||||
@ -1439,11 +1601,17 @@ export default function Estimate({ params }) {
|
||||
className="input-light al-r"
|
||||
value={convertNumberToPriceDecimal(item?.showSalePrice === '0' ? null : item?.salePrice?.replaceAll(',', ''))}
|
||||
disabled={
|
||||
estimateContextState?.estimateType === 'YJSS'
|
||||
? item?.paDispOrder
|
||||
? true
|
||||
: item.pkgMaterialFlg !== '1'
|
||||
: item.itemId === '' || !!item?.paDispOrder
|
||||
item.openFlg === '1'
|
||||
? true
|
||||
: estimateContextState?.estimateType === 'YJSS'
|
||||
? item?.paDispOrder
|
||||
? true
|
||||
: item.pkgMaterialFlg !== '1'
|
||||
: item.itemId === '' || !!item?.paDispOrder
|
||||
? true
|
||||
: item.openFlg === '1'
|
||||
? true
|
||||
: false
|
||||
}
|
||||
onChange={(e) => {
|
||||
onChangeSalePrice(e.target.value, item.dispOrder, index)
|
||||
@ -1451,13 +1619,23 @@ export default function Estimate({ params }) {
|
||||
maxLength={12}
|
||||
/>
|
||||
</div>
|
||||
{/* <div className="btn-area">
|
||||
<span className="tb_ico open_check"></span>
|
||||
</div> */}
|
||||
{item.openFlg === '1' && (
|
||||
<div className="btn-area">
|
||||
<span className="tb_ico open_check"></span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</td>
|
||||
<td className="al-r">
|
||||
{convertNumberToPriceDecimal(item?.showSaleTotPrice === '0' ? null : item?.saleTotPrice?.replaceAll(',', ''))}
|
||||
{convertNumberToPriceDecimal(
|
||||
item?.showSaleTotPrice === '0'
|
||||
? null
|
||||
: item?.amount === ''
|
||||
? null
|
||||
: item?.saleTotPrice === '0'
|
||||
? null
|
||||
: item?.saleTotPrice?.replaceAll(',', ''),
|
||||
)}
|
||||
</td>
|
||||
</tr>
|
||||
)
|
||||
|
||||
@ -11,7 +11,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
|
||||
const { getMessage } = useMessage()
|
||||
const { get } = useAxios()
|
||||
|
||||
const { handleEstimateCopy, state } = useEstimateController(planNo)
|
||||
const { handleEstimateCopy, estimateContextState } = useEstimateController(planNo)
|
||||
|
||||
const { session } = useContext(SessionContext)
|
||||
|
||||
@ -105,10 +105,10 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
|
||||
}, [planNo])
|
||||
|
||||
useEffect(() => {
|
||||
if (state?.charger) {
|
||||
setCopyReceiveUser(state.charger)
|
||||
if (estimateContextState?.charger) {
|
||||
setCopyReceiveUser(estimateContextState.charger)
|
||||
}
|
||||
}, [state.charger])
|
||||
}, [estimateContextState?.charger])
|
||||
|
||||
//T01 1차점 자동완성 인풋때 목록 변환
|
||||
const onInputChange = (key) => {
|
||||
@ -282,7 +282,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
|
||||
type="text"
|
||||
className="input-light"
|
||||
required
|
||||
defaultValue={state?.charger}
|
||||
defaultValue={estimateContextState?.charger}
|
||||
onChange={(e) => {
|
||||
setCopyReceiveUser(e.target.value)
|
||||
}}
|
||||
|
||||
@ -40,9 +40,8 @@ export default function ProductFeaturesPop({ popShowSpecialNoteList, showProduct
|
||||
{showSpecialNoteList.length > 0 &&
|
||||
showSpecialNoteList.map((row) => {
|
||||
return (
|
||||
<dl>
|
||||
<dl key={row.code}>
|
||||
<dt>{row.codeNm}</dt>
|
||||
{/* <dd dangerouslySetInnerHTML={{ __html: row.remarks }}></dd> */}
|
||||
<dd dangerouslySetInnerHTML={{ __html: row.remarks }} style={{ whiteSpace: 'pre-wrap' }}></dd>
|
||||
</dl>
|
||||
)
|
||||
|
||||
@ -15,7 +15,6 @@ import { MENU } from '@/common/common'
|
||||
import PanelBatchStatistics from '@/components/floor-plan/modal/panelBatch/PanelBatchStatistics'
|
||||
import { totalDisplaySelector } from '@/store/settingAtom'
|
||||
import ImgLoad from '@/components/floor-plan/modal/ImgLoad'
|
||||
import { EventContext } from '@/app/floor-plan/EventProvider'
|
||||
|
||||
export default function CanvasFrame() {
|
||||
const canvasRef = useRef(null)
|
||||
|
||||
@ -20,7 +20,7 @@ export default function CanvasLayout({ children }) {
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { swalFire } = useSwal()
|
||||
const { plans, initCanvasPlans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
|
||||
|
||||
useEffect(() => {
|
||||
loadCanvasPlanData(session.userId, objectNo, pid)
|
||||
@ -34,10 +34,9 @@ export default function CanvasLayout({ children }) {
|
||||
<button
|
||||
key={`plan-${plan.id}`}
|
||||
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
|
||||
onClick={() => handleCurrentPlan(session.userId, plan.id)}
|
||||
onClick={() => handleCurrentPlan(plan.id)}
|
||||
>
|
||||
<span>
|
||||
{!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === plan.id) && 'New '}
|
||||
{`Plan ${plan.ordering}`}
|
||||
{modifiedPlans.some((modifiedPlan) => modifiedPlan === plan.id) && ' [ M ]'}
|
||||
</span>
|
||||
@ -45,10 +44,7 @@ export default function CanvasLayout({ children }) {
|
||||
className="close"
|
||||
onClick={(e) =>
|
||||
swalFire({
|
||||
text:
|
||||
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === plan.id) ? 'New ' : '') +
|
||||
`Plan ${plan.ordering} ` +
|
||||
getMessage('plan.message.confirm.delete'),
|
||||
text: `Plan ${plan.ordering} ` + getMessage('plan.message.confirm.delete'),
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
handleDeletePlan(e, plan.id)
|
||||
|
||||
@ -40,6 +40,8 @@ import EstimateCopyPop from '../estimate/popup/EstimateCopyPop'
|
||||
import { pwrGnrSimTypeState } from '@/store/simulatorAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
|
||||
export default function CanvasMenu(props) {
|
||||
const { menuNumber, setMenuNumber } = props
|
||||
const pathname = usePathname()
|
||||
@ -49,7 +51,7 @@ export default function CanvasMenu(props) {
|
||||
const [type, setType] = useRecoilState(menuTypeState)
|
||||
const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState)
|
||||
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore)
|
||||
const setCurrentMenu = useSetRecoilState(currentMenuState)
|
||||
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
|
||||
const setOuterLinePoints = useSetRecoilState(outerLinePointsState)
|
||||
const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState)
|
||||
const canvasSetting = useRecoilValue(canvasSettingState)
|
||||
@ -66,7 +68,7 @@ export default function CanvasMenu(props) {
|
||||
const [estimateCopyPopupOpen, setEstimateCopyPopupOpen] = useState(false)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { currentCanvasPlan, saveCanvas } = usePlan()
|
||||
const { saveCanvas } = usePlan()
|
||||
const { swalFire } = useSwal()
|
||||
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
|
||||
// const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useContext(EventContext)
|
||||
@ -74,6 +76,7 @@ export default function CanvasMenu(props) {
|
||||
const { commonFunctions } = useCommonUtils()
|
||||
const SelectOption = [{ name: '瓦53A' }, { name: '瓦53A' }]
|
||||
const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
|
||||
const { restoreModuleInstArea } = useModuleBasicSetting()
|
||||
|
||||
const onClickNav = (menu) => {
|
||||
setMenuNumber(menu.index)
|
||||
@ -88,6 +91,10 @@ export default function CanvasMenu(props) {
|
||||
setType('outline')
|
||||
break
|
||||
case 3:
|
||||
if (type === 'module') {
|
||||
restoreModuleInstArea()
|
||||
}
|
||||
|
||||
setType('surface')
|
||||
break
|
||||
case 4:
|
||||
@ -111,13 +118,7 @@ export default function CanvasMenu(props) {
|
||||
|
||||
// 저장버튼(btn08) 클릭 시 호출되는 함수
|
||||
const handleSaveCanvas = async () => {
|
||||
// swalFire({
|
||||
// text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
|
||||
// type: 'confirm',
|
||||
// confirmFn: async () => {
|
||||
await saveCanvas(sessionState.userId)
|
||||
// },
|
||||
// })
|
||||
await saveCanvas()
|
||||
}
|
||||
|
||||
const [placementInitialId, setPlacementInitialId] = useState(uuidv4())
|
||||
@ -317,11 +318,11 @@ export default function CanvasMenu(props) {
|
||||
<div className="ico-btn-from">
|
||||
<button className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}>
|
||||
<span className="ico ico01"></span>
|
||||
<span>{getMessage('plan.menu.estimate.docDown')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
|
||||
</button>
|
||||
<button className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
|
||||
<span className="ico ico02"></span>
|
||||
<span>{getMessage('plan.menu.estimate.save')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.save')}</span>
|
||||
</button>
|
||||
<button
|
||||
className="btn-frame gray ico-flx"
|
||||
@ -330,7 +331,7 @@ export default function CanvasMenu(props) {
|
||||
}}
|
||||
>
|
||||
<span className="ico ico03"></span>
|
||||
<span>{getMessage('plan.menu.estimate.reset')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.reset')}</span>
|
||||
</button>
|
||||
|
||||
{estimateRecoilState?.docNo !== null && (sessionState.storeId === 'T01' || sessionState.storeLvl === '1') && (
|
||||
@ -341,9 +342,13 @@ export default function CanvasMenu(props) {
|
||||
}}
|
||||
>
|
||||
<span className="ico ico04"></span>
|
||||
<span>{getMessage('plan.menu.estimate.copy')}</span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.copy')}</span>
|
||||
</button>
|
||||
)}
|
||||
<button className="btn-frame gray ico-flx">
|
||||
<span className="ico ico05"></span>
|
||||
<span className="name">{getMessage('plan.menu.estimate.unLock')}</span>
|
||||
</button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
@ -8,6 +8,9 @@ import { useRefFiles } from '@/hooks/common/useRefFiles'
|
||||
import { usePlan } from '@/hooks/usePlan'
|
||||
|
||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
import { useCanvas } from '@/hooks/useCanvas'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
|
||||
export default function ImgLoad() {
|
||||
const {
|
||||
@ -22,13 +25,20 @@ export default function ImgLoad() {
|
||||
setMapPositionAddress,
|
||||
handleFileDelete,
|
||||
handleMapImageDown,
|
||||
handleAddressDelete,
|
||||
} = useRefFiles()
|
||||
const { currentCanvasPlan } = usePlan()
|
||||
const { currentCanvasPlan, setCurrentCanvasPlan } = usePlan()
|
||||
const { getMessage } = useMessage()
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { floorPlanState, setFloorPlanState } = useContext(FloorPlanContext)
|
||||
|
||||
const handleModal = () => {
|
||||
setFloorPlanState({ ...floorPlanState, refFileModalOpen: false })
|
||||
setFloorPlanState({ ...floorPlanState, refFileModalOpen: false, toggleRotate: false })
|
||||
setCurrentCanvasPlan({
|
||||
...currentCanvasPlan,
|
||||
bgImageName: refImage?.name ?? null,
|
||||
mapPositionAddress,
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -37,8 +47,24 @@ export default function ImgLoad() {
|
||||
}, [floorPlanState.refFileModalOpen])
|
||||
|
||||
useEffect(() => {
|
||||
const refFileMethod = currentCanvasPlan?.mapPositionAddress === null ? '1' : '2'
|
||||
const backGroundImage = canvas?.getObjects().filter((obj) => obj.name === 'backGroundImage')
|
||||
if (backGroundImage && backGroundImage.length === 1) {
|
||||
backGroundImage[0].set({
|
||||
lockMovementX: !floorPlanState.toggleRotate,
|
||||
lockMovementY: !floorPlanState.toggleRotate,
|
||||
lockRotation: !floorPlanState.toggleRotate,
|
||||
lockScalingX: !floorPlanState.toggleRotate,
|
||||
lockScalingY: !floorPlanState.toggleRotate,
|
||||
selectable: floorPlanState.toggleRotate,
|
||||
})
|
||||
}
|
||||
}, [floorPlanState.toggleRotate])
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentCanvasPlan) return
|
||||
const refFileMethod = currentCanvasPlan?.mapPositionAddress === null || currentCanvasPlan?.mapPositionAddress?.trim() === '' ? '1' : '2'
|
||||
setRefFileMethod(refFileMethod)
|
||||
setMapPositionAddress(currentCanvasPlan?.mapPositionAddress ?? '')
|
||||
}, [currentCanvasPlan])
|
||||
|
||||
return (
|
||||
@ -50,7 +76,7 @@ export default function ImgLoad() {
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className="img-flex-box">
|
||||
<span className="normal-font mr10">サイズ調整と回転</span>
|
||||
<span className="normal-font mr10">{getMessage('modal.image.load.size.rotate')}</span>
|
||||
<label className="toggle-btn">
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -64,13 +90,13 @@ export default function ImgLoad() {
|
||||
<div className="img-load-item">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio03" id="ra06" value={'1'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '1'} />
|
||||
<label htmlFor="ra06">ファイルを読み込む</label>
|
||||
<label htmlFor="ra06">{getMessage('common.input.file')}</label>
|
||||
</div>
|
||||
<div className="img-flex-box">
|
||||
<div className="img-edit-wrap">
|
||||
<label className="img-edit-btn" htmlFor="img_file">
|
||||
<span className="img-edit"></span>
|
||||
ファイルの追加
|
||||
{getMessage('common.load')}
|
||||
</label>
|
||||
<input
|
||||
type="file"
|
||||
@ -80,21 +106,20 @@ export default function ImgLoad() {
|
||||
/>
|
||||
</div>
|
||||
<div className="img-name-wrap">
|
||||
{/* <input type="text" className="input-origin al-l" defaultValue={'IMG_Name.PNG'} readOnly />
|
||||
<button className="img-check"></button> */}
|
||||
{currentCanvasPlan?.bgImageName === null ? (
|
||||
<input type="text" className="input-origin al-l" value={refImage ? refImage.name : ''} readOnly />
|
||||
) : (
|
||||
<input type="text" className="input-origin al-l" value={currentCanvasPlan?.bgImageName} readOnly />
|
||||
)}
|
||||
{(refImage || currentCanvasPlan?.bgImageName) && <button className="img-check" onClick={handleFileDelete}></button>}
|
||||
<input
|
||||
type="text"
|
||||
className="input-origin al-l"
|
||||
value={refImage ? (refImage?.name ?? '') : (currentCanvasPlan?.bgImageName ?? '')}
|
||||
readOnly
|
||||
/>
|
||||
{refImage && <button className="img-check" onClick={handleFileDelete}></button>}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="img-load-item">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio03" id="ra07" value={'2'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '2'} />
|
||||
<label htmlFor="ra07">アドレスを読み込む</label>
|
||||
<label htmlFor="ra07">{getMessage('common.input.address.load')}</label>
|
||||
</div>
|
||||
<div className="img-flex-box for-address">
|
||||
<input
|
||||
@ -106,18 +131,21 @@ export default function ImgLoad() {
|
||||
onChange={(e) => setMapPositionAddress(e.target.value)}
|
||||
/>
|
||||
<div className="img-edit-wrap">
|
||||
<button className="img-edit-btn" onClick={refFileMethod === '2' ? handleMapImageDown : () => {}}>
|
||||
完了
|
||||
<button
|
||||
className={`img-edit-btn ${mapPositionAddress.trim().length === 0 ? 'no-click' : ''}`}
|
||||
onClick={refFileMethod === '2' ? handleMapImageDown : () => {}}
|
||||
>
|
||||
{getMessage('common.finish')}
|
||||
</button>
|
||||
</div>
|
||||
{mapPositionAddress && <span className="check-address fail"></span>}
|
||||
{mapPositionAddress && <button className="check-address fail" onClick={handleAddressDelete}></button>}
|
||||
{/* <span className="check-address success"></span> */}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act" onClick={handleModal}>
|
||||
完了
|
||||
{getMessage('common.finish')}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -20,7 +20,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
const orientationRef = useRef(null)
|
||||
const { initEvent } = useEvent()
|
||||
// const { initEvent } = useContext(EventContext)
|
||||
const { makeModuleInstArea, manualModuleSetup, autoModuleSetup } = useModuleBasicSetting()
|
||||
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting()
|
||||
const handleBtnNextStep = () => {
|
||||
if (tabNum === 1) {
|
||||
orientationRef.current.handleNextStep()
|
||||
@ -28,20 +28,16 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
setTabNum(tabNum + 1)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea() //기붕 모듈설치면 생성
|
||||
|
||||
return () => {
|
||||
initEvent() //모듈설치면 선택 이벤트 삭제
|
||||
}
|
||||
}, [])
|
||||
|
||||
const placementRef = {
|
||||
isChidori: useRef('false'),
|
||||
setupLocation: useRef('center'),
|
||||
isMaxSetup: useRef('false'),
|
||||
}
|
||||
|
||||
const placementFlatRef = {
|
||||
setupLocation: useRef('south'),
|
||||
}
|
||||
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={pos}>
|
||||
<div className={`modal-pop-wrap lx-2`}>
|
||||
@ -66,7 +62,9 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
|
||||
{/*배치면 초기설정 - 입력방법: 육지붕*/}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 3 && <PitchPlacement setTabNum={setTabNum} />}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet == 3 && tabNum === 3 && (
|
||||
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
|
||||
)}
|
||||
|
||||
<div className="grid-btn-wrap">
|
||||
{tabNum !== 1 && (
|
||||
@ -80,14 +78,29 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
|
||||
Next
|
||||
</button>
|
||||
)}
|
||||
|
||||
{tabNum === 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={manualModuleSetup}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet != 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={manualModuleSetup}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{canvasSetting.roofSizeSet && canvasSetting.roofSizeSet === 3 && (
|
||||
<>
|
||||
<button className="btn-frame modal mr5" onClick={() => manualFlatroofModuleSetup(placementFlatRef)}>
|
||||
{getMessage('modal.module.basic.setting.passivity.placement')}
|
||||
</button>
|
||||
<button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}>
|
||||
{getMessage('modal.module.basic.setting.auto.placement')}
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -34,7 +34,7 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
|
||||
onClick={() => setCompasDeg(15 * (12 + index))}
|
||||
>
|
||||
{index === 0 && <i>180°</i>}
|
||||
{index === 6 && <i>270°</i>}
|
||||
{index === 6 && <i>-90°</i>}
|
||||
</div>
|
||||
))}
|
||||
{Array.from({ length: 180 / 15 }).map((dot, index) => (
|
||||
@ -56,7 +56,7 @@ export const Orientation = forwardRef(({ tabNum }, ref) => {
|
||||
<div className="center-wrap">
|
||||
<div className="d-check-box pop">
|
||||
<input type="checkbox" id="ch99" checked={!hasAnglePassivity} onChange={() => setHasAnglePassivity(!hasAnglePassivity)} />
|
||||
<label htmlFor="ch99">{getMessage('modal.module.basic.setting.orientation.setting.angle.passivity')}(0〜360)</label>
|
||||
<label htmlFor="ch99">{getMessage('modal.module.basic.setting.orientation.setting.angle.passivity')}(-180 〜 180)</label>
|
||||
</div>
|
||||
<div className="outline-form">
|
||||
<div className="input-grid mr10" style={{ width: '160px' }}>
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import { forwardRef, useEffect, useState } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { forwardRef, useState } from 'react'
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
|
||||
const Placement = forwardRef((props, refs) => {
|
||||
const { getMessage } = useMessage()
|
||||
@ -7,6 +8,12 @@ const Placement = forwardRef((props, refs) => {
|
||||
const [setupLocation, setSetupLocation] = useState('center')
|
||||
const [isMaxSetup, setIsMaxSetup] = useState('false')
|
||||
|
||||
const { makeModuleInstArea } = useModuleBasicSetting()
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea()
|
||||
}, [])
|
||||
|
||||
const moduleData = {
|
||||
header: [
|
||||
{ type: 'check', name: '', prop: 'check', width: 70 },
|
||||
|
||||
@ -1,7 +1,26 @@
|
||||
import { forwardRef, useState, useEffect } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
|
||||
import { compasDegAtom } from '@/store/orientationAtom'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
|
||||
export default function PitchPlacement() {
|
||||
const PitchPlacement = forwardRef((props, refs) => {
|
||||
const { getMessage } = useMessage()
|
||||
const [setupLocation, setSetupLocation] = useState('south')
|
||||
const { makeModuleInstArea } = useModuleBasicSetting()
|
||||
const compasDeg = useRecoilValue(compasDegAtom)
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
useEffect(() => {
|
||||
makeModuleInstArea()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
handleChangeSetupLocation()
|
||||
}, [setupLocation])
|
||||
|
||||
const moduleData = {
|
||||
header: [
|
||||
{ type: 'check', name: '', prop: 'check', width: 70 },
|
||||
@ -24,6 +43,45 @@ export default function PitchPlacement() {
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const handleSetupLocation = (e) => {
|
||||
refs.setupLocation.current = e.target
|
||||
setSetupLocation(e.target.value)
|
||||
}
|
||||
|
||||
const handleChangeSetupLocation = () => {
|
||||
if (setupLocation === 'south') {
|
||||
canvas.getObjects().forEach((obj) => obj.name === 'flatExcretaLine' && canvas.remove(obj))
|
||||
return null
|
||||
} else {
|
||||
const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴
|
||||
moduleSetupSurfaces.forEach((surface, index) => {
|
||||
console.log(`surface ${index} : `, surface)
|
||||
|
||||
const excretaLine = surface.lines
|
||||
|
||||
excretaLine.forEach((line) => {
|
||||
line.set({
|
||||
stroke: '#642EFB',
|
||||
strokeWidth: 5,
|
||||
surfaceId: surface.surfaceId,
|
||||
name: 'flatExcretaLine',
|
||||
})
|
||||
canvas.add(line)
|
||||
|
||||
line.on('selected', () => {
|
||||
excretaLine.forEach((obj) => obj.set({ stroke: '#642EFB', isSelected: false }))
|
||||
if (!line.isSelected) {
|
||||
line.set({ stroke: 'red', isSelected: true })
|
||||
} else {
|
||||
line.set({ stroke: '#642EFB', isSelected: false })
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="module-table-box mb10">
|
||||
@ -88,11 +146,26 @@ export default function PitchPlacement() {
|
||||
<div className="hexagonal-item">
|
||||
<div className="pop-form-radio">
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra01" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra01"
|
||||
value={'south'}
|
||||
checked={setupLocation === 'south'}
|
||||
defaultChecked
|
||||
onChange={handleSetupLocation}
|
||||
/>
|
||||
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label>
|
||||
</div>
|
||||
<div className="d-check-radio pop">
|
||||
<input type="radio" name="radio01" id="ra02" />
|
||||
<input
|
||||
type="radio"
|
||||
name="radio01"
|
||||
id="ra02"
|
||||
value={'excreta'}
|
||||
checked={setupLocation === 'excreta'}
|
||||
onChange={handleSetupLocation}
|
||||
/>
|
||||
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label>
|
||||
</div>
|
||||
</div>
|
||||
@ -102,4 +175,6 @@ export default function PitchPlacement() {
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
export default PitchPlacement
|
||||
|
||||
@ -1,54 +1,44 @@
|
||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
import QSelectBox from '@/components/common/select/QSelectBox'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { canvasState, dotLineGridSettingState, dotLineIntervalSelector } from '@/store/canvasAtom'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
||||
import { canvasState } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { onlyNumberInputChange } from '@/util/input-utils'
|
||||
import { settingModalGridOptionsState } from '@/store/settingAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
|
||||
const TYPE = {
|
||||
DOT: 'DOT',
|
||||
LINE: 'LINE',
|
||||
}
|
||||
|
||||
const defaultDotLineGridSetting = {
|
||||
INTERVAL: {
|
||||
type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격
|
||||
ratioInterval: 910,
|
||||
verticalInterval: 910,
|
||||
horizontalInterval: 910,
|
||||
dimension: 1, // 치수
|
||||
},
|
||||
DOT: false,
|
||||
LINE: false,
|
||||
}
|
||||
|
||||
export default function DotLineGrid(props) {
|
||||
// const [modalOption, setModalOption] = useRecoilState(modalState); //modal 열림닫힘 state
|
||||
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
||||
const [close, setClose] = useState(false)
|
||||
//const interval = useRecoilValue(dotLineIntervalSelector)
|
||||
const { id, setIsShow, pos = { x: 840, y: -815 }, isConfig = false } = props
|
||||
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
|
||||
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
|
||||
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
|
||||
const [currentSetting, setCurrentSetting] = useState(
|
||||
JSON.stringify(dotLineGridSetting) === JSON.stringify(defaultDotLineGridSetting) ? { ...defaultDotLineGridSetting } : { ...dotLineGridSetting },
|
||||
)
|
||||
const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState)
|
||||
const interval = useRecoilValue(dotLineIntervalSelector)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { get, post } = useAxios()
|
||||
const { swalFire } = useSwal()
|
||||
const { closePopup } = usePopup()
|
||||
const { swalFire } = useSwal()
|
||||
|
||||
const {
|
||||
selectOption,
|
||||
setSelectOption,
|
||||
SelectOptions,
|
||||
currentSetting,
|
||||
setCurrentSetting,
|
||||
dotLineGridSettingState,
|
||||
setSettingModalGridOptions,
|
||||
setDotLineGridSettingState,
|
||||
} = useCanvasSetting()
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
useEffect(() => {
|
||||
console.log('DotLineGrid useEffect 실행')
|
||||
|
||||
return () => {
|
||||
setSettingModalGridOptions((prev) => {
|
||||
const newSettingOptions = [...prev]
|
||||
@ -58,20 +48,6 @@ export default function DotLineGrid(props) {
|
||||
}
|
||||
}, [])
|
||||
|
||||
const SelectOption = [
|
||||
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
|
||||
{ id: 2, name: '1/2', value: 1 / 2 },
|
||||
{ id: 3, name: '1/4', value: 1 / 4 },
|
||||
{ id: 4, name: '1/10', value: 1 / 10 },
|
||||
]
|
||||
const [selectOption, setSelectOption] = useState(SelectOption[0])
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
useEffect(() => {
|
||||
console.log('DotLineGrid useEffect 실행')
|
||||
fetchGridSettings()
|
||||
}, [objectNo])
|
||||
|
||||
const HandleClickClose = () => {
|
||||
// setClose(true)
|
||||
// setTimeout(() => {
|
||||
@ -90,61 +66,31 @@ export default function DotLineGrid(props) {
|
||||
})
|
||||
}
|
||||
|
||||
// Canvas Grid Setting 조회 및 초기화
|
||||
const fetchGridSettings = async () => {
|
||||
try {
|
||||
const res = await get({ url: `/api/canvas-management/canvas-grid-settings/by-object/${objectNo}` })
|
||||
|
||||
const patternData = {
|
||||
INTERVAL: {
|
||||
type: res.gridType,
|
||||
horizontalInterval: res.gridHorizon * 10,
|
||||
verticalInterval: res.gridVertical * 10,
|
||||
ratioInterval: res.gridRatio * 10,
|
||||
},
|
||||
dimension: res.gridDimen,
|
||||
DOT: res.dotGridDisplay,
|
||||
LINE: res.lineGridDisplay,
|
||||
}
|
||||
|
||||
const matchedOption = SelectOption.find((option) => option.value == res.gridDimen)
|
||||
|
||||
// dimension 값에 맞는 옵션을 선택
|
||||
setSelectOption(matchedOption)
|
||||
|
||||
// 서버에서 받은 데이터로 상태 업데이트
|
||||
setCurrentSetting(patternData)
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
const handleSave = async () => {
|
||||
if (!currentSetting.DOT && !currentSetting.LINE) {
|
||||
swalFire({ text: '배치할 그리드를 설정해주세요.' })
|
||||
return
|
||||
}
|
||||
try {
|
||||
const patternData = {
|
||||
objectNo,
|
||||
dotGridDisplay: currentSetting.DOT,
|
||||
lineGridDisplay: currentSetting.LINE,
|
||||
gridType: currentSetting.INTERVAL.type,
|
||||
gridHorizon: currentSetting.INTERVAL.horizontalInterval / 10,
|
||||
gridVertical: currentSetting.INTERVAL.verticalInterval / 10,
|
||||
gridRatio: currentSetting.INTERVAL.ratioInterval / 10,
|
||||
gridDimen: currentSetting.INTERVAL.dimension,
|
||||
}
|
||||
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-grid-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
setDotLineGridSettingState({ ...currentSetting })
|
||||
closePopup(id, isConfig)
|
||||
})
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
setDotLineGridSettingState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
INTERVAL: {
|
||||
type: currentSetting.INTERVAL.type,
|
||||
horizontalInterval: currentSetting.INTERVAL.horizontalInterval,
|
||||
verticalInterval: currentSetting.INTERVAL.verticalInterval,
|
||||
ratioInterval: currentSetting.INTERVAL.ratioInterval,
|
||||
dimension: currentSetting.INTERVAL.dimension,
|
||||
},
|
||||
DOT: currentSetting.DOT,
|
||||
LINE: currentSetting.LINE,
|
||||
flag: true,
|
||||
}
|
||||
//setDotLineGridSettingState({ ...currentSetting })
|
||||
})
|
||||
|
||||
setIsShow(false)
|
||||
closePopup(id, isConfig)
|
||||
}
|
||||
|
||||
const handleRadioChange = (e) => {
|
||||
@ -198,8 +144,19 @@ export default function DotLineGrid(props) {
|
||||
.filter((obj) => obj.name === 'dotGrid')
|
||||
.forEach((obj) => canvas?.remove(obj))
|
||||
|
||||
resetDotLineGridSetting()
|
||||
setSelectOption(SelectOption[0])
|
||||
// resetDotLineGridSetting()
|
||||
setCurrentSetting({
|
||||
INTERVAL: {
|
||||
type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격
|
||||
ratioInterval: 910,
|
||||
verticalInterval: 910,
|
||||
horizontalInterval: 910,
|
||||
dimension: 1, // 치수
|
||||
},
|
||||
DOT: false,
|
||||
LINE: false,
|
||||
})
|
||||
setSelectOption(SelectOptions[0])
|
||||
}
|
||||
|
||||
return (
|
||||
@ -296,7 +253,7 @@ export default function DotLineGrid(props) {
|
||||
<span>mm</span>
|
||||
</div>
|
||||
<div className="grid-select">
|
||||
<QSelectBox options={SelectOption} onChange={changeDimension} value={selectOption} />
|
||||
<QSelectBox options={SelectOptions} onChange={changeDimension} value={selectOption} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -17,8 +17,7 @@ export default function GridCopy(props) {
|
||||
const currentObject = useRecoilValue(currentObjectState)
|
||||
const { copy } = useGrid()
|
||||
const handleApply = () => {
|
||||
// copy(currentObject, )
|
||||
copy(currentObject, ['↑', '←'].includes(arrow) ? Number(length) * -1 : Number(length))
|
||||
copy(currentObject, ['↑', '←'].includes(arrow) ? +length * -1 : +length)
|
||||
}
|
||||
return (
|
||||
<WithDraggable isShow={true} pos={pos}>
|
||||
|
||||
@ -5,12 +5,10 @@ import { useMessage } from '@/hooks/useMessage'
|
||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { contextPopupPositionState } from '@/store/popupAtom'
|
||||
import { useRef, useState, useEffect, useContext } from 'react'
|
||||
import { useRef, useState } from 'react'
|
||||
import { useObjectBatch } from '@/hooks/object/useObjectBatch'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
|
||||
import { EventContext } from '@/app/floor-plan/EventProvider'
|
||||
|
||||
export default function SizeSetting(props) {
|
||||
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
|
||||
|
||||
@ -1,113 +1,26 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
|
||||
import { canvasSettingState } from '@/store/canvasAtom'
|
||||
import { basicSettingState } from '@/store/settingAtom'
|
||||
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
|
||||
import SizeGuide from '@/components/floor-plan/modal/placementShape/SizeGuide'
|
||||
import MaterialGuide from '@/components/floor-plan/modal/placementShape/MaterialGuide'
|
||||
import WithDraggable from '@/components/common/draggable/WithDraggable'
|
||||
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
|
||||
export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, setShowPlaceShapeModal }) {
|
||||
const [objectNo, setObjectNo] = useState('test123241008001') // 후에 삭제 필요
|
||||
const [showSizeGuideModal, setShowSizeGuidModal] = useState(false)
|
||||
const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false)
|
||||
const [selectedRoofMaterial, setSelectedRoofMaterial] = useState(1)
|
||||
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
||||
const { closePopup } = usePopup()
|
||||
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
|
||||
|
||||
const { getMessage } = useMessage()
|
||||
const { get, post } = useAxios()
|
||||
const { swalFire } = useSwal()
|
||||
|
||||
const { basicSetting, setBasicSettings, fetchBasicSettings, basicSettingSave } = useCanvasSetting()
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
useEffect(() => {
|
||||
console.log('PlacementShapeSetting useEffect 실행')
|
||||
|
||||
fetchSettings()
|
||||
}, [objectNo])
|
||||
|
||||
// PlacementShapeSetting 조회 및 초기화
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
|
||||
if (res.length == 0) return
|
||||
|
||||
// 'roofs' 배열을 생성하여 각 항목을 추가
|
||||
const roofsRow = res.map((item) => {
|
||||
return {
|
||||
roofSizeSet: item.roofSizeSet,
|
||||
roofAngleSet: item.roofAngleSet,
|
||||
}
|
||||
})
|
||||
|
||||
const roofsArray = res.some((item) => !item.roofSeq)
|
||||
? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정
|
||||
res.map(() => ({
|
||||
roofApply: true,
|
||||
roofSeq: 1,
|
||||
roofType: 1,
|
||||
roofWidth: 200,
|
||||
roofHeight: 200,
|
||||
roofHajebichi: 200,
|
||||
roofGap: 0,
|
||||
roofLayout: 'parallel',
|
||||
}))
|
||||
: res.map((item) => ({
|
||||
roofApply: item.roofApply === '' || item.roofApply === false ? false : true,
|
||||
roofSeq: item.roofSeq,
|
||||
roofType: item.roofType,
|
||||
roofWidth: item.roofWidth,
|
||||
roofHeight: item.roofHeight,
|
||||
roofHajebichi: item.roofHajebichi,
|
||||
roofGap: item.roofGap,
|
||||
roofLayout: item.roofLayout,
|
||||
}))
|
||||
console.log('roofsArray ', roofsArray)
|
||||
// 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음
|
||||
const patternData = {
|
||||
roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용
|
||||
roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용
|
||||
roofs: roofsArray, // 만들어진 roofs 배열
|
||||
}
|
||||
|
||||
// 데이터 설정
|
||||
setBasicSettings({ ...patternData })
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
|
||||
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
|
||||
setBasicSettings({ ...canvasSetting })
|
||||
}
|
||||
}
|
||||
|
||||
const submitCanvasConfig = async () => {
|
||||
try {
|
||||
const patternData = {
|
||||
objectNo,
|
||||
roofSizeSet: basicSetting.roofSizeSet,
|
||||
roofAngleSet: basicSetting.roofAngleSet,
|
||||
roofMaterialsAddList: basicSetting.roofs,
|
||||
}
|
||||
|
||||
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
})
|
||||
|
||||
//Recoil 설정
|
||||
setCanvasSetting({ ...basicSetting })
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
}
|
||||
fetchBasicSettings()
|
||||
}, [])
|
||||
|
||||
// Function to update the roofType and corresponding values
|
||||
const handleRoofTypeChange = (index, value) => {
|
||||
@ -122,7 +35,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
|
||||
roofWidth: 265,
|
||||
roofHeight: 235,
|
||||
roofGap: 455,
|
||||
hajebichi: 0,
|
||||
roofHajebichi: 0,
|
||||
}
|
||||
} else if (roofType === 2) {
|
||||
updatedRoofs[index] = {
|
||||
@ -490,7 +403,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, set
|
||||
</table>
|
||||
</div>
|
||||
<div className="grid-btn-wrap">
|
||||
<button className="btn-frame modal act" onClick={() => submitCanvasConfig()}>
|
||||
<button className="btn-frame modal act" onClick={() => basicSettingSave()}>
|
||||
{getMessage('modal.common.save')}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -14,7 +14,7 @@ export default function SizeGuide({ setShowSizeGuidModal }) {
|
||||
<div className="placement-table light">
|
||||
<table>
|
||||
<colgroup>
|
||||
<col style={{ width: '60px' }} />
|
||||
<col style={{ width: '65px' }} />
|
||||
<col />
|
||||
</colgroup>
|
||||
<tbody>
|
||||
|
||||
@ -3,11 +3,14 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
import { setSurfaceShapePattern } from '@/util/canvas-util'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
|
||||
export default function FirstOption() {
|
||||
export default function FirstOption(props) {
|
||||
const { getMessage } = useMessage()
|
||||
const { canvas, settingModalFirstOptions, setSettingModalFirstOptions } = useCanvasSetting()
|
||||
// const { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData } = useCanvasSetting()
|
||||
let { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData } = props
|
||||
const { option1, option2, dimensionDisplay } = settingModalFirstOptions
|
||||
const { initEvent } = useEvent()
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
useEffect(() => {
|
||||
@ -16,19 +19,27 @@ export default function FirstOption() {
|
||||
|
||||
const onClickOption = async (item) => {
|
||||
//치수 표시(단 건 선택)
|
||||
let dimensionDisplay = settingModalFirstOptions?.dimensionDisplay
|
||||
let option1 = settingModalFirstOptions?.option1
|
||||
let option2 = settingModalFirstOptions?.option2
|
||||
|
||||
if (item.column === 'corridorDimension' || item.column === 'realDimension' || item.column === 'noneDimension') {
|
||||
const options = settingModalFirstOptions?.dimensionDisplay.map((option) => {
|
||||
dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.map((option) => {
|
||||
option.selected = option.id === item.id
|
||||
return option
|
||||
})
|
||||
|
||||
// setSettingModalFirstOptions({ ...settingModalFirstOptions, dimensionDisplay: [...options] })
|
||||
|
||||
//화면 표시(단 건 선택)
|
||||
} else if (item.column === 'onlyBorder' || item.column === 'lineHatch' || item.column === 'allPainted') {
|
||||
const options2 = settingModalFirstOptions?.option2.map((option2) => {
|
||||
option2 = settingModalFirstOptions?.option2.map((option2) => {
|
||||
option2.selected = option2.id === item.id
|
||||
return option2
|
||||
})
|
||||
|
||||
// setSettingModalFirstOptions({ ...settingModalFirstOptions, option2: [...options] })
|
||||
|
||||
const polygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
|
||||
|
||||
polygons.forEach((polygon) => {
|
||||
@ -36,12 +47,24 @@ export default function FirstOption() {
|
||||
})
|
||||
//디스플레이 설정 표시(단 건 선택)
|
||||
} else {
|
||||
item.selected = !item.selected
|
||||
option1 = settingModalFirstOptions?.option1.map((opt) => {
|
||||
if (opt.id === item.id) {
|
||||
opt.selected = !opt.selected
|
||||
}
|
||||
return opt
|
||||
})
|
||||
|
||||
// setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: [...options] })
|
||||
}
|
||||
|
||||
setSettingModalFirstOptions({ ...settingModalFirstOptions, option1, option2, dimensionDisplay, fontFlag: true })
|
||||
setSettingsData({ ...settingsData, option1: [...option1], option2: [...option2], dimensionDisplay: [...dimensionDisplay] })
|
||||
}
|
||||
|
||||
// useEffect(() => {
|
||||
// console.log('🚀 ~ useEffect ~ initEvent:')
|
||||
// initEvent()
|
||||
// }, [onClickOption])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="modal-check-btn-wrap">
|
||||
|
||||
@ -4,28 +4,32 @@ import { settingModalGridOptionsState } from '@/store/settingAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { adsorptionPointAddModeState } from '@/store/canvasAtom'
|
||||
import { useTempGrid } from '@/hooks/useTempGrid'
|
||||
import { gridColorState } from '@/store/gridAtom'
|
||||
import { useColor } from 'react-color-palette'
|
||||
import ColorPickerModal from '@/components/common/color-picker/ColorPickerModal'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import DotLineGrid from '@/components/floor-plan/modal/grid/DotLineGrid'
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
|
||||
export default function GridOption() {
|
||||
export default function GridOption(props) {
|
||||
const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState)
|
||||
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
|
||||
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
|
||||
const { getMessage } = useMessage()
|
||||
const { tempGridMode, setTempGridMode } = useTempGrid()
|
||||
const [gridColor, setGridColor] = useRecoilState(gridColorState)
|
||||
const [color, setColor] = useColor(gridColor)
|
||||
const [showColorPickerModal, setShowColorPickerModal] = useState(false)
|
||||
const [showDotLineGridModal, setShowDotLineGridModal] = useState(false)
|
||||
const { addPopup, closePopup, closePopups } = usePopup()
|
||||
const [colorId, setColorId] = useState(uuidv4())
|
||||
const [dotLineId, setDotLineId] = useState(uuidv4())
|
||||
|
||||
// const { gridColor, setGridColor, color } = useCanvasSetting()
|
||||
const { gridColor, setGridColor, color } = props
|
||||
|
||||
const { initEvent } = useEvent()
|
||||
|
||||
useEffect(() => {
|
||||
console.log('GridOption useEffect 실행')
|
||||
setGridColor(color.hex)
|
||||
}, [color])
|
||||
|
||||
@ -91,6 +95,11 @@ export default function GridOption() {
|
||||
setGridOptions(newGridOptions)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log('🚀 ~ useEffect ~ initEvent:')
|
||||
initEvent()
|
||||
}, [gridOptions])
|
||||
|
||||
const dotLineGridProps = {
|
||||
id: dotLineId,
|
||||
setIsShow: setShowDotLineGridModal,
|
||||
|
||||
@ -8,8 +8,9 @@ import PlanSizeSetting from '@/components/floor-plan/modal/setting01/planSize/Pl
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { fontSelector, globalFontAtom } from '@/store/fontAtom'
|
||||
import { useEvent } from '@/hooks/useEvent'
|
||||
|
||||
export default function SecondOption() {
|
||||
export default function SecondOption(props) {
|
||||
const { getMessage } = useMessage()
|
||||
const { addPopup, closePopup } = usePopup()
|
||||
const [showFontSettingModal, setShowFontSettingModal] = useState(false)
|
||||
@ -24,6 +25,18 @@ export default function SecondOption() {
|
||||
const [fontId, setFontId] = useState(uuidv4())
|
||||
const [planSizeId, setPlanSizeId] = useState(uuidv4())
|
||||
|
||||
const { initEvent } = useEvent()
|
||||
|
||||
// const {
|
||||
// fetchSettings,
|
||||
// planSizeSettingMode,
|
||||
// setPlanSizeSettingMode,
|
||||
// settingModalSecondOptions,
|
||||
// setSettingModalSecondOptions,
|
||||
// adsorptionPointMode,
|
||||
// setAdsorptionPointMode,
|
||||
// setAdsorptionRange,
|
||||
// } = useCanvasSetting()
|
||||
const {
|
||||
fetchSettings,
|
||||
planSizeSettingMode,
|
||||
@ -33,7 +46,7 @@ export default function SecondOption() {
|
||||
adsorptionPointMode,
|
||||
setAdsorptionPointMode,
|
||||
setAdsorptionRange,
|
||||
} = useCanvasSetting()
|
||||
} = props
|
||||
const { option3, option4 } = settingModalSecondOptions
|
||||
|
||||
// 데이터를 최초 한 번만 조회
|
||||
@ -189,6 +202,11 @@ export default function SecondOption() {
|
||||
setAdsorptionRange(50)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log('🚀 ~ useEffect ~ initEvent:')
|
||||
initEvent()
|
||||
}, [adsorptionPointMode])
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="modal-check-btn-wrap">
|
||||
|
||||
@ -9,6 +9,7 @@ import GridOption from '@/components/floor-plan/modal/setting01/GridOption'
|
||||
import { canGridOptionSeletor } from '@/store/canvasAtom'
|
||||
import { useRecoilValue } from 'recoil'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
|
||||
|
||||
export default function SettingModal01(props) {
|
||||
const { id } = props
|
||||
@ -17,6 +18,37 @@ export default function SettingModal01(props) {
|
||||
const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor)
|
||||
const { closePopup } = usePopup()
|
||||
|
||||
const {
|
||||
canvas,
|
||||
settingModalFirstOptions,
|
||||
setSettingModalFirstOptions,
|
||||
settingsData,
|
||||
setSettingsData,
|
||||
fetchSettings,
|
||||
planSizeSettingMode,
|
||||
setPlanSizeSettingMode,
|
||||
settingModalSecondOptions,
|
||||
setSettingModalSecondOptions,
|
||||
adsorptionPointMode,
|
||||
setAdsorptionPointMode,
|
||||
setAdsorptionRange,
|
||||
gridColor,
|
||||
setGridColor,
|
||||
color,
|
||||
} = useCanvasSetting()
|
||||
const firstProps = { canvas, settingModalFirstOptions, setSettingModalFirstOptions, settingsData, setSettingsData }
|
||||
const secondProps = {
|
||||
fetchSettings,
|
||||
planSizeSettingMode,
|
||||
setPlanSizeSettingMode,
|
||||
settingModalSecondOptions,
|
||||
setSettingModalSecondOptions,
|
||||
adsorptionPointMode,
|
||||
setAdsorptionPointMode,
|
||||
setAdsorptionRange,
|
||||
}
|
||||
const gridProps = { gridColor, setGridColor, color }
|
||||
|
||||
const handleBtnClick = (num) => {
|
||||
setButtonAct(num)
|
||||
}
|
||||
@ -46,9 +78,9 @@ export default function SettingModal01(props) {
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{buttonAct === 1 && <FirstOption />}
|
||||
{buttonAct === 2 && <SecondOption />}
|
||||
{buttonAct === 3 && <GridOption />}
|
||||
{buttonAct === 1 && <FirstOption {...firstProps} />}
|
||||
{buttonAct === 2 && <SecondOption {...secondProps} />}
|
||||
{buttonAct === 3 && <GridOption {...gridProps} />}
|
||||
</div>
|
||||
</div>
|
||||
</WithDraggable>
|
||||
|
||||
@ -75,8 +75,6 @@ export default function PlanSizeSetting(props) {
|
||||
className="input-origin block"
|
||||
name={`originHorizon`}
|
||||
value={planSizeSettingMode.originHorizon}
|
||||
//onChange={(e) => setPlanSizeSettingMode({ ...planSizeSettingMode, originHorizon: Number(e.target.value), flag: false })}
|
||||
//onFocus={(e) => (originHorizon.current.value = '')}
|
||||
onChange={(e) => onlyNumberInputChange(e, changeInput)}
|
||||
/>
|
||||
</div>
|
||||
@ -90,8 +88,6 @@ export default function PlanSizeSetting(props) {
|
||||
className="input-origin block"
|
||||
name={`originVertical`}
|
||||
value={planSizeSettingMode.originVertical}
|
||||
//onChange={(e) => setPlanSizeSettingMode({ ...planSizeSettingMode, originVertical: Number(e.target.value), flag: false })}
|
||||
//onFocus={(e) => (originVertical.current.value = '')}
|
||||
onChange={(e) => onlyNumberInputChange(e, changeInput)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -96,7 +96,8 @@ export default function Header(props) {
|
||||
name: 'header.menus.management',
|
||||
url: '',
|
||||
children: [
|
||||
{ id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempdetail', children: [] },
|
||||
// { id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempdetail', children: [] },
|
||||
{ id: 3, name: 'header.menus.management.newStuff', url: '/management/stuff/tempReg', children: [] },
|
||||
{ id: 4, name: 'header.menus.management.stuffList', url: '/management/stuff', children: [] },
|
||||
],
|
||||
},
|
||||
@ -129,6 +130,14 @@ export default function Header(props) {
|
||||
}
|
||||
}
|
||||
|
||||
// Home 클릭시 물건 리코일 비우기
|
||||
const moveHome = () => {
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'DELETE',
|
||||
})
|
||||
}
|
||||
|
||||
const getMenuTemplate = (menus) => {
|
||||
return menus.map((menu) => {
|
||||
return (
|
||||
@ -139,7 +148,13 @@ export default function Header(props) {
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||
>
|
||||
{menu.children.length === 0 ? (
|
||||
<Link key={`${menu.id}`} href={menu.url}>
|
||||
<Link
|
||||
key={`${menu.id}`}
|
||||
href={menu.url}
|
||||
onClick={() => {
|
||||
moveHome()
|
||||
}}
|
||||
>
|
||||
{getMessage(menu.name)}
|
||||
</Link>
|
||||
) : (
|
||||
@ -154,7 +169,9 @@ export default function Header(props) {
|
||||
onMouseEnter={(e) => ToggleonMouse(e, 'add', 'li > ul')}
|
||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'li > ul')}
|
||||
>
|
||||
<Link href={m.url}>{getMessage(m.name)}</Link>
|
||||
<Link scroll={false} href={m.url}>
|
||||
{getMessage(m.name)}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
})}
|
||||
|
||||
@ -6,8 +6,9 @@ import { useRecoilValue, useRecoilState } from 'recoil'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { setSession } from '@/lib/authActions'
|
||||
|
||||
export default function ChangePasswordPop() {
|
||||
export default function ChangePasswordPop(props) {
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
|
||||
const { patch } = useAxios(globalLocaleState)
|
||||
@ -77,6 +78,7 @@ export default function ChangePasswordPop() {
|
||||
alert(getMessage('main.popup.login.success'))
|
||||
setSessionState({ ...sessionState, pwdInitYn: 'Y' })
|
||||
//메인으로 이동
|
||||
props.setChagePasswordPopOpen(false)
|
||||
router.push('/')
|
||||
} else {
|
||||
alert(res.result.resultMsg)
|
||||
|
||||
@ -22,19 +22,12 @@ export default function MainContents() {
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
const { promiseGet } = useAxios(globalLocaleState)
|
||||
|
||||
//최근 물건
|
||||
// const [objectList, setObjectList] = useState([])
|
||||
|
||||
//공지사항
|
||||
const [recentNoticeList, setRecentNoticeList] = useState([])
|
||||
|
||||
//FAQ
|
||||
const [recentFaqList, setRecentFaqList] = useState([])
|
||||
|
||||
//Sales Contact info
|
||||
// const [businessCharger, setBusinessCharger] = useState(null)
|
||||
// const [businessChargerMail, setBusinessChargerMail] = useState(null)
|
||||
|
||||
const { qcastState } = useContext(QcastContext)
|
||||
const { fetchObjectList, initObjectList } = useMainContentsController()
|
||||
|
||||
@ -47,28 +40,6 @@ export default function MainContents() {
|
||||
}
|
||||
}, [])
|
||||
|
||||
//최근 갱신 물건목록 / Sales Contact info 정보
|
||||
// const fetchObjectList = async () => {
|
||||
// try {
|
||||
// const apiUrl = `/api/main-page/object/${session?.storeId}/list`
|
||||
// await promiseGet({
|
||||
// url: apiUrl,
|
||||
// }).then((res) => {
|
||||
// if (res.status === 200) {
|
||||
// setObjectList(res.data.objectList)
|
||||
// setBusinessCharger(res.data.businessCharger)
|
||||
// setBusinessChargerMail(res.data.businessChargerMail)
|
||||
// } else {
|
||||
// setObjectList([])
|
||||
// setBusinessCharger(null)
|
||||
// setBusinessChargerMail(null)
|
||||
// }
|
||||
// })
|
||||
// } catch (error) {
|
||||
// console.error('MAIN API fetching error:', error)
|
||||
// }
|
||||
// }
|
||||
|
||||
//공지사항 호출
|
||||
const fetchNoticeList = async () => {
|
||||
try {
|
||||
@ -128,9 +99,9 @@ export default function MainContents() {
|
||||
className="recently-item"
|
||||
onClick={() => {
|
||||
if (row.tempFlg === '0') {
|
||||
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`)
|
||||
router.push(`/management/stuff/detail?objectNo=${row.objectNo.toString()}`, { scroll: false })
|
||||
} else {
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`)
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${row.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@ -6,7 +6,7 @@ export default function ProductItem({ num, name, children }) {
|
||||
// 더보기 페이지 이동
|
||||
const pageMove = (num) => {
|
||||
if (num === 1) {
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
} else if (num === 2) {
|
||||
router.push('/community/notice')
|
||||
} else {
|
||||
|
||||
@ -211,7 +211,6 @@ export default function Stuff() {
|
||||
fetchData()
|
||||
} else if (stuffSearchParams?.code === 'M') {
|
||||
const params = {
|
||||
saleStoreId: session?.storeId,
|
||||
schObjectNo: stuffSearchParams.schObjectNo,
|
||||
schAddress: '',
|
||||
schObjectName: '',
|
||||
@ -225,7 +224,7 @@ export default function Stuff() {
|
||||
endRow: pageNo * pageSize,
|
||||
schSelSaleStoreId: stuffSearchParams?.schOtherSelSaleStoreId ? stuffSearchParams.schOtherSelSaleStoreId : stuffSearchParams.schSelSaleStoreId,
|
||||
schSortType: 'R',
|
||||
code: 'S',
|
||||
code: 'E',
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
}
|
||||
@ -261,6 +260,7 @@ export default function Stuff() {
|
||||
fetchData()
|
||||
} else if (stuffSearchParams?.code === 'C') {
|
||||
resetStuffRecoil()
|
||||
setIsGlobalLoading(false)
|
||||
} else if (stuffSearchParams?.code === 'FINISH') {
|
||||
stuffSearchParams.startRow = 1
|
||||
stuffSearchParams.endRow = 1 * pageSize
|
||||
@ -278,6 +278,7 @@ export default function Stuff() {
|
||||
setTotalCount(0)
|
||||
}
|
||||
})
|
||||
setIsGlobalLoading(false)
|
||||
}
|
||||
fetchData()
|
||||
} else if (stuffSearchParams?.code === 'DELETE') {
|
||||
@ -305,6 +306,11 @@ export default function Stuff() {
|
||||
setStuffSearch({
|
||||
...newParams,
|
||||
})
|
||||
|
||||
setIsGlobalLoading(false)
|
||||
} else {
|
||||
stuffSearchParams.code = 'DELETE'
|
||||
setIsGlobalLoading(false)
|
||||
}
|
||||
}, [stuffSearchParams])
|
||||
|
||||
@ -320,7 +326,7 @@ export default function Stuff() {
|
||||
setPageSize(e.target.value)
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'S',
|
||||
code: 'E',
|
||||
startRow: startRow,
|
||||
endRow: 1 * e.target.value,
|
||||
pageSize: e.target.value,
|
||||
@ -331,7 +337,6 @@ export default function Stuff() {
|
||||
|
||||
//최근 등록일 수정일 정렬 이벤트
|
||||
const onChangeSortType = (e) => {
|
||||
// let startRow = (stuffSearchParams.pageNo - 1) * pageSize + 1
|
||||
let startRow = (1 - 1) * stuffSearchParams.pageSize + 1
|
||||
stuffSearchParams.startRow = startRow
|
||||
stuffSearchParams.endRow = startRow * stuffSearchParams.pageSize
|
||||
@ -345,7 +350,7 @@ export default function Stuff() {
|
||||
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'S',
|
||||
code: 'E',
|
||||
startRow: startRow,
|
||||
endRow: startRow * stuffSearchParams.pageSize,
|
||||
pageSize: stuffSearchParams.pageSize,
|
||||
@ -371,7 +376,7 @@ export default function Stuff() {
|
||||
|
||||
setStuffSearch({
|
||||
...stuffSearch,
|
||||
code: 'S',
|
||||
code: 'E',
|
||||
startRow: (page - 1) * pageSize + 1,
|
||||
endRow: page * stuffSearchParams?.pageSize,
|
||||
pageNo: page,
|
||||
|
||||
@ -7,7 +7,7 @@ import Select, { components } from 'react-select'
|
||||
import Link from 'next/link'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty } from '@/util/common-utils'
|
||||
import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { useRecoilValue, useSetRecoilState, useResetRecoilState, useRecoilState } from 'recoil'
|
||||
@ -75,7 +75,7 @@ export default function StuffDetail() {
|
||||
installHeight: '', //설치높이
|
||||
conType: '0', //계약조건(잉여 / 전량)
|
||||
remarks: '', //메모
|
||||
tempFlag: 'T', //임시저장(1) 저장(0)
|
||||
tempFlg: 'T', //임시저장(1) 저장(0)
|
||||
}
|
||||
const { register, setValue, getValues, handleSubmit, resetField, control, watch } = useForm({
|
||||
defaultValues: formInitValue,
|
||||
@ -108,7 +108,6 @@ export default function StuffDetail() {
|
||||
|
||||
const [editMode, setEditMode] = useState('NEW')
|
||||
const { managementState, setManagementState } = useContext(ManagementContext)
|
||||
|
||||
const [planGridProps, setPlanGridProps] = useState({
|
||||
planGridData: [],
|
||||
isPageable: false,
|
||||
@ -135,6 +134,7 @@ export default function StuffDetail() {
|
||||
field: 'moduleModel',
|
||||
headerName: getMessage('stuff.detail.planGridHeader.moduleModel'),
|
||||
flex: 1,
|
||||
wrapText: true,
|
||||
cellStyle: { justifyContent: 'flex-start' /* 좌측정렬*/ },
|
||||
},
|
||||
{
|
||||
@ -283,6 +283,7 @@ export default function StuffDetail() {
|
||||
{getMessage('stuff.detail.planGrid.btn1')}
|
||||
</button>
|
||||
<button
|
||||
style={buttonStyle}
|
||||
type="button"
|
||||
className="grid-btn"
|
||||
onClick={() => {
|
||||
@ -309,6 +310,7 @@ export default function StuffDetail() {
|
||||
|
||||
useEffect(() => {
|
||||
if (objectNo) {
|
||||
setManagementState({})
|
||||
setEditMode('EDIT')
|
||||
if (objectNo.substring(0, 1) !== 'T') {
|
||||
//벨리데이션 체크용..
|
||||
@ -321,7 +323,7 @@ export default function StuffDetail() {
|
||||
} else {
|
||||
setManagementState({})
|
||||
alert(getMessage('stuff.detail.header.notExistObjectNo'))
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
}
|
||||
if (isNotEmptyArray(res.data.planList)) {
|
||||
setPlanGridProps({ ...planGridProps, planGridData: res.data.planList })
|
||||
@ -333,7 +335,7 @@ export default function StuffDetail() {
|
||||
setPlanGridProps({ ...planGridProps, planGridData: [] })
|
||||
|
||||
alert(getMessage('stuff.detail.header.notExistObjectNo'))
|
||||
router.push('/management/stuff')
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@ -516,7 +518,6 @@ export default function StuffDetail() {
|
||||
firstList = res
|
||||
favList = res.filter((row) => row.priority !== 'B')
|
||||
otherList = res.filter((row) => row.firstAgentYn === 'N')
|
||||
|
||||
setSaleStoreList(firstList)
|
||||
setFavoriteStoreList(firstList)
|
||||
setShowSaleStoreList(firstList)
|
||||
@ -547,6 +548,9 @@ export default function StuffDetail() {
|
||||
form.setValue('otherSaleStoreLevel', managementState.saleStoreLevel)
|
||||
|
||||
form.setValue('saleStoreLevel', '1')
|
||||
|
||||
form.setValue('saleStoreId', managementState.firstAgentId)
|
||||
setSelOptions(managementState.firstAgentId)
|
||||
}
|
||||
|
||||
//설계의뢰No.
|
||||
@ -896,6 +900,8 @@ export default function StuffDetail() {
|
||||
|
||||
//팝업에서 넘어온 설계의뢰 정보로 바꾸기
|
||||
const setPlanReqInfo = (info) => {
|
||||
// console.log('session 정보:::::::', session)
|
||||
// console.log('설계의뢰에서 넘어온 정보:::::::', info)
|
||||
form.setValue('planReqNo', info.planReqNo)
|
||||
form.setValue('objectStatusId', info.building)
|
||||
setSelectObjectStatusId(info.building)
|
||||
@ -912,7 +918,11 @@ export default function StuffDetail() {
|
||||
})
|
||||
|
||||
//설계의뢰 팝업에선 WL_안붙어서 옴
|
||||
form.setValue('standardWindSpeedId', `WL_${info.windSpeed}`)
|
||||
if (info.windSpeed !== '') {
|
||||
form.setValue('standardWindSpeedId', `WL_${info.windSpeed}`)
|
||||
} else {
|
||||
form.setValue('standardWindSpeedId', `WL_${info.windSpeed}`)
|
||||
}
|
||||
form.setValue('verticalSnowCover', info.verticalSnowCover)
|
||||
form.setValue('surfaceType', info.surfaceType)
|
||||
|
||||
@ -1041,7 +1051,7 @@ export default function StuffDetail() {
|
||||
errors.prefId = true
|
||||
}
|
||||
|
||||
if (!formData.areaId) {
|
||||
if (!formData.areaId || formData.areaId === '0') {
|
||||
errors.areaId = true
|
||||
}
|
||||
|
||||
@ -1285,23 +1295,34 @@ export default function StuffDetail() {
|
||||
}
|
||||
|
||||
if (editMode === 'NEW') {
|
||||
await promisePost({ url: apiUrl, data: params }).then((res) => {
|
||||
//상세화면으로 전환
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.save'))
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
|
||||
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
await promisePost({ url: apiUrl, data: params })
|
||||
.then((res) => {
|
||||
//상세화면으로 전환
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.save'))
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
|
||||
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error::::::', error)
|
||||
alert(error?.response.data.message)
|
||||
})
|
||||
} else {
|
||||
// 수정모드일때는 PUT
|
||||
await promisePut({ url: apiUrl, data: params }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: res.data.objectNo })
|
||||
alert(getMessage('stuff.detail.save'))
|
||||
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
// await promisePut({ url: apiUrl, data: params }).then((res) => {
|
||||
await promisePut({ url: apiUrl, data: params })
|
||||
.then((res) => {
|
||||
if (res.status === 201) {
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: res.data.objectNo })
|
||||
alert(getMessage('stuff.detail.save'))
|
||||
router.push(`/management/stuff/detail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error::::::', error)
|
||||
alert(error?.response.data.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1346,38 +1367,57 @@ export default function StuffDetail() {
|
||||
|
||||
const apiUrl = '/api/object/save-object'
|
||||
if (objectNo) {
|
||||
await promisePut({ url: apiUrl, data: params }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.tempSave.message1'))
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
await promisePut({ url: apiUrl, data: params })
|
||||
.then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.tempSave.message1'))
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error::::::', error)
|
||||
alert(error?.response.data.message)
|
||||
})
|
||||
} else {
|
||||
await promisePost({ url: apiUrl, data: params }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.tempSave.message1'))
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
await promisePost({ url: apiUrl, data: params })
|
||||
.then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('stuff.detail.tempSave.message1'))
|
||||
router.push(`/management/stuff/tempdetail?objectNo=${res.data.objectNo.toString()}`, { scroll: false })
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log('error::::::', error)
|
||||
alert(error?.response.data.message)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 물건삭제
|
||||
const onDelete = () => {
|
||||
const specificationConfirmDate = managementState.specificationConfirmDate
|
||||
const delParams = {
|
||||
userId: session.userId,
|
||||
}
|
||||
if (specificationConfirmDate != null) {
|
||||
alert(getMessage('stuff.detail.delete.message1'))
|
||||
} else {
|
||||
if (confirm(getMessage('common.message.data.delete'))) {
|
||||
del({ url: `/api/object/${objectNo}` }).then(() => {
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: '' })
|
||||
if (session.storeId === 'T01') {
|
||||
stuffSearchParams.code = 'DELETE'
|
||||
} else {
|
||||
resetStuffRecoil()
|
||||
}
|
||||
router.push('/management/stuff')
|
||||
})
|
||||
// setIsGlobalLoading(true)
|
||||
del({ url: `/api/object/${objectNo}?${queryStringFormatter(delParams)}` })
|
||||
.then(() => {
|
||||
setFloorPlanObjectNo({ floorPlanObjectNo: '' })
|
||||
if (session.storeId === 'T01') {
|
||||
stuffSearchParams.code = 'DELETE'
|
||||
} else {
|
||||
resetStuffRecoil()
|
||||
}
|
||||
// setIsGlobalLoading(false)
|
||||
router.push('/management/stuff', { scroll: false })
|
||||
})
|
||||
.catch(() => {
|
||||
// setIsGlobalLoading(false)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1388,6 +1428,11 @@ export default function StuffDetail() {
|
||||
input.value = input.value.replace(/[^0-9]/g, '')
|
||||
}
|
||||
|
||||
const handleBlur = (e) => {
|
||||
let input = e.target
|
||||
input.value = input.value.replace(/[^0-9]/g, '')
|
||||
}
|
||||
|
||||
//자동완성 옵션 없을때 메세지 컴포넌트..
|
||||
const NoOptionsMessage = (props) => {
|
||||
return (
|
||||
@ -1775,7 +1820,8 @@ export default function StuffDetail() {
|
||||
<input
|
||||
type="text"
|
||||
className="input-light"
|
||||
onKeyUp={handleKeyUp}
|
||||
onInput={handleKeyUp}
|
||||
onBlur={handleBlur}
|
||||
value={form.watch('verticalSnowCover') || ''}
|
||||
{...register('verticalSnowCover')}
|
||||
/>
|
||||
@ -1842,7 +1888,8 @@ export default function StuffDetail() {
|
||||
<input
|
||||
type="text"
|
||||
className="input-light"
|
||||
onKeyUp={handleKeyUp}
|
||||
onInput={handleKeyUp}
|
||||
onBlur={handleBlur}
|
||||
value={form.watch('installHeight') || ''}
|
||||
{...register('installHeight')}
|
||||
/>
|
||||
@ -2032,8 +2079,8 @@ export default function StuffDetail() {
|
||||
onChange={onSelectionChange}
|
||||
getOptionLabel={(x) => x.saleStoreName}
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isClearable={managementState.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isDisabled={managementState.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : false}
|
||||
isClearable={managementState?.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isDisabled={managementState?.tempFlg === '0' ? true : session?.storeLvl !== '1' ? true : false}
|
||||
value={saleStoreList.filter(function (option) {
|
||||
return option.saleStoreId === selOptions
|
||||
})}
|
||||
@ -2066,7 +2113,7 @@ export default function StuffDetail() {
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isClearable={false}
|
||||
isDisabled={
|
||||
managementState.tempFlg === '0'
|
||||
managementState?.tempFlg === '0'
|
||||
? true
|
||||
: session?.storeLvl !== '1'
|
||||
? true
|
||||
@ -2151,9 +2198,13 @@ export default function StuffDetail() {
|
||||
getOptionLabel={(x) => x.saleStoreName}
|
||||
getOptionValue={(x) => x.saleStoreId}
|
||||
isDisabled={
|
||||
managementState.tempFlg === '0' ? true : session?.storeLvl === '1' && form.watch('saleStoreId') != '' ? false : true
|
||||
managementState?.tempFlg === '0'
|
||||
? true
|
||||
: session?.storeLvl === '1' && form.watch('saleStoreId') != ''
|
||||
? false
|
||||
: true
|
||||
}
|
||||
isClearable={managementState.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
isClearable={managementState?.tempFlg === '0' ? false : session?.storeLvl === '1' ? true : false}
|
||||
value={otherSaleStoreList.filter(function (option) {
|
||||
return option.saleStoreId === otherSelOptions
|
||||
})}
|
||||
@ -2293,7 +2344,8 @@ export default function StuffDetail() {
|
||||
<input
|
||||
type="text"
|
||||
className="input-light"
|
||||
onKeyUp={handleKeyUp}
|
||||
onInput={handleKeyUp}
|
||||
onBlur={handleBlur}
|
||||
value={form.watch('verticalSnowCover') || ''}
|
||||
{...register('verticalSnowCover')}
|
||||
/>
|
||||
@ -2365,7 +2417,8 @@ export default function StuffDetail() {
|
||||
<input
|
||||
type="text"
|
||||
className="input-light"
|
||||
onKeyUp={handleKeyUp}
|
||||
onInput={handleKeyUp}
|
||||
onBlur={handleBlur}
|
||||
value={form.watch('installHeight') || ''}
|
||||
{...register('installHeight')}
|
||||
/>
|
||||
|
||||
@ -83,7 +83,6 @@ export default function StuffSearchCondition() {
|
||||
}
|
||||
|
||||
setIsGlobalLoading(true)
|
||||
|
||||
if (stuffSearch.code === 'S') {
|
||||
if (stuffSearch.pageNo !== 1) {
|
||||
setStuffSearch({
|
||||
@ -254,6 +253,7 @@ export default function StuffSearchCondition() {
|
||||
|
||||
//초기화
|
||||
const resetRecoil = () => {
|
||||
setIsGlobalLoading(false)
|
||||
//T01아니면 자동완성 초기화 막기
|
||||
objectNoRef.current.value = ''
|
||||
saleStoreNameRef.current.value = ''
|
||||
@ -291,17 +291,39 @@ export default function StuffSearchCondition() {
|
||||
schSortType: 'R',
|
||||
pageNo: 1,
|
||||
pageSize: 100,
|
||||
code: 'S',
|
||||
// code: 'S',
|
||||
})
|
||||
} else {
|
||||
if (otherSaleStoreList.length > 1) {
|
||||
handleClear2()
|
||||
setOtherSaleStoreId('')
|
||||
stuffSearch.schObjectNo = ''
|
||||
stuffSearch.schAddress = ''
|
||||
stuffSearch.schObjectName = ''
|
||||
stuffSearch.schSaleStoreName = ''
|
||||
stuffSearch.schReceiveUser = ''
|
||||
stuffSearch.schDispCompanyName = ''
|
||||
stuffSearch.schDateType = 'U'
|
||||
|
||||
stuffSearch.startRow = 1
|
||||
stuffSearch.endRow = 100
|
||||
stuffSearch.schSortType = 'R'
|
||||
stuffSearch.pageNo = 1
|
||||
stuffSearch.pageSize = 100
|
||||
} else {
|
||||
stuffSearch.schObjectNo = ''
|
||||
stuffSearch.schAddress = ''
|
||||
stuffSearch.schObjectName = ''
|
||||
stuffSearch.schSaleStoreName = ''
|
||||
stuffSearch.schReceiveUser = ''
|
||||
stuffSearch.schDispCompanyName = ''
|
||||
stuffSearch.schDateType = 'U'
|
||||
|
||||
stuffSearch.startRow = 1
|
||||
stuffSearch.endRow = 100
|
||||
stuffSearch.schSortType = 'R'
|
||||
stuffSearch.pageNo = 1
|
||||
stuffSearch.pageSize = 100
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -491,7 +513,6 @@ export default function StuffSearchCondition() {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
//X42
|
||||
if (session?.storeId === 'T01') {
|
||||
if (stuffSearch.code === 'DELETE') {
|
||||
setObjectNo('')
|
||||
@ -523,6 +544,37 @@ export default function StuffSearchCondition() {
|
||||
stuffSearch.pageNo = 1
|
||||
stuffSearch.pageSize = 100
|
||||
|
||||
setSchSelSaleStoreId('')
|
||||
setOtherSaleStoreId('')
|
||||
} else if (stuffSearch.code === 'S') {
|
||||
setObjectNo('')
|
||||
setSaleStoreName('')
|
||||
setAddress('')
|
||||
setobjectName('')
|
||||
setDispCompanyName('')
|
||||
setReceiveUser('')
|
||||
objectNoRef.current.value = ''
|
||||
saleStoreNameRef.current.value = ''
|
||||
addressRef.current.value = ''
|
||||
objectNameRef.current.value = ''
|
||||
dispCompanyNameRef.current.value = ''
|
||||
receiveUserRef.current.value = ''
|
||||
stuffSearch.schObjectNo = ''
|
||||
stuffSearch.schAddress = ''
|
||||
stuffSearch.schObjectName = ''
|
||||
stuffSearch.schSaleStoreName = ''
|
||||
stuffSearch.schReceiveUser = ''
|
||||
stuffSearch.schDispCompanyName = ''
|
||||
stuffSearch.schDateType = 'U'
|
||||
stuffSearch.schFromDt = dayjs(new Date()).add(-1, 'year').format('YYYY-MM-DD')
|
||||
stuffSearch.schToDt = dayjs(new Date()).format('YYYY-MM-DD')
|
||||
stuffSearch.startRow = 1
|
||||
stuffSearch.endRow = 100
|
||||
stuffSearch.schSelSaleStoreId = ''
|
||||
stuffSearch.schOtherSelSaleStoreId = ''
|
||||
stuffSearch.schSortType = 'R'
|
||||
stuffSearch.pageNo = 1
|
||||
stuffSearch.pageSize = 100
|
||||
setSchSelSaleStoreId('')
|
||||
setOtherSaleStoreId('')
|
||||
}
|
||||
@ -564,7 +616,8 @@ export default function StuffSearchCondition() {
|
||||
<h3>{getMessage('stuff.search.title')}</h3>
|
||||
</div>
|
||||
<div className="left-unit-box">
|
||||
<Link href="/management/stuff/tempdetail" scroll={false}>
|
||||
<Link href="/management/stuff/tempReg" scroll={false}>
|
||||
{/* <Link href="/management/stuff/tempdetail" scroll={false}> */}
|
||||
<button type="button" className="btn-origin navy mr5">
|
||||
{getMessage('stuff.search.btn.register')}
|
||||
</button>
|
||||
|
||||
@ -1,19 +1,26 @@
|
||||
'use client'
|
||||
|
||||
import { useEffect } from 'react'
|
||||
import { useContext, useEffect } from 'react'
|
||||
|
||||
import Link from 'next/link'
|
||||
import Image from 'next/image'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRouter, useSearchParams } from 'next/navigation'
|
||||
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
|
||||
import { useSetRecoilState } from 'recoil'
|
||||
|
||||
import { QcastContext } from '@/app/QcastProvider'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { queryStringFormatter } from '@/util/common-utils'
|
||||
|
||||
export default function StuffSubHeader({ type }) {
|
||||
const { getMessage } = useMessage()
|
||||
const router = useRouter()
|
||||
|
||||
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState)
|
||||
|
||||
const { isGlobalLoading } = useContext(QcastContext)
|
||||
|
||||
useEffect(() => {
|
||||
window.scrollTo(0, 0)
|
||||
}, [])
|
||||
@ -35,85 +42,87 @@ export default function StuffSubHeader({ type }) {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="sub-header">
|
||||
<div className="sub-header-inner">
|
||||
{type === 'list' && (
|
||||
<>
|
||||
<Link href={'#'}>
|
||||
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
|
||||
</Link>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.stuffList')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{type === 'temp' && (
|
||||
<>
|
||||
<ul className="sub-header-title-wrap">
|
||||
<li className="title-item">
|
||||
<Link className="sub-header-title" href={'#'}>
|
||||
{getMessage('stuff.temp.subTitle')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.newStuff')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{type === 'detail' && (
|
||||
<>
|
||||
<ul className="sub-header-title-wrap">
|
||||
<li className="title-item">
|
||||
<Link className="sub-header-title" href={'#'}>
|
||||
{getMessage('stuff.temp.subTitle')}
|
||||
</Link>
|
||||
</li>
|
||||
<li className="title-item">
|
||||
<a className="sub-header-title" onClick={moveFloorPlan}>
|
||||
<span className="icon drawing"></span>
|
||||
{getMessage('stuff.temp.subTitle2')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.detail')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
!isGlobalLoading && (
|
||||
<>
|
||||
<div className="sub-header">
|
||||
<div className="sub-header-inner">
|
||||
{type === 'list' && (
|
||||
<>
|
||||
<Link href={'#'}>
|
||||
<h1 className="sub-header-title">{getMessage('header.menus.management')}</h1>
|
||||
</Link>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.stuffList')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{type === 'temp' && (
|
||||
<>
|
||||
<ul className="sub-header-title-wrap">
|
||||
<li className="title-item">
|
||||
<Link className="sub-header-title" href={'#'}>
|
||||
{getMessage('stuff.temp.subTitle')}
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.newStuff')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
{type === 'detail' && (
|
||||
<>
|
||||
<ul className="sub-header-title-wrap">
|
||||
<li className="title-item">
|
||||
<Link className="sub-header-title" href={'#'}>
|
||||
{getMessage('stuff.temp.subTitle')}
|
||||
</Link>
|
||||
</li>
|
||||
<li className="title-item">
|
||||
<a className="sub-header-title" onClick={moveFloorPlan}>
|
||||
<span className="icon drawing"></span>
|
||||
{getMessage('stuff.temp.subTitle2')}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul className="sub-header-location">
|
||||
<li className="location-item">
|
||||
<span className="home">
|
||||
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
|
||||
</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management')}</span>
|
||||
</li>
|
||||
<li className="location-item">
|
||||
<span>{getMessage('header.menus.management.detail')}</span>
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@ -5,14 +5,28 @@ import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { isObjectNotEmpty } from '@/util/common-utils'
|
||||
import { useAxios } from '../useAxios'
|
||||
|
||||
/**
|
||||
* 공통코드 관리를 위한 커스텀 훅
|
||||
*
|
||||
* @description
|
||||
* - 공통코드를 전역 상태로 관리하고 필요한 곳에서 사용할 수 있도록 함
|
||||
* - 최초 1회만 API를 호출하여 공통코드를 가져옴
|
||||
* - 언어 설정에 따라 한국어/일본어 코드명을 자동으로 변환
|
||||
*
|
||||
* @returns {Object}
|
||||
* - commonCode: 전체 공통코드 객체(recoil state)
|
||||
* - findCommonCode: 특정 공통코드 그룹을 조회하는 함수
|
||||
*
|
||||
* @example
|
||||
* const { commonCode, findCommonCode } = useCommonCode();
|
||||
* const honorificCodes = findCommonCode(200800);
|
||||
*/
|
||||
export const useCommonCode = () => {
|
||||
const [commonCode, setCommonCode] = useRecoilState(commonCodeState)
|
||||
const globalLocale = useRecoilValue(globalLocaleStore)
|
||||
const { promiseGet } = useAxios()
|
||||
|
||||
const findCommonCode = (key) => {
|
||||
// const arr = commonCode[key]
|
||||
// return arr.sort((a, b) => a.clPriority - b.clPriority)
|
||||
const resultCodes = commonCode[key]?.map((code) => {
|
||||
const result = {
|
||||
clHeadCd: code.clHeadCd,
|
||||
|
||||
@ -1,83 +1,161 @@
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { useAxios } from '../useAxios'
|
||||
import { currentCanvasPlanState } from '@/store/canvasAtom'
|
||||
import { convertDwgToPng, writeImageBuffer } from '@/lib/fileAction'
|
||||
import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom'
|
||||
import { convertDwgToPng, removeImage, writeImageBuffer, readImage } from '@/lib/fileAction'
|
||||
import { useCanvas } from '@/hooks/useCanvas'
|
||||
|
||||
export function useRefFiles() {
|
||||
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
|
||||
const [refImage, setRefImage] = useState(null)
|
||||
const [refFileMethod, setRefFileMethod] = useState('1')
|
||||
const [mapPositionAddress, setMapPositionAddress] = useState('')
|
||||
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
const [currentBgImage, setCurrentBgImage] = useState(null)
|
||||
const queryRef = useRef(null)
|
||||
|
||||
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
const { handleBackImageLoadToCanvas } = useCanvas()
|
||||
const { swalFire } = useSwal()
|
||||
const { get, promisePut, promisePost } = useAxios()
|
||||
// const { currentCanvasPlan, setCurrentCanvasPlan } = usePlan()
|
||||
const { get, post, promisePost } = useAxios()
|
||||
|
||||
useEffect(() => {
|
||||
if (refFileMethod === '1') {
|
||||
// 파일 불러오기
|
||||
setMapPositionAddress('')
|
||||
} else {
|
||||
setRefImage(null)
|
||||
}
|
||||
}, [refFileMethod])
|
||||
|
||||
/**
|
||||
* 현재 플랜이 변경되면 플랜 상태 저장
|
||||
*/
|
||||
useEffect(() => {
|
||||
// console.log('🚀 ~ useRefFiles ~ currentCanvasPlan:', currentCanvasPlan)
|
||||
// const handleCurrentPlan = async () => {
|
||||
// await promisePut({ url: '/api/canvas-management/canvas-statuses', data: currentCanvasPlan }).then((res) => {
|
||||
// console.log('🚀 ~ awaitpromisePut ~ res:', res)
|
||||
// })
|
||||
// }
|
||||
// handleCurrentPlan()
|
||||
}, [currentCanvasPlan])
|
||||
|
||||
/**
|
||||
* 파일 불러오기 버튼 컨트롤
|
||||
* @param {*} file
|
||||
*/
|
||||
const handleRefFile = (file) => {
|
||||
setRefImage(file)
|
||||
/**
|
||||
* 파일 확장자가 dwg일 경우 변환하여 이미지로 저장
|
||||
* 파일 확장자가 이미지일 경우 이미지 저장
|
||||
*/
|
||||
file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
|
||||
// handleUploadRefFile(file)
|
||||
console.log('handleRefFile', file)
|
||||
console.log('refImage', refImage)
|
||||
|
||||
if (refImage) {
|
||||
swalFire({
|
||||
text: '파일을 변경하시겠습니까?',
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
refFileSetting(file)
|
||||
// setRefImage(file)
|
||||
// file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
|
||||
},
|
||||
})
|
||||
} else {
|
||||
refFileSetting(file)
|
||||
}
|
||||
}
|
||||
|
||||
const refFileSetting = (file) => {
|
||||
if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) {
|
||||
// setRefImage(file)
|
||||
file.name.split('.').pop() === 'dwg' ? handleUploadConvertRefFile(file) : handleUploadImageRefFile(file)
|
||||
} else {
|
||||
swalFire({
|
||||
text: '이미지가 아닙니다.',
|
||||
type: 'alert',
|
||||
icon: 'error',
|
||||
})
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 파일 삭제
|
||||
*/
|
||||
const handleFileDelete = () => {
|
||||
setRefImage(null)
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, bgFileName: null }))
|
||||
swalFire({
|
||||
text: '삭제하시겠습니까?',
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
setRefImage(null)
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, bgFileName: null }))
|
||||
removeImage(currentCanvasPlan.id).then((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 주소 삭제
|
||||
*/
|
||||
const handleAddressDelete = () => {
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null }))
|
||||
swalFire({
|
||||
text: '삭제하시겠습니까?',
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
setMapPositionAddress('')
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null }))
|
||||
removeImage(currentCanvasPlan.id).then((res) => {
|
||||
console.log(res)
|
||||
})
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 주소로 구글 맵 이미지 다운로드
|
||||
*/
|
||||
const handleMapImageDown = async () => {
|
||||
console.log('🚀 ~ handleMapImageDown ~ handleMapImageDown:')
|
||||
if (queryRef.current.value === '' || queryRef.current.value === null) {
|
||||
return
|
||||
}
|
||||
|
||||
const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryRef.current.value}&fileNm=${uuidv4()}&zoom=20` })
|
||||
const res = await get({
|
||||
url: `http://localhost:3000/api/html2canvas?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`,
|
||||
})
|
||||
console.log('🚀 ~ handleMapImageDown ~ res:', res)
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: res.fileNm, mapPositionAddress: queryRef.current.value }))
|
||||
const file = await readImage(res.fileNm)
|
||||
console.log('🚀 ~ handleMapImageDown ~ file:', file)
|
||||
setCurrentBgImage(file)
|
||||
// handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`)
|
||||
// setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: currentCanvasPlan.id, mapPositionAddress: queryRef.current.value }))
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentBgImage) {
|
||||
return
|
||||
}
|
||||
console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage)
|
||||
handleBackImageLoadToCanvas(`plan-images/${currentCanvasPlan.id}.png`)
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: refImage?.name ?? null, mapPositionAddress: queryRef.current.value }))
|
||||
}, [currentBgImage])
|
||||
|
||||
/**
|
||||
* 이미지 파일 업로드
|
||||
* @param {*} file
|
||||
*/
|
||||
const handleUploadImageRefFile = async (file) => {
|
||||
console.log('🚀 ~ handleUploadImageRefFile ~ file:', file)
|
||||
const formData = new FormData()
|
||||
formData.append('file', file)
|
||||
formData.append('fileName', currentCanvasPlan.id)
|
||||
|
||||
const response = await fetch('http://localhost:3000/api/image-upload', {
|
||||
method: 'POST',
|
||||
body: formData,
|
||||
})
|
||||
const res = await post({ url: 'http://localhost:3000/api/image-upload', data: formData })
|
||||
console.log('🚀 ~ handleUploadImageRefFile ~ res:', res)
|
||||
const image = await readImage(res.fileNm)
|
||||
console.log('🚀 ~ handleUploadImageRefFile ~ file:', image)
|
||||
|
||||
const result = await response.json()
|
||||
console.log('🚀 ~ handleUploadImageRefFile ~ res:', result)
|
||||
// writeImageBuffer(file)
|
||||
setCurrentBgImage(image)
|
||||
setRefImage(file)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -92,6 +170,7 @@ export function useRefFiles() {
|
||||
.then((res) => {
|
||||
convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
|
||||
swalFire({ text: '파일 변환 성공' })
|
||||
setRefImage(res.data.Files[0].FileData)
|
||||
})
|
||||
.catch((err) => {
|
||||
swalFire({ text: '파일 변환 실패', icon: 'error' })
|
||||
@ -106,19 +185,6 @@ export function useRefFiles() {
|
||||
setRefFileMethod(e.target.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* 현재 플랜이 변경되면 플랜 상태 저장
|
||||
*/
|
||||
useEffect(() => {
|
||||
console.log('🚀 ~ useRefFiles ~ currentCanvasPlan:', currentCanvasPlan)
|
||||
// const handleCurrentPlan = async () => {
|
||||
// await promisePut({ url: '/api/canvas-management/canvas-statuses', data: currentCanvasPlan }).then((res) => {
|
||||
// console.log('🚀 ~ awaitpromisePut ~ res:', res)
|
||||
// })
|
||||
// }
|
||||
// handleCurrentPlan()
|
||||
}, [currentCanvasPlan])
|
||||
|
||||
return {
|
||||
refImage,
|
||||
queryRef,
|
||||
|
||||
@ -3,7 +3,7 @@ import { useContext, useEffect, useReducer, useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
|
||||
import { isObjectNotEmpty, isNotEmptyArray } from '@/util/common-utils'
|
||||
import { isObjectNotEmpty, isEmptyArray, isNotEmptyArray } from '@/util/common-utils'
|
||||
import { SessionContext } from '@/app/SessionProvider'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useRouter } from 'next/navigation'
|
||||
@ -18,6 +18,9 @@ const updateItemInList = (itemList, dispOrder, updates) => {
|
||||
}
|
||||
|
||||
export const useEstimateController = (planNo) => {
|
||||
const [fileList, setFileList] = useState([])
|
||||
const [deleteFileList, setDeleteFileList] = useState([])
|
||||
|
||||
const router = useRouter()
|
||||
const { session } = useContext(SessionContext)
|
||||
const globalLocaleState = useRecoilValue(globalLocaleStore)
|
||||
@ -39,6 +42,12 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (fileList.length > 0) {
|
||||
realSave(fileList)
|
||||
}
|
||||
}, [fileList])
|
||||
|
||||
// 상세 조회
|
||||
const fetchSetting = async (objectNo, planNo) => {
|
||||
try {
|
||||
@ -50,6 +59,14 @@ export const useEstimateController = (planNo) => {
|
||||
item.delFlg = '0'
|
||||
})
|
||||
}
|
||||
if (res.data.pkgAsp === null || res.data.pkgAsp == undefined) {
|
||||
res.data.pkgAsp = '0.00'
|
||||
} else {
|
||||
const number = parseFloat(res.data.pkgAsp)
|
||||
const roundedNumber = isNaN(number) ? '0.00' : number.toFixed(2)
|
||||
|
||||
res.data.pkgAsp = roundedNumber.toString()
|
||||
}
|
||||
setEstimateContextState(res.data)
|
||||
}
|
||||
}
|
||||
@ -68,7 +85,7 @@ export const useEstimateController = (planNo) => {
|
||||
}
|
||||
|
||||
const addItem = () => {
|
||||
let newItemDispOrder = Math.max(...estimateContextState.itemList.map((item) => item.dispOrder))
|
||||
let newItemDispOrder = estimateContextState.itemList.length === 0 ? 0 : Math.max(...estimateContextState.itemList.map((item) => item.dispOrder))
|
||||
newItemDispOrder = (Math.floor(newItemDispOrder / 100) + 1) * 100
|
||||
setEstimateContextState({
|
||||
itemList: [
|
||||
@ -89,6 +106,7 @@ export const useEstimateController = (planNo) => {
|
||||
partAdd: '1', //NEW 체인지 플래그
|
||||
delFlg: '0', //삭제 플래그 0 삭제하면 1
|
||||
addFlg: true,
|
||||
paDispOrder: null,
|
||||
},
|
||||
],
|
||||
})
|
||||
@ -127,6 +145,7 @@ export const useEstimateController = (planNo) => {
|
||||
const handleEstimateSubmit = async () => {
|
||||
//0. 필수체크
|
||||
let flag = true
|
||||
let originFileFlg = false
|
||||
let fileFlg = true
|
||||
let itemFlg = true
|
||||
if (estimateData.charger.trim().length === 0) {
|
||||
@ -144,23 +163,44 @@ export const useEstimateController = (planNo) => {
|
||||
return alert(getMessage('estimate.detail.save.requiredEstimateDate'))
|
||||
}
|
||||
|
||||
//첨부파일을 첨부안했는데
|
||||
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
|
||||
if (estimateData.estimateType === 'YJSS') {
|
||||
let pkgAsp = estimateData.pkgAsp
|
||||
if (pkgAsp === '0') {
|
||||
flag = false
|
||||
return alert(getMessage('estimate.detail.save.requiredPkgAsp'))
|
||||
}
|
||||
}
|
||||
|
||||
//기존에 첨부된 파일이 있으면 파일첨부관련 통과
|
||||
if (estimateData?.originFiles?.length > 0) {
|
||||
let cnt = estimateData.originFiles.filter((file) => file.delFlg === '0').length
|
||||
|
||||
if (cnt == 0) {
|
||||
originFileFlg = false
|
||||
} else {
|
||||
originFileFlg = true
|
||||
}
|
||||
}
|
||||
|
||||
if (flag) {
|
||||
if (estimateData.fileList.length < 1) {
|
||||
if (estimateData.itemList.length > 1) {
|
||||
estimateData.itemList.map((row) => {
|
||||
if (row.delFlg === '0') {
|
||||
if (row.fileUploadFlg === '1') {
|
||||
if (fileFlg) {
|
||||
if (estimateData.fileFlg === '0') {
|
||||
fileFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredFileUpload'))
|
||||
if (!originFileFlg) {
|
||||
//기존에 첨부된 파일이 없으면
|
||||
if (isEmptyArray(estimateData.newFileList)) {
|
||||
//새로 첨부한 파일이 없으면
|
||||
if (estimateData.itemList.length > 1) {
|
||||
estimateData.itemList.map((row) => {
|
||||
if (row.delFlg === '0') {
|
||||
if (row.fileUploadFlg === '1') {
|
||||
if (fileFlg) {
|
||||
if (estimateData.fileFlg === '0') {
|
||||
fileFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredFileUpload'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,10 +208,16 @@ export const useEstimateController = (planNo) => {
|
||||
if (fileFlg) {
|
||||
estimateData.itemList.map((item) => {
|
||||
if (item.delFlg === '0') {
|
||||
item.amount = item.amount?.replaceAll(',', '')
|
||||
item.salePrice = parseFloat(item.salePrice?.replaceAll(',', '')).toFixed(2)
|
||||
item.saleTotPrice = parseFloat(item.saleTotPrice?.replaceAll(',', '')).toFixed(2)
|
||||
if (item.addFlg) {
|
||||
if (item.itemId === '') {
|
||||
itemFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredItemId'))
|
||||
}
|
||||
}
|
||||
|
||||
item.amount = item.amount?.replaceAll(',', '')
|
||||
item.salePrice = Number(item.salePrice?.replaceAll(',', '')).toFixed(2)
|
||||
item.saleTotPrice = Number(item.saleTotPrice?.replaceAll(',', '')).toFixed(2)
|
||||
if (!item.paDispOrder) {
|
||||
if (itemFlg) {
|
||||
if (isNaN(item.amount)) {
|
||||
@ -188,39 +234,27 @@ export const useEstimateController = (planNo) => {
|
||||
item.salePrice = '0'
|
||||
}
|
||||
|
||||
if (item.salePrice < 1) {
|
||||
itemFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredSalePrice'))
|
||||
if (item.openFlg !== '1') {
|
||||
if (item.salePrice < 1) {
|
||||
itemFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredSalePrice'))
|
||||
}
|
||||
}
|
||||
|
||||
estimateData.pkgAsp = '0'
|
||||
estimateData.pkgTotPrice = '0'
|
||||
} else {
|
||||
if (item.pkgMaterialFlg === '1') {
|
||||
if (isNaN(item.salePrice)) {
|
||||
itemFlg = false
|
||||
return alert(getMessage('estimate.detail.save.requiredSalePrice'))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
if (flag && fileFlg && itemFlg) {
|
||||
//1. 첨부파일 저장시작
|
||||
const formData = new FormData()
|
||||
if (isNotEmptyArray(estimateData.tempFileList) > 1) {
|
||||
estimateData.tempFileList.forEach((file) => {
|
||||
formData.append('files', file)
|
||||
})
|
||||
formData.append('objectNo', estimateData.objectNo)
|
||||
formData.append('planNo', estimateData.planNo)
|
||||
formData.append('category', '10')
|
||||
formData.append('userId', estimateData.userId)
|
||||
|
||||
await post({ url: '/api/file/fileUpload', data: formData })
|
||||
}
|
||||
|
||||
//첨부파일저장끝
|
||||
|
||||
//제품라인 추가했는데 아이템 안고르고 저장하면itemId=''은 날리고 나머지 저장하기
|
||||
// estimateData.itemList = estimateData.itemList.filter((item) => item.itemId !== '')
|
||||
estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg)
|
||||
|
||||
let delCnt = 0
|
||||
@ -232,30 +266,104 @@ export const useEstimateController = (planNo) => {
|
||||
if (delCnt === estimateData.itemList.length) {
|
||||
return alert(getMessage('estimate.detail.save.requiredItem'))
|
||||
}
|
||||
}
|
||||
|
||||
let option = []
|
||||
estimateData.itemList.forEach((item) => {
|
||||
if (item.specialNoteCd) {
|
||||
let split2 = item.specialNoteCd.split('、')
|
||||
option = option.concat(split2)
|
||||
if (flag && fileFlg && itemFlg) {
|
||||
//1. 첨부파일 저장시작
|
||||
const formData = new FormData()
|
||||
if (estimateData?.newFileList?.length > 0) {
|
||||
estimateData.newFileList.forEach((file) => {
|
||||
formData.append('files', file)
|
||||
})
|
||||
formData.append('objectNo', estimateData.objectNo)
|
||||
formData.append('planNo', estimateData.planNo)
|
||||
formData.append('category', '10')
|
||||
formData.append('userId', estimateData.userId)
|
||||
|
||||
await post({ url: '/api/file/fileUpload', data: formData }).then((res) => {
|
||||
setFileList(res)
|
||||
})
|
||||
} else {
|
||||
setFileList([])
|
||||
realSave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const realSave = async (fileList) => {
|
||||
//첨부파일저장끝
|
||||
|
||||
let option = []
|
||||
estimateData.itemList.forEach((item) => {
|
||||
if (item.specialNoteCd) {
|
||||
let split2 = item.specialNoteCd.split('、')
|
||||
option = option.concat(split2)
|
||||
}
|
||||
})
|
||||
|
||||
let estimateOptions = ''
|
||||
let estimateOptionsArray
|
||||
estimateData.specialNoteList.map((item) => {
|
||||
if (item.pkgYn === '0') {
|
||||
if (item.check) {
|
||||
if (estimateOptions === '') {
|
||||
estimateOptions = item.code
|
||||
} else {
|
||||
estimateOptions += '、' + item.code
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (item.check) {
|
||||
let flg = '0'
|
||||
for (let i = 0; i < estimateData.uniqueData.length; i++) {
|
||||
if (item.code.indexOf(estimateData.uniqueData[i]) > -1) {
|
||||
flg = '1'
|
||||
}
|
||||
if (flg === '1') {
|
||||
estimateOptions += '、' + estimateData.uniqueData[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
estimateOptionsArray = estimateOptions.split('、').sort()
|
||||
estimateOptionsArray = Array.from(new Set(estimateOptionsArray))
|
||||
|
||||
estimateOptions = estimateOptionsArray.join('、')
|
||||
|
||||
estimateData.estimateOption = estimateOptions
|
||||
// console.log('최종아이템:::', estimateData.itemList)
|
||||
if (fileList?.length > 0) {
|
||||
estimateData.fileList = fileList
|
||||
} else {
|
||||
estimateData.fileList = []
|
||||
}
|
||||
if (estimateData.originFiles?.length > 0) {
|
||||
estimateData.deleteFileList = estimateData.originFiles?.filter((item) => item.delFlg === '1')
|
||||
} else {
|
||||
estimateData.deleteFileList = []
|
||||
}
|
||||
|
||||
if (estimateData.estimateType === 'YJSS') {
|
||||
estimateData.pkgAsp = estimateData.pkgAsp.replaceAll(',', '')
|
||||
}
|
||||
|
||||
console.log('최종저장::', estimateData)
|
||||
//2. 상세데이터 저장
|
||||
// return
|
||||
try {
|
||||
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
estimateData.newFileList = []
|
||||
// estimateData.originFiles = []
|
||||
alert(getMessage('estimate.detail.save.alertMsg'))
|
||||
//어디로 보낼지
|
||||
fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo)
|
||||
}
|
||||
})
|
||||
|
||||
console.log('아이템리스트::', estimateData.itemList)
|
||||
console.log('최종 정보::;', estimateData)
|
||||
//2. 상세데이터 저장
|
||||
// return
|
||||
try {
|
||||
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => {
|
||||
if (res.status === 201) {
|
||||
alert(getMessage('estimate.detail.save.alertMsg'))
|
||||
//어디로 보낼지
|
||||
fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo)
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.log('error::::::::::::', e.response.data.message)
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('error::::::::::::', e.response.data.message)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,43 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||
import { adsorptionPointModeState, adsorptionRangeState, canvasState, planSizeSettingState } from '@/store/canvasAtom'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
||||
import {
|
||||
adsorptionPointModeState,
|
||||
adsorptionRangeState,
|
||||
canvasState,
|
||||
planSizeSettingState,
|
||||
dotLineGridSettingState,
|
||||
canvasSettingState,
|
||||
} from '@/store/canvasAtom'
|
||||
import { globalLocaleStore } from '@/store/localeAtom'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { correntObjectNoState, corridorDimensionSelector, settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
|
||||
import {
|
||||
correntObjectNoState,
|
||||
corridorDimensionSelector,
|
||||
settingModalFirstOptionsState,
|
||||
settingModalSecondOptionsState,
|
||||
settingModalGridOptionsState,
|
||||
basicSettingState,
|
||||
settingsState,
|
||||
} from '@/store/settingAtom'
|
||||
import { POLYGON_TYPE } from '@/common/common'
|
||||
import { globalFontAtom } from '@/store/fontAtom'
|
||||
import { dimensionLineSettingsState } from '@/store/commonUtilsAtom'
|
||||
import { gridColorState } from '@/store/gridAtom'
|
||||
import { useColor } from 'react-color-palette'
|
||||
|
||||
let objectNo
|
||||
const defaultDotLineGridSetting = {
|
||||
INTERVAL: {
|
||||
type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격
|
||||
ratioInterval: 910,
|
||||
verticalInterval: 910,
|
||||
horizontalInterval: 910,
|
||||
dimension: 1, // 치수
|
||||
},
|
||||
DOT: false,
|
||||
LINE: false,
|
||||
}
|
||||
|
||||
export function useCanvasSetting() {
|
||||
const canvas = useRecoilValue(canvasState)
|
||||
@ -20,8 +47,11 @@ export function useCanvasSetting() {
|
||||
|
||||
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
|
||||
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
|
||||
|
||||
// const [settingsData, setSettingsData] = useRecoilState(settingsState)
|
||||
const [settingsData, setSettingsData] = useState({ ...settingModalFirstOptions, ...settingModalSecondOptions })
|
||||
const { option1, option2, dimensionDisplay } = settingModalFirstOptions
|
||||
const { option3, option4 } = settingModalSecondOptions
|
||||
const { option4 } = settingModalSecondOptions
|
||||
|
||||
const corridorDimension = useRecoilValue(corridorDimensionSelector)
|
||||
|
||||
@ -42,6 +72,27 @@ export function useCanvasSetting() {
|
||||
const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom)
|
||||
const [dimensionLineSettings, setDimensionLineSettings] = useRecoilState(dimensionLineSettingsState)
|
||||
|
||||
const setSettingModalGridOptions = useSetRecoilState(settingModalGridOptionsState)
|
||||
const [dotLineGridSetting, setDotLineGridSettingState] = useRecoilState(dotLineGridSettingState)
|
||||
const resetDotLineGridSetting = useResetRecoilState(dotLineGridSettingState)
|
||||
const [currentSetting, setCurrentSetting] = useState(
|
||||
JSON.stringify(dotLineGridSetting) === JSON.stringify(defaultDotLineGridSetting) ? { ...defaultDotLineGridSetting } : { ...dotLineGridSetting },
|
||||
)
|
||||
const [gridColor, setGridColor] = useRecoilState(gridColorState)
|
||||
const [color, setColor] = useColor(gridColor ?? '#FF0000')
|
||||
const [colorTemp, setColorTemp] = useState()
|
||||
|
||||
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
|
||||
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
|
||||
|
||||
const SelectOptions = [
|
||||
{ id: 1, name: getMessage('modal.canvas.setting.grid.dot.line.setting.line.origin'), value: 1 },
|
||||
{ id: 2, name: '1/2', value: 1 / 2 },
|
||||
{ id: 3, name: '1/4', value: 1 / 4 },
|
||||
{ id: 4, name: '1/10', value: 1 / 10 },
|
||||
]
|
||||
const [selectOption, setSelectOption] = useState(SelectOptions[0])
|
||||
|
||||
useEffect(() => {
|
||||
if (!canvas) {
|
||||
return
|
||||
@ -72,51 +123,66 @@ export function useCanvasSetting() {
|
||||
canvas?.renderAll()
|
||||
}, [corridorDimension])
|
||||
|
||||
// 배치면 초기설정 변경 시
|
||||
useEffect(() => {
|
||||
console.log('useCanvasSetting useEffect 실행1', correntObjectNo)
|
||||
}, [])
|
||||
//console.log('useCanvasSetting canvasSetting 실행', canvasSetting)
|
||||
if (canvasSetting.flag) {
|
||||
basicSettingSave()
|
||||
}
|
||||
}, [canvasSetting])
|
||||
|
||||
useEffect(() => {
|
||||
console.log('🚀 ~ useEffect ~ settingsData:', settingsData)
|
||||
}, [settingsData])
|
||||
|
||||
//흡착점 ON/OFF 변경 시
|
||||
useEffect(() => {
|
||||
console.log('useCanvasSetting useEffect 실행2', adsorptionPointMode.fontFlag, correntObjectNo)
|
||||
|
||||
if (adsorptionPointMode.fontFlag) {
|
||||
onClickOption2()
|
||||
frontSettings()
|
||||
fetchSettings()
|
||||
}
|
||||
}, [adsorptionPointMode])
|
||||
// useEffect(() => {
|
||||
// //console.log('useCanvasSetting 실행2', adsorptionPointMode.fontFlag, correntObjectNo)
|
||||
// if (adsorptionPointMode.fontFlag) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [adsorptionPointMode])
|
||||
|
||||
// 1 과 2 변경 시
|
||||
useEffect(() => {
|
||||
console.log('useCanvasSetting useEffect 실행3', settingModalFirstOptions.fontFlag, settingModalSecondOptions.fontFlag, correntObjectNo)
|
||||
if (settingModalFirstOptions.fontFlag || settingModalSecondOptions.fontFlag) {
|
||||
onClickOption2()
|
||||
frontSettings()
|
||||
fetchSettings()
|
||||
}
|
||||
}, [settingModalFirstOptions, settingModalSecondOptions])
|
||||
// useEffect(() => {
|
||||
// //console.log('useCanvasSetting 실행3', settingModalFirstOptions.fontFlag, settingModalSecondOptions.fontFlag, correntObjectNo)
|
||||
// if (settingModalFirstOptions.fontFlag || settingModalSecondOptions.fontFlag) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [settingModalFirstOptions, settingModalSecondOptions])
|
||||
|
||||
// 글꼴 변경 시
|
||||
useEffect(() => {
|
||||
console.log('useCanvasSetting useEffect 실행4', globalFont.fontFlag, correntObjectNo)
|
||||
if (globalFont.fontFlag) {
|
||||
onClickOption2()
|
||||
frontSettings()
|
||||
fetchSettings()
|
||||
}
|
||||
}, [globalFont])
|
||||
// useEffect(() => {
|
||||
// //console.log('useCanvasSetting 실행4', globalFont.fontFlag, correntObjectNo)
|
||||
// if (globalFont.fontFlag) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [globalFont])
|
||||
|
||||
// 도명크기 변경 시
|
||||
useEffect(() => {
|
||||
console.log('useCanvasSetting useEffect 실행5', planSizeSettingMode.flag, correntObjectNo)
|
||||
// useEffect(() => {
|
||||
// //console.log('useCanvasSetting 실행5', planSizeSettingMode.flag, correntObjectNo)
|
||||
// if (planSizeSettingMode.flag) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [planSizeSettingMode])
|
||||
|
||||
if (planSizeSettingMode.flag) {
|
||||
onClickOption2()
|
||||
frontSettings()
|
||||
fetchSettings()
|
||||
}
|
||||
}, [planSizeSettingMode])
|
||||
// 점/선 그리드 변경 시
|
||||
// useEffect(() => {
|
||||
// //console.log('useCanvasSetting 실행6', dotLineGridSetting.flag)
|
||||
// if (dotLineGridSetting.flag) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [dotLineGridSetting])
|
||||
|
||||
// 그리드 색 설정 변경 시
|
||||
// useEffect(() => {
|
||||
// console.log('useCanvasSetting 실행7', colorTemp, gridColor)
|
||||
// //colorTemp는 변경 전.. 값이 있고 변경된 컬러와 다를 때 실행
|
||||
// if (colorTemp !== undefined && colorTemp !== gridColor) {
|
||||
// onClickOption2()
|
||||
// }
|
||||
// }, [color])
|
||||
|
||||
const getFonts = (itemValue) => {
|
||||
if (!itemValue) return { id: 1, name: 'MS PGothic', value: 'MS PGothic' }
|
||||
@ -189,6 +255,95 @@ export function useCanvasSetting() {
|
||||
}
|
||||
}
|
||||
|
||||
// 기본설정(PlacementShapeSetting) 조회 및 초기화
|
||||
const fetchBasicSettings = async () => {
|
||||
try {
|
||||
await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}` }).then((res) => {
|
||||
console.log('fetchBasicSettings res ', res)
|
||||
if (res.length == 0) return
|
||||
|
||||
// 'roofs' 배열을 생성하여 각 항목을 추가
|
||||
const roofsRow = res.map((item) => {
|
||||
return {
|
||||
roofSizeSet: item.roofSizeSet,
|
||||
roofAngleSet: item.roofAngleSet,
|
||||
}
|
||||
})
|
||||
|
||||
const roofsArray = res.some((item) => !item.roofSeq)
|
||||
? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정
|
||||
res.map(() => ({
|
||||
flag: false,
|
||||
roofApply: true,
|
||||
roofSeq: 1,
|
||||
roofType: 1,
|
||||
roofWidth: 265,
|
||||
roofHeight: 235,
|
||||
roofHajebichi: 0,
|
||||
roofGap: 455,
|
||||
// roofType: 1,
|
||||
// roofWidth: 200,
|
||||
// roofHeight: 200,
|
||||
// roofHajebichi: 200,
|
||||
// roofGap: 0,
|
||||
roofLayout: 'parallel',
|
||||
}))
|
||||
: res.map((item) => ({
|
||||
flag: false,
|
||||
roofApply: item.roofApply === '' || item.roofApply === false ? false : true,
|
||||
roofSeq: item.roofSeq,
|
||||
roofType: item.roofType,
|
||||
roofWidth: item.roofWidth,
|
||||
roofHeight: item.roofHeight,
|
||||
roofHajebichi: item.roofHajebichi,
|
||||
roofGap: item.roofGap,
|
||||
roofLayout: item.roofLayout,
|
||||
}))
|
||||
console.log('roofsArray ', roofsArray)
|
||||
// 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음
|
||||
const patternData = {
|
||||
roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용
|
||||
roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용
|
||||
roofs: roofsArray, // 만들어진 roofs 배열
|
||||
}
|
||||
|
||||
//console.error('patternData', patternData)
|
||||
|
||||
// 데이터 설정
|
||||
setBasicSettings({ ...patternData })
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
|
||||
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
|
||||
setBasicSettings({ ...canvasSetting })
|
||||
}
|
||||
//setCanvasSetting({ ...basicSetting })
|
||||
}
|
||||
|
||||
// 기본설정(PlacementShapeSetting) 저장
|
||||
const basicSettingSave = async () => {
|
||||
try {
|
||||
const patternData = {
|
||||
objectNo: correntObjectNo,
|
||||
roofSizeSet: basicSetting.roofSizeSet,
|
||||
roofAngleSet: basicSetting.roofAngleSet,
|
||||
roofMaterialsAddList: basicSetting.roofs,
|
||||
}
|
||||
|
||||
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
})
|
||||
|
||||
//Recoil 설정
|
||||
setCanvasSetting({ ...basicSetting, flag: false })
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
}
|
||||
|
||||
// CanvasSetting 조회 및 초기화
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${correntObjectNo}` })
|
||||
@ -269,10 +424,35 @@ export function useCanvasSetting() {
|
||||
//글꼴 설정 Flag
|
||||
fontFlag: false,
|
||||
}
|
||||
console.log('fontPatternData', fontPatternData)
|
||||
|
||||
//조회된 글꼴 데이터 set
|
||||
setGlobalFont(fontPatternData)
|
||||
|
||||
//점/선 그리드
|
||||
const patternData = {
|
||||
INTERVAL: {
|
||||
type: res.gridType,
|
||||
horizontalInterval: res.gridHorizon * 10,
|
||||
verticalInterval: res.gridVertical * 10,
|
||||
ratioInterval: res.gridRatio * 10,
|
||||
dimension: res.gridDimen,
|
||||
},
|
||||
DOT: res.dotGridDisplay,
|
||||
LINE: res.lineGridDisplay,
|
||||
flag: false,
|
||||
}
|
||||
|
||||
const matchedOption = SelectOptions.find((option) => option.value == res.gridDimen)
|
||||
|
||||
// dimension 값에 맞는 옵션을 선택
|
||||
setSelectOption(matchedOption)
|
||||
|
||||
setDotLineGridSettingState(patternData)
|
||||
//setCurrentSetting(patternData)
|
||||
|
||||
//그리드 색 설정
|
||||
setGridColor(res.gridColor)
|
||||
setColorTemp(res.gridColor)
|
||||
} else {
|
||||
//조회된 글꼴 데이터가 없는 경우
|
||||
|
||||
@ -299,6 +479,14 @@ export function useCanvasSetting() {
|
||||
})
|
||||
|
||||
setGlobalFont({ ...globalFont, fontFlag: false })
|
||||
|
||||
//점/선 그리드
|
||||
setDotLineGridSettingState({ ...defaultDotLineGridSetting, flag: false })
|
||||
//setCurrentSetting({ ...defaultDotLineGridSetting })
|
||||
|
||||
//그리드 색 설정
|
||||
setGridColor('#FF0000')
|
||||
setColorTemp('#FF0000')
|
||||
}
|
||||
frontSettings()
|
||||
} catch (error) {
|
||||
@ -306,8 +494,8 @@ export function useCanvasSetting() {
|
||||
}
|
||||
}
|
||||
|
||||
// 옵션 클릭 후 저장
|
||||
const onClickOption2 = useCallback(async () => {
|
||||
// CanvasSetting 옵션 클릭 후 저장
|
||||
const onClickOption2 = async () => {
|
||||
// 서버에 전송할 데이터
|
||||
const dataToSend = {
|
||||
firstOption1: option1.map((item) => ({
|
||||
@ -394,13 +582,26 @@ export function useCanvasSetting() {
|
||||
originPixel: dimensionLineSettings.pixel,
|
||||
originColor: dimensionLineSettings.color,
|
||||
|
||||
//치수선 설정
|
||||
//도면크기 설정
|
||||
originHorizon: planSizeSettingMode.originHorizon,
|
||||
originVertical: planSizeSettingMode.originVertical,
|
||||
|
||||
dotGridDisplay: dotLineGridSetting.DOT,
|
||||
lineGridDisplay: dotLineGridSetting.LINE,
|
||||
gridType: dotLineGridSetting.INTERVAL.type,
|
||||
gridHorizon: dotLineGridSetting.INTERVAL.horizontalInterval / 10,
|
||||
gridVertical: dotLineGridSetting.INTERVAL.verticalInterval / 10,
|
||||
gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10,
|
||||
gridDimen: dotLineGridSetting.INTERVAL.dimension,
|
||||
|
||||
//gridColor: gridColor.gridColor,
|
||||
gridColor: gridColor,
|
||||
}
|
||||
|
||||
console.log('patternData ', patternData)
|
||||
|
||||
setColorTemp(gridColor)
|
||||
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
|
||||
.then((res) => {
|
||||
@ -408,13 +609,15 @@ export function useCanvasSetting() {
|
||||
|
||||
// Canvas 디스플레이 설정 시 해당 옵션 적용
|
||||
frontSettings()
|
||||
// 저장 후 재조회
|
||||
fetchSettings()
|
||||
})
|
||||
.catch((error) => {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
})
|
||||
|
||||
//setAdsorptionRange(item.range)
|
||||
}, [settingModalFirstOptions, settingModalSecondOptions, adsorptionPointMode, globalFont, planSizeSettingMode])
|
||||
}
|
||||
|
||||
// Canvas 디스플레이 설정 시 해당 옵션 적용
|
||||
const frontSettings = async () => {
|
||||
@ -491,6 +694,7 @@ export function useCanvasSetting() {
|
||||
|
||||
return {
|
||||
canvas,
|
||||
correntObjectNo,
|
||||
settingModalFirstOptions,
|
||||
setSettingModalFirstOptions,
|
||||
settingModalSecondOptions,
|
||||
@ -500,7 +704,6 @@ export function useCanvasSetting() {
|
||||
adsorptionRange,
|
||||
setAdsorptionRange,
|
||||
fetchSettings,
|
||||
//onClickOption,
|
||||
frontSettings,
|
||||
globalFont,
|
||||
setGlobalFont,
|
||||
@ -516,5 +719,26 @@ export function useCanvasSetting() {
|
||||
setDimensionLineSettings,
|
||||
planSizeSettingMode,
|
||||
setPlanSizeSettingMode,
|
||||
selectOption,
|
||||
setSelectOption,
|
||||
SelectOptions,
|
||||
currentSetting,
|
||||
setCurrentSetting,
|
||||
dotLineGridSettingState,
|
||||
setSettingModalGridOptions,
|
||||
setDotLineGridSettingState,
|
||||
resetDotLineGridSetting,
|
||||
gridColor,
|
||||
setGridColor,
|
||||
color,
|
||||
setColor,
|
||||
canvasSetting,
|
||||
setCanvasSetting,
|
||||
basicSetting,
|
||||
setBasicSettings,
|
||||
fetchBasicSettings,
|
||||
basicSettingSave,
|
||||
settingsData,
|
||||
setSettingsData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom'
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
|
||||
export const useCanvasSettingController = () => {
|
||||
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
|
||||
const [settingModalSecondOptions, setSettingModalSecondOptions] = useRecoilState(settingModalSecondOptionsState)
|
||||
const [objectNo, setObjectNo] = useState('test123240912001') // 이후 삭제 필요
|
||||
const { get } = useAxios()
|
||||
|
||||
useEffect(() => {
|
||||
fetchSettings()
|
||||
}, [objectNo])
|
||||
|
||||
useEffect(() => {
|
||||
fetchSettings()
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
onClickOnlyOne()
|
||||
fetchSettings()
|
||||
}, [settingModalFirstOptions, settingModalSecondOptions])
|
||||
|
||||
const fetchSettings = async () => {
|
||||
try {
|
||||
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
|
||||
const optionData1 = settingModalFirstOptions.option1.map((item) => ({ ...item, selected: res[item.column] }))
|
||||
const optionData2 = settingModalFirstOptions.option2.map((item) => ({ ...item, selected: res[item.column] }))
|
||||
const optionData3 = settingModalSecondOptions.option3.map((item) => ({ ...item }))
|
||||
const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] }))
|
||||
const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({
|
||||
...item,
|
||||
}))
|
||||
// 데이터 설정
|
||||
setSettingModalFirstOptions({
|
||||
option1: optionData1,
|
||||
option2: optionData2,
|
||||
dimensionDisplay: optionData5,
|
||||
})
|
||||
setSettingModalSecondOptions({
|
||||
option3: optionData3,
|
||||
option4: optionData4,
|
||||
})
|
||||
} catch (error) {
|
||||
console.error('Data fetching error:', error)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
const onClickOption = async (option) => {
|
||||
option.selected = !option.selected
|
||||
|
||||
setSettingModalFirstOptions({ option1, option2, dimensionDisplay })
|
||||
setSettingModalSecondOptions({ option3, option4 })
|
||||
|
||||
try {
|
||||
// 서버에 전송할 데이터
|
||||
const dataToSend = {
|
||||
firstOption1: option1.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
firstOption2: option2.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
firstOption3: dimensionDisplay.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
// secondOption1: secondOptions[0].option1.map((item) => ({
|
||||
// name: item.id,
|
||||
// name: item.name,
|
||||
// // 필요한 경우 데이터 항목 추가
|
||||
// })),
|
||||
secondOption2: option4.map((item) => ({
|
||||
column: item.column,
|
||||
selected: item.selected,
|
||||
})),
|
||||
}
|
||||
|
||||
const patternData = {
|
||||
objectNo,
|
||||
//디스플레이 설정(다중)
|
||||
allocDisplay: dataToSend.firstOption1[0].selected,
|
||||
outlineDisplay: dataToSend.firstOption1[1].selected,
|
||||
gridDisplay: dataToSend.firstOption1[2].selected,
|
||||
lineDisplay: dataToSend.firstOption1[3].selected,
|
||||
wordDisplay: dataToSend.firstOption1[4].selected,
|
||||
circuitNumDisplay: dataToSend.firstOption1[5].selected,
|
||||
flowDisplay: dataToSend.firstOption1[6].selected,
|
||||
trestleDisplay: dataToSend.firstOption1[7].selected,
|
||||
totalDisplay: dataToSend.firstOption1[8].selected,
|
||||
//차수 표시(다건)
|
||||
corridorDimension: dataToSend.firstOption3[0].selected,
|
||||
realDimension: dataToSend.firstOption3[1].selected,
|
||||
noneDimension: dataToSend.firstOption3[2].selected,
|
||||
//화면 표시(다중)
|
||||
onlyBorder: dataToSend.firstOption2[0].selected,
|
||||
lineHatch: dataToSend.firstOption2[1].selected,
|
||||
allPainted: dataToSend.firstOption2[2].selected,
|
||||
//흡착범위 설정(단건)
|
||||
adsorpRangeSmall: dataToSend.secondOption2[0].selected,
|
||||
adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected,
|
||||
adsorpRangeMedium: dataToSend.secondOption2[2].selected,
|
||||
adsorpRangeLarge: dataToSend.secondOption2[3].selected,
|
||||
}
|
||||
|
||||
// HTTP POST 요청 보내기
|
||||
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }).then((res) => {
|
||||
swalFire({ text: getMessage(res.returnMessage) })
|
||||
})
|
||||
} catch (error) {
|
||||
swalFire({ text: getMessage(res.returnMessage), icon: 'error' })
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
fetchSettings,
|
||||
settingModalFirstOptions,
|
||||
setSettingModalFirstOptions,
|
||||
settingModalSecondOptions,
|
||||
setSettingModalSecondOptions,
|
||||
onClickOption,
|
||||
ß,
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { useContext, useEffect, useRef } from 'react'
|
||||
import { useEffect, useRef } from 'react'
|
||||
import { distanceBetweenPoints } from '@/util/canvas-util'
|
||||
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
|
||||
import {
|
||||
@ -31,7 +31,6 @@ import { fabric } from 'fabric'
|
||||
import { outlineDisplaySelector } from '@/store/settingAtom'
|
||||
import { usePopup } from '@/hooks/usePopup'
|
||||
import PropertiesSetting from '@/components/floor-plan/modal/outerlinesetting/PropertiesSetting'
|
||||
import { EventContext } from '@/app/floor-plan/EventProvider'
|
||||
|
||||
//외벽선 그리기
|
||||
export function useOuterLineWall(id, propertiesId) {
|
||||
|
||||
@ -507,18 +507,33 @@ export function useCanvas(id) {
|
||||
* cad 파일 사용시 이미지 로딩 함수
|
||||
*/
|
||||
const handleBackImageLoadToCanvas = (url) => {
|
||||
console.log('image load url: ', url)
|
||||
|
||||
fabric.Image.fromURL(url, function (img) {
|
||||
canvas
|
||||
.getObjects()
|
||||
.filter((obj) => obj.name === 'backGroundImage')
|
||||
.forEach((img) => {
|
||||
canvas.remove(img)
|
||||
canvas?.renderAll()
|
||||
})
|
||||
fabric.Image.fromURL(`${url}?${new Date().getTime()}`, function (img) {
|
||||
console.log(img)
|
||||
img.set({
|
||||
left: 0,
|
||||
top: 0,
|
||||
width: 1500,
|
||||
height: 1500,
|
||||
selectable: true,
|
||||
width: img.width,
|
||||
height: img.height,
|
||||
name: 'backGroundImage',
|
||||
selectable: false,
|
||||
hasRotatingPoint: false, // 회전 핸들 활성화
|
||||
lockMovementX: false,
|
||||
lockMovementY: false,
|
||||
lockRotation: false,
|
||||
lockScalingX: false,
|
||||
lockScalingY: false,
|
||||
})
|
||||
canvas.add(img)
|
||||
canvas.renderAll()
|
||||
// image = img
|
||||
canvas?.add(img)
|
||||
canvas?.sendToBack(img)
|
||||
canvas?.renderAll()
|
||||
setBackImg(img)
|
||||
})
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { useRef } from 'react'
|
||||
import { useRecoilValue, useSetRecoilState } from 'recoil'
|
||||
import { canvasState, canvasZoomState, currentMenuState, textModeState } from '@/store/canvasAtom'
|
||||
import { fabric } from 'fabric'
|
||||
@ -20,9 +20,15 @@ export function useEvent() {
|
||||
|
||||
const textMode = useRecoilValue(textModeState)
|
||||
|
||||
useEffect(() => {
|
||||
initEvent()
|
||||
}, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, dotLineGridSetting, tempGridMode])
|
||||
// 이벤트 초기화 위치 수정 -> useCanvasSetting에서 세팅값 불러오고 나서 초기화 함수 호출
|
||||
// useEffect(() => {
|
||||
// initEvent()
|
||||
// }, [currentMenu, canvas, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, dotLineGridSetting])
|
||||
|
||||
// 임시 그리드 모드 변경 시 이벤트 초기화 호출 위치 수정 -> GridOption 컴포넌트에서 임시 그리드 모드 변경 시 이벤트 초기화 함수 호출
|
||||
// useEffect(() => {
|
||||
// initEvent()
|
||||
// }, [tempGridMode])
|
||||
|
||||
const initEvent = () => {
|
||||
if (!canvas) {
|
||||
|
||||
@ -1,11 +1,13 @@
|
||||
import { useEffect, useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { v4 as uuidv4, validate as isValidUUID } from 'uuid'
|
||||
import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { canvasState, currentCanvasPlanState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom'
|
||||
import { useAxios } from '@/hooks/useAxios'
|
||||
import { useMessage } from '@/hooks/useMessage'
|
||||
import { useSwal } from '@/hooks/useSwal'
|
||||
import { SAVE_KEY } from '@/common/common'
|
||||
import { readImage, removeImage } from '@/lib/fileAction'
|
||||
import { useCanvas } from '@/hooks/useCanvas'
|
||||
|
||||
export function usePlan() {
|
||||
const [planNum, setPlanNum] = useState(0)
|
||||
@ -13,9 +15,9 @@ export function usePlan() {
|
||||
const [currentCanvasStatus, setCurrentCanvasStatus] = useState(null)
|
||||
|
||||
const [canvas, setCanvas] = useRecoilState(canvasState)
|
||||
|
||||
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
|
||||
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) // DB에 저장된 plan
|
||||
const [plans, setPlans] = useRecoilState(plansState) // 전체 plan (DB에 저장된 plan + 저장 안된 새로운 plan)
|
||||
const [plans, setPlans] = useRecoilState(plansState) // 전체 plan
|
||||
const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan
|
||||
const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag
|
||||
|
||||
@ -108,22 +110,22 @@ export function usePlan() {
|
||||
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus }))
|
||||
}
|
||||
}, [currentCanvasStatus])
|
||||
|
||||
/**
|
||||
* 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단
|
||||
*/
|
||||
const checkModifiedCanvasPlan = (planId) => {
|
||||
const canvasStatus = currentCanvasData()
|
||||
if (isValidUUID(planId)) {
|
||||
// 새로운 캔버스
|
||||
return JSON.parse(canvasStatus).objects.length > 0
|
||||
} else {
|
||||
// 저장된 캔버스
|
||||
// 각각 object들의 uuid 목록을 추출하여 비교
|
||||
const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects)
|
||||
const initPlanData = initCanvasPlans.find((plan) => plan.id === planId)
|
||||
const dbObjsUuids = getObjectUuids(JSON.parse(initPlanData.canvasStatus).objects)
|
||||
return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index])
|
||||
const planData = plans.find((plan) => plan.id === planId)
|
||||
if (planData.canvasStatus === '') {
|
||||
// 빈 상태로 저장된 캔버스
|
||||
return true
|
||||
}
|
||||
|
||||
// 각각 object들의 uuid 목록을 추출하여 비교
|
||||
const canvasStatus = currentCanvasData()
|
||||
const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects)
|
||||
const dbObjsUuids = getObjectUuids(JSON.parse(planData.canvasStatus).objects)
|
||||
return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index])
|
||||
}
|
||||
const getObjectUuids = (objects) => {
|
||||
return objects
|
||||
@ -140,16 +142,12 @@ export function usePlan() {
|
||||
/**
|
||||
* 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 후 저장
|
||||
*/
|
||||
const checkUnsavedCanvasPlan = async (userId) => {
|
||||
const checkUnsavedCanvasPlan = async () => {
|
||||
swalFire({
|
||||
text:
|
||||
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === currentCanvasPlan.id) ? 'New ' : '') +
|
||||
`Plan ${currentCanvasPlan.ordering}의 변경 사항을 저장하시겠습니까?`,
|
||||
text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.save.modified'),
|
||||
type: 'confirm',
|
||||
confirmFn: async () => {
|
||||
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)
|
||||
? await putCanvasStatus(currentCanvasPlan.canvasStatus)
|
||||
: await postCanvasStatus(userId, currentCanvasPlan.canvasStatus)
|
||||
await putCanvasStatus(currentCanvasPlan.canvasStatus)
|
||||
},
|
||||
})
|
||||
resetModifiedPlans()
|
||||
@ -172,18 +170,16 @@ export function usePlan() {
|
||||
/**
|
||||
* 페이지 내 캔버스를 저장
|
||||
*/
|
||||
const saveCanvas = async (userId) => {
|
||||
const saveCanvas = async () => {
|
||||
const canvasStatus = currentCanvasData('save')
|
||||
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)
|
||||
? await putCanvasStatus(canvasStatus)
|
||||
: await postCanvasStatus(userId, canvasStatus)
|
||||
await putCanvasStatus(canvasStatus)
|
||||
}
|
||||
|
||||
/**
|
||||
* objectNo에 해당하는 canvas 목록을 조회
|
||||
*/
|
||||
const getCanvasByObjectNo = async (userId, objectNo) => {
|
||||
return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
|
||||
return await get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
|
||||
res.map((item, index) => ({
|
||||
id: item.id,
|
||||
userId: item.userId,
|
||||
@ -199,28 +195,20 @@ export function usePlan() {
|
||||
/**
|
||||
* 신규 canvas 데이터를 저장
|
||||
*/
|
||||
const postCanvasStatus = async (userId, canvasStatus) => {
|
||||
const postCanvasStatus = async (userId, objectNo, canvasStatus) => {
|
||||
const planData = {
|
||||
userId: userId,
|
||||
imageName: 'image_name', // api 필수항목이여서 임시로 넣음, 이후 삭제 필요
|
||||
objectNo: currentCanvasPlan.objectNo,
|
||||
objectNo: objectNo,
|
||||
bgImageName: currentCanvasPlan?.bgImageName ?? null,
|
||||
mapPositionAddress: currentCanvasPlan?.mapPositionAddress ?? null,
|
||||
canvasStatus: canvasToDbFormat(canvasStatus),
|
||||
}
|
||||
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
|
||||
.then((res) => {
|
||||
setInitCanvasPlans((initCanvasPlans) => [...initCanvasPlans, { id: res.data, canvasStatus: canvasStatus }])
|
||||
setPlans((plans) =>
|
||||
plans.map((plan) =>
|
||||
plan.id === currentCanvasPlan.id
|
||||
? {
|
||||
...plan,
|
||||
id: res.data,
|
||||
canvasStatus: canvasStatus,
|
||||
}
|
||||
: plan,
|
||||
),
|
||||
)
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
setPlans([...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }])
|
||||
handleCurrentPlan(res.data)
|
||||
setPlanNum(planNum + 1)
|
||||
})
|
||||
.catch((error) => {
|
||||
swalFire({ text: error.message, icon: 'error' })
|
||||
@ -233,13 +221,12 @@ export function usePlan() {
|
||||
const putCanvasStatus = async (canvasStatus) => {
|
||||
const planData = {
|
||||
id: currentCanvasPlan.id,
|
||||
bgImageName: currentCanvasPlan?.bgImageName ?? null,
|
||||
mapPositionAddress: currentCanvasPlan?.mapPositionAddress ?? null,
|
||||
canvasStatus: canvasToDbFormat(canvasStatus),
|
||||
}
|
||||
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
|
||||
.then((res) => {
|
||||
setInitCanvasPlans((initCanvasPlans) =>
|
||||
initCanvasPlans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)),
|
||||
)
|
||||
setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
})
|
||||
@ -251,40 +238,30 @@ export function usePlan() {
|
||||
/**
|
||||
* id에 해당하는 canvas 데이터를 삭제
|
||||
*/
|
||||
const delCanvasById = (id) => {
|
||||
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
|
||||
const delCanvasById = async (id) => {
|
||||
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
|
||||
}
|
||||
|
||||
/**
|
||||
* objectNo에 해당하는 canvas 데이터들을 삭제
|
||||
*/
|
||||
const delCanvasByObjectNo = (objectNo) => {
|
||||
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
|
||||
const delCanvasByObjectNo = async (objectNo) => {
|
||||
return await promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
|
||||
}
|
||||
|
||||
/**
|
||||
* plan 이동
|
||||
* 현재 plan의 작업상태를 확인, 저장 후 이동
|
||||
*/
|
||||
const handleCurrentPlan = async (userId, newCurrentId) => {
|
||||
const handleCurrentPlan = async (newCurrentId) => {
|
||||
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
|
||||
if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) {
|
||||
// swalFire({
|
||||
// text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
|
||||
// type: 'confirm',
|
||||
// confirmFn: async () => {
|
||||
// await saveCanvas(userId)
|
||||
// updateCurrentPlan(newCurrentId)
|
||||
// },
|
||||
// denyFn: () => {
|
||||
// updateCurrentPlan(newCurrentId)
|
||||
// },
|
||||
// })
|
||||
await saveCanvas(userId)
|
||||
await saveCanvas()
|
||||
}
|
||||
updateCurrentPlan(newCurrentId)
|
||||
}
|
||||
}
|
||||
|
||||
const updateCurrentPlan = (newCurrentId) => {
|
||||
setPlans((plans) =>
|
||||
plans.map((plan) => {
|
||||
@ -295,29 +272,35 @@ export function usePlan() {
|
||||
useEffect(() => {
|
||||
setCurrentCanvasPlan(plans.find((plan) => plan.isCurrent) || null)
|
||||
setSelectedPlan(plans.find((plan) => plan.isCurrent))
|
||||
// setBgImage()
|
||||
}, [plans])
|
||||
|
||||
const setBgImage = () => {
|
||||
// readImage(selectedPlan?.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* 새로운 plan 생성
|
||||
* 현재 plan의 데이터가 있을 경우 복제 여부를 확인
|
||||
*/
|
||||
const handleAddPlan = (userId, objectNo) => {
|
||||
const handleAddPlan = async (userId, objectNo) => {
|
||||
JSON.parse(currentCanvasData()).objects.length > 0
|
||||
? swalFire({
|
||||
text:
|
||||
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === currentCanvasPlan.id) ? 'New ' : '') +
|
||||
`Plan ${currentCanvasPlan.ordering} ` +
|
||||
getMessage('plan.message.confirm.copy'),
|
||||
text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.copy'),
|
||||
type: 'confirm',
|
||||
confirmFn: () => {
|
||||
addPlan(userId, objectNo, currentCanvasData())
|
||||
confirmFn: async () => {
|
||||
await postCanvasStatus(userId, objectNo, currentCanvasData())
|
||||
},
|
||||
denyFn: () => {
|
||||
addPlan(userId, objectNo, '')
|
||||
denyFn: async () => {
|
||||
await postCanvasStatus(userId, objectNo, '')
|
||||
},
|
||||
})
|
||||
: addPlan(userId, objectNo, '')
|
||||
: await postCanvasStatus(userId, objectNo, '')
|
||||
}
|
||||
|
||||
/**
|
||||
* DB에 추가하지 않고 화면 상에서 plan을 추가하는 함수
|
||||
*/
|
||||
const addPlan = (userId, objectNo, canvasStatus) => {
|
||||
const id = uuidv4()
|
||||
const newPlan = {
|
||||
@ -328,32 +311,26 @@ export function usePlan() {
|
||||
ordering: planNum + 1,
|
||||
}
|
||||
setPlans([...plans, newPlan])
|
||||
handleCurrentPlan(userId, id)
|
||||
handleCurrentPlan(id)
|
||||
setPlanNum(planNum + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* plan 삭제
|
||||
*/
|
||||
const handleDeletePlan = (e, id) => {
|
||||
const handleDeletePlan = async (e, id) => {
|
||||
e.stopPropagation() // 이벤트 버블링 방지
|
||||
|
||||
if (initCanvasPlans.some((plan) => plan.id === id)) {
|
||||
delCanvasById(id)
|
||||
.then((res) => {
|
||||
setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id))
|
||||
setPlans((plans) => plans.filter((plan) => plan.id !== id))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
swalFire({ text: getMessage('plan.message.delete') })
|
||||
})
|
||||
.catch((error) => {
|
||||
swalFire({ text: error.message, icon: 'error' })
|
||||
})
|
||||
} else {
|
||||
setPlans((plans) => plans.filter((plan) => plan.id !== id))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
swalFire({ text: getMessage('plan.message.delete') })
|
||||
}
|
||||
await delCanvasById(id)
|
||||
.then((res) => {
|
||||
setPlans((plans) => plans.filter((plan) => plan.id !== id))
|
||||
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
|
||||
removeImage(currentCanvasPlan.id)
|
||||
swalFire({ text: getMessage('plan.message.delete') })
|
||||
})
|
||||
.catch((error) => {
|
||||
swalFire({ text: error.message, icon: 'error' })
|
||||
})
|
||||
|
||||
// 삭제 후 last 데이터에 포커싱
|
||||
const lastPlan = plans.filter((plan) => plan.id !== id).at(-1)
|
||||
@ -368,16 +345,15 @@ export function usePlan() {
|
||||
/**
|
||||
* plan 조회
|
||||
*/
|
||||
const loadCanvasPlanData = (userId, objectNo, pid) => {
|
||||
getCanvasByObjectNo(userId, objectNo).then((res) => {
|
||||
const loadCanvasPlanData = async (userId, objectNo, pid) => {
|
||||
await getCanvasByObjectNo(userId, objectNo).then((res) => {
|
||||
// console.log('canvas 목록 ', res)
|
||||
if (res.length > 0) {
|
||||
setInitCanvasPlans(res)
|
||||
setPlans(res)
|
||||
updateCurrentPlan(res[pid - 1].id)
|
||||
setPlanNum(res.length)
|
||||
} else {
|
||||
addPlan(userId, objectNo, '')
|
||||
postCanvasStatus(userId, objectNo, '')
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -385,9 +361,9 @@ export function usePlan() {
|
||||
return {
|
||||
canvas,
|
||||
plans,
|
||||
initCanvasPlans,
|
||||
selectedPlan,
|
||||
currentCanvasPlan,
|
||||
setCurrentCanvasPlan,
|
||||
modifiedPlans,
|
||||
modifiedPlanFlag,
|
||||
setModifiedPlanFlag,
|
||||
|
||||
@ -4,6 +4,7 @@ import fs from 'fs/promises'
|
||||
|
||||
const CAD_FILE_PATH = 'public/cad-images'
|
||||
const IMAGE_FILE_PATH = 'public/plan-bg-images'
|
||||
const FILE_PATH = 'public/plan-images'
|
||||
|
||||
/**
|
||||
* 파일 변환 & 저장
|
||||
@ -39,25 +40,56 @@ const writeImageBase64 = async (title, data) => {
|
||||
return fs.writeFile(`${IMAGE_FILE_PATH}/${title}.png`, data, 'base64')
|
||||
}
|
||||
|
||||
/**
|
||||
* 이미지 저장
|
||||
* Buffer 형식으로 저장
|
||||
* @param {*} title
|
||||
* @param {*} data
|
||||
* @returns
|
||||
*/
|
||||
const writeImageBuffer = async (file) => {
|
||||
// 해당 경로에 Directory 가 없다면 생성
|
||||
// /**
|
||||
// * 이미지 저장
|
||||
// * Buffer 형식으로 저장
|
||||
// * @param {*} title
|
||||
// * @param {*} data
|
||||
// * @returns
|
||||
// */
|
||||
// const writeImageBuffer = async (file) => {
|
||||
// // 해당 경로에 Directory 가 없다면 생성
|
||||
// try {
|
||||
// await fs.readdir(IMAGE_FILE_PATH)
|
||||
// } catch {
|
||||
// await fs.mkdir(IMAGE_FILE_PATH)
|
||||
// }
|
||||
//
|
||||
// const arrayBuffer = await fileURLToPath.arrayBuffer()
|
||||
// const buffer = new Uint8Array(arrayBuffer)
|
||||
//
|
||||
// return fs.writeFile(`${IMAGE_FILE_PATH}/${file.fileName}`, buffer)
|
||||
// }
|
||||
|
||||
const writeImage = async (fileName, file) => {
|
||||
try {
|
||||
await fs.readdir(IMAGE_FILE_PATH)
|
||||
await fs.readdir(FILE_PATH)
|
||||
} catch {
|
||||
await fs.mkdir(IMAGE_FILE_PATH)
|
||||
await fs.mkdir(FILE_PATH)
|
||||
}
|
||||
|
||||
const arrayBuffer = await fileURLToPath.arrayBuffer()
|
||||
const buffer = new Uint8Array(arrayBuffer)
|
||||
|
||||
return fs.writeFile(`${IMAGE_FILE_PATH}/${file.fileName}`, buffer)
|
||||
return fs.writeFile(`${FILE_PATH}/${fileName}.png`, file)
|
||||
}
|
||||
|
||||
export { convertDwgToPng, writeImageBase64, writeImageBuffer }
|
||||
const readImage = async (fileName) => {
|
||||
const file = await fs.readFile(`${FILE_PATH}/${fileName}`)
|
||||
// .then((res) => {
|
||||
// console.log('readImage-then', res)
|
||||
// })
|
||||
// .catch((e) => {
|
||||
// console.log('readImage-catch', e)
|
||||
// })
|
||||
console.log('🚀 ~ readImage ~ file:', file)
|
||||
|
||||
return file
|
||||
}
|
||||
|
||||
const removeImage = async (fileName) => {
|
||||
try {
|
||||
await fs.rm(`${FILE_PATH}/${fileName}.png`)
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
|
||||
export { convertDwgToPng, writeImageBase64, writeImage, readImage, removeImage }
|
||||
|
||||
@ -3,8 +3,8 @@ export const defaultSession = {}
|
||||
export const sessionOptions = {
|
||||
password: process.env.SESSION_SECRET,
|
||||
cookieName: 'lama-session',
|
||||
cookieOptions: {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
// cookieOptions: {
|
||||
// httpOnly: true,
|
||||
// secure: process.env.NODE_ENV === 'production',
|
||||
// },
|
||||
}
|
||||
|
||||
@ -164,6 +164,7 @@
|
||||
"plan.menu.estimate.save": "保存",
|
||||
"plan.menu.estimate.reset": "初期化",
|
||||
"plan.menu.estimate.copy": "見積書のコピー",
|
||||
"plan.menu.estimate.unLock": "ロック解除",
|
||||
"plan.menu.simulation": "発展シミュレーション",
|
||||
"plan.menu.simulation.excel": "Excel",
|
||||
"plan.menu.simulation.pdf": "PDF",
|
||||
@ -294,6 +295,7 @@
|
||||
"modal.actual.size.setting.plane.size.length": "廊下の寸法の長さ",
|
||||
"modal.actual.size.setting.actual.size.length": "実寸長",
|
||||
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
|
||||
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
|
||||
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
|
||||
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
|
||||
"plan.message.save": "저장되었습니다.",
|
||||
@ -341,6 +343,7 @@
|
||||
"modal.panel.column.insert.info": "挿入する方向を選択してください。",
|
||||
"modal.panel.column.insert.type.left": "左挿入",
|
||||
"modal.panel.column.insert.type.right": "右挿入",
|
||||
"modal.image.load.size.rotate": "サイズ調整と回転",
|
||||
"contextmenu.column.insert": "列の挿入",
|
||||
"contextmenu.row.move": "단 이동(JA)",
|
||||
"contextmenu.row.copy": "단 복사(JA)",
|
||||
@ -483,9 +486,13 @@
|
||||
"common.message.writeToConfirm": "作成解除を実行しますか?",
|
||||
"common.message.password.init.success": "パスワード [{0}] に初期化されました。",
|
||||
"common.message.no.edit.save": "この文書は変更できません。",
|
||||
"common.load": "ファイルの追加",
|
||||
"common.input.file": "ファイルを読み込む",
|
||||
"common.input.file.load": "ファイルの追加",
|
||||
"common.input.image.load": "이미지 불러오기",
|
||||
"common.input.address.load": "アドレスを読み込む",
|
||||
"common.require": "必須",
|
||||
"common.finish": "完了",
|
||||
"common.ok": "確認",
|
||||
"commons.west": "立つ",
|
||||
"commons.east": "ドン",
|
||||
@ -835,6 +842,7 @@
|
||||
"estimate.detail.fileList.btn": "ファイル選択",
|
||||
"estimate.detail.fileList.extCheck": "そのファイルはイメージファイルではありません",
|
||||
"estimate.detail.header.fileList2": "添付ファイル一覧",
|
||||
"estimate.detail.fileList2.btn.return": "復元",
|
||||
"estimate.detail.header.specialEstimate": "見積もりの具体的な",
|
||||
"estimate.detail.header.specialEstimateProductInfo": "製品情報",
|
||||
"estimate.detail.sepcialEstimateProductInfo.totAmount": "数量 (PCS)",
|
||||
@ -897,10 +905,14 @@
|
||||
"estimate.detail.save.requiredItem": "製品は1つ以上登録する必要があります.",
|
||||
"estimate.detail.save.requiredCharger": "担当者は必須です.",
|
||||
"estimate.detail.save.requiredObjectName": "案件名は必須です.",
|
||||
"estimate.detail.save.requiredPkgAsp": "住宅pkg単価は0より大きい値を入力してください.",
|
||||
"estimate.detail.save.requiredEstimateDate": "見積日は必須です.",
|
||||
"estimate.detail.save.requiredItemId": "製品を選択してください.",
|
||||
"estimate.detail.save.requiredAmount": "数量は0より大きい値を入力してください.",
|
||||
"estimate.detail.save.requiredSalePrice": "単価は0より大きい値を入力してください.",
|
||||
"estimate.detail.reset.confirmMsg": "保存した見積書情報が初期化され、図面情報が反映されます。本当に初期化しますか?",
|
||||
"estimate.detail.alert.delFile": "添付ファイルを完全に削除するには[保存]ボタンをクリックしてください",
|
||||
"estimate.detail.alert.selectDelItem": "削除する商品を選択してください.",
|
||||
"simulator.title.sub1": "物件番号",
|
||||
"simulator.title.sub2": "作成日",
|
||||
"simulator.title.sub3": "システム容量",
|
||||
|
||||
@ -168,6 +168,7 @@
|
||||
"plan.menu.estimate.save": "저장",
|
||||
"plan.menu.estimate.reset": "초기화",
|
||||
"plan.menu.estimate.copy": "견적서 복사",
|
||||
"plan.menu.estimate.unLock": "잠금 해제",
|
||||
"plan.menu.simulation": "발전 시뮬레이션",
|
||||
"plan.menu.simulation.excel": "Excel",
|
||||
"plan.menu.simulation.pdf": "PDF",
|
||||
@ -299,6 +300,7 @@
|
||||
"modal.actual.size.setting.plane.size.length": "복도치수 길이",
|
||||
"modal.actual.size.setting.actual.size.length": "실제치수 길이",
|
||||
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
|
||||
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
|
||||
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
|
||||
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
|
||||
"plan.message.save": "저장되었습니다.",
|
||||
@ -348,6 +350,7 @@
|
||||
"modal.panel.column.insert.info": "삽입할 방향을 선택해주세요.",
|
||||
"modal.panel.column.insert.type.left": "왼쪽 삽입",
|
||||
"modal.panel.column.insert.type.right": "오른쪽 삽입",
|
||||
"modal.image.load.size.rotate": "크기 조절 및 회전",
|
||||
"contextmenu.row.move": "단 이동",
|
||||
"contextmenu.row.copy": "단 복사",
|
||||
"contextmenu.row.remove": "단 삭제",
|
||||
@ -492,9 +495,13 @@
|
||||
"common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?",
|
||||
"common.message.password.init.success": "비밀번호 [{0}]로 초기화 되었습니다.",
|
||||
"common.message.no.edit.save": "This document cannot be changed.",
|
||||
"common.load": "불러오기",
|
||||
"common.input.file": "파일 불러오기",
|
||||
"common.input.file.load": "불러오기",
|
||||
"common.input.image.load": "이미지 불러오기",
|
||||
"common.input.address.load": "주소 불러오기",
|
||||
"common.require": "필수",
|
||||
"common.finish": "완료",
|
||||
"common.ok": "확인",
|
||||
"commons.west": "서",
|
||||
"commons.east": "동",
|
||||
@ -845,6 +852,7 @@
|
||||
"estimate.detail.fileList.btn": "파일선택",
|
||||
"estimate.detail.fileList.extCheck": "해당 파일은 이미지 파일이 아닙니다",
|
||||
"estimate.detail.header.fileList2": "첨부파일 목록",
|
||||
"estimate.detail.fileList2.btn.return": "복원",
|
||||
"estimate.detail.header.specialEstimate": "견적특이사항",
|
||||
"estimate.detail.header.specialEstimateProductInfo": "제품정보",
|
||||
"estimate.detail.sepcialEstimateProductInfo.totAmount": "수량 (PCS)",
|
||||
@ -907,10 +915,14 @@
|
||||
"estimate.detail.save.requiredItem": "제품은 1개이상 등록해야 됩니다.",
|
||||
"estimate.detail.save.requiredCharger": "담당자는 필수값 입니다.",
|
||||
"estimate.detail.save.requiredObjectName": "안건명은 필수값 입니다.",
|
||||
"estimate.detail.save.requiredPkgAsp": "주택pkg 단가는 0보다 큰 값을 입력하세요.",
|
||||
"estimate.detail.save.requiredEstimateDate": "견적일은 필수값 입니다.",
|
||||
"estimate.detail.save.requiredItemId": "제품을 선택해주세요.",
|
||||
"estimate.detail.save.requiredAmount": "수량은 0보다 큰값을 입력해주세요.",
|
||||
"estimate.detail.save.requiredSalePrice": "단가는 0보다 큰값을 입력해주세요.",
|
||||
"estimate.detail.reset.confirmMsg": "저장된 견적서 정보가 초기화되고, 도면정보가 반영됩니다. 정말로 초기화 하시겠습니까?",
|
||||
"estimate.detail.alert.delFile": "첨부파일을 완전히 삭제하려면 [저장]버튼을 클릭하십시오.",
|
||||
"estimate.detail.alert.selectDelItem": "삭제할 제품을 선택하세요.",
|
||||
"simulator.title.sub1": "물건번호",
|
||||
"simulator.title.sub2": "작성일",
|
||||
"simulator.title.sub3": "시스템 용량",
|
||||
|
||||
@ -260,12 +260,6 @@ export const dotLineIntervalSelector = selector({
|
||||
},
|
||||
})
|
||||
|
||||
// canvas plan 초기 목록
|
||||
export const initCanvasPlansState = atom({
|
||||
key: 'initCanvasPlans',
|
||||
default: [],
|
||||
})
|
||||
|
||||
// 현재 canvas plan
|
||||
export const currentCanvasPlanState = atom({
|
||||
key: 'currentCanvasPlan',
|
||||
|
||||
@ -1,8 +1,7 @@
|
||||
import { atom } from 'recoil'
|
||||
import dayjs from 'dayjs'
|
||||
import { v1 } from 'uuid'
|
||||
export const stuffSearchState = atom({
|
||||
key: `stuffSearchState/${v1()}`,
|
||||
key: `stuffSearchState`,
|
||||
default: {
|
||||
schObjectNo: '', //물건번호
|
||||
schAddress: '', //물건주소
|
||||
|
||||
@ -139,6 +139,7 @@
|
||||
&.ico02{background-image: url(../../public/static/images/canvas/ico-flx02.svg);}
|
||||
&.ico03{background-image: url(../../public/static/images/canvas/ico-flx03.svg);}
|
||||
&.ico04{background-image: url(../../public/static/images/canvas/ico-flx04.svg);}
|
||||
&.ico05{background-image: url(../../public/static/images/canvas/ico-flx05.svg);}
|
||||
}
|
||||
.name{
|
||||
font-size: 12px;
|
||||
@ -720,6 +721,7 @@
|
||||
&.one{
|
||||
.estimate-box{
|
||||
&:last-child{
|
||||
flex: 1;
|
||||
min-width: unset;
|
||||
}
|
||||
}
|
||||
@ -803,6 +805,7 @@
|
||||
}
|
||||
}
|
||||
.file-list{
|
||||
min-height: 52px;
|
||||
.file-item{
|
||||
margin-bottom: 15px;
|
||||
span{
|
||||
@ -827,6 +830,47 @@
|
||||
&:last-child{
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.file-item-wrap{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 30px;
|
||||
.return-wrap{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
.return{
|
||||
padding: 0;
|
||||
font-size: 13px;
|
||||
color: #B0BCCD;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
.return-btn{
|
||||
flex: none;
|
||||
position: relative;
|
||||
top: 0;
|
||||
left: 0;
|
||||
transform: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
height: 24px;
|
||||
padding: 0 9px;
|
||||
margin-left: 10px;
|
||||
background: none;
|
||||
border: 1px solid #B0BCCD;
|
||||
border-radius: 2px;
|
||||
font-size: 12px;
|
||||
color: #B0BCCD;
|
||||
font-weight: 500;
|
||||
.return-ico{
|
||||
display: block;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
background: url(../../public/static/images/canvas/return-btn.svg)no-repeat center;
|
||||
background-size: contain;
|
||||
margin-right: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -877,6 +921,16 @@
|
||||
&.act{
|
||||
background-color: #F7F9FA;
|
||||
}
|
||||
.special-note-check-box{
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.check-name{
|
||||
font-size: 13px;
|
||||
color: #45576F;
|
||||
cursor: pointer;
|
||||
line-height: 1.3;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -884,7 +938,7 @@
|
||||
border: 1px solid #ECF0F4;
|
||||
border-radius: 3px;
|
||||
padding: 24px;
|
||||
max-height: 350px;
|
||||
height: 350px;
|
||||
overflow-y: auto;
|
||||
margin-bottom: 30px;
|
||||
dl{
|
||||
|
||||
@ -1308,23 +1308,23 @@ $alert-color: #101010;
|
||||
height: 253px;
|
||||
.circle{
|
||||
top: 86%;
|
||||
&:nth-child(1),
|
||||
&:nth-child(7),
|
||||
&:nth-child(13),
|
||||
&:nth-child(19){
|
||||
&::before{
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 20px;
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
width: 1px;
|
||||
height: 6px;
|
||||
background-color: #8B8B8B;
|
||||
}
|
||||
}
|
||||
// &:nth-child(1),
|
||||
// &:nth-child(7),
|
||||
// &:nth-child(13),
|
||||
// &:nth-child(19){
|
||||
// &::before{
|
||||
// content: '';
|
||||
// position: absolute;
|
||||
// top: 20px;
|
||||
// left: 50%;
|
||||
// transform: translateX(-50%);
|
||||
// width: 1px;
|
||||
// height: 6px;
|
||||
// background-color: #8B8B8B;
|
||||
// }
|
||||
// }
|
||||
i{
|
||||
top: 32px;
|
||||
top: 22px;
|
||||
}
|
||||
&.act{
|
||||
i{color: #8B8B8B;}
|
||||
|
||||
@ -1,109 +1,45 @@
|
||||
.spinner-wrap {
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
.loader {
|
||||
font-size: 10px;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
text-indent: -9999em;
|
||||
animation: mulShdSpin 1.1s infinite ease;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
@keyframes mulShdSpin {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em #101010,
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.5),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.7);
|
||||
.spinner-wrap{
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: #fff;
|
||||
.loader {
|
||||
font-size: 10px;
|
||||
width: 1.2em;
|
||||
height: 1.2em;
|
||||
border-radius: 50%;
|
||||
position: relative;
|
||||
text-indent: -9999em;
|
||||
animation: mulShdSpin 1.1s infinite ease;
|
||||
transform: translateZ(0);
|
||||
}
|
||||
12.5% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.7),
|
||||
1.8em -1.8em 0 0em #101010,
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.5);
|
||||
}
|
||||
25% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.5),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.7),
|
||||
2.5em 0em 0 0em #101010,
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
37.5% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.2),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.5),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.7),
|
||||
1.75em 1.75em 0 0em #101010,
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
50% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.2),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.5),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.7),
|
||||
0em 2.5em 0 0em #101010,
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
62.5% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.2),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.5),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.7),
|
||||
-1.8em 1.8em 0 0em #101010,
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
75% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.2),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.5),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.7),
|
||||
-2.6em 0em 0 0em #101010,
|
||||
-1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
87.5% {
|
||||
box-shadow:
|
||||
0em -2.6em 0em 0em rgba(16, 16, 16, 0.2),
|
||||
1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2),
|
||||
2.5em 0em 0 0em rgba(16, 16, 16, 0.2),
|
||||
1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2),
|
||||
0em 2.5em 0 0em rgba(16, 16, 16, 0.2),
|
||||
-1.8em 1.8em 0 0em rgba(16, 16, 16, 0.5),
|
||||
-2.6em 0em 0 0em rgba(16, 16, 16, 0.7),
|
||||
-1.8em -1.8em 0 0em #101010;
|
||||
}
|
||||
}
|
||||
}
|
||||
@keyframes mulShdSpin {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: 0em -2.6em 0em 0em #101010, 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2), 2.5em 0em 0 0em rgba(16, 16, 16, 0.2), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2), 0em 2.5em 0 0em rgba(16, 16, 16, 0.2), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2), -2.6em 0em 0 0em rgba(16, 16, 16, 0.5), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.7);
|
||||
}
|
||||
12.5% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.7), 1.8em -1.8em 0 0em #101010, 2.5em 0em 0 0em rgba(16, 16, 16, 0.2), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2), 0em 2.5em 0 0em rgba(16, 16, 16, 0.2), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2), -2.6em 0em 0 0em rgba(16, 16, 16, 0.2), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.5);
|
||||
}
|
||||
25% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.5), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.7), 2.5em 0em 0 0em #101010, 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2), 0em 2.5em 0 0em rgba(16, 16, 16, 0.2), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2), -2.6em 0em 0 0em rgba(16, 16, 16, 0.2), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
37.5% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.2), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.5), 2.5em 0em 0 0em rgba(16, 16, 16, 0.7), 1.75em 1.75em 0 0em #101010, 0em 2.5em 0 0em rgba(16, 16, 16, 0.2), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2), -2.6em 0em 0 0em rgba(16, 16, 16, 0.2), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
50% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.2), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2), 2.5em 0em 0 0em rgba(16, 16, 16, 0.5), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.7), 0em 2.5em 0 0em #101010, -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.2), -2.6em 0em 0 0em rgba(16, 16, 16, 0.2), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
62.5% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.2), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2), 2.5em 0em 0 0em rgba(16, 16, 16, 0.2), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.5), 0em 2.5em 0 0em rgba(16, 16, 16, 0.7), -1.8em 1.8em 0 0em #101010, -2.6em 0em 0 0em rgba(16, 16, 16, 0.2), -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
75% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.2), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2), 2.5em 0em 0 0em rgba(16, 16, 16, 0.2), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2), 0em 2.5em 0 0em rgba(16, 16, 16, 0.5), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.7), -2.6em 0em 0 0em #101010, -1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2);
|
||||
}
|
||||
87.5% {
|
||||
box-shadow: 0em -2.6em 0em 0em rgba(16, 16, 16, 0.2), 1.8em -1.8em 0 0em rgba(16, 16, 16, 0.2), 2.5em 0em 0 0em rgba(16, 16, 16, 0.2), 1.75em 1.75em 0 0em rgba(16, 16, 16, 0.2), 0em 2.5em 0 0em rgba(16, 16, 16, 0.2), -1.8em 1.8em 0 0em rgba(16, 16, 16, 0.5), -2.6em 0em 0 0em rgba(16, 16, 16, 0.7), -1.8em -1.8em 0 0em #101010;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -824,6 +824,8 @@ export function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode
|
||||
ctx.strokeStyle = 'black'
|
||||
ctx.lineWidth = 0.2
|
||||
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
|
||||
} else {
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
|
||||
}
|
||||
|
||||
if (polygon.direction === 'east' || polygon.direction === 'west') {
|
||||
|
||||
@ -93,3 +93,27 @@ export const inputNumberCheck = (e) => {
|
||||
input.value = input.value.replace(/[^\d]/g, '')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 파이프함수 정의
|
||||
* @param {...any} fns 순수함수들
|
||||
* @returns
|
||||
*/
|
||||
export const pipe =
|
||||
(...fns) =>
|
||||
(x) =>
|
||||
fns.reduce((v, f) => f(v), x)
|
||||
|
||||
/**
|
||||
* 캔버스 각도에 따른 흐름 방향 계산
|
||||
* @param {number} canvasAngle
|
||||
* @returns {object} 흐름 방향 객체
|
||||
*/
|
||||
export const calculateFlowDirection = (canvasAngle) => {
|
||||
return {
|
||||
down: -canvasAngle,
|
||||
up: 180 - canvasAngle,
|
||||
left: 90 - canvasAngle < 180 ? 90 - canvasAngle : 90 - canvasAngle - 360,
|
||||
right: -90 - canvasAngle < -180 ? -90 - canvasAngle + 360 : -90 - canvasAngle,
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user