Merge branch 'dev' of ssh://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into qcast-pub

This commit is contained in:
김민식 2025-03-07 14:43:43 +09:00
commit 7c73c6ade3
24 changed files with 267 additions and 210 deletions

View File

@ -1,4 +1,4 @@
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="https://dev-api.hanasys.jp"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"

View File

@ -1,4 +1,4 @@
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" NEXT_PUBLIC_API_SERVER_PATH="https://api.hanasys.jp/"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"

View File

@ -15,6 +15,13 @@ const nextConfig = {
sassOptions: { sassOptions: {
includePaths: ['./src/styles'], includePaths: ['./src/styles'],
}, },
experimental: {
staleTimes: {
dynamic: 0,
dynamicSWR: 0,
dynamicSSR: 0,
},
},
} }
export default nextConfig export default nextConfig

View File

@ -5,12 +5,12 @@
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
"build": "next build", "build": "next build",
"start": "next start", "start": "next start -p 3000",
"start:dev": "next start -p 3001",
"lint": "next lint", "lint": "next lint",
"serve": "node server.js" "serve": "node server.js"
}, },
"dependencies": { "dependencies": {
"@nextui-org/react": "^2.4.2",
"ag-grid-react": "^32.0.2", "ag-grid-react": "^32.0.2",
"axios": "^1.7.8", "axios": "^1.7.8",
"big.js": "^6.2.2", "big.js": "^6.2.2",

View File

@ -1,5 +0,0 @@
import { NextUIProvider } from '@nextui-org/react'
export default function UIProvider({ children }) {
return <NextUIProvider>{children}</NextUIProvider>
}

View File

@ -9,7 +9,7 @@ import { setSession, login, checkSession } from '@/lib/authActions'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
import { sessionStore } from '@/store/commonAtom' import { sessionStore } from '@/store/commonAtom'
import { useRouter } from 'next/navigation' import { redirect, useRouter } from 'next/navigation'
import { useSearchParams } from 'next/navigation' import { useSearchParams } from 'next/navigation'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner' import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
@ -28,11 +28,13 @@ export default function Login() {
autoLoginProcess(autoLoginParam) autoLoginProcess(autoLoginParam)
} }
checkSession().then((res) => { // console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
if (res) { // checkSession().then((res) => {
login() // console.log('🚀 ~ checkSession ~ res:', res)
} // if (res) {
}) // login()
// }
// })
}, []) }, [])
const autoLoginProcess = async (autoLoginParam) => { const autoLoginProcess = async (autoLoginParam) => {
@ -49,7 +51,7 @@ export default function Login() {
setSessionState(result) setSessionState(result)
login() login()
} else { } else {
router.push('/login') router.push('/login', undefined, { shallow: true })
} }
}) })
} }

View File

@ -42,7 +42,7 @@ export default function QPagination(props) {
></button> ></button>
</li> </li>
<li className="page-item last"> <li className="page-item last">
<button type="button" disabled={currentPage === totalPages} onClick={() => handlePage(totalPages)}></button> <button type="button" disabled={totalPages === 0 ? true : currentPage === totalPages} onClick={() => handlePage(totalPages)}></button>
</li> </li>
</ol> </ol>
) )

View File

@ -77,8 +77,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.initOptions = options this.initOptions = options
this.init()
this.initLines() this.initLines()
this.init()
this.setShape() this.setShape()
}, },
@ -290,6 +290,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
let points = this.getCurrentPoints() let points = this.getCurrentPoints()
this.texts = [] this.texts = []
points.forEach((start, i) => { points.forEach((start, i) => {
const end = points[(i + 1) % points.length] const end = points[(i + 1) % points.length]
const dx = Big(end.x).minus(Big(start.x)) const dx = Big(end.x).minus(Big(start.x))
@ -321,6 +322,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
lockScalingX: true, lockScalingX: true,
lockScalingY: true, lockScalingY: true,
idx: i, idx: i,
actualSize: this.lines[i].attributes?.actualSize,
planeSize: this.lines[i].attributes?.planeSize,
name: 'lengthText', name: 'lengthText',
parent: this, parent: this,
}) })

View File

@ -9,7 +9,6 @@ import { deepCopyArray } from '@/util/common-utils'
import { canvasState } from '@/store/canvasAtom' import { canvasState } from '@/store/canvasAtom'
import * as turf from '@turf/turf' import * as turf from '@turf/turf'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useModal } from '@nextui-org/react'
import { useModule } from '@/hooks/module/useModule' import { useModule } from '@/hooks/module/useModule'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'

View File

@ -8,7 +8,7 @@ import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { dimmedStore, sessionStore } from '@/store/commonAtom' import { dimmedStore, sessionStore } from '@/store/commonAtom'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { logout } from '@/lib/authActions' import { checkSession, logout } from '@/lib/authActions'
import QSelectBox from '@/components/common/select/QSelectBox' import QSelectBox from '@/components/common/select/QSelectBox'
@ -178,6 +178,7 @@ export default function Header(props) {
<Link <Link
key={`${menu.id}`} key={`${menu.id}`}
href={menu.url} href={menu.url}
replace={true}
onClick={() => { onClick={() => {
// moveHome() // moveHome()
removeStuffRecoil(menu) removeStuffRecoil(menu)
@ -203,6 +204,7 @@ export default function Header(props) {
<Link <Link
scroll={false} scroll={false}
href={m.url} href={m.url}
replace={true}
onClick={() => { onClick={() => {
removeStuffRecoil(m) removeStuffRecoil(m)
}} }}
@ -266,7 +268,7 @@ export default function Header(props) {
code: 'DELETE', code: 'DELETE',
}) })
logout() logout()
router.replace('/login') router.replace('/login', undefined, { shallow: true })
}} }}
> >
{getMessage('header.logout')} {getMessage('header.logout')}

View File

@ -2,7 +2,6 @@
import { useState, useEffect, useRef, useContext } from 'react' import { useState, useEffect, useRef, useContext } from 'react'
import { useRouter, useSearchParams } from 'next/navigation' import { useRouter, useSearchParams } from 'next/navigation'
import { Button } from '@nextui-org/react'
import Select from 'react-select' import Select from 'react-select'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom' import { globalLocaleStore } from '@/store/localeAtom'
@ -528,12 +527,12 @@ export default function StuffDetail() {
} }
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
//
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
if (session?.storeId === 'T01') { if (session?.storeId === 'T01') {
//
res.map((row) => {
row.value = row.saleStoreId
row.label = row.saleStoreName
})
firstList = res.filter((row) => row.saleStoreLevel === '1') firstList = res.filter((row) => row.saleStoreLevel === '1')
firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId) firstList.sort((a, b) => (a.saleStoreId !== 'T01') - (b.saleStoreId !== 'T01') || a.saleStoreId - b.saleStoreId)
favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B') favList = firstList.filter((row) => row.saleStoreId === 'T01' || row.priority !== 'B')
@ -553,7 +552,6 @@ export default function StuffDetail() {
let data = managementState?.firstAgentId ? managementState.firstAgentId : managementState.saleStoreId let data = managementState?.firstAgentId ? managementState.firstAgentId : managementState.saleStoreId
url = `/api/object/saleStore/${data}/list?firstFlg=0&userId=${session?.userId}` url = `/api/object/saleStore/${data}/list?firstFlg=0&userId=${session?.userId}`
get({ url: url }).then((res) => { get({ url: url }).then((res) => {
if (!isEmptyArray(res)) { if (!isEmptyArray(res)) {
res.map((row) => { res.map((row) => {
@ -1711,12 +1709,12 @@ export default function StuffDetail() {
{getMessage('stuff.detail.required')} {getMessage('stuff.detail.required')}
</div> </div>
<div className="left-unit-box"> <div className="left-unit-box">
<Button className="btn-origin grey mr5" onPress={onTempSave} style={{ display: showButton }}> <button type="button" className="btn-origin grey mr5" onClick={onTempSave} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.tempSave')} {getMessage('stuff.detail.btn.tempSave')}
</Button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<button <button
type="button" type="button"
className="btn-origin grey" className="btn-origin grey"
@ -1753,9 +1751,16 @@ export default function StuffDetail() {
)) || )) ||
null} null}
</div> </div>
<Button type="button" className="btn-origin grey" onPress={onSearchDesignRequestPopOpen} style={{ display: showButton }}> <button
type="button"
className="btn-origin grey"
onClick={() => {
onSearchDesignRequestPopOpen()
}}
style={{ display: showButton }}
>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
</Button> </button>
</div> </div>
</td> </td>
</tr> </tr>
@ -2004,9 +2009,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" disabled value={form.watch('zipNo') || ''} /> <input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div> </div>
<Button className="btn-origin grey" onPress={onSearchPostNumberPopOpen} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onSearchPostNumberPopOpen} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.addressPop')} {getMessage('stuff.detail.btn.addressPop')}
</Button> </button>
<div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div> <div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div>
</div> </div>
</td> </td>
@ -2094,9 +2099,9 @@ export default function StuffDetail() {
></Select> ></Select>
</div> </div>
<span className="mr10">{getMessage('stuff.detail.standardWindSpeedIdSpan')}</span> <span className="mr10">{getMessage('stuff.detail.standardWindSpeedIdSpan')}</span>
<Button type="button" className="btn-origin grey" onPress={onSearchWindSpeedPopOpen} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onSearchWindSpeedPopOpen} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.windSpeedPop')} {getMessage('stuff.detail.btn.windSpeedPop')}
</Button> </button>
</div> </div>
</td> </td>
</tr> </tr>
@ -2207,12 +2212,12 @@ export default function StuffDetail() {
</table> </table>
</div> </div>
<div className="sub-right-footer"> <div className="sub-right-footer">
<Button className="btn-origin grey mr5" onPress={onTempSave} style={{ display: showButton }}> <button type="button" className="btn-origin grey mr5" onClick={onTempSave} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.tempSave')} {getMessage('stuff.detail.btn.tempSave')}
</Button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<button <button
type="button" type="button"
className="btn-origin grey" className="btn-origin grey"
@ -2247,23 +2252,23 @@ export default function StuffDetail() {
> >
{getMessage('stuff.detail.btn.moveList')} {getMessage('stuff.detail.btn.moveList')}
</button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<Button type="button" className="btn-origin grey" onPress={onDelete} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onDelete} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.delete')} {getMessage('stuff.detail.btn.delete')}
</Button> </button>
</div> </div>
</> </>
) : ( ) : (
<> <>
<div className="left-unit-box"> <div className="left-unit-box">
<Button className="btn-origin grey mr5" onPress={onTempSave} style={{ display: showButton }}> <button type="button" className="btn-origin grey mr5" onClick={onTempSave} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.tempSave')} {getMessage('stuff.detail.btn.tempSave')}
</Button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<button <button
type="button" type="button"
className="btn-origin grey" className="btn-origin grey"
@ -2305,9 +2310,14 @@ export default function StuffDetail() {
</div> </div>
{managementState?.tempFlg === '1' ? ( {managementState?.tempFlg === '1' ? (
<> <>
<Button className="btn-origin grey" onPress={onSearchDesignRequestPopOpen} style={{ display: showButton }}> <button
type="button"
className="btn-origin grey"
onClick={onSearchDesignRequestPopOpen}
style={{ display: showButton }}
>
{getMessage('stuff.planReqPopup.title')} {getMessage('stuff.planReqPopup.title')}
</Button> </button>
</> </>
) : null} ) : null}
</div> </div>
@ -2566,9 +2576,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" disabled value={form.watch('zipNo') || ''} /> <input type="text" className="input-light" disabled value={form.watch('zipNo') || ''} />
</div> </div>
<Button className="btn-origin grey" onPress={onSearchPostNumberPopOpen} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onSearchPostNumberPopOpen} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.addressPop')} {getMessage('stuff.detail.btn.addressPop')}
</Button> </button>
<div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div> <div className="guide">{getMessage('stuff.detail.btn.addressPop.guide')}</div>
</div> </div>
</td> </td>
@ -2661,9 +2671,9 @@ export default function StuffDetail() {
></Select> ></Select>
</div> </div>
<span className="mr10">{getMessage('stuff.detail.standardWindSpeedIdSpan')}</span> <span className="mr10">{getMessage('stuff.detail.standardWindSpeedIdSpan')}</span>
<Button type="button" className="btn-origin grey" onPress={onSearchWindSpeedPopOpen} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onSearchWindSpeedPopOpen} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.windSpeedPop')} {getMessage('stuff.detail.btn.windSpeedPop')}
</Button> </button>
</div> </div>
</td> </td>
</tr> </tr>
@ -2826,23 +2836,23 @@ export default function StuffDetail() {
> >
{getMessage('stuff.detail.btn.moveList')} {getMessage('stuff.detail.btn.moveList')}
</button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<Button type="button" className="btn-origin grey" onPress={onDelete} style={{ display: showButton }}> <button type="button" className="btn-origin grey" onClick={onDelete} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.delete')} {getMessage('stuff.detail.btn.delete')}
</Button> </button>
</div> </div>
</> </>
) : ( ) : (
<> <>
<div className="sub-right-footer"> <div className="sub-right-footer">
<Button className="btn-origin grey mr5" onPress={onTempSave} style={{ display: showButton }}> <button type="button" className="btn-origin grey mr5" onClick={onTempSave} style={{ display: showButton }}>
{getMessage('stuff.detail.btn.tempSave')} {getMessage('stuff.detail.btn.tempSave')}
</Button> </button>
<Button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}> <button type="submit" className="btn-origin navy mr5" style={{ display: showButton }}>
{getMessage('stuff.detail.btn.save')} {getMessage('stuff.detail.btn.save')}
</Button> </button>
<button <button
type="button" type="button"
className="btn-origin grey" className="btn-origin grey"

View File

@ -23,7 +23,7 @@ export default function StuffSubHeader({ type }) {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState)
const { managementState, setManagementState } = useContext(GlobalDataContext) const { managementState } = useContext(GlobalDataContext)
const [buttonStyle, setButtonStyle] = useState('') const [buttonStyle, setButtonStyle] = useState('')
@ -31,11 +31,11 @@ export default function StuffSubHeader({ type }) {
useEffect(() => { useEffect(() => {
window.scrollTo(0, 0) window.scrollTo(0, 0)
setManagementState({})
}, []) }, [])
useEffect(() => { useEffect(() => {
if (type === 'detail') { if (type === 'detail') {
setButtonStyle('')
if (isObjectNotEmpty(managementState)) { if (isObjectNotEmpty(managementState)) {
if (managementState?.createSaleStoreId === 'T01') { if (managementState?.createSaleStoreId === 'T01') {
if (session?.storeId !== 'T01') { if (session?.storeId !== 'T01') {

View File

@ -1,5 +1,4 @@
import React, { useCallback, useEffect, useRef, useState } from 'react' import React, { useCallback, useEffect, useRef, useState } from 'react'
import { Button, Input } from '@nextui-org/react'
import { useRecoilState, useSetRecoilState } from 'recoil' import { useRecoilState, useSetRecoilState } from 'recoil'
import { modalState } from '@/store/modalAtom' import { modalState } from '@/store/modalAtom'
import { fabric } from 'fabric' import { fabric } from 'fabric'
@ -19,7 +18,7 @@ const ObjectPlacement = ({ canvas }) => {
const [batchType, setBatchType] = useState(BATCH_TYPE.OPENING) const [batchType, setBatchType] = useState(BATCH_TYPE.OPENING)
// free or dimension / // free or dimension /
const [inputType, setInputType] = useState(INPUT_TYPE.FREE) const [inputType, setinputType] = useState(INPUT_TYPE.FREE)
const handleSave = () => { const handleSave = () => {
setMode(batchType) setMode(batchType)
@ -38,7 +37,7 @@ const ObjectPlacement = ({ canvas }) => {
<div className="mb-4"> <div className="mb-4">
<div className="flex"> <div className="flex">
<Button <button
className={`w-1/2 py-2 ${objectPlacementMode.batchType === BATCH_TYPE.OPENING ? 'bg-blue-500 text-white rounded-l' : 'bg-gray-200 text-gray-700 rounded-r'}`} className={`w-1/2 py-2 ${objectPlacementMode.batchType === BATCH_TYPE.OPENING ? 'bg-blue-500 text-white rounded-l' : 'bg-gray-200 text-gray-700 rounded-r'}`}
onClick={() => { onClick={() => {
setBatchType(BATCH_TYPE.OPENING) setBatchType(BATCH_TYPE.OPENING)
@ -46,8 +45,8 @@ const ObjectPlacement = ({ canvas }) => {
}} }}
> >
개구 배치 개구 배치
</Button> </button>
<Button <button
className={`w-1/2 py-2 ${objectPlacementMode.batchType === BATCH_TYPE.SHADOW ? 'bg-blue-500 text-white rounded-l' : 'bg-gray-200 text-gray-700 rounded-r'}`} className={`w-1/2 py-2 ${objectPlacementMode.batchType === BATCH_TYPE.SHADOW ? 'bg-blue-500 text-white rounded-l' : 'bg-gray-200 text-gray-700 rounded-r'}`}
onClick={() => { onClick={() => {
setBatchType(BATCH_TYPE.SHADOW) setBatchType(BATCH_TYPE.SHADOW)
@ -55,7 +54,7 @@ const ObjectPlacement = ({ canvas }) => {
}} }}
> >
그림자 배치 그림자 배치
</Button> </button>
</div> </div>
</div> </div>
@ -64,7 +63,7 @@ const ObjectPlacement = ({ canvas }) => {
<div className="mb-2"> <div className="mb-2">
<label className="inline-flex items-center"> <label className="inline-flex items-center">
<Input <input
type="radio" type="radio"
name="inputType" name="inputType"
checked={objectPlacementMode.inputType === INPUT_TYPE.FREE} checked={objectPlacementMode.inputType === INPUT_TYPE.FREE}
@ -79,7 +78,7 @@ const ObjectPlacement = ({ canvas }) => {
<div className="mb-2"> <div className="mb-2">
<label className="inline-flex items-center"> <label className="inline-flex items-center">
<Input <input
type="radio" type="radio"
name="inputType" name="inputType"
checked={objectPlacementMode.inputType === INPUT_TYPE.DIMENSION} checked={objectPlacementMode.inputType === INPUT_TYPE.DIMENSION}
@ -95,7 +94,7 @@ const ObjectPlacement = ({ canvas }) => {
<div className="flex mb-2"> <div className="flex mb-2">
<div className="mr-2"> <div className="mr-2">
<label className="block text-gray-700 text-sm mb-1">가로길이</label> <label className="block text-gray-700 text-sm mb-1">가로길이</label>
<Input <input
type="text" type="text"
className="w-full px-3 py-2 border rounded" className="w-full px-3 py-2 border rounded"
placeholder="mm" placeholder="mm"
@ -108,7 +107,7 @@ const ObjectPlacement = ({ canvas }) => {
<div> <div>
<label className="block text-gray-700 text-sm mb-1">세로길이</label> <label className="block text-gray-700 text-sm mb-1">세로길이</label>
<Input <input
type="text" type="text"
className="w-full px-3 py-2 border rounded" className="w-full px-3 py-2 border rounded"
placeholder="mm" placeholder="mm"
@ -122,7 +121,7 @@ const ObjectPlacement = ({ canvas }) => {
<div className="mb-4"> <div className="mb-4">
<label className="inline-flex items-center"> <label className="inline-flex items-center">
<Input <input
type="checkbox" type="checkbox"
name={`areaBoundary`} name={`areaBoundary`}
checked={objectPlacementMode.areaBoundary} checked={objectPlacementMode.areaBoundary}
@ -134,9 +133,9 @@ const ObjectPlacement = ({ canvas }) => {
</div> </div>
<div className="text-center"> <div className="text-center">
<Button onClick={handleSave} className="bg-gray-500 text-white py-2 px-4 rounded"> <button onClick={handleSave} className="bg-gray-500 text-white py-2 px-4 rounded">
저장 저장
</Button> </button>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,4 +1,3 @@
import { Button, Input } from '@nextui-org/react'
import { useState } from 'react' import { useState } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil' import { useRecoilValue, useSetRecoilState } from 'recoil'
import { modalState } from '@/store/modalAtom' import { modalState } from '@/store/modalAtom'
@ -780,9 +779,9 @@ export const SurfaceShapeModal = ({ canvas }) => {
const buttons = [] const buttons = []
for (let i = 1; i <= 29; i++) { for (let i = 1; i <= 29; i++) {
buttons.push( buttons.push(
<Button key={i} className="m-1 p-2" value={i} onClick={onChangeType}> <button key={i} className="m-1 p-2" value={i} onClick={onChangeType}>
{i} 추가 {i} 추가
</Button>, </button>,
) )
} }
@ -798,97 +797,97 @@ export const SurfaceShapeModal = ({ canvas }) => {
{type === 1 ? ( {type === 1 ? (
<div> <div>
길이1 길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} /> <input type="text" name={'length1'} value={length1} onChange={setLength} />
{length3 === 0 && ( {length3 === 0 && (
<> <>
길이2 길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} /> <input type="text" name={'length2'} value={length2} onChange={setLength} />
</> </>
)} )}
대각선 <Input type="text" name={'length3'} value={length3} onChange={setLength} /> 대각선 <input type="text" name={'length3'} value={length3} onChange={setLength} />
</div> </div>
) : [2, 4, 5].includes(type) ? ( ) : [2, 4, 5].includes(type) ? (
<div> <div>
길이1 길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} /> <input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2 길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} /> <input type="text" name={'length2'} value={length2} onChange={setLength} />
</div> </div>
) : [3, 6, 7, 8, 9, 24, 28, 29].includes(type) ? ( ) : [3, 6, 7, 8, 9, 24, 28, 29].includes(type) ? (
<> <>
길이1 길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} /> <input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2 길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} /> <input type="text" name={'length2'} value={length2} onChange={setLength} />
길이3 길이3
<Input type="text" name={'length3'} value={length3} onChange={setLength} /> <input type="text" name={'length3'} value={length3} onChange={setLength} />
</> </>
) : [11, 12, 19, 20, 21, 22, 25, 26, 27].includes(type) ? ( ) : [11, 12, 19, 20, 21, 22, 25, 26, 27].includes(type) ? (
<> <>
길이1 길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} /> <input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2 길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} /> <input type="text" name={'length2'} value={length2} onChange={setLength} />
길이3 길이3
<Input type="text" name={'length3'} value={length3} onChange={setLength} /> <input type="text" name={'length3'} value={length3} onChange={setLength} />
길이4 길이4
<Input type="text" name={'length4'} value={length4} onChange={setLength} /> <input type="text" name={'length4'} value={length4} onChange={setLength} />
</> </>
) : [10, 13, 14, 15, 16, 17, 18, 23].includes(type) ? ( ) : [10, 13, 14, 15, 16, 17, 18, 23].includes(type) ? (
<> <>
길이1 길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} /> <input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2 길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} /> <input type="text" name={'length2'} value={length2} onChange={setLength} />
길이3 길이3
<Input type="text" name={'length3'} value={length3} onChange={setLength} /> <input type="text" name={'length3'} value={length3} onChange={setLength} />
길이4 길이4
<Input type="text" name={'length4'} value={length4} onChange={setLength} /> <input type="text" name={'length4'} value={length4} onChange={setLength} />
길이5 길이5
<Input type="text" name={'length5'} value={length5} onChange={setLength} /> <input type="text" name={'length5'} value={length5} onChange={setLength} />
</> </>
) : ( ) : (
<></> <></>
)} )}
<div className="flex flex-col items-center"> <div className="flex flex-col items-center">
<div className="flex"> <div className="flex">
<Button <button
className={`p-4 border rounded-lg ${direction === 'north' ? 'bg-blue-200' : ''} flex items-center justify-center`} className={`p-4 border rounded-lg ${direction === 'north' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('north')} onClick={() => setDirection('north')}
> >
</Button> </button>
</div> </div>
<div className="flex space-x-4"> <div className="flex space-x-4">
<Button <button
className={`p-4 border rounded-lg ${direction === 'west' ? 'bg-blue-200' : ''} flex items-center justify-center`} className={`p-4 border rounded-lg ${direction === 'west' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('west')} onClick={() => setDirection('west')}
> >
</Button> </button>
<Button <button
className={`p-4 border rounded-lg ${direction === 'east' ? 'bg-blue-200' : ''} flex items-center justify-center`} className={`p-4 border rounded-lg ${direction === 'east' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('east')} onClick={() => setDirection('east')}
> >
</Button> </button>
</div> </div>
<div className="mt-4"> <div className="mt-4">
<Button <button
className={`p-4 border rounded-lg ${direction === 'south' ? 'bg-blue-200' : ''} flex items-center justify-center`} className={`p-4 border rounded-lg ${direction === 'south' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('south')} onClick={() => setDirection('south')}
> >
</Button> </button>
</div> </div>
</div> </div>
<div> <div>
<Button className="m-1 p-2" color={'primary'} onClick={closeModal}> <button className="m-1 p-2" color={'primary'} onClick={closeModal}>
닫기 닫기
</Button> </button>
<Button className="m-1 p-2" color={'primary'} onClick={onSave}> <button className="m-1 p-2" color={'primary'} onClick={onSave}>
저장 저장
</Button> </button>
</div> </div>
</> </>
) )

View File

@ -1,38 +0,0 @@
'use client'
import { memo } from 'react'
import { Card, Image } from '@nextui-org/react'
function ThumbnailList(props) {
const { thumbnails, canvas } = props
const handleSelectThumb = (canvasStatus) => {
console.log('canvasStatus', canvasStatus.length)
canvas?.clear() // .
canvas?.loadFromJSON(JSON.parse(canvasStatus), function () {
canvas?.renderAll() // .
})
}
return (
<>
<div className="flex justify-center m-4 w-full">
{thumbnails.length > 0 &&
thumbnails.map((thumbnail, index) => (
<Card isFooterBlurred radius="lg" key={index} className="border-none m-2">
<Image
alt="Woman listing to music"
className="object-cover"
height={200}
src={thumbnail.imageName}
width={200}
onClick={() => handleSelectThumb(thumbnail.canvasStatus)}
/>
</Card>
))}
</div>
</>
)
}
export default memo(ThumbnailList)

View File

@ -16,7 +16,7 @@ export const useMainContentsController = () => {
useEffect(() => { useEffect(() => {
checkSession().then((res) => { checkSession().then((res) => {
if (!res) { if (!res) {
router.replace('/login') router.replace('/login', undefined, { shallow: true })
} }
}) })
setIsGlobalLoading(true) setIsGlobalLoading(true)

View File

@ -1665,13 +1665,13 @@ export const useTrestle = () => {
canvas.add(bracket) canvas.add(bracket)
canvas.renderAll() canvas.renderAll()
if (direction === 'south') { if (direction === 'south') {
startPointY -= height startPointY -= height - moduleIntvlVer / 10
} else if (direction === 'north') { } else if (direction === 'north') {
startPointY += height startPointY += height + moduleIntvlVer / 10
} else if (direction === 'east') { } else if (direction === 'east') {
startPointX -= width startPointX -= width - moduleIntvlHor / 10
} else if (direction === 'west') { } else if (direction === 'west') {
startPointX += width startPointX += width + moduleIntvlHor / 10
} }
} }
} }

View File

@ -12,6 +12,7 @@ import {
triangleToPolygon, triangleToPolygon,
getDegreeByChon, getDegreeByChon,
toFixedWithoutRounding, toFixedWithoutRounding,
getTrianglePoints,
} from '@/util/canvas-util' } 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'
@ -28,13 +29,11 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent() const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useEvent()
// const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useContext(EventContext) // const { addCanvasMouseEventListener, initEvent, addDocumentEventListener } = useContext(EventContext)
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { drawDirectionArrow } = usePolygon() const { drawDirectionArrow, addPolygon, addLengthText } = usePolygon()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const lengthTextFont = useRecoilValue(fontSelector('lengthText')) const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const roofDisplay = useRecoilValue(roofDisplaySelector) const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addPolygon } = usePolygon()
useEffect(() => { useEffect(() => {
if (canvas) { if (canvas) {
// dbClickEvent() // dbClickEvent()
@ -419,7 +418,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
addCanvasMouseEventListener('mouse:up', (e) => { addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) { if (dormer) {
const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer)) const trianglePolygon = pointsToTurfPolygon(offsetRef > 0 ? getTrianglePoints(dormerOffset) : getTrianglePoints(dormer))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때 //지붕 밖으로 그렸을때
@ -448,8 +447,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
direction = 'north' direction = 'north'
} }
let { leftPoints, rightPoints, groupPoints } = let { leftPoints, rightPoints, groupPoints, dormerPoints } =
offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef) : splitDormerTriangle(dormer, directionRef) offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef, dormer) : splitDormerTriangle(dormer, directionRef)
canvas?.remove(offsetRef > 0 ? dormerOffset : dormer) canvas?.remove(offsetRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0) if (offsetRef > 0)
@ -512,10 +511,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
false, false,
) )
leftTriangle.texts.forEach((text) => {
text.bringToFront()
})
const rightTriangle = addPolygon( const rightTriangle = addPolygon(
rightPoints, rightPoints,
{ {
@ -587,7 +582,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
canvas?.remove(dormer) canvas?.remove(dormer)
offsetPolygon = addPolygon( offsetPolygon = addPolygon(
triangleToPolygon(dormer), dormerPoints,
{ {
selectable: true, selectable: true,
lockMovementX: true, // X 축 이동 잠금 lockMovementX: true, // X 축 이동 잠금
@ -604,7 +599,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontSize: lengthTextFont.fontSize.value, fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value, fontWeight: lengthTextFont.fontWeight.value,
angle: originAngle, // angle: originAngle,
pitch: pitch, pitch: pitch,
dormerAttributes: { dormerAttributes: {
height: height, height: height,
@ -639,6 +634,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
) )
} }
addLengthText(leftTriangle)
addLengthText(rightTriangle)
addLengthText(offsetPolygon)
const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle] const groupPolygon = offsetPolygon ? [leftTriangle, rightTriangle, offsetPolygon] : [leftTriangle, rightTriangle]
const objectGroup = new fabric.Group(groupPolygon, { const objectGroup = new fabric.Group(groupPolygon, {
@ -667,9 +666,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
} }
}) })
} else if (buttonAct === 4) { } else if (buttonAct === 4) {
const heightLength = height - (width / 2) * (pitch * 0.25)
const heightOffsetLength = height + offsetRef - (width / 2 + offsetWidthRef) * (pitch * 0.25)
addCanvasMouseEventListener('mouse:move', (e) => { addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true isDown = true
if (!isDown) return if (!isDown) return
@ -774,7 +770,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
addCanvasMouseEventListener('mouse:up', (e) => { addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) { if (dormer) {
const pentagonPolygon = pointsToTurfPolygon(dormer.points) const pentagonPolygon = pointsToTurfPolygon(offsetRef > 0 ? dormerOffset.getCurrentPoints() : dormer.getCurrentPoints())
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface) const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때 //지붕 밖으로 그렸을때
@ -804,11 +800,8 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
direction = 'north' direction = 'north'
} }
const offsetMode = offsetRef > 0 || offsetWidthRef > 0 ? 'offset' : 'normal'
let { leftPoints, rightPoints, groupPoints } = let { leftPoints, rightPoints, groupPoints } =
offsetRef > 0 || offsetWidthRef > 0 offsetRef > 0 || offsetWidthRef > 0 ? splitDormerPentagon(dormerOffset, directionRef) : splitDormerPentagon(dormer, directionRef)
? splitDormerPentagon(dormerOffset, directionRef, offsetMode)
: splitDormerPentagon(dormer, directionRef, offsetMode)
canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer) canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0) if (offsetRef > 0)
@ -948,7 +941,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
canvas?.remove(dormer) canvas?.remove(dormer)
offsetPolygon = addPolygon( offsetPolygon = addPolygon(
dormer.points, dormer.getCurrentPoints(),
{ {
selectable: true, selectable: true,
lockMovementX: true, // X 축 이동 잠금 lockMovementX: true, // X 축 이동 잠금
@ -965,7 +958,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
fontSize: lengthTextFont.fontSize.value, fontSize: lengthTextFont.fontSize.value,
fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', fontStyle: lengthTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: lengthTextFont.fontWeight.value, fontWeight: lengthTextFont.fontWeight.value,
angle: originAngle, // angle: originAngle,
groupPoints: groupPoints, groupPoints: groupPoints,
dormerAttributes: { dormerAttributes: {
height: height, height: height,
@ -1012,6 +1005,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
) )
} }
addLengthText(leftPentagon)
addLengthText(rightPentagon)
addLengthText(offsetPolygon)
const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon] const groupPolygon = offsetPolygon ? [leftPentagon, rightPentagon, offsetPolygon] : [leftPentagon, rightPentagon]
const objectGroup = new fabric.Group(groupPolygon, { const objectGroup = new fabric.Group(groupPolygon, {
@ -1058,13 +1055,18 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
if (setIsHidden) setIsHidden(false) if (setIsHidden) setIsHidden(false)
} }
const splitDormerTriangle = (triangle, direction) => { const splitDormerTriangle = (triangle, direction, dormer = null) => {
const halfWidth = triangle.width / 2 const halfWidth = triangle.width / 2
let dormerPoints = []
let leftPoints = [] let leftPoints = []
let rightPoints = [] let rightPoints = []
let groupPoints = [] let groupPoints = []
if (dormer) {
dormerPoints = getTrianglePoints(dormer)
}
if (direction === 'down') { if (direction === 'down') {
leftPoints = [ leftPoints = [
{ x: triangle.left, y: triangle.top }, { x: triangle.left, y: triangle.top },
@ -1122,23 +1124,23 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
} else if (direction === 'right') { } else if (direction === 'right') {
leftPoints = [ leftPoints = [
{ x: triangle.left, y: triangle.top }, { x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + halfWidth },
{ x: triangle.left + triangle.height, y: triangle.top }, { x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height },
] ]
rightPoints = [ rightPoints = [
{ x: triangle.left, y: triangle.top }, { x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height }, { x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height }, { x: triangle.left + triangle.height, y: triangle.top - halfWidth },
] ]
groupPoints = [ groupPoints = [
{ x: triangle.left, y: triangle.top }, { x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height }, { x: triangle.left + triangle.height, y: triangle.top + halfWidth },
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height }, { x: triangle.left + triangle.height, y: triangle.top - halfWidth },
] ]
} }
return { leftPoints, rightPoints, groupPoints } return { leftPoints, rightPoints, groupPoints, dormerPoints }
} }
const splitDormerPentagon = (pentagon, direction, offsetMode) => { const splitDormerPentagon = (pentagon, direction, offsetMode) => {
@ -1326,15 +1328,24 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
const reGroupObject = (groupObj) => { const reGroupObject = (groupObj) => {
groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨 groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨
console.log('groupObj', groupObj)
const reGroupObjects = [] const reGroupObjects = []
groupObj._objects.forEach((obj) => { groupObj._objects.forEach((obj) => {
const newObj = new QPolygon(obj.getCurrentPoints(), { const newObj = addPolygon(
...obj, obj.getCurrentPoints(),
points: obj.getCurrentPoints(), {
scaleX: 1, ...obj,
scaleY: 1, points: obj.getCurrentPoints(),
texts: [], scaleX: 1,
}) scaleY: 1,
lines: obj.lines ?? [],
groupPoints: groupObj.groupPoints ?? [],
groupId: groupObj.groupId ?? '',
},
false,
)
reGroupObjects.push(newObj) reGroupObjects.push(newObj)
canvas.remove(obj) canvas.remove(obj)
if (newObj.direction) { if (newObj.direction) {
@ -1342,6 +1353,7 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
} }
newObj.fire('modified') newObj.fire('modified')
}) })
const reGroup = new fabric.Group(reGroupObjects, { const reGroup = new fabric.Group(reGroupObjects, {
subTargetCheck: true, subTargetCheck: true,
name: groupObj.name, name: groupObj.name,
@ -1350,10 +1362,20 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
parentId: groupObj.parentId, parentId: groupObj.parentId,
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
groupPoints: groupObj.groupPoints ?? [],
groupId: groupObj.groupId ?? '',
}) })
canvas?.add(reGroup) canvas?.add(reGroup)
canvas?.remove(groupObj) canvas?.remove(groupObj)
reGroup._objects.forEach((obj) => {
if (obj.hasOwnProperty('texts')) {
obj.texts.forEach((text) => {
text.bringToFront()
})
}
})
return reGroup return reGroup
} }
@ -1368,6 +1390,10 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
}) })
const originObj = { ...obj } const originObj = { ...obj }
const turfSurface = pointsToTurfPolygon(parentSurface.points)
const originLeft = obj.left
const originTop = obj.top
addCanvasMouseEventListener('mouse:up', (e) => { addCanvasMouseEventListener('mouse:up', (e) => {
//개구, 그림자 타입일 경우 폴리곤 타입 변경 //개구, 그림자 타입일 경우 폴리곤 타입 변경
if (BATCH_TYPE.OPENING === obj.name || BATCH_TYPE.SHADOW === obj.name) { if (BATCH_TYPE.OPENING === obj.name || BATCH_TYPE.SHADOW === obj.name) {
@ -1375,7 +1401,6 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
points: rectToPolygon(obj), points: rectToPolygon(obj),
}) })
const turfSurface = pointsToTurfPolygon(parentSurface.points)
const turfObject = pointsToTurfPolygon(obj.points) const turfObject = pointsToTurfPolygon(obj.points)
if (turf.booleanWithin(turfObject, turfSurface)) { if (turf.booleanWithin(turfObject, turfSurface)) {
@ -1398,8 +1423,36 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
lockMovementY: true, lockMovementY: true,
}) })
if (obj.type === 'group') reGroupObject(obj) if (obj.name === BATCH_TYPE.TRIANGLE_DORMER || obj.name === BATCH_TYPE.PENTAGON_DORMER) {
obj.setCoords() const calcLeft = obj.left - originLeft
const calcTop = obj.top - originTop
const currentDormerPoints = obj.groupPoints.map((item) => {
return {
x: item.x + calcLeft,
y: item.y + calcTop,
}
})
const turfObject = pointsToTurfPolygon(currentDormerPoints)
if (turf.booleanWithin(turfObject, turfSurface)) {
obj.set({
lockMovementX: true,
lockMovementY: true,
groupPoints: currentDormerPoints,
})
if (obj.type === 'group') reGroupObject(obj)
obj.setCoords()
} else {
swalFire({
title: getMessage('batch.object.outside.roof'),
icon: 'warning',
})
obj.set({ ...originObj, lockMovementX: true, lockMovementY: true })
}
}
} }
canvas.discardActiveObject() canvas.discardActiveObject()
initEvent() initEvent()
@ -1512,8 +1565,27 @@ export function useObjectBatch({ isHidden, setIsHidden }) {
length2 = parseInt(length2) / 10 length2 = parseInt(length2) / 10
const dormer = canvas.getActiveObject() const dormer = canvas.getActiveObject()
if (length1) dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1 if (length1) {
if (length2) dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2 if (!arrow1) {
swalFire({
title: getMessage('length.direction.is.required'),
icon: 'warning',
})
} else {
dormer.top = arrow1 === 'down' ? dormer.top + length1 : dormer.top - length1
}
}
if (length2) {
if (!arrow2) {
swalFire({
title: getMessage('length.direction.is.required'),
icon: 'warning',
})
} else {
dormer.left = arrow2 === 'left' ? dormer.left - length2 : dormer.left + length2
}
}
if (dormer.type === 'group') { if (dormer.type === 'group') {
const newDormer = reGroupObject(dormer) const newDormer = reGroupObject(dormer)

View File

@ -146,13 +146,9 @@ export function useCanvasSetting(executeEffect = true) {
if (!executeEffect) { if (!executeEffect) {
return return
} }
const tempFetchRoofMaterials = !fetchRoofMaterials
/** 초 1회만 실행하도록 처리 */ /** 초 1회만 실행하도록 처리 */
setFetchRoofMaterials(tempFetchRoofMaterials) addRoofMaterials()
if (tempFetchRoofMaterials) {
addRoofMaterials()
}
}, []) }, [])
/** /**

View File

@ -197,7 +197,6 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
surfaceId: surfaceId, surfaceId: surfaceId,
direction: direction, direction: direction,
}) })
canvas?.add(batchSurface)
canvas.setActiveObject(batchSurface) canvas.setActiveObject(batchSurface)
setSurfaceShapePattern(batchSurface, roofDisplay.column) setSurfaceShapePattern(batchSurface, roofDisplay.column)
drawDirectionArrow(batchSurface) drawDirectionArrow(batchSurface)

View File

@ -3,8 +3,8 @@ import { fabric } from 'fabric'
import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util' import { actionHandler, anchorWrapper, polygonPositionHandler } from '@/util/canvas-util'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { canvasSizeState, canvasState, fontSizeState } from '@/store/canvasAtom' import { canvasSizeState, canvasState, canvasZoomState, fontSizeState } from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import { defineQLine } from '@/util/qline-utils' import { defineQLine } from '@/util/qline-utils'
@ -27,6 +27,7 @@ export function useCanvas(id) {
const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent()
const isImageDisplay = useRecoilValue(imageDisplaySelector) const isImageDisplay = useRecoilValue(imageDisplaySelector)
const {} = useFont() const {} = useFont()
const resetCanvasZoom = useResetRecoilState(canvasZoomState)
/** /**
* 처음 셋팅 * 처음 셋팅
@ -43,7 +44,7 @@ export function useCanvas(id) {
setCanvas(c) setCanvas(c)
setCanvasForEvent(c) setCanvasForEvent(c)
attachDefaultEventOnCanvas() attachDefaultEventOnCanvas()
resetCanvasZoom()
return () => { return () => {
// c.dispose() // c.dispose()
c.clear() c.clear()

View File

@ -1040,3 +1040,17 @@ export function calculateVisibleModuleHeight(sourceWidth, sourceHeight, angle, d
export function toFixedWithoutRounding(number, decimals) { export function toFixedWithoutRounding(number, decimals) {
return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals) return Math.floor(number * Math.pow(10, decimals)) / Math.pow(10, decimals)
} }
export function getTrianglePoints(triangle) {
const matrix = triangle.calcTransformMatrix()
const w = triangle.width / 2
const h = triangle.height / 2
const points = [
{ x: 0, y: -h },
{ x: -w, y: h },
{ x: w, y: h },
]
return points.map((point) => fabric.util.transformPoint(point, matrix))
}

View File

@ -1,2 +1,2 @@
var exec = require('child_process').exec var exec = require('child_process').exec
exec('yarn serve', { windowsHide: true }) exec('yarn start', { windowsHide: true })

View File

@ -1,5 +1,3 @@
const { nextui } = require('@nextui-org/react')
/** @type {import('tailwindcss').Config} */ /** @type {import('tailwindcss').Config} */
module.exports = { module.exports = {
content: [ content: [
@ -12,11 +10,10 @@ module.exports = {
extend: { extend: {
backgroundImage: { backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic': 'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
}, },
}, },
}, },
darkMode: 'class', darkMode: 'class',
plugins: [nextui()], plugins: [],
} }