From d8341385a4828212ff212744950e96a4dea6ce5e Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 21 Mar 2025 16:44:01 +0900 Subject: [PATCH 01/45] =?UTF-8?q?chore:=20=ED=99=98=EA=B2=BD=EB=B3=80?= =?UTF-8?q?=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 8 +++++++- .env.production | 8 +++++++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index cfc50e71..bd024a3b 100644 --- a/.env.development +++ b/.env.development @@ -8,4 +8,10 @@ SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" -NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" \ No newline at end of file +NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" + +AWS_REGION="ap-northeast-2" +AMPLIFY_BUCKET="interplug" +AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" +AWS_SECRET_ACCESS_KEY="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" +AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" diff --git a/.env.production b/.env.production index 09bb27d3..28c4dd86 100644 --- a/.env.production +++ b/.env.production @@ -10,4 +10,10 @@ NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secr # NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin" # NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin" NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" -NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" \ No newline at end of file +NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" + +AWS_REGION="ap-northeast-2" +AMPLIFY_BUCKET="interplug" +AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" +AWS_SECRET_ACCESS_KEY="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" +AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" \ No newline at end of file From 20cef812ae305d12b88e0b42cec36be401e5ea4b Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 21 Mar 2025 16:47:14 +0900 Subject: [PATCH 02/45] =?UTF-8?q?chore:=20=EB=B8=8C=EB=9D=BC=EC=9A=B0?= =?UTF-8?q?=EC=A0=80=EC=9A=A9=20=ED=99=98=EA=B2=BD=EB=B3=80=EC=88=98=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .env.development | 2 +- .env.production | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index bd024a3b..4f613c70 100644 --- a/.env.development +++ b/.env.development @@ -14,4 +14,4 @@ AWS_REGION="ap-northeast-2" AMPLIFY_BUCKET="interplug" AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" AWS_SECRET_ACCESS_KEY="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" -AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" +NEXT_PUBLIC_AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" diff --git a/.env.production b/.env.production index 28c4dd86..f0951f7a 100644 --- a/.env.production +++ b/.env.production @@ -16,4 +16,4 @@ AWS_REGION="ap-northeast-2" AMPLIFY_BUCKET="interplug" AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" AWS_SECRET_ACCESS_KEY="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" -AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" \ No newline at end of file +NEXT_PUBLIC_AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" \ No newline at end of file From a7b90621542218c6deb00210741e1ff56c45d880 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 24 Mar 2025 13:58:29 +0900 Subject: [PATCH 03/45] =?UTF-8?q?feat:=20s3=20=EC=97=85=EB=A1=9C=EB=93=9C?= =?UTF-8?q?=20=EA=B8=B0=EB=B3=B8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + qcast3.database.sqlite | Bin 16384 -> 16384 bytes src/app/api/image/upload/route.js | 70 ++++++++++++++++++++ src/components/floor-plan/modal/ImgLoad.jsx | 2 +- src/hooks/common/useRefFiles.js | 17 +++-- 5 files changed, 85 insertions(+), 5 deletions(-) create mode 100644 src/app/api/image/upload/route.js diff --git a/package.json b/package.json index 1f31b9d3..230e1b81 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "serve": "node server.js" }, "dependencies": { + "@aws-sdk/client-s3": "^3.772.0", "ag-grid-react": "^32.0.2", "axios": "^1.7.8", "big.js": "^6.2.2", diff --git a/qcast3.database.sqlite b/qcast3.database.sqlite index c0c43e6faa95884fffddcdf0dcf1413c2e23f368..66ac677f482169e439cd063c21efbc753f2a27c9 100644 GIT binary patch delta 122 zcmZo@U~Fh$oFL68J5k1&QFdd(e0^>{UIri#U|`^1y_w5kA%AEv9~*-xW23Bzp}7H9 zMoCFQv6a4lW?o5ZQ9({=x?ZudUSff6UVc$YMrvYliLQ}eVs2tpeqLgEv0ie1u6}7j YPJUvFer{!PVUBK2etN!MRzYey0Qtuyp8x;= delta 81 zcmZo@U~Fh$oFL68HBrWyQEFqte0^?SUIri#U|`^1xtYsgA^&85J6#RSloWGg%T!a{ jH1jlLT@#B`Bi$sUltkS`LvvGe( { + const Body = Buffer.from(await file.arrayBuffer()) + const Key = `upload/${file.name}` + const ContentType = file.ContentType + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + return { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + + const result = await uploadImage(file) + result.message = '이미지 업로드 성공' + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const Key = `upload/${searchParams.get('fileName')}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + if (!Key) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/components/floor-plan/modal/ImgLoad.jsx b/src/components/floor-plan/modal/ImgLoad.jsx index dda395a9..f0a86938 100644 --- a/src/components/floor-plan/modal/ImgLoad.jsx +++ b/src/components/floor-plan/modal/ImgLoad.jsx @@ -120,7 +120,7 @@ export default function ImgLoad() { value={refImage ? (refImage?.name ?? '') : (currentCanvasPlan?.bgImageName ?? '')} readOnly /> - {refImage && } + {currentCanvasPlan?.bgImageName && } diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index b21cc954..1642daa9 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -28,7 +28,7 @@ export function useRefFiles() { const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const { handleBackImageLoadToCanvas } = useCanvas() const { swalFire } = useSwal() - const { get, post } = useAxios() + const { get, post, del } = useAxios() useEffect(() => { if (refFileMethod === '1') { @@ -84,6 +84,9 @@ export function useRefFiles() { text: '삭제하시겠습니까?', type: 'confirm', confirmFn: async () => { + console.log('🚀 ~ handleFileDelete ~ handleFileDelete:', refImage) + console.log('🚀 ~ handleFileDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName) + await del({ url: `http://localhost:3000/api/image/upload?fileName=${currentCanvasPlan.bgImageName}` }) setRefImage(null) setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null })) await deleteBackGroundImage({ @@ -179,18 +182,24 @@ export function useRefFiles() { const formData = new FormData() formData.append('file', file) + // const res = await post({ + // url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/upload`, + // data: formData, + // }) const res = await post({ - url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/upload`, + url: `http://localhost:3000/api/image/upload`, data: formData, }) console.log('🚀 ~ handleUploadImageRefFile ~ res:', res) - setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) + // setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) + setCurrentBgImage(`${res.filePath}`) setRefImage(file) const params = { objectId: currentCanvasPlan.id, planNo: currentCanvasPlan.planNo, - imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`, + // imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`, + imagePath: `${res.filePath}`, } console.log('🚀 ~ handleUploadImageRefFile ~ params:', params) await setBackGroundImage(params) From 2492b45a66159ad7392ff04a86c91ae9c5dcc5b9 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 24 Mar 2025 17:08:31 +0900 Subject: [PATCH 04/45] =?UTF-8?q?feat:=20=EA=B5=AC=EA=B8=80=20=EB=A7=B5=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=84=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/image/map/route.js | 68 +++++++++++++++++++++++++++++++++ src/hooks/common/useRefFiles.js | 14 +++++-- 2 files changed, 79 insertions(+), 3 deletions(-) create mode 100644 src/app/api/image/map/route.js diff --git a/src/app/api/image/map/route.js b/src/app/api/image/map/route.js new file mode 100644 index 00000000..3bcfb35a --- /dev/null +++ b/src/app/api/image/map/route.js @@ -0,0 +1,68 @@ +import { NextResponse } from 'next/server' + +export async function GET(req) { + try { + const searchParams = req.nextUrl.searchParams + const q = searchParams.get('q') + const fileNm = searchParams.get('fileNm') + const zoom = searchParams.get('zoom') + + /** 구글 맵을 이미지로 변경하기 위한 API */ + const API_KEY = 'AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc' + const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=${zoom}&maptype=satellite&size=640x640&scale=1&key=${API_KEY}` + const decodeUrl = decodeURIComponent(targetUrl) + + /** 구글 맵을 이미지로 변경하기 위한 API 호출 */ + const response = await fetch(decodeUrl) + const data = await response.arrayBuffer() + // const buffer = Buffer.from(data) + + /** 변경된 이미지를 S3에 업로드 */ + const Body = Buffer.from(data) + const Key = `map/${file.name}` + const ContentType = 'image/png' + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + const result = { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const Key = `map/${searchParams.get('fileName')}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + if (!Key) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index 1642daa9..254c4b12 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -105,6 +105,9 @@ export function useRefFiles() { text: '삭제하시겠습니까?', type: 'confirm', confirmFn: async () => { + console.log('🚀 ~ handleAddressDelete ~ handleAddressDelete:', refImage) + console.log('🚀 ~ handleAddressDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName) + await del({ url: `http://localhost:3000/api/image/map?fileName=${currentCanvasPlan.bgImageName}` }) setMapPositionAddress('') setCurrentBgImage(null) setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null })) @@ -135,16 +138,21 @@ export function useRefFiles() { option1: newOption1, })) + // const res = await get({ + // url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, + // }) const res = await get({ - url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, + url: `http://localhost:3000/api/map/upload?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, }) console.log('🚀 ~ handleMapImageDown ~ res:', res) - setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) + // setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) + setCurrentBgImage(`${res.filePath}`) await setBackGroundImage({ objectId: currentCanvasPlan.id, planNo: currentCanvasPlan.planNo, - imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`, + // imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`, + imagePath: `${res.filePath}`, }) } From 9a9fa522f9e158d06c18a5bee97c3e749d4f0afe Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 24 Mar 2025 17:54:32 +0900 Subject: [PATCH 05/45] =?UTF-8?q?feat:=20=EA=B5=AC=EA=B8=80=20=EB=A7=B5=20?= =?UTF-8?q?=EC=BB=A8=EB=B2=84=ED=8A=B8=20=EA=B8=B0=EB=8A=A5=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qcast3.database.sqlite | Bin 16384 -> 16384 bytes src/app/api/image/map/route.js | 14 ++++++++++++-- src/hooks/common/useRefFiles.js | 29 +++++++++++++++++++---------- 3 files changed, 31 insertions(+), 12 deletions(-) diff --git a/qcast3.database.sqlite b/qcast3.database.sqlite index 66ac677f482169e439cd063c21efbc753f2a27c9..e6022fd79a14effb51bb9a253191dd42b5f6ec9e 100644 GIT binary patch delta 59 zcmZo@U~Fh$oFL7pHc`fzQEg+we0^?VUIqpRM*bZP{5v*t8LZ>ya1&-@5M^v+p1j%K PoHIAEpjh9;(A)q3y!Q^F delta 63 zcmZo@U~Fh$oFL68J5k1&QFdd(e0^>{UIri#U|`^1y_w5k9slH`_C{i*1v&YNDf+pU R#f3S#Ir-`NdRYaj=>Q$c63zes diff --git a/src/app/api/image/map/route.js b/src/app/api/image/map/route.js index 3bcfb35a..0cc76c02 100644 --- a/src/app/api/image/map/route.js +++ b/src/app/api/image/map/route.js @@ -1,4 +1,14 @@ import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3' + +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) export async function GET(req) { try { @@ -19,7 +29,7 @@ export async function GET(req) { /** 변경된 이미지를 S3에 업로드 */ const Body = Buffer.from(data) - const Key = `map/${file.name}` + const Key = `maps/${fileNm}` const ContentType = 'image/png' await s3.send( @@ -46,7 +56,7 @@ export async function GET(req) { export async function DELETE(req) { try { const searchParams = req.nextUrl.searchParams - const Key = `map/${searchParams.get('fileName')}` + const Key = `maps/${searchParams.get('fileName')}` console.log('🚀 ~ DELETE ~ Key:', Key) if (!Key) { diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index 254c4b12..3e726364 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -142,7 +142,7 @@ export function useRefFiles() { // url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, // }) const res = await get({ - url: `http://localhost:3000/api/map/upload?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, + url: `http://localhost:3000/api/image/map?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`, }) console.log('🚀 ~ handleMapImageDown ~ res:', res) // setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) @@ -160,16 +160,25 @@ export function useRefFiles() { * 배경 이미지 로드를 위한 세팅 */ useEffect(() => { - if (!currentBgImage) { - return - } + // if (!currentBgImage) { + // return + // } console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage) - handleBackImageLoadToCanvas(currentBgImage) - setCurrentCanvasPlan((prev) => ({ - ...prev, - bgImageName: refImage?.name ?? null, - mapPositionAddress: queryRef.current.value, - })) + if (currentBgImage) { + handleBackImageLoadToCanvas(currentBgImage) + setCurrentCanvasPlan((prev) => ({ + ...prev, + // bgImageName: refImage?.name ?? null, + bgImageName: currentBgImage.split('/').pop(), + mapPositionAddress: queryRef.current.value, + })) + } else { + setCurrentCanvasPlan((prev) => ({ + ...prev, + bgImageName: null, + mapPositionAddress: null, + })) + } }, [currentBgImage]) /** From 11edbe19883e7034f58673dabc38def0179fd1a2 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 24 Mar 2025 19:01:09 +0900 Subject: [PATCH 06/45] =?UTF-8?q?feat:=20cad=ED=8C=8C=EC=9D=BC=20=EC=BB=A8?= =?UTF-8?q?=EB=B2=84=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/image/cad/route.js | 70 +++++++++++++++++++++++++++++++++ src/hooks/common/useRefFiles.js | 37 ++++++++++++++--- 2 files changed, 101 insertions(+), 6 deletions(-) create mode 100644 src/app/api/image/cad/route.js diff --git a/src/app/api/image/cad/route.js b/src/app/api/image/cad/route.js new file mode 100644 index 00000000..510feff2 --- /dev/null +++ b/src/app/api/image/cad/route.js @@ -0,0 +1,70 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3' + +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +const uploadImage = async (file) => { + const Body = Buffer.from(await file.arrayBuffer()) + const Key = `cads/${file.name}` + const ContentType = file.ContentType + + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body, + ContentType, + }), + ) + + return { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + + const result = await uploadImage(file) + result.message = '이미지 업로드 성공' + + return NextResponse.json(result) + } catch (error) { + console.error(error) + return NextResponse.json({ error: 'Failed to upload image' }, { status: 500 }) + } +} + +export async function DELETE(req) { + try { + const searchParams = req.nextUrl.searchParams + const Key = `cads/${searchParams.get('fileName')}` + console.log('🚀 ~ DELETE ~ Key:', Key) + + if (!Key) { + return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) + } + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key, + }), + ) + + return NextResponse.json({ message: '이미지 삭제 성공' }, { status: 200 }) + } catch (error) { + console.error('S3 Delete Error:', error) + return NextResponse.json({ error: 'Failed to delete image' }, { status: 500 }) + } +} diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index 3e726364..097d42ae 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -87,8 +87,9 @@ export function useRefFiles() { console.log('🚀 ~ handleFileDelete ~ handleFileDelete:', refImage) console.log('🚀 ~ handleFileDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName) await del({ url: `http://localhost:3000/api/image/upload?fileName=${currentCanvasPlan.bgImageName}` }) - setRefImage(null) - setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null })) + // setRefImage(null) + setCurrentBgImage(null) + // setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null })) await deleteBackGroundImage({ objectId: currentCanvasPlan.id, planNo: currentCanvasPlan.planNo, @@ -110,7 +111,7 @@ export function useRefFiles() { await del({ url: `http://localhost:3000/api/image/map?fileName=${currentCanvasPlan.bgImageName}` }) setMapPositionAddress('') setCurrentBgImage(null) - setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null })) + // setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null })) await deleteBackGroundImage({ objectId: currentCanvasPlan.id, planNo: currentCanvasPlan.planNo, @@ -173,6 +174,7 @@ export function useRefFiles() { mapPositionAddress: queryRef.current.value, })) } else { + setRefImage(null) setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null, @@ -230,15 +232,38 @@ export function useRefFiles() { const formData = new FormData() formData.append('file', file) + /** 캐드 도면 파일 변환 */ const res = await post({ url: converterUrl, data: formData }) console.log('🚀 ~ handleUploadConvertRefFile ~ res:', res) + + /** 캐드 도면 파일 업로드 */ const result = await post({ - url: `${process.env.NEXT_PUBLIC_HOST_URL}/cad/convert`, + url: `http://localhost:3000/api/image/cad`, data: res, }) console.log('🚀 ~ handleUploadConvertRefFile ~ result:', result) - setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${result.filePath}`) - setRefImage(res.Files[0].FileData) + + setCurrentBgImage(`${result.filePath}`) + setRefImage(file) + + const params = { + objectId: currentCanvasPlan.id, + planNo: currentCanvasPlan.planNo, + // imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`, + imagePath: `${result.filePath}`, + } + console.log('🚀 ~ handleUploadImageRefFile ~ params:', params) + await setBackGroundImage(params) + + // const res = await post({ url: converterUrl, data: formData }) + // console.log('🚀 ~ handleUploadConvertRefFile ~ res:', res) + // const result = await post({ + // url: `${process.env.NEXT_PUBLIC_HOST_URL}/cad/convert`, + // data: res, + // }) + // console.log('🚀 ~ handleUploadConvertRefFile ~ result:', result) + // setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${result.filePath}`) + // setRefImage(res.Files[0].FileData) } /** From 97389f714162a0872e8a7a9d9d3ed3a5d9735f20 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 25 Mar 2025 11:01:40 +0900 Subject: [PATCH 07/45] =?UTF-8?q?feat:=20=EC=BA=94=EB=B2=84=EC=8A=A4=20?= =?UTF-8?q?=EC=9D=B4=EB=AF=B8=EC=A7=80=20S3=EB=A1=9C=20=EC=A0=80=EC=9E=A5?= =?UTF-8?q?=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/api/image/canvas/route.js | 120 ++++++++++++++++++++++++++++ src/app/api/image/upload/route.js | 8 +- src/hooks/floorPlan/useImgLoader.js | 3 +- 3 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/app/api/image/canvas/route.js diff --git a/src/app/api/image/canvas/route.js b/src/app/api/image/canvas/route.js new file mode 100644 index 00000000..f2e6df86 --- /dev/null +++ b/src/app/api/image/canvas/route.js @@ -0,0 +1,120 @@ +import { NextResponse } from 'next/server' +import { S3Client, PutObjectCommand, DeleteObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3' +import sharp from 'sharp' +import { v4 as uuidv4 } from 'uuid' +const Bucket = process.env.AMPLIFY_BUCKET +const s3 = new S3Client({ + region: process.env.AWS_REGION, + credentials: { + accessKeyId: process.env.AWS_ACCESS_KEY_ID, + secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY, + }, +}) + +const checkArea = (obj) => { + const { width, height, left, top } = obj + + if (left < 0 || top < 0 || width > 1600 || height > 1000) { + return false + } + + return true +} + +const cropImage = async (Key, width, height, left, top) => { + try { + const checkResult = checkArea({ width, height, left, top }) + + // Get the image from S3 + const { Body } = await s3.send( + new GetObjectCommand({ + Bucket, + Key, + }), + ) + + // Convert stream to buffer + const chunks = [] + for await (const chunk of Body) { + chunks.push(chunk) + } + const imageBuffer = Buffer.concat(chunks) + + let processedImage + if (!checkResult) { + processedImage = await sharp(imageBuffer).toBuffer() + } else { + processedImage = await sharp(imageBuffer) + .extract({ + width: parseInt(width), + height: parseInt(height), + left: parseInt(left), + top: parseInt(top), + }) + .png() + .toBuffer() + } + return processedImage + } catch (error) { + console.error('Error processing image:', error) + throw error + } +} + +export async function POST(req) { + try { + const formData = await req.formData() + const file = formData.get('file') + const objectNo = formData.get('objectNo') + const planNo = formData.get('planNo') + const type = formData.get('type') + const width = formData.get('width') + const height = formData.get('height') + const left = formData.get('left') + const top = formData.get('top') + + const OriginalKey = `Drawing/${uuidv4()}` + + // Upload original image + await s3.send( + new PutObjectCommand({ + Bucket, + Key: OriginalKey, + Body: Buffer.from(await file.arrayBuffer()), + ContentType: 'image/png', + }), + ) + + // Process the image + const bufferImage = await cropImage(OriginalKey, width, height, left, top) + + const Key = `Drawing/${objectNo}_${planNo}_${type}` + + // Upload processed image + await s3.send( + new PutObjectCommand({ + Bucket, + Key, + Body: bufferImage, + ContentType: 'image/png', + }), + ) + + await s3.send( + new DeleteObjectCommand({ + Bucket, + Key: OriginalKey, + }), + ) + + const result = { + filePath: `https://${process.env.AMPLIFY_BUCKET}.s3.${process.env.AWS_REGION}.amazonaws.com/${Key}`, + fileName: Key, + } + + return NextResponse.json(result) + } catch (error) { + console.error('Error in POST:', error) + return NextResponse.json({ error: 'Failed to process and upload image' }, { status: 500 }) + } +} diff --git a/src/app/api/image/upload/route.js b/src/app/api/image/upload/route.js index 99daa259..4d875257 100644 --- a/src/app/api/image/upload/route.js +++ b/src/app/api/image/upload/route.js @@ -48,13 +48,15 @@ export async function POST(req) { export async function DELETE(req) { try { const searchParams = req.nextUrl.searchParams - const Key = `upload/${searchParams.get('fileName')}` - console.log('🚀 ~ DELETE ~ Key:', Key) + const fileName = searchParams.get('fileName') - if (!Key) { + if (!fileName) { return NextResponse.json({ error: 'fileName parameter is required' }, { status: 400 }) } + const Key = `upload/${fileName}` + console.log('🚀 ~ DELETE ~ Key:', Key) + await s3.send( new DeleteObjectCommand({ Bucket, diff --git a/src/hooks/floorPlan/useImgLoader.js b/src/hooks/floorPlan/useImgLoader.js index e51a4a2b..2a5a09ab 100644 --- a/src/hooks/floorPlan/useImgLoader.js +++ b/src/hooks/floorPlan/useImgLoader.js @@ -79,7 +79,8 @@ export function useImgLoader() { /** 이미지 크롭 요청 */ const result = await post({ - url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/canvas`, + // url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/canvas`, + url: `http://localhost:3000/api/image/canvas`, data: formData, }) console.log('🚀 ~ handleCanvasToPng ~ result:', result) From 553a259c1fc4f09e14bc4ab0569898f225d91b32 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 25 Mar 2025 11:02:08 +0900 Subject: [PATCH 08/45] =?UTF-8?q?chore:=20=EB=8F=84=EB=A9=B4=20=EC=9D=B4?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=20=ED=81=AC=EB=A1=AD=EC=9D=84=20=EC=9C=84?= =?UTF-8?q?=ED=95=9C=20sharp=20lib=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index 230e1b81..4c3b230b 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ "react-responsive-modal": "^6.4.2", "react-select": "^5.8.1", "recoil": "^0.7.7", + "sharp": "^0.33.5", "sqlite": "^5.1.1", "sqlite3": "^5.1.7", "sweetalert2": "^11.14.1", From 8d645d08dca2ba91b6aa71dcc542804acfdc84ff Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 25 Mar 2025 13:33:36 +0900 Subject: [PATCH 09/45] =?UTF-8?q?refactor:=20API=20Router=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9D=BC=EB=B6=80=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 패턴에 어긋나는 응답 포맷 수정 - 주석 작성 --- src/app/api/image/cad/route.js | 1 - src/app/api/image/canvas/route.js | 19 ++++++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/app/api/image/cad/route.js b/src/app/api/image/cad/route.js index 510feff2..b7d64a50 100644 --- a/src/app/api/image/cad/route.js +++ b/src/app/api/image/cad/route.js @@ -36,7 +36,6 @@ export async function POST(req) { const file = formData.get('file') const result = await uploadImage(file) - result.message = '이미지 업로드 성공' return NextResponse.json(result) } catch (error) { diff --git a/src/app/api/image/canvas/route.js b/src/app/api/image/canvas/route.js index f2e6df86..6a15e9bf 100644 --- a/src/app/api/image/canvas/route.js +++ b/src/app/api/image/canvas/route.js @@ -75,7 +75,10 @@ export async function POST(req) { const OriginalKey = `Drawing/${uuidv4()}` - // Upload original image + /** + * 원본 이미지를 우선 저장한다. + * 이미지 이름이 겹지는 현상을 방지하기 위해 uuid 를 사용한다. + */ await s3.send( new PutObjectCommand({ Bucket, @@ -85,12 +88,19 @@ export async function POST(req) { }), ) - // Process the image + /** + * 저장된 원본 이미지를 기준으로 크롭여부를 결정하여 크롭 이미지를 저장한다. + */ const bufferImage = await cropImage(OriginalKey, width, height, left, top) + /** + * 크롭 이미지 이름을 결정한다. + */ const Key = `Drawing/${objectNo}_${planNo}_${type}` - // Upload processed image + /** + * 크롭이 완료된 이미지를 업로드한다. + */ await s3.send( new PutObjectCommand({ Bucket, @@ -100,6 +110,9 @@ export async function POST(req) { }), ) + /** + * 크롭이미지 저장이 완료되면 원본 이미지를 삭제한다. + */ await s3.send( new DeleteObjectCommand({ Bucket, From c7de33b8b9021a794c1d7129e2931d7c76dc72cc Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Tue, 25 Mar 2025 14:20:28 +0900 Subject: [PATCH 10/45] =?UTF-8?q?fix:=20popup=20spinner=20=EB=8F=99?= =?UTF-8?q?=EC=9E=91=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- qcast3.database.sqlite | Bin 16384 -> 16384 bytes src/hooks/common/useRefFiles.js | 8 +++++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/qcast3.database.sqlite b/qcast3.database.sqlite index e6022fd79a14effb51bb9a253191dd42b5f6ec9e..166f2da26bfaf6d977a400c5ef8dd5a21ef49896 100644 GIT binary patch delta 82 zcmZo@U~Fh$oFL7pHBrWyQEOwue0^R~UIqpRM*bZP{5$wlHuD%n@bd(TvN4EqHp-fq mm|0FfYHuV~T9A{Un4+IsSzMT-o0FfOua{Mjnm&1ly$1kpWEZml delta 102 zcmZo@U~Fh$oFL7pHc`fzQEg+we0^SFUIqpRM*bZP{5yC(HuD%n@K27nlQmB^w=_vL zH8IjnPDx79HAyoz)lEt>veZpUGdD6yGBZd_O197|$O{YQ4d!EG5M^wXH8C_d;F`R{ G-U9$hz8XaU diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index 097d42ae..3be7fff2 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -1,5 +1,5 @@ import { useEffect, useRef, useState } from 'react' -import { useRecoilState } from 'recoil' +import { useRecoilState, useSetRecoilState } from 'recoil' import { useSwal } from '@/hooks/useSwal' import { useAxios } from '../useAxios' @@ -7,6 +7,7 @@ import { currentCanvasPlanState } from '@/store/canvasAtom' import { useCanvas } from '@/hooks/useCanvas' import { deleteBackGroundImage, setBackGroundImage } from '@/lib/imageActions' import { settingModalFirstOptionsState } from '@/store/settingAtom' +import { popSpinnerState } from '@/store/popupAtom' /** * 배경 이미지 관리 @@ -29,6 +30,7 @@ export function useRefFiles() { const { handleBackImageLoadToCanvas } = useCanvas() const { swalFire } = useSwal() const { get, post, del } = useAxios() + const setPopSpinnerStore = useSetRecoilState(popSpinnerState) useEffect(() => { if (refFileMethod === '1') { @@ -84,6 +86,7 @@ export function useRefFiles() { text: '삭제하시겠습니까?', type: 'confirm', confirmFn: async () => { + setPopSpinnerStore(true) console.log('🚀 ~ handleFileDelete ~ handleFileDelete:', refImage) console.log('🚀 ~ handleFileDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName) await del({ url: `http://localhost:3000/api/image/upload?fileName=${currentCanvasPlan.bgImageName}` }) @@ -94,6 +97,7 @@ export function useRefFiles() { objectId: currentCanvasPlan.id, planNo: currentCanvasPlan.planNo, }) + setPopSpinnerStore(false) }, }) } @@ -188,6 +192,7 @@ export function useRefFiles() { * @param {*} file */ const handleUploadImageRefFile = async (file) => { + setPopSpinnerStore(true) const newOption1 = settingModalFirstOptions.option1.map((option) => ({ ...option, selected: option.column === 'imageDisplay' ? true : option.selected, @@ -222,6 +227,7 @@ export function useRefFiles() { } console.log('🚀 ~ handleUploadImageRefFile ~ params:', params) await setBackGroundImage(params) + setPopSpinnerStore(false) } /** From c6b96bec23a054ed5dcff169a5c14719f54d7ccc Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 23 Apr 2025 10:03:25 +0900 Subject: [PATCH 11/45] chore: update environment variables to use protocol-relative URLs for host --- .env.development | 2 +- .env.production | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index 4f613c70..ceac1712 100644 --- a/.env.development +++ b/.env.development @@ -1,6 +1,6 @@ NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" -NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" +NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" diff --git a/.env.production b/.env.production index f0951f7a..767c3e4b 100644 --- a/.env.production +++ b/.env.production @@ -1,6 +1,6 @@ NEXT_PUBLIC_API_SERVER_PATH="https://api.hanasys.jp/" -NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000" +NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" From 8de8416160b822ae4b142dab68e2cb3b2a380158 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 23 Apr 2025 10:10:57 +0900 Subject: [PATCH 12/45] =?UTF-8?q?managementStateLoaded=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../modal/circuitTrestle/CircuitTrestleSetting.jsx | 3 --- .../step/type/PassivityCircuitAllocation.jsx | 4 +--- src/hooks/useEstimate.js | 14 ++++++++------ 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index a836044e..501302e3 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -83,9 +83,6 @@ export default function CircuitTrestleSetting({ id }) { } = useCircuitTrestle() // const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2) useEffect(() => { - if (!managementState) { - setManagementState(managementStateLoaded) - } // setCircuitData({ // makers, // selectedMaker, 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 e009a864..3c53b94f 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/type/PassivityCircuitAllocation.jsx @@ -37,9 +37,7 @@ export default function PassivityCircuitAllocation(props) { const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText')) useEffect(() => { setModuleStatisticsData() - if (!managementState) { - setManagementState(managementStateLoaded) - } + canvas .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE) diff --git a/src/hooks/useEstimate.js b/src/hooks/useEstimate.js index fae0b558..3536fda9 100644 --- a/src/hooks/useEstimate.js +++ b/src/hooks/useEstimate.js @@ -13,7 +13,7 @@ import { useTrestle } from '@/hooks/module/useTrestle' import { usePlan } from '@/hooks/usePlan' export function useEstimate() { - const { managementStateLoaded } = useContext(GlobalDataContext) + const { managementState } = useContext(GlobalDataContext) const { setIsGlobalLoading } = useContext(QcastContext) const router = useRouter() const loginUserState = useRecoilValue(loginUserStore) @@ -31,16 +31,18 @@ export function useEstimate() { * @param {Object} estimateParam - 견적서 저장 데이터 */ const saveEstimate = async (estimateParam) => { + console.log('managementState', managementState) + const userId = loginUserState.userId - const saleStoreId = managementStateLoaded.saleStoreId + const saleStoreId = managementState.saleStoreId const objectNo = currentCanvasPlan.objectNo const planNo = currentCanvasPlan.planNo const slope = estimateParam.roofSurfaceList[0].slope const angle = estimateParam.roofSurfaceList[0].angle - const surfaceType = managementStateLoaded.surfaceType - const setupHeight = managementStateLoaded.installHeight - const standardWindSpeedId = managementStateLoaded.standardWindSpeedId - const snowfall = managementStateLoaded.verticalSnowCover + const surfaceType = managementState.surfaceType + const setupHeight = managementState.installHeight + const standardWindSpeedId = managementState.standardWindSpeedId + const snowfall = managementState.verticalSnowCover const drawingFlg = '1' const saveEstimateData = { From fe957102d964e0ddaa47ba20d63a19f53834a8dd Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 28 Apr 2025 13:20:35 +0900 Subject: [PATCH 13/45] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=84=A4=EC=B9=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/basic/BasicSetting.jsx | 5 +- src/hooks/common/useMasterController.js | 2 +- src/hooks/module/useModuleBasicSetting.js | 450 +++++++++++++++--- src/locales/ja.json | 3 +- src/locales/ko.json | 3 +- 5 files changed, 397 insertions(+), 66 deletions(-) diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 9a09aa1e..a930c148 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -334,9 +334,12 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { - + )} diff --git a/src/hooks/common/useMasterController.js b/src/hooks/common/useMasterController.js index 60aab800..21220726 100644 --- a/src/hooks/common/useMasterController.js +++ b/src/hooks/common/useMasterController.js @@ -18,7 +18,7 @@ export function useMasterController() { */ const getRoofMaterialList = async () => { return await get({ url: '/api/v1/master/getRoofMaterialList' }).then((res) => { - console.log('🚀🚀 ~ getRoofMaterialList ~ res:', res) + // console.log('🚀🚀 ~ getRoofMaterialList ~ res:', res) return res }) } diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 1871e34a..86279910 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -95,7 +95,7 @@ export function useModuleBasicSetting(tabNum) { setTrestleDetailList(roofConstructionArray) //북면 설치 가능 판매점 - if (moduleSelectionData.common.saleStoreNorthFlg === '1') { + if (moduleSelectionData.common.saleStoreNorthFlg == '1') { setSaleStoreNorthFlg(true) } } @@ -111,6 +111,10 @@ export function useModuleBasicSetting(tabNum) { } } + useEffect(() => { + console.log('saleStoreNorthFlg', saleStoreNorthFlg) + }, [saleStoreNorthFlg]) + //가대 상세 데이터 들어오면 실행 useEffect(() => { if (trestleDetailList.length > 0) { @@ -236,8 +240,26 @@ export function useModuleBasicSetting(tabNum) { } }) + let isNorth = false + const isExistSurface = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.parentId === roof.id) + if (isExistSurface) { + if (canvasSetting.roofSizeSet != '3') { + //북면이 있지만 + if (roof.directionText && roof.directionText.indexOf('北') > -1) { + //북쪽일때 해당 서북서, 동북동은 제외한다고 한다 + if (!(roof.directionText.indexOf('西北西') > -1 || roof.directionText.indexOf('東北東') > -1)) { + isNorth = true + } + } + + isExistSurface.set({ + isNorth: isNorth, //북면여부 + isSaleStoreNorthFlg: moduleSelectionData.common.saleStoreNorthFlg == '1' ? true : false, //북면설치가능점 여부 + }) + } + addTargetMouseEventListener('mousedown', isExistSurface, function () { toggleSelection(isExistSurface) }) @@ -270,7 +292,6 @@ export function useModuleBasicSetting(tabNum) { //모듈설치영역?? 생성 const surfaceId = uuidv4() - let isNorth = false if (canvasSetting.roofSizeSet != '3') { //북면이 있지만 @@ -307,6 +328,7 @@ export function useModuleBasicSetting(tabNum) { trestleDetail: trestleDetail, isNorth: isNorth, perPixelTargetFind: true, + isSaleStoreNorthFlg: moduleSelectionData.common.saleStoreNorthFlg == '1' ? true : false, //북면설치가능점 여부 // angle: -compasDeg, }) @@ -352,8 +374,11 @@ export function useModuleBasicSetting(tabNum) { const isExist = selectedModuleInstSurfaceArray.some((obj) => obj.parentId === setupSurface.parentId) //최초 선택일때 if (!isExist) { - //설치면이 북면이고 북면설치 허용점이 아니면 - if (setupSurface.isNorth && !saleStoreNorthFlg) { + //모듈에 북면 설치 가능 모듈이 있는지 확인함 + const isNorthModuleYn = moduleSelectionData?.module.itemList.some((module) => module.northModuleYn === 'Y') + + //설치면이 북면이고 북면설치 허용점이 아니면 북면 모듈이 한개도 없으면 + if (setupSurface.isNorth && !setupSurface.isSaleStoreNorthFlg && !isNorthModuleYn) { swalFire({ text: getMessage('module.not.batch.north'), icon: 'warning' }) return } @@ -538,9 +563,15 @@ export function useModuleBasicSetting(tabNum) { parentId: moduleSetupSurfaces[i].parentId, }) + const northModuleYn = checkedModule.some((module) => module.northModuleYn === 'Y') //북면이고 북면설치상점이 아니면 그냥 return - if (trestlePolygon.isNorth && !saleStoreNorthFlg) { - return + if (trestlePolygon.isNorth && !trestlePolygon.isSaleStoreNorthFlg) { + if (!northModuleYn) { + //북면이고 설치 가능 상점이 아닌데 북면 설치 모듈이 있으면 + return + } else { + canvas?.add(tempModule) //움직여가면서 추가됨 + } } else { canvas?.add(tempModule) //움직여가면서 추가됨 } @@ -765,7 +796,7 @@ export function useModuleBasicSetting(tabNum) { const mixAsgYn = trestlePolygon.modules[0].moduleInfo.mixAsgYn //현재 체크된 모듈기준으로 혼합가능인지 확인 Y === Y, N === N 일때만 설치 가능 if (checkedModule[0].mixAsgYn !== mixAsgYn) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) return } } @@ -798,7 +829,7 @@ export function useModuleBasicSetting(tabNum) { const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 //겹치면 안됨 if (intersection) { - swalFire({ text: getMessage('module.place.overobject') }) + swalFire({ text: getMessage('module.place.overobject'), icon: 'warning' }) isIntersection = false } }) @@ -876,7 +907,7 @@ export function useModuleBasicSetting(tabNum) { } if (checkedModule.length === 0) { - swalFire({ text: getMessage('module.place.select.module') }) + swalFire({ text: getMessage('module.place.select.module'), icon: 'warning' }) setIsManualModuleLayoutSetup(false) setManualSetupMode(`manualLayoutSetup_false`) return @@ -890,7 +921,7 @@ export function useModuleBasicSetting(tabNum) { ) if (hasZeroLength) { - swalFire({ text: getMessage('module.layout.setup.has.zero.value') }) + swalFire({ text: getMessage('module.layout.setup.has.zero.value'), icon: 'warning' }) setIsManualModuleLayoutSetup(false) setManualSetupMode(`manualLayoutSetup_false`) return @@ -902,7 +933,7 @@ export function useModuleBasicSetting(tabNum) { //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 if (mixAsgY.length > 0 && mixAsgN.length > 0) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) return } @@ -1068,9 +1099,15 @@ export function useModuleBasicSetting(tabNum) { parentId: moduleSetupSurfaces[i].parentId, }) + const northModuleYn = checkedModule.some((module) => module.northModuleYn === 'Y') //북면이고 북면설치상점이 아니면 그냥 return - if (trestlePolygon.isNorth && !saleStoreNorthFlg) { - return + if (trestlePolygon.isNorth && !trestlePolygon.isSaleStoreNorthFlg) { + if (!northModuleYn) { + //북면이고 설치 가능 상점이 아닌데 북면 설치 모듈이 있으면 + return + } else { + canvas?.add(tempModule) //움직여가면서 추가됨 + } } else { canvas?.add(tempModule) //움직여가면서 추가됨 } @@ -1732,23 +1769,51 @@ export function useModuleBasicSetting(tabNum) { } //자동 모듈 설치(그리드 방식) - const autoModuleSetup = (placementRef) => { + const autoModuleSetup = (type, layoutSetupRef) => { initEvent() //마우스 이벤트 초기화 + //실패한 지붕재 배열 + let failAutoSetupRoof = [] + + let checkedLayoutData + + /** + * 자동 레이아웃일때 0이 있거나 혼합이 있는지 확인하는 로직 + */ + if (type === 'layout') { + checkedLayoutData = layoutSetupRef.filter((module) => module.checked) + const hasZeroLength = checkedLayoutData.some((module) => module.row === 0 || module.col === 0) + + if (hasZeroLength) { + swalFire({ text: getMessage('module.layout.setup.has.zero.value'), icon: 'warning' }) + return + } + + //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 + const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') + const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') + + //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 + if (mixAsgY.length > 0 && mixAsgN.length > 0) { + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) + return + } + } + if (checkedModule.length === 0) { - swalFire({ text: getMessage('module.place.select.module') }) + swalFire({ text: getMessage('module.place.select.module'), icon: 'warning' }) return } - //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 - const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') - const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') + // //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 + // const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') + // const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') - //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 - if (mixAsgY.length > 0 && mixAsgN.length > 0) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) - return - } + // //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 + // if (mixAsgY.length > 0 && mixAsgN.length > 0) { + // swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + // return + // } const isChidori = moduleSetupOption.isChidori const setupLocation = moduleSetupOption.setupLocation @@ -1820,14 +1885,50 @@ export function useModuleBasicSetting(tabNum) { return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) } + /** + * 자동 레이아웃 설치 일시 row col 초과 여부 확인 + * @param {*} trestleDetailData + * @returns + */ + const checkAutoLayoutModuleSetup = (moduleSetupSurface, trestleDetailData) => { + const isMultipleModules = checkedModule.length > 1 //모듈이 여러개면 + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = isMultipleModules + ? trestleDetailData.moduleMaxRows + : trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + //단수 합단수 + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => item.checked).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + + // + const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) + + if (sumRowCount > maxRow || sumColCount) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && layoutSetupRef.find((item, index) => item.checked && item.row > trestleDetailData.module[index].mixModuleMaxRows) + + if (isPassedObject) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + return true + } + //흐름 방향이 남쪽(아래) const downFlowSetupModule = ( - surfaceMaxLines, + surfaceMaxLines, //deprecated maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, - isCenter = false, + isCenter = false, //deprecated intvHor, intvVer, ) => { @@ -1840,8 +1941,35 @@ export function useModuleBasicSetting(tabNum) { let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트 let isChidoriLine = false let flowLines + let installedModuleMixYn + const isNorthSurface = moduleSetupSurface.isNorth + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 + + let layoutRow = 0 + let layoutCol = 0 + + if (type === 'layout') { + const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) + if (!isPassed) { + return + } + } + + for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { + const module = checkedModule[moduleIndex] + + if (type === 'layout' && checkedLayoutData) { + const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) + layoutRow = layout.row + layoutCol = layout.col + } + //혼합여부에 따라 설치 여부 결정 + if (installedModuleMixYn && installedModuleMixYn !== module.mixAsgYn) { + continue + } + //북면일때 + const isNorthModuleYn = module.northModuleYn === 'Y' - checkedModule.forEach((module, moduleIndex) => { const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0] //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임 // let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows @@ -1857,18 +1985,38 @@ export function useModuleBasicSetting(tabNum) { } } + if (moduleSetupSurface.isSaleStoreNorthFlg) { + //북면일때 + if (isIncludeNorthModule) { + if (!isNorthModuleYn && isNorthSurface) { + continue + } //흐름 방향이 북쪽(위) + } + } else { + if (isNorthSurface) { + if (!isNorthModuleYn) { + continue + } + } + } + //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] let calcAreaWidth = Math.abs(flowLines.right.x1 - flowLines.left.x1) //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직 let calcModuleWidthCount = calcAreaWidth / (width + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 - let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 - let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 - let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1 let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1) + if (type === 'layout') { + calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol + calcModuleHeightCount = layoutRow + } + + let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 + let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 + let calcStartPoint = flowLines.right.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬 let startPointX = flowLines.left.x1 + calcStartPoint //시작점을 만든다 @@ -1882,7 +2030,7 @@ export function useModuleBasicSetting(tabNum) { let chidoriLength = 0 //첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산 - if (moduleIndex > 0) { + if (installedModuleHeightCount > 0) { // moduleMaxRows = totalModuleMaxRows - installedModuleHeightCount //두번째 모듈일때 isChidoriLine = installedModuleHeightCount % 2 != 0 ? true : false //첫번째에서 짝수에서 끝났으면 홀수는 치도리가 아님 짝수는 치도리 } @@ -1892,12 +2040,12 @@ export function useModuleBasicSetting(tabNum) { let moduleY = flowLines.bottom.y1 - height * i - 1 //살짝 여유를 준다 //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산 - if (moduleIndex > 0) { - moduleY = installedLastHeightCoord - intvVer + if (installedModuleHeightCount > 0) { + moduleY = installedLastHeightCoord } //첫번째는 붙여서 두번째는 마진을 주고 설치 - heightMargin = i === 0 ? 0 : intvVer * i + heightMargin = installedModuleHeightCount === 0 ? 0 : intvVer for (let j = 0; j < totalModuleWidthCount; j++) { let moduleX = startPointX + width * j + 1 //5정도 마진을 준다 @@ -1947,18 +2095,19 @@ export function useModuleBasicSetting(tabNum) { installedLastHeightCoord = moduleY - height - heightMargin } else { //디버깅용 - // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) - // canvas?.add(tempModule) - // canvas.renderAll() + tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + canvas?.add(tempModule) + canvas.renderAll() } } if (isInstall) { ++installedModuleHeightCount + installedModuleMixYn = module.mixAsgYn } } setupModule.push(moduleArray) - }) + } } const topFlowSetupModule = ( @@ -1980,8 +2129,36 @@ export function useModuleBasicSetting(tabNum) { let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트 let isChidoriLine = false let flowLines + let installedModuleMixYn + const isNorthSurface = moduleSetupSurface.isNorth + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 + + let layoutRow = 0 + let layoutCol = 0 + + if (type === 'layout') { + const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) + if (!isPassed) { + return + } + } + + for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { + const module = checkedModule[moduleIndex] + + if (type === 'layout' && checkedLayoutData) { + const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) + layoutRow = layout.row + layoutCol = layout.col + } + + //혼합여부에 따라 설치 여부 결정 + if (installedModuleMixYn && installedModuleMixYn !== module.mixAsgYn) { + continue + } + + const isNorthModuleYn = module.northModuleYn === 'Y' - checkedModule.forEach((module, moduleIndex) => { const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0] //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임 let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows @@ -1997,20 +2174,45 @@ export function useModuleBasicSetting(tabNum) { } } - //흐름 방향이 북쪽(위) + if (moduleSetupSurface.isSaleStoreNorthFlg) { + //북면가능 설치 대리점이면 + //북면일때 + if (isIncludeNorthModule) { + //북면 모듈이 있는지 확인하는 로직 + if (!isNorthModuleYn && isNorthSurface) { + //북면 모듈이 있으면 북면 모듈만 깔고 나머지는 스킵 + continue + } //흐름 방향이 북쪽(위) + } + } else { + // 불면설치 불가 대리점이면 + if (isNorthSurface) { + //북면일때 + if (!isNorthModuleYn) { + //북면 모듈이 아니면 스킵 + continue + } + } + } //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직 let calcModuleWidthCount = calcAreaWidth / (width + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 + let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1 + let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1) + + //단수지정 자동이면 + if (type === 'layout') { + calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol + calcModuleHeightCount = layoutRow + } + let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 //??어쩔때는 붙고 어쩔때는 안붙고 멋대로??? let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 - let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1 - let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1) - let calcStartPoint = flowLines.left.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬 let startPointX = flowLines.right.x1 - calcStartPoint //시작점을 만든다 @@ -2032,11 +2234,11 @@ export function useModuleBasicSetting(tabNum) { let isInstall = false let moduleY = flowLines.top.y1 + height * i //탑의 y점에서부터 아래로 그려 내려간다 - if (moduleIndex > 0) { - moduleY = installedLastHeightCoord + intvVer + 1 + if (installedModuleHeightCount > 0) { + moduleY = installedLastHeightCoord } - heightMargin = i === 0 ? 0 : intvVer * i //모듈간에 마진이 있어 마진값도 넣음 + heightMargin = installedModuleHeightCount === 0 ? 0 : intvVer //모듈간에 마진이 있어 마진값도 넣음 for (let j = 0; j < totalModuleWidthCount; j++) { //모듈 열수 만큼 반복 let moduleX = startPointX - width * j - 1 //시작점에서 우 -> 좌로 그려 내려간다 @@ -2087,11 +2289,12 @@ export function useModuleBasicSetting(tabNum) { } if (isInstall) { ++installedModuleHeightCount + installedModuleMixYn = module.mixAsgYn } } setupModule.push(moduleArray) - }) + } } //남, 북과 같은 로직으로 적용하려면 좌우는 열 -> 행 으로 그려야함 @@ -2115,8 +2318,36 @@ export function useModuleBasicSetting(tabNum) { let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트 let isChidoriLine = false let flowLines + let installedModuleMixYn + const isNorthSurface = moduleSetupSurface.isNorth + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 - checkedModule.forEach((module, moduleIndex) => { + let layoutRow = 0 + let layoutCol = 0 + + if (type === 'layout') { + const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) + if (!isPassed) { + return + } + } + + for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { + const module = checkedModule[moduleIndex] + + //단수 지정이면 + if (type === 'layout' && checkedLayoutData) { + const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) + layoutRow = layout.row + layoutCol = layout.col + } + + //혼합여부에 따라 설치 여부 결정 + if (installedModuleMixYn && installedModuleMixYn !== module.mixAsgYn) { + continue + } + + const isNorthModuleYn = module.northModuleYn === 'Y' const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0] //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임 let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows @@ -2135,19 +2366,46 @@ export function useModuleBasicSetting(tabNum) { } } + if (moduleSetupSurface.isSaleStoreNorthFlg) { + //북면가능 설치 대리점이면 + //북면일때 + if (isIncludeNorthModule) { + //북면 모듈이 있는지 확인하는 로직 + if (!isNorthModuleYn && isNorthSurface) { + //북면 모듈이 있으면 북면 모듈만 깔고 나머지는 스킵 + continue + } //흐름 방향이 북쪽(위) + } + } else { + // 불면설치 불가 대리점이면 + if (isNorthSurface) { + //북면일때 + if (!isNorthModuleYn) { + //북면 모듈이 아니면 스킵 + continue + } + } + } + //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] let calcAreaWidth = flowLines.bottom.y1 - flowLines.top.y1 //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직 let calcModuleWidthCount = calcAreaWidth / (height + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 + let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1 + let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) + + //단수지정 자동이면 + if (type === 'layout') { + calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol + calcModuleHeightCount = layoutRow + } + let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 - let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1 - let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) - let calcStartPoint = flowLines.bottom.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * height) / 2 : 0 //반씩 나눠서 중앙에 맞춤 left 높이 기준으로 양변이 직선일때만 가운데 정렬 let startPointX = flowLines.top.y1 + calcStartPoint //시작점을 만든다 @@ -2171,12 +2429,12 @@ export function useModuleBasicSetting(tabNum) { let moduleY = flowLines.left.x1 + width * i + 1 //살짝 여유를 준다 //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산 - if (moduleIndex > 0) { - moduleY = installedLastHeightCoord + intvHor + if (installedModuleHeightCount > 0) { + moduleY = installedLastHeightCoord } //첫번째는 붙여서 두번째는 마진을 주고 설치 - heightMargin = i === 0 ? 0 : intvHor * i + heightMargin = installedModuleHeightCount === 0 ? 0 : intvHor for (let j = 0; j < totalModuleWidthCount; j++) { let moduleX = startPointX + height * j + 1 //5정도 마진을 준다 @@ -2227,10 +2485,11 @@ export function useModuleBasicSetting(tabNum) { if (isInstall) { ++installedModuleHeightCount + installedModuleMixYn = module.mixAsgYn } } setupModule.push(moduleArray) - }) + } } const rightFlowSetupModule = ( @@ -2252,8 +2511,35 @@ export function useModuleBasicSetting(tabNum) { let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트 let isChidoriLine = false let flowLines + let installedModuleMixYn + const isNorthSurface = moduleSetupSurface.isNorth + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 - checkedModule.forEach((module, moduleIndex) => { + let layoutRow = 0 + let layoutCol = 0 + + if (type === 'layout') { + const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) + if (!isPassed) { + return + } + } + + for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { + const module = checkedModule[moduleIndex] + + if (type === 'layout' && checkedLayoutData) { + const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) + layoutRow = layout.row + layoutCol = layout.col + } + + //혼합여부에 따라 설치 여부 결정 + if (installedModuleMixYn && installedModuleMixYn !== module.mixAsgYn) { + continue + } + + const isNorthModuleYn = module.northModuleYn === 'Y' const tmpModuleData = trestleDetailData.module.filter((moduleObj) => module.moduleTpCd === moduleObj.moduleTpCd)[0] //혼합모듈일때는 mixModuleMaxRows 값이 0 이상임 let moduleMaxRows = tmpModuleData.mixModuleMaxRows === 0 ? tmpModuleData.moduleMaxRows : tmpModuleData.mixModuleMaxRows @@ -2272,18 +2558,45 @@ export function useModuleBasicSetting(tabNum) { } } + if (moduleSetupSurface.isSaleStoreNorthFlg) { + //북면가능 설치 대리점이면 + //북면일때 + if (isIncludeNorthModule) { + //북면 모듈이 있는지 확인하는 로직 + if (!isNorthModuleYn && isNorthSurface) { + //북면 모듈이 있으면 북면 모듈만 깔고 나머지는 스킵 + continue + } //흐름 방향이 북쪽(위) + } + } else { + // 불면설치 불가 대리점이면 + if (isNorthSurface) { + //북면일때 + if (!isNorthModuleYn) { + //북면 모듈이 아니면 스킵 + continue + } + } + } + //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 const moduleArray = [] let calcAreaWidth = flowLines.bottom.y1 - flowLines.top.y1 //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직 let calcModuleWidthCount = calcAreaWidth / (height + intvHor + 1) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직 + let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1 + let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) + + //단수지정 자동이면 + if (type === 'layout') { + calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol + calcModuleHeightCount = layoutRow + } + let calcMaxModuleWidthCount = calcModuleWidthCount > moduleMaxCols ? moduleMaxCols : calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀 // let totalModuleWidthCount = isChidori ? Math.abs(calcMaxModuleWidthCount) : Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다 - let calcAreaHeight = flowLines.right.x1 - flowLines.left.x1 - let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) - let calcStartPoint = flowLines.top.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * height) / 2 : 0 //반씩 나눠서 중앙에 맞춤 left 높이 기준으로 양변이 직선일때만 가운데 정렬 let startPointX = flowLines.bottom.y2 - calcStartPoint //시작점을 만든다 @@ -2307,12 +2620,12 @@ export function useModuleBasicSetting(tabNum) { let moduleY = flowLines.right.x1 - width * i - 1 //살짝 여유를 준다 //두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산 - if (moduleIndex > 0) { - moduleY = installedLastHeightCoord - intvHor + if (installedModuleHeightCount > 0) { + moduleY = installedLastHeightCoord } //첫번째는 붙여서 두번째는 마진을 주고 설치 - heightMargin = i === 0 ? 0 : intvHor * i + heightMargin = installedModuleHeightCount === 0 ? 0 : intvHor for (let j = 0; j < totalModuleWidthCount; j++) { let moduleX = startPointX - height * j - 1 //5정도 마진을 준다 @@ -2366,11 +2679,12 @@ export function useModuleBasicSetting(tabNum) { if (isInstall) { ++installedModuleHeightCount + installedModuleMixYn = module.mixAsgYn } } setupModule.push(moduleArray) - }) + } } moduleSetupSurfaces.forEach((moduleSetupSurface, index) => { @@ -2460,6 +2774,18 @@ export function useModuleBasicSetting(tabNum) { } }) // calculateForApi() + + if (type === 'layout' && failAutoSetupRoof.length > 0) { + const roofNamesList = failAutoSetupRoof.map((roof) => ({ + roofName: roof.roofMaterial.roofMatlNmJp, + moduleMaxRows: roof.trestleDetail.moduleMaxRows, + })) + + const alertString = roofNamesList.map((item, index) => `${item.roofName}(${item.moduleMaxRows})`) + console.log('alertString', alertString) + + // swalFire({ text: alertString, icon: 'warning' }) + } } const coordToTurfPolygon = (points) => { diff --git a/src/locales/ja.json b/src/locales/ja.json index 5ab74329..1fc75a67 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -149,9 +149,10 @@ "modal.module.basic.setting.pitch.module.column.amount": "列数", "modal.module.basic.setting.pitch.module.column.margin": "左右間隔", "modal.module.basic.setting.prev": "前に戻る", - "modal.module.basic.setting.row.batch": "段・列数指定配置", + "modal.module.basic.setting.row.batch": "レイアウト指定", "modal.module.basic.setting.passivity.placement": "手動配置", "modal.module.basic.setting.auto.placement": "自動配置", + "modal.module.basic.setting.auto.row.batch": "自動レイアウト指定", "plan.menu.module.circuit.setting.circuit.trestle.setting": "回路設定", "modal.circuit.trestle.setting": "回路設定", "modal.circuit.trestle.setting.alloc.trestle": "架台配置", diff --git a/src/locales/ko.json b/src/locales/ko.json index 1090b4b1..cd8b855b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -152,7 +152,8 @@ "modal.module.basic.setting.prev": "이전", "modal.module.basic.setting.row.batch": "단·열수 지정 배치", "modal.module.basic.setting.passivity.placement": "수동 배치", - "modal.module.basic.setting.auto.placement": "설정값으로 자동 배치", + "modal.module.basic.setting.auto.placement": "자동 배치", + "modal.module.basic.setting.auto.row.batch": "자동 단·열수 지정 배치 ", "plan.menu.module.circuit.setting.circuit.trestle.setting": "회로설정", "modal.circuit.trestle.setting": "회로설정", "modal.circuit.trestle.setting.alloc.trestle": "가대할당", From 1c7b81c99f2b5bdec165298533f6446622fa3804 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 28 Apr 2025 14:09:58 +0900 Subject: [PATCH 14/45] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 86279910..e60a5324 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -2775,6 +2775,9 @@ export function useModuleBasicSetting(tabNum) { }) // calculateForApi() + /** + * 자동 레이아웃일떄 설치 가능한 애들은 설치 해주고 실패한 애들은 이름, 최대 설치 가능한 높이 알려줄라고 + */ if (type === 'layout' && failAutoSetupRoof.length > 0) { const roofNamesList = failAutoSetupRoof.map((roof) => ({ roofName: roof.roofMaterial.roofMatlNmJp, From ed27f2ed93ad0eff56ffb659e96f9ae6fb33b873 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 29 Apr 2025 13:09:46 +0900 Subject: [PATCH 15/45] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=9E=90=EB=8F=99?= =?UTF-8?q?=20=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20=EC=84=A4=EC=B9=98=20?= =?UTF-8?q?validate=20=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/common.js | 5 + .../floor-plan/modal/basic/BasicSetting.jsx | 6 +- .../floor-plan/modal/basic/step/Placement.jsx | 6 +- src/hooks/module/useModuleBasicSetting.js | 190 ++++++++++++------ 4 files changed, 140 insertions(+), 67 deletions(-) diff --git a/src/common/common.js b/src/common/common.js index abda5acd..c98cf385 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -125,6 +125,11 @@ export const TRESTLE_MATERIAL = { BRACKET: 'bracket', } +export const MODULE_SETUP_TYPE = { + LAYOUT: 'layout', + AUTO: 'auto', +} + export const SAVE_KEY = [ 'selectable', 'name', diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index a930c148..66a76d71 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -1,4 +1,4 @@ -import { POLYGON_TYPE } from '@/common/common' +import { POLYGON_TYPE, MODULE_SETUP_TYPE } from '@/common/common' import WithDraggable from '@/components/common/draggable/WithDraggable' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' @@ -334,10 +334,10 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { - - diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index 909f5229..5d2c8c6a 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -64,9 +64,9 @@ const Placement = forwardRef((props, refs) => { } }, []) - useEffect(() => { - console.log('moduleRowColArray', moduleRowColArray) - }, [moduleRowColArray]) + // useEffect(() => { + // console.log('moduleRowColArray', moduleRowColArray) + // }, [moduleRowColArray]) //최초 지입시 체크 useEffect(() => { diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index e60a5324..1ce7298f 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -19,7 +19,7 @@ import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qp import { QPolygon } from '@/components/fabric/QPolygon' import { moduleSetupSurfaceState } from '@/store/canvasAtom' import { useEvent } from '@/hooks/useEvent' -import { POLYGON_TYPE, BATCH_TYPE, LINE_TYPE } from '@/common/common' +import { POLYGON_TYPE, BATCH_TYPE, LINE_TYPE, MODULE_SETUP_TYPE } from '@/common/common' import * as turf from '@turf/turf' import { useSwal } from '@/hooks/useSwal' import { compasDegAtom } from '@/store/orientationAtom' @@ -1772,6 +1772,8 @@ export function useModuleBasicSetting(tabNum) { const autoModuleSetup = (type, layoutSetupRef) => { initEvent() //마우스 이벤트 초기화 + console.log('checkedModule', checkedModule) + //실패한 지붕재 배열 let failAutoSetupRoof = [] @@ -1780,7 +1782,7 @@ export function useModuleBasicSetting(tabNum) { /** * 자동 레이아웃일때 0이 있거나 혼합이 있는지 확인하는 로직 */ - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { checkedLayoutData = layoutSetupRef.filter((module) => module.checked) const hasZeroLength = checkedLayoutData.some((module) => module.row === 0 || module.col === 0) @@ -1789,15 +1791,15 @@ export function useModuleBasicSetting(tabNum) { return } - //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 - const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') - const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') + // //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 + // const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') + // const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') - //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 - if (mixAsgY.length > 0 && mixAsgN.length > 0) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) - return - } + // //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 + // if (mixAsgY.length > 0 && mixAsgN.length > 0) { + // swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) + // return + // } } if (checkedModule.length === 0) { @@ -1805,16 +1807,6 @@ export function useModuleBasicSetting(tabNum) { return } - // //혼합 가능 모듈과 혼합 불가능 모듈을 선택했을때 카운트를 해서 확인 - // const mixAsgY = checkedModule.filter((obj) => obj.mixAsgYn === 'Y') - // const mixAsgN = checkedModule.filter((obj) => obj.mixAsgYn === 'N') - - // //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 - // if (mixAsgY.length > 0 && mixAsgN.length > 0) { - // swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) - // return - // } - const isChidori = moduleSetupOption.isChidori const setupLocation = moduleSetupOption.setupLocation const isMaxSetup = false @@ -1859,6 +1851,9 @@ export function useModuleBasicSetting(tabNum) { name: POLYGON_TYPE.MODULE, } + //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') + //선택된 지붕안에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 포함되면 배열 반환 const objectsIncludeSurface = (turfModuleSetupSurface) => { let containsBatchObjects = [] @@ -1891,32 +1886,108 @@ export function useModuleBasicSetting(tabNum) { * @returns */ const checkAutoLayoutModuleSetup = (moduleSetupSurface, trestleDetailData) => { - const isMultipleModules = checkedModule.length > 1 //모듈이 여러개면 - const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 - const maxRow = isMultipleModules - ? trestleDetailData.moduleMaxRows - : trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + /** + * 체크된 모듈중에 북면 모듈이 있으면 북면 모듈만 따로 계산하고 아니면 전체 모듈을 계산 + * 북면 모듈이 있고 북면이 들어오면 북면의 row를 계산한다 + * + */ - //단수 합단수 - const sumRowCount = isMultipleModules - ? layoutSetupRef.filter((item) => item.checked).reduce((acc, cur) => acc + cur.row, 0) - : layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + //북면 모듈이 없을때 + if (!isIncludeNorthModule) { + const isMultipleModules = checkedModule.length > 1 //모듈이 여러개면 + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = isMultipleModules + ? trestleDetailData.moduleMaxRows + : trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - // - const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) + //단수 합단수 + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => item.checked).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 - if (sumRowCount > maxRow || sumColCount) { - failAutoSetupRoof.push(moduleSetupSurface) - return false - } + // + const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) - // 혼합일때 모듈 개별의 row를 체크함 - const isPassedObject = - isMultipleModules && layoutSetupRef.find((item, index) => item.checked && item.row > trestleDetailData.module[index].mixModuleMaxRows) + if (sumRowCount > maxRow || sumColCount) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } - if (isPassedObject) { - failAutoSetupRoof.push(moduleSetupSurface) - return false + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && layoutSetupRef.find((item, index) => item.checked && item.row > trestleDetailData.module[index].mixModuleMaxRows) + + if (isPassedObject) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + } else { + //북면 모듈만 선택했을때 + if (checkedModule.length === 1) { + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + //단수 합단수 + const sumRowCount = layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) + + if (sumRowCount > maxRow || sumColCount) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + } else { + const normalModule = checkedModule.filter((item) => item.northModuleYn === 'N') + const northModule = checkedModule.filter((item) => item.northModuleYn === 'Y') + + //만약 북면 모듈이 2개면 이 하위 로직 가져다가 쓰면됨 northModule === 만 바꾸면 될듯 + // northModule을 배열로 만들고 include로 해서 체크 해야됨 + if (normalModule.length > 0 && !moduleSetupSurface.isNorth) { + const isMultipleModules = normalModule.length > 1 //모듈이 여러개면 + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = isMultipleModules + ? trestleDetailData.moduleMaxRows + : trestleDetailData.module.find((item) => item.moduleTpCd === normalModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + //단수 합단수 + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => item.checked && item.moduleId !== northModule[0].itemId).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === normalModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + + // + const sumColCount = layoutSetupRef.filter((item) => item.col && item.moduleId !== northModule[0].itemId).some((item) => item.col > maxCol) + + if (sumRowCount > maxRow || sumColCount) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && + layoutSetupRef.find( + (item, index) => + item.checked && item.moduleId !== northModule[0].itemId && item.row > trestleDetailData.module[index].mixModuleMaxRows, + ) + + if (isPassedObject) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + } + + if (northModule.length > 0 && moduleSetupSurface.isNorth) { + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + const sumRowCount = layoutSetupRef.find((item) => item.moduleId === northModule[0].itemId).row + const sumColCount = layoutSetupRef.filter((item) => item.col && item.moduleId !== northModule[0].itemId).some((item) => item.col > maxCol) + + if (sumRowCount > maxRow || sumColCount) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } + } + } } return true } @@ -1943,12 +2014,11 @@ export function useModuleBasicSetting(tabNum) { let flowLines let installedModuleMixYn const isNorthSurface = moduleSetupSurface.isNorth - const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 let layoutRow = 0 let layoutCol = 0 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) if (!isPassed) { return @@ -1958,7 +2028,7 @@ export function useModuleBasicSetting(tabNum) { for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { const module = checkedModule[moduleIndex] - if (type === 'layout' && checkedLayoutData) { + if (type === MODULE_SETUP_TYPE.LAYOUT && checkedLayoutData) { const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) layoutRow = layout.row layoutCol = layout.col @@ -2009,7 +2079,7 @@ export function useModuleBasicSetting(tabNum) { let calcAreaHeight = flowLines.bottom.y1 - flowLines.top.y1 let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1) - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol calcModuleHeightCount = layoutRow } @@ -2095,9 +2165,9 @@ export function useModuleBasicSetting(tabNum) { installedLastHeightCoord = moduleY - height - heightMargin } else { //디버깅용 - tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) - canvas?.add(tempModule) - canvas.renderAll() + // tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 }) + // canvas?.add(tempModule) + // canvas.renderAll() } } if (isInstall) { @@ -2136,7 +2206,7 @@ export function useModuleBasicSetting(tabNum) { let layoutRow = 0 let layoutCol = 0 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) if (!isPassed) { return @@ -2146,7 +2216,7 @@ export function useModuleBasicSetting(tabNum) { for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { const module = checkedModule[moduleIndex] - if (type === 'layout' && checkedLayoutData) { + if (type === MODULE_SETUP_TYPE.LAYOUT && checkedLayoutData) { const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) layoutRow = layout.row layoutCol = layout.col @@ -2204,7 +2274,7 @@ export function useModuleBasicSetting(tabNum) { let calcModuleHeightCount = calcAreaHeight / (height + intvVer + 1) //단수지정 자동이면 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol calcModuleHeightCount = layoutRow } @@ -2325,7 +2395,7 @@ export function useModuleBasicSetting(tabNum) { let layoutRow = 0 let layoutCol = 0 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) if (!isPassed) { return @@ -2336,7 +2406,7 @@ export function useModuleBasicSetting(tabNum) { const module = checkedModule[moduleIndex] //단수 지정이면 - if (type === 'layout' && checkedLayoutData) { + if (type === MODULE_SETUP_TYPE.LAYOUT && checkedLayoutData) { const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) layoutRow = layout.row layoutCol = layout.col @@ -2397,7 +2467,7 @@ export function useModuleBasicSetting(tabNum) { let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) //단수지정 자동이면 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol calcModuleHeightCount = layoutRow } @@ -2518,7 +2588,7 @@ export function useModuleBasicSetting(tabNum) { let layoutRow = 0 let layoutCol = 0 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { const isPassed = checkAutoLayoutModuleSetup(moduleSetupSurface, trestleDetailData) if (!isPassed) { return @@ -2528,7 +2598,7 @@ export function useModuleBasicSetting(tabNum) { for (let moduleIndex = 0; moduleIndex < checkedModule.length; moduleIndex++) { const module = checkedModule[moduleIndex] - if (type === 'layout' && checkedLayoutData) { + if (type === MODULE_SETUP_TYPE.LAYOUT && checkedLayoutData) { const layout = checkedLayoutData.find((item) => module.itemId === item.moduleId) layoutRow = layout.row layoutCol = layout.col @@ -2588,7 +2658,7 @@ export function useModuleBasicSetting(tabNum) { let calcModuleHeightCount = calcAreaHeight / (width + intvVer + 1) //단수지정 자동이면 - if (type === 'layout') { + if (type === MODULE_SETUP_TYPE.LAYOUT) { calcModuleWidthCount = layoutCol > calcModuleWidthCount ? calcModuleWidthCount : layoutCol calcModuleHeightCount = layoutRow } @@ -2778,16 +2848,14 @@ export function useModuleBasicSetting(tabNum) { /** * 자동 레이아웃일떄 설치 가능한 애들은 설치 해주고 실패한 애들은 이름, 최대 설치 가능한 높이 알려줄라고 */ - if (type === 'layout' && failAutoSetupRoof.length > 0) { + if (type === MODULE_SETUP_TYPE.LAYOUT && failAutoSetupRoof.length > 0) { const roofNamesList = failAutoSetupRoof.map((roof) => ({ roofName: roof.roofMaterial.roofMatlNmJp, moduleMaxRows: roof.trestleDetail.moduleMaxRows, })) const alertString = roofNamesList.map((item, index) => `${item.roofName}(${item.moduleMaxRows})`) - console.log('alertString', alertString) - - // swalFire({ text: alertString, icon: 'warning' }) + swalFire({ text: alertString, icon: 'warning' }) } } From d5bba49ca975bd5c694f4ed1e1a81b9b5ae9250e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 2 May 2025 09:23:59 +0900 Subject: [PATCH 16/45] =?UTF-8?q?console.log=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 1ce7298f..ffff4344 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1772,8 +1772,6 @@ export function useModuleBasicSetting(tabNum) { const autoModuleSetup = (type, layoutSetupRef) => { initEvent() //마우스 이벤트 초기화 - console.log('checkedModule', checkedModule) - //실패한 지붕재 배열 let failAutoSetupRoof = [] From 08722e8b51e3392b1f1960445f7f8ef6f0f1bf0e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 2 May 2025 15:50:27 +0900 Subject: [PATCH 17/45] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EB=A0=88=EC=9D=B4?= =?UTF-8?q?=EC=95=84=EC=9B=83=20=EC=84=A4=EC=B9=98=20=EC=9E=91=EC=97=85?= =?UTF-8?q?=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 79 +++++++++++++++++------ 1 file changed, 58 insertions(+), 21 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index ffff4344..785c6b0f 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1822,20 +1822,35 @@ export function useModuleBasicSetting(tabNum) { } //어짜피 자동으로 누르면 선택안된데도 다 날아간다 - canvas.getObjects().forEach((obj) => { - if (obj.name === POLYGON_TYPE.MODULE) { - canvas.remove(obj) - } - }) + // canvas.getObjects().forEach((obj) => { + // if (obj.name === POLYGON_TYPE.MODULE) { + // canvas.remove(obj) + // } + // }) - notSelectedTrestlePolygons.forEach((obj) => { - if (obj.modules) { - obj.modules.forEach((module) => { - canvas?.remove(module) - }) - obj.modules = [] - } - }) + //자동일때만 선택 안된 모듈 삭제 + if (type === MODULE_SETUP_TYPE.AUTO) { + notSelectedTrestlePolygons.forEach((obj) => { + if (obj.modules) { + obj.modules.forEach((module) => { + canvas?.remove(module) + canvas?.renderAll() + }) + obj.modules = [] + } + }) + } else { + //레이아웃일때는 기존에 깔린 모듈은 삭제 하지 않음 선택된 영역만 모듈 삭제 + moduleSetupSurfaces.forEach((obj) => { + if (obj.modules) { + obj.modules.forEach((module) => { + canvas?.remove(module) + canvas?.renderAll() + }) + obj.modules = [] + } + }) + } let moduleOptions = { stroke: 'black', @@ -1936,23 +1951,25 @@ export function useModuleBasicSetting(tabNum) { } else { const normalModule = checkedModule.filter((item) => item.northModuleYn === 'N') const northModule = checkedModule.filter((item) => item.northModuleYn === 'Y') + const northModuleIds = northModule.map((item) => item.itemId) //만약 북면 모듈이 2개면 이 하위 로직 가져다가 쓰면됨 northModule === 만 바꾸면 될듯 // northModule을 배열로 만들고 include로 해서 체크 해야됨 if (normalModule.length > 0 && !moduleSetupSurface.isNorth) { + //C1C2 모듈일 경우ㅁㅁ const isMultipleModules = normalModule.length > 1 //모듈이 여러개면 const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows : trestleDetailData.module.find((item) => item.moduleTpCd === normalModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - //단수 합단수 + //북면 모듈 id를 제외한 모듈의 단 체크 const sumRowCount = isMultipleModules - ? layoutSetupRef.filter((item) => item.checked && item.moduleId !== northModule[0].itemId).reduce((acc, cur) => acc + cur.row, 0) + ? layoutSetupRef.filter((item) => item.checked && !northModuleIds.includes(item.moduleId)).reduce((acc, cur) => acc + cur.row, 0) : layoutSetupRef.find((item) => item.moduleId === normalModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 - // - const sumColCount = layoutSetupRef.filter((item) => item.col && item.moduleId !== northModule[0].itemId).some((item) => item.col > maxCol) + //북면 모듈 id를 제외한 모듈의 열 체크 + const sumColCount = layoutSetupRef.filter((item) => item.col && !northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) if (sumRowCount > maxRow || sumColCount) { failAutoSetupRoof.push(moduleSetupSurface) @@ -1964,7 +1981,7 @@ export function useModuleBasicSetting(tabNum) { isMultipleModules && layoutSetupRef.find( (item, index) => - item.checked && item.moduleId !== northModule[0].itemId && item.row > trestleDetailData.module[index].mixModuleMaxRows, + item.checked && !item.moduleId.includes(northModuleIds) && item.row > trestleDetailData.module[index].mixModuleMaxRows, ) if (isPassedObject) { @@ -1974,16 +1991,36 @@ export function useModuleBasicSetting(tabNum) { } if (northModule.length > 0 && moduleSetupSurface.isNorth) { + const isMultipleModules = northModule.length > 1 //모듈이 여러개면 const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 - const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - const sumRowCount = layoutSetupRef.find((item) => item.moduleId === northModule[0].itemId).row - const sumColCount = layoutSetupRef.filter((item) => item.col && item.moduleId !== northModule[0].itemId).some((item) => item.col > maxCol) + const maxRow = isMultipleModules + ? trestleDetailData.moduleMaxRows + : trestleDetailData.module.find((item) => item.moduleTpCd === northModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => northModuleIds.includes(item.moduleId)).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === northModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + + const sumColCount = layoutSetupRef.filter((item) => item.col && northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) if (sumRowCount > maxRow || sumColCount) { failAutoSetupRoof.push(moduleSetupSurface) return false } + + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && + layoutSetupRef.find( + (item, index) => + item.checked && northModuleIds.includes(item.moduleId) && item.row > trestleDetailData.module[index].mixModuleMaxRows, + ) + + if (isPassedObject) { + failAutoSetupRoof.push(moduleSetupSurface) + return false + } } } } From d6b0e4994af85b6360f2b60759027913e68ae235 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 7 May 2025 14:47:08 +0900 Subject: [PATCH 18/45] =?UTF-8?q?#=20[1014]=20:=20819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # [작업내용] : http://1.248.227.176:43333/issues/1014 --- .../floor-plan/modal/basic/BasicSetting.jsx | 6 +- .../floor-plan/modal/basic/step/Placement.jsx | 6 +- src/hooks/module/useModuleBasicSetting.js | 170 +++++------------- src/locales/ja.json | 4 +- 4 files changed, 57 insertions(+), 129 deletions(-) diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 66a76d71..a70b9a22 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -331,15 +331,15 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { + - )} diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index 5d2c8c6a..c6556ea3 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -37,7 +37,7 @@ const Placement = forwardRef((props, refs) => { const resetModuleSetupOption = useResetRecoilState(moduleSetupOptionState) const [colspan, setColspan] = useState(1) - const [moduleRowColArray, setModuleRowColArray] = useRecoilState(moduleRowColArrayState) + const moduleRowColArray = useRecoilValue(moduleRowColArrayState) //모듈 배치면 생성 useEffect(() => { @@ -337,6 +337,7 @@ const Placement = forwardRef((props, refs) => { ))} + {colspan > 1 && {getMessage('total')}} {selectedModules.itemList.map((item) => ( @@ -356,10 +357,11 @@ const Placement = forwardRef((props, refs) => { {item.addRoof?.roofMatlNmJp} - {moduleRowColArray[index]?.map((item) => ( + {moduleRowColArray[index]?.map((item, index2) => ( <> {item.moduleMaxRows} {colspan > 1 && {item.mixModuleMaxRows}} + {colspan > 1 && index2 === moduleRowColArray[index].length - 1 && {item.maxRow}} ))} diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 785c6b0f..c43477d7 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -49,20 +49,17 @@ export function useModuleBasicSetting(tabNum) { const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState) const canvasSetting = useRecoilValue(canvasSettingState) const moduleSelectionData = useRecoilValue(moduleSelectionDataState) - const [trestleDetailParams, setTrestleDetailParams] = useState([]) const [trestleDetailList, setTrestleDetailList] = useState([]) const selectedModules = useRecoilValue(selectedModuleState) - const { getTrestleDetailList } = useMasterController() const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false) const setCurrentObject = useSetRecoilState(currentObjectState) const { setModuleStatisticsData } = useCircuitTrestle() const { createRoofPolygon, createMarginPolygon, createPaddingPolygon } = useMode() - const { drawDirectionArrow } = usePolygon() const moduleSetupOption = useRecoilValue(moduleSetupOptionState) const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState) - const [moduleRowColArray, setModuleRowColArray] = useRecoilState(moduleRowColArrayState) + const setModuleRowColArray = useSetRecoilState(moduleRowColArrayState) useEffect(() => { return () => { @@ -111,10 +108,6 @@ export function useModuleBasicSetting(tabNum) { } } - useEffect(() => { - console.log('saleStoreNorthFlg', saleStoreNorthFlg) - }, [saleStoreNorthFlg]) - //가대 상세 데이터 들어오면 실행 useEffect(() => { if (trestleDetailList.length > 0) { @@ -153,7 +146,7 @@ export function useModuleBasicSetting(tabNum) { const moduleRowArray = [] if (isObjectNotEmpty(detail) && detail.module.length > 0) { detail.module.forEach((module) => { - moduleRowArray.push({ moduleMaxRows: module.moduleMaxRows, mixModuleMaxRows: module.mixModuleMaxRows }) + moduleRowArray.push({ moduleMaxRows: module.moduleMaxRows, mixModuleMaxRows: module.mixModuleMaxRows, maxRow: detail.moduleMaxRows }) }) } rowColArray.push(moduleRowArray) @@ -456,14 +449,14 @@ export function useModuleBasicSetting(tabNum) { } if (checkedModule.length === 0) { - swalFire({ text: getMessage('module.place.select.module') }) + swalFire({ text: getMessage('module.place.select.module'), icon: 'warning' }) setIsManualModuleSetup(false) setManualSetupMode(`manualSetup_false`) return } if (checkedModule.length > 1) { - swalFire({ text: getMessage('module.place.select.one.module') }) + swalFire({ text: getMessage('module.place.select.one.module'), icon: 'warning' }) setIsManualModuleSetup(false) setManualSetupMode(`manualSetup_false`) return @@ -1048,26 +1041,6 @@ export function useModuleBasicSetting(tabNum) { }, ] - //아래래 - // let points = [ - // { - // x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, - // y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, - // }, - // { - // x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, - // y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, - // }, - // { - // x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, - // y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, - // }, - // { - // x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, - // y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, - // }, - // ] - const turfPoints = coordToTurfPolygon(points) if (turf.booleanWithin(turfPoints, turfPolygon)) { @@ -1829,6 +1802,16 @@ export function useModuleBasicSetting(tabNum) { // }) //자동일때만 선택 안된 모듈 삭제 + moduleSetupSurfaces.forEach((obj) => { + if (obj.modules) { + obj.modules.forEach((module) => { + canvas?.remove(module) + canvas?.renderAll() + }) + obj.modules = [] + } + }) + if (type === MODULE_SETUP_TYPE.AUTO) { notSelectedTrestlePolygons.forEach((obj) => { if (obj.modules) { @@ -1839,17 +1822,6 @@ export function useModuleBasicSetting(tabNum) { obj.modules = [] } }) - } else { - //레이아웃일때는 기존에 깔린 모듈은 삭제 하지 않음 선택된 영역만 모듈 삭제 - moduleSetupSurfaces.forEach((obj) => { - if (obj.modules) { - obj.modules.forEach((module) => { - canvas?.remove(module) - canvas?.renderAll() - }) - obj.modules = [] - } - }) } let moduleOptions = { @@ -1864,9 +1836,6 @@ export function useModuleBasicSetting(tabNum) { name: POLYGON_TYPE.MODULE, } - //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 - const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') - //선택된 지붕안에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 포함되면 배열 반환 const objectsIncludeSurface = (turfModuleSetupSurface) => { let containsBatchObjects = [] @@ -1895,49 +1864,46 @@ export function useModuleBasicSetting(tabNum) { /** * 자동 레이아웃 설치 일시 row col 초과 여부 확인 + * 체크된 모듈중에 북면 모듈이 있으면 북면 모듈만 따로 계산하고 아니면 전체 모듈을 계산 + * 북면 모듈이 있고 북면이 들어오면 북면의 row를 계산한다 + * * @param {*} trestleDetailData * @returns */ const checkAutoLayoutModuleSetup = (moduleSetupSurface, trestleDetailData) => { - /** - * 체크된 모듈중에 북면 모듈이 있으면 북면 모듈만 따로 계산하고 아니면 전체 모듈을 계산 - * 북면 모듈이 있고 북면이 들어오면 북면의 row를 계산한다 - * - */ - //북면 모듈이 없을때 + //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') + const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + + //북면 모듈이 없으면 if (!isIncludeNorthModule) { - const isMultipleModules = checkedModule.length > 1 //모듈이 여러개면 - const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 + const isMultipleModules = checkedModule.length > 1 //모듈이 여러개인지 체크하고 + + //멀티 모듈이면 모듈밖에 내려온 정보의 maxRow 단일 모듈이면 모듈에 maxRow const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows : trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - //단수 합단수 + //멀티 모듈이면 모듈밖에 내려온 정보의 row 합, 단일 모듈이면 모듈에 row const sumRowCount = isMultipleModules ? layoutSetupRef.filter((item) => item.checked).reduce((acc, cur) => acc + cur.row, 0) : layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 - // + //col는 moduleItems 배열 밖에 내려옴 const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) - if (sumRowCount > maxRow || sumColCount) { - failAutoSetupRoof.push(moduleSetupSurface) - return false - } - - // 혼합일때 모듈 개별의 row를 체크함 + // 혼합일때 모듈 개별의 maxRow를 체크해서 가능여부 확인 const isPassedObject = - isMultipleModules && layoutSetupRef.find((item, index) => item.checked && item.row > trestleDetailData.module[index].mixModuleMaxRows) - - if (isPassedObject) { + isMultipleModules && layoutSetupRef.find((item, index) => item.checked && item.row > trestleDetailData.module[index].mixModuleMaxRows) //체크된 배열은 checked여부로 체크해서 index와 동일함 + //전체 카은트된 열수가 크거나 혼합카운트가 존재 하면 실패 + if (sumRowCount > maxRow || sumColCount || isPassedObject) { failAutoSetupRoof.push(moduleSetupSurface) return false } } else { //북면 모듈만 선택했을때 if (checkedModule.length === 1) { - const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 //단수 합단수 @@ -1958,7 +1924,6 @@ export function useModuleBasicSetting(tabNum) { if (normalModule.length > 0 && !moduleSetupSurface.isNorth) { //C1C2 모듈일 경우ㅁㅁ const isMultipleModules = normalModule.length > 1 //모듈이 여러개면 - const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows : trestleDetailData.module.find((item) => item.moduleTpCd === normalModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 @@ -1971,11 +1936,6 @@ export function useModuleBasicSetting(tabNum) { //북면 모듈 id를 제외한 모듈의 열 체크 const sumColCount = layoutSetupRef.filter((item) => item.col && !northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) - if (sumRowCount > maxRow || sumColCount) { - failAutoSetupRoof.push(moduleSetupSurface) - return false - } - // 혼합일때 모듈 개별의 row를 체크함 const isPassedObject = isMultipleModules && @@ -1984,16 +1944,15 @@ export function useModuleBasicSetting(tabNum) { item.checked && !item.moduleId.includes(northModuleIds) && item.row > trestleDetailData.module[index].mixModuleMaxRows, ) - if (isPassedObject) { + // 합산 단수가 맥스단수보다 크거나 열이 맥스열수보다 크거나 혼합일때 모듈 개별의 row가 맥스단수보다 크면 실패 + if (sumRowCount > maxRow || sumColCount || isPassedObject) { failAutoSetupRoof.push(moduleSetupSurface) return false } } - if (northModule.length > 0 && moduleSetupSurface.isNorth) { + if (northModule.length > 0) { const isMultipleModules = northModule.length > 1 //모듈이 여러개면 - const maxCol = trestleDetailData.moduleMaxCols //최대 열수 -> 얘는 멀티랑 관계없음 - const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows : trestleDetailData.module.find((item) => item.moduleTpCd === northModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 @@ -2004,11 +1963,6 @@ export function useModuleBasicSetting(tabNum) { const sumColCount = layoutSetupRef.filter((item) => item.col && northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) - if (sumRowCount > maxRow || sumColCount) { - failAutoSetupRoof.push(moduleSetupSurface) - return false - } - // 혼합일때 모듈 개별의 row를 체크함 const isPassedObject = isMultipleModules && @@ -2017,7 +1971,8 @@ export function useModuleBasicSetting(tabNum) { item.checked && northModuleIds.includes(item.moduleId) && item.row > trestleDetailData.module[index].mixModuleMaxRows, ) - if (isPassedObject) { + // 합산 단수가 맥스단수보다 크거나 열이 맥스열수보다 크거나 혼합일때 모듈 개별의 row가 맥스단수보다 크면 실패 + if (sumRowCount > maxRow || sumColCount || isPassedObject) { failAutoSetupRoof.push(moduleSetupSurface) return false } @@ -2028,16 +1983,7 @@ export function useModuleBasicSetting(tabNum) { } //흐름 방향이 남쪽(아래) - const downFlowSetupModule = ( - surfaceMaxLines, //deprecated - maxLengthLine, - moduleSetupArray, - moduleSetupSurface, - containsBatchObjects, - isCenter = false, //deprecated - intvHor, - intvVer, - ) => { + const downFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail @@ -2215,16 +2161,7 @@ export function useModuleBasicSetting(tabNum) { } } - const topFlowSetupModule = ( - surfaceMaxLines, - maxLengthLine, - moduleSetupArray, - moduleSetupSurface, - containsBatchObjects, - isCenter = false, - intvHor, - intvVer, - ) => { + const topFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail @@ -2405,12 +2342,11 @@ export function useModuleBasicSetting(tabNum) { //남, 북과 같은 로직으로 적용하려면 좌우는 열 -> 행 으로 그려야함 //변수명은 bottom 기준으로 작성하여 동일한 방향으로 진행한다 const leftFlowSetupModule = ( - surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, - isCenter = false, + intvHor, intvVer, ) => { @@ -2597,16 +2533,7 @@ export function useModuleBasicSetting(tabNum) { } } - const rightFlowSetupModule = ( - surfaceMaxLines, - maxLengthLine, - moduleSetupArray, - moduleSetupSurface, - containsBatchObjects, - isCenter = false, - intvHor, - intvVer, - ) => { + const rightFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터 @@ -2798,7 +2725,6 @@ export function useModuleBasicSetting(tabNum) { const turfModuleSetupSurface = polygonToTurfPolygon(moduleSetupSurface) //폴리곤을 turf 객체로 변환 const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 - const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface) let maxLengthLine = moduleSetupSurface.lines.reduce((acc, cur) => { return acc.length > cur.length ? acc : cur @@ -2819,30 +2745,30 @@ export function useModuleBasicSetting(tabNum) { if (setupLocation === 'eaves') { // 흐름방향이 남쪽일때 if (moduleSetupSurface.direction === 'south') { - downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'west') { - leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'east') { - rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'north') { - topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } } else if (setupLocation === 'ridge') { //용마루 if (moduleSetupSurface.direction === 'south') { - topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + topFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'west') { - rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + rightFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'east') { - leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + leftFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } if (moduleSetupSurface.direction === 'north') { - downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, false, intvHor, intvVer) + downFlowSetupModule(maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) } } diff --git a/src/locales/ja.json b/src/locales/ja.json index c6a1ea0e..44bf3bb4 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1071,8 +1071,8 @@ "module.layout.setup.max.count.multiple": "モジュール{0}の単体での最大段数は{1}、最大列数は{2}です。 (JA)", "roofAllocation.not.found": "割り当てる屋根がありません。 (JA)", "modal.module.basic.setting.module.placement.max.size.check": "屋根材別モジュールの単体の単体での最大段数、2種混合の段数を確認して下さい", - "modal.module.basic.setting.module.placement.max.row": "単体での最大段数", - "modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合時の最大段数", + "modal.module.basic.setting.module.placement.max.row": "単体で\rの最大段数", + "modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合時\rの最大段数", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)", "modal.module.basic.setting.module.placement.mix.asg.yn": "混合", "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)" From d244ba3b97c426cefbfa7923a7a8c438c37d5b0e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 7 May 2025 15:18:59 +0900 Subject: [PATCH 19/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 고도화 단수 열수 자동 배치 작업 --- .gitmessage.txt | 3 +++ .../floor-plan/modal/basic/step/Placement.jsx | 9 +++++---- src/hooks/module/useModuleBasicSetting.js | 11 +++-------- src/locales/ja.json | 3 ++- src/locales/ko.json | 3 ++- 5 files changed, 15 insertions(+), 14 deletions(-) create mode 100644 .gitmessage.txt diff --git a/.gitmessage.txt b/.gitmessage.txt new file mode 100644 index 00000000..07932f22 --- /dev/null +++ b/.gitmessage.txt @@ -0,0 +1,3 @@ +[일감번호] : [제목] + +[작업내용] : \ No newline at end of file diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index c6556ea3..1d2545e6 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -330,20 +330,21 @@ const Placement = forwardRef((props, refs) => { {selectedModules && selectedModules.itemList.map((item) => ( - + // +
{item.itemNm}
))} - {colspan > 1 && {getMessage('total')}} + {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} {selectedModules.itemList.map((item) => ( <> {getMessage('modal.module.basic.setting.module.placement.max.row')} - {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} + {/* {colspan > 1 && {getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}} */} ))} @@ -360,7 +361,7 @@ const Placement = forwardRef((props, refs) => { {moduleRowColArray[index]?.map((item, index2) => ( <> {item.moduleMaxRows} - {colspan > 1 && {item.mixModuleMaxRows}} + {/* {colspan > 1 && {item.mixModuleMaxRows}} */} {colspan > 1 && index2 === moduleRowColArray[index].length - 1 && {item.maxRow}} ))} diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c43477d7..c7173dca 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -2809,14 +2809,9 @@ export function useModuleBasicSetting(tabNum) { /** * 자동 레이아웃일떄 설치 가능한 애들은 설치 해주고 실패한 애들은 이름, 최대 설치 가능한 높이 알려줄라고 */ - if (type === MODULE_SETUP_TYPE.LAYOUT && failAutoSetupRoof.length > 0) { - const roofNamesList = failAutoSetupRoof.map((roof) => ({ - roofName: roof.roofMaterial.roofMatlNmJp, - moduleMaxRows: roof.trestleDetail.moduleMaxRows, - })) - - const alertString = roofNamesList.map((item, index) => `${item.roofName}(${item.moduleMaxRows})`) - swalFire({ text: alertString, icon: 'warning' }) + if (type === MODULE_SETUP_TYPE.LAYOUT && failAutoSetupRoof.length) { + const roofNames = failAutoSetupRoof.map((roof) => roof.roofMaterial.roofMatlNmJp).join(', ') + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.over.max.row', [roofNames]), icon: 'warning' }) } } diff --git a/src/locales/ja.json b/src/locales/ja.json index 44bf3bb4..343673d5 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1075,5 +1075,6 @@ "modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合時\rの最大段数", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)", "modal.module.basic.setting.module.placement.mix.asg.yn": "混合", - "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)" + "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)", + "modal.module.basic.setting.module.placement.over.max.row": "{0}의 최대단수를 초과했습니다. 최대단수표를 참고해 주세요.(JA)" } diff --git a/src/locales/ko.json b/src/locales/ko.json index cd8b855b..b3e3e99b 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1076,5 +1076,6 @@ "modal.module.basic.setting.module.placement.max.rows.multiple": "2종 혼합 최대단수", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "혼합 설치 불가능한 모듈입니다.", "modal.module.basic.setting.module.placement.mix.asg.yn": "혼합", - "modal.module.basic.setting.layoutpassivity.placement": "레이아웃 배치" + "modal.module.basic.setting.layoutpassivity.placement": "레이아웃 배치", + "modal.module.basic.setting.module.placement.over.max.row": "{0}의 최대단수를 초과했습니다. 최대단수표를 참고해 주세요." } From f3b8ee40fab1f229f975c57ae7707b6a7b9b0494 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 7 May 2025 16:56:28 +0900 Subject: [PATCH 20/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 문구 수정 및 alert icon 정리 --- src/hooks/module/useModuleBasicSetting.js | 34 +++++++++++------------ src/locales/ja.json | 2 +- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c7173dca..4471bc74 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -89,12 +89,12 @@ export function useModuleBasicSetting(tabNum) { //roofIndex 넣기 const roofConstructionArray = roofConstructions.map((detail) => ({ ...detail.trestleDetail, roofIndex: detail.roofIndex })) - setTrestleDetailList(roofConstructionArray) - //북면 설치 가능 판매점 if (moduleSelectionData.common.saleStoreNorthFlg == '1') { setSaleStoreNorthFlg(true) } + + setTrestleDetailList(roofConstructionArray) } } else { //육지붕 일경우에는 바로 배치면 설치LL @@ -865,10 +865,10 @@ export function useModuleBasicSetting(tabNum) { // getModuleStatistics() } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) } } else { - swalFire({ text: getMessage('module.place.out') }) + swalFire({ text: getMessage('module.place.out'), icon: 'warning' }) } } }) @@ -1266,7 +1266,7 @@ export function useModuleBasicSetting(tabNum) { const mixAsgYn = trestlePolygon.modules[0].moduleInfo.mixAsgYn //현재 체크된 모듈기준으로 혼합가능인지 확인 Y === Y, N === N 일때만 설치 가능 if (checkedModule[0].mixAsgYn !== mixAsgYn) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) return } } @@ -1425,7 +1425,7 @@ export function useModuleBasicSetting(tabNum) { // canvas.renderAll() } } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) return } } @@ -1520,7 +1520,7 @@ export function useModuleBasicSetting(tabNum) { // canvas.renderAll() } } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) return } } @@ -1613,7 +1613,7 @@ export function useModuleBasicSetting(tabNum) { // canvas.renderAll() } } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) return } } @@ -1705,7 +1705,7 @@ export function useModuleBasicSetting(tabNum) { // canvas.renderAll() } } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) return } } @@ -1790,7 +1790,7 @@ export function useModuleBasicSetting(tabNum) { const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 if (moduleSetupSurfaces.length === 0) { - swalFire({ text: getMessage('module.place.no.surface') }) + swalFire({ text: getMessage('module.place.no.surface'), icon: 'warning' }) return } @@ -3119,13 +3119,13 @@ export function useModuleBasicSetting(tabNum) { let moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 if (isManualModuleSetup) { if (checkedModule.length === 0) { - swalFire({ text: getMessage('module.place.select.module') }) + swalFire({ text: getMessage('module.place.select.module'), icon: 'warning' }) setIsManualModuleSetup(!isManualModuleSetup) return } if (checkedModule.length > 1) { - swalFire({ text: getMessage('module.place.select.one.module') }) + swalFire({ text: getMessage('module.place.select.one.module'), icon: 'warning' }) setIsManualModuleSetup(!isManualModuleSetup) return } @@ -3438,7 +3438,7 @@ export function useModuleBasicSetting(tabNum) { const mixAsgYn = trestlePolygon.modules[0].moduleInfo.mixAsgYn //현재 체크된 모듈기준으로 혼합가능인지 확인 Y === Y, N === N 일때만 설치 가능 if (checkedModule[0].mixAsgYn !== mixAsgYn) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) return } } @@ -3471,7 +3471,7 @@ export function useModuleBasicSetting(tabNum) { const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 //겹치면 안됨 if (intersection) { - swalFire({ text: getMessage('module.place.overobject') }) + swalFire({ text: getMessage('module.place.overobject'), icon: 'warning' }) isIntersection = false } }) @@ -3489,10 +3489,10 @@ export function useModuleBasicSetting(tabNum) { manualDrawModules.push(manualModule) setModuleStatisticsData() } else { - swalFire({ text: getMessage('module.place.overlab') }) + swalFire({ text: getMessage('module.place.overlab'), icon: 'warning' }) } } else { - swalFire({ text: getMessage('module.place.out') }) + swalFire({ text: getMessage('module.place.out'), icon: 'warning' }) } } }) @@ -3522,7 +3522,7 @@ export function useModuleBasicSetting(tabNum) { //Y인 모듈과 N인 모듈이 둘다 존재하면 설치 불가 if (mixAsgY.length > 0 && mixAsgN.length > 0) { - swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error') }) + swalFire({ text: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn.error'), icon: 'warning' }) return } diff --git a/src/locales/ja.json b/src/locales/ja.json index b37fbc3a..d378ff36 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1079,5 +1079,5 @@ "modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)", "modal.module.basic.setting.module.placement.mix.asg.yn": "混合", "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)", - "modal.module.basic.setting.module.placement.over.max.row": "{0}의 최대단수를 초과했습니다. 최대단수표를 참고해 주세요.(JA)" + "modal.module.basic.setting.module.placement.over.max.row": "{0} 最大段数超過しました。最大段数表を参考にしてください。" } From 47245e438c5200849078d9dc7a80c7d92700f372 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 8 May 2025 09:48:31 +0900 Subject: [PATCH 21/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 불필요 소스 삭제 --- src/locales/ja.json | 1 - src/locales/ko.json | 1 - 2 files changed, 2 deletions(-) diff --git a/src/locales/ja.json b/src/locales/ja.json index d378ff36..796eea85 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1078,6 +1078,5 @@ "modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合時\rの最大段数", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)", "modal.module.basic.setting.module.placement.mix.asg.yn": "混合", - "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)", "modal.module.basic.setting.module.placement.over.max.row": "{0} 最大段数超過しました。最大段数表を参考にしてください。" } diff --git a/src/locales/ko.json b/src/locales/ko.json index 9bc55162..c67e3823 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1079,6 +1079,5 @@ "modal.module.basic.setting.module.placement.max.rows.multiple": "2종 혼합 최대단수", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "혼합 설치 불가능한 모듈입니다.", "modal.module.basic.setting.module.placement.mix.asg.yn": "혼합", - "modal.module.basic.setting.layoutpassivity.placement": "레이아웃 배치", "modal.module.basic.setting.module.placement.over.max.row": "{0}의 최대단수를 초과했습니다. 최대단수표를 참고해 주세요." } From ef75ad0ef8a080d58e086de2d4f98204a254bd63 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 8 May 2025 13:29:13 +0900 Subject: [PATCH 22/45] chore: update environment variables for Japanese server configuration --- .env.development | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/.env.development b/.env.development index ceac1712..6488b496 100644 --- a/.env.development +++ b/.env.development @@ -10,8 +10,16 @@ NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secr NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin" NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin" -AWS_REGION="ap-northeast-2" -AMPLIFY_BUCKET="interplug" -AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" -AWS_SECRET_ACCESS_KEY="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" -NEXT_PUBLIC_AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" +# 테스트용 +# AWS_REGION="ap-northeast-2" +# AMPLIFY_BUCKET="interplug" +# AWS_ACCESS_KEY_ID="AKIAVWMWJCUXFHEAZ4FR" +# AWS_SECRET_ACCESS_KEY="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" +# NEXT_PUBLIC_AWS_S3_BASE_URL="https://interplug.s3.ap-northeast-2.amazonaws.com" + +# 실제 일본 서버 +AWS_REGION="ap-northeast-1" +AMPLIFY_BUCKET="files.hanasys.jp" +AWS_ACCESS_KEY_ID="AKIA3K4QWLZHFZRJOM2E" +AWS_SECRET_ACCESS_KEY="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" +NEXT_PUBLIC_AWS_S3_BASE_URL="http://files.hanasys.jp.s3-website-ap-northeast-1.amazonaws.com" \ No newline at end of file From e961648d853bbbcc9e1e4b98626f9059524cb4bc Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 8 May 2025 16:55:39 +0900 Subject: [PATCH 23/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 멀티모듈일때 북면 모듈 포함일 경우 북면이 아닌 면에 설치되는 오류 수정 --- src/hooks/module/useModuleBasicSetting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 4471bc74..2880d29a 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1951,7 +1951,7 @@ export function useModuleBasicSetting(tabNum) { } } - if (northModule.length > 0) { + if (northModule.length > 0 && moduleSetupSurface.isNorth) { const isMultipleModules = northModule.length > 1 //모듈이 여러개면 const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows From 694923696013a462e0a65dfab99f03cc36491a34 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Thu, 8 May 2025 18:02:41 +0900 Subject: [PATCH 24/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 북면설치 모듈일 경우, 북면과, 북면이 아닐때 분기 처리 --- src/hooks/module/useModuleBasicSetting.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 2880d29a..1d9c7d66 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1902,7 +1902,7 @@ export function useModuleBasicSetting(tabNum) { return false } } else { - //북면 모듈만 선택했을때 + //북면 모듈이 1개만있을때 if (checkedModule.length === 1) { const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 @@ -1951,7 +1951,8 @@ export function useModuleBasicSetting(tabNum) { } } - if (northModule.length > 0 && moduleSetupSurface.isNorth) { + //북면 모듈이 있고 북면에 있을때 + if (northModule.length > 0 && (moduleSetupSurface.isNorth || !moduleSetupSurface.isNorth)) { const isMultipleModules = northModule.length > 1 //모듈이 여러개면 const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows From 391fe39a2d48ab39c659b19b7e0891b764bd4bfa Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 9 May 2025 15:04:21 +0900 Subject: [PATCH 25/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 하단방향 오류 수정 --- src/hooks/module/useModuleBasicSetting.js | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 1d9c7d66..57218019 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1996,6 +1996,7 @@ export function useModuleBasicSetting(tabNum) { let flowLines let installedModuleMixYn const isNorthSurface = moduleSetupSurface.isNorth + const isIncludeNorthModule = checkedModule.some((module) => module.northModuleYn === 'Y') //체크된 모듈 중에 북면 모듈이 있는지 확인하는 로직 let layoutRow = 0 let layoutCol = 0 @@ -2342,15 +2343,7 @@ export function useModuleBasicSetting(tabNum) { //남, 북과 같은 로직으로 적용하려면 좌우는 열 -> 행 으로 그려야함 //변수명은 bottom 기준으로 작성하여 동일한 방향으로 진행한다 - const leftFlowSetupModule = ( - maxLengthLine, - moduleSetupArray, - moduleSetupSurface, - containsBatchObjects, - - intvHor, - intvVer, - ) => { + const leftFlowSetupModule = (maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, intvHor, intvVer) => { let setupModule = [] const trestleDetailData = moduleSetupSurface.trestleDetail //가대 상세 데이터 From 56b891734597a9e1409477f2a688007668780113 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Fri, 9 May 2025 15:48:08 +0900 Subject: [PATCH 26/45] =?UTF-8?q?[1014]=20:=20[819=E3=81=AE=E8=BF=BD?= =?UTF-8?q?=E5=8A=A0=E3=80=80=E3=83=AC=E3=82=A4=E3=82=A2=E3=82=A6=E3=83=88?= =?UTF-8?q?=E6=8C=87=E5=AE=9A=E9=85=8D=E7=BD=AE=E3=81=AE=E8=87=AA=E5=8B=95?= =?UTF-8?q?=E9=85=8D=E7=BD=AE]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 멀티모듈일 경우에 북면 모듈이 같이 계산되는 로직 수정 --- src/hooks/module/useModuleBasicSetting.js | 80 +++++++++++------------ 1 file changed, 37 insertions(+), 43 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 57218019..a3f2eb0e 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1902,57 +1902,51 @@ export function useModuleBasicSetting(tabNum) { return false } } else { - //북면 모듈이 1개만있을때 - if (checkedModule.length === 1) { - const maxRow = trestleDetailData.module.find((item) => item.moduleTpCd === checkedModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 + const normalModule = checkedModule.filter((item) => item.northModuleYn === 'N') + const northModule = checkedModule.filter((item) => item.northModuleYn === 'Y') + const northModuleIds = northModule.map((item) => item.itemId) + let isPassedNormalModule = false - //단수 합단수 - const sumRowCount = layoutSetupRef.find((item) => item.moduleId === checkedModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 - const sumColCount = layoutSetupRef.filter((item) => item.col).some((item) => item.col > maxCol) + //만약 북면 모듈이 2개면 이 하위 로직 가져다가 쓰면됨 northModule === 만 바꾸면 될듯 + // northModule을 배열로 만들고 include로 해서 체크 해야됨 + if (normalModule.length > 0 && !moduleSetupSurface.isNorth) { + //C1C2 모듈일 경우ㅁㅁ + const isMultipleModules = normalModule.length > 1 //모듈이 여러개면 + const maxRow = isMultipleModules + ? trestleDetailData.moduleMaxRows + : trestleDetailData.module.find((item) => item.moduleTpCd === normalModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - if (sumRowCount > maxRow || sumColCount) { + //북면 모듈 id를 제외한 모듈의 단 체크 + const sumRowCount = isMultipleModules + ? layoutSetupRef.filter((item) => item.checked && !northModuleIds.includes(item.moduleId)).reduce((acc, cur) => acc + cur.row, 0) + : layoutSetupRef.find((item) => item.moduleId === normalModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 + + //북면 모듈 id를 제외한 모듈의 열 체크 + const sumColCount = layoutSetupRef.filter((item) => item.col && !northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) + + // 혼합일때 모듈 개별의 row를 체크함 + const isPassedObject = + isMultipleModules && + layoutSetupRef.find( + (item, index) => item.checked && !item.moduleId.includes(northModuleIds) && item.row > trestleDetailData.module[index].mixModuleMaxRows, + ) + + // 합산 단수가 맥스단수보다 크거나 열이 맥스열수보다 크거나 혼합일때 모듈 개별의 row가 맥스단수보다 크면 실패 + if (sumRowCount > maxRow || sumColCount || isPassedObject) { failAutoSetupRoof.push(moduleSetupSurface) return false + } else { + isPassedNormalModule = true } - } else { - const normalModule = checkedModule.filter((item) => item.northModuleYn === 'N') - const northModule = checkedModule.filter((item) => item.northModuleYn === 'Y') - const northModuleIds = northModule.map((item) => item.itemId) - - //만약 북면 모듈이 2개면 이 하위 로직 가져다가 쓰면됨 northModule === 만 바꾸면 될듯 - // northModule을 배열로 만들고 include로 해서 체크 해야됨 - if (normalModule.length > 0 && !moduleSetupSurface.isNorth) { - //C1C2 모듈일 경우ㅁㅁ - const isMultipleModules = normalModule.length > 1 //모듈이 여러개면 - const maxRow = isMultipleModules - ? trestleDetailData.moduleMaxRows - : trestleDetailData.module.find((item) => item.moduleTpCd === normalModule[0].moduleTpCd).moduleMaxRows //멀티모듈이면 밖에 maxRows로 판단 아니면 module->itemmList를 가지고 판단 - - //북면 모듈 id를 제외한 모듈의 단 체크 - const sumRowCount = isMultipleModules - ? layoutSetupRef.filter((item) => item.checked && !northModuleIds.includes(item.moduleId)).reduce((acc, cur) => acc + cur.row, 0) - : layoutSetupRef.find((item) => item.moduleId === normalModule[0].itemId).row //멀티모듈이면 전체 합, 체크된 한개의 열 - - //북면 모듈 id를 제외한 모듈의 열 체크 - const sumColCount = layoutSetupRef.filter((item) => item.col && !northModuleIds.includes(item.moduleId)).some((item) => item.col > maxCol) - - // 혼합일때 모듈 개별의 row를 체크함 - const isPassedObject = - isMultipleModules && - layoutSetupRef.find( - (item, index) => - item.checked && !item.moduleId.includes(northModuleIds) && item.row > trestleDetailData.module[index].mixModuleMaxRows, - ) - - // 합산 단수가 맥스단수보다 크거나 열이 맥스열수보다 크거나 혼합일때 모듈 개별의 row가 맥스단수보다 크면 실패 - if (sumRowCount > maxRow || sumColCount || isPassedObject) { - failAutoSetupRoof.push(moduleSetupSurface) - return false - } - } + } + //위에서 일반 모듈이 설치가 완료면 그냥 넘어간다 + //일반 모듈이 pass라면 일반 모듈이 설치됨 + //만약 일반모듈이 체크가 안되어 있으면 밑에 로직을 탐 + if (!isPassedNormalModule) { //북면 모듈이 있고 북면에 있을때 if (northModule.length > 0 && (moduleSetupSurface.isNorth || !moduleSetupSurface.isNorth)) { + //북면 모듈이 있는데 일반 모듈이 있을때 북면이 아니면 그냥 북면은 그냥 pass const isMultipleModules = northModule.length > 1 //모듈이 여러개면 const maxRow = isMultipleModules ? trestleDetailData.moduleMaxRows From f03d35ec8db9bbcef240561fe5430139f177faf4 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 12 May 2025 11:11:09 +0900 Subject: [PATCH 27/45] =?UTF-8?q?[1037]=20:=20[=E3=83=A2=E3=82=B8=E3=83=A5?= =?UTF-8?q?=E3=83=BC=E3=83=AB1=E6=9E=9A=E3=82=92=E5=89=8A=E9=99=A4?= =?UTF-8?q?=E3=81=99=E3=82=8B=E6=99=82=E3=81=AE=E8=A1=A8=E7=A4=BA]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 모듈 선택시 아웃라인 두께 조정 --- src/hooks/useCanvasEvent.js | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 4a601ed8..22aad7cf 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -4,7 +4,7 @@ import { v4 as uuidv4 } from 'uuid' import { canvasSizeState, canvasState, canvasZoomState, currentMenuState, currentObjectState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' import { fontSelector } from '@/store/fontAtom' -import { MENU } from '@/common/common' +import { MENU, POLYGON_TYPE } from '@/common/common' // 캔버스에 필요한 이벤트 export function useCanvasEvent() { @@ -204,9 +204,12 @@ export function useCanvasEvent() { if (selected?.length > 0) { selected.forEach((obj) => { - if (obj.type === 'QPolygon' && currentMenu !== MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + // if (obj.type === 'QPolygon' && currentMenu !== MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + if (obj.type === 'QPolygon') { obj.set({ stroke: 'red' }) - obj.bringToFront() + if (obj.name === POLYGON_TYPE.MODULE && currentMenu === MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + obj.set({ strokeWidth: 3 }) + } } }) canvas.renderAll() @@ -218,10 +221,13 @@ export function useCanvasEvent() { if (deselected?.length > 0) { deselected.forEach((obj) => { - if (obj.type === 'QPolygon' && currentMenu !== MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + if (obj.type === 'QPolygon') { if (obj.name !== 'moduleSetupSurface') { obj.set({ stroke: 'black' }) } + if (obj.name === POLYGON_TYPE.MODULE && currentMenu === MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + obj.set({ strokeWidth: 0.3 }) + } } }) } @@ -234,17 +240,24 @@ export function useCanvasEvent() { if (deselected?.length > 0) { deselected.forEach((obj) => { - if (obj.type === 'QPolygon' && currentMenu !== MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + if (obj.type === 'QPolygon') { obj.set({ stroke: 'black' }) + if (obj.name === POLYGON_TYPE.MODULE && currentMenu === MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + //모듈 미선택시 라인 두께 변경 + obj.set({ strokeWidth: 0.3 }) + } } }) } if (selected?.length > 0) { selected.forEach((obj) => { - if (obj.type === 'QPolygon' && currentMenu !== MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + if (obj.type === 'QPolygon') { obj.set({ stroke: 'red' }) - obj.bringToFront() + if (obj.name === POLYGON_TYPE.MODULE && currentMenu === MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING) { + //모듈 선택시 라인 두께 변경 + obj.set({ strokeWidth: 3 }) + } } }) } From a652d09b8d7eb99f879f05d7a180d114e67bc91e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 13 May 2025 10:46:26 +0900 Subject: [PATCH 28/45] =?UTF-8?q?[1036]=20:=20[=E3=83=97=E3=83=A9=E3=83=B3?= =?UTF-8?q?=E3=82=92=E3=82=B3=E3=83=94=E3=83=BC/=E7=A7=BB=E5=8B=95?= =?UTF-8?q?=E3=81=99=E3=82=8B=E6=99=82=E3=81=AE=E8=87=AA=E5=8B=95=E4=BF=9D?= =?UTF-8?q?=E5=AD=98=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 탭간 이동, 복사시 저장 여부 확인 로직 추가 --- src/components/floor-plan/CanvasLayout.jsx | 2 +- .../floor-plan/modal/basic/step/Placement.jsx | 19 ++++----- src/hooks/useCanvasEvent.js | 12 +++++- src/hooks/usePlan.js | 40 +++++++++++++++---- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/src/components/floor-plan/CanvasLayout.jsx b/src/components/floor-plan/CanvasLayout.jsx index 059e96aa..cce79df2 100644 --- a/src/components/floor-plan/CanvasLayout.jsx +++ b/src/components/floor-plan/CanvasLayout.jsx @@ -37,7 +37,7 @@ export default function CanvasLayout({ children }) {
+
{getMessage('estimate.detail.header.singleCable')}
+
+
+
+
{getMessage('estimate.detail.header.doubleCable')}
+
+
@@ -1927,7 +1976,7 @@ export default function Estimate({}) { onChangeSelect(item.dispOrder)} checked={!!selection.has(item.dispOrder)} /> diff --git a/src/locales/ja.json b/src/locales/ja.json index 35f0b757..c59d0a16 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -944,6 +944,8 @@ "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG金額", "estimate.detail.header.showPrice": "価格表示", "estimate.detail.header.unitPrice": "定価", + "estimate.detail.header.singleCable": "片端ケーブル長さ", + "estimate.detail.header.doubleCable": "両端ケーブル長さ", "estimate.detail.showPrice.pricingBtn": "Pricing", "estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります。 Pricingを進めてください。", "estimate.detail.showPrice.pricingBtn.confirm": "価格登録初期化されますがよろしいですか?", diff --git a/src/locales/ko.json b/src/locales/ko.json index daf9ad60..3374c1b9 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -945,6 +945,8 @@ "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액", "estimate.detail.header.showPrice": "가격표시", "estimate.detail.header.unitPrice": "정가", + "estimate.detail.header.singleCable": "편당케이블 길이", + "estimate.detail.header.doubleCable": "양단케이블 길이", "estimate.detail.showPrice.pricingBtn": "Pricing", "estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. 제품 선택 후 Pricing을 진행해주세요.", "estimate.detail.showPrice.pricingBtn.confirm": "가격등록을 초기화 하시겠습니까?", From 5b322d0143a0aa0d800e7de76eeb6417b2b3e986 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 14 May 2025 14:06:45 +0900 Subject: [PATCH 39/45] feature/ysCha (#37) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [948] - 견적서 양단케이블 selectbox 추가 케이블 체크 가능. 단어 추가 --- src/components/estimate/Estimate.jsx | 75 +++++++++++++++++++++++----- src/locales/ja.json | 2 + src/locales/ko.json | 2 + 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 8ce54402..7237e056 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -60,7 +60,7 @@ export default function Estimate({}) { const [cableItemList, setCableItemList] = useState([]) //케이블 리스트 const [cableItem, setCableItem] = useState('') //케이블 선택값 - + const [cableDbItem, setCableDbItem] = useState('') //케이블 선택값 const [startDate, setStartDate] = useState(new Date()) const singleDatePickerProps = { startDate, @@ -98,7 +98,7 @@ export default function Estimate({}) { } const initEstimate = (currPid = currentPid) => { - console.log('🚀 ~ initEstimate ~ currPid:', currPid) + // console.log('🚀 ~ initEstimate ~ currPid:', currPid) closeAll() setObjectNo(objectRecoil.floorPlanObjectNo) @@ -117,6 +117,7 @@ export default function Estimate({}) { item.value = item.clRefChr1 item.label = item.clRefChr2 }) + // console.log(code2) setCableItemList(code2) } @@ -152,7 +153,7 @@ export default function Estimate({}) { } useEffect(() => { - console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan) + // console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan) if (selectedPlan) initEstimate(selectedPlan.planNo) }, [selectedPlan]) @@ -739,6 +740,18 @@ export default function Estimate({}) { setCableItem(value) } + /* 케이블 select 변경시 */ + const onChangeDisplayDoubleCableItem = (value, itemList) => { + itemList.map((item, index) => { + if (item.dispCableFlg === '1' && item.itemTpCd === 'M12') { + if (value !== '') { + onChangeDisplayItem(value, item.dispOrder, index, true) + } + } + }) + setCableDbItem(value) + } + // 아이템 자동완성 검색시 아이템 추가/변경시 const onChangeDisplayItem = (itemId, dispOrder, index, flag) => { const param = { @@ -1088,15 +1101,20 @@ export default function Estimate({}) { item.showSaleTotPrice = '0' } - if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12') { + if (item.dispCableFlg === '1' ) { dispCableFlgCnt++ - setCableItem(item.itemId) + if(item.itemTpCd === 'M12') { + setCableDbItem(item.itemId) + }else{ + setCableItem(item.itemId) + } } } }) if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0 @@ -1159,14 +1177,20 @@ export default function Estimate({}) { dispCableFlgCnt++ } - if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12') { - setCableItem(item.itemId) + if (item.dispCableFlg === '1'){ + + if(item.itemTpCd === 'M12') { + setCableDbItem(item.itemId) + }else{ + setCableItem(item.itemId) + } } } }) if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } totals.vatPrice = totals.supplyPrice * 0.1 @@ -1227,6 +1251,7 @@ export default function Estimate({}) { if (dispCableFlgCnt === 0) { setCableItem('100038') + setCableDbItem('100037') } } }, [estimateContextState?.itemList, cableItemList]) @@ -1831,6 +1856,7 @@ export default function Estimate({}) {
+
{getMessage('estimate.detail.header.singleCable')}
+
+
+
+
{getMessage('estimate.detail.header.doubleCable')}
+
+
@@ -1927,7 +1976,7 @@ export default function Estimate({}) { onChangeSelect(item.dispOrder)} checked={!!selection.has(item.dispOrder)} /> diff --git a/src/locales/ja.json b/src/locales/ja.json index 35f0b757..c59d0a16 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -944,6 +944,8 @@ "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG金額", "estimate.detail.header.showPrice": "価格表示", "estimate.detail.header.unitPrice": "定価", + "estimate.detail.header.singleCable": "片端ケーブル長さ", + "estimate.detail.header.doubleCable": "両端ケーブル長さ", "estimate.detail.showPrice.pricingBtn": "Pricing", "estimate.detail.showPrice.pricingBtn.noItemId": "Pricingが欠落しているアイテムがあります。 Pricingを進めてください。", "estimate.detail.showPrice.pricingBtn.confirm": "価格登録初期化されますがよろしいですか?", diff --git a/src/locales/ko.json b/src/locales/ko.json index daf9ad60..3374c1b9 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -945,6 +945,8 @@ "estimate.detail.sepcialEstimateProductInfo.pkgPrice": "PKG 금액", "estimate.detail.header.showPrice": "가격표시", "estimate.detail.header.unitPrice": "정가", + "estimate.detail.header.singleCable": "편당케이블 길이", + "estimate.detail.header.doubleCable": "양단케이블 길이", "estimate.detail.showPrice.pricingBtn": "Pricing", "estimate.detail.showPrice.pricingBtn.noItemId": "Pricing이 누락된 아이템이 있습니다. 제품 선택 후 Pricing을 진행해주세요.", "estimate.detail.showPrice.pricingBtn.confirm": "가격등록을 초기화 하시겠습니까?", From 80bf9263fdd5f2ae85eee3a86163ba0399bac9ea Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 14 May 2025 15:16:28 +0900 Subject: [PATCH 40/45] =?UTF-8?q?=3F=3F=20=3D>=20=3F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/ja.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/ja.json b/src/locales/ja.json index c59d0a16..57953508 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -346,9 +346,9 @@ "modal.actual.size.setting.not.exist.size": "実際の寸法の長さを入力してください", "modal.actual.size.setting.plane.size.length": "廊下寸法の長さ", "modal.actual.size.setting.actual.size.length": "実寸長", - "plan.message.confirm.save": "プラン保存しますか??", - "plan.message.confirm.copy": "プランコピーしますか??", - "plan.message.confirm.delete": "プラン削除しますか??", + "plan.message.confirm.save": "プラン保存しますか?", + "plan.message.confirm.copy": "プランコピーしますか?", + "plan.message.confirm.delete": "プラン削除しますか?", "plan.message.save": "保存されました。", "plan.message.delete": "削除されました。", "plan.message.leave": "物件状況(リスト)に移動しますか? [はい]を選択した場合は保存して移動します。", From 9609cad8f55fe5da7911ecaa74373337b30f4eda Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 14 May 2025 15:18:50 +0900 Subject: [PATCH 41/45] =?UTF-8?q?=3F=3F=20=3D>=20=3F=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed-on: https://git.hanasys.jp/qcast3/qcast-front/pulls/38 --- src/locales/ja.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/ja.json b/src/locales/ja.json index c59d0a16..57953508 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -346,9 +346,9 @@ "modal.actual.size.setting.not.exist.size": "実際の寸法の長さを入力してください", "modal.actual.size.setting.plane.size.length": "廊下寸法の長さ", "modal.actual.size.setting.actual.size.length": "実寸長", - "plan.message.confirm.save": "プラン保存しますか??", - "plan.message.confirm.copy": "プランコピーしますか??", - "plan.message.confirm.delete": "プラン削除しますか??", + "plan.message.confirm.save": "プラン保存しますか?", + "plan.message.confirm.copy": "プランコピーしますか?", + "plan.message.confirm.delete": "プラン削除しますか?", "plan.message.save": "保存されました。", "plan.message.delete": "削除されました。", "plan.message.leave": "物件状況(リスト)に移動しますか? [はい]を選択した場合は保存して移動します。", From e6da798e4300a6e9c3b4f1d351de4243e89efa2c Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 15 May 2025 14:13:06 +0900 Subject: [PATCH 42/45] fix: update API server path in development environment to use secure HTTPS URL --- .env.development | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env.development b/.env.development index d3e1ba88..f35f6208 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,4 @@ -NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" +NEXT_PUBLIC_API_SERVER_PATH="https://dev-api.hanasys.jp" NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000" From 59a55e4c881cc87d7f3d2d0ae8abd0aa16a62e95 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 16 May 2025 10:31:23 +0900 Subject: [PATCH 43/45] =?UTF-8?q?961=20:=20=EC=99=B8=EB=B2=BD=EC=84=A0=20?= =?UTF-8?q?=EA=B7=B8=EB=A6=AC=EA=B8=B0=20=EB=B0=8F=20=EB=B0=B0=EC=B9=98?= =?UTF-8?q?=EB=A9=B4=20=EA=B7=B8=EB=A6=AC=EA=B8=B0=EC=97=90=20=EB=8C=80?= =?UTF-8?q?=ED=95=B4=EC=84=9C=E3=80=80=E5=A4=96=E5=A3=81=E7=B7=9A=E3=82=92?= =?UTF-8?q?=E6=8F=8F=E3=81=8F=E3=83=BB=E9=85=8D=E7=BD=AE=E9=9D=A2=E3=81=AE?= =?UTF-8?q?=E6=8F=8F=E7=94=BB=E3=81=AB=E3=81=A4=E3=81=84=E3=81=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. "외벽선 그리기", "배치면 그리기"에서 선을 그을때 우클릭으로 "undo" 할 수 있도록 해주세요. 2. 마찬가지로 "외벽선 그리기", "배치면 그리기"로 지붕면을 확정할 때 Enter Key로 지붕면을 확정할 수 있도록 해주시기 바랍니다. --- src/hooks/roofcover/useOuterLineWall.js | 7 +++++++ src/hooks/surface/usePlacementShapeDrawing.js | 19 ++++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js index 18a07cf8..9ca76ea5 100644 --- a/src/hooks/roofcover/useOuterLineWall.js +++ b/src/hooks/roofcover/useOuterLineWall.js @@ -96,6 +96,10 @@ export function useOuterLineWall(id, propertiesId) { } addCanvasMouseEventListener('mouse:down', mouseDown) + addDocumentEventListener('contextmenu', document, (e) => { + handleRollback() + }) + clear() return () => { initEvent() @@ -690,6 +694,9 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } + if (e.key === 'Enter') { + handleFix() + } // 포커스가 length1에 있지 않으면 length1에 포커스를 줌 const activeElem = document.activeElement if (activeElem !== length1Ref.current) { diff --git a/src/hooks/surface/usePlacementShapeDrawing.js b/src/hooks/surface/usePlacementShapeDrawing.js index d53faa39..be23cd7c 100644 --- a/src/hooks/surface/usePlacementShapeDrawing.js +++ b/src/hooks/surface/usePlacementShapeDrawing.js @@ -92,6 +92,9 @@ export function usePlacementShapeDrawing(id) { } addCanvasMouseEventListener('mouse:down', mouseDown) + addDocumentEventListener('contextmenu', document, (e) => { + handleRollback() + }) clear() }, [verticalHorizontalMode, points, adsorptionPointAddMode, adsorptionPointMode, adsorptionRange, interval, tempGridMode]) @@ -175,7 +178,7 @@ export function usePlacementShapeDrawing(id) { } } -/* + /* mouseMove */ const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) @@ -184,7 +187,7 @@ mouseMove const { getAdsorptionPoints } = useAdsorptionPoint() const mouseMove = (e) => { - removeMouseLine(); + removeMouseLine() const pointer = canvas.getPointer(e.e) const roofsPoints = roofs.map((roof) => roof.points).flat() roofAdsorptionPoints.current = [...roofsPoints] @@ -246,7 +249,6 @@ mouseMove }) canvas?.add(horizontalLine, verticalLine) canvas?.renderAll() - } useEffect(() => { @@ -768,6 +770,7 @@ mouseMove if (points.length === 0) { return } + enterCheck(e) // 포커스가 length1에 있지 않으면 length1에 포커스를 줌 const activeElem = document.activeElement @@ -833,6 +836,7 @@ mouseMove if (points.length === 0) { return } + enterCheck(e) const key = e.key const activeElem = document.activeElement @@ -866,6 +870,7 @@ mouseMove if (points.length === 0) { return } + enterCheck(e) const key = e.key switch (key) { case 'Down': // IE/Edge에서 사용되는 값 @@ -891,6 +896,7 @@ mouseMove if (points.length === 0) { return } + enterCheck(e) const key = e.key switch (key) { case 'Enter': { @@ -915,6 +921,7 @@ mouseMove if (points.length === 0) { return } + enterCheck(e) const key = e.key switch (key) { @@ -979,6 +986,12 @@ mouseMove isFix.current = true } + const enterCheck = (e) => { + if (e.key === 'Enter') { + handleFix() + } + } + return { points, setPoints, From 46f9385163be4096114cf7892bfe10c14c3068d8 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Fri, 16 May 2025 10:37:30 +0900 Subject: [PATCH 44/45] =?UTF-8?q?enterCheck=20=EC=A0=84=EB=B6=80=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/roofcover/useOuterLineWall.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/hooks/roofcover/useOuterLineWall.js b/src/hooks/roofcover/useOuterLineWall.js index 9ca76ea5..302a4c9a 100644 --- a/src/hooks/roofcover/useOuterLineWall.js +++ b/src/hooks/roofcover/useOuterLineWall.js @@ -694,9 +694,7 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } - if (e.key === 'Enter') { - handleFix() - } + enterCheck(e) // 포커스가 length1에 있지 않으면 length1에 포커스를 줌 const activeElem = document.activeElement if (activeElem !== length1Ref.current) { @@ -761,6 +759,7 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } + enterCheck(e) const key = e.key const activeElem = document.activeElement @@ -794,6 +793,7 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } + enterCheck(e) const key = e.key switch (key) { case 'Down': // IE/Edge에서 사용되는 값 @@ -819,6 +819,7 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } + enterCheck(e) const key = e.key switch (key) { case 'Enter': { @@ -843,7 +844,7 @@ export function useOuterLineWall(id, propertiesId) { if (points.length === 0) { return } - + enterCheck(e) const key = e.key switch (key) { case 'Down': // IE/Edge에서 사용되는 값 @@ -909,6 +910,12 @@ export function useOuterLineWall(id, propertiesId) { isFix.current = true } + const enterCheck = (e) => { + if (e.key === 'Enter') { + handleFix() + } + } + return { points, setPoints, From 97d20321ed0ed9df6719e98e56ec0d0e4ad40f9b Mon Sep 17 00:00:00 2001 From: yjnoh Date: Mon, 19 May 2025 10:29:49 +0900 Subject: [PATCH 45/45] =?UTF-8?q?[1049]=20:=20[=E6=96=87=E5=AD=97=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : 번역 작업 진행 --- src/locales/ja.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/ja.json b/src/locales/ja.json index 57953508..6eef1edc 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -125,9 +125,9 @@ "modal.module.basic.settting.module.error6": "垂木の間隔を入力してください。\n(屋根材: {0})", "modal.module.basic.settting.module.error7": "下在ビーチを入力してください。\n(屋根材: {0})", "modal.module.basic.settting.module.error8": "モジュール配置領域の値を入力してください。\n(屋根材: {0})", - "modal.module.basic.settting.module.error9": "軒側の値は{0} mm以上でなければなりません。\n(屋根材: {1})", - "modal.module.basic.settting.module.error10": "吊下側の値は{0} mm以上でなければなりません。\n(屋根材: {1})", - "modal.module.basic.settting.module.error11": "ケラバ側の値は{0} mm以上でなければなりません。\n(屋根材: {1})", + "modal.module.basic.settting.module.error9": "軒側の配置領域の値を{0} mm以上に変更してください。\n(屋根材: {1})", + "modal.module.basic.settting.module.error10": "棟側の配置領域の値を{0} mm上に変更してください。\n(屋根材: {1})", + "modal.module.basic.settting.module.error11": "ケラバ側の配置領域の値を{0} mm上に変更してください。\n(屋根材: {1})", "modal.module.basic.settting.module.error12": "施工方法を選択してください。\n(屋根材: {0})", "modal.module.basic.setting.module.placement": "モジュールの配置", "modal.module.basic.setting.module.placement.select.fitting.type": "設置形態を選択してください。", @@ -786,7 +786,7 @@ "stuff.search.schObjectNo": "物件番号", "stuff.search.schSaleStoreName": "販売代理店名", "stuff.search.schAddress": "商品アドレス", - "stuff.search.schObjectName": "商品名", + "stuff.search.schObjectName": "物件名", "stuff.search.schDispCompanyName": "見積先", "stuff.search.schSelSaleStoreId": "販売代理店選択", "stuff.search.schReceiveUser": "担当者",