Merge branch 'dev'

This commit is contained in:
yoosangwook 2024-10-18 17:16:28 +09:00
commit dfde512b6f
52 changed files with 4639 additions and 3386 deletions

12
.env
View File

@ -1,12 +0,0 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
# DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority"
#DATABASE_URL = "mongodb%2Bsrv%3A%2F%2Fyoo32767%3AGuCtswjLGqUaNL0G%40cluster0.vsdtcnb.mongodb.net%2F%3FretryWrites%3Dtrue%26w%3Dmajority%26appName%3DCluster0"
# DATABASE_URL = "mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/Cluster0?retryWrites=true&w=majority"
# DATABASE_URL="mongodb://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/sample_mflix?retryWrites=true&w=majority"
DATABASE_URL="mongodb+srv://yoo32767:GuCtswjLGqUaNL0G@cluster0.vsdtcnb.mongodb.net/mytest"

View File

@ -1,14 +1,8 @@
NEXT_PUBLIC_TEST="테스트변수입니다. development"
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
# NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080"
# NEXT_PUBLIC_API_SERVER_PATH="http://172.30.1.60:8080"
DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-local.q-cells.jp:8120/eos/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-qa.q-cells.jp:8120/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-local.q-cells.jp:8120/qm/login/autoLogin" NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-qa.q-cells.jp:8120/qm/login/autoLogin"

View File

@ -1,12 +1,8 @@
NEXT_PUBLIC_TEST="테스트변수입니다. production"
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
DATABASE_URL=""
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-local.q-cells.jp:8120/eos/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-local.q-cells.jp:8120/qm/login/autoLogin" NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin"

View File

@ -44,7 +44,6 @@
"prettier": "^3.3.3", "prettier": "^3.3.3",
"prisma": "^5.18.0", "prisma": "^5.18.0",
"react-color-palette": "^7.2.2", "react-color-palette": "^7.2.2",
"react-dropdown-select": "^4.11.3",
"react-select": "^5.8.1", "react-select": "^5.8.1",
"sass": "^1.77.8", "sass": "^1.77.8",
"tailwindcss": "^3.4.1" "tailwindcss": "^3.4.1"

View File

@ -0,0 +1,4 @@
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.998535 1L3.99723 3.99594L6.99593 1" stroke="#697C8F" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M7 6.98376L3.99319 3.99595L1.00263 6.99999" stroke="#697C8F" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 370 B

View File

@ -0,0 +1,12 @@
'use client'
import { createContext, useState } from 'react'
export const SessionContext = createContext({
session: {},
})
export default function SessionProvider({ useSession, children }) {
const [session, setSession] = useState(useSession)
return <SessionContext.Provider value={{ session }}>{children}</SessionContext.Provider>
}

View File

@ -15,6 +15,7 @@ import './globals.css'
import '../styles/style.scss' import '../styles/style.scss'
import '../styles/contents.scss' import '../styles/contents.scss'
import Dimmed from '@/components/ui/Dimmed' import Dimmed from '@/components/ui/Dimmed'
import SessionProvider from './SessionProvider'
// const inter = Inter({ subsets: ['latin'] }) // const inter = Inter({ subsets: ['latin'] })
@ -70,7 +71,9 @@ export default async function RootLayout({ children }) {
<Header userSession={sessionProps} /> <Header userSession={sessionProps} />
<div className="content"> <div className="content">
<Dimmed /> <Dimmed />
<QcastProvider>{children}</QcastProvider> <QcastProvider>
<SessionProvider useSession={sessionProps}>{children}</SessionProvider>
</QcastProvider>
</div> </div>
<footer> <footer>
<div className="footer-inner"> <div className="footer-inner">

View File

@ -66,8 +66,13 @@ export const LINE_TYPE = {
}, },
SUBLINE: { SUBLINE: {
/** /**
* * 추녀 / 마루 / 박공 / 지붕골 / 박공단
*/ */
HIP: 'hip',
RIDGE: 'ridge',
GABLE: 'gable',
VALLEY: 'valley',
VERGE: 'verge',
}, },
} }

View File

@ -30,7 +30,7 @@ export default function Playground() {
const fileRef = useRef(null) const fileRef = useRef(null)
const queryRef = useRef(null) const queryRef = useRef(null)
const [zoom, setZoom] = useState(20) const [zoom, setZoom] = useState(20)
const { get, promisePost } = useAxios() const { get, promiseGet, promisePost } = useAxios()
const testVar = process.env.NEXT_PUBLIC_TEST const testVar = process.env.NEXT_PUBLIC_TEST
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -43,6 +43,8 @@ export default function Playground() {
const [checkboxInput, setCheckboxInput] = useState([]) const [checkboxInput, setCheckboxInput] = useState([])
const [selectedValue, setSelectedValue] = useState('') const [selectedValue, setSelectedValue] = useState('')
const [users, setUsers] = useState([])
useEffect(() => { useEffect(() => {
console.log('textInput:', textInput) console.log('textInput:', textInput)
}, [textInput]) }, [textInput])
@ -142,6 +144,10 @@ export default function Playground() {
}, },
} }
useEffect(() => {
console.log('users:', users)
}, [users])
return ( return (
<> <>
<div className="container mx-auto p-4 m-4 border"> <div className="container mx-auto p-4 m-4 border">
@ -305,6 +311,32 @@ export default function Playground() {
<div className="my-2"> <div className="my-2">
<QPagination {...paginationProps} /> <QPagination {...paginationProps} />
</div> </div>
<div className="my-2">
<Button
onClick={() => {
promiseGet({ url: 'http://localhost:8080/api/user' }).then((res) => setUsers(res.data))
}}
>
axios get test
</Button>
</div>
<div className="my-2">
<Button
onClick={() => {
const result = promisePost({
url: 'http://localhost:8080/api/user',
data: {
firstName: 'Yoo',
lastName: 'Sangwook',
email: 'yoo1757@naver.com',
age: 46,
},
}).then((res) => console.log('res', res))
}}
>
axios post test
</Button>
</div>
</div> </div>
</> </>
) )

View File

@ -27,7 +27,7 @@ export default function QContextMenu(props) {
const handleContextMenu = (e) => { const handleContextMenu = (e) => {
// e.preventDefault() // contextmenu // e.preventDefault() // contextmenu
setContextMenu({ visible: true, x: e.pageX, y: e.pageY }) setContextMenu({ visible: true, x: e.pageX, y: e.pageY })
console.log(111, canvasProps) // console.log(111, canvasProps)
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) // canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
} }

View File

@ -61,7 +61,7 @@ export default function Archive() {
<div className="sub-content"> <div className="sub-content">
<div className="sub-content-inner"> <div className="sub-content-inner">
<div className="sub-table-box"> <div className="sub-table-box">
<Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={true} /> <Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={false} />
<ArchiveTable clsCode={boardType.clsCode} /> <ArchiveTable clsCode={boardType.clsCode} />
</div> </div>
</div> </div>

View File

@ -45,7 +45,7 @@ export default function ArchiveTable({ clsCode }) {
} }
fetchData() fetchData()
}, [search.searchValue]) }, [search.searchValue, search.searchFlag])
// //
const handleDetailFileListDown = async (noticeNo) => { const handleDetailFileListDown = async (noticeNo) => {
@ -74,6 +74,7 @@ export default function ArchiveTable({ clsCode }) {
return ( return (
<> <>
{boardList.length > 0 ? (
<div className="file-down-list"> <div className="file-down-list">
{boardList?.map((board) => ( {boardList?.map((board) => (
<div key={board.noticeNo} className="file-down-item"> <div key={board.noticeNo} className="file-down-item">
@ -98,6 +99,9 @@ export default function ArchiveTable({ clsCode }) {
</div> </div>
))} ))}
</div> </div>
) : (
<div className="file-down-nodata">{getMessage('common.message.no.data')}</div>
)}
</> </>
) )
} }

View File

@ -75,7 +75,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
const y2 = this.top + this.height * scaleY const y2 = this.top + this.height * scaleY
const dx = x2 - x1 const dx = x2 - x1
const dy = y2 - y1 const dy = y2 - y1
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1))
}, },
addLengthText() { addLengthText() {
@ -150,7 +150,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
getLength() { getLength() {
//10배 곱해진 값 return //10배 곱해진 값 return
return Number(this.length.toFixed(1) * 10) return Number(this.length.toFixed(0) * 10)
}, },
setViewLengthText(bool) { setViewLengthText(bool) {

View File

@ -199,32 +199,16 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const end = points[(i + 1) % points.length] const end = points[(i + 1) % points.length]
const dx = end.x - start.x const dx = end.x - start.x
const dy = end.y - start.y const dy = end.y - start.y
const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10 const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) * 10
let midPoint let midPoint
switch (this.direction) {
case 'north':
midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2 - 30)
break
case 'west':
midPoint = new fabric.Point((start.x + end.x) / 2 - 30, (start.y + end.y) / 2)
break
case 'south':
midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2 + 30)
break
case 'east':
midPoint = new fabric.Point((start.x + end.x) / 2 + 30, (start.y + end.y) / 2)
break
default:
midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2) midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
break
}
const degree = (Math.atan2(dy, dx) * 180) / Math.PI const degree = (Math.atan2(dy, dx) * 180) / Math.PI
// Create new text object if it doesn't exist // Create new text object if it doesn't exist
const text = new fabric.Text(length.toFixed(0), { const text = new fabric.Text(length.toString(), {
left: midPoint.x, left: midPoint.x,
top: midPoint.y, top: midPoint.y,
fontSize: this.fontSize, fontSize: this.fontSize,

View File

@ -13,11 +13,7 @@ export default function CanvasFrame({ plan }) {
const canvasRef = useRef(null) const canvasRef = useRef(null)
const { canvas } = useCanvas('canvas') const { canvas } = useCanvas('canvas')
const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu() const { contextMenu, currentContextMenu, setCurrentContextMenu } = useContextMenu()
const currentObject = useRecoilValue(currentObjectState)
useEffect(() => {
console.log(currentObject)
}, [currentObject])
useEvent() useEvent()
const loadCanvas = () => { const loadCanvas = () => {

View File

@ -1,122 +1,29 @@
'use client' 'use client'
import { useEffect, useState } from 'react' import { useContext, useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import CanvasFrame from './CanvasFrame' import CanvasFrame from './CanvasFrame'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { currentCanvasPlanState, initCanvasPlansState, plansState } from '@/store/canvasAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { SessionContext } from '@/app/SessionProvider'
export default function CanvasLayout() { export default function CanvasLayout() {
const { session } = useContext(SessionContext)
console.log('session >>> ', session)
const [objectNo, setObjectNo] = useState('test123240822001') // const [objectNo, setObjectNo] = useState('test123240822001') //
const [planNum, setPlanNum] = useState(0)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState)
const [plans, setPlans] = useRecoilState(plansState)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { getCanvasByObjectNo, delCanvasById, checkModifiedCanvasPlan, saveCanvas, currentCanvasData } = usePlan() const { plans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
const handleCurrentPlan = (newCurrentId) => {
// console.log('currentPlan newCurrentId: ', newCurrentId)
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
if (currentCanvasPlan?.id && checkModifiedCanvasPlan()) {
swalFire({
html: getMessage('common.message.confirm.save') + `</br>${currentCanvasPlan.name}`,
type: 'confirm',
confirmFn: async () => {
await saveCanvas(sessionState.userId)
updateCurrentPlan(newCurrentId)
},
denyFn: () => {
updateCurrentPlan(newCurrentId)
},
})
} else {
updateCurrentPlan(newCurrentId)
}
}
}
const updateCurrentPlan = (newCurrentId) => {
setPlans((plans) =>
plans.map((plan) => {
return { ...plan, isCurrent: plan.id === newCurrentId }
}),
)
}
useEffect(() => {
setCurrentCanvasPlan(plans.find((plan) => plan.isCurrent) || null)
}, [plans])
const handleDeletePlan = (e, id) => {
e.stopPropagation() //
if (initCanvasPlans.some((plan) => plan.id === id)) {
delCanvasById(id)
.then((res) => {
swalFire({ text: getMessage('common.message.delete') })
// console.log('[DELETE] canvas-statuses res :::::::: %o', res)
setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id))
setPlans((plans) => plans.filter((plan) => plan.id !== id))
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
// console.error('[DELETE] canvas-statuses res error :::::::: %o', error)
})
} else {
setPlans((plans) => plans.filter((plan) => plan.id !== id))
swalFire({ text: getMessage('common.message.delete') })
}
// last
const lastPlan = plans.filter((plan) => plan.id !== id).at(-1)
if (!lastPlan) {
setPlanNum(0)
setCurrentCanvasPlan(null)
} else if (id !== lastPlan.id) {
handleCurrentPlan(lastPlan.id)
}
}
const addEmptyPlan = () => {
setPlans([...plans, { id: planNum, name: `Plan ${planNum + 1}`, objectNo: `${objectNo}` }])
handleCurrentPlan(planNum)
setPlanNum(planNum + 1)
}
const addCopyPlan = () => {
const copyPlan = {
id: planNum,
name: `Plan ${planNum + 1}`,
objectNo: `${objectNo}`,
userId: sessionState.userId,
canvasStatus: currentCanvasData(),
}
setPlans((plans) => [...plans, copyPlan])
handleCurrentPlan(planNum)
setPlanNum(planNum + 1)
}
useEffect(() => { useEffect(() => {
if (!currentCanvasPlan) { console.log('loadCanvasPlanData 실행, sessionState.userId >>> ', sessionState.userId)
getCanvasByObjectNo(sessionState.userId, objectNo).then((res) => { loadCanvasPlanData(sessionState.userId, objectNo)
// console.log('canvas ', res)
if (res.length > 0) {
setInitCanvasPlans(res)
setPlans(res)
handleCurrentPlan(res.at(-1).id) // last
setPlanNum(res.length)
} else {
addEmptyPlan()
}
})
}
}, []) }, [])
return ( return (
@ -127,14 +34,14 @@ export default function CanvasLayout() {
<button <button
key={`plan-${plan.id}`} key={`plan-${plan.id}`}
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`} className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
onClick={() => handleCurrentPlan(plan.id)} onClick={() => handleCurrentPlan(sessionState.userId, plan.id)}
> >
<span>{plan.name}</span> <span>{plan.name}</span>
<i <i
className="close" className="close"
onClick={(e) => onClick={(e) =>
swalFire({ swalFire({
html: getMessage('common.message.confirm.delete') + `</br>${plan.name}`, text: `${plan.name} ` + getMessage('plan.message.confirm.delete'),
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
handleDeletePlan(e, plan.id) handleDeletePlan(e, plan.id)
@ -146,23 +53,7 @@ export default function CanvasLayout() {
))} ))}
</div> </div>
{plans.length < 10 && ( {plans.length < 10 && (
<button <button className="plane-add" onClick={() => handleAddPlan(sessionState.userId, objectNo)}>
className="plane-add"
onClick={() =>
JSON.parse(currentCanvasData()).objects.length > 0
? swalFire({
html: `${currentCanvasPlan.name} 을 복제하시겠습니까?`,
type: 'confirm',
confirmFn: () => {
addCopyPlan()
},
denyFn: () => {
addEmptyPlan()
},
})
: addEmptyPlan()
}
>
<span></span> <span></span>
</button> </button>
)} )}

View File

@ -19,6 +19,7 @@ import { MENU } from '@/common/common'
import KO from '@/locales/ko.json' import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json' import JA from '@/locales/ja.json'
import { settingModalFirstOptionsState } from '@/store/settingAtom' import { settingModalFirstOptionsState } from '@/store/settingAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
const canvasMenus = [ const canvasMenus = [
{ index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING },
@ -58,7 +59,8 @@ export default function CanvasMenu(props) {
const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState) const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState)
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore)
const setCurrentMenu = useSetRecoilState(currentMenuState) const setCurrentMenu = useSetRecoilState(currentMenuState)
const setPoints = useSetRecoilState(outerLinePointsState) const setOuterLinePoints = useSetRecoilState(outerLinePointsState)
const setPlacementPoints = useSetRecoilState(placementShapeDrawingPointsState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setcurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
@ -121,14 +123,14 @@ export default function CanvasMenu(props) {
}, [menuNumber, type]) }, [menuNumber, type])
// (btn08) // (btn08)
const handleSaveCanvas = () => { const handleSaveCanvas = async () => {
swalFire({ // swalFire({
html: getMessage('common.message.confirm.save') + `</br>${currentCanvasPlan.name}`, // text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
type: 'confirm', // type: 'confirm',
confirmFn: () => { // confirmFn: async () => {
saveCanvas(sessionState.userId) await saveCanvas(sessionState.userId)
}, // },
}) // })
} }
const onClickPlacementInitialMenu = () => { const onClickPlacementInitialMenu = () => {
@ -140,7 +142,8 @@ export default function CanvasMenu(props) {
} }
const handleClear = () => { const handleClear = () => {
setPoints([]) setOuterLinePoints([])
setPlacementPoints([])
canvas?.clear() canvas?.clear()
} }

View File

@ -1,8 +1,13 @@
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable' import WithDraggable from '@/components/common/draggable/WithDraggable'
import { globalPitchState } from '@/store/canvasAtom'
import { useRecoilState } from 'recoil'
import { useRef } from 'react'
export default function Slope({ setShowSlopeSettingModal }) { export default function Slope({ setShowSlopeSettingModal }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [globalPitch, setGlobalPitch] = useRecoilState(globalPitchState)
const inputRef = useRef()
return ( return (
<WithDraggable isShow={true} pos={{ x: 50, y: -950 }}> <WithDraggable isShow={true} pos={{ x: 50, y: -950 }}>
<div className={`modal-pop-wrap xxxm`}> <div className={`modal-pop-wrap xxxm`}>
@ -19,13 +24,21 @@ export default function Slope({ setShowSlopeSettingModal }) {
{getMessage('slope')} {getMessage('slope')}
</span> </span>
<div className="input-grid mr5"> <div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={300} /> <input type="text" className="input-origin block" defaultValue={globalPitch} ref={inputRef} />
</div> </div>
<span className="thin">{getMessage('size.angle')}</span> <span className="thin">{getMessage('size.angle')}</span>
</div> </div>
</div> </div>
<div className="grid-btn-wrap"> <div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button> <button
className="btn-frame modal act"
onClick={() => {
setGlobalPitch(inputRef.current.value)
setShowSlopeSettingModal(false)
}}
>
{getMessage('modal.common.save')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -46,6 +46,7 @@ export default function ObjectSetting({ setShowObjectSettingModal }) {
heightRef: useRef(null), heightRef: useRef(null),
pitchRef: useRef(null), pitchRef: useRef(null),
offsetRef: useRef(null), offsetRef: useRef(null),
offsetWidthRef: useRef(null),
directionRef: useRef(null), directionRef: useRef(null),
} }

View File

@ -1,8 +1,17 @@
import Image from 'next/image' import Image from 'next/image'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { forwardRef, useState } from 'react'
export default function PentagonDormer() { const PentagonDormer = forwardRef((props, refs) => {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [direction, setDirection] = useState('down')
refs.directionRef.current = direction
const getDirection = (e) => {
setDirection(e.target.value)
refs.directionRef.current = e.target.value
}
return ( return (
<> <>
<div className="discrimination-box mb10"> <div className="discrimination-box mb10">
@ -18,7 +27,7 @@ export default function PentagonDormer() {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" defaultValue={2000} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.heightRef} defaultValue={2000} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>
@ -29,7 +38,7 @@ export default function PentagonDormer() {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" defaultValue={1000} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.offsetRef} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>
@ -40,18 +49,18 @@ export default function PentagonDormer() {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" defaultValue={4000} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.widthRef} defaultValue={2000} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>
</div> </div>
</div> </div>
<div className="eaves-keraba-item"> <div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.object.setting.offset.depth')}</div> <div className="eaves-keraba-th">{getMessage('modal.object.setting.offset.width')}</div>
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" defaultValue={500} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.offsetWidthRef} />
</div> </div>
<span className="thin">mm</span> <span className="thin">mm</span>
</div> </div>
@ -62,7 +71,7 @@ export default function PentagonDormer() {
<div className="eaves-keraba-td"> <div className="eaves-keraba-td">
<div className="outline-form"> <div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}> <div className="input-grid mr5" style={{ width: '60px' }}>
<input type="text" className="input-origin block" defaultValue={4} /> <input type="text" className="input-origin block" placeholder={0} ref={refs.pitchRef} defaultValue={4} />
</div> </div>
<span className="thin"></span> <span className="thin"></span>
</div> </div>
@ -80,13 +89,15 @@ export default function PentagonDormer() {
<span className="right">{getMessage('commons.east')}</span> <span className="right">{getMessage('commons.east')}</span>
<span className="bottom">{getMessage('commons.south')}</span> <span className="bottom">{getMessage('commons.south')}</span>
<span className="left">{getMessage('commons.west')}</span> <span className="left">{getMessage('commons.west')}</span>
<button className="plane-btn up"></button> <button className={`plane-btn up ${direction === 'up' ? ' act' : ''}`} value="up" onClick={getDirection}></button>
<button className="plane-btn right"></button> <button className={`plane-btn right ${direction === 'right' ? ' act' : ''}`} value="right" onClick={getDirection}></button>
<button className="plane-btn down act"></button> <button className={`plane-btn down ${direction === 'down' ? ' act' : ''}`} value="down" onClick={getDirection}></button>
<button className="plane-btn left"></button> <button className={`plane-btn left ${direction === 'left' ? ' act' : ''}`} value="left" onClick={getDirection}></button>
</div> </div>
</div> </div>
</div> </div>
</> </>
) )
} })
export default PentagonDormer

View File

@ -5,7 +5,6 @@ import { forwardRef, useState } from 'react'
const TriangleDormer = forwardRef((props, refs) => { const TriangleDormer = forwardRef((props, refs) => {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const [direction, setDirection] = useState('down') const [direction, setDirection] = useState('down')
refs.directionRef.current = direction refs.directionRef.current = direction
const getDirection = (e) => { const getDirection = (e) => {

View File

@ -66,6 +66,7 @@ export default function Stuff() {
gridColumns: [ gridColumns: [
{ {
field: 'lastEditDatetime', field: 'lastEditDatetime',
minWidth: 200,
headerName: getMessage('stuff.gridHeader.lastEditDatetime'), headerName: getMessage('stuff.gridHeader.lastEditDatetime'),
headerCheckboxSelection: true, headerCheckboxSelection: true,
headerCheckboxSelectionCurrentPageOnly: true, // headerCheckboxSelectionCurrentPageOnly: true, //
@ -244,9 +245,8 @@ export default function Stuff() {
} }
async function fetchData() { async function fetchData() {
// const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}` // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(params)}`
const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(params)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(params)}`
await get({ await get({
url: apiUrl, url: apiUrl,
}).then((res) => { }).then((res) => {
@ -295,8 +295,6 @@ export default function Stuff() {
useEffect(() => { useEffect(() => {
if (stuffSearchParams?.code === 'E') { if (stuffSearchParams?.code === 'E') {
//console.log('::::::::', stuffSearchParams, sessionState) //console.log('::::::::', stuffSearchParams, sessionState)
// stuffSearchParams.startRow = (pageNo - 1) * pageSize + 1
// stuffSearchParams.endRow = pageNo * pageSize
stuffSearchParams.startRow = 1 stuffSearchParams.startRow = 1
stuffSearchParams.endRow = 1 * pageSize stuffSearchParams.endRow = 1 * pageSize
stuffSearchParams.schSortType = defaultSortType stuffSearchParams.schSortType = defaultSortType
@ -304,8 +302,8 @@ export default function Stuff() {
setPageNo(1) setPageNo(1)
async function fetchData() { async function fetchData() {
const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}`
// const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}`
await get({ url: apiUrl }).then((res) => { await get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -334,8 +332,8 @@ export default function Stuff() {
}) })
setPageNo(1) setPageNo(1)
// const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}`
const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}`
get({ url: apiUrl }).then((res) => { get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -365,8 +363,8 @@ export default function Stuff() {
setPageNo(1) setPageNo(1)
const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}` // const apiUrl = `/api/object/list?saleStoreId=T01&${queryStringFormatter(stuffSearchParams)}`
// const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}` const apiUrl = `/api/object/list?saleStoreId=${sessionState?.storeId}&${queryStringFormatter(stuffSearchParams)}`
get({ url: apiUrl }).then((res) => { get({ url: apiUrl }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt }) setGridProps({ ...gridProps, gridData: res, count: res[0].totCnt })
@ -406,14 +404,14 @@ export default function Stuff() {
<div className="sub-table-box"> <div className="sub-table-box">
<div className="table-box-title-wrap"> <div className="table-box-title-wrap">
<div className="title-wrap"> <div className="title-wrap">
<h3>물건목록</h3> <h3>{getMessage('stuff.search.grid.title')}</h3>
<ul className="info-wrap"> <ul className="info-wrap">
<li> <li>
전체 {getMessage('stuff.search.grid.all')}
<span>{convertNumberToPriceDecimal(totalCount)}</span> <span>{convertNumberToPriceDecimal(totalCount)}</span>
</li> </li>
<li> <li>
선택 {getMessage('stuff.search.grid.selected')}
<span className="red">{convertNumberToPriceDecimal(selectedRowDataCount)}</span> <span className="red">{convertNumberToPriceDecimal(selectedRowDataCount)}</span>
</li> </li>
</ul> </ul>
@ -421,8 +419,8 @@ export default function Stuff() {
<div className="left-unit-box"> <div className="left-unit-box">
<div className="select-box mr5" style={{ width: '110px' }}> <div className="select-box mr5" style={{ width: '110px' }}>
<select className="select-light black" name="" id="" onChange={onChangeSortType}> <select className="select-light black" name="" id="" onChange={onChangeSortType}>
<option value="R">최근 등록일</option> <option value="R">{getMessage('stuff.search.grid.schSortTypeR')}</option>
<option value="U">최근 수정일</option> <option value="U">{getMessage('stuff.search.grid.schSortTypeU')}</option>
</select> </select>
</div> </div>
<div className="select-box" style={{ width: '80px' }}> <div className="select-box" style={{ width: '80px' }}>

View File

@ -16,6 +16,8 @@ import FindAddressPop from './popup/FindAddressPop'
import PlanRequestPop from './popup/PlanRequestPop' import PlanRequestPop from './popup/PlanRequestPop'
import WindSelectPop from './popup/WindSelectPop' import WindSelectPop from './popup/WindSelectPop'
export default function StuffDetail() { export default function StuffDetail() {
const [selOptions, setSelOptions] = useState('')
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const router = useRouter() const router = useRouter()
@ -79,7 +81,7 @@ export default function StuffDetail() {
const [detailData, setDetailData] = useState({}) const [detailData, setDetailData] = useState({})
useEffect(() => { useEffect(() => {
console.log('objectNo::', objectNo) // console.log('objectNo::', objectNo)
if (objectNo) { if (objectNo) {
console.log('수정화면') console.log('수정화면')
@ -107,26 +109,28 @@ export default function StuffDetail() {
// 1 saleStoreId=201TES01 // 1 saleStoreId=201TES01
// T01 // T01
//1 : X167 //1 : X167 T01
get({ url: `/api/object/saleStore/T01/list` }).then((res) => { // get({ url: `/api/object/saleStore/TEMP02/list` }).then((res) => {
// get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
const firstList = res.filter((row) => row.saleStoreLevel === '1') const firstList = res.filter((row) => row.saleStoreLevel === '1')
const otherList = res.filter((row) => row.saleStoreLevel !== '1') const otherList = res.filter((row) => row.saleStoreLevel !== '1')
//1 //1
setSaleStoreList(firstList) setSaleStoreList(firstList)
setSelOptions(sessionState?.storeId)
form.setValue('saleStoreId', sessionState?.storeId)
form.setValue('saleStoreLevel', sessionState?.storeLvl)
//1 //1
setOriginOtherSaleStoreList(otherList) setOriginOtherSaleStoreList(otherList)
setOtherSaleStoreList(otherList) setOtherSaleStoreList(otherList)
} }
}) })
} }
}, [objectNo]) }, [objectNo, sessionState])
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(detailData)) { if (isObjectNotEmpty(detailData)) {
console.log('상세데이타:::::::', detailData)
// API // API
get({ url: '/api/object/prefecture/list' }).then((res) => { get({ url: '/api/object/prefecture/list' }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
@ -151,6 +155,8 @@ export default function StuffDetail() {
setOtherSaleStoreList(otherList) setOtherSaleStoreList(otherList)
} }
}) })
console.log('상세데이타::세팅:::::', detailData)
} }
}, [detailData]) }, [detailData])
@ -161,12 +167,14 @@ export default function StuffDetail() {
form.setValue('saleStoreId', key.saleStoreId) form.setValue('saleStoreId', key.saleStoreId)
form.setValue('saleStoreName', key.saleStoreName) form.setValue('saleStoreName', key.saleStoreName)
form.setValue('saleStoreLevel', key.saleStoreLevel) form.setValue('saleStoreLevel', key.saleStoreLevel)
setSelOptions(key.saleStoreId)
// 1 2 list // 1 2 list
//  // 
let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId) let newOtherSaleStoreList = originOtherSaleStoreList.filter((row) => row.firstAgentId === key.saleStoreId)
setOtherSaleStoreList(newOtherSaleStoreList) setOtherSaleStoreList(newOtherSaleStoreList)
} else { } else {
//X //X
setSelOptions('')
form.setValue('saleStoreId', '') form.setValue('saleStoreId', '')
form.setValue('saleStoreName', '') form.setValue('saleStoreName', '')
form.setValue('saleStoreLevel', '') form.setValue('saleStoreLevel', '')
@ -209,8 +217,17 @@ export default function StuffDetail() {
form.setValue('zipNo', info.zipNo) form.setValue('zipNo', info.zipNo)
} }
// //
const setPlanReqInfo = (info) => {} const setPlanReqInfo = (info) => {
console.log('팝업에서 넘어온 설계의뢰 정보::: ', info)
//building :
//planReqName :
//zipNo :
// :address1 : address2
// setPrefValue(info.prefId)
// :
// form.setValue('dispCompanyName', info.planReqName)
}
// //
const setWindSppedInfo = (info) => { const setWindSppedInfo = (info) => {
@ -286,7 +303,7 @@ export default function StuffDetail() {
} }
// console.log('::', errors) // console.log('::', errors)
setIsFormValid(Object.keys(errors).length === 0) setIsFormValid(Object.keys(errors).length === 0 ? true : false)
} else { } else {
console.log('상세일때 폼체크') console.log('상세일때 폼체크')
} }
@ -345,25 +362,14 @@ export default function StuffDetail() {
form.setValue('areaId', e.target.value) form.setValue('areaId', e.target.value)
} }
// useEffect(() => {
// if (!isEmptyArray(areaIdList)) {
// let _prefName = form.watch('prefName')
// // console.log(' API', _prefName)
// get({ url: `/api/object/windSpeed/${_prefName}/list` }).then((res) => {
// // console.log('res::', res)
// if (!isEmptyArray(res)) {
// setWindSpeedList(res)
// }
// })
// }
// }, [areaIdList])
// //
const onValid = (data) => { const onValid = (data, e) => {
const formData = form.getValues()
console.log('필수값 통과:::', data, formData)
// console.log(' formData:::', formData)
// PUT // PUT
// console.log(' ') // console.log(' ')
// console.log('data::::::', data) // console.log('data::::::', data)
const formData = form.getValues()
// console.log('formData::::', formData) // console.log('formData::::', formData)
// const _dispCompanyName = watch('dispCompanyName') // const _dispCompanyName = watch('dispCompanyName')
// const _objectStatusId = watch('objectStatusId') // const _objectStatusId = watch('objectStatusId')
@ -391,6 +397,8 @@ export default function StuffDetail() {
// //
const onTempSave = async () => { const onTempSave = async () => {
console.log('임시저장:::::')
return
const formData = form.getValues() const formData = form.getValues()
// console.log('formData::', formData) // console.log('formData::', formData)
const params = { const params = {
@ -441,7 +449,7 @@ export default function StuffDetail() {
let testobj = '10' let testobj = '10'
del({ url: `/api/object/${testobj}` }).then((res) => { del({ url: `/api/object/${testobj}` }).then((res) => {
// console.log(' :::', res) console.log('삭제 결과:::', res)
router.push('/management/stuff') router.push('/management/stuff')
}) })
} }
@ -470,9 +478,9 @@ export default function StuffDetail() {
<div className="input-wrap mr5" style={{ width: '200px' }}> <div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" readOnly /> <input type="text" className="input-light" readOnly />
</div> </div>
<button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}> <Button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
</button> </Button>
</div> </div>
</td> </td>
</tr> </tr>
@ -536,13 +544,21 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="flx-box"> <div className="flx-box">
<div style={{ width: '567px', marginRight: '5px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={saleStoreList} options={saleStoreList}
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
isClearable={true} isClearable={true}
value={saleStoreList.filter(function (option) {
return option.saleStoreId === selOptions
})}
/> />
</div> </div>
<div className="input-wrap" style={{ width: '216px' }}> <div className="input-wrap" style={{ width: '216px' }}>
@ -562,8 +578,13 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="flx-box"> <div className="flx-box">
<div style={{ width: '567px', marginRight: '5px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
<Select <Select
id="long-value-select2"
instanceId="long-value-select2"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref} ref={ref}
options={otherSaleStoreList} options={otherSaleStoreList}
onChange={onSelectionChange2} onChange={onSelectionChange2}
@ -669,9 +690,9 @@ export default function StuffDetail() {
</select> </select>
</div> */} </div> */}
<span className="mr10">{getMessage('stuff.detail.windSpeedSpan')}</span> <span className="mr10">{getMessage('stuff.detail.windSpeedSpan')}</span>
<button className="btn-origin grey" onClick={onSearchWindSpeedPopOpen}> <Button className="btn-origin grey" onClick={onSearchWindSpeedPopOpen}>
{getMessage('stuff.detail.btn.windSpeedPop')} {getMessage('stuff.detail.btn.windSpeedPop')}
</button> </Button>
</div> </div>
</td> </td>
</tr> </tr>
@ -764,18 +785,18 @@ export default function StuffDetail() {
</div> </div>
<div className="sub-table-footer"> <div className="sub-table-footer">
{!isFormValid ? ( {!isFormValid ? (
<button className="btn-origin grey mr5" onClick={onTempSave}> <Button className="btn-origin grey mr5" onClick={onTempSave}>
New화면 임시저장 New화면 임시저장
</button> </Button>
) : ( ) : (
<button type="submit" className="btn-origin navy mr5"> <Button type="submit" className="btn-origin navy mr5">
NEW 화면 저장 NEW 화면 저장
</button> </Button>
)} )}
<Link href="/management/stuff"> <Link href="/management/stuff">
<button type="button" className="btn-origin grey"> <Button type="button" className="btn-origin grey">
NEW화면 물건목록이동 NEW화면 물건목록이동
</button> </Button>
</Link> </Link>
</div> </div>
</div> </div>
@ -801,9 +822,9 @@ export default function StuffDetail() {
<div className="input-wrap mr5" style={{ width: '200px' }}> <div className="input-wrap mr5" style={{ width: '200px' }}>
<input type="text" className="input-light" readOnly /> <input type="text" className="input-light" readOnly />
</div> </div>
<button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}> <Button className="btn-origin grey" onClick={onSearchDesignRequestPopOpen}>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
</button> </Button>
</div> </div>
</td> </td>
</tr> </tr>
@ -813,7 +834,7 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="input-wrap" style={{ width: '500px' }}> <div className="input-wrap" style={{ width: '500px' }}>
{/* <input type="text" className="input-light" {...form.register('dispCompanyName')} value={form.watch('dispCompanyName')} /> */} <input type="text" className="input-light" {...form.register('dispCompanyName')} value={form.watch('dispCompanyName')} />
</div> </div>
</td> </td>
</tr> </tr>
@ -865,7 +886,7 @@ export default function StuffDetail() {
</th> </th>
<td> <td>
<div className="flx-box"> <div className="flx-box">
<div style={{ width: '567px', marginRight: '5px' }}> <div className="select-wrap mr5" style={{ width: '567px' }}>
{/* <Select {/* <Select
options={saleStoreList} options={saleStoreList}
value={form.watch('saleStoreId')} value={form.watch('saleStoreId')}
@ -890,32 +911,32 @@ export default function StuffDetail() {
{objectNo.substring(0, 1) === 'R' ? ( {objectNo.substring(0, 1) === 'R' ? (
<> <>
<Link href="/management/stuff"> <Link href="/management/stuff">
<button type="button" className="btn-origin grey"> <Button type="button" className="btn-origin grey mr5">
R상세:물건목록 R상세:물건목록
</button> </Button>
</Link> </Link>
<button type="submit" className="btn-origin navy mr5"> <Button type="submit" className="btn-origin navy mr5">
R상세:저장 R상세:저장
</button> </Button>
<button type="submit" className="btn-origin navy mr5" onClick={onDelete}> <Button type="submit" className="btn-origin navy" onClick={onDelete}>
R상세:물건삭제 R상세:물건삭제
</button> </Button>
</> </>
) : ( ) : (
<> <>
{!isFormValid ? ( {!isFormValid ? (
<button type="submit" className="btn-origin navy mr5" onClick={onTempSave}> <Button type="submit" className="btn-origin navy mr5" onClick={onTempSave}>
TEMP상세:임시저장 TEMP상세:임시저장
</button> </Button>
) : ( ) : (
<button type="submit" className="btn-origin navy mr5"> <Button type="submit" className="btn-origin navy mr5">
TEMP상세:저장 TEMP상세:저장
</button> </Button>
)} )}
<Link href="/management/stuff"> <Link href="/management/stuff">
<button type="button" className="btn-origin grey"> <Button type="button" className="btn-origin grey">
T상세:물건목록 T상세:물건목록
</button> </Button>
</Link> </Link>
</> </>
)} )}
@ -923,7 +944,14 @@ export default function StuffDetail() {
)} )}
{showAddressButtonValid && <FindAddressPop setShowAddressButtonValid={setShowAddressButtonValid} zipInfo={setZipInfo} />} {showAddressButtonValid && <FindAddressPop setShowAddressButtonValid={setShowAddressButtonValid} zipInfo={setZipInfo} />}
{showDesignRequestButtonValid && ( {showDesignRequestButtonValid && (
<PlanRequestPop setShowDesignRequestButtonValid={setShowDesignRequestButtonValid} planReqInfo={setPlanReqInfo} /> <PlanRequestPop
setShowDesignRequestButtonValid={setShowDesignRequestButtonValid}
saleStoreId={form.watch('saleStoreId')}
saleStoreLevel={form.watch('saleStoreLevel')}
otherSaleStoreId={form.watch('otherSaleStoreId')}
otherSaleStoreLevel={form.watch('otherSaleStoreLevel')}
planReqInfo={setPlanReqInfo}
/>
)} )}
{showWindSpeedButtonValid && ( {showWindSpeedButtonValid && (
<WindSelectPop setShowWindSpeedButtonValid={setShowWindSpeedButtonValid} prefName={form.watch('prefName')} windSpeedInfo={setWindSppedInfo} /> <WindSelectPop setShowWindSpeedButtonValid={setShowWindSpeedButtonValid} prefName={form.watch('prefName')} windSpeedInfo={setWindSppedInfo} />

View File

@ -69,12 +69,6 @@ export default function StuffQGrid(props) {
props.getCellDoubleClicked(event) props.getCellDoubleClicked(event)
}, []) }, [])
const autoSizeStrategy = useMemo(() => {
return {
type: 'fitCellContents',
}
}, [])
// Fetch data & update rowData state // Fetch data & update rowData state
useEffect(() => { useEffect(() => {
gridData ? setRowData(gridData) : '' gridData ? setRowData(gridData) : ''

View File

@ -18,7 +18,6 @@ import { useMessage } from '@/hooks/useMessage'
import { isObjectNotEmpty } from '@/util/common-utils' import { isObjectNotEmpty } from '@/util/common-utils'
export default function StuffSearchCondition() { export default function StuffSearchCondition() {
const sessionState = useRecoilValue(sessionStore) const sessionState = useRecoilValue(sessionStore)
const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore) const [appMessageState, setAppMessageState] = useRecoilState(appMessageStore)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -74,10 +73,6 @@ export default function StuffSearchCondition() {
startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1, startRow: stuffSearch?.startRow ? stuffSearch.startRow : 1,
endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100, endRow: stuffSearch?.endRow ? stuffSearch.endRow : 100,
schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R', schSortType: stuffSearch?.schSortType ? stuffSearch.schSortType : 'R',
selObject: {
label: stuffSearch.selObject.label,
value: stuffSearch.selObject.value,
},
}) })
} }
@ -99,9 +94,8 @@ export default function StuffSearchCondition() {
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(sessionState)) { if (isObjectNotEmpty(sessionState)) {
// console.log(' ::::::::', sessionState)
// storeId T01 1 // storeId T01 1
// get({ url: `/api/object/saleStore/201TES01/list` }).then((res) => { // get({ url: `/api/object/saleStore/TEMP02/list` }).then((res) => {
get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => { get({ url: `/api/object/saleStore/${sessionState?.storeId}/list` }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
res.map((row) => { res.map((row) => {
@ -129,7 +123,6 @@ export default function StuffSearchCondition() {
...stuffSearch, ...stuffSearch,
code: 'S', code: 'S',
schSelSaleStoreId: key.saleStoreId, schSelSaleStoreId: key.saleStoreId,
selObject: { value: key.saleStoreId, label: key.saleStoreName },
}) })
} else { } else {
setSchSelSaleStoreId('') setSchSelSaleStoreId('')
@ -159,7 +152,7 @@ export default function StuffSearchCondition() {
<h3>{getMessage('stuff.search.title')}</h3> <h3>{getMessage('stuff.search.title')}</h3>
</div> </div>
<div className="left-unit-box"> <div className="left-unit-box">
<Link href="/management/stuff/tempdetail"> <Link href="/management/stuff/tempdetail" scroll={false}>
<button type="button" className="btn-origin navy mr5"> <button type="button" className="btn-origin navy mr5">
{getMessage('stuff.search.btn1')} {getMessage('stuff.search.btn1')}
</button> </button>
@ -190,7 +183,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.code === 'E' || stuffSearch?.code === 'M' ? stuffSearch.schObjectNo : objectNo} value={stuffSearch?.code === 'E' || stuffSearch?.code === 'M' ? stuffSearch.schObjectNo : objectNo}
onChange={(e) => { onChange={(e) => {
setObjectNo(e.target.value) setObjectNo(e.target.value)
@ -205,7 +197,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName} value={stuffSearch?.schSaleStoreName ? stuffSearch.schSaleStoreName : saleStoreName}
onChange={(e) => { onChange={(e) => {
setSaleStoreName(e.target.value) setSaleStoreName(e.target.value)
@ -220,7 +211,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.schAddress ? stuffSearch.schAddress : address} value={stuffSearch?.schAddress ? stuffSearch.schAddress : address}
onChange={(e) => { onChange={(e) => {
setAddress(e.target.value) setAddress(e.target.value)
@ -237,7 +227,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName} value={stuffSearch?.schObjectName ? stuffSearch.schObjectName : objectName}
onChange={(e) => { onChange={(e) => {
setobjectName(e.target.value) setobjectName(e.target.value)
@ -252,7 +241,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName} value={stuffSearch?.schDispCompanyName ? stuffSearch.schDispCompanyName : dispCompanyName}
onChange={(e) => { onChange={(e) => {
setDispCompanyName(e.target.value) setDispCompanyName(e.target.value)
@ -263,18 +251,39 @@ export default function StuffSearchCondition() {
</td> </td>
<th>{getMessage('stuff.search.schSelSaleStoreId')}</th> <th>{getMessage('stuff.search.schSelSaleStoreId')}</th>
<td> <td>
<div className="select-wrap">
{schSelSaleStoreList?.length > 0 && ( {schSelSaleStoreList?.length > 0 && (
<Select <Select
id="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
ref={ref} ref={ref}
options={schSelSaleStoreList} options={schSelSaleStoreList}
onChange={onSelectionChange} onChange={onSelectionChange}
getOptionLabel={(x) => x.saleStoreName} getOptionLabel={(x) => x.saleStoreName}
getOptionValue={(x) => x.saleStoreId} getOptionValue={(x) => x.saleStoreId}
defaultValue={stuffSearch?.selObject?.value ? stuffSearch?.selObject : null} value={schSelSaleStoreList.filter(function (option) {
if (stuffSearch?.code === 'S' && schSelSaleStoreId === '') {
return false
} else if (stuffSearch?.code === 'S' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else if (stuffSearch?.code === 'E' && schSelSaleStoreId !== '') {
return option.saleStoreId === schSelSaleStoreId
} else {
if (stuffSearch?.schSelSaleStoreId !== '') {
return option.saleStoreId === stuffSearch.schSelSaleStoreId
} else {
return false
}
}
})}
isDisabled={sessionState?.storeLvl === '1' ? false : true} isDisabled={sessionState?.storeLvl === '1' ? false : true}
isClearable={true} isClearable={true}
/> />
)} )}
</div>
</td> </td>
</tr> </tr>
<tr> <tr>
@ -284,7 +293,6 @@ export default function StuffSearchCondition() {
<input <input
type="text" type="text"
className="input-light" className="input-light"
// placeholder=" "
value={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser} value={stuffSearch?.schReceiveUser ? stuffSearch.schReceiveUser : receiveUser}
onChange={(e) => { onChange={(e) => {
setReceiveUser(e.target.value) setReceiveUser(e.target.value)

View File

@ -79,7 +79,6 @@ export default function FindAddressPop(props) {
} }
// //
const applyAddress = () => { const applyAddress = () => {
// console.log(' :::::::::', prefId, address1, address2, address3, zipNo)
if (prefId == null) { if (prefId == null) {
alert(getMessage('stuff.addressPopup.error.message2')) alert(getMessage('stuff.addressPopup.error.message2'))
} else { } else {

View File

@ -1,6 +1,5 @@
import React, { useState, useRef, useEffect } from 'react' import React, { useState, useRef, useEffect } from 'react'
import { useForm } from 'react-hook-form' import { useForm } from 'react-hook-form'
import { queryStringFormatter } from '@/util/common-utils'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
@ -12,14 +11,24 @@ import dayjs from 'dayjs'
import PlanRequestPopQGrid from './PlanRequestPopQGrid' import PlanRequestPopQGrid from './PlanRequestPopQGrid'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { planReqSearchState } from '@/store/planReqAtom' import { planReqSearchState } from '@/store/planReqAtom'
import { isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils'
import Select from 'react-select'
import QPagination from '@/components/common/pagination/QPagination'
export default function PlanRequestPop(props) { export default function PlanRequestPop(props) {
const sessionState = useRecoilValue(sessionStore) const [pageNo, setPageNo] = useState(1) //
const [pageSize, setPageSize] = useState(20) //
const [totalCount, setTotalCount] = useState(0) //
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
const { get } = useAxios(globalLocaleState) const [planReqObject, setPlanReqObject] = useState({})
const { get, promiseGet } = useAxios(globalLocaleState)
const { getMessage } = useMessage() const { getMessage } = useMessage()
//Select ref
const ref = useRef()
// //
const [startDate, setStartDate] = useState(dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD')) const [startDate, setStartDate] = useState(dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD'))
const [endDate, setEndDate] = useState(dayjs(new Date()).format('YYYY-MM-DD')) const [endDate, setEndDate] = useState(dayjs(new Date()).format('YYYY-MM-DD'))
@ -34,7 +43,6 @@ export default function PlanRequestPop(props) {
setStartDate: setEndDate, setStartDate: setEndDate,
} }
const ref = useRef()
const resetPlanReqRecoil = useResetRecoilState(planReqSearchState) const resetPlanReqRecoil = useResetRecoilState(planReqSearchState)
const [planReqSearch, setPlanReqSearch] = useRecoilState(planReqSearchState) const [planReqSearch, setPlanReqSearch] = useRecoilState(planReqSearchState)
@ -47,14 +55,41 @@ export default function PlanRequestPop(props) {
const [schDateGbn, setSchDateGbn] = useState('S') //(S/R) const [schDateGbn, setSchDateGbn] = useState('S') //(S/R)
// //
const resetRecoil = () => {} const resetRecoil = () => {
setSchPlanReqNo('')
setSchTitle('')
setSchAddress('')
setSchSaleStoreName('')
setSchPlanReqName('')
setSchDateGbn('S')
setStartDate(dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD'))
setEndDate(dayjs(new Date()).format('YYYY-MM-DD'))
setSchPlanStatCd('')
handleClear() //
resetPlanReqRecoil()
}
// .. //
const handleClear = () => { const handleClear = () => {
if (ref.current.state.dropDown) { if (ref.current) {
ref.current.methods.dropDown() ref.current.clearValue()
}
}
//
const onSelectionChange = (key) => {
//
// console.log('E::::::::', key)
if (isObjectNotEmpty(key)) {
setSchPlanStatCd(key.value)
setPlanReqSearch({
...planReqSearch,
schPlanStatCd: key.value,
})
} else { } else {
ref.current.state.values = [] //X
setSchPlanStatCd('')
setPlanReqSearch({ ...planReqSearch, schPlanStatCd: '' })
} }
} }
@ -63,6 +98,60 @@ export default function PlanRequestPop(props) {
setEndDate(planReqSearch?.schEndDt ? planReqSearch.schEndDt : dayjs(new Date()).format('YYYY-MM-DD')) setEndDate(planReqSearch?.schEndDt ? planReqSearch.schEndDt : dayjs(new Date()).format('YYYY-MM-DD'))
}, [planReqSearch]) }, [planReqSearch])
//
const onSubmit = (page, type) => {
const params = {
// saleStoreId: 'T100',
// saleStoreLevel: '1',
saleStoreId: props?.otherSaleStoreId ? props.otherSaleStoreId : props.saleStoreId,
saleStoreLevel: props?.otherSaleStoreLevel ? props.otherSaleStoreLevel : props.saleStoreLevel,
schPlanReqNo: planReqSearch?.schPlanReqNo ? planReqSearch.schPlanReqNo : schPlanReqNo,
schTitle: planReqSearch?.schTitle ? planReqSearch.schTitle : schTitle,
schAddress: planReqSearch?.schAddress ? planReqSearch.schAddress : schAddress,
schSaleStoreName: planReqSearch?.schSaleStoreName ? planReqSearch.schSaleStoreName : schSaleStoreName,
schPlanReqName: planReqSearch?.schPlanReqName ? planReqSearch.schPlanReqName : schPlanReqName,
schPlanStatCd: planReqSearch?.schPlanStatCd ? planReqSearch.schPlanStatCd : schPlanStatCd,
schDateGbn: planReqSearch?.schDateGbn ? planReqSearch.schDateGbn : schDateGbn,
schStartDt: dayjs(startDate).format('YYYY-MM-DD'),
schEndDt: dayjs(endDate).format('YYYY-MM-DD'),
startRow: type === 'S' ? (1 - 1) * pageSize + 1 : (page - 1) * pageSize + 1,
endRow: type === 'S' ? 1 * pageSize : page * pageSize,
}
if (type === 'S') {
setPageNo(1)
} else {
setPageNo(page)
}
// console.log(params)
const apiUrl = `/api/object/planReq/list?${queryStringFormatter(params)}`
promiseGet({ url: apiUrl }).then((res) => {
if (res.status === 200) {
if (isNotEmptyArray(res.data.data)) {
setGridProps({ ...gridProps, gridData: res.data.data, gridCount: res.data.data[0].totCnt })
setTotalCount(res.data.data[0].totCnt)
} else {
setGridProps({ ...gridProps, gridData: [], gridCount: 0 })
setTotalCount(0)
}
} else {
setGridProps({ ...gridProps, gridData: [], gridCount: 0 })
setTotalCount(0)
}
})
}
//
const handleChangePage = (page) => {
setPlanReqSearch({
...planReqSearch,
startRow: (page - 1) * pageSize + 1,
endRow: page * pageSize,
})
setPageNo(page)
onSubmit(page, 'P')
}
const [gridProps, setGridProps] = useState({ const [gridProps, setGridProps] = useState({
gridData: [], gridData: [],
isPageable: false, isPageable: false,
@ -117,6 +206,45 @@ export default function PlanRequestPop(props) {
], ],
}) })
//
const getSelectedRowdata = (data) => {
if (isNotEmptyArray(data)) {
setPlanReqObject(data[0])
} else {
setPlanReqObject({})
}
}
//
const applyPlanReq = () => {
if (isObjectNotEmpty(planReqObject)) {
props.planReqInfo(planReqObject)
//
props.setShowDesignRequestButtonValid(false)
} else {
alert(getMessage('stuff.planReqPopup.error.message1'))
}
}
const tempList = [
{
label: '완료',
value: 'C',
},
{
label: '저장',
value: 'I',
},
{
label: '접수',
value: 'R',
},
{
label: '제출',
value: 'S',
},
]
return ( return (
<div className="modal-popup"> <div className="modal-popup">
<div className="modal-dialog big"> <div className="modal-dialog big">
@ -132,8 +260,17 @@ export default function PlanRequestPop(props) {
<div className="design-tit-wrap"> <div className="design-tit-wrap">
<h3>{getMessage('stuff.planReqPopup.popTitle')}</h3> <h3>{getMessage('stuff.planReqPopup.popTitle')}</h3>
<div className="design-search-wrap"> <div className="design-search-wrap">
<button className="btn-origin grey mr5">{getMessage('stuff.planReqPopup.btn1')}</button> <button
<button className="btn-origin navy ">{getMessage('stuff.planReqPopup.btn2')}</button> className="btn-origin navy mr5"
onClick={() => {
onSubmit(pageNo, 'S')
}}
>
{getMessage('stuff.planReqPopup.btn1')}
</button>
<button className="btn-origin grey" onClick={resetRecoil}>
{getMessage('stuff.planReqPopup.btn2')}
</button>
</div> </div>
</div> </div>
<div className="design-request-table"> <div className="design-request-table">
@ -224,12 +361,18 @@ export default function PlanRequestPop(props) {
<th>{getMessage('stuff.planReqPopup.search.planStatName')}</th> <th>{getMessage('stuff.planReqPopup.search.planStatName')}</th>
<td> <td>
<div className="select-wrap"> <div className="select-wrap">
<select className="select-light" name="" id=""> <Select
<option value={''}>All</option> id="long-value-select1"
<option value={'SAVE'}>저장</option> instanceId="long-value-select1"
<option value={'SUBMIT'}>제출</option> className="react-select-custom"
<option value={'RECEIPT'}>접수</option> classNamePrefix="custom"
</select> ref={ref}
options={tempList}
onChange={onSelectionChange}
isSearchable={false}
placeholder="Select"
isClearable={true}
/>
</div> </div>
</td> </td>
</tr> </tr>
@ -285,14 +428,19 @@ export default function PlanRequestPop(props) {
</div> </div>
<div className="design-request-grid"> <div className="design-request-grid">
<div className="design-request-grid-tit">Plan List</div> <div className="design-request-grid-tit">Plan List</div>
<PlanRequestPopQGrid {...gridProps} /> <PlanRequestPopQGrid {...gridProps} getSelectedRowdata={getSelectedRowdata} />
<div className="pagination-wrap">
<QPagination pageNo={pageNo} pageSize={pageSize} pagePerBlock={10} totalCount={totalCount} handleChangePage={handleChangePage} />
</div>
</div> </div>
</div> </div>
<div className="footer-btn-wrap"> <div className="footer-btn-wrap">
<button className="btn-origin grey mr5" onClick={() => props.setShowDesignRequestButtonValid(false)}> <button className="btn-origin grey mr5" onClick={() => props.setShowDesignRequestButtonValid(false)}>
{getMessage('stuff.planReqPopup.btn3')} {getMessage('stuff.planReqPopup.btn3')}
</button> </button>
<button className="btn-origin navy ">{getMessage('stuff.planReqPopup.btn4')}</button> <button className="btn-origin navy" onClick={applyPlanReq}>
{getMessage('stuff.planReqPopup.btn4')}
</button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -39,8 +39,14 @@ export default function PlanRequestPopQGrid(props) {
[gridData], [gridData],
) )
//
const onSelectionChanged = () => {
const selectedData = gridApi.getSelectedRows()
props.getSelectedRowdata(selectedData)
}
return ( return (
<div className="ag-theme-quartz" style={{ height: 500 }}> <div className="ag-theme-quartz" style={{ height: 350 }}>
<AgGridReact <AgGridReact
onGridReady={onGridReady} onGridReady={onGridReady}
rowBuffer={rowBuffer} rowBuffer={rowBuffer}
@ -49,7 +55,7 @@ export default function PlanRequestPopQGrid(props) {
defaultColDef={defaultColDef} defaultColDef={defaultColDef}
rowSelection={'singleRow'} rowSelection={'singleRow'}
pagination={isPageable} pagination={isPageable}
// onSelectionChanged={onSelectionChanged} onSelectionChanged={onSelectionChanged}
/> />
</div> </div>
) )

View File

@ -150,7 +150,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.userId')}</th> <th>{getMessage('myinfo.info.userId')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={userId} readOnly /> <input type="text" className="input-light" value={userId || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -158,7 +158,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.nameKana')}</th> <th>{getMessage('myinfo.info.nameKana')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.nameKana} readOnly /> <input type="text" className="input-light" value={info?.nameKana || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -166,7 +166,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.name')}</th> <th>{getMessage('myinfo.info.name')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.name} readOnly /> <input type="text" className="input-light" value={info?.name || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -235,7 +235,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.category')}</th> <th>{getMessage('myinfo.info.category')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.groupName} readOnly /> <input type="text" className="input-light" value={info?.groupName || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -243,7 +243,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.tel')}</th> <th>{getMessage('myinfo.info.tel')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.tel} readOnly /> <input type="text" className="input-light" value={info?.tel || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -251,7 +251,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.fax')}</th> <th>{getMessage('myinfo.info.fax')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.fax} readOnly /> <input type="text" className="input-light" value={info?.fax || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>
@ -259,7 +259,7 @@ export default function UserInfoModal({ userId, userInfoModal, setUserInfoModal
<th>{getMessage('myinfo.info.mail')}</th> <th>{getMessage('myinfo.info.mail')}</th>
<td> <td>
<div className="input-wrap"> <div className="input-wrap">
<input type="text" className="input-light" value={info?.mail} readOnly /> <input type="text" className="input-light" value={info?.mail || ''} readOnly />
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -4,14 +4,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import { INPUT_TYPE, BATCH_TYPE } from '@/common/common' import { INPUT_TYPE, BATCH_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
import { import { polygonToTurfPolygon, rectToPolygon, triangleToPolygon, pointsToTurfPolygon, setSurfaceShapePattern } from '@/util/canvas-util'
polygonToTurfPolygon,
rectToPolygon,
triangleToPolygon,
pointsToTurfPolygon,
splitDormerTriangle,
setSurfaceShapePattern,
} from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
@ -211,11 +204,13 @@ export function useObjectBatch() {
const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER
const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP
const height = dormerPlacement.heightRef.current.value / 10 const height = dormerPlacement.heightRef.current.value / 10
const width = dormerPlacement.widthRef.current.value / 10
const pitch = dormerPlacement.pitchRef.current.value const pitch = dormerPlacement.pitchRef.current.value
const directionRef = dormerPlacement.directionRef.current
const offsetRef = dormerPlacement.offsetRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetRef.current.value) / 10 const offsetRef = dormerPlacement.offsetRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetRef.current.value) / 10
const offsetWidthRef = dormerPlacement.offsetWidthRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
const directionRef = dormerPlacement.directionRef.current
let dormer, dormerOffset, isDown, selectedSurface let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
console.log('dormerPlacement', dormerPlacement) console.log('dormerPlacement', dormerPlacement)
@ -229,8 +224,6 @@ export function useObjectBatch() {
const bottomLength = height / (pitch * 0.25) const bottomLength = height / (pitch * 0.25)
const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25) const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25)
console.log(bottomOffsetLength)
addCanvasMouseEventListener('mouse:move', (e) => { addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true isDown = true
if (!isDown) return if (!isDown) return
@ -305,16 +298,16 @@ export function useObjectBatch() {
addCanvasMouseEventListener('mouse:up', (e) => { addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) { if (dormer) {
// const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer)) const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
// const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
// //지붕 밖으로 그렸을때 //지붕 밖으로 그렸을때
// if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) { if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
// swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' }) swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
// //일단 지워 //일단 지워
// deleteTempObjects() deleteTempObjects()
// return return
// } }
//각도 추가 //각도 추가
let originAngle = 0 //기본 남쪽 let originAngle = 0 //기본 남쪽
@ -387,6 +380,183 @@ export function useObjectBatch() {
drawDirectionArrow(leftTriangle) drawDirectionArrow(leftTriangle)
drawDirectionArrow(rightTriangle) drawDirectionArrow(rightTriangle)
isDown = false
initEvent()
}
})
} else if (buttonAct === 4) {
const heightLength = height - (width / 2) * (pitch * 0.25)
//(동의길이 깊이)+출폭(깊이)-[(입력한 폭값)/2+출폭(폭)]*(0.25*입력한 寸)
const heightOffsetLength = height + offsetRef - (width / 2 + offsetWidthRef) * (pitch * 0.25)
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e)
surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface
}
})
let angle = 0
if (directionRef === 'left') {
//서
angle = 90
} else if (directionRef === 'right') {
//동
angle = 270
} else if (directionRef === 'up') {
//북
angle = 180
}
pentagonPoints = [
{ x: pointer.x, y: pointer.y },
{ x: pointer.x - width / 2, y: pointer.y + (height - heightLength) },
{ x: pointer.x - width / 2, y: pointer.y + height },
{ x: pointer.x + width / 2, y: pointer.y + height },
{ x: pointer.x + width / 2, y: pointer.y + (height - heightLength) },
]
pentagonOffsetPoints = [
{ x: pointer.x, y: pointer.y },
{ x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
{ x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef },
{ x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef },
{ x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
]
dormer = new QPolygon(pentagonPoints, {
fill: 'white',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormer)
if (offsetRef > 0 || offsetWidthRef > 0) {
dormerOffset = new QPolygon(pentagonOffsetPoints, {
fill: 'gray',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormerOffset)
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) {
// const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
// const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
// //지붕 밖으로 그렸을때
// if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
// swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
// //일단 지워
// deleteTempObjects()
// return
// }
//각도 추가
let originAngle = 0 //기본 남쪽
let direction = 'south'
if (directionRef === 'left') {
//서
originAngle = 90
direction = 'west'
} else if (directionRef === 'right') {
//동
originAngle = 270
direction = 'east'
} else if (directionRef === 'up') {
//북
originAngle = 180
direction = 'north'
}
const offsetMode = offsetRef > 0 || offsetWidthRef > 0 ? 'offset' : 'normal'
let splitedPentagon =
offsetRef > 0 || offsetWidthRef > 0
? splitDormerPentagon(dormerOffset, directionRef, offsetMode)
: splitDormerPentagon(dormer, directionRef, offsetMode)
canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0)
dormer.set({
name: dormerName,
stroke: 'black',
strokeWidth: 1,
strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다
const leftPentagon = new QPolygon(splitedPentagon[0], {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
const rightPentagon = new QPolygon(splitedPentagon[1], {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
canvas?.add(leftPentagon)
canvas?.add(rightPentagon)
//패턴
setSurfaceShapePattern(leftPentagon)
setSurfaceShapePattern(rightPentagon)
//방향
drawDirectionArrow(leftPentagon)
drawDirectionArrow(rightPentagon)
isDown = false isDown = false
initEvent() initEvent()
} }
@ -408,8 +578,140 @@ export function useObjectBatch() {
initEvent() //이벤트 초기화 initEvent() //이벤트 초기화
} }
const splitDormerTriangle = (triangle, direction) => {
const halfWidth = triangle.width / 2
let leftPoints = []
let rightPoints = []
if (direction === 'down') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top + triangle.height },
{ x: triangle.left, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top + triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top + triangle.height },
]
} else if (direction === 'up') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top - triangle.height },
{ x: triangle.left, y: triangle.top - triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top - triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top - triangle.height },
]
} else if (direction === 'left') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top - halfWidth },
{ x: triangle.left - triangle.height, y: triangle.top },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top + halfWidth },
]
} else if (direction === 'right') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height },
]
}
return [leftPoints, rightPoints]
}
const splitDormerPentagon = (pentagon, direction, offsetMode) => {
const points = pentagon.points
console.log(pentagon.points)
let leftPoints = []
let rightPoints = []
if (direction === 'down') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[1].x, y: points[1].y },
{ x: points[2].x, y: points[2].y },
{ x: points[0].x, y: points[3].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x, y: points[2].y },
{ x: points[3].x, y: points[3].y },
{ x: points[4].x, y: points[4].y },
]
} else if (direction === 'up') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[1].x, y: points[0].y - (points[1].y - points[0].y) },
{ x: points[2].x, y: points[0].y - (points[2].y - points[0].y) },
{ x: points[0].x, y: points[0].y - (points[2].y - points[0].y) },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[3].x, y: points[0].y - (points[1].y - points[0].y) },
{ x: points[3].x, y: points[0].y - (points[2].y - points[0].y) },
{ x: points[0].x, y: points[0].y - (points[2].y - points[0].y) },
]
} else if (direction === 'left') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x - (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x - (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
]
} else if (direction === 'right') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x + (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x + (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
]
}
console.log(leftPoints, rightPoints)
return [leftPoints, rightPoints]
}
return { return {
applyOpeningAndShadow, applyOpeningAndShadow,
applyDormers, applyDormers,
splitDormerTriangle,
splitDormerPentagon,
} }
} }

View File

@ -23,10 +23,11 @@ import {
outerLineLength2State, outerLineLength2State,
outerLineTypeState, outerLineTypeState,
} from '@/store/outerLineAtom' } from '@/store/outerLineAtom'
import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util' import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { booleanPointInPolygon } from '@turf/turf'
// 보조선 작성 // 보조선 작성
export function useAuxiliaryDrawing(setShowAuxiliaryModal) { export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
@ -76,6 +77,8 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
useEffect(() => { useEffect(() => {
typeRef.current = type typeRef.current = type
clear()
addDocumentEventListener('keydown', document, keydown[type])
}, [type]) }, [type])
useEffect(() => { useEffect(() => {
@ -103,12 +106,8 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
} }
}, []) }, [])
useEffect(() => {
clear()
addDocumentEventListener('keydown', document, keydown[type])
}, [type])
const clear = () => { const clear = () => {
addCanvasMouseEventListener('mouse:move', mouseMove)
setLength1(0) setLength1(0)
setLength2(0) setLength2(0)
@ -459,8 +458,9 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
} }
const mouseDown = (e) => { const mouseDown = (e) => {
addCanvasMouseEventListener('mouse:move', mouseMove) canvas.renderAll()
const pointer = getIntersectMousePoint(e) const pointer = getIntersectMousePoint(e)
console.log(pointer)
mousePointerArr.current.push(pointer) mousePointerArr.current.push(pointer)
if (mousePointerArr.current.length === 2) { if (mousePointerArr.current.length === 2) {
@ -538,39 +538,47 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
// 보조선 절삭 // 보조선 절삭
const cutAuxiliary = (e) => { const cutAuxiliary = (e) => {
const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed) const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine')
if (auxiliaryLines.length === 0) { if (auxiliaryLines.length === 0) {
return return
} }
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const allLines = [...auxiliaryLines]
roofBases.forEach((roofBase) => {
roofBase.lines.forEach((line) => {
allLines.push(line)
})
})
auxiliaryLines.forEach((line1) => { auxiliaryLines.forEach((line1) => {
auxiliaryLines.forEach((line2) => { allLines.forEach((line2) => {
const lines = [line1, line2]
if (line1 === line2) { if (line1 === line2) {
return return
} }
const intersectionPoint = calculateIntersection(line1, line2) const intersectionPoint = calculateIntersection(line1, line2)
if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) { if (!intersectionPoint) {
return return
} }
roofAdsorptionPoints.current.push(intersectionPoint) roofAdsorptionPoints.current.push(intersectionPoint)
intersectionPoints.current.push(intersectionPoint) intersectionPoints.current.push(intersectionPoint)
lines.forEach((line) => {
const distance1 = distanceBetweenPoints({ x: line.x1, y: line.y1 }, intersectionPoint) const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint)
const distance2 = distanceBetweenPoints({ x: line.x2, y: line.y2 }, intersectionPoint) const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint)
if (distance1 === 0 || distance2 === 0) { if (distance1 === 0 || distance2 === 0) {
return return
} }
//historyLine에서 기존 line을 제거한다. //historyLine에서 기존 line을 제거한다.
lineHistory.current = lineHistory.current.filter((history) => history !== line) lineHistory.current = lineHistory.current.filter((history) => history !== line1)
let newLine let newLine
if (distance1 >= distance2) { if (distance1 >= distance2) {
newLine = addLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], { newLine = addLine([line1.x1, line1.y1, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black', stroke: 'black',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
@ -579,7 +587,7 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
intersectionPoint, intersectionPoint,
}) })
} else { } else {
newLine = addLine([line.x2, line.y2, intersectionPoint.x, intersectionPoint.y], { newLine = addLine([line1.x2, line1.y2, intersectionPoint.x, intersectionPoint.y], {
stroke: 'black', stroke: 'black',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
@ -589,8 +597,7 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
}) })
} }
lineHistory.current.push(newLine) lineHistory.current.push(newLine)
removeLine(line) removeLine(line1)
})
}) })
}) })
addCanvasMouseEventListener('mouse:move', mouseMove) addCanvasMouseEventListener('mouse:move', mouseMove)
@ -600,10 +607,15 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
* 일변전으로 돌아가기 * 일변전으로 돌아가기
*/ */
const handleRollback = () => { const handleRollback = () => {
const lastLine = lineHistory.current.pop() const innerPoint = canvas.getObjects().find((obj) => obj.name === 'innerPoint')
if (innerPoint) {
mousePointerArr.current = [] mousePointerArr.current = []
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint')) canvas.remove(innerPoint)
canvas.renderAll()
return
}
const lastLine = lineHistory.current.pop()
if (lastLine) { if (lastLine) {
roofAdsorptionPoints.current = roofAdsorptionPoints.current.filter( roofAdsorptionPoints.current = roofAdsorptionPoints.current.filter(
(point) => point.x !== lastLine.intersectionPoint?.x && point.y !== lastLine.intersectionPoint?.y, (point) => point.x !== lastLine.intersectionPoint?.x && point.y !== lastLine.intersectionPoint?.y,
@ -621,10 +633,25 @@ export function useAuxiliaryDrawing(setShowAuxiliaryModal) {
return return
} }
const roofBases = canvas.getObjects().find((obj) => obj.name === 'roofBase') const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const innerLines = [...lineHistory.current] const innerLines = [...lineHistory.current]
roofBases.innerLines = [...innerLines] roofBases.forEach((roofBase) => {
const roofInnerLines = innerLines.filter((line) => {
const turfPolygon = polygonToTurfPolygon(roofBase)
// innerLines의 두 점이 모두 polygon 안에 있는지 확인
const inPolygon1 = booleanPointInPolygon([line.x1, line.y1], turfPolygon)
const inPolygon2 = booleanPointInPolygon([line.x2, line.y2], turfPolygon)
if (inPolygon1 && inPolygon2) {
line.attributes = { ...line.attributes, roofId: roofBase.id }
return true
}
})
roofBase.innerLines = [...roofInnerLines]
})
setShowAuxiliaryModal(false) setShowAuxiliaryModal(false)
} }

View File

@ -29,12 +29,19 @@ import {
} from '@/store/outerLineAtom' } from '@/store/outerLineAtom'
import { calculateAngle } from '@/util/qpolygon-utils' import { calculateAngle } from '@/util/qpolygon-utils'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { QLine } from '@/components/fabric/QLine'
//외벽선 그리기 //외벽선 그리기
export function useOuterLineWall(setShowOutlineModal) { export function useOuterLineWall(setShowOutlineModal) {
const canvas = useRecoilValue(canvasState) const canvas = useRecoilValue(canvasState)
const { addCanvasMouseEventListener, addDocumentEventListener, removeAllMouseEventListeners, removeAllDocumentEventListeners, removeMouseEvent } = const {
useEvent() initEvent,
addCanvasMouseEventListener,
addDocumentEventListener,
removeAllMouseEventListeners,
removeAllDocumentEventListeners,
removeMouseEvent,
} = useEvent()
const { getIntersectMousePoint } = useMouse() const { getIntersectMousePoint } = useMouse()
const { addLine, removeLine } = useLine() const { addLine, removeLine } = useLine()
const { tempGridMode } = useTempGrid() const { tempGridMode } = useTempGrid()
@ -75,6 +82,9 @@ export function useOuterLineWall(setShowOutlineModal) {
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
clear() clear()
return () => {
initEvent()
}
}, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) }, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode])
useEffect(() => { useEffect(() => {
@ -215,11 +225,11 @@ export function useOuterLineWall(setShowOutlineModal) {
return return
} }
/*if (lastPoint.x === firstPoint.x && lastPoint.y === firstPoint.y) { if (Math.abs(lastPoint.x - firstPoint.x) < 1 && Math.abs(lastPoint.y - firstPoint.y) < 1) {
return return
} }
if (lastPoint.x === firstPoint.x || lastPoint.y === firstPoint.y) { if (Math.abs(lastPoint.x - firstPoint.x) < 1 || Math.abs(lastPoint.y - firstPoint.y) < 1) {
let isAllRightAngle = true let isAllRightAngle = true
const firstPoint = points[0] const firstPoint = points[0]
@ -238,38 +248,27 @@ export function useOuterLineWall(setShowOutlineModal) {
if (isAllRightAngle) { if (isAllRightAngle) {
return return
} }
const line = new QLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], { const line = addLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
canvas?.add(line)
addLineText(line)
} else { } else {
const guideLine1 = new QLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], { const guideLine1 = addLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
strokeDashArray: [1, 1, 1], strokeDashArray: [1, 1, 1],
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
const guideLine2 = new QLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], { const guideLine2 = addLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
strokeDashArray: [1, 1, 1], strokeDashArray: [1, 1, 1],
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
if (guideLine1.length > 0) {
canvas?.add(guideLine1)
addLineText(guideLine1)
} }
canvas?.add(guideLine2)
addLineText(guideLine2)
}*/
} }
}, [points]) }, [points])

View File

@ -95,7 +95,11 @@ export function useRoofAllocationSetting(setShowRoofAllocationSettingModal) {
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase') const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
try {
splitPolygonWithLines(roofBase) splitPolygonWithLines(roofBase)
} catch (e) {
return
}
roofBase.innerLines.forEach((line) => { roofBase.innerLines.forEach((line) => {
canvas.remove(line) canvas.remove(line)

View File

@ -33,6 +33,11 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod
const [type, setType] = useState(TYPES.EAVES) const [type, setType] = useState(TYPES.EAVES)
const isFix = useRef(false)
const initLines = useRef([])
const [isLoading, setIsLoading] = useState(false)
const buttons = [ const buttons = [
{ id: 1, name: getMessage('eaves'), type: TYPES.EAVES }, { id: 1, name: getMessage('eaves'), type: TYPES.EAVES },
{ id: 2, name: getMessage('gable'), type: TYPES.GABLE }, { id: 2, name: getMessage('gable'), type: TYPES.GABLE },
@ -46,15 +51,20 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod
if (!outerLineFix || outerLines.length === 0) { if (!outerLineFix || outerLines.length === 0) {
swalFire({ text: '외벽선이 없습니다.' }) swalFire({ text: '외벽선이 없습니다.' })
setShowRoofShapePassivitySettingModal(false) setShowRoofShapePassivitySettingModal(false)
return
} }
setIsLoading(true)
}, []) }, [])
useEffect(() => { useEffect(() => {
if (!isLoading) return
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine') const wallLines = canvas.getObjects().filter((obj) => obj.name === 'wallLine')
canvas.remove(wallLines)
canvas?.remove(...wallLines)
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
initLines.current = outerLines.map((line) => ({ ...line }))
outerLines.forEach((outerLine, idx) => { outerLines.forEach((outerLine, idx) => {
if (idx === 0) { if (idx === 0) {
currentLineRef.current = outerLine currentLineRef.current = outerLine
@ -66,10 +76,11 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod
canvas?.renderAll() canvas?.renderAll()
return () => { return () => {
handleLineToPolygon()
canvas?.discardActiveObject() canvas?.discardActiveObject()
initEvent() initEvent()
} }
}, []) }, [isLoading])
useEffect(() => { useEffect(() => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
@ -166,6 +177,14 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod
} }
const handleSave = () => { const handleSave = () => {
isFix.current = true
handleLineToPolygon()
setShowRoofShapePassivitySettingModal(false)
}
const handleLineToPolygon = () => {
const roofBases = canvas.getObjects().filter((obj) => obj.name === 'roofBase')
const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine') const exceptObjs = canvas.getObjects().filter((obj) => obj.name !== 'outerLine' && obj.parent?.name !== 'outerLine')
const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') const lines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
exceptObjs.forEach((obj) => { exceptObjs.forEach((obj) => {
@ -176,13 +195,28 @@ export function useRoofShapePassivitySetting(setShowRoofShapePassivitySettingMod
hideLine(line) hideLine(line)
}) })
const wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' }) let wall
if (isFix.current) {
wall = addPolygonByLines(lines, { name: 'wallLine', fill: 'transparent', stroke: 'black' })
} else {
// 그냥 닫을 경우 처리
wall = addPolygonByLines([...initLines.current], { name: 'wallLine', fill: 'transparent', stroke: 'black' })
lines.forEach((line, idx) => {
line.attributes = initLines.current[idx].attributes
})
}
wall.lines = [...lines] wall.lines = [...lines]
// 기존 그려진 지붕이 없다면
if (isFix.current) {
// 완료 한 경우에는 지붕까지 그려줌
const roof = drawRoofPolygon(wall) const roof = drawRoofPolygon(wall)
canvas.renderAll()
setShowRoofShapePassivitySettingModal(false)
} }
canvas.renderAll()
}
return { handleSave, handleConfirm, buttons, type, setType, TYPES, offsetRef, pitchRef, handleRollback } return { handleSave, handleConfirm, buttons, type, setType, TYPES, offsetRef, pitchRef, handleRollback }
} }

View File

@ -244,8 +244,13 @@ export function useRoofShapeSetting(setShowRoofShapeSettingModal) {
} }
} }
// 기존 wallLine 제거 // 기존 wallLine, roofBase 제거
canvas?.remove(canvas.getObjects().filter((obj) => obj.name === 'wallLine')) canvas
.getObjects()
.filter((obj) => obj.name === 'wallLine' || obj.name === 'roofBase')
.forEach((line) => {
canvas.remove(line)
})
const polygon = addPolygonByLines(outerLines, { name: 'wallLine' }) const polygon = addPolygonByLines(outerLines, { name: 'wallLine' })
polygon.lines = [...outerLines] polygon.lines = [...outerLines]

View File

@ -1,4 +1,4 @@
import { canvasState } from '@/store/canvasAtom' import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil' import { useRecoilValue } from 'recoil'
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
@ -21,6 +21,8 @@ export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) {
const arrow1Ref = useRef(null) const arrow1Ref = useRef(null)
const arrow2Ref = useRef(null) const arrow2Ref = useRef(null)
const currentObject = useRecoilValue(currentObjectState)
const [isLoading, setIsLoading] = useState(false) const [isLoading, setIsLoading] = useState(false)
const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => { const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => {
@ -87,6 +89,7 @@ export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) {
if (!isLoading) { if (!isLoading) {
return return
} }
canvas?.discardActiveObject()
removeOuterLineEditCircle() removeOuterLineEditCircle()
addCanvasMouseEventListener('mouse:down', mouseDown) addCanvasMouseEventListener('mouse:down', mouseDown)
if (type === TYPES.WALL_LINE_EDIT) { if (type === TYPES.WALL_LINE_EDIT) {
@ -94,6 +97,20 @@ export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) {
} }
}, [type]) }, [type])
useEffect(() => {
canvas
.getObjects()
.filter((obj) => obj.name === 'outerLine')
.forEach((line) => {
line.set({ stroke: 'black' })
})
if (currentObject?.name === 'outerLine') {
currentObject.set({ stroke: '#EA10AC' })
canvas.renderAll()
}
}, [currentObject])
const removeOuterLineEditCircle = () => { const removeOuterLineEditCircle = () => {
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'outerLineEditCircleStart' || obj.name === 'outerLineEditCircleEnd')) canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'outerLineEditCircleStart' || obj.name === 'outerLineEditCircleEnd'))
} }
@ -106,7 +123,6 @@ export function useWallLineOffsetSetting(setShowWallLineOffsetSettingModal) {
} }
currentWallLineRef.current = e.target currentWallLineRef.current = e.target
console.log(currentWallLineRef.current.idx, currentWallLineRef.current.direction)
if (type === TYPES.WALL_LINE_EDIT) { if (type === TYPES.WALL_LINE_EDIT) {
addCircleByLine(currentWallLineRef.current) addCircleByLine(currentWallLineRef.current)
} }

View File

@ -232,11 +232,11 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) {
return return
} }
/*if (lastPoint.x === firstPoint.x && lastPoint.y === firstPoint.y) { if (Math.abs(lastPoint.x - firstPoint.x) < 1 && Math.abs(lastPoint.y - firstPoint.y) < 1) {
return return
} }
if (lastPoint.x === firstPoint.x || lastPoint.y === firstPoint.y) { if (Math.abs(lastPoint.x - firstPoint.x) < 1 || Math.abs(lastPoint.y - firstPoint.y) < 1) {
let isAllRightAngle = true let isAllRightAngle = true
const firstPoint = points[0] const firstPoint = points[0]
@ -255,38 +255,27 @@ export function usePlacementShapeDrawing(setShowPlaceShapeDrawingModal) {
if (isAllRightAngle) { if (isAllRightAngle) {
return return
} }
const line = new QLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], { const line = addLine([lastPoint.x, lastPoint.y, firstPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
selectable: false, selectable: false,
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
canvas?.add(line)
addLineText(line)
} else { } else {
const guideLine1 = new QLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], { const guideLine1 = addLine([lastPoint.x, lastPoint.y, lastPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
strokeDashArray: [1, 1, 1], strokeDashArray: [1, 1, 1],
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
const guideLine2 = new QLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], { const guideLine2 = addLine([guideLine1.x2, guideLine1.y2, firstPoint.x, firstPoint.y], {
stroke: 'grey', stroke: 'grey',
strokeWidth: 1, strokeWidth: 1,
strokeDashArray: [1, 1, 1], strokeDashArray: [1, 1, 1],
name: 'helpGuideLine', name: 'helpGuideLine',
}) })
if (guideLine1.length > 0) {
canvas?.add(guideLine1)
addLineText(guideLine1)
} }
canvas?.add(guideLine2)
addLineText(guideLine2)
}*/
} }
}, [points]) }, [points])

View File

@ -40,59 +40,59 @@ export function useAxios(lang = '') {
// response 추가 로직 // response 추가 로직
axios.interceptors.request.use(undefined, (error) => {}) axios.interceptors.request.use(undefined, (error) => {})
const get = async ({ url }) => { const get = async ({ url, option = {} }) => {
return await getInstances(url) return await getInstances(url)
.get(url) .get(url, option)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
} }
const promiseGet = async ({ url }) => { const promiseGet = async ({ url, option = {} }) => {
return await getInstances(url).get(url) return await getInstances(url).get(url, option)
} }
const post = async ({ url, data }) => { const post = async ({ url, data, option = {} }) => {
return await getInstances(url) return await getInstances(url)
.post(url, data) .post(url, data, option)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
} }
const promisePost = async ({ url, data }) => { const promisePost = async ({ url, data, option = {} }) => {
return await getInstances(url).post(url, data) return await getInstances(url).post(url, data, option)
} }
const put = async ({ url, data }) => { const put = async ({ url, data, option = {} }) => {
return await getInstances(url) return await getInstances(url)
.put(url, data) .put(url, data, option)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
} }
const promisePut = async ({ url, data }) => { const promisePut = async ({ url, data, option = {} }) => {
return await getInstances(url).put(url, data) return await getInstances(url).put(url, data, option)
} }
const patch = async ({ url, data }) => { const patch = async ({ url, data, option = {} }) => {
return await getInstances(url) return await getInstances(url)
.patch(url, data) .patch(url, data, option)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
} }
const promisePatch = async ({ url, data }) => { const promisePatch = async ({ url, data, option = {} }) => {
return await getInstances(url).patch(url, data) return await getInstances(url).patch(url, data, option)
} }
const del = async ({ url }) => { const del = async ({ url, option = {} }) => {
return await getInstances(url) return await getInstances(url)
.delete(url) .delete(url, option)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
} }
const promiseDel = async ({ url }) => { const promiseDel = async ({ url, option = {} }) => {
return await getInstances(url).delete(url) return await getInstances(url).delete(url, option)
} }
return { get, promiseGet, post, promisePost, put, promisePut, patch, promisePatch, del, promiseDel } return { get, promiseGet, post, promisePost, put, promisePut, patch, promisePatch, del, promiseDel }

View File

@ -2,7 +2,7 @@ import { useEffect, useRef } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasState, canvasZoomState, currentMenuState, textModeState } from '@/store/canvasAtom' import { canvasState, canvasZoomState, currentMenuState, textModeState } from '@/store/canvasAtom'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { calculateDistance, distanceBetweenPoints, findClosestPoint } from '@/util/canvas-util' import { calculateDistance, calculateIntersection, distanceBetweenPoints, findClosestPoint, polygonToTurfPolygon } from '@/util/canvas-util'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
import { useDotLineGrid } from '@/hooks/useDotLineGrid' import { useDotLineGrid } from '@/hooks/useDotLineGrid'
import { useTempGrid } from '@/hooks/useTempGrid' import { useTempGrid } from '@/hooks/useTempGrid'
@ -43,7 +43,6 @@ export function useEvent() {
//default Event 추가 //default Event 추가
addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent) addCanvasMouseEventListener('mouse:move', defaultMouseMoveEvent)
addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent) addCanvasMouseEventListener('mouse:out', defaultMouseOutEvent)
addDocumentEventListener('keydown', document, defaultKeyboardEvent)
addDocumentEventListener('contextmenu', document, defaultContextMenuEvent) addDocumentEventListener('contextmenu', document, defaultContextMenuEvent)
if (adsorptionPointAddMode) { if (adsorptionPointAddMode) {
addCanvasMouseEventListener('mouse:down', adsorptionPointAddModeStateEvent) addCanvasMouseEventListener('mouse:down', adsorptionPointAddModeStateEvent)
@ -152,6 +151,17 @@ export function useEvent() {
} }
} }
try {
const helpGuideLines = canvas.getObjects().filter((obj) => obj.name === 'helpGuideLine')
if (helpGuideLines.length === 2) {
const guideIntersectionPoint = calculateIntersection(helpGuideLines[0], helpGuideLines[1])
if (guideIntersectionPoint && distanceBetweenPoints(guideIntersectionPoint, pointer) <= adsorptionRange) {
arrivalPoint = guideIntersectionPoint
}
}
} catch (e) {}
const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], { const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], {
stroke: 'red', stroke: 'red',
strokeWidth: 1, strokeWidth: 1,

View File

@ -14,7 +14,7 @@ export const useLine = () => {
fontFamily: fontFamily, fontFamily: fontFamily,
}) })
if (line.length === 0) { if (line.length < 1) {
return null return null
} }

View File

@ -1,3 +1,4 @@
import { useEffect, useState } from 'react'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
@ -5,10 +6,13 @@ import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
export function usePlan() { export function usePlan() {
const [planNum, setPlanNum] = useState(0)
const [canvas, setCanvas] = useRecoilState(canvasState) const [canvas, setCanvas] = useRecoilState(canvasState)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) // DB에 저장된 plan
const [plans, setPlans] = useRecoilState(plansState) const [plans, setPlans] = useRecoilState(plansState) // 전체 plan (DB에 저장된 plan + 저장 안된 새로운 plan)
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { get, promisePost, promisePut, promiseDel } = useAxios() const { get, promisePost, promisePut, promiseDel } = useAxios()
@ -72,6 +76,9 @@ export function usePlan() {
// }, 1000) // }, 1000)
} }
/**
* 현재 캔버스에 그려진 데이터를 추출
*/
const currentCanvasData = () => { const currentCanvasData = () => {
removeMouseLines() removeMouseLines()
return addCanvas() return addCanvas()
@ -81,8 +88,7 @@ export function usePlan() {
* 실시간 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 * 실시간 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단
*/ */
const checkModifiedCanvasPlan = () => { const checkModifiedCanvasPlan = () => {
removeMouseLines() const canvasStatus = currentCanvasData()
const canvasStatus = addCanvas()
const initPlanData = initCanvasPlans.find((plan) => plan.id === currentCanvasPlan.id) const initPlanData = initCanvasPlans.find((plan) => plan.id === currentCanvasPlan.id)
if (!initPlanData) { if (!initPlanData) {
@ -90,17 +96,12 @@ export function usePlan() {
return JSON.parse(canvasStatus).objects.length > 0 return JSON.parse(canvasStatus).objects.length > 0
} else { } else {
// 저장된 캔버스 // 저장된 캔버스
if (canvasStatus === initPlanData.canvasStatus) {
return false
} else {
// 각각 object들의 id 목록을 추출하여 비교 // 각각 object들의 id 목록을 추출하여 비교
const canvasObjsIds = getObjectIds(JSON.parse(canvasStatus).objects) const canvasObjsIds = getObjectIds(JSON.parse(canvasStatus).objects)
const dbObjsIds = getObjectIds(JSON.parse(initPlanData.canvasStatus).objects) const dbObjsIds = getObjectIds(JSON.parse(initPlanData.canvasStatus).objects)
return canvasObjsIds.length !== dbObjsIds.length || !canvasObjsIds.every((id, index) => id === dbObjsIds[index]) return canvasObjsIds.length !== dbObjsIds.length || !canvasObjsIds.every((id, index) => id === dbObjsIds[index])
} }
} }
}
const getObjectIds = (objects) => { const getObjectIds = (objects) => {
return objects return objects
.filter((obj) => obj.hasOwnProperty('id')) .filter((obj) => obj.hasOwnProperty('id'))
@ -112,9 +113,6 @@ export function usePlan() {
* DB에 저장된 데이터를 canvas에서 사용할 있도록 포맷화 * DB에 저장된 데이터를 canvas에서 사용할 있도록 포맷화
*/ */
const dbToCanvasFormat = (cs) => { const dbToCanvasFormat = (cs) => {
// return JSON.stringify(cs.replace(/##/g, '"')) //.replace(/\\/g, ''))//.slice(1, -1))
// JSON.stringify()를 사용하면 "가 \"로 바뀐다. 따라서, JSON.stringify를 제거
// canvasToDbFormat()에서 \\의 상황을 없앴으므로 replace(/\\/g, '')를 제거
return cs.replace(/##/g, '"') return cs.replace(/##/g, '"')
} }
@ -122,92 +120,24 @@ export function usePlan() {
* canvas의 데이터를 DB에 저장할 있도록 포맷화 * canvas의 데이터를 DB에 저장할 있도록 포맷화
*/ */
const canvasToDbFormat = (cs) => { const canvasToDbFormat = (cs) => {
// return JSON.stringify(cs).replace(/"/g, '##')
// addCanvas()에서 JSON.stringify()를 거쳐서 나오는데, 또 감싸버려서 \가 \\로 된다. 따라서, JSON.stringify를 제거
return cs.replace(/"/g, '##') return cs.replace(/"/g, '##')
} }
/** /**
* 페이지 캔버스를 저장하는 함수 * 페이지 캔버스를 저장
*
* 1. 신규 저장 : POST
* param(body) : userId, objectNo, canvasStatus
* 2. 수정 저장 : PUT
* param(body) : id, canvasStatus
*/ */
const saveCanvas = async (userId) => { const saveCanvas = async (userId) => {
removeMouseLines() const canvasStatus = currentCanvasData()
const canvasStatus = addCanvas() initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)
? await putCanvasStatus(canvasStatus)
if (initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id)) { : await postCanvasStatus(userId, canvasStatus)
// canvas 수정
const planData = {
id: currentCanvasPlan.id,
canvasStatus: canvasToDbFormat(canvasStatus),
}
return await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => {
swalFire({ text: getMessage('common.message.save') })
// console.log('[PUT] canvas-statuses res :::::::: %o', 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)))
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
// console.error('[PUT] canvas-statuses error :::::::: %o', error)
})
} else {
// canvas 신규 등록
const planData = {
userId: userId,
imageName: 'image_name', // api 필수항목이여서 임시로 넣음, 이후 삭제 필요
objectNo: currentCanvasPlan.objectNo,
canvasStatus: canvasToDbFormat(canvasStatus),
}
return await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => {
swalFire({ text: getMessage('common.message.save') })
// console.log('[POST] canvas-statuses response :::::::: %o', res)
setInitCanvasPlans((initCanvasPlans) => [
...initCanvasPlans,
{
id: res.data,
name: currentCanvasPlan.objectNo + '-' + res.data,
userId: userId,
canvasStatus: canvasStatus,
isNew: currentCanvasPlan.id,
},
])
setPlans((plans) =>
plans.map((plan) =>
plan.id === currentCanvasPlan.id
? {
...plan,
id: res.data,
name: currentCanvasPlan.objectNo + '-' + res.data,
userId: userId,
canvasStatus: canvasStatus,
isNew: currentCanvasPlan.id,
}
: plan,
),
)
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
// console.error('[POST] canvas-statuses res error :::::::: %o', error)
})
}
} }
/** /**
* objectNo에 해당하는 canvas 목록을 조회하는 함수 * objectNo에 해당하는 canvas 목록을 조회
*/ */
const getCanvasByObjectNo = async (userId, objectNo) => { const getCanvasByObjectNo = async (userId, objectNo) => {
// console.log(`[GET] objectNo: ${objectNo} / userId: ${userId}`)
return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) => return get({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}/${userId}` }).then((res) =>
res.map((item) => ({ res.map((item) => ({
id: item.id, id: item.id,
@ -220,27 +150,192 @@ export function usePlan() {
} }
/** /**
* id에 해당하는 canvas 데이터를 삭제하는 함수 * canvas 데이터를 추가
*/
const postCanvasStatus = async (userId, canvasStatus) => {
const planData = {
userId: userId,
imageName: 'image_name', // api 필수항목이여서 임시로 넣음, 이후 삭제 필요
objectNo: currentCanvasPlan.objectNo,
canvasStatus: canvasToDbFormat(canvasStatus),
}
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => {
swalFire({ text: getMessage('plan.message.save') })
setInitCanvasPlans((initCanvasPlans) => [...initCanvasPlans, { id: res.data, canvasStatus: canvasStatus }])
setPlans((plans) =>
plans.map((plan) =>
plan.id === currentCanvasPlan.id
? {
...plan,
id: res.data,
name: currentCanvasPlan.objectNo + '-' + res.data,
canvasStatus: canvasStatus,
}
: plan,
),
)
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
})
}
/**
* id에 해당하는 canvas 데이터를 수정
*/
const putCanvasStatus = async (canvasStatus) => {
const planData = {
id: currentCanvasPlan.id,
canvasStatus: canvasToDbFormat(canvasStatus),
}
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => {
swalFire({ text: getMessage('plan.message.save') })
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)))
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
})
}
/**
* id에 해당하는 canvas 데이터를 삭제
*/ */
const delCanvasById = (id) => { const delCanvasById = (id) => {
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` }) return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-id/${id}` })
} }
/** /**
* objectNo에 해당하는 canvas 데이터들을 삭제하는 함수 * objectNo에 해당하는 canvas 데이터들을 삭제
*/ */
const delCanvasByObjectNo = (objectNo) => { const delCanvasByObjectNo = (objectNo) => {
return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` }) return promiseDel({ url: `/api/canvas-management/canvas-statuses/by-object/${objectNo}` })
} }
/**
* plan 이동
* 현재 plan의 작업상태를 확인, 저장 이동
*/
const handleCurrentPlan = (userId, newCurrentId) => {
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
if (currentCanvasPlan?.id && checkModifiedCanvasPlan()) {
swalFire({
text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
type: 'confirm',
confirmFn: async () => {
await saveCanvas(userId)
updateCurrentPlan(newCurrentId)
},
denyFn: () => {
updateCurrentPlan(newCurrentId)
},
})
} else {
updateCurrentPlan(newCurrentId)
}
}
}
const updateCurrentPlan = (newCurrentId) => {
setPlans((plans) =>
plans.map((plan) => {
return { ...plan, isCurrent: plan.id === newCurrentId }
}),
)
}
useEffect(() => {
setCurrentCanvasPlan(plans.find((plan) => plan.isCurrent) || null)
}, [plans])
/**
* 새로운 plan 생성
* 현재 plan의 데이터가 있을 경우 복제 여부를 확인
*/
const handleAddPlan = (userId, objectNo) => {
JSON.parse(currentCanvasData()).objects.length > 0
? swalFire({
text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.copy'),
type: 'confirm',
confirmFn: () => {
addPlan(userId, objectNo, currentCanvasData())
},
denyFn: () => {
addPlan(userId, objectNo)
},
})
: addPlan(userId, objectNo)
}
const addPlan = (userId, objectNo, canvasStatus = '') => {
const newPlan = {
id: planNum,
name: `Plan ${planNum + 1}`,
objectNo: objectNo,
userId: userId,
canvasStatus: canvasStatus,
}
setPlans([...plans, newPlan])
handleCurrentPlan(userId, planNum)
setPlanNum(planNum + 1)
}
/**
* plan 삭제
*/
const handleDeletePlan = (e, id) => {
e.stopPropagation() // 이벤트 버블링 방지
if (initCanvasPlans.some((plan) => plan.id === id)) {
delCanvasById(id)
.then((res) => {
swalFire({ text: getMessage('plan.message.delete') })
setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id))
setPlans((plans) => plans.filter((plan) => plan.id !== id))
})
.catch((error) => {
swalFire({ text: error.message, icon: 'error' })
})
} else {
setPlans((plans) => plans.filter((plan) => plan.id !== id))
swalFire({ text: getMessage('plan.message.delete') })
}
// 삭제 후 last 데이터에 포커싱
const lastPlan = plans.filter((plan) => plan.id !== id).at(-1)
if (!lastPlan) {
setPlanNum(0)
setCurrentCanvasPlan(null)
} else if (id !== lastPlan.id) {
updateCurrentPlan(lastPlan.id)
}
}
/**
* plan 조회
*/
const loadCanvasPlanData = (userId, objectNo) => {
getCanvasByObjectNo(userId, objectNo).then((res) => {
// console.log('canvas 목록 ', res)
if (res.length > 0) {
setInitCanvasPlans(res)
setPlans(res)
updateCurrentPlan(res.at(-1).id) // last 데이터에 포커싱
setPlanNum(res.length)
} else {
addPlan(userId, objectNo)
}
})
}
return { return {
canvas, canvas,
removeMouseLines, plans,
currentCanvasData,
saveCanvas, saveCanvas,
addCanvas, handleCurrentPlan,
checkModifiedCanvasPlan, handleAddPlan,
getCanvasByObjectNo, handleDeletePlan,
delCanvasById, loadCanvasPlanData,
} }
} }

View File

@ -247,6 +247,11 @@
"modal.object.setting.direction.select": "方向の選択", "modal.object.setting.direction.select": "方向の選択",
"modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。", "modal.placement.surface.setting.info": "ⓘ ①の長さ入力後に対角線の長さを入力すると、②の長さを自動計算します。",
"modal.placement.surface.setting.diagonal.length": "斜めの長さ", "modal.placement.surface.setting.diagonal.length": "斜めの長さ",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
"plan.message.save": "저장되었습니다.",
"plan.message.delete": "삭제되었습니다.",
"setting": "設定", "setting": "設定",
"common.message.no.data": "No data", "common.message.no.data": "No data",
"common.message.no.dataDown": "ダウンロードするデータがありません", "common.message.no.dataDown": "ダウンロードするデータがありません",
@ -335,7 +340,7 @@
"common.message.writeToConfirm": "作成解除を実行しますか?", "common.message.writeToConfirm": "作成解除を実行しますか?",
"common.message.password.init.success": "パスワード [{0}] に初期化されました。", "common.message.password.init.success": "パスワード [{0}] に初期化されました。",
"common.message.no.edit.save": "この文書は変更できません。", "common.message.no.edit.save": "この文書は変更できません。",
"common.require": "필수", "common.require": "必須",
"commons.west": "立つ", "commons.west": "立つ",
"commons.east": "ドン", "commons.east": "ドン",
"commons.south": "立つ", "commons.south": "立つ",
@ -497,6 +502,7 @@
"stuff.planReqPopup.search.period": "期間検索", "stuff.planReqPopup.search.period": "期間検索",
"stuff.planReqPopup.search.schDateGbnS": "提出日", "stuff.planReqPopup.search.schDateGbnS": "提出日",
"stuff.planReqPopup.search.schDateGbnR": "受付日", "stuff.planReqPopup.search.schDateGbnR": "受付日",
"stuff.planReqPopup.error.message1": "設計依頼を選択してください。",
"stuff.search.title": "物件状況", "stuff.search.title": "物件状況",
"stuff.search.btn1": "物件登録", "stuff.search.btn1": "物件登録",
"stuff.search.btn2": "照会", "stuff.search.btn2": "照会",
@ -511,6 +517,11 @@
"stuff.search.period": "期間検索", "stuff.search.period": "期間検索",
"stuff.search.schDateTypeU": "更新日", "stuff.search.schDateTypeU": "更新日",
"stuff.search.schDateTypeR": "登録日", "stuff.search.schDateTypeR": "登録日",
"stuff.search.grid.title": "商品リスト",
"stuff.search.grid.all": "全体",
"stuff.search.grid.selected": "選択",
"stuff.search.grid.schSortTypeR": "最近の登録日",
"stuff.search.grid.schSortTypeU": "最近の更新日",
"stuff.windSelectPopup.title": "風速選択", "stuff.windSelectPopup.title": "風速選択",
"stuff.windSelectPopup.table.selected": "選択", "stuff.windSelectPopup.table.selected": "選択",
"stuff.windSelectPopup.table.windspeed": "風速", "stuff.windSelectPopup.table.windspeed": "風速",

View File

@ -252,6 +252,11 @@
"modal.object.setting.direction.select": "방향 선택", "modal.object.setting.direction.select": "방향 선택",
"modal.placement.surface.setting.info": "ⓘ ①의 길이 입력 후 대각선 길이를 입력하면 ②의 길이를 자동 계산합니다.", "modal.placement.surface.setting.info": "ⓘ ①의 길이 입력 후 대각선 길이를 입력하면 ②의 길이를 자동 계산합니다.",
"modal.placement.surface.setting.diagonal.length": "대각선 길이", "modal.placement.surface.setting.diagonal.length": "대각선 길이",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
"plan.message.save": "저장되었습니다.",
"plan.message.delete": "삭제되었습니다.",
"setting": "설정", "setting": "설정",
"common.message.no.data": "No data", "common.message.no.data": "No data",
"common.message.no.dataDown": "No data to download", "common.message.no.dataDown": "No data to download",
@ -502,6 +507,7 @@
"stuff.planReqPopup.search.period": "기간검색", "stuff.planReqPopup.search.period": "기간검색",
"stuff.planReqPopup.search.schDateGbnS": "제출일", "stuff.planReqPopup.search.schDateGbnS": "제출일",
"stuff.planReqPopup.search.schDateGbnR": "접수일", "stuff.planReqPopup.search.schDateGbnR": "접수일",
"stuff.planReqPopup.error.message1": "설계의뢰를 선택해주세요.",
"stuff.search.title": "물건현황", "stuff.search.title": "물건현황",
"stuff.search.btn1": "신규등록", "stuff.search.btn1": "신규등록",
"stuff.search.btn2": "조회", "stuff.search.btn2": "조회",
@ -516,6 +522,11 @@
"stuff.search.period": "기간검색", "stuff.search.period": "기간검색",
"stuff.search.schDateTypeU": "갱신일", "stuff.search.schDateTypeU": "갱신일",
"stuff.search.schDateTypeR": "등록일", "stuff.search.schDateTypeR": "등록일",
"stuff.search.grid.title": "물건목록",
"stuff.search.grid.all": "전체",
"stuff.search.grid.selected": "선택",
"stuff.search.grid.schSortTypeR": "최근 등록일",
"stuff.search.grid.schSortTypeU": "최근 갱신일",
"stuff.windSelectPopup.title": "풍속선택", "stuff.windSelectPopup.title": "풍속선택",
"stuff.windSelectPopup.table.selected": "선택", "stuff.windSelectPopup.table.selected": "선택",
"stuff.windSelectPopup.table.windspeed": "풍속", "stuff.windSelectPopup.table.windspeed": "풍속",

View File

@ -289,3 +289,8 @@ export const canGridOptionSeletor = selector({
return points.length === 0 || outerLineFix return points.length === 0 || outerLineFix
}, },
}) })
export const globalPitchState = atom({
key: 'globalPitch',
default: 4,
})

View File

@ -16,7 +16,7 @@ export const planReqSearchState = atom({
schStartDt: dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD'), //시작일 schStartDt: dayjs(new Date()).add(-3, 'month').format('YYYY-MM-DD'), //시작일
schEndDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일 schEndDt: dayjs(new Date()).format('YYYY-MM-DD'), //종료일
startRow: 1, startRow: 1,
endRow: 100, endRow: 20,
}, },
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })

View File

@ -18,10 +18,6 @@ export const stuffSearchState = atom({
startRow: 1, startRow: 1,
endRow: 100, endRow: 100,
schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일) schSortType: 'R', //정렬조건 (R:최근등록일 U:최근수정일)
selObject: {
value: '',
label: '',
},
}, },
dangerouslyAllowMutability: true, dangerouslyAllowMutability: true,
}) })

View File

@ -75,8 +75,8 @@
height: 45px; height: 45px;
border-radius: 100px; border-radius: 100px;
padding: 0 20px; padding: 0 20px;
border: 1px solid rgba(255, 255, 255, 0.30); border: 1px solid rgba(255, 255, 255, 0.3);
background: rgba(31, 31, 31, 0.30); background: rgba(31, 31, 31, 0.3);
.main-search { .main-search {
flex: 1; flex: 1;
height: 100%; height: 100%;
@ -110,13 +110,28 @@
flex-direction: column; flex-direction: column;
padding: 40px; padding: 40px;
border-radius: 6px; border-radius: 6px;
background: #FFF; background: #fff;
box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02); box-shadow: 0px 3px 30px 0px rgba(0, 0, 0, 0.02);
&.item01{flex: 1; max-height: 400px;} &.item01 {
&.item02{flex: none; width: 451px; max-height: 400px;} flex: 1;
&.item03{flex: 1;} max-height: 400px;
&.item04{flex: none; width: 351px;} }
&.item05{flex: none; width: 451px;} &.item02 {
flex: none;
width: 451px;
max-height: 400px;
}
&.item03 {
flex: 1;
}
&.item04 {
flex: none;
width: 351px;
}
&.item05 {
flex: none;
width: 451px;
}
.product-item-title-wrap { .product-item-title-wrap {
display: flex; display: flex;
align-items: center; align-items: center;
@ -131,16 +146,26 @@
width: 40px; width: 40px;
height: 40px; height: 40px;
border-radius: 50px; border-radius: 50px;
background: #14324F; background: #14324f;
margin-right: 12px; margin-right: 12px;
background-repeat: no-repeat; background-repeat: no-repeat;
background-size: 22px 22px; background-size: 22px 22px;
background-position: center; background-position: center;
&.ico01{background-image: url(../../public/static/images/main/product_ico01.svg);} &.ico01 {
&.ico02{background-image: url(../../public/static/images/main/product_ico02.svg);} background-image: url(../../public/static/images/main/product_ico01.svg);
&.ico03{background-image: url(../../public/static/images/main/product_ico03.svg);} }
&.ico04{background-image: url(../../public/static/images/main/product_ico04.svg);} &.ico02 {
&.ico05{background-image: url(../../public/static/images/main/product_ico05.svg);} background-image: url(../../public/static/images/main/product_ico02.svg);
}
&.ico03 {
background-image: url(../../public/static/images/main/product_ico03.svg);
}
&.ico04 {
background-image: url(../../public/static/images/main/product_ico04.svg);
}
&.ico05 {
background-image: url(../../public/static/images/main/product_ico05.svg);
}
} }
} }
.more-btn { .more-btn {
@ -156,7 +181,7 @@
overflow: hidden; overflow: hidden;
.recently-list { .recently-list {
.recently-item { .recently-item {
border: 1px solid #F2F2F2; border: 1px solid #f2f2f2;
background-color: transparent; background-color: transparent;
padding: 29.9px 20px; padding: 29.9px 20px;
margin-bottom: 5px; margin-bottom: 5px;
@ -193,7 +218,7 @@
transform: translateY(-50%); transform: translateY(-50%);
width: 1px; width: 1px;
height: 10px; height: 10px;
background-color: #BBB; background-color: #bbb;
} }
&:last-child { &:last-child {
&:after { &:after {
@ -245,9 +270,15 @@
} }
} }
} }
&::-webkit-scrollbar {width: 4px; /* 스크롤바의 너비 */} &::-webkit-scrollbar {
&::-webkit-scrollbar-thumb {background: #697C8F; /* 스크롤바의 색상 */} width: 4px; /* 스크롤바의 너비 */
&::-webkit-scrollbar-track {background: transparent; /*스크롤바 뒷 배경 색상*/} }
&::-webkit-scrollbar-thumb {
background: #697c8f; /* 스크롤바의 색상 */
}
&::-webkit-scrollbar-track {
background: transparent; /*스크롤바 뒷 배경 색상*/
}
} }
.faq-item { .faq-item {
position: relative; position: relative;
@ -300,9 +331,9 @@
padding: 20px; padding: 20px;
text-align: left; text-align: left;
border-radius: 4px; border-radius: 4px;
background-color: #697C8F; background-color: #697c8f;
margin-bottom: 5px; margin-bottom: 5px;
transition: background .17s ease-in-out; transition: background 0.17s ease-in-out;
span { span {
position: relative; position: relative;
display: block; display: block;
@ -333,14 +364,19 @@
.contact-info-list { .contact-info-list {
padding: 25px 30px; padding: 25px 30px;
border-radius: 4px; border-radius: 4px;
background-color: #F4F4F7; background-color: #f4f4f7;
.info-item { .info-item {
display: flex; display: flex;
align-items: center; align-items: center;
padding: 15px 0; padding: 15px 0;
border-bottom: 1px solid #fff; border-bottom: 1px solid #fff;
&:first-child{padding-top: 0;} &:first-child {
&:last-child{padding-bottom: 0; border: none;} padding-top: 0;
}
&:last-child {
padding-bottom: 0;
border: none;
}
.icon-box { .icon-box {
display: flex; display: flex;
margin-right: 12px; margin-right: 12px;
@ -388,7 +424,7 @@
color: #364864; color: #364864;
font-weight: 400; font-weight: 400;
padding-bottom: 30px; padding-bottom: 30px;
border-bottom: 1px solid #E5E9EF; border-bottom: 1px solid #e5e9ef;
span { span {
display: block; display: block;
font-weight: 600; font-weight: 600;
@ -404,7 +440,7 @@
position: relative; position: relative;
display: flex; display: flex;
align-items: center; align-items: center;
border: 1px solid #E5E9EF; border: 1px solid #e5e9ef;
height: 45px; height: 45px;
padding-left: 40px; padding-left: 40px;
padding-right: 15px; padding-right: 15px;
@ -419,7 +455,7 @@
&::placeholder { &::placeholder {
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
color: #D1D7E0; color: #d1d7e0;
} }
} }
&::before { &::before {
@ -476,19 +512,19 @@
display: block; display: block;
width: 100%; width: 100%;
height: 45px; height: 45px;
background-color: #5C6773; background-color: #5c6773;
color: #fff; color: #fff;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
border-radius: 4px; border-radius: 4px;
transition: background .15s ease-in-out; transition: background 0.15s ease-in-out;
&:hover { &:hover {
background-color: #717e8d; background-color: #717e8d;
} }
&.light { &.light {
background-color: #fff; background-color: #fff;
border: 1px solid #5C6773; border: 1px solid #5c6773;
color: #5C6773; color: #5c6773;
} }
} }
.login-btn-box { .login-btn-box {
@ -561,17 +597,16 @@
width: 22px; width: 22px;
height: 22px; height: 22px;
top: -1px; top: -1px;
border-color: #A8B6C7; border-color: #a8b6c7;
border-radius: 3px; border-radius: 3px;
transition: background .05s ease-in-out; transition: background 0.05s ease-in-out;
} }
} }
input[type='checkbox']:checked + label::before {
border-color: #a8b6c7;
background-color: #a8b6c7;
} }
input[type=checkbox]:checked + label::before{ input[type='checkbox']:checked + label::after {
border-color: #A8B6C7;
background-color: #A8B6C7;
}
input[type=checkbox]:checked + label::after{
border-color: #fff; border-color: #fff;
width: 7px; width: 7px;
height: 11px; height: 11px;
@ -579,6 +614,7 @@
left: 1px; left: 1px;
} }
} }
}
// 회원가입 // 회원가입
.center-page-wrap { .center-page-wrap {
@ -587,7 +623,7 @@
justify-content: center; justify-content: center;
width: 100%; width: 100%;
min-height: 100vh; min-height: 100vh;
background-color: #F4F4F7; background-color: #f4f4f7;
overflow-x: hidden; overflow-x: hidden;
.center-page-inner { .center-page-inner {
width: 100%; width: 100%;
@ -612,7 +648,6 @@
max-width: 1000px; max-width: 1000px;
} }
} }
} }
// 회원가입 완료 // 회원가입 완료
@ -633,14 +668,14 @@
.complete-email-wrap { .complete-email-wrap {
padding: 36px 30px; padding: 36px 30px;
border-radius: 2px; border-radius: 2px;
background: #F4F4F7; background: #f4f4f7;
margin-bottom: 20px; margin-bottom: 20px;
.email-info { .email-info {
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
color: #000; color: #000;
span { span {
color: #204AF4; color: #204af4;
font-weight: 500; font-weight: 500;
} }
} }

View File

@ -5,12 +5,24 @@ $pop-normal-size: 12px;
$alert-color: #101010; $alert-color: #101010;
@keyframes mountpop { @keyframes mountpop {
from{opacity: 0; scale: 0.95;} from {
to{opacity: 1; scale: 1;} opacity: 0;
scale: 0.95;
}
to {
opacity: 1;
scale: 1;
}
} }
@keyframes unmountpop { @keyframes unmountpop {
from{opacity: 1; scale: 1;} from {
to{opacity: 0; scale: 0.95;} opacity: 1;
scale: 1;
}
to {
opacity: 0;
scale: 0.95;
}
} }
.normal-font { .normal-font {
@ -34,6 +46,9 @@ $alert-color: #101010;
border-radius: 4px; border-radius: 4px;
background-color: #272727; background-color: #272727;
z-index: 9999999; z-index: 9999999;
&.xsm {
width: 200px;
}
&.xxxm { &.xxxm {
width: 240px; width: 240px;
} }
@ -74,10 +89,10 @@ $alert-color: #101010;
width: 800px; width: 800px;
} }
&.mount { &.mount {
animation: mountpop .17s ease-in-out forwards; animation: mountpop 0.17s ease-in-out forwards;
} }
&.unmount { &.unmount {
animation: unmountpop .17s ease-in-out forwards; animation: unmountpop 0.17s ease-in-out forwards;
} }
&.alert { &.alert {
position: absolute; position: absolute;
@ -182,7 +197,7 @@ $alert-color: #101010;
} }
} }
.outer-line-wrap { .outer-line-wrap {
border-top: 1px solid #3C3C3C; border-top: 1px solid #3c3c3c;
margin-top: 10px; margin-top: 10px;
padding-top: 15px; padding-top: 15px;
margin-bottom: 15px; margin-bottom: 15px;
@ -204,7 +219,7 @@ $alert-color: #101010;
.adsorption-point { .adsorption-point {
display: flex; display: flex;
align-items: center; align-items: center;
background-color: #3A3A3A; background-color: #3a3a3a;
border-radius: 3px; border-radius: 3px;
padding-left: 11px; padding-left: 11px;
overflow: hidden; overflow: hidden;
@ -225,7 +240,7 @@ $alert-color: #101010;
&.act { &.act {
i { i {
color: $pop-color; color: $pop-color;
background-color: #1083E3; background-color: #1083e3;
} }
} }
} }
@ -245,7 +260,7 @@ $alert-color: #101010;
display: flex; display: flex;
align-items: center; align-items: center;
background-color: transparent; background-color: transparent;
border: 1px solid #3D3D3D; border: 1px solid #3d3d3d;
border-radius: 2px; border-radius: 2px;
padding: 15px 10px; padding: 15px 10px;
gap: 20px; gap: 20px;
@ -272,7 +287,9 @@ $alert-color: #101010;
} }
} }
.select-form { .select-form {
.sort-select{width: 100%;} .sort-select {
width: 100%;
}
} }
.grid-select { .grid-select {
flex: 1; flex: 1;
@ -317,7 +334,6 @@ $alert-color: #101010;
color: $pop-color; color: $pop-color;
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
padding-bottom: 15px; padding-bottom: 15px;
} }
.grid-direction { .grid-direction {
display: flex; display: flex;
@ -334,11 +350,17 @@ $alert-color: #101010;
background-position: center; background-position: center;
background-size: 16px 15px; background-size: 16px 15px;
border-radius: 50%; border-radius: 50%;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
opacity: 0.6; opacity: 0.6;
&.down{transform: rotate(180deg);} &.down {
&.left{transform: rotate(-90deg);} transform: rotate(180deg);
&.right{transform: rotate(90deg);} }
&.left {
transform: rotate(-90deg);
}
&.right {
transform: rotate(90deg);
}
&:hover, &:hover,
&.act { &.act {
opacity: 1; opacity: 1;
@ -414,10 +436,11 @@ $alert-color: #101010;
} }
&.light { &.light {
padding: 0; padding: 0;
th,td{ th,
td {
color: $alert-color; color: $alert-color;
border-bottom: none; border-bottom: none;
border-top: 1px solid #EFEFEF; border-top: 1px solid #efefef;
} }
th { th {
padding: 14px 0; padding: 14px 0;
@ -450,7 +473,7 @@ $alert-color: #101010;
gap: 20px; gap: 20px;
} }
.select-wrap { .select-wrap {
div{ .sort-select {
width: 100%; width: 100%;
} }
} }
@ -541,7 +564,7 @@ $alert-color: #101010;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
width: 50%; width: 50%;
background-color: #3D3D3D; background-color: #3d3d3d;
border-radius: 2px; border-radius: 2px;
} }
} }
@ -549,7 +572,7 @@ $alert-color: #101010;
// 외벽선 속성 설정 // 외벽선 속성 설정
.properties-guide { .properties-guide {
font-size: $pop-normal-size; font-size: $pop-normal-size;
color: #AAA; color: #aaa;
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
margin-bottom: 14px; margin-bottom: 14px;
} }
@ -578,17 +601,17 @@ $alert-color: #101010;
color: #fff; color: #fff;
font-weight: 700; font-weight: 700;
border-radius: 2px; border-radius: 2px;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.green { &.green {
background-color: #305941; background-color: #305941;
border: 1px solid #45CD7D; border: 1px solid #45cd7d;
&:hover { &:hover {
background-color: #3a6b4e; background-color: #3a6b4e;
} }
} }
&.blue { &.blue {
background-color: #2E5360; background-color: #2e5360;
border: 1px solid #3FBAE6; border: 1px solid #3fbae6;
&:hover { &:hover {
background-color: #365f6e; background-color: #365f6e;
} }
@ -610,8 +633,8 @@ $alert-color: #101010;
justify-content: center; justify-content: center;
width: 100%; width: 100%;
padding: 13px; padding: 13px;
background-color: #3D3D3D; background-color: #3d3d3d;
transition: background .15s ease-in-out; transition: background 0.15s ease-in-out;
img { img {
max-width: 100%; max-width: 100%;
} }
@ -622,13 +645,17 @@ $alert-color: #101010;
color: $pop-color; color: $pop-color;
margin-top: 10px; margin-top: 10px;
text-align: center; text-align: center;
transition: color .15s ease-in-out; transition: color 0.15s ease-in-out;
} }
.shape-menu-box { .shape-menu-box {
&.act, &.act,
&:hover { &:hover {
.shape-box{background-color: #008BFF;} .shape-box {
.shape-title{color: #008BFF;} background-color: #008bff;
}
.shape-title {
color: #008bff;
}
} }
} }
} }
@ -643,7 +670,7 @@ $alert-color: #101010;
} }
.discrimination-box { .discrimination-box {
padding: 16px 12px; padding: 16px 12px;
border: 1px solid #3D3D3D; border: 1px solid #3d3d3d;
border-radius: 2px; border-radius: 2px;
} }
@ -676,12 +703,12 @@ $alert-color: #101010;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 5px; padding: 5px;
background-color: #3D3D3D; background-color: #3d3d3d;
border: 1px solid #3D3D3D; border: 1px solid #3d3d3d;
border-radius: 2px; border-radius: 2px;
cursor: pointer; cursor: pointer;
&.act { &.act {
border: 1px solid #ED0004; border: 1px solid #ed0004;
} }
} }
&:last-child { &:last-child {
@ -780,7 +807,7 @@ $alert-color: #101010;
border: 1px solid #646464; border: 1px solid #646464;
border-radius: 2px; border-radius: 2px;
padding: 0 10px; padding: 0 10px;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
i { i {
height: 15px; height: 15px;
display: block; display: block;
@ -788,7 +815,7 @@ $alert-color: #101010;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.allocation01 { &.allocation01 {
background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg);
width: 15px; width: 15px;
@ -830,9 +857,9 @@ $alert-color: #101010;
margin-bottom: 10px; margin-bottom: 10px;
.shape-menu-box { .shape-menu-box {
border-radius: 2px; border-radius: 2px;
background-color: #3D3D3D; background-color: #3d3d3d;
padding: 8px; padding: 8px;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
.shape-box { .shape-box {
display: flex; display: flex;
justify-content: center; justify-content: center;
@ -845,7 +872,7 @@ $alert-color: #101010;
} }
&.act, &.act,
&:hover { &:hover {
background-color: #008BFF; background-color: #008bff;
} }
} }
} }
@ -856,23 +883,32 @@ $alert-color: #101010;
justify-content: center; justify-content: center;
gap: 5px; gap: 5px;
padding: 5px; padding: 5px;
background-color: #3D3D3D; background-color: #3d3d3d;
margin-bottom: 24px; margin-bottom: 24px;
.library-btn { .library-btn {
width: 30px; width: 30px;
height: 30px; height: 30px;
border: 1px solid #6C6C6C; border: 1px solid #6c6c6c;
border-radius: 2px; border-radius: 2px;
background-color: transparent; background-color: transparent;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.ico01{background-image: url(../../public/static/images/canvas/shape_labrary01.svg); background-size: 14px 14px;} &.ico01 {
&.ico02{background-image: url(../../public/static/images/canvas/shape_labrary02.svg); background-size: 13px 17px;} background-image: url(../../public/static/images/canvas/shape_labrary01.svg);
&.ico03{background-image: url(../../public/static/images/canvas/shape_labrary03.svg); background-size: 17px 13px;} background-size: 14px 14px;
}
&.ico02 {
background-image: url(../../public/static/images/canvas/shape_labrary02.svg);
background-size: 13px 17px;
}
&.ico03 {
background-image: url(../../public/static/images/canvas/shape_labrary03.svg);
background-size: 17px 13px;
}
&:hover { &:hover {
border-color: #1083E3; border-color: #1083e3;
background-color: #1083E3; background-color: #1083e3;
} }
} }
} }
@ -883,7 +919,7 @@ $alert-color: #101010;
.plane-box { .plane-box {
padding: 10px; padding: 10px;
border-radius: 2px; border-radius: 2px;
background-color: #3D3D3D; background-color: #3d3d3d;
.plane-box-tit { .plane-box-tit {
font-size: $pop-normal-size; font-size: $pop-normal-size;
font-weight: 600; font-weight: 600;
@ -955,11 +991,27 @@ $alert-color: #101010;
position: absolute; position: absolute;
font-size: 12px; font-size: 12px;
font-weight: 500; font-weight: 500;
color: #B1B1B1; color: #b1b1b1;
&.top{top: 0; left: 50%; transform: translateX(-50%);} &.top {
&.right{top: 50%; right: 0; transform: translateY(-50%);} top: 0;
&.bottom{bottom: 0; left: 50%; transform: translateX(-50%);} left: 50%;
&.left{top: 50%; left: 0; transform: translateY(-50%);} transform: translateX(-50%);
}
&.right {
top: 50%;
right: 0;
transform: translateY(-50%);
}
&.bottom {
bottom: 0;
left: 50%;
transform: translateX(-50%);
}
&.left {
top: 50%;
left: 0;
transform: translateY(-50%);
}
} }
.plane-btn { .plane-btn {
position: absolute; position: absolute;
@ -971,11 +1023,27 @@ $alert-color: #101010;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center; background-position: center;
border-radius: 50%; border-radius: 50%;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.up{top: 22px; left: 50%; transform: translateX(-50%);} &.up {
&.right{top: 50%; right: 32px; transform: translateY(-50%) rotate(90deg);} top: 22px;
&.down{bottom: 22px; left: 50%; transform: translateX(-50%) rotate(180deg);} left: 50%;
&.left{top: 50%; left: 32px; transform: translateY(-50%) rotate(270deg);} transform: translateX(-50%);
}
&.right {
top: 50%;
right: 32px;
transform: translateY(-50%) rotate(90deg);
}
&.down {
bottom: 22px;
left: 50%;
transform: translateX(-50%) rotate(180deg);
}
&.left {
top: 50%;
left: 32px;
transform: translateY(-50%) rotate(270deg);
}
&:hover, &:hover,
&.act { &.act {
background-color: #fff; background-color: #fff;
@ -1035,7 +1103,7 @@ $alert-color: #101010;
.warning { .warning {
font-size: $pop-normal-size; font-size: $pop-normal-size;
font-weight: $pop-normal-weight; font-weight: $pop-normal-weight;
color: #FFAFAF; color: #ffafaf;
} }
// 속성 변경 // 속성 변경
@ -1087,37 +1155,157 @@ $alert-color: #101010;
top: 12.5px; top: 12.5px;
left: 50%; left: 50%;
font-size: 11px; font-size: 11px;
color: #8B8B8B; color: #8b8b8b;
font-weight: 500; font-weight: 500;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-use-select: none; -ms-use-select: none;
user-select: none; user-select: none;
} }
&:nth-child(1) { transform: rotate(180deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(180deg);}} &:nth-child(1) {
&:nth-child(2) { transform: rotate(195deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(165deg);}} transform: rotate(180deg) translate(-50%, -50%);
&:nth-child(3) { transform: rotate(210deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(150deg);}} i {
&:nth-child(4) { transform: rotate(225deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(135deg);}} transform: translateX(-50%) rotate(180deg);
&:nth-child(5) { transform: rotate(240deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(120deg);}} }
&:nth-child(6) { transform: rotate(255deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(105deg);}} }
&:nth-child(7) { transform: rotate(270deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(90deg);}} &:nth-child(2) {
&:nth-child(8) { transform: rotate(285deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(75deg);}} transform: rotate(195deg) translate(-50%, -50%);
&:nth-child(9) { transform: rotate(300deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(60deg);}} i {
&:nth-child(10) { transform: rotate(315deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(45deg);}} transform: translateX(-50%) rotate(165deg);
&:nth-child(11) { transform: rotate(330deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(30deg);}} }
&:nth-child(12) { transform: rotate(345deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(15deg);}} }
&:nth-child(13) { transform: rotate(0deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(0deg);}} &:nth-child(3) {
&:nth-child(14) { transform: rotate(15deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-15deg);}} transform: rotate(210deg) translate(-50%, -50%);
&:nth-child(15) { transform: rotate(30deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-30deg);}} i {
&:nth-child(16) { transform: rotate(45deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-45deg);}} transform: translateX(-50%) rotate(150deg);
&:nth-child(17) { transform: rotate(60deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-60deg);}} }
&:nth-child(18) { transform: rotate(75deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-75deg);}} }
&:nth-child(19) { transform: rotate(90deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-90deg);}} &:nth-child(4) {
&:nth-child(20) { transform: rotate(105deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-105deg);}} transform: rotate(225deg) translate(-50%, -50%);
&:nth-child(21) { transform: rotate(120deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-120deg);}} i {
&:nth-child(22) { transform: rotate(135deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-135deg);}} transform: translateX(-50%) rotate(135deg);
&:nth-child(23) { transform: rotate(150deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-150deg);}} }
&:nth-child(24) { transform: rotate(165deg) translate(-50%, -50%); i{transform: translateX(-50%) rotate(-165deg);}} }
&:nth-child(5) {
transform: rotate(240deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(120deg);
}
}
&:nth-child(6) {
transform: rotate(255deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(105deg);
}
}
&:nth-child(7) {
transform: rotate(270deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(90deg);
}
}
&:nth-child(8) {
transform: rotate(285deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(75deg);
}
}
&:nth-child(9) {
transform: rotate(300deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(60deg);
}
}
&:nth-child(10) {
transform: rotate(315deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(45deg);
}
}
&:nth-child(11) {
transform: rotate(330deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(30deg);
}
}
&:nth-child(12) {
transform: rotate(345deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(15deg);
}
}
&:nth-child(13) {
transform: rotate(0deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(0deg);
}
}
&:nth-child(14) {
transform: rotate(15deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-15deg);
}
}
&:nth-child(15) {
transform: rotate(30deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-30deg);
}
}
&:nth-child(16) {
transform: rotate(45deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-45deg);
}
}
&:nth-child(17) {
transform: rotate(60deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-60deg);
}
}
&:nth-child(18) {
transform: rotate(75deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-75deg);
}
}
&:nth-child(19) {
transform: rotate(90deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-90deg);
}
}
&:nth-child(20) {
transform: rotate(105deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-105deg);
}
}
&:nth-child(21) {
transform: rotate(120deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-120deg);
}
}
&:nth-child(22) {
transform: rotate(135deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-135deg);
}
}
&:nth-child(23) {
transform: rotate(150deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-150deg);
}
}
&:nth-child(24) {
transform: rotate(165deg) translate(-50%, -50%);
i {
transform: translateX(-50%) rotate(-165deg);
}
}
&.act { &.act {
&::after { &::after {
content: ''; content: '';
@ -1152,7 +1340,6 @@ $alert-color: #101010;
} }
} }
// 지붕모듈선택 // 지붕모듈선택
.roof-module-tab { .roof-module-tab {
display: flex; display: flex;
@ -1167,13 +1354,13 @@ $alert-color: #101010;
border-radius: 2px; border-radius: 2px;
background-color: transparent; background-color: transparent;
font-size: 12px; font-size: 12px;
color: #AAA; color: #aaa;
text-align: center; text-align: center;
cursor: default; cursor: default;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.act { &.act {
background-color: #1083E3; background-color: #1083e3;
border: 1px solid #1083E3; border: 1px solid #1083e3;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
@ -1186,7 +1373,7 @@ $alert-color: #101010;
background-position: center; background-position: center;
background-size: cover; background-size: cover;
background-image: url(../../public/static/images/canvas/module_tab_arr.svg); background-image: url(../../public/static/images/canvas/module_tab_arr.svg);
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.act { &.act {
background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg); background-image: url(../../public/static/images/canvas/module_tab_arr_white.svg);
} }
@ -1212,14 +1399,16 @@ $alert-color: #101010;
transform: translateX(-50%); transform: translateX(-50%);
width: 1px; width: 1px;
height: 6px; height: 6px;
background-color: #8B8B8B; background-color: #8b8b8b;
} }
} }
i { i {
top: 32px; top: 32px;
} }
&.act { &.act {
i{color: #8B8B8B;} i {
color: #8b8b8b;
}
} }
} }
} }
@ -1251,7 +1440,7 @@ $alert-color: #101010;
height: 30px; height: 30px;
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&:first-child { &:first-child {
border-left: 1px solid #505050; border-left: 1px solid #505050;
} }
@ -1265,7 +1454,7 @@ $alert-color: #101010;
.module-table-box { .module-table-box {
flex: 1; flex: 1;
background-color: #3D3D3D; background-color: #3d3d3d;
border-radius: 2px; border-radius: 2px;
.module-table-inner { .module-table-inner {
padding: 10px; padding: 10px;
@ -1278,7 +1467,7 @@ $alert-color: #101010;
padding: 10px 0; padding: 10px 0;
font-size: 12px; font-size: 12px;
color: #fff; color: #fff;
border-bottom: 1px solid #4D4D4D; border-bottom: 1px solid #4d4d4d;
} }
.eaves-keraba-table { .eaves-keraba-table {
width: 100%; width: 100%;
@ -1301,7 +1490,7 @@ $alert-color: #101010;
.warning-guide { .warning-guide {
padding: 20px; padding: 20px;
.warning { .warning {
color: #FFCACA; color: #ffcaca;
max-height: 55px; max-height: 55px;
overflow-y: auto; overflow-y: auto;
padding-right: 30px; padding-right: 30px;
@ -1310,7 +1499,7 @@ $alert-color: #101010;
background-color: transparent; background-color: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: #D9D9D9; background-color: #d9d9d9;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background-color: transparent; background-color: transparent;
@ -1321,7 +1510,7 @@ $alert-color: #101010;
.module-self-table { .module-self-table {
display: table; display: table;
border-top: 1px solid #4D4D4D; border-top: 1px solid #4d4d4d;
border-collapse: collapse; border-collapse: collapse;
width: 100%; width: 100%;
.self-table-item { .self-table-item {
@ -1330,7 +1519,7 @@ $alert-color: #101010;
.self-item-th { .self-item-th {
display: table-cell; display: table-cell;
vertical-align: middle; vertical-align: middle;
border-bottom: 1px solid #4D4D4D; border-bottom: 1px solid #4d4d4d;
} }
.self-item-th { .self-item-th {
width: 60px; width: 60px;
@ -1358,7 +1547,7 @@ $alert-color: #101010;
.hexagonal-wrap { .hexagonal-wrap {
.hexagonal-item { .hexagonal-item {
padding: 15px 0; padding: 15px 0;
border-bottom: 1px solid #4D4D4D; border-bottom: 1px solid #4d4d4d;
&:first-child { &:first-child {
padding-top: 0; padding-top: 0;
} }
@ -1396,7 +1585,7 @@ $alert-color: #101010;
background-color: transparent; background-color: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: #D9D9D9; background-color: #d9d9d9;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background-color: transparent; background-color: transparent;
@ -1414,7 +1603,7 @@ $alert-color: #101010;
gap: 5px; gap: 5px;
min-height: 60px; min-height: 60px;
padding: 12px; padding: 12px;
border: 1px solid rgba(255, 255, 255, 0.20); border: 1px solid rgba(255, 255, 255, 0.2);
span { span {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
@ -1447,7 +1636,7 @@ $alert-color: #101010;
background-color: transparent; background-color: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: #D9D9D9; background-color: #d9d9d9;
} }
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
background-color: transparent; background-color: transparent;
@ -1505,13 +1694,284 @@ $alert-color: #101010;
width: 16px; width: 16px;
height: 16px; height: 16px;
&.pink { &.pink {
border: 2px solid #EA10AC; border: 2px solid #ce1c9c;
background-color: #16417D; background-color: #16417d;
} }
&.white { &.white {
border: 2px solid #FFF; border: 2px solid #fff;
background-color: #001027; background-color: #001027;
} }
} }
} }
} }
// color setting
.color-setting-wrap {
padding-bottom: 15px;
border-bottom: 1px solid #424242;
.color-tit {
font-size: 13px;
font-weight: 500;
color: #ffffff;
margin-bottom: 10px;
}
.color-picker {
.react-colorful {
width: 100%;
height: auto;
gap: 20px;
.react-colorful__pointer {
width: 15px;
height: 15px;
border: 4px solid #fff;
}
.react-colorful__saturation {
border-radius: 2px;
height: 200px;
border-bottom: 5px solid #000;
}
.react-colorful__last-control {
border-radius: 2px;
height: 10px;
}
}
.hex-color-box {
display: flex;
align-items: center;
margin-top: 15px;
.color-box-tit {
font-size: 12px;
color: #fff;
font-weight: 500;
margin-right: 10px;
}
.color-hex-input {
width: 150px;
margin-right: 5px;
input {
width: 100%;
}
}
.color-box {
display: block;
width: 30px;
height: 30px;
border-radius: 4px;
}
}
.default-color-wrap {
margin-top: 25px;
.default-tit {
font-size: 12px;
font-weight: 500;
color: #fff;
margin-bottom: 10px;
}
.color-button-wrap {
display: grid;
grid-template-columns: repeat(8, 1fr);
gap: 21px;
.default-color {
display: block;
width: 100%;
height: 30px;
border-radius: 4px;
}
}
}
}
}
// 글꼴 설정 팝업
.font-option-warp {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 15px 5px;
margin-bottom: 15px;
.font-option-item {
.option-item-tit {
font-size: 12px;
font-weight: 500;
color: #fff;
margin-bottom: 10px;
}
}
}
.font-ex-wrap {
margin-bottom: 15px;
.font-ex-tit {
font-size: 12px;
font-weight: 500;
color: #fff;
margin-bottom: 10px;
}
.font-ex-box {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 80px;
background-color: #fff;
}
}
// 치수선 설정
.font-btn-wrap {
margin-bottom: 15px;
button {
width: 100%;
height: 30px;
line-height: 28px;
}
}
.line-color-wrap {
margin-bottom: 15px;
.color-btn {
display: block;
width: 100%;
height: 30px;
border-radius: 2px;
}
}
.form-box {
width: 100%;
background-color: #fff;
padding: 10px 0 20px;
.line-form {
position: relative;
width: 102px;
height: 40px;
margin: 0 auto;
border-left: 1px dashed #101010;
border-right: 1px dashed #101010;
.line-font-box {
position: absolute;
bottom: -3px;
left: 0;
width: 100%;
text-align: center;
.font {
display: block;
padding-bottom: 6px;
color: #101010;
}
.line {
position: relative;
display: block;
width: 100%;
height: 1px;
border-radius: 30px;
&::before {
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(45deg);
left: 1px;
width: 9px;
height: 9px;
border: 1px solid;
border-color: inherit;
border-top: none;
border-right: none;
}
&::after {
content: '';
position: absolute;
top: 50%;
transform: translateY(-50%) rotate(45deg);
right: 1px;
width: 9px;
height: 9px;
border: 1px solid;
border-color: inherit;
border-bottom: none;
border-left: none;
}
}
}
}
}
// 사이즈 변경
.size-inner-warp {
position: relative;
}
.size-check-wrap {
position: relative;
display: block;
width: 132px;
height: 132px;
margin: 0 auto;
.size-btn {
position: absolute;
width: 16px;
height: 16px;
border: 1px solid #fff;
border-radius: 50%;
&.act {
&::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 8px;
height: 8px;
background-color: #fff;
border-radius: 50%;
}
}
&:nth-child(1) {
top: 0;
left: 0;
}
&:nth-child(2) {
top: 0;
right: 0;
}
&:nth-child(3) {
bottom: 0;
left: 0;
}
&:nth-child(4) {
bottom: 0;
right: 0;
}
}
.size-box {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 100px;
height: 100px;
background-color: #fff;
}
}
.size-option-top {
margin-bottom: 15px;
}
.size-option-side {
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
}
.size-option-wrap {
width: 88px;
margin: 0 auto;
.size-option {
display: flex;
align-items: center;
input {
width: 100%;
flex: 1;
}
span {
flex: none;
}
}
}

View File

@ -3,29 +3,100 @@
-moz-text-size-adjust: none; -moz-text-size-adjust: none;
-ms-text-size-adjust: none; -ms-text-size-adjust: none;
text-size-adjust: none; text-size-adjust: none;
box-sizing: content-box box-sizing: content-box;
} }
*, ::after, ::before { *,
::after,
::before {
box-sizing: border-box; box-sizing: border-box;
} }
html, body{ html,
body {
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size: 16px; font-size: 16px;
} }
html, body, div, span, applet, object, iframe, html,
h1, h2, h3, h4, h5, h6, p, blockquote, pre, body,
a, abbr, acronym, address, big, cite, code, div,
del, dfn, em, img, ins, kbd, q, s, samp, span,
small, strike, strong, sub, sup, tt, var, applet,
b, u, i, center, object,
dl, dt, dd, ol, ul, li, iframe,
fieldset, form, label, legend, h1,
table, caption, tbody, tfoot, thead, tr, th, td, h2,
article, aside, canvas, details, embed, h3,
figure, figcaption, footer, header, hgroup, h4,
menu, nav, output, ruby, section, summary, h5,
time, mark, audio, video { h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
hgroup,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
margin: 0; margin: 0;
padding: 0; padding: 0;
border: 0; border: 0;
@ -37,23 +108,38 @@ time, mark, audio, video {
font-smooth: never; font-smooth: never;
} }
/* HTML5 display-role reset for older browsers */ /* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure, article,
footer, header, hgroup, menu, nav, section { aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
menu,
nav,
section {
display: block; display: block;
} }
body { body {
line-height: 1.4; line-height: 1.4;
} }
body:first-of-type caption { display:none;} body:first-of-type caption {
display: none;
}
ol, ul { ol,
ul {
list-style: none; list-style: none;
} }
blockquote, q { blockquote,
q {
quotes: none; quotes: none;
} }
blockquote:before, blockquote:after, blockquote:before,
q:before, q:after { blockquote:after,
q:before,
q:after {
content: ''; content: '';
content: none; content: none;
} }
@ -63,7 +149,9 @@ table {
border-spacing: 0; border-spacing: 0;
border: 0 none; border: 0 none;
} }
caption, th, td { caption,
th,
td {
text-align: left; text-align: left;
font-weight: normal; font-weight: normal;
border: 0; border: 0;
@ -73,26 +161,38 @@ a {
cursor: pointer; cursor: pointer;
color: #000; color: #000;
} }
a, a:hover, a:active { a,
a:hover,
a:active {
text-decoration: none; text-decoration: none;
-webkit-tap-highlight-color: transparent; -webkit-tap-highlight-color: transparent;
} }
/*form_style*/ /*form_style*/
input, select, textarea, button, a, label { input,
select,
textarea,
button,
a,
label {
-webkit-tap-highlight-color: rgba(0, 0, 0, 0); -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
} }
button,input[type=text], input[type=button] { button,
input[type='text'],
input[type='button'] {
-webkit-appearance: none; -webkit-appearance: none;
-webkit-border-radius: 0; -webkit-border-radius: 0;
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
border-radius: 0 border-radius: 0;
} }
input[type=checkbox], input[type=radio] { input[type='checkbox'],
input[type='radio'] {
box-sizing: border-box; box-sizing: border-box;
padding: 0; padding: 0;
} }
input, select, button { input,
select,
button {
border: 0 none; border: 0 none;
outline: none; outline: none;
margin: 0; margin: 0;
@ -131,24 +231,53 @@ button{
} }
// margin // margin
.mt5{margin-top: 5px !important;} .mt5 {
.mt10{margin-top: 10px !important;} margin-top: 5px !important;
.mt15{margin-top: 15px !important;} }
.mb5{margin-bottom: 5px !important;} .mt10 {
.mb10{margin-bottom: 10px !important;} margin-top: 10px !important;
.mb15{margin-bottom: 15px !important;} }
.mr5{margin-right: 5px !important;} .mt15 {
.mr10{margin-right: 10px !important;} margin-top: 15px !important;
.mr15{margin-right: 15px !important;} }
.ml5{margin-left: 5px !important;} .mb5 {
.ml10{margin-left: 10px !important;} margin-bottom: 5px !important;
.ml15{margin-left: 15px !important;} }
.mb10 {
margin-bottom: 10px !important;
}
.mb15 {
margin-bottom: 15px !important;
}
.mr5 {
margin-right: 5px !important;
}
.mr10 {
margin-right: 10px !important;
}
.mr15 {
margin-right: 15px !important;
}
.ml5 {
margin-left: 5px !important;
}
.ml10 {
margin-left: 10px !important;
}
.ml15 {
margin-left: 15px !important;
}
// align // align
.al-l{text-align: left !important;} .al-l {
.al-r{text-align: right !important;} text-align: left !important;
.al-c{text-align: center !important;} }
.al-r {
text-align: right !important;
}
.al-c {
text-align: center !important;
}
// button // button
.btn-frame { .btn-frame {
@ -163,7 +292,7 @@ button{
border: 1px solid #000; border: 1px solid #000;
text-align: center; text-align: center;
font-family: 'Pretendard', sans-serif; font-family: 'Pretendard', sans-serif;
transition: all .17s ease-in-out; transition: all 0.17s ease-in-out;
cursor: pointer; cursor: pointer;
&.block { &.block {
width: 100%; width: 100%;
@ -176,15 +305,15 @@ button{
} }
&.deepgray { &.deepgray {
background-color: #2C2C2C; background-color: #2c2c2c;
border: 1px solid #484848; border: 1px solid #484848;
} }
&.gray { &.gray {
background-color: #3C3C3C; background-color: #3c3c3c;
border: 1px solid #545454; border: 1px solid #545454;
} }
&.dark { &.dark {
background-color: #1C1C1C; background-color: #1c1c1c;
border: 1px solid #484848; border: 1px solid #484848;
} }
&.modal { &.modal {
@ -193,8 +322,8 @@ button{
border: 1px solid #484848; border: 1px solid #484848;
color: #aaa; color: #aaa;
&:hover { &:hover {
background-color: #1083E3; background-color: #1083e3;
border: 1px solid #1083E3; border: 1px solid #1083e3;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
@ -204,13 +333,13 @@ button{
padding: 0 10px; padding: 0 10px;
line-height: 28px; line-height: 28px;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
background-color: #2D2D2D; background-color: #2d2d2d;
border: 1px solid #393939; border: 1px solid #393939;
color: #aaa; color: #aaa;
&.act, &.act,
&:hover { &:hover {
background-color: #414E6C; background-color: #414e6c;
border: 1px solid #414E6C; border: 1px solid #414e6c;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
@ -224,11 +353,11 @@ button{
border: 1px solid #484848; border: 1px solid #484848;
color: #fff; color: #fff;
&.blue { &.blue {
background-color: #414E6C; background-color: #414e6c;
border: 1px solid #414E6C; border: 1px solid #414e6c;
&:hover { &:hover {
background-color: #414E6C; background-color: #414e6c;
border: 1px solid #414E6C; border: 1px solid #414e6c;
} }
} }
&.white { &.white {
@ -255,7 +384,7 @@ button{
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
background-color: transparent; background-color: transparent;
border: 1px solid #676767; border: 1px solid #676767;
color: #AAAAAA; color: #aaaaaa;
&:hover { &:hover {
background-color: #272727; background-color: #272727;
border-color: #676767; border-color: #676767;
@ -264,8 +393,8 @@ button{
} }
&:hover, &:hover,
&.act { &.act {
background-color: #1083E3; background-color: #1083e3;
border: 1px solid #1083E3; border: 1px solid #1083e3;
color: #fff; color: #fff;
font-weight: 500; font-weight: 500;
} }
@ -295,7 +424,7 @@ button{
color: #fff; color: #fff;
font-size: 13px; font-size: 13px;
font-weight: 400; font-weight: 400;
transition: all .15s ease-in-out; transition: all 0.15s ease-in-out;
&.navy { &.navy {
background-color: #304961; background-color: #304961;
&:hover { &:hover {
@ -303,21 +432,21 @@ button{
} }
} }
&.grey { &.grey {
background-color: #94A0AD; background-color: #94a0ad;
&:hover { &:hover {
background-color: #607F9A; background-color: #607f9a;
} }
} }
&.green { &.green {
background-color: #A6BBA8; background-color: #a6bba8;
&:hover { &:hover {
background-color: #98af9b; background-color: #98af9b;
} }
} }
&.white { &.white {
border: 1px solid #94A0AD; border: 1px solid #94a0ad;
background-color: #fff; background-color: #fff;
color: #94A0AD; color: #94a0ad;
&:hover { &:hover {
background-color: #fff; background-color: #fff;
} }
@ -333,7 +462,7 @@ button{
line-height: 30px; line-height: 30px;
padding: 0 25px 0 10px; padding: 0 25px 0 10px;
background-color: #373737; background-color: #373737;
border: 1px solid #3F3F3F; border: 1px solid #3f3f3f;
border-radius: 2px; border-radius: 2px;
border-top-left-radius: 2px; border-top-left-radius: 2px;
color: #fff; color: #fff;
@ -353,7 +482,7 @@ button{
max-height: 100px; max-height: 100px;
overflow-y: auto; overflow-y: auto;
background-color: #373737; background-color: #373737;
border: 1px solid #3F3F3F; border: 1px solid #3f3f3f;
border-radius: 2px; border-radius: 2px;
transition: all 0.17s ease-in-out; transition: all 0.17s ease-in-out;
visibility: hidden; visibility: hidden;
@ -363,20 +492,19 @@ button{
align-items: center; align-items: center;
padding: 8px 20px; padding: 8px 20px;
line-height: 1.4; line-height: 1.4;
transition: all .17s ease-in-out; transition: all 0.17s ease-in-out;
button { button {
font-size: 12px; font-size: 12px;
color: #fff; color: #fff;
line-height: 1.4; line-height: 1.4;
} }
&:hover { &:hover {
background-color: #2C2C2C; background-color: #2c2c2c;
} }
} }
&::-webkit-scrollbar { &::-webkit-scrollbar {
width: 2px; width: 2px;
background-color: transparent; background-color: transparent;
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
background-color: #5a5a5a; background-color: #5a5a5a;
@ -396,7 +524,7 @@ button{
height: 6px; height: 6px;
background: url(/static/images/common/select-arr.svg) no-repeat center; background: url(/static/images/common/select-arr.svg) no-repeat center;
background-size: cover; background-size: cover;
transition: all .17s ease-in-out; transition: all 0.17s ease-in-out;
} }
&.active { &.active {
.select-item-wrap { .select-item-wrap {
@ -414,17 +542,17 @@ button{
display: block; display: block;
width: 100%; width: 100%;
height: 30px; height: 30px;
background: #FFF url(../../public/static/images/common/select_light_arr.svg) calc(100% - 11px) center no-repeat; background: #fff url(../../public/static/images/common/select_light_arr.svg) calc(100% - 11px) center no-repeat;
background-size: 10px 6px; background-size: 10px 6px;
border: 1px solid #eee; border: 1px solid #eee;
padding: 0 30px 0 10px; padding: 0 30px 0 10px;
font-size: 13px; font-size: 13px;
color: #45576F; color: #45576f;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
cursor: pointer; cursor: pointer;
&:disabled { &:disabled {
opacity: 1; opacity: 1;
background-color: #FAFAFA; background-color: #fafafa;
color: #999; color: #999;
cursor: default; cursor: default;
} }
@ -440,7 +568,6 @@ button{
} }
} }
// input // input
.form-input { .form-input {
label { label {
@ -451,9 +578,9 @@ button{
margin-bottom: 10px; margin-bottom: 10px;
} }
} }
input[type=password], input[type='password'],
input[type=number], input[type='number'],
input[type=text]{ input[type='text'] {
&.input-origin { &.input-origin {
display: inline-block; display: inline-block;
height: 30px; height: 30px;
@ -476,7 +603,7 @@ input[type=text]{
width: 100%; width: 100%;
} }
&:read-only { &:read-only {
color: #AAA; color: #aaa;
} }
&.plane { &.plane {
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
@ -494,27 +621,25 @@ input[type=text]{
background-color: #fff; background-color: #fff;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
font-size: 13px; font-size: 13px;
color: #45576F; color: #45576f;
font-weight: normal; font-weight: normal;
transition: border-color .17s ease-in-out; transition: border-color 0.17s ease-in-out;
text-align: left; text-align: left;
&:read-only { &:read-only {
background-color: #FAFAFA; background-color: #fafafa;
color: #999999; color: #999999;
} }
} }
} }
// check-btn // check-btn
.check-btn { .check-btn {
display: flex; display: flex;
align-items: center; align-items: center;
height: 30px; height: 30px;
background-color: #3A3A3A; background-color: #3a3a3a;
border-radius: 3px; border-radius: 3px;
transition: all .17s ease-in-out; transition: all 0.17s ease-in-out;
.check-area { .check-area {
flex: none; flex: none;
width: 30px; width: 30px;
@ -551,10 +676,10 @@ input[type=text]{
display: block; display: block;
height: 30px; height: 30px;
border-radius: 3px; border-radius: 3px;
background-color: #3A3A3A; background-color: #3a3a3a;
padding: 0 11px; padding: 0 11px;
text-align: left; text-align: left;
transition: all .17s ease-in-out; transition: all 0.17s ease-in-out;
span { span {
position: relative; position: relative;
font-size: 12px; font-size: 12px;
@ -588,15 +713,15 @@ input[type=text]{
background-color: #272727; background-color: #272727;
border: 1px solid #484848; border: 1px solid #484848;
span { span {
color: #Fff; color: #fff;
&:after { &:after {
background: url(../../public/static/images/canvas/arr_btn_ico_white.svg) no-repeat center; background: url(../../public/static/images/canvas/arr_btn_ico_white.svg) no-repeat center;
} }
} }
&:hover, &:hover,
&.act { &.act {
background-color: #1083E3; background-color: #1083e3;
border: 1px solid #1083E3; border: 1px solid #1083e3;
} }
} }
} }
@ -606,8 +731,8 @@ input[type=text]{
.d-check-box { .d-check-box {
line-height: 1.1; line-height: 1.1;
cursor: pointer; cursor: pointer;
input[type=checkbox], input[type='checkbox'],
input[type=radio]{ input[type='radio'] {
position: static; position: static;
margin-left: 0; margin-left: 0;
cursor: pointer; cursor: pointer;
@ -630,7 +755,7 @@ input[type=text]{
} }
&.light { &.light {
label { label {
color: #45576F; color: #45576f;
} }
} }
&.no-text { &.no-text {
@ -644,7 +769,7 @@ input[type=text]{
label { label {
&::before { &::before {
cursor: pointer; cursor: pointer;
content: ""; content: '';
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 17px; width: 17px;
@ -658,11 +783,13 @@ input[type=text]{
text-align: center; text-align: center;
font-size: 13px; font-size: 13px;
line-height: 1.4; line-height: 1.4;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out; transition:
border 0.15s ease-in-out,
color 0.15s ease-in-out;
} }
&::after { &::after {
cursor: pointer; cursor: pointer;
content: ""; content: '';
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 9px; width: 9px;
@ -678,20 +805,22 @@ input[type=text]{
line-height: 1.4; line-height: 1.4;
opacity: 0; opacity: 0;
visibility: hidden; visibility: hidden;
transition: opacity 0.15s ease-in-out, color 0.15s ease-in-out; transition:
opacity 0.15s ease-in-out,
color 0.15s ease-in-out;
} }
} }
&.light { &.light {
label { label {
&:before { &:before {
border-color: #D6D6D7; border-color: #d6d6d7;
} }
&:after { &:after {
background-color: #697C8F; background-color: #697c8f;
} }
} }
} }
input[type=radio]:checked + label::after{ input[type='radio']:checked + label::after {
opacity: 1; opacity: 1;
visibility: visible; visibility: visible;
} }
@ -715,10 +844,12 @@ input[type=text]{
// check-box // check-box
.d-check-box { .d-check-box {
label { label {
&.red{color: #FFCACA;} &.red {
color: #ffcaca;
}
&::before { &::before {
cursor: pointer; cursor: pointer;
content: ""; content: '';
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 17px; width: 17px;
@ -726,32 +857,36 @@ input[type=text]{
top: 2px; top: 2px;
left: 0; left: 0;
margin-left: -12px; margin-left: -12px;
border: 1px solid #D6D6D7; border: 1px solid #d6d6d7;
background-color: #fff; background-color: #fff;
transition: border 0.15s ease-in-out, color 0.15s ease-in-out; transition:
border 0.15s ease-in-out,
color 0.15s ease-in-out;
} }
&:after { &:after {
cursor: pointer; cursor: pointer;
content: ""; content: '';
display: inline-block; display: inline-block;
position: absolute; position: absolute;
width: 16px; width: 16px;
height: 16px; height: 16px;
top: 0; top: 0;
left: 0; left: 0;
margin-left: -.8rem; margin-left: -0.8rem;
transition: border 0.05s ease-in-out, color 0.05s ease-in-out; transition:
border 0.05s ease-in-out,
color 0.05s ease-in-out;
} }
} }
input[type=checkbox]:checked + label::after{ input[type='checkbox']:checked + label::after {
content: ""; content: '';
display: inline-block; display: inline-block;
position: absolute; position: absolute;
top: 1px; top: 1px;
left: -1px; left: -1px;
width: 5px; width: 5px;
height: 8px; height: 8px;
border: 2px solid #697C8F; border: 2px solid #697c8f;
border-left: none; border-left: none;
border-top: none; border-top: none;
transform: translate(7.75px, 4.5px) rotate(45deg); transform: translate(7.75px, 4.5px) rotate(45deg);
@ -763,7 +898,7 @@ input[type=text]{
background-color: transparent; background-color: transparent;
} }
} }
input[type=checkbox]:checked + label::after{ input[type='checkbox']:checked + label::after {
border-color: #fff; border-color: #fff;
} }
&.no-text { &.no-text {
@ -773,23 +908,25 @@ input[type=text]{
} }
} }
&.sel { &.sel {
input[type=checkbox]:checked + label{ input[type='checkbox']:checked + label {
color: #D7C863; color: #d7c863;
} }
input[type=checkbox]:checked + label::before, input[type='checkbox']:checked + label::before,
input[type=checkbox]:checked + label::after{ input[type='checkbox']:checked + label::after {
border-color: #D7C863; border-color: #d7c863;
} }
} }
} }
// date-picker // date-picker
.date-picker { .date-picker {
svg{display: none;} svg {
display: none;
}
.react-datepicker-wrapper { .react-datepicker-wrapper {
width: 100%; width: 100%;
} }
input[type=text]{ input[type='text'] {
display: block; display: block;
width: 100%; width: 100%;
height: 30px; height: 30px;
@ -797,7 +934,7 @@ input[type=text]{
border-radius: 2px; border-radius: 2px;
border: 1px solid #eee; border: 1px solid #eee;
font-size: 13px; font-size: 13px;
color: #45576F; color: #45576f;
font-weight: normal; font-weight: normal;
font-family: 'Noto Sans JP', sans-serif; font-family: 'Noto Sans JP', sans-serif;
background: #fff url(../../public/static/images/common/datepicker.svg) calc(100% - 11px) center no-repeat; background: #fff url(../../public/static/images/common/datepicker.svg) calc(100% - 11px) center no-repeat;
@ -805,3 +942,86 @@ input[type=text]{
cursor: pointer; cursor: pointer;
} }
} }
// react select
.react-select-custom {
width: 100%;
.custom__control {
height: 30px;
min-height: unset;
border-radius: 2px;
border-color: #eee;
background-color: #fff;
&:hover {
border-color: #eee;
}
}
.custom__control--is-focused {
border-color: #eee;
box-shadow: unset;
&:hover {
border-color: #eee;
}
}
.custom__value-container {
height: 100%;
padding: 0 10px;
}
.custom__placeholder,
.custom__single-value {
margin: 0;
}
.custom__single-value {
font-size: 13px;
color: #45576f;
font-weight: 400;
}
.custom__placeholder {
font-size: 13px;
color: #bbbbbb;
font-weight: 400;
}
.custom__indicator {
padding: 0;
svg {
display: none;
}
}
.custom__clear-indicator {
width: 30px;
height: 100%;
background: url(../../public/static/images/common/select_del.svg) no-repeat center;
background-size: 8px 8px;
}
.custom__dropdown-indicator {
width: 30px;
height: 100%;
background: url(../../public/static/images/common/select_light_arr.svg) no-repeat center;
}
.custom__menu {
margin: 1px 0;
border-radius: 2px;
overflow: hidden;
}
.custom__menu-list {
padding: 0;
}
.custom__option {
font-size: 13px;
padding: 7px 10px;
color: #45576f;
}
.custom__option--is-selected {
color: #fff;
}
// disable
&.custom--is-disabled {
.custom__control {
background-color: #fafafa;
}
.custom__single-value {
color: #999999;
}
}
}

View File

@ -8,8 +8,10 @@ export const handleFileDown = async (file) => {
const params = new URLSearchParams({ const params = new URLSearchParams({
encodeFileNo: file.encodeFileNo, encodeFileNo: file.encodeFileNo,
}) })
const options = { responseType: 'blob' }
const apiUrl = `${url}?${params.toString()}` const apiUrl = `${url}?${params.toString()}`
await promiseGet({ url: apiUrl, responseType: 'blob' })
await promiseGet({ url: apiUrl, option: options })
.then((resultData) => { .then((resultData) => {
if (resultData) { if (resultData) {
const blob = new Blob([resultData.data], { type: resultData.headers['content-type'] || 'application/octet-stream' }) const blob = new Blob([resultData.data], { type: resultData.headers['content-type'] || 'application/octet-stream' })
@ -25,7 +27,7 @@ export const handleFileDown = async (file) => {
} }
}) })
.catch((error) => { .catch((error) => {
alert(error.response.data.message) alert('File does not exist.')
}) })
} }

View File

@ -744,67 +744,6 @@ export const polygonToTurfPolygon = (polygon) => {
) )
} }
export const splitDormerTriangle = (triangle, direction) => {
const halfWidth = triangle.width / 2
let leftPoints = []
let rightPoints = []
let leftPointOffset = []
let rightPointOffset = []
if (direction === 'down') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top + triangle.height },
{ x: triangle.left, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top + triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top + triangle.height },
]
} else if (direction === 'up') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top - triangle.height },
{ x: triangle.left, y: triangle.top - triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top - triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top - triangle.height },
]
} else if (direction === 'left') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top - halfWidth },
{ x: triangle.left - triangle.height, y: triangle.top },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top + halfWidth },
]
} else if (direction === 'right') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height },
]
}
return [leftPoints, rightPoints]
}
export const triangleToPolygon = (triangle) => { export const triangleToPolygon = (triangle) => {
const points = [] const points = []
const halfWidth = triangle.width / 2 const halfWidth = triangle.width / 2
@ -853,7 +792,7 @@ export function setSurfaceShapePattern(polygon) {
patternSourceCanvas.width = polygon.width * ratio patternSourceCanvas.width = polygon.width * ratio
patternSourceCanvas.height = polygon.height * ratio patternSourceCanvas.height = polygon.height * ratio
const ctx = patternSourceCanvas.getContext('2d') const ctx = patternSourceCanvas.getContext('2d')
const offset = roofStyle === 1 ? 0 : patternSize.width / 2 let offset = roofStyle === 1 ? 0 : patternSize.width / 2
const rows = Math.floor(patternSourceCanvas.height / patternSize.height) const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
const cols = Math.floor(patternSourceCanvas.width / patternSize.width) const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
@ -861,6 +800,28 @@ export function setSurfaceShapePattern(polygon) {
ctx.strokeStyle = 'green' ctx.strokeStyle = 'green'
ctx.lineWidth = 0.4 ctx.lineWidth = 0.4
if (polygon.direction === 'east' || polygon.direction === 'west') {
offset = roofStyle === 1 ? 0 : patternSize.height / 2
for (let col = 0; col <= cols; col++) {
const x = col * patternSize.width
const yStart = 0
const yEnd = patternSourceCanvas.height
ctx.beginPath()
ctx.moveTo(x, yStart) // 선 시작점
ctx.lineTo(x, yEnd) // 선 끝점
ctx.stroke()
for (let row = 0; row <= rows; row++) {
const y = row * patternSize.height + (col % 2 === 0 ? 0 : offset)
const xStart = col * patternSize.width
const xEnd = xStart + patternSize.width
ctx.beginPath()
ctx.moveTo(xStart, y) // 선 시작점
ctx.lineTo(xEnd, y) // 선 끝점
ctx.stroke()
}
}
} else {
for (let row = 0; row <= rows; row++) { for (let row = 0; row <= rows; row++) {
const y = row * patternSize.height const y = row * patternSize.height
@ -880,6 +841,7 @@ export function setSurfaceShapePattern(polygon) {
ctx.stroke() ctx.stroke()
} }
} }
}
// 패턴 생성 // 패턴 생성
const pattern = new fabric.Pattern({ const pattern = new fabric.Pattern({

View File

@ -273,7 +273,7 @@
resolved "https://registry.npmjs.org/@bedrock-layout/use-stateful-ref/-/use-stateful-ref-1.4.1.tgz" resolved "https://registry.npmjs.org/@bedrock-layout/use-stateful-ref/-/use-stateful-ref-1.4.1.tgz"
integrity sha512-4eKO2KdQEXcR5LI4QcxqlJykJUDQJWDeWYAukIn6sRQYoabcfI5kDl61PUi6FR6o8VFgQ8IEP7HleKqWlSe8SQ== integrity sha512-4eKO2KdQEXcR5LI4QcxqlJykJUDQJWDeWYAukIn6sRQYoabcfI5kDl61PUi6FR6o8VFgQ8IEP7HleKqWlSe8SQ==
"@emotion/babel-plugin@^11.11.0", "@emotion/babel-plugin@^11.12.0": "@emotion/babel-plugin@^11.12.0":
version "11.12.0" version "11.12.0"
resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz#7b43debb250c313101b3f885eba634f1d723fcc2"
integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw== integrity sha512-y2WQb+oP8Jqvvclh8Q55gLUyb7UFvgv7eJfsj7td5TToBrIUtPay2kMrZi4xjq9qw2vD0ZR5fSho0yqoFgX7Rw==
@ -290,7 +290,7 @@
source-map "^0.5.7" source-map "^0.5.7"
stylis "4.2.0" stylis "4.2.0"
"@emotion/cache@^11.11.0", "@emotion/cache@^11.13.0", "@emotion/cache@^11.4.0": "@emotion/cache@^11.13.0", "@emotion/cache@^11.4.0":
version "11.13.1" version "11.13.1"
resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7" resolved "https://registry.yarnpkg.com/@emotion/cache/-/cache-11.13.1.tgz#fecfc54d51810beebf05bf2a161271a1a91895d7"
integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw== integrity sha512-iqouYkuEblRcXmylXIwwOodiEK5Ifl7JcX7o6V4jI3iW4mLXX3dmt5xwBtIkJiQEXFAI+pC8X0i67yiPkH9Ucw==
@ -306,32 +306,11 @@
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b" resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b"
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g== integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
"@emotion/is-prop-valid@^1.2.1":
version "1.3.1"
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz#8d5cf1132f836d7adbe42cf0b49df7816fc88240"
integrity sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==
dependencies:
"@emotion/memoize" "^0.9.0"
"@emotion/memoize@^0.9.0": "@emotion/memoize@^0.9.0":
version "0.9.0" version "0.9.0"
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102" resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102"
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ== integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==
"@emotion/react@11.11.0":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.0.tgz#408196b7ef8729d8ad08fc061b03b046d1460e02"
integrity sha512-ZSK3ZJsNkwfjT3JpDAWJZlrGD81Z3ytNDsxw1LKq1o+xkmO5pnWfr6gmCC8gHEFf3nSSX/09YrG67jybNPxSUw==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.11.0"
"@emotion/cache" "^11.11.0"
"@emotion/serialize" "^1.1.2"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
"@emotion/utils" "^1.2.1"
"@emotion/weak-memoize" "^0.3.1"
hoist-non-react-statics "^3.3.1"
"@emotion/react@^11.8.1": "@emotion/react@^11.8.1":
version "11.13.3" version "11.13.3"
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.3.tgz#a69d0de2a23f5b48e0acf210416638010e4bd2e4" resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.13.3.tgz#a69d0de2a23f5b48e0acf210416638010e4bd2e4"
@ -346,7 +325,7 @@
"@emotion/weak-memoize" "^0.4.0" "@emotion/weak-memoize" "^0.4.0"
hoist-non-react-statics "^3.3.1" hoist-non-react-statics "^3.3.1"
"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.1": "@emotion/serialize@^1.2.0", "@emotion/serialize@^1.3.1":
version "1.3.2" version "1.3.2"
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.2.tgz#e1c1a2e90708d5d85d81ccaee2dfeb3cc0cccf7a" resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.2.tgz#e1c1a2e90708d5d85d81ccaee2dfeb3cc0cccf7a"
integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA== integrity sha512-grVnMvVPK9yUVE6rkKfAJlYZgo0cu3l9iMC77V7DW6E1DUIrU68pSEXRmFZFOFB1QFo57TncmOcvcbMDWsL4yA==
@ -362,38 +341,21 @@
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c" resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.4.0.tgz#c9299c34d248bc26e82563735f78953d2efca83c"
integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg== integrity sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==
"@emotion/styled@11.11.0":
version "11.11.0"
resolved "https://registry.yarnpkg.com/@emotion/styled/-/styled-11.11.0.tgz#26b75e1b5a1b7a629d7c0a8b708fbf5a9cdce346"
integrity sha512-hM5Nnvu9P3midq5aaXj4I+lnSfNi7Pmd4EWk1fOZ3pxookaQTNew6bp4JaCBYM4HVFZF9g7UjJmsUmC2JlxOng==
dependencies:
"@babel/runtime" "^7.18.3"
"@emotion/babel-plugin" "^11.11.0"
"@emotion/is-prop-valid" "^1.2.1"
"@emotion/serialize" "^1.1.2"
"@emotion/use-insertion-effect-with-fallbacks" "^1.0.1"
"@emotion/utils" "^1.2.1"
"@emotion/unitless@^0.10.0": "@emotion/unitless@^0.10.0":
version "0.10.0" version "0.10.0"
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745" resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.10.0.tgz#2af2f7c7e5150f497bdabd848ce7b218a27cf745"
integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg== integrity sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==
"@emotion/use-insertion-effect-with-fallbacks@^1.0.1", "@emotion/use-insertion-effect-with-fallbacks@^1.1.0": "@emotion/use-insertion-effect-with-fallbacks@^1.1.0":
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf" resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.1.0.tgz#1a818a0b2c481efba0cf34e5ab1e0cb2dcb9dfaf"
integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw== integrity sha512-+wBOcIV5snwGgI2ya3u99D7/FJquOIniQT1IKyDsBmEgwvpxMNeS65Oib7OnE2d2aY+3BU4OiH+0Wchf8yk3Hw==
"@emotion/utils@^1.2.1", "@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1": "@emotion/utils@^1.4.0", "@emotion/utils@^1.4.1":
version "1.4.1" version "1.4.1"
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.1.tgz#b3adbb43de12ee2149541c4f1337d2eb7774f0ad" resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.1.tgz#b3adbb43de12ee2149541c4f1337d2eb7774f0ad"
integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA== integrity sha512-BymCXzCG3r72VKJxaYVwOXATqXIZ85cuvg0YOUDxMGNrKc1DJRZk8MgV5wyXRyEayIMd4FuXJIUgTBXvDNW5cA==
"@emotion/weak-memoize@^0.3.1":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
integrity sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==
"@emotion/weak-memoize@^0.4.0": "@emotion/weak-memoize@^0.4.0":
version "0.4.0" version "0.4.0"
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6" resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
@ -5955,14 +5917,6 @@ react-draggable@^4.4.6:
clsx "^1.1.1" clsx "^1.1.1"
prop-types "^15.8.1" prop-types "^15.8.1"
react-dropdown-select@^4.11.3:
version "4.11.3"
resolved "https://registry.yarnpkg.com/react-dropdown-select/-/react-dropdown-select-4.11.3.tgz#b23b8906f3bedc9d6a1a2125af936b34d4057158"
integrity sha512-/mOGSqqhmKsxxrmotLM+qn1Ss3nxGN6QnYusyQ7f0wizsWrc7ZmbcZhGRtwkJwpL6JYDQVTn19EYxJU1XfXrDA==
dependencies:
"@emotion/react" "11.11.0"
"@emotion/styled" "11.11.0"
react-hook-form@^7.53.0: react-hook-form@^7.53.0:
version "7.53.0" version "7.53.0"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.53.0.tgz#3cf70951bf41fa95207b34486203ebefbd3a05ab" resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.53.0.tgz#3cf70951bf41fa95207b34486203ebefbd3a05ab"