diff --git a/MainLayout.codediagram b/docs/diagrams/MainLayout.codediagram similarity index 100% rename from MainLayout.codediagram rename to docs/diagrams/MainLayout.codediagram diff --git a/docs/diagrams/canvas-setting.codediagram b/docs/diagrams/canvas-setting.codediagram new file mode 100644 index 00000000..bd87ebb4 --- /dev/null +++ b/docs/diagrams/canvas-setting.codediagram @@ -0,0 +1 @@ +{"id":-1,"name":"Onboarding diagram","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"HduNR37Az-","position":{"x":800,"y":-590},"sizes":{"width":400,"height":146},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"\bCanvas Setting "},{"type":"text","marks":[{"type":"bold"}],"text":"☀️"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"canvas 전체 내용을 설정한다."}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"저장 버튼 없이 UI를 변경하면 Update가 일어난다."}]}]}]}]},"color":{"bgColor":"hsla(211, 33%, 22%, 1)","bgName":"blue"},"nodeType":"block"},{"uid":"DiKZ2umB3G","position":{"x":450,"y":-250},"sizes":{"width":549.78125,"height":189.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"SettingModal01.jsx"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"{buttonAct === 1 && }\n{buttonAct === 2 && }\n{buttonAct === 3 && }"}]}]},"nodeType":"block"},{"uid":"EAKK_XFrUP","position":{"x":70,"y":90},"sizes":{"width":400,"height":210},"autoheight":false,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"FirstOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"디스플레이 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function FirstOption(props) {"}]}]},"nodeType":"block"},{"uid":"-QZuVi6n7M","position":{"x":540,"y":90},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"SecondOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"글꼴 및 도면 크기 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function SecondOption(props) {"}]}]},"nodeType":"block"},{"uid":"OIDIoPPwFU","position":{"x":1220,"y":90},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/setting01/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"GridOption.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"그리드 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function GridOption(props) {"}]}]},"nodeType":"block"},{"uid":"iEbZe6FrdP","position":{"x":550,"y":380},"sizes":{"width":400,"height":200},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/dimensionLine/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"DimensionLineSetting.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"글꼴 및 크기 변경"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function DimensionLineSetting(props) {"}]}]},"nodeType":"block"},{"uid":"5ovY6Y7atI","position":{"x":1010,"y":380},"sizes":{"width":400,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/grid/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"DotLineGrid.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"점, 선, 그리드 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function DotLineGrid(props) {"}]}]},"nodeType":"block"},{"uid":"yVBft0fd68","position":{"x":1470,"y":380},"sizes":{"width":400,"height":200},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/common/color-picker/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"ColorPickerModal.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"색 설정"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function ColorPickerModal(props) {"}]}]},"nodeType":"block"},{"uid":"KcDc1JqWZL","position":{"x":270,"y":-700},"sizes":{"width":470,"height":336.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"CanvasMenu.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"modal 창 ON"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"const handlePopup = () => {\n const id = uuidv4()\n addPopup(id, 1, , true)\n}"}]},{"type":"paragraph","content":[{"type":"text","text":"canvas 설정 조회"}]},{"type":"codeBlock","attrs":{"language":"javascriptreact","wrapCode":false},"content":[{"type":"text","text":"const { fetchSettings } = useCanvasSetting()"}]}]},"nodeType":"block"},{"uid":"y2Vg-dWtlJ","position":{"x":-390,"y":-620},"sizes":{"width":520,"height":385.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/option/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"useCanvasSetting.js"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"canvas 설정 관리 hook"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"const fetchSettings = async () => {"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":false},"content":[{"type":"text","text":"const [settingsData, setSettingsData] = useState({\n ...settingModalFirstOptions,\n ...settingModalSecondOptions,\n ...globalFont,\n ...dotLineGridSetting,\n ...planSizeSettingMode,\n ...dimensionLineSettings,\n ...color,\n })"}]}]},"nodeType":"block"}],"configs":{"centerX":373.0590486994188,"centerY":572.9825354968084,"zoomLevel":1.017264811197917},"arrowData":{"arrowsMap":{"arrow-point-bI0wBh3Ufk-bottom-point-PSPLIYKa9J-top":{"to":"point-PSPLIYKa9J-top","from":"point-bI0wBh3Ufk-bottom","label":"Normal Box","direction":"ft","selectable":true},"arrow-point-bI0wBh3Ufk-bottom-point-ytXK_ayIc1-top":{"to":"point-ytXK_ayIc1-top","from":"point-bI0wBh3Ufk-bottom","label":"Code Box","direction":"ft","selectable":true},"arrow-point-hyyRZE3E8u-right-point-6ZopTaEaDZ-left":{"to":"point-6ZopTaEaDZ-left","from":"point-hyyRZE3E8u-right","label":"call","direction":"ft","selectable":true}},"pointsMap":{"point-PSPLIYKa9J-top":{"x":805.9999797489683,"y":60,"id":"point-PSPLIYKa9J-top","direction":"top"},"point-ytXK_ayIc1-top":{"x":205.99999493724206,"y":60,"id":"point-ytXK_ayIc1-top","direction":"top"},"point-6ZopTaEaDZ-left":{"x":220,"y":605.9999898744841,"id":"point-6ZopTaEaDZ-left","direction":"left"},"point-hyyRZE3E8u-right":{"x":100,"y":606,"id":"point-hyyRZE3E8u-right","direction":"right"},"point-bI0wBh3Ufk-bottom":{"x":515.9999797489683,"y":-40,"id":"point-bI0wBh3Ufk-bottom","direction":"bottom"}},"edgesMap":{"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-EAKK_XFrUP-EAKK_XFrUP-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-EAKK_XFrUP-EAKK_XFrUP-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"EAKK_XFrUP","toHandleId":"EAKK_XFrUP-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-DiKZ2umB3G-DiKZ2umB3G-bottom--QZuVi6n7M--QZuVi6n7M-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom--QZuVi6n7M--QZuVi6n7M-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"-QZuVi6n7M","toHandleId":"-QZuVi6n7M-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-OIDIoPPwFU-OIDIoPPwFU-top":{"uid":"edge-DiKZ2umB3G-DiKZ2umB3G-bottom-OIDIoPPwFU-OIDIoPPwFU-top","fromNodeId":"DiKZ2umB3G","fromHandleId":"DiKZ2umB3G-bottom","toNodeId":"OIDIoPPwFU","toHandleId":"OIDIoPPwFU-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge--QZuVi6n7M--QZuVi6n7M-bottom-iEbZe6FrdP-iEbZe6FrdP-top":{"uid":"edge--QZuVi6n7M--QZuVi6n7M-bottom-iEbZe6FrdP-iEbZe6FrdP-top","fromNodeId":"-QZuVi6n7M","fromHandleId":"-QZuVi6n7M-bottom","toNodeId":"iEbZe6FrdP","toHandleId":"iEbZe6FrdP-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-5ovY6Y7atI-5ovY6Y7atI-top":{"uid":"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-5ovY6Y7atI-5ovY6Y7atI-top","fromNodeId":"OIDIoPPwFU","fromHandleId":"OIDIoPPwFU-bottom","toNodeId":"5ovY6Y7atI","toHandleId":"5ovY6Y7atI-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-yVBft0fd68-yVBft0fd68-top":{"uid":"edge-OIDIoPPwFU-OIDIoPPwFU-bottom-yVBft0fd68-yVBft0fd68-top","fromNodeId":"OIDIoPPwFU","fromHandleId":"OIDIoPPwFU-bottom","toNodeId":"yVBft0fd68","toHandleId":"yVBft0fd68-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-KcDc1JqWZL-KcDc1JqWZL-bottom-DiKZ2umB3G-DiKZ2umB3G-top":{"uid":"edge-KcDc1JqWZL-KcDc1JqWZL-bottom-DiKZ2umB3G-DiKZ2umB3G-top","fromNodeId":"KcDc1JqWZL","fromHandleId":"KcDc1JqWZL-bottom","toNodeId":"DiKZ2umB3G","toHandleId":"DiKZ2umB3G-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-KcDc1JqWZL-KcDc1JqWZL-left-y2Vg-dWtlJ-y2Vg-dWtlJ-right":{"uid":"edge-KcDc1JqWZL-KcDc1JqWZL-left-y2Vg-dWtlJ-y2Vg-dWtlJ-right","fromNodeId":"KcDc1JqWZL","fromHandleId":"KcDc1JqWZL-left","toNodeId":"y2Vg-dWtlJ","toHandleId":"y2Vg-dWtlJ-right","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}} \ No newline at end of file diff --git a/docs/diagrams/배치면초기설정.codediagram b/docs/diagrams/배치면초기설정.codediagram new file mode 100644 index 00000000..814a256d --- /dev/null +++ b/docs/diagrams/배치면초기설정.codediagram @@ -0,0 +1 @@ +{"id":-1,"name":"Onboarding diagram","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"HduNR37Az-","position":{"x":690,"y":-270},"sizes":{"width":400,"height":168},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"배치면 초기설정 "},{"type":"text","marks":[{"type":"bold"}],"text":"☀️"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"플랜당 필수 설정"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"필수로 설정이 저장되어야 하기 때문에 닫기 버튼 없음"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"저장 버튼으로 update 처리"}]}]}]}]},"color":{"bgColor":"hsla(211, 33%, 22%, 1)","bgName":"blue"},"nodeType":"block"},{"uid":"eB4rr9xOVw","position":{"x":500,"y":-40},"sizes":{"width":810,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/placementShape/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"PlacementShapeSetting.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"배치면 초기 설정 팝업"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) {"}]}]},"nodeType":"block"},{"uid":"dzN8hw1chO","position":{"x":990,"y":310},"sizes":{"width":550,"height":361},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/option/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"useCanvasSetting.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 조회 및 초기화\n */\nconst fetchBasicSettings = async (planNo, openPoint) => {"}]},{"type":"paragraph"},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":false},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 저장\n */\nconst basicSettingSave = async (params) => {"}]}]},"nodeType":"block"},{"uid":"YX7IHZIiqg","position":{"x":330,"y":310},"sizes":{"width":590,"height":259.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"usePlan.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 플랜 삭제 시 배치면 초기설정 데이터 삭제\n *\n * @param {string} objectNo - 물건번호\n * @param {string} planNo - 플랜번호\n */\nconst deleteBasicSettings = async (objectNo, planNo) => {"}]}]},"nodeType":"block"}],"configs":{"centerX":47.05904869941878,"centerY":349.9825354968084,"zoomLevel":1.017264811197917},"arrowData":{"arrowsMap":{"arrow-point-bI0wBh3Ufk-bottom-point-PSPLIYKa9J-top":{"to":"point-PSPLIYKa9J-top","from":"point-bI0wBh3Ufk-bottom","label":"Normal Box","direction":"ft","selectable":true},"arrow-point-bI0wBh3Ufk-bottom-point-ytXK_ayIc1-top":{"to":"point-ytXK_ayIc1-top","from":"point-bI0wBh3Ufk-bottom","label":"Code Box","direction":"ft","selectable":true},"arrow-point-hyyRZE3E8u-right-point-6ZopTaEaDZ-left":{"to":"point-6ZopTaEaDZ-left","from":"point-hyyRZE3E8u-right","label":"call","direction":"ft","selectable":true}},"pointsMap":{"point-PSPLIYKa9J-top":{"x":805.9999797489683,"y":60,"id":"point-PSPLIYKa9J-top","direction":"top"},"point-ytXK_ayIc1-top":{"x":205.99999493724206,"y":60,"id":"point-ytXK_ayIc1-top","direction":"top"},"point-6ZopTaEaDZ-left":{"x":220,"y":605.9999898744841,"id":"point-6ZopTaEaDZ-left","direction":"left"},"point-hyyRZE3E8u-right":{"x":100,"y":606,"id":"point-hyyRZE3E8u-right","direction":"right"},"point-bI0wBh3Ufk-bottom":{"x":515.9999797489683,"y":-40,"id":"point-bI0wBh3Ufk-bottom","direction":"bottom"}},"edgesMap":{"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"YX7IHZIiqg","toHandleId":"YX7IHZIiqg-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"dzN8hw1chO","toHandleId":"dzN8hw1chO-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}} \ No newline at end of file diff --git a/src/app/api/html2canvas/route.js b/src/app/api/html2canvas/route.js deleted file mode 100644 index 21f93c82..00000000 --- a/src/app/api/html2canvas/route.js +++ /dev/null @@ -1,22 +0,0 @@ -'use server' - -import fs from 'fs/promises' - -import { NextResponse } from 'next/server' -import { writeImage, writeImageBuffer } from '@/lib/fileAction' - -export async function GET(req) { - const path = 'public/plan-map-images' - const q = req.nextUrl.searchParams.get('q') - const fileNm = req.nextUrl.searchParams.get('fileNm') - const zoom = req.nextUrl.searchParams.get('zoom') - const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=${zoom}&maptype=satellite&size=640x640&scale=1&key=AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc` - const decodeUrl = decodeURIComponent(targetUrl) - - const response = await fetch(decodeUrl) - const data = await response.arrayBuffer() - const buffer = Buffer.from(data) - await writeImage(fileNm, buffer) - - return NextResponse.json({ fileNm: `${fileNm}.png` }) -} diff --git a/src/app/api/image-upload/route.js b/src/app/api/image-upload/route.js deleted file mode 100644 index 219544fe..00000000 --- a/src/app/api/image-upload/route.js +++ /dev/null @@ -1,15 +0,0 @@ -'use server' - -import { NextResponse } from 'next/server' -import { writeImage } from '@/lib/fileAction' - -export async function POST(req) { - const formData = await req.formData() - const file = formData.get('file') - const fileName = formData.get('fileName') - const arrayBuffer = await file.arrayBuffer() - const buffer = Buffer.from(arrayBuffer) - await writeImage(fileName, buffer) - - return NextResponse.json({ fileNm: `${fileName}.png` }) -} diff --git a/src/app/api/swr-tutorial/route.js b/src/app/api/swr-tutorial/route.js deleted file mode 100644 index 99ebaf15..00000000 --- a/src/app/api/swr-tutorial/route.js +++ /dev/null @@ -1,25 +0,0 @@ -import { NextResponse } from 'next/server' - -const defaultData = [ - { - id: 1, - name: 'John Doe', - email: 'john.doe@example.com', - }, - { - id: 2, - name: 'Jane Lee', - email: 'jane.lee@example.com', - }, -] - -export async function GET(req, res) { - return NextResponse.json(defaultData) -} - -export const POST = async (req, res) => { - const { id, name, email } = await req.json() - const newData = { id, name, email } - console.log('🚀 ~ POST ~ newData:', newData) - return NextResponse.json([...defaultData, newData]) -} diff --git a/src/app/playground/page.jsx b/src/app/playground/page.jsx deleted file mode 100644 index 3a3ad1d1..00000000 --- a/src/app/playground/page.jsx +++ /dev/null @@ -1,9 +0,0 @@ -import Playground from '@/components/Playground' - -export default async function PlaygroundPage() { - return ( - <> - - - ) -} diff --git a/src/app/roof/page.jsx b/src/app/roof/page.jsx deleted file mode 100644 index 960ffa89..00000000 --- a/src/app/roof/page.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import Hero from '@/components/Hero' -import Roof from '@/components/Roof' - -export default async function RoofPage() { - return ( - <> - -
- -
- - ) -} diff --git a/src/app/roof2/page.jsx b/src/app/roof2/page.jsx deleted file mode 100644 index 94e86fbe..00000000 --- a/src/app/roof2/page.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import Roof2 from '@/components/Roof2' - -export default async function Roof2Page() { - return ( - <> -
- -
- - ) -} diff --git a/src/app/settings/page.jsx b/src/app/settings/page.jsx deleted file mode 100644 index ab714682..00000000 --- a/src/app/settings/page.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import Hero from '@/components/Hero' -import Settings from '@/components/Settings' - -export default async function SettingsPage() { - return ( - <> - -
- -
- - ) -} diff --git a/src/components/GridSettingsModal.jsx b/src/components/GridSettingsModal.jsx deleted file mode 100644 index 92b2e618..00000000 --- a/src/components/GridSettingsModal.jsx +++ /dev/null @@ -1,273 +0,0 @@ -import { useEffect, useRef, useState } from 'react' -import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react' -import { useRecoilState, useRecoilValue } from 'recoil' -import { modalContent, modalState } from '@/store/modalAtom' -import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom' -import { fabric } from 'fabric' -import { ColorPicker, useColor } from 'react-color-palette' -import 'react-color-palette/css' -import { gridColorState } from '@/store/gridAtom' - -export default function GridSettingsModal(props) { - const { canvasProps } = props - const [isCustomGridSetting, setIsCustomGridSetting] = useState(true) - const [gridCheckedValue, setGridCheckValue] = useState([]) - const [ratioValue, setRatioValue] = useState('1') - const moduleLength = useRef(null) //모듈 mm 길이 입력 - const customModuleHoriLength = useRef(null) - const customModuleVertLength = useRef(null) - - const [open, setOpen] = useRecoilState(modalState) - const [guideLine, setGuideLine] = useRecoilState(guideLineState) - const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState) - const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState) - - const gridSettingArray = [] - - const gridColor = useRecoilValue(gridColorState) - const [colorPickerShow, setColorPickerShow] = useState(false) - - const boxStyle = { - width: '50px', - height: '30px', - border: '1px solid black', - backgroundColor: guideColor.hex, - } - useEffect(() => { - moduleLength.current.value = 90 - customModuleHoriLength.current.value = 90 - customModuleVertLength.current.value = 90 - }, []) - - useEffect(() => { - setIsCustomGridSetting(ratioValue !== 'custom') - }, [ratioValue]) - - const drawGridSettings = () => { - //기존에 선택된 데이터가 있으면 그 데이터를 포함한다 - if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) { - gridSettingArray.push(...guideLine) - } - - let moduleHoriLength = moduleLength.current.value //가로 간격 - let moduleVertLength = moduleLength.current.value //새로 간격 - - if (ratioValue === 'custom') { - moduleHoriLength = customModuleHoriLength.current.value - moduleVertLength = customModuleVertLength.current.value - } else { - moduleHoriLength = moduleHoriLength / ratioValue - moduleVertLength = moduleVertLength / ratioValue - } - - if (gridCheckedValue.includes('line')) { - const horizontalLineArray = [] - const verticalLineArray = [] - - for (let i = 0; i < canvasProps.height / moduleVertLength + 1; i++) { - const horizontalLine = new fabric.Line( - [0, i * moduleVertLength - moduleVertLength / 2, canvasProps.width, i * moduleVertLength - moduleVertLength / 2], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'guideLine', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'horizontal', - }, - ) - canvasProps.add(horizontalLine) - horizontalLineArray.push(horizontalLine) - } - - for (let i = 0; i < canvasProps.width / moduleHoriLength + 1; i++) { - const verticalLine = new fabric.Line( - [i * moduleHoriLength - moduleHoriLength / 2, 0, i * moduleHoriLength - moduleHoriLength / 2, canvasProps.height], - { - stroke: gridColor, - strokeWidth: 1, - selectable: true, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - name: 'guideLine', - strokeDashArray: [5, 2], - opacity: 0.3, - direction: 'vertical', - }, - ) - canvasProps.add(verticalLine) - verticalLineArray.push(verticalLine) - } - canvasProps.renderAll() - - const snapDistance = 10 - - const recoilObj = { - guideMode: 'guideLine', - horizontalLineArray, - verticalLineArray, - moduleVertLength: moduleVertLength, - moduleHoriLength: moduleHoriLength, - } - gridSettingArray.push(recoilObj) - const newHoriGuideLines = [...horiGuideLines] - horizontalLineArray.forEach((line) => { - newHoriGuideLines.push(line) - }) - const newVertGuideLines = [...vertGuideLines] - verticalLineArray.forEach((line) => { - newVertGuideLines.push(line) - }) - setHoriGuideLines(newHoriGuideLines) - setVertGuideLines(newVertGuideLines) - } - - if (gridCheckedValue.includes('dot')) { - const circle = new fabric.Circle({ - radius: 2, - fill: 'white', - stroke: guideColor.hex, - strokeWidth: 0.7, - originX: 'center', - originY: 'center', - selectable: false, - lockMovementX: true, - lockMovementY: true, - lockRotation: true, - lockScalingX: true, - lockScalingY: true, - }) - - const patternSourceCanvas = new fabric.StaticCanvas(null, { - width: moduleHoriLength, - height: moduleVertLength, - }) - - patternSourceCanvas.add(circle) - - circle.set({ - left: patternSourceCanvas.width / 2, - top: patternSourceCanvas.height / 2, - }) - - patternSourceCanvas.renderAll() - - const pattern = new fabric.Pattern({ - source: patternSourceCanvas.getElement(), - repeat: 'repeat', - }) - - const backgroundPolygon = new fabric.Polygon( - [ - { x: 0, y: 0 }, - { x: canvasProps.width, y: 0 }, - { x: canvasProps.width, y: canvasProps.height }, - { x: 0, y: canvasProps.height }, - ], - { - fill: pattern, - selectable: false, - name: 'guideDot', - }, - ) - - canvasProps.add(backgroundPolygon) - backgroundPolygon.sendToBack() - canvasProps.renderAll() - - const recoilObj = { - guideMode: 'guideDot', - moduleVertLength: moduleVertLength, - moduleHoriLength: moduleHoriLength, - } - - gridSettingArray.push(recoilObj) - } - canvasProps.renderAll() - setGuideLine(gridSettingArray) - } - - const removeGuideLines = () => { - if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) { - const guideLines = canvasProps._objects.filter((obj) => obj.name === 'guideLine' || obj.name === 'guideDot') - guideLines?.forEach((item) => canvasProps.remove(item)) - canvasProps.renderAll() - setGuideLine([]) - setHoriGuideLines([]) - setVertGuideLines([]) - } else { - alert('그리드가 없습니다.') - return - } - } - - return ( - <> -
-
- -
-
- - mm -
-
- - 원치수 - 1/2 - 1/4 - 1/10 - 임의간격 - -
-
- 가이드컬러
setColorPickerShow(!colorPickerShow)}>
-
- {colorPickerShow && ( - - )} - -
- - 종횡연동 - -
-
-
- - mm -
-
- - mm -
- -
- - - - -
- - ) -} diff --git a/src/components/Headers.jsx b/src/components/Headers.jsx deleted file mode 100644 index 02859c96..00000000 --- a/src/components/Headers.jsx +++ /dev/null @@ -1,21 +0,0 @@ -import Link from 'next/link' - -export default function Headers() { - return ( -
- -
- ) -} diff --git a/src/components/Hero.jsx b/src/components/Hero.jsx deleted file mode 100644 index a6e7761f..00000000 --- a/src/components/Hero.jsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function Hero(props) { - return ( -
-

{props.title}

-
- ) -} diff --git a/src/components/InitSettingsModal.jsx b/src/components/InitSettingsModal.jsx deleted file mode 100644 index 4cfc483d..00000000 --- a/src/components/InitSettingsModal.jsx +++ /dev/null @@ -1,253 +0,0 @@ -'use client' - -import { useEffect, useState, memo, useCallback } from 'react' -import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react' -import { useRecoilState, useRecoilValue } from 'recoil' -import { modalContent, modalState } from '@/store/modalAtom' -import { canvasSettingState } from '@/store/canvasAtom' -import { useAxios } from '@/hooks/useAxios' - -export default function InitSettingsModal(props) { - const [objectNo, setObjectNo] = useState('test123240909003') // 후에 삭제 필요 - const [open, setOpen] = useRecoilState(modalState) - const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState) - const [roofMaterials, setRoofMaterials] = useState([]) - const [basicSetting, setBasicSettings] = useState({ - roofDrawingSet: '1', - roofSizeSet: '1', - roofAngleSet: 'slope', - roofs: [{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }], - }) - - const modelProps = { - open, - setOpen, - } - - const { get, post } = useAxios() - - useEffect(() => { - get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => { - if (res.length == 0) return - - // 'roofs' 배열을 생성하여 각 항목을 추가 - const roofsRow = res.map((item) => { - return { - roofDrawingSet: String(item.roofDrawingSet), - roofSizeSet: String(item.roofSizeSet), - roofAngleSet: item.roofAngleSet, - } - }) - - const roofsArray = res.some((item) => !item.roofSeq) - ? //최초 지붕재 추가 정보의 경우 roofsArray를 초기화 설정 - [{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }] - : res.map((item) => ({ - roofSeq: String(item.roofSeq), - roofType: String(item.roofType), - roofWidth: String(item.roofWidth), - roofHeight: String(item.roofHeight), - roofGap: String(item.roofGap), - roofLayout: item.roofLayout, - })) - - // 나머지 데이터와 함께 'roofs' 배열을 patternData에 넣음 - const patternData = { - roofDrawingSet: roofsRow[0].roofDrawingSet, // 첫 번째 항목의 값을 사용 - roofSizeSet: roofsRow[0].roofSizeSet, // 첫 번째 항목의 값을 사용 - roofAngleSet: roofsRow[0].roofAngleSet, // 첫 번째 항목의 값을 사용 - roofs: roofsArray, // 만들어진 roofs 배열 - } - - // 데이터 설정 - setBasicSettings({ ...patternData }) - }) - - if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) { - setBasicSettings({ ...canvasSetting }) - } - }, []) - - //기본 설정값 변경 함수 - const handleBasicSetting = (event) => { - const newBasicSetting = { ...basicSetting, [event.target.name]: event.target.value } - setBasicSettings(newBasicSetting) - } - - //배열 값 변경 함수 - const handleRoofSettings = (id, event) => { - // 기본 세팅에서 roofs 배열을 복사 - const updatedRoofs = [...basicSetting.roofs] - - // roofSeq가 id와 일치하는 항목의 인덱스 찾기 - const index = updatedRoofs.findIndex((roof) => roof.roofSeq === id) - - if (index !== -1) { - // 해당 인덱스의 항목을 수정 - updatedRoofs[index] = { - ...updatedRoofs[index], - [event.target.name]: event.target.value, - } - - // 수정된 배열을 상태에 반영 - setBasicSettings((prevState) => ({ - ...prevState, - roofs: updatedRoofs, - })) - } - } - - //저장 - const submitCanvasConfig = async () => { - if (!objectNo) { - alert('object_no를 입력하세요.') - return - } - - const patternData = { - objectNo, - roofDrawingSet: basicSetting.roofDrawingSet, - roofSizeSet: basicSetting.roofSizeSet, - roofAngleSet: basicSetting.roofAngleSet, - roofMaterialsAddList: basicSetting.roofs, - } - await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }) - - //Recoil 설정 - setCanvasSetting({ ...basicSetting }) - - // 저장 후 재조회 - //await handleSelect() - } - - return ( - <> -
-
배치면 초기설정
- -
-
- - 치수 입력에 의한 물건작성 - -
-
- -
-
- - 복사도 입력 - 실측값 입력 - 육지붕 - -
-
- -
-
- - 경사 - 각도 - -
-
- - {/* Roofs Array Rendering */} - {basicSetting.roofs && - basicSetting.roofs.map((roof, index) => { - return ( -
- 타입 : - - 너비 : - handleRoofSettings(roof.roofSeq, e)} - /> - mm - 높이 : - handleRoofSettings(roof.roofSeq, e)} - /> - mm - 서까래 간격 : - handleRoofSettings(roof.roofSeq, e)} - /> - mm -
- handleRoofSettings(roof.roofSeq, e)} - > - 병렬식 - 계단식 - -
-
- ) - })} - -
- - - setObjectNo(e.target.value)} /> -
-
- - ) -} diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx deleted file mode 100644 index 8a365646..00000000 --- a/src/components/Playground.jsx +++ /dev/null @@ -1,919 +0,0 @@ -'use client' - -import { useRef, useState, useEffect, useContext } from 'react' -import Image from 'next/image' -import { useRecoilState } from 'recoil' -import { v4 as uuidv4 } from 'uuid' -import { FaAnglesUp } from 'react-icons/fa6' -import { FaAnglesDown } from 'react-icons/fa6' -import { Button } from '@nextui-org/react' -import ColorPicker from './common/color-picker/ColorPicker' -import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom' - -import { useAxios } from '@/hooks/useAxios' -import { useMessage } from '@/hooks/useMessage' -import { useMasterController } from '@/hooks/common/useMasterController' -import { useSwal } from '@/hooks/useSwal' -import { convertDwgToPng } from '@/lib/cadAction' -import { GlobalDataContext } from '@/app/GlobalDataProvider' -import QInput from './common/input/Qinput' -import QSelect from './common/select/QSelect' -import QPagination from './common/pagination/QPagination' -import QSelectBox from './common/select/QSelectBox' -import SampleReducer from './sample/SampleReducer' - -import styles from './playground.module.css' -import useSWR from 'swr' -import useSWRMutation from 'swr/mutation' -import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController' -import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom' -import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions' -import { useRouter } from 'next/navigation' -import { QcastContext } from '@/app/QcastProvider' - -export default function Playground() { - const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) - const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) - const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState) - const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState) - const fileRef = useRef(null) - const queryRef = useRef(null) - const [zoom, setZoom] = useState(20) - const { get, promiseGet, post, promisePost, getFetcher, postFetcher } = useAxios() - const testVar = process.env.NEXT_PUBLIC_TEST - const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL - const { getMessage } = useMessage() - const { swalFire } = useSwal() - const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController() - - const [color, setColor] = useState('#ff0000') - - const [textInput, setTextInput] = useState('') - const [numberInput, setNumberInput] = useState('') - const [radioInput, setRadioInput] = useState('') - const [checkboxInput, setCheckboxInput] = useState([]) - const [selectedValue, setSelectedValue] = useState('') - - const [users, setUsers] = useState([]) - - const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext) - - const router = useRouter() - const { setIsGlobalLoading } = useContext(QcastContext) - - useEffect(() => { - setIsGlobalLoading(false) - }, []) - - useEffect(() => { - console.log('textInput:', textInput) - }, [textInput]) - useEffect(() => { - console.log('numberInput:', numberInput) - }, [numberInput]) - useEffect(() => { - console.log('radioInput:', radioInput) - }, [radioInput]) - useEffect(() => { - console.log('checkboxInput:', checkboxInput) - }, [checkboxInput]) - useEffect(() => { - console.log('selectedValue:', selectedValue) - }, [selectedValue]) - - const handleUsers = async () => { - // const users = await get('/api/user/find-all') - const params = { - url: '/api/user/find-all', - } - const users = await get(params) - console.log('users', users) - } - - const handleConvert = async () => { - console.log('file', fileRef.current.files[0]) - - const formData = new FormData() - formData.append('file', fileRef.current.files[0]) - - await promisePost({ url: converterUrl, data: formData }) - .then((res) => { - console.log('response: ', res) - convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData) - setUseCadFile(true) - setCadFileName(res.data.Files[0].FileName) - swalFire({ text: '파일 변환 완료' }) - }) - .catch((err) => { - console.error(err) - swalFire({ text: '파일 변환 실패' }) - }) - } - - const handleDownImage = async (fileName = '') => { - const fileNm = fileName === '' ? uuidv4() : fileName - const queryString = queryRef.current.value === '' ? '서울시 서대문구 연세로5다길 22-3 발리빌라 3층' : queryRef.current.value - const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryString}&fileNm=${fileNm}&zoom=${zoom}` }) - console.log('res', res) - setGoogleMapFileName(res.fileNm) - swalFire({ text: '이미지 저장 완료' }) - setUseGoogleMapFile(true) - } - - const handleZoom = async (type) => { - if (type === 'up') { - setZoom((prevState) => prevState + 1) - } else { - setZoom((prevState) => prevState - 1) - } - - await handleDownImage() - } - - const data = [ - { - id: 1, - author: 'SWYOO', - contents: '버튼 정리(템플릿 적용)', - date: '2024.07.16', - }, - { - id: 2, - author: 'SWYOO', - contents: 'README.md 파일 이미지 경로 수정', - date: '2024.07.17', - }, - { - id: 3, - author: 'SWYOO', - contents: '', - date: '', - }, - ] - - const handleSwalAlert = () => { - swalFire({ - text: '알림 테스트입니다.', - }) - } - - const paginationProps = { - pageNo: 1, - pageSize: 10, - pagePerBlock: 10, - totalCount: 26, - handleChangePage: (page) => { - console.log('page', page) - }, - } - - useEffect(() => { - console.log('users:', users) - }, [users]) - - const codes = [ - { - clHeadCd: '203800', - clCode: 'HEI_455', - clCodeNm: '세로 455mm이하', - clPriority: 1, - name: '세로 455mm이하', - id: 'HEI_455', - }, - { - clHeadCd: '203800', - clCode: 'HEI_500', - clCodeNm: '세로 500mm이하', - clPriority: 2, - name: '세로 500mm이하', - id: 'HEI_500', - }, - { - clHeadCd: '203800', - clCode: 'HEI_606', - clCodeNm: '세로 606mm이하', - clPriority: 3, - name: '세로 606mm이하', - id: 'HEI_606', - }, - { - clHeadCd: '203800', - clCode: 'WID_606', - clCodeNm: '가로 606mm이하', - clPriority: 4, - name: '가로 606mm이하', - id: 'WID_606', - }, - { - clHeadCd: '203800', - clCode: 'ETC', - clCodeNm: '기타', - clPriority: 5, - name: '기타', - id: 'ETC', - }, - ] - - const [myData, setMyData] = useState({ - roofMatlCd: 'ROOF_ID_WA_53A', - roofMatlNm: '화와 A', - roofMatlNmJp: '和瓦A', - widAuth: 'R', - widBase: '265.000', - lenAuth: 'R', - lenBase: '235.000', - roofPchAuth: null, - roofPchBase: null, - raftAuth: 'C', - raftBaseCd: 'HEI_455', - id: 'ROOF_ID_WA_53A', - name: '화와 A', - selected: true, - nameJp: '和瓦A', - length: 235, - width: 265, - layout: 'P', - hajebichi: null, - }) - - const handleChangeMyData = () => { - setMyData({ ...myData, raftBaseCd: 'HEI_500' }) - } - - const [myData2, setMyData2] = useState({}) - - const handleChangeMyData2 = () => { - setMyData2({ - roofMatlCd: 'ROOF_ID_WA_53A', - roofMatlNm: '화와 A', - roofMatlNmJp: '和瓦A', - widAuth: 'R', - widBase: '265.000', - lenAuth: 'R', - lenBase: '235.000', - roofPchAuth: null, - roofPchBase: null, - raftAuth: 'C', - raftBaseCd: 'HEI_455', - id: 'ROOF_ID_WA_53A', - name: '화와 A', - selected: true, - nameJp: '和瓦A', - length: 235, - width: 265, - layout: 'P', - hajebichi: null, - }) - } - - // const [callFlag, setCallFlag] = useState(false) - // const { data: tutoData, error, isLoading } = useSWR('http://localhost:8080/api/tutorial', getFetcher) - // const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher) - // const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher) - - // if (isLoading) { - // return
Loading...
- // } - - // if (error) { - // return
Error...
- // } - - // const [moduleSelectionDataPlanListStore, setModuleSelectionDataPlanListStore] = useRecoilState(moduleSelectionDataPlanListState) - // useEffect(() => { - // console.log('🚀 ~ Playground ~ moduleSelectionDataPlanListStore:', moduleSelectionDataPlanListStore) - // }, [moduleSelectionDataPlanListStore]) - // const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController({ objectNo: 'R201T01241120001', planNo: 2, popupType: 2 }) - - return ( - <> -
-
이 영역은 테스트입니다.
-
- {' '} - {' '} - {' '} - {' '} - -
- -
- - - -
- - - -
- - -
- - -
-
-
- - - - -
-
{testVar}
-
-
- -
-
-
-

Sass 테스트입니다.

-
-
test']) }}>
-
-

React ColorPicker

- -
{color}
-
-
-

캐드 파일 이미지 사용

- -
- -
-
-
-

구글 맵 이미지 사용

- -
- -
- {useGoogleMapFile && ( - <> -
-

Zoom Controller : {zoom}

- - -
-
- -
- - )} -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
- {/*
-

{managementStateLoaded?.objectNo}

-
*/} -
- -
- {/*
- {tutoData && - tutoData.map((item) => ( -
- {item.name} / {item.email} -
- ))} -
-
- -
-
- -
*/} -
- -
-
- -
-
- - ) -} diff --git a/src/components/Roof.jsx b/src/components/Roof.jsx deleted file mode 100644 index 51ba639e..00000000 --- a/src/components/Roof.jsx +++ /dev/null @@ -1,351 +0,0 @@ -'use client' - -import { useEffect } from 'react' -import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util' -import { useCanvas } from '@/hooks/useCanvas' -import { fabric } from 'fabric' -import { v4 as uuidv4 } from 'uuid' - -export default function Roof() { - const { - canvas, - addShape, - handleUndo, - handleRedo, - handleClear, - handleCopy, - handleDelete, - handleSave, - handlePaste, - handleRotate, - attachCustomControlOnPolygon, - saveImage, - handleFlip, - } = useCanvas('canvas') - - useEffect(() => { - let circle = new fabric.Circle({ - radius: 40, - fill: 'rgba(200, 0, 0, 0.3)', - originX: 'center', - originY: 'center', - }) - - let text = new fabric.Textbox('AJLoveChina', { - originX: 'center', - originY: 'center', - textAlign: 'center', - fontSize: 12, - }) - - let group = new fabric.Group([circle, text], { - left: 100, - top: 100, - originX: 'center', - originY: 'center', - }) - - group.on('mousedblclick', () => { - // textForEditing is temporary obj, - // and will be removed after editing - console.log(text.type) - let textForEditing = new fabric.Textbox(text.text, { - originX: 'center', - originY: 'center', - textAlign: text.textAlign, - fontSize: text.fontSize, - - left: group.left, - top: group.top, - }) - - // hide group inside text - text.visible = false - // note important, text cannot be hidden without this - group.addWithUpdate() - - textForEditing.visible = true - // do not give controls, do not allow move/resize/rotation on this - textForEditing.hasConstrols = false - - // now add this temporary obj to canvas - canvas.add(textForEditing) - canvas.setActiveObject(textForEditing) - // make the cursor showing - textForEditing.enterEditing() - textForEditing.selectAll() - - // editing:exited means you click outside of the textForEditing - textForEditing.on('editing:exited', () => { - let newVal = textForEditing.text - let oldVal = text.text - - // then we check if text is changed - if (newVal !== oldVal) { - text.set({ - text: newVal, - visible: true, - }) - - // comment before, you must call this - group.addWithUpdate() - - // we do not need textForEditing anymore - textForEditing.visible = false - canvas?.remove(textForEditing) - - // optional, buf for better user experience - canvas?.setActiveObject(group) - } - }) - }) - - canvas?.add(group) - }, [canvas]) - - const addRect = () => { - const rect = new fabric.Rect({ - height: 200, - width: 200, - top: 10, - left: 10, - opacity: 0.4, - fill: randomColor(), - stroke: 'red', - name: uuidv4(), - }) - - addShape(rect) - } - - const addHorizontalLine = () => { - const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 } - /** - * 시작X,시작Y,도착X,도착Y 좌표 - */ - const horizontalLine = new fabric.Line([x1, y1, x2, y2], { - name: uuidv4(), - stroke: 'red', - strokeWidth: 3, - selectable: true, - }) - - const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), { - fontSize: 20, - left: (x2 - x1) / 2, - top: y1 - 20, - }) - - const group = new fabric.Group([horizontalLine, text], { - left: 20, - top: 20, - }) - - // addShape(horizontalLine) - addShape(group) - console.log(JSON.stringify(canvas)) - } - - const addVerticalLine = () => { - const verticalLine = new fabric.Line([10, 10, 10, 100], { - name: uuidv4(), - stroke: 'red', - strokeWidth: 3, - selectable: true, - }) - - addShape(verticalLine) - } - - const addTriangle = () => { - const triangle = new fabric.Triangle({ - name: uuidv4(), - top: 50, - left: 50, - width: 100, - stroke: randomColor(), - strokeWidth: 3, - }) - - addShape(triangle) - } - - const addTrapezoid = () => { - const trapezoid = new fabric.Polygon( - [ - { x: 100, y: 100 }, // 좌상단 - { x: 500, y: 100 }, // 우상단 - { x: 750, y: 700 }, // 우하단 - { x: 250, y: 400 }, // 좌하단 - ], - { - name: uuidv4(), - stroke: 'red', - opacity: 0.4, - strokeWidth: 3, - selectable: true, - objectCaching: false, - }, - ) - attachCustomControlOnPolygon(trapezoid) - const group = addDistanceTextToPolygon(trapezoid) - addGroupClickEvent(group) - canvas?.add(group) - canvas?.renderAll() - } - - // group에 클릭 이벤트를 추가하여 클릭 시 group을 제거하고 object들만 남기는 함수 - function addGroupClickEvent(group) { - group.on('selected', (e) => { - console.log(e) - }) - group.on('mousedblclick', (e) => { - // textForEditing is temporary obj, - // and will be removed after editing - const pointer = canvas?.getPointer(e.e) // 마우스 클릭 위치 가져오기 - let minDistance = Infinity - let closestTextbox = null - const groupPoint = group.getCenterPoint() - group.getObjects().forEach(function (object) { - if (object.type === 'textbox') { - // 객체가 TextBox인지 확인 - - const objectCenter = object.getCenterPoint() // TextBox 객체의 중심점 가져오기 - const dx = objectCenter.x + groupPoint.x - pointer.x - const dy = objectCenter.y + groupPoint.y - pointer.y - const distance = Math.sqrt(dx * dx + dy * dy) // 마우스 클릭 위치와 TextBox 객체 사이의 거리 계산 - - if (distance < minDistance) { - // 가장 짧은 거리를 가진 TextBox 객체 찾기 - minDistance = distance - closestTextbox = object - } - } - }) - - let textForEditing = new fabric.Textbox(closestTextbox.text, { - originX: 'center', - originY: 'center', - textAlign: closestTextbox.textAlign, - fontSize: closestTextbox.fontSize, - left: closestTextbox.left + groupPoint.x, - top: closestTextbox.top + groupPoint.y, - }) - - // hide group inside text - closestTextbox.visible = false - // note important, text cannot be hidden without this - group.addWithUpdate() - - textForEditing.visible = true - // do not give controls, do not allow move/resize/rotation on this - textForEditing.hasConstrols = false - - // now add this temporary obj to canvas - canvas?.add(textForEditing) - canvas?.setActiveObject(textForEditing) - // make the cursor showing - textForEditing?.enterEditing() - textForEditing?.selectAll() - - // editing:exited means you click outside of the textForEditing - textForEditing?.on('editing:exited', () => { - let newVal = textForEditing.text - - // then we check if text is changed - closestTextbox.set({ - text: newVal, - visible: true, - }) - - // comment before, you must call this - group.addWithUpdate() - - // we do not need textForEditing anymore - textForEditing.visible = false - canvas?.remove(textForEditing) - - // optional, buf for better user experience - canvas?.setActiveObject(group) - }) - }) - } - - // IText를 수정할 때 해당 값을 길이로 갖는 다른 polygon을 생성하고 다시 그룹화하는 함수 - function addTextModifiedEvent(text, polygon, index) { - text.on('editing:exited', function () {}) - } - - const randomColor = () => { - return '#' + Math.round(Math.random() * 0xffffff).toString(16) - } - - return ( - <> -
- - - - - - - - - - - - - - - -
- -
- -
- - ) -} diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx deleted file mode 100644 index 731fe8c6..00000000 --- a/src/components/Roof2.jsx +++ /dev/null @@ -1,1099 +0,0 @@ -'use client' - -import { useCanvas } from '@/hooks/useCanvas' -import { useEffect, useRef, useState } from 'react' -import { v4 as uuidv4 } from 'uuid' -import { useMode } from '@/hooks/useMode' -import { LINE_TYPE, Mode } from '@/common/common' -import { Button } from '@nextui-org/react' -import RangeSlider from './ui/RangeSlider' -import { useRecoilState, useRecoilValue } from 'recoil' -import { - cadFileCompleteState, - cadFileNameState, - canvasSizeState, - compassState, - currentObjectState, - fontSizeState, - globalCompassState, - googleMapFileNameState, - roofMaterialState, - roofState, - sortedPolygonArray, - templateTypeState, - useCadFileState, - useGoogleMapFileState, - wallState, -} from '@/store/canvasAtom' -import { QLine } from '@/components/fabric/QLine' -import { getCanvasState, insertCanvasState } from '@/lib/canvas' -import { calculateIntersection } from '@/util/canvas-util' -import { QPolygon } from '@/components/fabric/QPolygon' -import QContextMenu from './common/context-menu/QContextMenu' -import { modalContent, modalState } from '@/store/modalAtom' -import { useAxios } from '@/hooks/useAxios' -import QPolygonContextMenu from '@/components/common/context-menu/QPolygonContextMenu' -import QLineContextMenu from '@/components/common/context-menu/QLineContextMenu' -import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMenu' - -import InitSettingsModal from './InitSettingsModal' -import GridSettingsModal from './GridSettingsModal' -import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' -import { changeCurrentRoof, drawDirectionStringToArrow } from '@/util/qpolygon-utils' -import ThumbnailList from '@/components/ui/ThumbnailLIst' -import ObjectPlacement from '@/components/ui/ObjectPlacement' -import { globalLocaleStore } from '@/store/localeAtom' - -export default function Roof2(props) { - const { name, userId, email, isLoggedIn } = props - const { - canvas, - handleRedo, - handleUndo, - setCanvasBackgroundWithDots, - saveImage, - addCanvas, - handleBackImageLoadToCanvas, - handleCadImageInit, - backImg, - setBackImg, - } = useCanvas('canvas') - - const globalLocaleState = useRecoilValue(globalLocaleStore) - - const { get } = useAxios(globalLocaleState) - - const canvasRef = useRef(null) - - //canvas 기본 사이즈 - const [canvasSize, setCanvasSize] = useRecoilState(canvasSizeState) - - //canvas 가로 사이즈 - const [verticalSize, setVerticalSize] = useState(canvasSize.vertical) - //canvas 세로 사이즈 - const [horizontalSize, setHorizontalSize] = useState(canvasSize.horizontal) - // 글자크기 - const [fontSize, setFontSize] = useRecoilState(fontSizeState) - - const [sortedArray] = useRecoilState(sortedPolygonArray) - - const [angle, setAngle] = useState(0) - - const [showControl, setShowControl] = useState(false) - - //지붕재 - const roofMaterial = useRecoilValue(roofMaterialState) - - const [templateType, setTemplateType] = useRecoilState(templateTypeState) - - const [compass, setCompass] = useRecoilState(compassState) - - const roof = useRecoilValue(roofState) - - const wall = useRecoilValue(wallState) - - const [open, setOpen] = useRecoilState(modalState) - const [contents, setContent] = useRecoilState(modalContent) - - const [scale, setScale] = useState(1) - const currentObject = useRecoilValue(currentObjectState) - - //canvas 썸네일 - const [thumbnails, setThumbnails] = useState([]) - const thumbnailProps = { - thumbnails, - canvas, - } - - let imgPath - // cad 파일 업로드 - const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) - const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) - const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState) - useCadFile && (imgPath = `/cadImages/${cadFileName}`) - - // 구글맵 이미지 업로드 - const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState) - const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState) - useGoogleMapFile && (imgPath = `/mapImages/${googleMapFileName}`) - - const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState) - - const { - mode, - setMode, - changeMode, - handleClear, - zoomIn, - zoomOut, - zoom, - togglePolygonLine, - handleOuterlinesTest, - handleOuterlinesTest2, - applyTemplateB, - makeRoofPatternPolygon, - createRoofRack, - drawRoofPolygon, - drawCellInTrestle, - drawCellManualInTrestle, - setDirectionTrestles, - cutHelpLines, - } = useMode() - - // const [canvasState, setCanvasState] = useRecoilState(canvasAtom) - - useEffect(() => { - get({ url: `/api/canvas-management/canvas-statuses/by-object/test123240822001/${userId}` }).then((res) => { - // console.log(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(() => { - if (!canvas) { - return - } - changeMode(canvas, mode) - - if (!cadFileComplete && useCadFile) { - // cad 파일 로드 - useCadFile && handleBackImageLoadToCanvas(imgPath, canvas) - } - - if (useGoogleMapFile) { - handleBackImageLoadToCanvas(imgPath, canvas) - } - }, [canvas, mode]) - - const makeLine = () => { - if (canvas) { - const line = new QLine([50, 50, 200, 50], { - stroke: 'black', - selectable: true, - strokeWidth: 2, - fontSize: fontSize, - }) - - canvas?.add(line) - } - } - - const makePolygon = () => { - if (canvas) { - const polygon = new QPolygon( - [ - { x: 100, y: 100 }, - { x: 600, y: 200 }, - { x: 700, y: 800 }, - { x: 100, y: 800 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - }, - ) - canvas?.add(polygon) - - // polygon.fillCell({ width: 50, height: 30, padding: 10 }) - } - } - - useEffect(() => { - setCanvasSize({ ...canvasSize, vertical: parseInt(verticalSize), horizontal: parseInt(horizontalSize) }) - }, [verticalSize, horizontalSize]) - - /** - * 값 변경시 - */ - // useEffect(() => { - // canvasSizeMode() - // }, [verticalSize, horizontalSize]) - useEffect(() => { - const { vertical, horizontal } = canvasSize - if (vertical !== verticalSize || horizontal !== horizontalSize) { - canvas?.setWidth(horizontalSize) - canvas?.setHeight(verticalSize) - canvas?.renderAll() - } - }, [canvasSize, canvas]) - - const makeQPolygon = () => { - const type1 = [ - { x: 100, y: 100 }, - { x: 850, y: 100 }, - { x: 850, y: 800 }, - { x: 500, y: 800 }, - { x: 500, y: 400 }, - { x: 100, y: 400 }, - ] - const type2 = [ - { x: 200, y: 100 }, - { x: 200, y: 1000 }, - { x: 1100, y: 1000 }, - { x: 1100, y: 600 }, - { x: 650, y: 600 }, - { x: 650, y: 100 }, - ] - - const type3 = [ - { x: 200, y: 100 }, - { x: 200, y: 800 }, - { x: 500, y: 800 }, - { x: 500, y: 300 }, - { x: 800, y: 300 }, - { x: 800, y: 100 }, - ] - - const type4 = [ - { x: 150, y: 450 }, - { x: 150, y: 800 }, - { x: 750, y: 800 }, - { x: 750, y: 300 }, - { x: 550, y: 300 }, - { x: 550, y: 450 }, - ] - - const type1A = [ - { x: 67, y: 81 }, - { x: 67, y: 660 }, - { x: 437, y: 660 }, - { x: 437, y: 1190 }, - { x: 858, y: 1190 }, - { x: 858, y: 81 }, - ] - - const type1B = [ - { x: 137, y: 42 }, - { x: 137, y: 621 }, - { x: 667, y: 621 }, - { x: 667, y: 991 }, - { x: 1088, y: 991 }, - { x: 1088, y: 42 }, - ] - - const eightPoint = [ - { x: 240.1111, y: 130.1111 }, - { x: 240.1111, y: 630.1111 }, - { x: 640.1111, y: 630.1111 }, - { x: 640.1111, y: 480.1111 }, - { x: 440.1111, y: 480.1111 }, - { x: 440.1111, y: 280.1111 }, - { x: 740.1111, y: 280.1111 }, - { x: 740.1111, y: 130.1111 }, - ] - - const eightPoint2 = [ - { x: 197, y: 215 }, - { x: 197, y: 815 }, - { x: 397, y: 815 }, - { x: 397, y: 1115 }, - { x: 697, y: 1115 }, - { x: 697, y: 815 }, - { x: 897, y: 815 }, - { x: 897, y: 215 }, - ] - - const eightPoint3 = [ - { x: 190, y: 147 }, - { x: 190, y: 747 }, - { x: 490, y: 747 }, - { x: 490, y: 497 }, - { x: 640, y: 497 }, - { x: 640, y: 747 }, - { x: 1090, y: 747 }, - { x: 1090, y: 147 }, - ] - - const eightPoint4 = [ - { x: 200, y: 200 }, - { x: 200, y: 400 }, - { x: 500, y: 400 }, - { x: 500, y: 700 }, - { x: 800, y: 700 }, - { x: 800, y: 400 }, - { x: 1100, y: 400 }, - { x: 1100, y: 200 }, - ] - - const eightPoint5 = [ - { x: 140, y: 101 }, - { x: 140, y: 601 }, - { x: 440, y: 601 }, - { x: 440, y: 801 }, - { x: 840, y: 801 }, - { x: 840, y: 601 }, - { x: 1140, y: 601 }, - { x: 1140, y: 101 }, - ] - - const twelvePoint = [ - { x: 195, y: 166 }, - { x: 195, y: 466 }, - { x: 395, y: 466 }, - { x: 395, y: 766 }, - { x: 545, y: 766 }, - { x: 545, y: 466 }, - { x: 695, y: 466 }, - { x: 695, y: 666 }, - { x: 845, y: 666 }, - { x: 845, y: 466 }, - { x: 995, y: 466 }, - { x: 995, y: 166 }, - ] - - const twelvePoint2 = [ - { x: 165, y: 81 }, - { x: 165, y: 1081 }, - { x: 465, y: 1081 }, - { x: 465, y: 781 }, - { x: 765, y: 781 }, - { x: 765, y: 1081 }, - { x: 1065, y: 1081 }, - { x: 1065, y: 581 }, - { x: 765, y: 581 }, - { x: 765, y: 281 }, - { x: 1065, y: 281 }, - { x: 1065, y: 81 }, - ] - - const complicatedType = [ - { x: 100, y: 100 }, - { x: 100, y: 1100 }, - { x: 400, y: 1100 }, - { x: 400, y: 800 }, - { x: 700, y: 800 }, - { x: 700, y: 1100 }, - { x: 1000, y: 1100 }, - { x: 1000, y: 600 }, - { x: 700, y: 600 }, - { x: 700, y: 300 }, - { x: 1000, y: 300 }, - { x: 1000, y: 100 }, - ] - - const testType = [ - { x: 500, y: 400 }, - { x: 650, y: 550 }, - { x: 575, y: 625 }, - { x: 325, y: 625 }, - { x: 100, y: 400 }, - ] - - const testType2 = [ - { x: 100, y: 400 }, - { x: 325, y: 625 }, - { x: 575, y: 625 }, - { x: 650, y: 550 }, - { x: 500, y: 400 }, - ] - - const triangleType = [ - { x: 100, y: 100 }, - { x: 100, y: 600 }, - { x: 600, y: 600 }, - { x: 600, y: 100 }, - ] - - const rectangleType1 = [ - { x: 500, y: 100 }, - { x: 500, y: 800 }, - { x: 900, y: 800 }, - { x: 900, y: 100 }, - ] - - const rectangleType2 = [ - { x: 100, y: 100 }, - { x: 100, y: 300 }, - { x: 600, y: 300 }, - { x: 600, y: 100 }, - ] - - const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint] - const newP = [ - { x: 450, y: 450 }, - { x: 650, y: 250 }, - { x: 675, y: 275 }, - { x: 450, y: 850 }, - ] - - const test1 = [ - { x: 381, y: 178 }, - { x: 381, y: 659.3 }, - { x: 773.3, y: 659.3 }, - { x: 773.3, y: 497.9 }, - { x: 1457, y: 497.9 }, - { x: 1457, y: 178 }, - ] - - const test2 = [ - { x: 113, y: 114.9 }, - { x: 113, y: 371.9 }, - { x: 762, y: 371.9 }, - { x: 762, y: 818.7 }, - { x: 1478.6, y: 818.7 }, - { x: 1478.6, y: 114.9 }, - ] - - const test3 = [ - { x: 100, y: 100 }, - { x: 100, y: 600 }, - { x: 600, y: 600 }, - { x: 600, y: 100 }, - { x: 500, y: 100 }, - { x: 500, y: 200 }, - { x: 200, y: 200 }, - { x: 200, y: 100 }, - ] - - const test4 = [ - { x: 100, y: 100 }, - { x: 100, y: 1000 }, - { x: 1100, y: 1000 }, - { x: 1100, y: 550 }, - { x: 500, y: 550 }, - { x: 500, y: 100 }, - ] - - const polygon = new QPolygon(test4, { - fill: 'transparent', - stroke: 'green', - strokeWidth: 1, - selectable: false, - fontSize: fontSize, - name: 'wall', - }) - - canvas?.add(polygon) - handleOuterlinesTest2(polygon, 50) - setTemplateType(1) - } - - const rotateShape = () => { - if (canvas) { - const activeObject = canvas?.getActiveObject() - - if (activeObject) { - activeObject.rotate(angle) - canvas?.renderAll() - } - } - } - - const makeQLine = () => { - if (canvas) { - const line = new QLine([50, 250, 900, 250], { - stroke: 'black', - strokeWidth: 5, - fontSize: fontSize, - selectable: true, - }) - - const line2 = new QLine([450, 450, 821, 78], { - stroke: 'black', - strokeWidth: 5, - fontSize: fontSize, - selectable: true, - }) - - canvas?.add(line) - canvas?.add(line2) - - const interSectionPoint = calculateIntersection(line, line2) - - if (interSectionPoint) { - const circle = new fabric.Circle({ - radius: 5, - fill: 'red', - left: interSectionPoint.x - 5, - top: interSectionPoint.y - 5, - }) - - canvas?.add(circle) - } - } - } - - const addBackgroundInPolygon = (polygon) => { - fabric.Image.fromURL('assets/img/check2.png', function (img) { - // 패턴 객체를 생성합니다. - const pattern = new fabric.Pattern({ - source: img.getElement(), - repeat: 'repeat', - }) - - polygon.fillBackground(pattern) - }) - } - - function PolygonToLine() { - const polygon = canvas?.getActiveObject() - - if (polygon.type !== 'QPolygon') { - return - } - - const lines = togglePolygonLine(polygon) - } - - /** - * canvas 내용 저장하기 - */ - const handleSaveCanvas = async () => { - // const jsonStr = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize'])) - const jsonObj = JSON.stringify(canvas?.toDatalessJSON(['type', 'fontSize', 'lines'])) - console.log(jsonObj) - - const param = { - loginId: 'test', - canvas: jsonObj, - } - console.log(param) - - await insertCanvasState(param) - handleClear() - } - - const drawRoofMaterial = () => { - const { width, height, roofStyle } = roofMaterial - - const wallPolygon = canvas?.getObjects().find((obj) => obj.name === 'wall') - - wallPolygon.set('strokeDashArray', [10, 5, 2, 5]) - wallPolygon.set('stroke', 'blue') - wallPolygon.set('strokeWidth', 1) - - const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof') - - roofs.forEach((roof) => { - let maxLengthLine = roof.lines.reduce((acc, cur) => { - return acc.length > cur.length ? acc : cur - }) - - const roofRatio = window.devicePixelRatio || 1 - - // 패턴 소스를 위한 임시 캔버스 생성 - const patternSourceCanvas = document.createElement('canvas') - if (roofStyle === 1) { - if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') { - patternSourceCanvas.width = width * roofRatio - patternSourceCanvas.height = height * roofRatio - } else { - patternSourceCanvas.width = height * roofRatio - patternSourceCanvas.height = width * roofRatio - } - } else if (roofStyle === 2) { - if (maxLengthLine.direction === 'right' || maxLengthLine.direction === 'left') { - patternSourceCanvas.width = width * 2 - patternSourceCanvas.height = height * 2 - } else { - patternSourceCanvas.width = height * 2 - patternSourceCanvas.height = width * 2 - } - } - - const ctx = patternSourceCanvas.getContext('2d') - - ctx.scale(roofRatio, roofRatio) - ctx.strokeStyle = 'green' - ctx.lineWidth = 0.4 - // 벽돌 패턴 그리기 - if (roofStyle === 1) { - ctx.strokeRect(0, 0, 50, 30) - } else if (roofStyle === 2) { - // 지그재그 - ctx.strokeRect(0, 0, 200, 100) - ctx.strokeRect(100, 100, 200, 100) - } - - // 패턴 생성 - const pattern = new fabric.Pattern({ - source: patternSourceCanvas, - repeat: 'repeat', - }) - roof.set('fill', null) - - roof.set('fill', pattern) - canvas?.renderAll() - }) - } - - /** - * canvas 내용 불러오기 - */ - const handleLoadCanvas = async () => { - const canvasStates = await getCanvasState() - console.log(JSON.parse(canvasStates.canvas)) - canvas?.loadFromJSON(JSON.parse(canvasStates.canvas)) - } - - /** - * 컨트롤러 보이기/숨기기 - */ - const handleShowController = () => { - setShowControl(!showControl) - } - - const drawRoofPatterns = (roofStyle) => { - makeRoofPatternPolygon(roofStyle) - } - - const deleteCell = () => { - const selectedCells = canvas?.getObjects().filter((obj) => obj.name === 'cell' && obj.selected) - - selectedCells.forEach((cell) => { - canvas?.remove(cell) - }) - } - - const setCompassState = (degree) => { - setCompass(degree) - } - - const changeLength = (e) => { - const polygon = canvas?.getActiveObject() - - if (polygon?.type !== 'QPolygon') { - return - } - setScale(e) - polygon.setScaleX(e) - - canvas?.renderAll() - } - - const moduleConfiguration = () => { - createRoofRack() - } - - const setDirectionStringToArrow = () => { - drawDirectionStringToArrow(canvas, globalCampass) - - /** - * 나중에 유틸로 다시 구현 - */ - // const groupShapes = canvas?.getObjects().filter((obj) => obj.name === 'cellGroup') - - // console.log('groupShapes', groupShapes) - - // groupShapes.forEach((obj) => { - // let originAngle = obj._objects.find((array) => array.originAngle !== undefined).originAngle - - // console.log('originAngle', originAngle) - - // let rotateAngle = globalCampass - - // // let rotateAngle = originAngle + globalCampass - // // if (rotateAngle > 360) { - // // rotateAngle -= 360 - // // } - - // console.log('rotateAngle', rotateAngle) - - // obj.set({ angle: rotateAngle, originX: 'center', originY: 'center' }) - // obj.setCoords() - // }) - canvas?.renderAll() - } - - const setHipRoof = () => { - const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[2] - currentRoof.attributes.type = LINE_TYPE.WALLLINE.EAVES - currentRoof.attributes.offset = 50 - changeCurrentRoof(currentRoof, canvas) - } - const setGableRoof = () => { - const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[2] - currentRoof.attributes.type = LINE_TYPE.WALLLINE.GABLE - currentRoof.attributes.offset = 30 - changeCurrentRoof(currentRoof, canvas) - } - const setHipAndGableRoof = () => { - let offset = Number(prompt('팔작지붕 폭', '50')) - if (!isNaN(offset) && offset > 0) { - const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[2] - currentRoof.attributes.type = LINE_TYPE.WALLLINE.HIPANDGABLE - currentRoof.attributes.width = offset - changeCurrentRoof(currentRoof, canvas) - } else { - alert('폭은 0 보다 커야 함') - } - } - const setJerkInHeadRoof = () => { - let offset = Number(prompt('팔작지붕 폭', '50')) - if (!isNaN(offset) && offset > 0) { - const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[2] - currentRoof.attributes.type = LINE_TYPE.WALLLINE.JERKINHEAD - currentRoof.attributes.width = offset - changeCurrentRoof(currentRoof, canvas) - } else { - alert('폭은 0 보다 커야 함') - } - } - const setWallRoof = () => { - let offset = Number(prompt('소매 폭', '0')) - const polygon = canvas?.getObjects().find((obj) => obj.name === 'roof') - const currentRoof = polygon.lines[2] - currentRoof.attributes.type = LINE_TYPE.WALLLINE.WALL - currentRoof.attributes.width = offset - changeCurrentRoof(currentRoof, canvas) - } - return ( - <> - {canvas && ( - <> -
- - - - - - - - - - - - - - - - - - - - - - - - - - { - - } - - 현재 줌 : {zoom}% - - - {/*{templateType === 0 && (*/} - {/* <>*/} - - {/* */} - {/*)}*/} - - - - - - - - - {/**/} - {/* - - */} - - {templateType === 1 && ( - <> - - - - - - )} - - - - - - - -
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- - )} - - {/*
-

각도 입력(0~360) 후 방향설정 클릭

- { - const val = e.target.value.replace(/[^-0-9]/g, '') - if (val < 0 || val > 360) { - setGlobalCampass(0) - } else { - setGlobalCampass(Number(val)) - } - }} - /> - -
*/} - {/*
- Compass Circle -
- N, S, E, W Labels -
N
-
S
-
- E -
-
- W -
-
- - Compass Pointer -
- Red Upper Triangle -
-
-
*/} -
- - {!canvas ? null : mode === Mode.DRAW_LINE ? ( - - ) : currentObject?.type === 'QPolygon' ? ( - - ) : currentObject?.type === 'QLine' ? ( - - ) : ( - - )} -
- - ) -} diff --git a/src/components/Settings.jsx b/src/components/Settings.jsx deleted file mode 100644 index 51680711..00000000 --- a/src/components/Settings.jsx +++ /dev/null @@ -1,324 +0,0 @@ -'use client' - -import React, { useEffect, useState } from 'react' -import { Button } from '@nextui-org/react' - -import { useAxios } from '@/hooks/useAxios' - -import { useRecoilState } from 'recoil' -import { customSettingsState } from '@/store/canvasAtom' -import { modalContent, modalState } from '@/store/modalAtom' - -import ColorPicker from './common/color-picker/ColorPicker' - -export default function Settings() { - const [objectNo, setObjectNo] = useState('test123240829010') - const [error, setError] = useState(null) - const [customSettings, setCustomSettings] = useRecoilState(customSettingsState) - - const [color, setColor] = useState('#ff0000') - - const [open, setOpen] = useRecoilState(modalState) - const [contents, setContent] = useRecoilState(modalContent) - - const { get, post } = useAxios() - - const handleSavePopup = () => { - console.log('color ', color) - } - - const handleClosePopup = () => { - setContent('') - setOpen(false) - console.log('colorSetting ', color) - } - - const colorSetting = ( - <> -
-

React ColorPicker

- -
{color}
-
-

- -

- - ) - - const customStyles = { - overlay: { - backgroundColor: 'rgba(0,0,0,0.5)', - }, - content: { - width: '300px', - height: '400px', - margin: 'auto', - borderRadius: '4px', - boxShadow: '0 2px 4px rgba(0,0,0,0.2)', - padding: '20px', - }, - } - - // 상태를 하나의 객체로 관리 - const [settings, setSettings] = useState({ - display1: Array(11).fill(false), // 화면 표시1 - display2: Array(3).fill(false), // 화면 표시2 - rangeSetting: 0, // 흡착 범위 설정 - gridSettings: Array(5).fill(false), // 그리드 설정 - }) - - const gridItems = { - display1: [ - '할당 표시', - '도면 표시', - '그리드 표시', - '문자 표시', - '흐름방향 표시', - '복도치수 표시', - '실제치수 표시', - '치수 표시 없음', - '가대 표시', - '좌표 표시', - '도면전환 표시', - ], - display2: ['테두리만', '라인해치', 'All Painted'], - rangeSetting: ['극소', '소', '중', '대'], - gridSettings: ['임의 그리드', '실선 그리드', '점 그리드', '그리드 색 설정', '흡착점 추가'], - } - - // 초기 조회 - useEffect(() => { - if (!objectNo) { - alert('object_no를 입력하세요.') - } - }, []) - - // 클릭 시 상태 변경 함수 - const handleToggle = (type, index) => { - // '실선 그리드' 클릭 시 팝업 열기 - if (type === 'gridSettings' && gridItems.gridSettings[index] === '실선 그리드') { - //openGridPopup() - } - - // '그리드 색 설정' 클릭 시 팝업 열기 - if (type === 'gridSettings' && gridItems.gridSettings[index] === '그리드 색 설정') { - //setSelectedGridSetting(gridItems.gridSettings[index]) - //setIsPopupOpen(true) - //return prevSettings // 설정은 변경하지 않음 - - setOpen(true) - setContent({ ...colorSetting }) - } - - setSettings((prevSettings) => { - // prevSettings[type]이 배열인지 확인하고, 그렇지 않은 경우 빈 배열로 초기화 - let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : [] - - if (type === 'rangeSetting') { - return { ...prevSettings, [type]: index } - } - - updated[index] = updated[index] === false ? true : false - return { ...prevSettings, [type]: updated } - }) - } - - // '실선 그리드' 클릭 시 팝업을 열기 위한 함수 - const openGridPopup = () => { - const popupWidth = 500 - const popupHeight = 300 - - // 팝업 창 위치를 화면 중앙으로 조정하기 위해 계산 - const left = window.innerWidth / 2 - popupWidth / 2 - const top = window.innerHeight / 2 - popupHeight / 2 - - // 새 창 열기 - window - .open - //'./components/intro', // 팝업으로 띄울 페이지의 URL - //'_blank', // 새 창으로 열기 - //`width=${popupWidth},height=${popupHeight},top=${top},left=${left}`, // 크기와 위치 지정 - () - } - - // Canvas Setting 조회 및 초기화 - const handleSelect = async () => { - try { - if (!objectNo) { - alert('object_no를 입력하세요.') - return - } - - const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` }) - - // 데이터가 없는 경우 - if (!res) { - console.warn('조회 결과가 없습니다.') - // 기본값을 설정하거나 사용자에게 알림 표시 - setSettings({ - display1: Array(11).fill(false), // 화면 표시1 기본값 - display2: Array(3).fill(false), // 화면 표시2 기본값 - rangeSetting: 0, // 흡착 범위 설정 기본값 - gridSettings: Array(5).fill(false), // 그리드 설정 기본값 - }) - - alert('조회된 데이터가 없습니다. 기본 설정이 적용됩니다.') - return // 이후 코드 실행을 중단 - } - - const data = { - display1: [ - res.assignDisplay, - res.drawDisplay, - res.gridDisplay, - res.charDisplay, - res.flowDisplay, - res.hallwayDimenDisplay, - res.actualDimenDisplay, - res.noDimenDisplay, - res.trestleDisplay, - res.coordiDisplay, - res.drawConverDisplay, - ], - display2: [res.onlyBorder, res.lineHatch, res.allPainted], - rangeSetting: res.adsorpRangeSetting, - gridSettings: [res.randomGrid, res.solidGrid, res.dotGrid, res.gridColorSet, res.adsorpPointAdd], - } - - // 데이터 설정 - setSettings({ - display1: data.display1, - display2: data.display2, - rangeSetting: data.rangeSetting, - gridSettings: data.gridSettings, - }) - } catch (error) { - console.error('Data fetching error:', error) - } - } - - // Canvas Setting 저장 - const handleSubmit = async () => { - if (!objectNo) { - alert('object_no를 입력하세요.') - return - } - - const patternData = { - objectNo, - assignDisplay: settings.display1[0], - drawDisplay: settings.display1[1], - gridDisplay: settings.display1[2], - charDisplay: settings.display1[3], - flowDisplay: settings.display1[4], - hallwayDimenDisplay: settings.display1[5], - actualDimenDisplay: settings.display1[6], - noDimenDisplay: settings.display1[7], - trestleDisplay: settings.display1[8], - coordiDisplay: settings.display1[9], - drawConverDisplay: settings.display1[10], - onlyBorder: settings.display2[0], - lineHatch: settings.display2[1], - allPainted: settings.display2[2], - adsorpRangeSetting: settings.rangeSetting, - randomGrid: settings.gridSettings[0], - solidGrid: settings.gridSettings[1], - dotGrid: settings.gridSettings[2], - gridColorSet: settings.gridSettings[3], - adsorpPointAdd: settings.gridSettings[4], - } - - console.log('patternData', patternData) - - await post({ url: `/api/canvas-management/canvas-settings`, data: patternData }) - - //Recoil 설정 - setCustomSettings({ ...patternData }) - - // 저장 후 재조회 - await handleSelect() - } - - return ( - <> -
-
- setObjectNo(e.target.value)} /> - - -
-
-

[디스플레이 설정]

-

* 도면에 표시할 항목을 클릭하면 적용 됩니다.

-
- {gridItems.display1.map((item, index) => ( -
handleToggle('display1', index)} - > - {settings.display1[index]} {item} -
- ))} -
-
-

* 화면 표시

-
- {gridItems.display2.map((item, index) => ( -
handleToggle('display2', index)} - > - {settings.display2[index]} {item} -
- ))} -
-

[글꼴/도면크기 설정]

-

* 글꼴 및 크기 변경

-
-
문자 글꼴 변경
-
흐름방향 글꼴 변경
-
치수 글꼴 변경
-
회로번호 글꼴 변경
-
- `` -

* 흡착 범위 설정

-
- {gridItems.rangeSetting.map((item, index) => ( -
handleToggle('rangeSetting', index)} - > - {item} -
- ))} -
-
-
치수선 설정
-
도면 크기 설정
-
흡착점 ON
-
-

[그리드 설정]

-
- -
{color}
-
-
- {gridItems.gridSettings.map((item, index) => ( -
handleToggle('gridSettings', index)} - > - {settings.gridSettings[index]} {item} -
- ))} -
-
-
- - ) -} diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index deb95caf..72e7bb30 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -87,7 +87,7 @@ export default function Estimate({}) { const { getMessage } = useMessage() const { closeAll } = usePopup() - const { setMenuNumber } = useCanvasMenu() + const { setSelectedMenu } = useCanvasMenu() //새로 추가한 첨부파일 props const fileUploadProps = { uploadFiles: files, @@ -142,7 +142,7 @@ export default function Estimate({}) { }, [selectedPlan]) useEffect(() => { - setMenuNumber(5) + setSelectedMenu('estimate') initEstimate() }, []) diff --git a/src/components/estimate/EstimateFileUploader.jsx b/src/components/estimate/EstimateFileUploader.jsx index 950ed6af..c02d4637 100644 --- a/src/components/estimate/EstimateFileUploader.jsx +++ b/src/components/estimate/EstimateFileUploader.jsx @@ -3,11 +3,14 @@ import { useRef } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMessage } from '@/hooks/useMessage' +import { useSwal } from '@/hooks/useSwal' export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { const fileInputRef = useRef(null) const { getMessage } = useMessage() + const { swalFire } = useSwal() + const handleButtonClick = (e) => { e.preventDefault() fileInputRef.current.click() @@ -20,9 +23,16 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { const fileList = [] let passFlag = true + const allowedFileTypes = [ + 'image/', + 'application/pdf', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-excel', + ] Array.from(e.target.files).forEach((file) => { - let fileType = file.type - if (!fileType.includes('image')) { + //엑셀, pdf, 이미지 + const fileType = file.type + if (!allowedFileTypes.some((type) => fileType.includes(type))) { passFlag = false } else { fileList.push({ data: file, id: uuidv4() }) @@ -30,30 +40,11 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { }) if (!passFlag) { - alert(getMessage('estimate.detail.fileList.extCheck')) + swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' }) } - // const { files } = e.target - // const file = files[0] - // const fileType = file.type - // if (!fileType.includes('image')) { - // return alert(getMessage('estimate.detail.fileList.extCheck')) - // } - - // setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }]) - //다중으로 변경 setUploadFiles([...uploadFiles, ...fileList]) e.target.value = '' - // const formData = new FormData() - // formData.append('file', e.target.files[0]) - // formData.append('objectNo', objectNo) // 받아와야 하는 값 - // formData.append('planNo', planNo) // 받아와야 하는 값 - // formData.append('category', category) // 받아와야 하는 값 - // formData.append('userId', session.userId) - - // await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => { - // if (res.data > 0) setUploadFiles([...files, { name: e.target.files[0].name, id: uuidv4() }]) - // }) } const deleteFile = (id) => { @@ -65,10 +56,17 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { e.stopPropagation() const fileList = [] let passFlag = true + const allowedFileTypes = [ + 'image/', + 'application/pdf', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + 'application/vnd.ms-excel', + ] Array.from(e.dataTransfer.files).forEach((file) => { + //엑셀, pdf, 이미지 let fileType = file.type - if (!fileType.includes('image')) { + if (!allowedFileTypes.some((type) => fileType.includes(type))) { passFlag = false } else { fileList.push({ data: file, id: uuidv4() }) @@ -76,7 +74,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { }) if (!passFlag) { - alert(getMessage('estimate.detail.fileList.extCheck')) + swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' }) } setUploadFiles([...uploadFiles, ...fileList]) @@ -103,16 +101,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) { - onChangeFiles(e)} - /> + onChangeFiles(e)} />
-
+
{plans.map((plan, index) => (
-
num === menuNumber) ? 'active' : ''}`}> - {[2, 3, 4].some((num) => num === menuNumber) && } +
num === selectedMenu) ? 'active' : ''}`}> + {['outline', 'surface', 'module'].some((num) => num === selectedMenu) && }
{/* 견적서(menuNumber=== 5) 상세화면인경우 문서다운로드 팝업 */} {estimatePopupOpen && ( diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx index 054f1e00..25efa782 100644 --- a/src/components/floor-plan/FloorPlan.jsx +++ b/src/components/floor-plan/FloorPlan.jsx @@ -18,7 +18,7 @@ export default function FloorPlan({ children }) { const pid = searchParams.get('pid') const { closeAll } = usePopup() - const { menuNumber, setMenuNumber } = useCanvasMenu() + const { selectedMenu, setSelectedMenu } = useCanvasMenu() const { fetchSettings } = useCanvasSetting() const resetCurrentMenu = useResetRecoilState(currentMenuState) useEffect(() => { @@ -54,15 +54,17 @@ export default function FloorPlan({ children }) { }, [correntObjectNo]) const modalProps = { - menuNumber, - setMenuNumber, + selectedMenu, + setSelectedMenu, } return ( <>
-
{children}
+
+ {children} +
) diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index c1f40140..693ccc9d 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -6,32 +6,37 @@ import { useMessage } from '@/hooks/useMessage' import useMenu from '@/hooks/common/useMenu' import { canvasState, currentMenuState } from '@/store/canvasAtom' import { useRecoilState, useRecoilValue } from 'recoil' -import { menuTypeState, subMenusState } from '@/store/menuAtom' +import { subMenusState } from '@/store/menuAtom' +import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' export default function MenuDepth01() { - const type = useRecoilValue(menuTypeState) const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() const { handleMenu } = useMenu() + const { selectedMenu, setSelectedMenu } = useCanvasMenu() const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) const subMenus = useRecoilValue(subMenusState) const onClickMenu = ({ id, menu }) => { if (menu === currentMenu) { - handleMenu(type) + handleMenu(selectedMenu) } else { setCurrentMenu(menu) } } useEffect(() => { - handleMenu(type) + console.log(subMenus[selectedMenu]) + }, [selectedMenu]) + + useEffect(() => { + handleMenu(selectedMenu) canvas?.discardActiveObject() }, [currentMenu]) return (
    - {subMenus[type]?.map((menu) => { + {subMenus[selectedMenu]?.map((menu) => { return (
  • diff --git a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx index 69f5383e..eaf41524 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -220,8 +220,8 @@ export default function PassivityCircuitAllocation(props) { goodsNo: model.goodsNo, serQtyList: [ { - serQty: result[index + 1].maxValue, - paralQty: result[index + 1].count, + serQty: result[(index + 1).toString()].maxValue, + paralQty: result[(index + 1).toString()].count, rmdYn: 'Y', usePossYn: 'Y', roofSurfaceList: roofSurfaceList, diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index ed400f95..2fed8591 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -63,20 +63,21 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla /** * 지붕재 초기값 */ - const defaultRoofSettings = { - roofSizeSet: '1', // 기본 치수 입력 방법 - roofAngleSet: 'slope', // 기본 지붕 각도 설정 + const DEFAULT_ROOF_SETTINGS = { + roofSizeSet: '1', + roofAngleSet: 'slope', angle: 21.8, - hajebichi: '', + hajebichi: null, id: 'ROOF_ID_WA_53A', index: 0, layout: ROOF_MATERIAL_LAYOUT.PARALLEL, lenAuth: 'R', lenBase: '235.000', - length: '235', + length: 235, name: '일본기와 A', nameJp: '和瓦A', pitch: 4, + planNo: planNo, raft: '', raftAuth: 'C', raftBaseCd: 'HEI_455', @@ -89,12 +90,12 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla selected: true, widAuth: 'R', widBase: '265.000', - width: '265', + width: 265, } useEffect(() => { /** - * 메뉴에서 배치면초기설정 선택 시 조회 + * 메뉴에서 배치면초기설정 선택 시 조회 후 화면 오픈 */ if (openPoint && openPoint === 'canvasMenus') fetchBasicSettings(planNo, openPoint) }, []) @@ -103,18 +104,16 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla if (addedRoofs.length > 0) { const raftCodeList = findCommonCode('203800') setRaftCodes(raftCodeList) - - /** - * 데이터 설정 확인 후 데이터가 없으면 기본 데이터 설정 - */ - if (addedRoofs.length > 0) { - setCurrentRoof({ ...addedRoofs[0], planNo: basicSetting.planNo }) - } else { - setCurrentRoof(defaultRoofSettings) - } + setCurrentRoof({ ...addedRoofs[0], planNo: planNo, roofSizeSet: String(basicSetting.roofSizeSet), roofAngleSet: basicSetting.roofAngleSet }) + } else { + /** 데이터 설정 확인 후 데이터가 없으면 기본 데이터 설정 */ + setCurrentRoof({ ...DEFAULT_ROOF_SETTINGS }) } }, [addedRoofs]) + /** + * 배치면초기설정 정보 변경 시 basicSettings 설정 + */ useEffect(() => { if (!currentRoof) return setBasicSettings({ @@ -256,7 +255,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla id={item.id} name={item.name} value={item.value} - checked={currentRoof?.roofSizeSet === item.value} + checked={String(currentRoof?.roofSizeSet) === item.value} onChange={(e) => setCurrentRoof({ ...currentRoof, roofSizeSet: e.target.value })} /> @@ -279,7 +278,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla id={item.id} name={item.name} value={item.value} - checked={currentRoof?.roofAngleSet === item.value} + checked={String(currentRoof?.roofAngleSet) === item.value} onChange={(e) => setCurrentRoof({ ...currentRoof, roofAngleSet: e.target.value })} /> diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index a95f34d2..aacaeea4 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -38,7 +38,7 @@ export default function StuffDetail() { const [showButton, setShowButton] = useState('') //임시저장, 저장, 삭제 버튼 컨트롤 - const { setMenuNumber } = useCanvasMenu() + const { setSelectedMenu } = useCanvasMenu() //공통코드 const { commonCode, findCommonCode } = useCommonCode() @@ -308,7 +308,7 @@ export default function StuffDetail() { onClick={() => { setFloorPlanObjectNo({ floorPlanObjectNo: params.data.objectNo }) setIsGlobalLoading(true) - setMenuNumber(5) + setSelectedMenu('estimate') router.push(`/floor-plan/estimate/5?pid=${params.data.planNo}&objectNo=${params.data.objectNo}`) }} > @@ -1653,7 +1653,7 @@ export default function StuffDetail() { pid: planNo, objectNo: objectNo, } - setMenuNumber(null) + setSelectedMenu(null) const url = `/floor-plan?${queryStringFormatter(param)}` router.push(url) } diff --git a/src/components/management/StuffSubHeader.jsx b/src/components/management/StuffSubHeader.jsx index 368926a2..18eaa761 100644 --- a/src/components/management/StuffSubHeader.jsx +++ b/src/components/management/StuffSubHeader.jsx @@ -27,7 +27,7 @@ export default function StuffSubHeader({ type }) { const [buttonStyle, setButtonStyle] = useState('') - const { setMenuNumber } = useCanvasMenu() + const { setSelectedMenu } = useCanvasMenu() useEffect(() => { window.scrollTo(0, 0) @@ -55,7 +55,7 @@ export default function StuffSubHeader({ type }) { objectNo: objectNo, } - setMenuNumber(null) + setSelectedMenu(null) const url = `/floor-plan?${queryStringFormatter(param)}` router.push(url) diff --git a/src/components/playground.module.css b/src/components/playground.module.css deleted file mode 100644 index 273a4a34..00000000 --- a/src/components/playground.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.test { - @apply bg-red-500; - @apply text-2xl; -} diff --git a/src/hooks/common/useCanvasMenu.js b/src/hooks/common/useCanvasMenu.js index 0fb1e87d..f90881d3 100644 --- a/src/hooks/common/useCanvasMenu.js +++ b/src/hooks/common/useCanvasMenu.js @@ -1,4 +1,4 @@ -import { menuNumberState } from '@/store/menuAtom' +import { selectedMenuState } from '@/store/menuAtom' import { useRecoilState, useRecoilValue } from 'recoil' import { useEffect } from 'react' import { canvasState } from '@/store/canvasAtom' @@ -6,28 +6,12 @@ import { usePolygon } from '@/hooks/usePolygon' import { POLYGON_TYPE } from '@/common/common' export const useCanvasMenu = () => { - const [menuNumber, setMenuNumber] = useRecoilState(menuNumberState) + const [selectedMenu, setSelectedMenu] = useRecoilState(selectedMenuState) const canvas = useRecoilValue(canvasState) const { drawDirectionArrow } = usePolygon() - /*useEffect(() => { - /!* - * 모듈,회로 구성을 벗어나면 방향 표시 초기화 필요 - * *!/ - if (!canvas) return - if (![4, 5].includes(menuNumber)) { - canvas - .getObjects() - .filter((obj) => obj.name === POLYGON_TYPE.ROOF) - .forEach((obj) => { - obj.set('moduleCompass', null) - // drawDirectionArrow(obj) - }) - } - }, [menuNumber])*/ - return { - menuNumber, - setMenuNumber, + selectedMenu, + setSelectedMenu, } } diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js index e1c37915..60aab800 100644 --- a/src/hooks/common/useMasterController.js +++ b/src/hooks/common/useMasterController.js @@ -2,10 +2,6 @@ import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { useSwal } from '@/hooks/useSwal' import { getQueryString } from '@/util/common-utils' -import { trestleRequest, constructionRequest, trestleDetailRequest } from '@/models/apiModels' -import { POST } from '@/app/api/image-upload/route' -import { canvasState } from '@/store/canvasAtom' -import { useRecoilValue } from 'recoil' /** * 마스터 컨트롤러 훅 diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index 14bf6447..2e40dab5 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -49,7 +49,7 @@ export const useTrestle = () => { const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId) const roofMaterialIndex = parent.roofMaterial.index if (+roofSizeSet === 3) { - return true + return } const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction if (!construction) { diff --git a/src/hooks/option/useCanvasSetting.js b/src/hooks/option/useCanvasSetting.js index 8cdecf1c..5ae28ba9 100644 --- a/src/hooks/option/useCanvasSetting.js +++ b/src/hooks/option/useCanvasSetting.js @@ -33,7 +33,6 @@ import { useColor } from 'react-color-palette' import { useMasterController } from '@/hooks/common/useMasterController' import PlacementShapeSetting, { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { useCanvasMenu } from '../common/useCanvasMenu' -import { menuTypeState } from '@/store/menuAtom' import { usePopup } from '../usePopup' import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider' import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions' @@ -43,21 +42,19 @@ import { v4 as uuidv4 } from 'uuid' const defaultDotLineGridSetting = { INTERVAL: { - type: 2, // 1: 가로,세로 간격 수동, 2: 비율 간격 + type: 2 /* 1: 가로,세로 간격 수동, 2: 비율 간격 */, ratioInterval: 910, verticalInterval: 910, horizontalInterval: 910, - dimension: 1, // 치수 + dimension: 1 /* 치수 */, }, DOT: false, LINE: false, } -// let previousRoofMaterialsYn = 'N' // 지붕재 select 정보 비교 후 변경된 것이 없으면 1회만 실행 - export function useCanvasSetting() { const canvas = useRecoilValue(canvasState) - /* canvas가 null이 아닐 때에만 getObjects 호출 */ + /** canvas가 null이 아닐 때에만 getObjects 호출 */ const canvasObjects = canvas ? canvas.getObjects() : [] const [correntObjectNo, setCorrentObjectNo] = useRecoilState(correntObjectNoState) @@ -88,7 +85,7 @@ export function useCanvasSetting() { ) const [gridColor, setGridColor] = useRecoilState(gridColorState) const [color, setColor] = useColor(gridColor ?? '#FF0000') - const { menuNumber, setMenuNumber } = useCanvasMenu() + const { selectedMenu, setSelectedMenu } = useCanvasMenu() const [settingsData, setSettingsData] = useState({ ...settingModalFirstOptions, @@ -116,17 +113,16 @@ export function useCanvasSetting() { const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom) const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) const [fetchRoofMaterials, setFetchRoofMaterials] = useRecoilState(fetchRoofMaterialsState) - const [type, setType] = useRecoilState(menuTypeState) const setCurrentMenu = useSetRecoilState(currentMenuState) - const resetModuleSelectionData = useResetRecoilState(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터 - const resetSelectedModules = useResetRecoilState(selectedModuleState) //선택된 모듈 + const resetModuleSelectionData = useResetRecoilState(moduleSelectionDataState) /* 다음으로 넘어가는 최종 데이터 */ + const resetSelectedModules = useResetRecoilState(selectedModuleState) /* 선택된 모듈 */ const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2) - const [raftCodes, setRaftCodes] = useState([]) // 서까래 정보 + const [raftCodes, setRaftCodes] = useState([]) /* 서까래 정보 */ const { findCommonCode } = useCommonCode() - const [currentRoof, setCurrentRoof] = useState(null) // 현재 선택된 지붕재 정보 + const [currentRoof, setCurrentRoof] = useState(null) /* 현재 선택된 지붕재 정보 */ const { addPopup } = usePopup() const [popupId, setPopupId] = useState(uuidv4()) @@ -144,7 +140,7 @@ export function useCanvasSetting() { useEffect(() => { const tempFetchRoofMaterials = !fetchRoofMaterials - /* 초 1회만 실행하도록 처리 */ + /** 초 1회만 실행하도록 처리 */ setFetchRoofMaterials(tempFetchRoofMaterials) if (tempFetchRoofMaterials) { addRoofMaterials() @@ -176,7 +172,23 @@ export function useCanvasSetting() { angle: item.angle ? parseInt(item.angle) : 21.8, })) setRoofMaterials(roofLists) - const selectedRoofMaterial = roofLists[0] + } + + useEffect(() => { + if (addedRoofs.length > 0 && addedRoofs[0].planNo === basicSetting.planNo) { + const raftCodeList = findCommonCode('203800') + setRaftCodes(raftCodeList) + setCurrentRoof({ + ...addedRoofs[0], + planNo: addedRoofs[0].planNo, + roofSizeSet: String(basicSetting.roofSizeSet), + roofAngleSet: basicSetting.roofAngleSet, + }) + } + }, [addedRoofs]) + + useEffect(() => { + const selectedRoofMaterial = roofMaterials[0] if (addedRoofs.length === 0) { const newAddedRoofs = [] @@ -184,19 +196,7 @@ export function useCanvasSetting() { setAddedRoofs(newAddedRoofs) } setBasicSettings({ ...basicSetting, selectedRoofMaterial: selectedRoofMaterial }) - } - - /** - * 배치면 초기설정 화면이 열리지 않아도 데이터 set 하기 위해서 추가 - */ - useEffect(() => { - if (addedRoofs.length > 0) { - const raftCodeList = findCommonCode('203800') - setRaftCodes(raftCodeList) - - setCurrentRoof({ ...addedRoofs[0] }) - } - }, [addedRoofs]) + }, [roofMaterials]) useEffect(() => { if (!canvas) { @@ -369,9 +369,9 @@ export function useCanvasSetting() { }, ] - /* 메뉴에서 배치면 초기설정 클릭 시 실행하지 않음 */ + /** 메뉴에서 배치면 초기설정 클릭 시 실행하지 않음 */ if (openPoint === null) { - /* 배치면 초기설정 미저장 상태이면 화면 열기 */ + /** 배치면 초기설정 미저장 상태이면 화면 열기 */ const placementInitialProps = { id: popupId, pos: { @@ -385,7 +385,7 @@ export function useCanvasSetting() { } } - /* 데이터 설정 */ + /** 데이터 설정 */ const addRoofs = [] for (let i = 0; i < roofsArray.length; i++) { roofMaterials?.map((material) => { @@ -440,6 +440,19 @@ export function useCanvasSetting() { // setCanvasSetting({ ...basicSetting }) } + /** + * 저장/복사저장 시 지붕 크기에 따른 메뉴 설정 + */ + const setMenuByRoofSize = (roofSizeSet) => { + if (['2', '3'].includes(String(roofSizeSet))) { + setSelectedMenu('surface') + setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING) + } else { + setSelectedMenu('outline') + setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) + } + } + /** * 기본설정(PlacementShapeSetting) 저장 */ @@ -471,31 +484,23 @@ export function useCanvasSetting() { await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData }).then((res) => { swalFire({ text: getMessage(res.returnMessage) }) - /* BasicSettings Recoil 설정 */ + /** BasicSettings Recoil 설정 */ setBasicSettings({ ...params }) }) - /* CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ + /** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ setCanvasSetting({ ...basicSetting, roofSizeSet: String(params.roofSizeSet), }) - /* 메뉴 설정 */ - if (['2', '3'].includes(params.roofSizeSet)) { - setMenuNumber(3) - setType('surface') - setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING) - } else { - setMenuNumber(2) - setType('outline') - setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) - } + /** 메뉴 설정 */ + setMenuByRoofSize(params.roofSizeSet) - /* 배치면초기설정 조회 */ + /** 배치면초기설정 조회 */ fetchBasicSettings(params.planNo, 'basicSettingSave') - /* 모듈 선택 데이터 초기화 */ + /** 모듈 선택 데이터 초기화 */ resetModuleSelectionData() moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] }) const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE) @@ -536,27 +541,19 @@ export function useCanvasSetting() { swalFire({ text: getMessage(res.returnMessage) }) }) - /* CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ + /** CanvasSetting Recoil 설정 - roofSizeSet을 문자열로 변환 */ setCanvasSetting({ ...basicSetting, roofSizeSet: String(params.roofSizeSet), }) - /* 메뉴 설정 */ - if (['2', '3'].includes(params?.roofSizeSet)) { - setMenuNumber(3) - setType('surface') - setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING) - } else { - setMenuNumber(2) - setType('outline') - setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE) - } + /** 메뉴 설정 */ + setMenuByRoofSize(params.roofSizeSet) - /* 배치면초기설정 조회 */ + /** 배치면초기설정 조회 */ fetchBasicSettings(Number(params.planNo), 'basicSettingSave') - /* 모듈 선택 데이터 초기화 */ + /** 모듈 선택 데이터 초기화 */ resetModuleSelectionData() moduleSelectedDataTrigger({ common: {}, module: {}, roofConstructions: [] }) const isModuleExist = canvas.getObjects().some((obj) => obj.name === POLYGON_TYPE.MODULE) @@ -582,24 +579,16 @@ export function useCanvasSetting() { const optionData4 = settingModalSecondOptions.option4.map((item) => ({ ...item, selected: res[item.column] })) const optionData5 = settingModalFirstOptions.dimensionDisplay.map((item) => ({ ...item })) - /** - * 흡착점 ON/OFF - */ + /** 흡착점 ON/OFF */ setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: res.adsorpPoint }) - /** - * 치수선 설정 - */ + /** 치수선 설정 */ setDimensionLineSettings({ ...dimensionLineSettings, pixel: res.originPixel, color: res.originColor }) - /** - * 도면크기 설정 - */ + /** 도면크기 설정 */ setPlanSizeSettingMode({ ...planSizeSettingMode, originHorizon: res.originHorizon, originVertical: res.originVertical }) - /** - * 데이터 설정 - */ + /** 데이터 설정 */ setSettingModalFirstOptions({ ...settingModalFirstOptions, option1: optionData1, @@ -614,45 +603,35 @@ export function useCanvasSetting() { const fontPatternData = { commonText: { - /** - * 문자 글꼴 조회 데이터 - */ + /** 문자 글꼴 조회 데이터 */ fontFamily: getFonts(res.wordFont), fontWeight: getFontStyles(res.wordFontStyle), fontSize: getFontSizes(res.wordFontSize), fontColor: getFontColors(res.wordFontColor), }, flowText: { - /** - * 흐름방향 글꼴 조회 데이터 - */ + /** 흐름방향 글꼴 조회 데이터 */ fontFamily: getFonts(res.flowFont), fontWeight: getFontStyles(res.flowFontStyle), fontSize: getFontSizes(res.flowFontSize), fontColor: getFontColors(res.flowFontColor), }, dimensionLineText: { - /** - * 치수 글꼴 조회 데이터 - */ + /** 치수 글꼴 조회 데이터 */ fontFamily: getFonts(res.dimensioFont), fontWeight: getFontStyles(res.dimensioFontStyle), fontSize: getFontSizes(res.dimensioFontSize), fontColor: getFontColors(res.dimensioFontColor), }, circuitNumberText: { - /** - * 회로번호 글꼴 조회 데이터 - */ + /** 회로번호 글꼴 조회 데이터 */ fontFamily: getFonts(res.circuitNumFont), fontWeight: getFontStyles(res.circuitNumFontStyle), fontSize: getFontSizes(res.circuitNumFontSize), fontColor: getFontColors(res.circuitNumFontColor), }, lengthText: { - /** - * 치수선 글꼴 조회 데이터 - */ + /** 치수선 글꼴 조회 데이터 */ fontFamily: getFonts(res.lengthFont), fontWeight: getFontStyles(res.lengthFontStyle), fontSize: getFontSizes(res.lengthFontSize), @@ -660,14 +639,10 @@ export function useCanvasSetting() { }, } - /** - * 조회된 글꼴 데이터 set - */ + /** 조회된 글꼴 데이터 set */ setGlobalFont(fontPatternData) - /** - * 점/선 그리드 - */ + /** 점/선 그리드 */ const patternData = { INTERVAL: { type: res.gridType, @@ -682,47 +657,31 @@ export function useCanvasSetting() { setDotLineGridSettingState(patternData) - /** - * 그리드 색 설정 - */ + /** 그리드 색 설정 */ setGridColor(res.gridColor) } else { - //조회된 글꼴 데이터가 없는 경우 (데이터 초기화) + /** 조회된 글꼴 데이터가 없는 경우 (데이터 초기화) */ - /** - * 흡착점 ON/OFF - */ + /** 흡착점 ON/OFF */ setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: false }) - /** - * 치수선 설정 - */ + /** 치수선 설정 */ resetDimensionLineSettings() - /** - * 도면크기 설정 - */ + /** 도면크기 설정 */ resetPlanSizeSettingMode() - /** - * 데이터 설정 - */ + /** 데이터 설정 */ resetSettingModalFirstOptions() resetSettingModalSecondOptions() - /** - * 데이터 초기화 - */ + /** 데이터 초기화 */ resetGlobalFont() - /** - * 점/선 그리드 - */ + /** 점/선 그리드 */ setDotLineGridSettingState({ ...defaultDotLineGridSetting }) - /** - * 그리드 색 설정 - */ + /** 그리드 색 설정 */ setGridColor('#FF0000') } @@ -736,9 +695,7 @@ export function useCanvasSetting() { * CanvasSetting 옵션 클릭 후 저장 */ const onClickOption2 = async () => { - /** - * 서버에 전송할 데이터 - */ + /** 서버에 전송할 데이터 */ const dataToSend = { firstOption1: option1.map((item) => ({ column: item.column, @@ -759,13 +716,9 @@ export function useCanvasSetting() { })), } const patternData = { - /** - * 견적서 번호 - */ + /** 견적서 번호 */ objectNo: correntObjectNo, - /** - * 디스플레이 설정(다중) - */ + /** 디스플레이 설정(다중) */ allocDisplay: dataToSend.firstOption1[0].selected, outlineDisplay: dataToSend.firstOption1[1].selected, gridDisplay: dataToSend.firstOption1[2].selected, @@ -776,85 +729,62 @@ export function useCanvasSetting() { trestleDisplay: dataToSend.firstOption1[7].selected, imageDisplay: dataToSend.firstOption1[8].selected, totalDisplay: dataToSend.firstOption1[9].selected, - /** - * 차수 표시(단 건) - */ + /** 차수 표시(단 건) */ corridorDimension: dataToSend.firstOption3[0].selected, realDimension: dataToSend.firstOption3[1].selected, noneDimension: dataToSend.firstOption3[2].selected, - /** - * 화면 표시(단 건) - */ + /** 화면 표시(단 건) */ onlyBorder: dataToSend.firstOption2[0].selected, lineHatch: dataToSend.firstOption2[1].selected, allPainted: dataToSend.firstOption2[2].selected, - /** - * 흡착범위 설정(단 건) - */ + /** 흡착범위 설정(단 건) */ adsorpRangeSmall: dataToSend.secondOption2[0].selected, adsorpRangeSmallSemi: dataToSend.secondOption2[1].selected, adsorpRangeMedium: dataToSend.secondOption2[2].selected, adsorpRangeLarge: dataToSend.secondOption2[3].selected, - - /** - * 흡착점 ON/OFF - */ + /** 흡착점 ON/OFF */ adsorpPoint: adsorptionPointMode.adsorptionPoint, //??: adsorptionRange, 사용여부 확인 필요 - /** - * 글꼴 설정 - */ - //문자 글꼴 + /** 문자 글꼴 설정 */ wordFont: globalFont.commonText.fontFamily?.value ?? 'MS PGothic', wordFontStyle: globalFont.commonText.fontWeight?.value ?? 'normal', wordFontSize: globalFont.commonText.fontSize?.value ?? 16, wordFontColor: globalFont.commonText.fontColor?.value ?? 'black', - /** - * 흐름방향 글꼴 - */ + /** 흐름방향 글꼴 설정 */ flowFont: globalFont.flowText.fontFamily?.value ?? 'MS PGothic', flowFontStyle: globalFont.flowText.fontWeight?.value ?? 'normal', flowFontSize: globalFont.flowText.fontSize?.value ?? 16, flowFontColor: globalFont.flowText.fontColor?.value ?? 'black', - /** - * 치수 글꼴 - */ + /** 치수 글꼴 설정 */ dimensioFont: globalFont.dimensionLineText.fontFamily?.value ?? 'MS PGothic', dimensioFontStyle: globalFont.dimensionLineText.fontWeight?.value ?? 'normal', dimensioFontSize: globalFont.dimensionLineText.fontSize?.value ?? 16, dimensioFontColor: globalFont.dimensionLineText.fontColor?.value ?? 'black', - /** - * 회로번호 글꼴 - */ + /** 회로번호 글꼴 설정 */ circuitNumFont: globalFont.circuitNumberText.fontFamily?.value ?? 'MS PGothic', circuitNumFontStyle: globalFont.circuitNumberText.fontWeight?.value ?? 'normal', circuitNumFontSize: globalFont.circuitNumberText.fontSize?.value ?? 16, circuitNumFontColor: globalFont.circuitNumberText.fontColor?.value ?? 'black', - /** - * 치수선 글꼴 - */ + /** 치수선 글꼴 설정 */ lengthFont: globalFont.lengthText.fontFamily?.value ?? 'MS PGothic', lengthFontStyle: globalFont.lengthText.fontWeight?.value ?? 'normal', lengthFontSize: globalFont.lengthText.fontSize?.value ?? 16, lengthFontColor: globalFont.lengthText.fontColor?.value ?? 'black', - /** - * 치수선 설정 - */ + /** 치수선 설정 */ originPixel: dimensionLineSettings.pixel, originColor: dimensionLineSettings.color, - /** - * 도면크기 설정 - */ + /** 도면크기 설정 */ originHorizon: planSizeSettingMode.originHorizon, originVertical: planSizeSettingMode.originVertical, + /** 점/선 그리드 */ dotGridDisplay: dotLineGridSetting.DOT, lineGridDisplay: dotLineGridSetting.LINE, gridType: dotLineGridSetting.INTERVAL.type, @@ -863,6 +793,7 @@ export function useCanvasSetting() { gridRatio: dotLineGridSetting.INTERVAL.ratioInterval / 10, gridDimen: dotLineGridSetting.INTERVAL.dimension, + /** 그리드 색 설정 */ gridColor: gridColor, } @@ -875,13 +806,10 @@ export function useCanvasSetting() { .then((res) => { //swalFire({ text: getMessage(res.returnMessage) }) - /** - * Canvas 디스플레이 설정 시 해당 옵션 적용 - */ + /** Canvas 디스플레이 설정 시 해당 옵션 적용 */ frontSettings() - /** - * 저장 후 재조회 - */ + + /** 저장 후 재조회 */ fetchSettings() }) .catch((error) => { @@ -912,8 +840,8 @@ export function useCanvasSetting() { */ /** - * 옵션명 - * 옵션상태 + * 옵션명 optionName + * 옵션상태 optionSelected */ let optionName let optionSelected @@ -948,15 +876,11 @@ export function useCanvasSetting() { optionName = ['backGroundImage'] break case 'totalDisplay': - /** - * 작업할 필요 없음 - */ + /** 작업할 필요 없음 */ optionName = [] break } - /** - * 표시 선택 상태(true/false) - */ + /** 표시 선택 상태(true/false)*/ optionSelected = option1[i].selected canvasObjects diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index bf2756ec..4dc7d839 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -19,7 +19,6 @@ import ActualSizeSetting from '@/components/floor-plan/modal/roofAllocation/Actu import { useMessage } from '@/hooks/useMessage' import useMenu from '@/hooks/common/useMenu' import { useCanvasMenu } from '@/hooks/common/useCanvasMenu' -import { menuTypeState } from '@/store/menuAtom' import { useRoofFn } from '@/hooks/common/useRoofFn' import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting' import { globalLocaleStore } from '@/store/localeAtom' @@ -37,8 +36,7 @@ export function useRoofAllocationSetting(id) { const [popupId, setPopupId] = useState(uuidv4()) const { addPopup, closePopup, closeAll } = usePopup() const currentObject = useRecoilValue(currentObjectState) - const { setMenuNumber } = useCanvasMenu() - const setMenuType = useSetRecoilState(menuTypeState) + const { setSelectedMenu } = useCanvasMenu() const roofMaterials = useRecoilValue(roofMaterialsSelector) const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector) const [basicSetting, setBasicSetting] = useRecoilState(basicSettingState) @@ -387,8 +385,7 @@ export function useRoofAllocationSetting(id) { }) setEditingLines([]) closeAll() - setMenuNumber(3) - setMenuType('surface') + setSelectedMenu('surface') modifyModuleSelectionData() } diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index 6ebd1414..50f61172 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -37,7 +37,7 @@ import { roofDisplaySelector } from '@/store/settingAtom' import { useRoofFn } from '@/hooks/common/useRoofFn' import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' -// 면형상 배치 +// 배치면 그리기 export function usePlacementShapeDrawing(id) { const canvas = useRecoilValue(canvasState) const roofDisplay = useRecoilValue(roofDisplaySelector) @@ -93,6 +93,12 @@ export function usePlacementShapeDrawing(id) { useEffect(() => { setPoints([]) + + return () => { + const placementShapeDrawingStartPoint = canvas.getObjects().find((obj) => obj.name === 'placementShapeDrawingStartPoint') + + canvas.remove(placementShapeDrawingStartPoint) + } }, []) useEffect(() => { diff --git a/src/lib/authActions.js b/src/lib/authActions.js index e1bbd192..68dab9f7 100644 --- a/src/lib/authActions.js +++ b/src/lib/authActions.js @@ -58,32 +58,3 @@ export async function login() { redirect('/') } } - -export const customSetMenuNumber = async ({ objectNo, pid, menuNum, callback = () => {} }) => { - let db = null - - if (!db) { - db = await open({ - filename: 'qcast3.global.sqlite', - driver: sqlite3.Database, - }) - } - - const chkSql = `SELECT menu_num FROM current_menu WHERE object_no = ? AND pid = ?` - const prevMenuNum = await getInstance().get(chkSql, objectNo, pid) - - if (prevMenuNum) { - if (prevMenuNum > menuNum) { - callback() - } else { - const sql = `UPDATE current_menu SET menu_num = ? WHERE object_no = ? AND pid = ?` - await getInstance().run(sql, menuNum, objectNo, pid) - - setMenuNumber(menuNum) - } - } else { - const sql = `INSERT INTO current_menu (object_no, pid, menu_num) VALUES (?, ?, ?)` - await getInstance().run(sql, objectNo, pid, menuNum) - setMenuNumber(menuNum) - } -} diff --git a/src/locales/ja.json b/src/locales/ja.json index 677f9cab..ef70bb9b 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -896,7 +896,7 @@ "estimate.detail.dragFileGuide": "(※北面設置の場合、ファイル添付が必須です.)", "estimate.detail.header.fileList1": "ファイル添付", "estimate.detail.fileList.btn": "ファイル選択", - "estimate.detail.fileList.extCheck": "画像ファイルのみ添付可能です。", + "estimate.detail.fileList.extCheck": "画像、PDF、Excelファイルのみ添付可能.", "estimate.detail.header.fileList2": "添付ファイル一覧", "estimate.detail.fileList2.btn.return": "復元", "estimate.detail.header.specialEstimate": "見積もりの特定", diff --git a/src/locales/ko.json b/src/locales/ko.json index 67b4b301..d60e226d 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -897,7 +897,7 @@ "estimate.detail.dragFileGuide": "(※ 북면설치인 경우, 파일 첨부가 필수입니다.)", "estimate.detail.header.fileList1": "파일첨부", "estimate.detail.fileList.btn": "파일선택", - "estimate.detail.fileList.extCheck": "이미지 파일만 첨부 가능합니다.", + "estimate.detail.fileList.extCheck": "이미지, PDF, 엑셀 파일만 첨부 가능합니다.", "estimate.detail.header.fileList2": "첨부파일 목록", "estimate.detail.fileList2.btn.return": "복원", "estimate.detail.header.specialEstimate": "견적특이사항", diff --git a/src/store/menuAtom.js b/src/store/menuAtom.js index 759df0fd..0254cbb9 100644 --- a/src/store/menuAtom.js +++ b/src/store/menuAtom.js @@ -6,32 +6,33 @@ export const menuNumberState = atom({ default: null, }) -export const menuTypeState = atom({ - key: 'menuTypeState', +export const selectedMenuState = atom({ + key: 'selectedMenuState', default: null, }) export const menusState = atom({ key: 'menusState', default: [ - { index: 0, name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, + { type: 'drawing', name: 'plan.menu.plan.drawing', icon: 'con00', title: MENU.PLAN_DRAWING }, //. 도면 작성 { - index: 1, + type: 'placement', // 배치면 초기설정 name: 'plan.menu.placement.surface.initial.setting', icon: 'con01', title: MENU.INITIAL_CANVAS_SETTING, }, - { index: 2, name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT }, - { index: 3, name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT }, - { index: 4, name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT }, - { index: 5, name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT }, - { index: 6, name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT }, + { type: 'outline', name: 'plan.menu.roof.cover', icon: 'con02', title: MENU.ROOF_COVERING.DEFAULT }, + { type: 'surface', name: 'plan.menu.placement.surface', icon: 'con03', title: MENU.BATCH_CANVAS.DEFAULT }, + { type: 'module', name: 'plan.menu.module.circuit.setting', icon: 'con04', title: MENU.MODULE_CIRCUIT_SETTING.DEFAULT }, + { type: 'estimate', name: 'plan.menu.estimate', icon: 'con06', title: MENU.ESTIMATE.DEFAULT }, + { type: 'simulation', name: 'plan.menu.simulation', icon: 'con05', title: MENU.POWER_GENERATION_SIMULATION.DEFAULT }, ], }) export const subMenusState = atom({ key: 'subMenusState', default: { + placement: [], // 배치면 초기 설정 outline: [ // 지붕덮개 { id: 0, name: 'plan.menu.roof.cover.outline.drawing', menu: MENU.ROOF_COVERING.EXTERIOR_WALL_LINE }, diff --git a/src/styles/_modal.scss b/src/styles/_modal.scss index a19aba2e..fed29abe 100644 --- a/src/styles/_modal.scss +++ b/src/styles/_modal.scss @@ -995,6 +995,26 @@ $alert-color: #101010; } } } + &:disabled{ + color: $pop-color; + border: 1px solid #646464; + background-color: transparent; + opacity: 0.5; + &.act, + &:hover{ + color: $pop-color; + border: 1px solid #646464; + background-color: transparent; + i{ + &.allocation01{ + background-image: url(../../public/static/images/canvas/allocation_icon01_white.svg); + } + &.allocation02{ + background-image: url(../../public/static/images/canvas/allocation_icon02_white.svg); + } + } + } + } } }