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"

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"

View File

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

View File

@ -5,12 +5,12 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"start": "next start -p 3000",
"start:dev": "next start -p 3001",
"lint": "next lint",
"serve": "node server.js"
},
"dependencies": {
"@nextui-org/react": "^2.4.2",
"ag-grid-react": "^32.0.2",
"axios": "^1.7.8",
"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 { globalLocaleStore } from '@/store/localeAtom'
import { sessionStore } from '@/store/commonAtom'
import { useRouter } from 'next/navigation'
import { redirect, useRouter } from 'next/navigation'
import { useSearchParams } from 'next/navigation'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
@ -28,11 +28,13 @@ export default function Login() {
autoLoginProcess(autoLoginParam)
}
checkSession().then((res) => {
if (res) {
login()
}
})
// console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
// checkSession().then((res) => {
// console.log('🚀 ~ checkSession ~ res:', res)
// if (res) {
// login()
// }
// })
}, [])
const autoLoginProcess = async (autoLoginParam) => {
@ -49,7 +51,7 @@ export default function Login() {
setSessionState(result)
login()
} else {
router.push('/login')
router.push('/login', undefined, { shallow: true })
}
})
}

View File

@ -42,7 +42,7 @@ export default function QPagination(props) {
></button>
</li>
<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>
</ol>
)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,4 +1,3 @@
import { Button, Input } from '@nextui-org/react'
import { useState } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { modalState } from '@/store/modalAtom'
@ -780,9 +779,9 @@ export const SurfaceShapeModal = ({ canvas }) => {
const buttons = []
for (let i = 1; i <= 29; i++) {
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} 추가
</Button>,
</button>,
)
}
@ -798,97 +797,97 @@ export const SurfaceShapeModal = ({ canvas }) => {
{type === 1 ? (
<div>
길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} />
<input type="text" name={'length1'} value={length1} onChange={setLength} />
{length3 === 0 && (
<>
길이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>
) : [2, 4, 5].includes(type) ? (
<div>
길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} />
<input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} />
<input type="text" name={'length2'} value={length2} onChange={setLength} />
</div>
) : [3, 6, 7, 8, 9, 24, 28, 29].includes(type) ? (
<>
길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} />
<input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} />
<input type="text" name={'length2'} value={length2} onChange={setLength} />
길이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) ? (
<>
길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} />
<input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} />
<input type="text" name={'length2'} value={length2} onChange={setLength} />
길이3
<Input type="text" name={'length3'} value={length3} onChange={setLength} />
<input type="text" name={'length3'} value={length3} onChange={setLength} />
길이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) ? (
<>
길이1
<Input type="text" name={'length1'} value={length1} onChange={setLength} />
<input type="text" name={'length1'} value={length1} onChange={setLength} />
길이2
<Input type="text" name={'length2'} value={length2} onChange={setLength} />
<input type="text" name={'length2'} value={length2} onChange={setLength} />
길이3
<Input type="text" name={'length3'} value={length3} onChange={setLength} />
<input type="text" name={'length3'} value={length3} onChange={setLength} />
길이4
<Input type="text" name={'length4'} value={length4} onChange={setLength} />
<input type="text" name={'length4'} value={length4} onChange={setLength} />
길이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">
<Button
<button
className={`p-4 border rounded-lg ${direction === 'north' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('north')}
>
</Button>
</button>
</div>
<div className="flex space-x-4">
<Button
<button
className={`p-4 border rounded-lg ${direction === 'west' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('west')}
>
</Button>
<Button
</button>
<button
className={`p-4 border rounded-lg ${direction === 'east' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('east')}
>
</Button>
</button>
</div>
<div className="mt-4">
<Button
<button
className={`p-4 border rounded-lg ${direction === 'south' ? 'bg-blue-200' : ''} flex items-center justify-center`}
onClick={() => setDirection('south')}
>
</Button>
</button>
</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 className="m-1 p-2" color={'primary'} onClick={onSave}>
</button>
<button className="m-1 p-2" color={'primary'} onClick={onSave}>
저장
</Button>
</button>
</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(() => {
checkSession().then((res) => {
if (!res) {
router.replace('/login')
router.replace('/login', undefined, { shallow: true })
}
})
setIsGlobalLoading(true)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1040,3 +1040,17 @@ export function calculateVisibleModuleHeight(sourceWidth, sourceHeight, angle, d
export function toFixedWithoutRounding(number, 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
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} */
module.exports = {
content: [
@ -12,11 +10,10 @@ module.exports = {
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
'gradient-conic': 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
darkMode: 'class',
plugins: [nextui()],
plugins: [],
}