feat: 썸네일 기능 추가

This commit is contained in:
yoosangwook 2024-08-22 16:59:04 +09:00
parent 86e863e240
commit 39e8554eff
10 changed files with 86 additions and 31 deletions

View File

@ -1,6 +1,7 @@
NEXT_PUBLIC_TEST="테스트변수입니다. development" 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"
DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true" DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true"

View File

@ -27,7 +27,7 @@
"react-responsive-modal": "^6.4.2", "react-responsive-modal": "^6.4.2",
"react-toastify": "^10.0.5", "react-toastify": "^10.0.5",
"recoil": "^0.7.7", "recoil": "^0.7.7",
"uuid": "^9.0.1" "uuid": "^10.0.0"
}, },
"devDependencies": { "devDependencies": {
"@turf/turf": "^7.0.0", "@turf/turf": "^7.0.0",

View File

@ -3,7 +3,7 @@ import RoofSelect from '@/app/[locale]/roof2/RoofSelect'
import { initCheck } from '@/util/session-util' import { initCheck } from '@/util/session-util'
export default async function Roof2Page() { export default async function Roof2Page() {
await initCheck() const session = await initCheck()
return ( return (
<> <>
@ -13,7 +13,7 @@ export default async function Roof2Page() {
</div> </div>
</div> </div>
<div className="flex flex-col justify-center my-8 pt-20"> <div className="flex flex-col justify-center my-8 pt-20">
<Roof2 /> <Roof2 session={session} />
</div> </div>
</> </>
) )

View File

@ -2,6 +2,7 @@
import { useCanvas } from '@/hooks/useCanvas' import { useCanvas } from '@/hooks/useCanvas'
import { useEffect, useState, useRef } from 'react' import { useEffect, useState, useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMode } from '@/hooks/useMode' import { useMode } from '@/hooks/useMode'
import { Button } from '@nextui-org/react' import { Button } from '@nextui-org/react'
import RangeSlider from './ui/RangeSlider' import RangeSlider from './ui/RangeSlider'
@ -23,8 +24,9 @@ import { QPolygon } from '@/components/fabric/QPolygon'
import ThumbnailList from './ui/ThumbnailLIst' import ThumbnailList from './ui/ThumbnailLIst'
import CanvasWithContextMenu from '@/util/context-util' import CanvasWithContextMenu from '@/util/context-util'
import { Mode } from '@/common/common' import { Mode } from '@/common/common'
import { get } from '@/lib/Axios'
export default function Roof2() { export default function Roof2({ session }) {
const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas') const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas')
const canvasRef = useRef(null) const canvasRef = useRef(null)
@ -60,6 +62,7 @@ export default function Roof2() {
const [thumbnails, setThumbnails] = useState([]) const [thumbnails, setThumbnails] = useState([])
const thumbnailProps = { const thumbnailProps = {
thumbnails, thumbnails,
canvas,
} }
const { const {
@ -85,6 +88,23 @@ export default function Roof2() {
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom) // const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
useEffect(() => {
get({ url: `/api/canvas-management/canvas-statuses/by-object/test123240822001` }).then((res) => {
const arrangeData = res.map((item) => {
console.log(item.canvasStatus.replace(/##/g, '"').replace(/\\/g, ''))
const test = item.canvasStatus.replace(/##/g, '"').replace(/\\/g, '')
const test2 = test.substring(1, test.length - 1)
return {
id: item.id,
userId: item.userId,
imageName: `/canvasState/${item.imageName}.png`,
canvasStatus: JSON.stringify(test2),
}
})
setThumbnails(arrangeData)
})
}, [])
useEffect(() => { useEffect(() => {
if (!canvas) { if (!canvas) {
return return
@ -632,7 +652,7 @@ export default function Roof2() {
</Button> </Button>
</> </>
)} )}
<Button className="m-1 p-2" onClick={() => saveImage('title')}> <Button className="m-1 p-2" onClick={() => saveImage(uuidv4(), session.userId, setThumbnails)}>
저장 저장
</Button> </Button>
{/*<Button className="m-1 p-2" onClick={rotateShape}> {/*<Button className="m-1 p-2" onClick={rotateShape}>

View File

@ -1,10 +1,19 @@
import { Card, Image } from '@nextui-org/react' 'use client'
import { memo } from 'react' import { memo } from 'react'
import { Card, Image } from '@nextui-org/react'
function ThumbnailList(props) { function ThumbnailList(props) {
const { thumbnails } = props const { thumbnails, canvas } = props
console.log('thumbnails', thumbnails)
console.log('ThumbnailList') const handleSelectThumb = (canvasStatus) => {
console.log('canvasStatus', canvasStatus.length)
canvas?.clear() // .
canvas?.loadFromJSON(JSON.parse(canvasStatus), function () {
canvas?.renderAll() // .
})
}
return ( return (
<> <>
@ -12,7 +21,14 @@ function ThumbnailList(props) {
{thumbnails.length > 0 && {thumbnails.length > 0 &&
thumbnails.map((thumbnail, index) => ( thumbnails.map((thumbnail, index) => (
<Card isFooterBlurred radius="lg" className="border-none m-2"> <Card isFooterBlurred radius="lg" className="border-none m-2">
<Image alt="Woman listing to music" className="object-cover" height={200} src="https://nextui.org/images/hero-card.jpeg" width={200} /> <Image
alt="Woman listing to music"
className="object-cover"
height={200}
src={thumbnail.imageName}
width={200}
onClick={() => handleSelectThumb(thumbnail.canvasStatus)}
/>
</Card> </Card>
))} ))}
</div> </div>

View File

@ -11,6 +11,7 @@ import { defineQLine } from '@/util/qline-utils'
import { defineQPloygon } from '@/util/qpolygon-utils' import { defineQPloygon } from '@/util/qpolygon-utils'
import { writeImage } from '@/lib/canvas' import { writeImage } from '@/lib/canvas'
import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { useCanvasEvent } from '@/hooks/useCanvasEvent'
import { post } from '@/lib/Axios'
export function useCanvas(id) { export function useCanvas(id) {
const [canvas, setCanvas] = useState() const [canvas, setCanvas] = useState()
@ -333,7 +334,7 @@ export function useCanvas(id) {
* 이미지로 저장하는 함수 * 이미지로 저장하는 함수
* @param {string} title - 저장할 이미지 이름 * @param {string} title - 저장할 이미지 이름
*/ */
const saveImage = async (title = 'canvas') => { const saveImage = async (title = 'canvas', userId, setThumbnails) => {
removeMouseLines() removeMouseLines()
await writeImage(title, canvas?.toDataURL('image/png').replace('data:image/png;base64,', '')) await writeImage(title, canvas?.toDataURL('image/png').replace('data:image/png;base64,', ''))
.then((res) => { .then((res) => {
@ -342,6 +343,19 @@ export function useCanvas(id) {
.catch((err) => { .catch((err) => {
console.log('err', err) console.log('err', err)
}) })
const canvasStatus = addCanvas()
const patternData = {
userId: userId,
imageName: title,
objectNo: 'test123240822001',
canvasStatus: JSON.stringify(canvasStatus).replace(/"/g, '##'),
}
await post({ url: '/api/canvas-management/canvas-statuses', data: patternData })
setThumbnails((prev) => [...prev, { imageName: `/canvasState/${title}.png`, userId, canvasStatus: JSON.stringify(canvasStatus) }])
} }
const handleFlip = () => { const handleFlip = () => {
@ -435,15 +449,16 @@ export function useCanvas(id) {
const str = JSON.stringify(objs) const str = JSON.stringify(objs)
canvas?.clear() canvas?.clear()
return str
setTimeout(() => { // setTimeout(() => {
// 역직렬화하여 캔버스에 객체를 다시 추가합니다. // // 역직렬화하여 캔버스에 객체를 다시 추가합니다.
canvas?.loadFromJSON(JSON.parse(str), function () { // canvas?.loadFromJSON(JSON.parse(str), function () {
// 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다. // // 모든 객체가 로드되고 캔버스에 추가된 후 호출됩니다.
console.log(canvas?.getObjects().filter((obj) => obj.name === 'roof')) // console.log(canvas?.getObjects().filter((obj) => obj.name === 'roof'))
canvas?.renderAll() // 캔버스를 다시 그립니다. // canvas?.renderAll() // 캔버스를 다시 그립니다.
}) // })
}, 1000) // }, 1000)
} }
return { return {

View File

@ -24,32 +24,32 @@ axiosInstance.interceptors.request.use(undefined, (error) => {
// } // }
}) })
export const get = (url) => export const get = ({ url }) =>
axiosInstance axiosInstance
.get(url) .get(url)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
export const post = (url, data) => export const post = ({ url, data }) =>
axiosInstance axiosInstance
.post(url, data) .post(url, data)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
export const put = (url, data) => export const put = ({ url, data }) =>
axiosInstance axiosInstance
.put(url, data) .put(url, data)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
export const patch = (url, data) => export const patch = ({ url, data }) =>
axiosInstance axiosInstance
.patch(url, data) .patch(url, data)
.then((res) => res.data) .then((res) => res.data)
.catch(console.error) .catch(console.error)
export const del = (url) => export const del = ({ url }) =>
axiosInstance axiosInstance
.delete(url) .delete(url)
.then((res) => res.data) .then((res) => res.data)

View File

@ -48,8 +48,9 @@ export async function login(formData) {
throw Error('Wrong Credentials!') throw Error('Wrong Credentials!')
} }
session.name = loginUser.USER_ID session.name = loginUser.name
session.email = loginUser.SALE_STORE_ID session.userId = loginUser.userId
session.email = loginUser.email
session.isLoggedIn = true session.isLoggedIn = true
console.log('session:', session) console.log('session:', session)

View File

@ -7,4 +7,6 @@ export const initCheck = async () => {
if (!session.isLoggedIn) { if (!session.isLoggedIn) {
redirect('/login') redirect('/login')
} }
return session
} }

View File

@ -6108,16 +6108,16 @@ util-deprecate@^1.0.1, util-deprecate@^1.0.2:
resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
uuid@^10.0.0:
version "10.0.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-10.0.0.tgz#5a95aa454e6e002725c79055fd42aaba30ca6294"
integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==
uuid@^8.3.0: uuid@^8.3.0:
version "8.3.2" version "8.3.2"
resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
uuid@^9.0.1:
version "9.0.1"
resolved "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz"
integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==
w3c-hr-time@^1.0.2: w3c-hr-time@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz"