Compare commits

..

No commits in common. "feature/jimp-test" and "main" have entirely different histories.

149 changed files with 4612 additions and 15345 deletions

View File

@ -1,32 +1,11 @@
NEXT_PUBLIC_RUN_MODE="development"
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"
NEXT_PUBLIC_API_HOST_URL="https://dev.hanasys.jp"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
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"
# 테스트용
# 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="//files.hanasys.jp"
S3_PROFILE="dev"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"

View File

@ -1,32 +0,0 @@
NEXT_PUBLIC_RUN_MODE="local.dev"
NEXT_PUBLIC_API_SERVER_PATH="https://dev-api.hanasys.jp"
NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000"
NEXT_PUBLIC_API_HOST_URL="http://1.248.227.176:5000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
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-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="//files.hanasys.jp"
S3_PROFILE="dev"

View File

@ -1,32 +0,0 @@
NEXT_PUBLIC_RUN_MODE="local"
NEXT_PUBLIC_API_SERVER_PATH="https://dev-api.hanasys.jp"
NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000"
NEXT_PUBLIC_API_HOST_URL="http://localhost:3000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
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-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="//files.hanasys.jp"
S3_PROFILE="dev"

View File

@ -1,33 +1,13 @@
NEXT_PUBLIC_RUN_MODE="production"
NEXT_PUBLIC_API_SERVER_PATH="https://api.hanasys.jp/"
NEXT_PUBLIC_HOST_URL="//1.248.227.176:4000"
NEXT_PUBLIC_API_HOST_URL="https://www.hanasys.jp"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"
SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
# 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"
# 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="//files.hanasys.jp"
# 실제 일본 서버
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="//files.hanasys.jp"
S3_PROFILE="prd"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"

View File

@ -1,3 +0,0 @@
[일감번호] : [제목]
[작업내용] :

View File

@ -34,5 +34,3 @@ You can check out [the Next.js GitHub repository](https://github.com/vercel/next
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.
deploy test

View File

@ -1,13 +0,0 @@
module.exports = {
apps: [
{
name: 'qcast-front-development',
script: 'node_modules/next/dist/bin/next',
instances: 1,
exec_mode: 'fork',
env: {
PORT: 5010,
},
},
],
}

View File

@ -1,13 +0,0 @@
module.exports = {
apps: [
{
name: 'qcast-front-local-development',
script: 'node_modules/next/dist/bin/next',
instances: 1,
exec_mode: 'fork',
env: {
PORT: 5000,
},
},
],
}

View File

@ -1,13 +0,0 @@
module.exports = {
apps: [
{
name: 'qcast-front-production',
script: 'node_modules/next/dist/bin/next',
instances: 2,
exec_mode: 'cluster',
env: {
NODE_ENV: 'production',
},
},
],
}

View File

@ -3,34 +3,27 @@
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "env-cmd -f .env.localhost next dev",
"local:dev": "env-cmd -f .env.local.dev next dev",
"build": "env-cmd -f .env.production next build",
"build:dev": "env-cmd -f .env.development next build",
"build:local.dev": "env-cmd -f .env.local.dev next build",
"start:cluster1": "env-cmd -f .env.production next start -p 5000",
"start:cluster2": "env-cmd -f .env.production next start -p 5001",
"start:dev": "env-cmd -f .env.development next start -p 5010",
"dev": "next dev",
"build": "next build",
"start": "next start -p 5000",
"start:dev": "next start -p 5010",
"lint": "next lint",
"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",
"chart.js": "^4.4.6",
"dayjs": "^1.11.13",
"env-cmd": "^10.1.0",
"fabric": "^5.3.0",
"framer-motion": "^11.2.13",
"fs": "^0.0.1-security",
"iron-session": "^8.0.2",
"jimp": "^1.6.0",
"js-cookie": "^3.0.5",
"mathjs": "^13.0.2",
"mssql": "^11.0.1",
"next": "14.2.28",
"next": "14.2.21",
"next-international": "^1.2.4",
"react": "^18",
"react-chartjs-2": "^5.2.0",
@ -44,7 +37,6 @@
"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",

View File

@ -1,13 +0,0 @@
module.exports = {
apps: [
{
name: 'qcast-front-production-1',
script: 'node_modules/next/dist/bin/next',
instances: 1,
exec_mode: 'fork',
env: {
PORT: 5000,
},
},
],
}

View File

@ -1,13 +0,0 @@
module.exports = {
apps: [
{
name: 'qcast-front-production-2',
script: 'node_modules/next/dist/bin/next',
instances: 1,
exec_mode: 'fork',
env: {
PORT: 5001,
},
},
],
}

View File

@ -1,3 +0,0 @@
<svg width="16" height="14" viewBox="0 0 16 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M8 0L15.7942 13.5H0.205771L8 0Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

@ -1,4 +0,0 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="8.25" stroke="#101010" stroke-width="1.5"/>
<path d="M7.94995 16.5C10.0485 14.302 13.9289 14.1986 16.05 16.5M14.2455 9.75C14.2455 10.9926 13.2367 12 11.9923 12C10.7479 12 9.73912 10.9926 9.73912 9.75C9.73912 8.50736 10.7479 7.5 11.9923 7.5C13.2367 7.5 14.2455 8.50736 14.2455 9.75Z" stroke="#101010" stroke-width="1.5" stroke-linecap="round"/>
</svg>

Before

Width:  |  Height:  |  Size: 474 B

Binary file not shown.

View File

@ -1,13 +1,21 @@
'use client'
import { createContext, useState } from 'react'
import { createContext, useEffect, useState } from 'react'
import { useLocalStorage } from 'usehooks-ts'
export const GlobalDataContext = createContext(null)
const GlobalDataProvider = ({ children }) => {
const [managementState, setManagementState] = useState(null)
const [managementStateLoaded, setManagementStateLoaded] = useLocalStorage('managementStateLoaded', null)
return <GlobalDataContext.Provider value={{ managementState, setManagementState }}>{children}</GlobalDataContext.Provider>
useEffect(() => {
if (managementState !== null) {
setManagementStateLoaded(managementState)
}
}, [managementState])
return <GlobalDataContext.Provider value={{ managementState, setManagementState, managementStateLoaded }}>{children}</GlobalDataContext.Provider>
}
export default GlobalDataProvider

View File

@ -1,70 +0,0 @@
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) => {
console.log('🚀 ~ uploadImage ~ file:', file)
const Body = Buffer.from(await file.arrayBuffer())
const Key = `cads/${file.name}`
const ContentType = 'image/png'
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)
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 })
}
}

View File

@ -1,149 +0,0 @@
import { NextResponse } from 'next/server'
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { v4 as uuidv4 } from 'uuid'
import { Jimp } from 'jimp'
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 {
// Get the image from S3
const { Body } = await s3.send(
new GetObjectCommand({
Bucket,
Key,
}),
)
const chunks = []
for await (const chunk of Body) {
chunks.push(chunk)
}
const buffer = Buffer.concat(chunks)
const image = await Jimp.read(buffer)
image.autocrop({ tolerance: 0.0002, leaveBorder: 10 })
return await image.getBuffer('image/png')
// Convert stream to buffer
// const chunks = []
// for await (const chunk of Body) {
// chunks.push(chunk)
// }
// const imageBuffer = Buffer.concat(chunks)
// const image = await Jimp.read(Body)
// if (!checkResult) {
// processedImage = await image.toBuffer()
// }
//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()}`
/**
* 원본 이미지를 우선 저장한다.
* 이미지 이름이 겹지는 현상을 방지하기 위해 uuid 사용한다.
*/
await s3.send(
new PutObjectCommand({
Bucket,
Key: OriginalKey,
Body: Buffer.from(await file.arrayBuffer()),
ContentType: 'image/png',
}),
)
/**
* 저장된 원본 이미지를 기준으로 크롭여부를 결정하여 크롭 이미지를 저장한다.
*/
const bufferImage = await cropImage(OriginalKey, width, height, left, top)
/**
* 크롭 이미지 이름을 결정한다.
*/
const Key = `Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_${type}.png`
/**
* 크롭이 완료된 이미지를 업로드한다.
*/
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 })
}
}

View File

@ -1,59 +0,0 @@
import { NextResponse } from 'next/server'
import { S3Client, CopyObjectCommand, 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,
},
})
export async function POST(req) {
const { objectNo, planNo, newObjectNo, newPlanNo } = await req.json()
const responseArray = []
//견적서1 번 이미지
const isExistImage1 = await s3.send(
new GetObjectCommand({
Bucket,
Key: `Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_1.png`,
}),
)
//견적서2 번 이미지
const isExistImage2 = await s3.send(
new GetObjectCommand({
Bucket,
Key: `Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_2.png`,
}),
)
//견적서1,2 번 이미지 둘다 있어야함
if (isExistImage1.$metadata.httpStatusCode === 200 && isExistImage2.$metadata.httpStatusCode === 200) {
//견적서1 번 이미지 복사
const copyCommand = new CopyObjectCommand({
Bucket,
CopySource: encodeURI(`${Bucket}/Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_1.png`),
Key: `Drawing/${process.env.S3_PROFILE}/${newObjectNo}_${newPlanNo}_1.png`,
})
const response = await s3.send(copyCommand)
const copyCommand2 = new CopyObjectCommand({
Bucket,
CopySource: encodeURI(`${Bucket}/Drawing/${process.env.S3_PROFILE}/${objectNo}_${planNo}_2.png`),
Key: `Drawing/${process.env.S3_PROFILE}/${newObjectNo}_${newPlanNo}_2.png`,
})
const response2 = await s3.send(copyCommand2)
responseArray.push(response, response2)
return NextResponse.json({ message: '견적서 이미지 복사 성공', responseArray }, { status: 200 })
} else {
return NextResponse.json({ message: '견적서 이미지 복사 실패(존재하지 않는 이미지)', responseArray }, { status: 400 })
}
}

View File

@ -1,78 +0,0 @@
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 {
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 = `maps/${fileNm}`
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 = `maps/${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 })
}
}

View File

@ -1,72 +0,0 @@
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 = `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 fileName = searchParams.get('fileName')
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,
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 })
}
}

View File

@ -1,9 +0,0 @@
import Qna from '@/components/community/Qna'
export default async function CommunityQnaPage() {
return (
<>
<Qna />
</>
)
}

View File

@ -45,19 +45,8 @@ const FloorPlanProvider = ({ children }) => {
// const pathname = usePathname()
// const setCorrentObjectNo = useSetRecoilState(correntObjectNoState)
const searchParams = useSearchParams()
const path = usePathname()
const objectNo = searchParams.get('objectNo')
const pid = searchParams.get('pid')
useEffect(() => {
setFloorPlanState((prev) => {
return {
...prev,
objectNo,
pid,
}
})
}, [path])
// useEffect(() => {
// console.log('🚀 ~ useEffect ~ objectNo:')
// if (pathname === '/floor-plan') {

View File

@ -21,8 +21,8 @@ import GlobalLoadingProvider from './GlobalLoadingProvider'
* 서버 컴포넌트에 한해서 개별로 설정할 있음
*/
export const metadata = {
title: 'HANASYS DESIGN',
description: 'HANASYS DESIGN',
title: 'HANASYS設計',
description: 'HANASYS設計',
}
/**
@ -58,7 +58,6 @@ export default async function RootLayout({ children }) {
pwdInitYn: session.pwdInitYn,
custCd: session.custCd,
isLoggedIn: session.isLoggedIn,
builderNo: session.builderNo
}
}
if (!headerPathname.includes('/login') && !session.isLoggedIn) {

View File

@ -125,11 +125,6 @@ export const TRESTLE_MATERIAL = {
BRACKET: 'bracket',
}
export const MODULE_SETUP_TYPE = {
LAYOUT: 'layout',
AUTO: 'auto',
}
export const SAVE_KEY = [
'selectable',
'name',
@ -208,10 +203,6 @@ export const SAVE_KEY = [
'fontWeight',
'dormerAttributes',
'toFixed',
'startPoint',
'endPoint',
'editable',
'isSortedPoints',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -14,7 +14,6 @@ import { sessionStore } from '@/store/commonAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import BoardDetailModal from './community/modal/BoardDetailModal'
import Config from '@/config/config.export'
export default function MainPage() {
const [sessionState, setSessionState] = useRecoilState(sessionStore)

View File

@ -2,111 +2,26 @@
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { setSession, login } from '@/lib/authActions'
import { sessionStore } from '@/store/commonAtom'
import { useRecoilState } from 'recoil'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { useRouter } from 'next/navigation'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
export default function AutoLoginPage({ autoLoginParam }) {
const router = useRouter()
const [isLoading, setIsLoading] = useState(autoLoginParam === 'Y' ? false : true)
const [globalLocaleState, setGlbalLocaleState] = useRecoilState(globalLocaleStore)
const { promisePost } = useAxios(globalLocaleState)
export default function AutoLoginPage() {
const [isLoading, setIsLoading] = useState(true)
const { getMessage } = useMessage()
const [userId, setUserId] = useState('')
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const [idFocus, setIdFocus] = useState(false)
const loginProcess = async () => {
setIsLoading(true)
await promisePost({ url: '/api/login/v1.0/user', data: { loginId: userId } }).then((response) => {
setIsLoading(false)
if (response.data) {
const res = response.data
const result = { ...res, storeLvl: res.groupId === '60000' ? '1' : '2', pwdInitYn: 'Y' }
setSession(result)
setSessionState(result)
login()
} else {
alert(getMessage('login.fail'))
router.push('/login?autoLoginParam1=Y')
}
})
}
return (
<>
{isLoading && <GlobalSpinner />}
{autoLoginParam !== 'Y' ? (
<>
<div className="login-input-frame">
<div className="login-frame-tit ">
<span>{getMessage('site.name')}</span>
{getMessage('site.sub_name')}
</div>
<div className="login-input-wrap">
<div className="login-area id" style={{ fontWeight: 'bolder' }}>
{getMessage('login.auto.page.text')}
</div>
</div>
<div className="login-input-frame">
<div className="login-frame-tit ">
<span>{getMessage('site.name')}</span>
{getMessage('site.sub_name')}
</div>
<div className="login-input-wrap">
<div className="login-area id" style={{ fontWeight: 'bolder' }}>
{getMessage('login.auto.page.text')}
</div>
</>
) : (
<>
<div className="login-input-frame">
<form
onSubmit={(e) => {
e.preventDefault()
loginProcess()
}}
className="space-y-6"
>
<div className="login-frame-tit">
<span>{getMessage('site.name')}</span>
{getMessage('site.sub_name')}
</div>
<div className="login-input-wrap">
<div className={`login-area id ${idFocus ? 'focus' : ''}`}>
<input
type="text"
className="login-input"
id="userId"
name="id"
required
value={userId}
placeholder={getMessage('login.id.placeholder')}
onChange={(e) => {
setUserId(e.target.value)
}}
onFocus={() => setIdFocus(true)}
onBlur={() => setIdFocus(false)}
/>
<button
type="button"
className="id-delete"
onClick={(e) => {
setUserId('')
}}
></button>
</div>
<div className="login-btn-box">
<button type="submit" className="login-btn">
{getMessage('login')}
</button>
</div>
</div>
</form>
</div>
</>
)}
</div>
</div>
</>
)
}

View File

@ -25,9 +25,7 @@ export default function Login() {
useEffect(() => {
if (autoLoginParam) {
if (autoLoginParam !== 'Y') {
autoLoginProcess(autoLoginParam)
}
autoLoginProcess(autoLoginParam)
}
// console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
@ -336,7 +334,7 @@ export default function Login() {
</div>
</>
)}
{autoLoginParam && <AutoLogin autoLoginParam={autoLoginParam} />}
{autoLoginParam && <AutoLogin />}
</div>
<div className="login-copyright">COPYRIGHT©2024 Hanwha Japan All Rights Reserved.</div>
</div>

View File

@ -6,19 +6,29 @@ import { contextMenuListState, contextMenuState } from '@/store/contextMenu'
import { useTempGrid } from '@/hooks/useTempGrid'
import { useContextMenu } from '@/hooks/useContextMenu'
import { useEvent } from '@/hooks/useEvent'
import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { canvasState } from '@/store/canvasAtom'
export default function QContextMenu(props) {
const canvas = useRecoilValue(canvasState)
const { contextRef, canvasProps } = props
const [contextMenu, setContextMenu] = useRecoilState(contextMenuState)
const contextMenuList = useRecoilValue(contextMenuListState)
const currentObject = useRecoilValue(currentObjectState)
const activeObject = canvasProps?.getActiveObject() //
const { tempGridMode, setTempGridMode } = useTempGrid()
const { handleKeyup } = useContextMenu()
const { addDocumentEventListener, removeDocumentEvent } = useEvent()
// const { addDocumentEventListener, removeDocumentEvent } = useContext(EventContext)
let contextType = ''
if (activeObject) {
if (activeObject.initOptions && activeObject.initOptions.name) {
//
if (activeObject.initOptions?.name?.indexOf('guide') > -1) {
contextType = 'surface' //
}
}
}
const getYPosition = (e) => {
const contextLength = contextMenuList.reduce((acc, cur, index) => {
return acc + cur.length
@ -26,13 +36,11 @@ export default function QContextMenu(props) {
return e?.clientY - (contextLength * 25 + contextMenuList.length * 2 * 17)
}
const handleContextMenu = (e) => {
// e.preventDefault() // contextmenu
if (currentObject) {
const isArray = currentObject.hasOwnProperty('arrayData')
if (isArray && currentObject.arrayData.length === 0) return
useEffect(() => {
if (!contextRef.current) return
const handleContextMenu = (e) => {
e.preventDefault() // contextmenu
if (tempGridMode) return
const position = {
x: window.innerWidth / 2 < e.pageX ? e.pageX - 240 : e.pageX,
@ -40,24 +48,21 @@ export default function QContextMenu(props) {
}
setContextMenu({ visible: true, ...position, currentMousePos: canvasProps.getPointer(e) })
addDocumentEventListener('keyup', document, handleKeyup)
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
}
}
const handleClick = (e) => {
// e.preventDefault()
setContextMenu({ ...contextMenu, visible: false })
}
const handleOutsideClick = (e) => {
// e.preventDefault()
if (contextMenu.visible) {
const handleClick = (e) => {
// e.preventDefault()
setContextMenu({ ...contextMenu, visible: false })
removeDocumentEvent('keyup')
}
}
useEffect(() => {
if (!contextRef.current) return
const handleOutsideClick = (e) => {
// e.preventDefault()
if (contextMenu.visible) {
setContextMenu({ ...contextMenu, visible: false })
removeDocumentEvent('keyup')
}
}
canvasProps?.upperCanvasEl.addEventListener('contextmenu', handleContextMenu)
document.addEventListener('click', handleClick)
@ -67,9 +72,43 @@ export default function QContextMenu(props) {
removeDocumentEvent('keyup')
document.removeEventListener('click', handleClick)
document.removeEventListener('click', handleOutsideClick)
canvasProps?.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //
}
}, [contextRef, contextMenuList, currentObject])
}, [contextRef, contextMenuList])
const handleObjectMove = () => {
activeObject.set({
lockMovementX: false, // X
lockMovementY: false, // Y
})
canvasProps?.on('object:modified', function (e) {
activeObject.set({
lockMovementX: true, // X
lockMovementY: true, // Y
})
})
}
const handleObjectDelete = () => {
if (confirm('삭제하실거?')) {
canvasProps.remove(activeObject)
}
}
const handleObjectCopy = () => {
activeObject.clone((cloned) => {
cloned.set({
left: activeObject.left + activeObject.width + 20,
initOptions: { ...activeObject.initOptions },
lockMovementX: true, // X
lockMovementY: true, // Y
lockRotation: true, //
lockScalingX: true, // X
lockScalingY: true, // Y
})
canvasProps?.add(cloned)
})
}
return (
<>

View File

@ -26,7 +26,6 @@ export default function QSelectBox({
targetKey = '',
showKey = '',
params = {},
tagTitle = '',
}) {
const { getMessage } = useMessage()
@ -40,7 +39,7 @@ export default function QSelectBox({
if (showKey !== '' && !value) {
//value showKey
// return options[0][showKey]
return title !== '' ? title : getMessage('selectbox.title')
return title
} else if (showKey !== '' && value) {
//value sourceKey targetKey
@ -83,13 +82,12 @@ export default function QSelectBox({
className={`sort-select ${openSelect ? 'active' : ''} ${disabled ? 'disabled' : ''}`}
ref={ref}
onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}
title={tagTitle}
>
<p>{selected}</p>
<ul className="select-item-wrap">
{options?.length > 0 &&
options?.map((option, index) => (
<li key={option.id + '_' + index} className="select-item" onClick={() => handleClickSelectOption(option)}>
<li key={option.id || index} className="select-item" onClick={() => handleClickSelectOption(option)}>
<button key={option.id + 'btn'}>{showKey !== '' ? option[showKey] : option.name}</button>
</li>
))}

View File

@ -1,212 +0,0 @@
'use client'
import Link from 'next/link'
import Image from 'next/image'
import Search from '@/components/community/Search'
import Pagination from '@/components/community/Pagination'
import { useContext } from 'react'
import { useEffect, useState } from 'react'
import { useResetRecoilState, useRecoilValue, useRecoilState } from 'recoil'
import { useMessage } from '@/hooks/useMessage'
import { searchState } from '@/store/boardAtom'
import { QcastContext } from '@/app/QcastProvider'
import QnaBoardDetailModal from '@/components/community/modal/QnaDetailModal'
import { sessionStore } from '@/store/commonAtom'
import { useAxios } from '@/hooks/useAxios'
import { useCommonCode } from '@/hooks/common/useCommonCode'
export default function Qna() {
const { getMessage } = useMessage()
const resetSearch = useResetRecoilState(searchState)
const [isInitialized, setIsInitialized] = useState(false)
//const search = useRecoilValue(searchState)
const [searchForm, setSearchForm] = useRecoilState(searchState)
const { findCommonCode } = useCommonCode()
const { setIsGlobalLoading } = useContext(QcastContext)
const { get } = useAxios()
const [boardList, setBoardList] = useState([])
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const [search, setSearch] = useRecoilState(searchState)
//
const [open, setOpen] = useState(false)
const [modalQnaNo, setModalQnaNo] = useState('')
const [modalQnaType, setModalQnaType] = useState('')
//
useEffect(() => {
async function fetchData() {
setIsGlobalLoading(true)
const startRow = (search.currentPage - 1) * search.pageBlock > 0 ? (search.currentPage - 1) * search.pageBlock + 1 : 1
const endRow = search.currentPage * search.pageBlock
const url = `/api/board/list`
const params = new URLSearchParams({
schNoticeTpCd : 'QC',
schNoticeClsCd: 'QNA',
compCd : 5200,
storeId : sessionState.storeId,
loginId : sessionState.userId,
schTitle : search.searchValue ? search.searchValue : '',
startRow : startRow,
endRow : endRow,
schMainYn : 'N',
siteTpCd : 'QC',
})
const apiUrl = `${url}?${params.toString()}`
const resultData = await get({ url: apiUrl })
if (resultData) {
if (resultData.result.code === 200) {
if (resultData.data.length > 0) {
setBoardList(resultData.data)
setSearch({ ...search, totalCount: resultData.data[0].totCnt })
} else {
setBoardList([])
setSearch({ ...search, totalCount: 0 })
}
} else {
alert(resultData.result.message)
}
}
setIsGlobalLoading(false)
}
fetchData()
}, [search.currentPage, search.searchValue, search.pageBlock, search.searchFlag])
useEffect(() => {
if (search.mainFlag === 'N') {
resetSearch()
} else {
// FAQ
setIsGlobalLoading(false)
setSearchForm({ ...searchForm, mainFlag: 'N' })
}
setIsInitialized(true)
//
// const codeL = findCommonCode(204200)
// const codeM = findCommonCode(204300)
// const codeS = findCommonCode(204400)
}, [])
if (!isInitialized) {
return null
}
const boardType = {
boardTitle: getMessage('qna.title'),
subTitle: getMessage('qna.sub.title'),
clsCode: 'QNA',
}
return (
<>
<div className="sub-header">
<div className="sub-header-inner">
<ul className="sub-header-title-wrap">
<li className="title-item">
<Link className="sub-header-title" href={'#'}>
{getMessage('qna.title')}
</Link>
</li>
</ul>
<ul className="sub-header-location">
<li className="location-item">
<span className="home">
<Image src="/static/images/main/home_icon.svg" alt="react" width={16} height={16} />
</span>
</li>
<li className="location-item">
<span>{getMessage('header.menus.community')}</span>
</li>
<li className="location-item">
<span>{getMessage('qna.title')}</span>
</li>
</ul>
</div>
</div>
<div className="sub-content">
<div className="sub-content-inner">
<div className="sub-table-box">
<Search title={boardType.boardTitle} subTitle={boardType.subTitle} isSelectUse={true} clsCode={boardType.clsCode} />
{/*<QnaTable clsCode={boardType.clsCode} />*/}
<div className="community-table">
<table>
<colgroup>
<col width={100}/>
<col width={150}/>
<col />
<col width={150}/>
<col width={150}/>
</colgroup>
<tbody>
{boardList.length > 0 ? (
boardList?.map((board) => (
<tr
key={board.qnaNo}
onClick={() => {
setOpen(true)
setModalQnaNo(board.qnaNo)
setModalQnaType("["+board?.qnaClsLrgCd+"/"+board?.qnaClsMidCd+"/"+board?.qnaClsSmlCd+"]")
}}
>
<td className="al-c">
{/* 번호 */}
{board.totCnt - board.rowNumber + 1}
</td>
{/* 답변 */}
{board?.answerYn === 'Y'? (<td className="al-c "> {getMessage('qna.list.header.answer.yes')}</td>) : (<td className="al-c org"> {getMessage('qna.list.header.answer.no')}</td>)}
<td>
<div className="mb5">[{board?.qnaClsLrgCd} / {board?.qnaClsMidCd} / {board?.qnaClsSmlCd}]</div>
{/* 제목 */}
<div className="text-frame">
<div className="text-overflow">{board.title}{board.qstTitle}</div>
{board.attachYn === 'Y' && <span className="clip"></span>}
</div>
</td>
<td>
<div className="renewal">
{/*{board.uptDt && (*/}
{/* <>*/}
{/* (<span>{getMessage('board.uptDt')}</span> : {board.uptDt})*/}
{/* </>*/}
{/*)}*/}
{board.regUserNm}
</div>
</td>
<td className="al-c">
{/* 등록일 */}
{board.regDt.split(' ')[0]}
</td>
</tr>
))
) : (
<tr>
<td className="al-c no-data" colSpan={5}>{getMessage('common.message.no.data')}</td>
</tr>
)}
</tbody>
</table>
</div>
<Pagination />
</div>
</div>
</div>
{open && <QnaBoardDetailModal qnaNo={modalQnaNo} setOpen={setOpen} qnaType = {modalQnaType} />}
</>
)
}

View File

@ -4,11 +4,10 @@ import { searchState } from '@/store/boardAtom'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import QnaRegModal from '@/components/community/modal/QnaRegModal'
export default function Search({ title = '', subTitle = '', isSelectUse = false, clsCode = '' }) {
export default function Search({ title = '', subTitle = '', isSelectUse = false }) {
const { getMessage } = useMessage()
const [open, setOpen] = useState(false)
const search = useRecoilValue(searchState)
const [searchForm, setSearchForm] = useRecoilState(searchState)
@ -33,13 +32,7 @@ export default function Search({ title = '', subTitle = '', isSelectUse = false,
} else {
setSearchView(false)
setSearchViewText('')
setSearchForm({
...searchForm,
currentPage: 1,
searchValue: '',
pageBlock : block,
searchFlag : !searchForm.searchFlag,
})
setSearchForm({ ...searchForm, currentPage: 1, searchValue: '', pageBlock: block, searchFlag: !searchForm.searchFlag })
}
//
setSearchValue('')
@ -64,10 +57,7 @@ export default function Search({ title = '', subTitle = '', isSelectUse = false,
onKeyDown={handleKeyDown}
value={searchValue}
/>
<button type="button" className="community-search-ico"
onClick={() => handleSearch(searchValue, selectPageBlock)}></button>
<button type="button" className="community-search-ico" onClick={() => handleSearch(searchValue, selectPageBlock)}></button>
</div>
{searchView && (
<div className="community-search-keyword">
@ -102,14 +92,6 @@ export default function Search({ title = '', subTitle = '', isSelectUse = false,
</div>
{isSelectUse && (
<div className="left-unit-box">
{clsCode === 'QNA' &&
<div>
<button className="btn-origin navy mr10"
onClick={() => {
setOpen(true)
}}> {getMessage('qna.sub.btn.inquiry')}</button>
</div>
}
<div className="select-box" style={{ width: '80px' }}>
<select
className="select-light black"
@ -130,7 +112,6 @@ export default function Search({ title = '', subTitle = '', isSelectUse = false,
</div>
)}
</div>
{open && <QnaRegModal setOpen={setOpen} setReload={handleSearch} searchValue={searchValue ? searchValue : searchViewText} selectPageBlock = {selectPageBlock}/>}
</>
)
}

View File

@ -1,127 +0,0 @@
'use client'
import { useEffect, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { handleFileDown } from '@/util/board-utils'
import { useMessage } from '@/hooks/useMessage'
import { sessionStore } from '@/store/commonAtom'
import { useRecoilState } from 'recoil'
export default function QnaDetailModal({ qnaNo, setOpen, qnaType }) {
const { getMessage } = useMessage()
// api
const { get } = useAxios()
const [boardDetail, setBoardDetail] = useState({})
const [sessionState, setSessionState] = useRecoilState(sessionStore)
useEffect(() => {
//
const fetchDetail = async (qnaNo) => {
const url = `/api/board/detail`
const params = new URLSearchParams({
noticeNo : qnaNo,
qnaNo : qnaNo,
schNoticeClsCd: 'QNA',
compCd : 5200,
loginId : sessionState.userId,
langCd : 'JA',
})
const apiUrl = `${url}?${params.toString()}`
const resultData = await get({ url: apiUrl })
if (resultData) {
if (resultData.result.code === 200) {
const boardDetail = resultData.data
setBoardDetail(boardDetail)
} else {
alert(resultData.result.message)
}
}
}
fetchDetail(qnaNo)
}, [])
return (
<>
<div key={qnaNo} className="modal-popup community">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
className="modal-close"
onClick={() => {
setOpen(false)
}}
>
{getMessage('board.sub.btn.close')}
</button>
</div>
<div className="modal-body">
<div className="oneonone-header-wrap">
<div className="oneonone-title"> {qnaType} {boardDetail.qstTitle}</div>
<div className="oneonone-infor">
<div className="profile">{boardDetail.regUserNm}</div>
<div className="date">{boardDetail.regDt}</div>
</div>
</div>
<div className="oneonone-detail">
{boardDetail.listFile && (
<dl className="community_detail-file-wrap">
<dt>{getMessage('qna.detail.sub.fileList')}</dt>
{boardDetail.listFile.map((boardFile) => (
<dd key={boardFile.encodeFileNo}>
<button type="button" className="down" onClick={() => handleFileDown(boardFile.fileNo, 'NO')}>
{boardFile.srcFileNm}
</button>
</dd>
))}
</dl>
)}
<div
className="community_detail-inner"
dangerouslySetInnerHTML={{
__html: boardDetail.qstContents ? boardDetail.qstContents.replaceAll('\n', '<br/>') : '',
}}
></div>
</div>
{boardDetail?.answerYn === 'Y' && (
<div className="oneonone-answer">
<div className="answer-title-wrap">
<div className="answer-title">Hanwha Japan {getMessage('qna.detail.sub.answer')}</div>
<div className="oneonone-infor">
<div className="profile">{boardDetail.ansRegNm}</div>
<div className="date">{boardDetail.ansRegDt}</div>
</div>
</div>
<div
className="community_detail-inner"
dangerouslySetInnerHTML={{
__html: boardDetail.ansContents ? boardDetail.ansContents.replaceAll('\n', '<br/>') : '',
}}
></div>
{boardDetail.ansListFile && (
<dl className="community_detail-file-wrap">
<dt>{getMessage('qna.detail.sub.fileList')}</dt>
{boardDetail.ansListFile.map((boardFile) => (
<dd key={boardFile.encodeFileNo}>
<button type="button" className="down" onClick={() => handleFileDown(boardFile.fileNo, 'N')}>
{boardFile.srcFileNm}
</button>
</dd>
))}
</dl>
)}
</div>
)}
</div>
</div>
</div>
</div>
</>
)
}

View File

@ -1,140 +0,0 @@
'use client'
import { useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
export default function QnaFileUploader({ uploadFiles, setUploadFiles, qnaData, setQnaData }) {
const fileInputRef = useRef(null)
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const handleButtonClick = (e) => {
e.preventDefault()
fileInputRef.current.click()
}
const onChangeFiles = async (e) => {
if (e.target.files.length <= 0) {
return
}
const fileList = []
let passFlag = true
const allowedFileTypes = [
'image/',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
]
Array.from(e.target.files).forEach((file) => {
//, pdf,
const fileType = file.type
if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
}
})
if (!passFlag) {
swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
setUploadFiles([...uploadFiles, ...fileList])
setQnaData({...qnaData, files:[...uploadFiles, ...fileList]})
e.target.value = ''
}
const deleteFile = (id) => {
setUploadFiles(uploadFiles.filter((file) => file.id !== id))
setQnaData({...qnaData, files:uploadFiles.filter((file) => file.id !== id)})
}
const handleDrop = (e) => {
e.preventDefault()
e.stopPropagation()
const fileList = []
let passFlag = true
const allowedFileTypes = [
'image/',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
]
Array.from(e.dataTransfer.files).forEach((file) => {
//, pdf,
let fileType = file.type
if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
}
})
if (!passFlag) {
swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
setUploadFiles([...uploadFiles, ...fileList])
setQnaData({...qnaData, files:[...uploadFiles, ...fileList]})
}
const handleDragOver = (e) => {
e.preventDefault()
e.stopPropagation()
}
const handleDragEnd = (e) => {
e.preventDefault()
e.stopPropagation()
}
const handleDragLeave = (e) => {
e.preventDefault()
e.stopPropagation()
}
return (
<div className="design-request-grid mt15">
<div className="design-request-count">
<div className="design-request-grid-tit">{getMessage("qna.reg.header.fileList")}</div>
<div className="btn-area one-on-one">
<label className="file-upload" htmlFor="img" onClick={handleButtonClick}>
Attach File
</label>
<input type="file" multiple name="file" ref={fileInputRef} style={{ display: 'none' }} onChange={(e) => onChangeFiles(e)} />
</div>
</div>
<div className="drag-file-box one-on-one">
<div className="drag-file-area"
draggable
onDrop={(e) => handleDrop(e)}
onDragOver={(e) => handleDragOver(e)}
onDragEnd={(e) => handleDragEnd(e)}
onDragLeave={(e) => handleDragLeave(e)}>
<p>Drag file here</p>
<ul className="file-list">
{uploadFiles.length > 0 &&
uploadFiles.map((file) => (
<li className="file-item" key={file.id}>
<span>
{file.data.name} <button className="delete" onClick={() => deleteFile(file.id)}></button>
</span>
</li>
))}
</ul>
</div>
</div>
</div>
)
}

View File

@ -1,454 +0,0 @@
'use client'
import { useMessage } from '@/hooks/useMessage'
import { sessionStore } from '@/store/commonAtom'
import { useRecoilState, useRecoilValue } from 'recoil'
import QnaFileUploader from '@/components/community/modal/QnaFileUploader'
import { useContext, useEffect, useRef, useState } from 'react'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import Select from 'react-select'
import dayjs from 'dayjs'
import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
import { useAxios } from '@/hooks/useAxios'
import { globalLocaleStore } from '@/store/localeAtom'
import { e } from 'mathjs'
import { set } from 'react-hook-form'
export default function QnaRegModal({ setOpen, setReload, searchValue, selectPageBlock }) {
const { getMessage } = useMessage()
const [fileList, setFileList] = useState([])
const [sessionState, setSessionState] = useRecoilState(sessionStore)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const [files, setFiles] = useState([])
const [qnaData, setQnaData] = useState([])
const [closeMdFlg, setCloseMdFlg] = useState(true)
const [closeSmFlg, setCloseSmFlg] = useState(true)
const [hideSmFlg, setHideSmFlg] = useState(false)
const qnaTypeLgCodeRef = useRef(null)
const qnaTypeMdCodeRef = useRef(null)
const qnaTypeSmCodeRef = useRef(null)
const qstMail = useRef(null);
const regUserNmRef = useRef(null)
const regUserTelNoRef = useRef(null)
const titleRef = useRef(null)
const contentsRef = useRef(null)
const { findCommonCode } = useCommonCode()
const [qnaTypeLgCodeList, setQnaTypeLgCodeList] = useState([])
const [qnaTypeMdCodeList, setQnaTypeMdCodeList] = useState([])
const [qnaTypeSmCodeList, setQnaTypeSmCodeList] = useState([])
const [phoneNumber, setPhoneNumber] = useState("");
const { swalFire } = useSwal()
const { setIsGlobalLoading } = useContext(QcastContext)
const [isBtnDisable, setIsBtnDisable] = useState(false);
const { promiseGet, post, promisePost } = useAxios(globalLocaleState)
let fileCheck = false;
const regPhoneNumber = (e) => {
const result = e.target.value
.replace(/[^0-9.]/g, "")
//.replace(/^(\d{0,3})(\d{0,4})(\d{0,4})$/g, "$1-$2-$3")
//.replace(/(-{1,2})$/g, "");
//setPhoneNumber(result);
setQnaData({...qnaData, regUserTelNo: result })
}
const fileUploadProps = {
uploadFiles: files,
setUploadFiles: setFiles,
}
// const fileSave = (qnaData, fileUploadProps) => {
// return qnaData.files.push(fileUploadProps.uploadFiles)
// }
const initQnaReg = async () => {
qstMail.current.value = ''
regUserNmRef.current.value = ''
regUserTelNoRef.current.value = ''
qnaTypeLgCodeRef.current.setValue();
qnaTypeMdCodeRef.current.setValue();
qnaTypeSmCodeRef.current?.setValue();
titleRef.current.value = ''
contentsRef.current.value = ''
//setQnaData([])
setQnaData({
...qnaData,
compCd: "5200",
siteTpCd: "QC",
schNoticeClsCd: "QNA",
regId: sessionState.userId,
storeId: sessionState.userId,
qstMail : sessionState.email
})
const codeL = findCommonCode(204200)
if (codeL != null) {
setQnaTypeLgCodeList(codeL)
}
setIsGlobalLoading(false)
setIsBtnDisable(false);
}
const onChangeQnaTypeL = (e) => {
if(e === undefined || e === null) return;
const codeM = findCommonCode(204300)
if (codeM != null) {
let codeList = []
codeM.map((item) => {
if(item.clRefChr1 === e.clCode) {
codeList.push(item);
}
})
setQnaTypeMdCodeList(codeList)
setQnaData({ ...qnaData, qnaClsLrgCd:e.clCode})
setCloseMdFlg(false)
qnaTypeMdCodeRef.current.setValue();
qnaTypeSmCodeRef.current?.setValue();
}
}
const onChangeQnaTypeM = (e) => {
if(e === undefined || e === null) return;
const codeS = findCommonCode(204400)
if (codeS != null) {
let codeList = []
codeS.map((item) => {
if (item.clRefChr1 === e.clCode) {
codeList.push(item);
}
})
setQnaData({ ...qnaData, qnaClsMidCd: e.clCode })
setCloseSmFlg(false)
setQnaTypeSmCodeList(codeList)
qnaTypeSmCodeRef.current?.setValue();
if(codeList.length > 0) {
setHideSmFlg(false)
}else{
setHideSmFlg(true)
}
}
}
const onChangeQnaTypeS = (e) => {
if(e === undefined || e === null) return;
setQnaData({ ...qnaData, qnaClsSmlCd:e.clCode})
}
const onFileSave = () => {
const formData= []
if(fileUploadProps.uploadFiles.length === 0) return;
if(!fileCheck) return;
fileUploadProps.uploadFiles.forEach((file) => {
//console.log("file::::::::",file)
formData.push(file)
})
setQnaData({ ...qnaData, files:formData })
fileCheck = false;
}
const isValidEmail = (email) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
};
const isEmpty = (value) => {
return value === null || value === undefined || value.trim() === "";
};
const handleQnaSubmit = async () => {
//
//console.log("1::::",qnaData)
let regUserNm = qnaData?.regUserNm??'';
if (!isValidEmail(qnaData.qstMail)) {
qstMail.current.focus();
swalFire({
title: getMessage('qna.reg.alert.require.qstMail'),
icon: 'warning',
});
return;
}
if (isEmpty(regUserNm)) {
regUserNmRef.current.value = '';
regUserNmRef.current.focus()
swalFire({
title: getMessage('qna.reg.alert.require.regUserNm'),
icon: 'warning',
})
return false
}
let qnaClsLrgCd = qnaData?.qnaClsLrgCd??'';
let qnaClsMidCd = qnaData?.qnaClsMidCd??'';
if (isEmpty(qnaClsLrgCd) || isEmpty(qnaClsMidCd) ) {
(isEmpty(qnaClsLrgCd))?qnaTypeLgCodeRef.current.focus():qnaTypeMdCodeRef.current.focus()
swalFire({
title: getMessage('qna.reg.alert.select.type'),
icon: 'warning',
})
return false
}
let title = qnaData?.title??'';
if (isEmpty(title)) {
titleRef.current.value = '';
titleRef.current.focus()
swalFire({
title: getMessage('qna.reg.alert.require.title'),
icon: 'warning',
})
return false
}
//console.log("5::::",qnaData)
let contents = qnaData?.contents??'';
if (isEmpty(contents)) {
contentsRef.current.value = '';
contentsRef.current.focus()
swalFire({
title: getMessage('qna.reg.alert.require.contents'),
icon: 'warning',
})
return false
}
const formData = new FormData()
if(qnaData?.files?.length > 0) {
qnaData?.files.forEach((file) => {
formData.append('files', file.data)
})
}
formData.append("compCd", qnaData.compCd)
formData.append("siteTpCd", qnaData.siteTpCd)
formData.append("qnaClsLrgCd", qnaData.qnaClsLrgCd)
formData.append("qnaClsMidCd", qnaData.qnaClsMidCd)
formData.append("qnaClsSmlCd", qnaData.qnaClsSmlCd)
formData.append("title", qnaData.title)
formData.append("contents", qnaData.contents)
formData.append("regId", qnaData.regId)
formData.append("storeId", qnaData.storeId)
formData.append("regUserNm", qnaData.regUserNm)
formData.append("regUserTelNo", qnaData.regUserTelNo)
formData.append("qstMail", qnaData.qstMail)
formData.append("schNoticeClsCd", qnaData.schNoticeClsCd)
//console.log(Array.from(formData));
swalFire({
html: getMessage('qna.reg.confirm.save'),
type: 'confirm',
confirmFn: async () => {
setIsBtnDisable(true);
setIsGlobalLoading(true)
try {
const apiUrl = 'api/board'
//console.log("7::::",qnaData)
await post({ url: `${apiUrl}/saveQna`, data: formData }).then((res) => {
if (res?.result.code === 200) {
//qnaData.newFileList = []
setIsGlobalLoading(false)
swalFire({ text: getMessage('qna.reg.alert.save'), type: 'alert' })
setOpen(false)
setReload(searchValue, selectPageBlock);
}else{
setIsGlobalLoading(false)
swalFire({ text: getMessage('qna.reg.alert.saveFail'), type: 'alert', icon: 'error' })
console.error('error::::::::::::', res)
}
setIsBtnDisable(false)
})
} catch (e) {
setIsGlobalLoading(false)
setIsBtnDisable(false);
console.error('error::::::::::::', e.message)
swalFire({ text: e.message, type: 'alert' , icon: 'error'})
console.error('error::::::::::::', e.message)
}
}
})
}
useEffect(() => {
initQnaReg()
},[])
// useEffect(() => {
// onFileSave()
//
// }, [onFileSave])
return (
<div className="modal-popup">
<div className="modal-dialog big">
<div className="modal-content">
<div className="modal-header">
<h1 className="title">{getMessage('qna.title')}</h1>
<button className="modal-close"
onClick={() => {
setOpen(false)
}}>{getMessage('board.sub.btn.close')}</button>
</div>
<div className="modal-body">
<div className="modal-body-inner">
<div className="design-request-table">
<div className="common-table">
<table>
<colgroup>
<col style={{ width: '100px' }} />
<col />
<col style={{ width: '120px' }} />
<col />
<col style={{ width: '150px' }} />
<col />
</colgroup>
<tbody>
<tr>
<th>{getMessage('qna.list.header.regNm')}</th>
<td><input type="text" className="input-light" value={sessionState?.userNm || ''} readOnly /></td>
<th>E-Mail<span className="red">*</span></th>
<td ><input type="text" className="input-light" required
ref={qstMail}
value={qnaData?.qstMail || ''}
onChange={(e) => setQnaData({...qnaData, qstMail: e.target.value })}
onBlur={(e) => setQnaData({ ...qnaData, qstMail: e.target.value })} />
</td>
<th>{getMessage('qna.reg.header.regDt')}</th>
<td>{dayjs(new Date()).format('YYYY-MM-DD')}</td>
</tr>
<tr>
<th>{getMessage('qna.reg.header.regUserNm')}<span className="red">*</span></th>
<td ><input type="text" className="input-light" required
ref={regUserNmRef}
value={qnaData?.regUserNm || '' }
onChange={(e) => setQnaData({...qnaData, regUserNm: e.target.value })}
onBlur={(e) => setQnaData({ ...qnaData, regUserNm: e.target.value })} /> </td>
<th>{getMessage('qna.reg.header.regUserTelNo')}</th>
<td colSpan={3}><input type="text" className="input-light"
ref={regUserTelNoRef}
maxLength={13}
value={qnaData?.regUserTelNo || '' }
onChange={regPhoneNumber}
/></td>
</tr>
</tbody>
</table>
</div>
</div>
<div className="design-request-grid">
<div className="design-request-count">
<div className="design-request-grid-tit">{getMessage("qna.reg.header.type")}, {getMessage("qna.reg.header.title")} <span
className="red">*</span></div>
</div>
<div className="flx-box one-on-one">
<div className="select-wrap mr5" >
<Select name="" ref={qnaTypeLgCodeRef}
options={qnaTypeLgCodeList}
placeholder="Select"
onChange={(e) => onChangeQnaTypeL(e)}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={false}
isSearchable={false}
/>
</div>
<div className="select-wrap mr5" >
<Select name="" ref={qnaTypeMdCodeRef}
options={qnaTypeMdCodeList}
placeholder="Select"
onChange={(e) => onChangeQnaTypeM(e)}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={false}
isSearchable={false}
isDisabled={closeMdFlg}
defaultValue={''}
/>
</div>
<div className="select-wrap" >
{!hideSmFlg && (
<Select name="" ref={qnaTypeSmCodeRef}
options={qnaTypeSmCodeList}
placeholder="Select"
onChange={(e) => onChangeQnaTypeS(e)}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={false}
isSearchable={false}
isDisabled={closeSmFlg}
/>)}
</div>
</div>
<div className="input-wrap mt5">
<input type="text" className="input-light" maxLength={200}
ref = {titleRef}
value={qnaData?.title || '' }
onChange={(e) => {setQnaData({ ...qnaData, title: e.target.value })}}
/>
</div>
</div>
<div className="design-request-grid mt15">
<div className="design-request-count">
<div className="design-request-grid-tit">{getMessage("qna.reg.header.contents")} <span className="red">*</span></div>
</div>
<div>
<textarea className="textarea-form" name="" id="" maxLength={4000}
ref={contentsRef}
value={qnaData?.contents || '' }
onChange={(e) => {setQnaData({ ...qnaData, contents: e.target.value })}} ></textarea>
</div>
</div>
<QnaFileUploader {...fileUploadProps} qnaData={qnaData} setQnaData={setQnaData} />
</div>
<div className="footer-btn-wrap">
{isBtnDisable === false && <button className="btn-origin navy mr5" onClick={handleQnaSubmit}>{getMessage("qna.reg.header.save")}</button>}
<button className="btn-origin grey" onClick={() => {
setOpen(false)
}}>{getMessage("board.sub.btn.close")}</button>
</div>
</div>
</div>
</div>
</div>
)
}

View File

@ -13,7 +13,7 @@ import dayjs from 'dayjs'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { SessionContext } from '@/app/SessionProvider'
import Select, { components } from 'react-select'
import Select from 'react-select'
import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from '@/util/common-utils'
import ProductFeaturesPop from './popup/ProductFeaturesPop'
import { v4 as uuidv4 } from 'uuid'
@ -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,7 +117,6 @@ export default function Estimate({}) {
item.value = item.clRefChr1
item.label = item.clRefChr2
})
// console.log(code2)
setCableItemList(code2)
}
@ -153,8 +152,8 @@ export default function Estimate({}) {
}
useEffect(() => {
// console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan)
if (selectedPlan) initEstimate(selectedPlan?.planNo?? currentPid)
console.log('🚀 ~ Estimate ~ selectedPlan:', selectedPlan)
if (selectedPlan) initEstimate(selectedPlan.planNo)
}, [selectedPlan])
useEffect(() => {
@ -176,10 +175,7 @@ export default function Estimate({}) {
row.check = false
estimateOption.map((row2) => {
if (row.pkgYn === '0') {
// if (row2 === row.code) {
// row.check = true
// }
if (row.code.split('、').includes(row2)) {
if (row2 === row.code) {
row.check = true
}
} else {
@ -221,10 +217,7 @@ export default function Estimate({}) {
row.check = false
estimateOption.map((row2) => {
if (row.pkgYn === '0') {
// if (row2 === row.code) {
// row.check = true
// }
if (row.code.split('、').includes(row2)) {
if (row2 === row.code) {
row.check = true
}
} else {
@ -247,6 +240,7 @@ export default function Estimate({}) {
}
}
})
setSpecialNoteList(res)
setSpecialNoteFirstFlg(true)
@ -383,8 +377,8 @@ export default function Estimate({}) {
useEffect(() => {
if (estimateContextState.estimateType !== '') {
const param = {
saleStoreId: estimateContextState.sapSaleStoreId,
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
docTpCd: estimateContextState?.estimateType,
}
@ -393,8 +387,6 @@ export default function Estimate({}) {
if (isNotEmptyArray(res?.data)) {
setStorePriceList(res.data)
}
setItemChangeYn(true)
})
if (estimateContextState.estimateType === 'YJSS') {
@ -424,6 +416,8 @@ export default function Estimate({}) {
handlePricing('UNIT_PRICE')
}
}
setItemChangeYn(true)
}
}, [estimateContextState?.estimateType])
@ -475,21 +469,6 @@ export default function Estimate({}) {
} else {
item.check = false
}
} else {
let codes = item.code.split('、')
let flg = '0'
if (codes.length > 1) {
for (let i = 0; i < pushData.length; i++) {
if (codes.indexOf(pushData[i]) > -1) {
flg = '1'
}
}
if (flg === '1') {
item.check = true
} else {
item.check = false
}
}
}
})
@ -499,26 +478,12 @@ export default function Estimate({}) {
})
}
//Pricing confirm
const handlePricingBtn = (showPriceCd) => {
swalFire({
text: getMessage('estimate.detail.showPrice.pricingBtn.confirm'),
type: 'confirm',
icon: 'warning',
confirmFn: () => {
handlePricing(showPriceCd)
},
})
}
//Pricing
const handlePricing = async (showPriceCd) => {
const param = {
saleStoreId: estimateContextState.sapSaleStoreId,
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
docTpCd: estimateContextState.estimateType,
secSapSalesStoreCd:
estimateContextState.secSapSalesStoreCd?.length > 0 && showPriceCd === 'QSP_PRICE' ? estimateContextState.secSapSalesStoreCd : '',
priceCd: showPriceCd,
itemIdList: estimateContextState.itemList.filter((item) => item.delFlg === '0' && item.paDispOrder === null),
}
@ -541,6 +506,7 @@ export default function Estimate({}) {
})
}
}
setIsGlobalLoading(true)
await promisePost({ url: '/api/estimate/price/item-price-list', data: param }).then((res) => {
let updateList = []
@ -565,7 +531,6 @@ export default function Estimate({}) {
updateList.push({
...item,
openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
unitOpenFlg: (showPriceCd === 'QSP_PRICE' && item.openFlg === '1') ? '1' : '0',
salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
})
@ -731,7 +696,7 @@ export default function Estimate({}) {
/* 케이블 select 변경시 */
const onChangeDisplayCableItem = (value, itemList) => {
itemList.map((item, index) => {
if (item.dispCableFlg === '1' && item.itemTpCd !== 'M12') {
if (item.dispCableFlg === '1') {
if (value !== '') {
onChangeDisplayItem(value, item.dispOrder, index, true)
}
@ -740,18 +705,6 @@ 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 = {
@ -1101,20 +1054,15 @@ export default function Estimate({}) {
item.showSaleTotPrice = '0'
}
if (item.dispCableFlg === '1' ) {
if (item.dispCableFlg === '1') {
dispCableFlgCnt++
if(item.itemTpCd === 'M12') {
setCableDbItem(item.itemId)
}else{
setCableItem(item.itemId)
}
setCableItem(item.itemId)
}
}
})
if (dispCableFlgCnt === 0) {
setCableItem('100038')
setCableDbItem('100037')
}
let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
@ -1177,20 +1125,14 @@ export default function Estimate({}) {
dispCableFlgCnt++
}
if (item.dispCableFlg === '1'){
if(item.itemTpCd === 'M12') {
setCableDbItem(item.itemId)
}else{
setCableItem(item.itemId)
}
if (item.dispCableFlg === '1') {
setCableItem(item.itemId)
}
}
})
if (dispCableFlgCnt === 0) {
setCableItem('100038')
setCableDbItem('100037')
}
totals.vatPrice = totals.supplyPrice * 0.1
@ -1251,26 +1193,10 @@ export default function Estimate({}) {
if (dispCableFlgCnt === 0) {
setCableItem('100038')
setCableDbItem('100037')
}
}
}, [estimateContextState?.itemList, cableItemList])
const [agencyCustList, setAgencyCustList] = useState([])
useEffect(() => {
// 952 - 2 sapSalesStoreCd
if (estimateContextState?.sapSalesStoreCd && session?.storeLvl === '1') {
const param = {
sapSalesStoreCd: estimateContextState.sapSalesStoreCd,
}
const apiUrl = `api/estimate/agency-cust-list?${queryStringFormatter(param)}`
get({ url: apiUrl }).then((res) => {
if (isNotEmptyArray(res?.data)) {
setAgencyCustList(res?.data)
}
})
}
}, [estimateContextState?.sapSalesStoreCd])
return (
<div className="sub-content estimate">
<div className="sub-content-inner">
@ -1281,7 +1207,7 @@ export default function Estimate({}) {
<div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
<div className="estimate-name">
{currentObjectNo} (Plan No: {currentPid})
{currentObjectNo} (Plan No: {planNo})
</div>
</div>
<div className="estimate-box">
@ -1415,79 +1341,36 @@ export default function Estimate({}) {
{getMessage('estimate.detail.estimateType')} <span className="important">*</span>
</th>
<td colSpan={3}>
<div className="form-flex-wrap">
<div className="radio-wrap">
{/*pkgRank is null, empty 인 경우 : 사용불가, 이전에 등록된 경우 사용가능, style로 제어*/}
<div
className="d-check-radio light mr10"
style={{
display:
(isNotEmptyArray(storePriceList) > 0 && storePriceList[0].pkgRank !== null && storePriceList[0].pkgRank !== '') ||
estimateContextState?.estimateType === 'YJSS'
? ''
: 'none',
<div className="radio-wrap">
<div className="d-check-radio light mr10">
<input
type="radio"
name="estimateType"
id="YJSS"
value={'YJSS'}
checked={estimateContextState?.estimateType === 'YJSS' ? true : false}
onChange={(e) => {
//
setHandlePricingFlag(true)
setEstimateContextState({ estimateType: e.target.value })
}}
>
<input
type="radio"
name="estimateType"
id="YJSS"
value={'YJSS'}
checked={estimateContextState?.estimateType === 'YJSS' ? true : false}
onChange={(e) => {
//
setHandlePricingFlag(true)
setEstimateContextState({ estimateType: e.target.value })
}}
/>
<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="estimateType"
id="YJOD"
value={'YJOD'}
checked={estimateContextState?.estimateType === 'YJOD' ? true : false}
onChange={(e) => {
setHandlePricingFlag(true)
setEstimateContextState({ estimateType: e.target.value })
}}
/>
<label htmlFor="YJOD">{getMessage('estimate.detail.estimateType.yjod')}</label>
</div>
/>
<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>
</div>
<div className="d-check-radio light">
<input
type="radio"
name="estimateType"
id="YJOD"
value={'YJOD'}
checked={estimateContextState?.estimateType === 'YJOD' ? true : false}
onChange={(e) => {
setHandlePricingFlag(true)
setEstimateContextState({ estimateType: e.target.value })
}}
/>
<label htmlFor="YJOD">{getMessage('estimate.detail.estimateType.yjod')}</label>
</div>
{session?.storeLvl === '1' && agencyCustList.length > 0 ? (
<div className="form-flex-select ml10">
<label htmlFor="">{getMessage('estimate.detail.agency')}</label>
<div className="select-wrap" style={{ width: '400px' }}>
<Select
id="agencyName"
instanceId="agencyName"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={agencyCustList}
onChange={(e) => {
if (isObjectNotEmpty(e)) {
setEstimateContextState({ secSapSalesStoreCd: e.sapSalesStoreCd })
} else {
setEstimateContextState({ secSapSalesStoreCd: '' })
}
}}
getOptionLabel={(x) => x.sapSalesStoreNm}
getOptionValue={(x) => x.sapSalesStoreCd}
isClearable={true}
isSearchable={true}
value={agencyCustList.filter(function (option) {
return option.sapSalesStoreCd === estimateContextState.secSapSalesStoreCd
})}
/>
</div>
</div>
) : (
''
)}
</div>
</td>
</tr>
@ -1846,17 +1729,15 @@ export default function Estimate({}) {
<button
type="button"
className="btn-origin grey ml5"
onClick={(event) => {
onClick={() => {
setHandlePricingFlag(true)
handlePricingBtn(showPriceCd)
handlePricing(showPriceCd)
}}
>
{getMessage('estimate.detail.showPrice.pricingBtn')}
</button>
</div>
<div className="product-price-wrap ml10">
<div className="product-price-tit">{getMessage('estimate.detail.header.singleCable')}</div>
<div className="select-wrap">
<select
className="select-light"
@ -1866,34 +1747,11 @@ export default function Estimate({}) {
value={cableItem}
>
{cableItemList.length > 0 &&
cableItemList.map((row) => {
if(!row.clRefChr2.includes('S')){
return <option key={row.clRefChr1} value={row.clRefChr1}>
{row.clRefChr2}
</option>
}
})}
</select>
</div>
</div>
<div className="product-price-wrap ml10">
<div className="product-price-tit">{getMessage('estimate.detail.header.doubleCable')}</div>
<div className="select-wrap">
<select
className="select-light"
onChange={(e) => {
onChangeDisplayDoubleCableItem(e.target.value, estimateContextState.itemList)
}}
value={cableDbItem}
>
{cableItemList.length > 0 &&
cableItemList.map((row) => {
if(row.clRefChr2.includes('S')){
return <option key={row.clRefChr1} value={row.clRefChr1}>
{row.clRefChr2.replace('S','')}
</option>
}
})}
cableItemList.map((row) => (
<option key={row.clRefChr1} value={row.clRefChr1}>
{row.clRefChr2}
</option>
))}
</select>
</div>
</div>
@ -1976,7 +1834,7 @@ export default function Estimate({}) {
<input
type="checkbox"
id={item?.dispOrder}
disabled={!!item?.paDispOrder || item.dispCableFlg === '1X'}
disabled={!!item?.paDispOrder || item.dispCableFlg === '1'}
onChange={() => onChangeSelect(item.dispOrder)}
checked={!!selection.has(item.dispOrder)}
/>
@ -2001,13 +1859,8 @@ export default function Estimate({}) {
}
}}
menuPlacement={'auto'}
getOptionLabel={(x) => x.itemName + ' (' + x.itemNo + ')'}
getOptionLabel={(x) => x.itemName}
getOptionValue={(x) => x.itemNo}
components={{
SingleValue: ({ children, ...props }) => {
return <components.SingleValue {...props}>{props.data.itemName}</components.SingleValue>
},
}}
isClearable={false}
isDisabled={!!item?.paDispOrder}
value={displayItemList.filter(function (option) {
@ -2027,17 +1880,12 @@ export default function Estimate({}) {
placeholder="Select"
options={cableItemList}
menuPlacement={'auto'}
getOptionLabel={(x) => x.clRefChr3 + ' (' + x.clRefChr1 + ')'}
getOptionLabel={(x) => x.clRefChr3}
getOptionValue={(x) => x.clRefChr1}
components={{
SingleValue: ({ children, ...props }) => {
return <components.SingleValue {...props}>{(item.itemTpCd === 'M12')? item.itemName : props.data.clRefChr3}</components.SingleValue>
},
}}
isClearable={false}
isDisabled={true}
value={cableItemList.filter(function (option) {
return (item.itemTpCd === 'M12')? item.itemId : option.clRefChr1 === item.itemId
return option.clRefChr1 === item.itemId
})}
/>
)}
@ -2088,11 +1936,7 @@ export default function Estimate({}) {
<input
type="text"
className="input-light al-r"
value={
item.openFlg === '1'
? 'OPEN'
: convertNumberToPriceDecimal(item?.showSalePrice === '0' ? null : item?.salePrice?.replaceAll(',', ''))
}
value={convertNumberToPriceDecimal(item?.showSalePrice === '0' ? null : item?.salePrice?.replaceAll(',', ''))}
disabled={
item.openFlg === '1'
? true
@ -2120,17 +1964,15 @@ export default function Estimate({}) {
</div>
</td>
<td className="al-r">
{item?.openFlg === '1'
? 'OPEN'
: convertNumberToPriceDecimal(
item?.showSaleTotPrice === '0'
{convertNumberToPriceDecimal(
item?.showSaleTotPrice === '0'
? null
: item?.amount === ''
? null
: item?.saleTotPrice === '0'
? null
: item?.amount === ''
? null
: item?.saleTotPrice === '0'
? null
: item?.saleTotPrice?.replaceAll(',', ''),
)}
: item?.saleTotPrice?.replaceAll(',', ''),
)}
</td>
</tr>
)

View File

@ -2,7 +2,7 @@ import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid'
import { QLine } from '@/components/fabric/QLine'
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
import { calculateAngle, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils'
import { calculateAngle, drawGabledRoof, drawRidgeRoof, drawShedRoof, toGeoJSON } from '@/util/qpolygon-utils'
import * as turf from '@turf/turf'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import Big from 'big.js'
@ -29,13 +29,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.texts = []
this.hips = []
this.ridges = []
this.connectRidges = []
this.cells = []
this.innerLines = []
this.children = []
this.separatePolygon = []
this.toFixed = options.toFixed ?? 1
this.baseLines = []
// this.colorLines = []
// 소수점 전부 제거
points.forEach((point) => {
@ -46,11 +45,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
options.sort = options.sort ?? true
options.parentId = options.parentId ?? null
this.isSortedPoints = false
if (!options.sort && points.length <= 8) {
points = sortedPointLessEightPoint(points)
this.isSortedPoints = true
} else {
let isDiagonal = false
points.forEach((point, i) => {
@ -66,7 +62,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
if (!isDiagonal) {
points = sortedPoints(points)
this.isSortedPoints = true
}
}
@ -124,12 +119,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.addLengthText()
this.on('moving', () => {
this.initLines()
this.addLengthText()
})
this.on('modified', (e) => {
this.initLines()
this.addLengthText()
})
@ -190,8 +183,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.lines = []
this.getCurrentPoints().forEach((point, i) => {
const nextPoint = this.getCurrentPoints()[(i + 1) % this.points.length]
this.points.forEach((point, i) => {
const nextPoint = this.points[(i + 1) % this.points.length]
const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], {
stroke: this.stroke,
strokeWidth: this.strokeWidth,
@ -218,12 +211,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
* @param settingModalFirstOptions
*/
drawHelpLine(settingModalFirstOptions) {
/* innerLines 초기화 */
this.innerLines.forEach((line) => {
this.canvas.remove(line)
})
this.canvas.renderAll()
let textMode = 'plane'
const dimensionDisplay = settingModalFirstOptions?.dimensionDisplay.find((opt) => opt.selected).id
@ -253,13 +240,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const hasShed = types.includes(LINE_TYPE.WALLLINE.SHED)
// A형, B형 박공 지붕
/* if (
if (
(gableOdd.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableEven.every((type) => gableType.includes(type))) ||
(gableEven.every((type) => type === LINE_TYPE.WALLLINE.EAVES) && gableOdd.every((type) => gableType.includes(type)))
) {
drawGabledRoof(this.id, this.canvas, textMode)
} else*/
if (hasShed) {
} else if (hasShed) {
const sheds = this.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED)
const areLinesParallel = function (line1, line2) {
const angle1 = calculateAngle(line1.startPoint, line1.endPoint)

View File

@ -12,7 +12,7 @@ import { usePlan } from '@/hooks/usePlan'
import { useContextMenu } from '@/hooks/useContextMenu'
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
import { currentMenuState } from '@/store/canvasAtom'
import { roofMaterialsAtom, totalDisplaySelector } from '@/store/settingAtom'
import { totalDisplaySelector } from '@/store/settingAtom'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { QcastContext } from '@/app/QcastProvider'
@ -30,16 +30,11 @@ import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useEvent } from '@/hooks/useEvent'
import { compasDegAtom } from '@/store/orientationAtom'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
import { useMasterController } from '@/hooks/common/useMasterController'
import { hotkeyStore } from '@/store/hotkeyAtom'
import { usePopup } from '@/hooks/usePopup'
export default function CanvasFrame() {
const canvasRef = useRef(null)
const { canvas } = useCanvas('canvas')
const { canvasLoadInit, gridInit } = useCanvasConfigInitialize()
const { closeAll } = usePopup()
const currentMenu = useRecoilValue(currentMenuState)
const { floorPlanState } = useContext(FloorPlanContext)
const { contextMenu, handleClick } = useContextMenu()
@ -76,12 +71,8 @@ export default function CanvasFrame() {
}
initEvent()
})
} else {
setSelectedMenu(null)
}
Object.keys(currentCanvasPlan).length > 0 && canvas && handleModuleSelectionTotal()
} else {
setSelectedMenu(null)
}
gridInit()
}
@ -101,8 +92,6 @@ export default function CanvasFrame() {
useEffect(() => {
setIsGlobalLoading(false)
// .
closeAll()
return () => {
canvas?.clear()
@ -121,38 +110,6 @@ export default function CanvasFrame() {
resetPcsCheckState()
}
/**
* 캔버스가 있을 경우 핫키 이벤트 처리
* hotkeyStore에 핫키 이벤트 리스너 추가
*
* const hotkeys = [
{ key: 'c', fn: () => asdf() },
{ key: 'v', fn: () => qwer() },
]
setHotkeyStore(hotkeys)
*/
const hotkeyState = useRecoilValue(hotkeyStore)
const hotkeyHandlerRef = useRef(null)
useEffect(() => {
hotkeyHandlerRef.current = (e) => {
hotkeyState.forEach((hotkey) => {
if (e.key === hotkey.key) {
hotkey.fn()
}
})
}
document.addEventListener('keyup', hotkeyHandlerRef.current)
return () => {
if (hotkeyHandlerRef.current) {
document.removeEventListener('keyup', hotkeyHandlerRef.current)
}
}
}, [hotkeyState])
/** 핫키 이벤트 처리 끝 */
return (
<div className="canvas-frame">
<canvas ref={canvasRef} id="canvas" style={{ position: 'relative' }}></canvas>

View File

@ -31,13 +31,12 @@ export default function CanvasLayout({ children }) {
return (
<div className="canvas-layout">
<div className={`canvas-page-list ${['outline', 'surface', 'module'].includes(selectedMenu) ? 'active' : ''}`}>
<div className="canvas-id">{objectNo}</div>
<div className="canvas-plane-wrap">
{plans.map((plan, index) => (
<button
key={`plan-${plan.id}`}
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
onClick={() => (plan.isCurrent ? '' : handleCurrentPlan(plan.id))}
onClick={() => handleCurrentPlan(plan.id)}
>
<span>{`Plan ${plan.planNo}`}</span>
{plans.length > 1 && !pathname.includes('/estimate') && !pathname.includes('/simulator') && (

View File

@ -4,7 +4,7 @@ import { useContext, useEffect, useState } from 'react'
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { v4 as uuidv4 } from 'uuid'
@ -50,7 +50,6 @@ import JA from '@/locales/ja.json'
import { QcastContext } from '@/app/QcastProvider'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePolygon } from '@/hooks/usePolygon'
import { useTrestle } from '@/hooks/module/useTrestle'
export default function CanvasMenu(props) {
const { selectedMenu, setSelectedMenu } = props
const pathname = usePathname()
@ -68,7 +67,6 @@ export default function CanvasMenu(props) {
const globalLocale = useRecoilValue(globalLocaleStore)
const canvas = useRecoilValue(canvasState)
const { handleZoomClear, handleZoom } = useCanvasEvent()
const { setAllModuleSurfaceIsComplete, isAllComplete } = useTrestle()
const { handleMenu } = useMenu()
// const urlParams = useSearchParams()
const { handleEstimateSubmit, fetchSetting, estimateContextState, setEstimateContextState } = useEstimateController()
@ -98,7 +96,7 @@ export default function CanvasMenu(props) {
const [lockButtonStyle, setLockButtonStyle] = useState('') //
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //
const resetCommonUtils = useResetRecoilState(commonUtilsState)
//
const { objectNo, pid } = floorPlanState
@ -166,7 +164,6 @@ export default function CanvasMenu(props) {
}
const onClickNav = async (menu) => {
resetCommonUtils()
switch (menu.type) {
case 'drawing':
swalFire({
@ -197,7 +194,6 @@ export default function CanvasMenu(props) {
confirmFn: () => {
//
setAllModuleSurfaceIsComplete(false)
const moduleSurfacesArray = canvas
.getObjects()
.filter((obj) => [POLYGON_TYPE.MODULE_SETUP_SURFACE, POLYGON_TYPE.MODULE, POLYGON_TYPE.OBJECT_SURFACE].includes(obj.name))
@ -237,12 +233,8 @@ export default function CanvasMenu(props) {
await reloadCanvasStatus(objectNo, pid)
break
case 'estimate':
if (!isAllComplete()) {
swalFire({ text: getMessage('estimate.menu.move.valid1') })
return
}
setIsGlobalLoading(true)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan?.planNo ?? pid}/detail` }).then((res) => {
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
if (estimateDetail.estimateDate !== null) {
@ -250,7 +242,7 @@ export default function CanvasMenu(props) {
setCurrentMenu(menu.title)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
setIsGlobalLoading(false)
router.push(`/floor-plan/estimate/5?pid=${selectedPlan?.planNo ?? pid}&objectNo=${objectNo}`)
router.push(`/floor-plan/estimate/5?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
if (pathname === '/floor-plan/estimate/5') {
setIsGlobalLoading(false)
}
@ -263,13 +255,13 @@ export default function CanvasMenu(props) {
break
case 'simulation':
setIsGlobalLoading(true)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan?.planNo ?? pid}/detail` }).then((res) => {
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
if (estimateDetail.estimateDate !== null && estimateDetail.docNo) {
setSelectedMenu(menu.type)
setCurrentMenu(menu.title)
router.push(`/floor-plan/simulator/6?pid=${selectedPlan?.planNo ?? pid}&objectNo=${objectNo}`)
router.push(`/floor-plan/simulator/6?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
if (pathname === '/floor-plan/simulator/6') {
setIsGlobalLoading(false)
}
@ -556,26 +548,13 @@ export default function CanvasMenu(props) {
{
<div className={`vertical-horizontal ${verticalHorizontalMode ? 'on' : ''}`}>
<span>{getMessage('plan.mode.vertical.horizontal')}</span>
<button
title={`${getMessage('plan.mode.vertical.horizontal')} ${verticalHorizontalMode ? 'ON' : 'OFF'}`}
onClick={() => setVerticalHorizontalMode(!verticalHorizontalMode)}
>
{verticalHorizontalMode ? 'ON' : 'OFF'}
</button>
<button onClick={() => setVerticalHorizontalMode(!verticalHorizontalMode)}>{verticalHorizontalMode ? 'ON' : 'OFF'}</button>
</div>
}
<div className="btn-from">
<button className={`btn01 ${commonUtils.text ? 'active' : ''}`} onClick={() => commonFunctions('text')} title="文字作成"></button>
<button
className={`btn02 ${commonUtils.dimension ? 'active' : ''} `}
onClick={() => commonFunctions('dimension')}
title="寸法作成"
></button>
<button
className={`btn03 ${commonUtils.distance ? 'active' : ''} `}
onClick={() => commonFunctions('distance')}
title="定規"
></button>
<button className={`btn01 ${commonUtils.text ? 'active' : ''}`} onClick={() => commonFunctions('text')}></button>
<button className={`btn02 ${commonUtils.dimension ? 'active' : ''} `} onClick={() => commonFunctions('dimension')}></button>
<button className={`btn03 ${commonUtils.distance ? 'active' : ''} `} onClick={() => commonFunctions('distance')}></button>
</div>
{isObjectNotEmpty(selectedRoofMaterial) && addedRoofs.length > 0 && (
<div className="select-box">
@ -601,7 +580,6 @@ export default function CanvasMenu(props) {
sourceKey={'index'}
targetKey={'index'}
disabled={+basicSetting.roofSizeSet === 3}
tagTitle={'屋根材変更'}
/>
}
</div>
@ -610,10 +588,9 @@ export default function CanvasMenu(props) {
<button
className={`btn10 ${floorPlanState.refFileModalOpen && 'active'}`}
onClick={() => setFloorPlanState({ ...floorPlanState, refFileModalOpen: true })}
title="読込"
></button>
{/*<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>*/}
<button className="btn04" onClick={handlePopup} title="設定"></button>
<button className="btn04" onClick={handlePopup}></button>
</div>
<div className="size-control">
<button
@ -622,9 +599,7 @@ export default function CanvasMenu(props) {
handleZoom(false)
}}
></button>
<span onClick={handleZoomClear} title="拡大・縮小">
{canvasZoom}%
</span>
<span onClick={handleZoomClear}>{canvasZoom}%</span>
<button
className="control-btn plus"
onClick={() => {
@ -633,8 +608,8 @@ export default function CanvasMenu(props) {
></button>
</div>
<div className="btn-from">
<button className="btn08" onClick={handleSaveCanvas} title="保存"></button>
<button className="btn09" onClick={handleLeaveCanvas} title="物件検索画面へ移動"></button>
<button className="btn08" onClick={handleSaveCanvas}></button>
<button className="btn09" onClick={handleLeaveCanvas}></button>
</div>
</>
)}
@ -659,7 +634,7 @@ export default function CanvasMenu(props) {
onClick={() => setEstimatePopupOpen(true)}
>
<span className="ico ico01"></span>
<span className="name">{getMessage('plan.menu.estimate.docDownload')}</span>
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
</button>
<button type="button" style={{ display: saveButtonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
<span className="ico ico02"></span>

View File

@ -1,18 +1,15 @@
'use client'
import { useContext, useEffect } from 'react'
import { useEffect } from 'react'
import CanvasMenu from '@/components/floor-plan/CanvasMenu'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { usePopup } from '@/hooks/usePopup'
import '@/styles/contents.scss'
import { notFound, useSearchParams } from 'next/navigation'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useRecoilState, useResetRecoilState } from 'recoil'
import { correntObjectNoState } from '@/store/settingAtom'
import { currentMenuState } from '@/store/canvasAtom'
import { globalLocaleStore } from '@/store/localeAtom'
import { useAxios } from '@/hooks/useAxios'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
export default function FloorPlan({ children }) {
const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState)
@ -23,39 +20,12 @@ export default function FloorPlan({ children }) {
const { selectedMenu, setSelectedMenu } = useCanvasMenu()
const { fetchSettings } = useCanvasSetting()
const resetCurrentMenu = useResetRecoilState(currentMenuState)
const globalLocaleState = useRecoilValue(globalLocaleStore)
const { promiseGet } = useAxios(globalLocaleState)
const { setManagementState } = useContext(GlobalDataContext)
useEffect(() => {
getStuffDetailInfo()
return () => {
resetCurrentMenu()
}
}, [])
const getStuffDetailInfo = () => {
promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => {
if (res.status === 200) {
const { data } = res
console.log(data)
let surfaceTypeValue
if (res.data.surfaceType === 'Ⅲ・Ⅳ') {
surfaceTypeValue = '3'
} else if (res.data.surfaceType === 'Ⅱ') {
surfaceTypeValue = '2'
}
// 0
if (res.data.installHeight === '0') {
res.data.installHeight = ''
}
setManagementState({ ...res.data, surfaceTypeValue: surfaceTypeValue })
}
})
}
/**
* URL 파라미터에서 objectNo 설정
*/

View File

@ -5,10 +5,9 @@ import { useEffect } from 'react'
import { useMessage } from '@/hooks/useMessage'
import useMenu from '@/hooks/common/useMenu'
import { canvasState, currentMenuState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import { subMenusState } from '@/store/menuAtom'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { commonUtilsState } from '@/store/commonUtilsAtom'
export default function MenuDepth01() {
const canvas = useRecoilValue(canvasState)
@ -17,10 +16,8 @@ export default function MenuDepth01() {
const { selectedMenu, setSelectedMenu } = useCanvasMenu()
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
const subMenus = useRecoilValue(subMenusState)
const resetCommonUtils = useResetRecoilState(commonUtilsState)
const onClickMenu = ({ id, menu }) => {
resetCommonUtils()
if (menu === currentMenu) {
handleMenu(selectedMenu)
} else {

View File

@ -120,7 +120,7 @@ export default function ImgLoad() {
value={refImage ? (refImage?.name ?? '') : (currentCanvasPlan?.bgImageName ?? '')}
readOnly
/>
{currentCanvasPlan?.bgImageName && <button className="img-check" onClick={handleFileDelete}></button>}
{refImage && <button className="img-check" onClick={handleFileDelete}></button>}
</div>
</div>
</div>

View File

@ -40,15 +40,15 @@ export default function AuxiliaryEdit(props) {
if (currentObject) {
copy(
currentObject,
arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
arrow2 ? (arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize)) : 0,
)
}
} else {
move(
currentObject,
arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
arrow2 ? (arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize)) : 0,
)
}

View File

@ -1,88 +1,109 @@
import { POLYGON_TYPE, MODULE_SETUP_TYPE } from '@/common/common'
import { useMessage } from '@/hooks/useMessage'
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation'
import { useContext, useEffect, useRef, useState } from 'react'
import Module from '@/components/floor-plan/modal/basic/step/Module'
import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchModule'
import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement'
import Placement from '@/components/floor-plan/modal/basic/step/Placement'
import { useRecoilValue, useRecoilState } from 'recoil'
import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState } from '@/store/canvasAtom'
import { usePopup } from '@/hooks/usePopup'
import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useEvent } from '@/hooks/useEvent'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { addedRoofsState, corridorDimensionSelector, basicSettingState } from '@/store/settingAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import Swal from 'sweetalert2'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useModuleSelection } from '@/hooks/module/useModuleSelection'
import { useOrientation } from '@/hooks/module/useOrientation'
import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import {
canvasState,
checkedModuleState,
currentCanvasPlanState,
isManualModuleLayoutSetupState,
isManualModuleSetupState,
toggleManualSetupModeState,
} from '@/store/canvasAtom'
import { loginUserStore } from '@/store/commonAtom'
import { roofsState } from '@/store/roofAtom'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { addedRoofsState, basicSettingState } from '@/store/settingAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import { useEffect, useRef, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import Swal from 'sweetalert2'
import Trestle from './step/Trestle'
import { currentCanvasPlanState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const [tabNum, setTabNum] = useState(1)
const canvasSetting = useRecoilValue(canvasSettingState)
const orientationRef = useRef(null)
const { initEvent } = useEvent()
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState)
const trestleRef = useRef(null)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const addedRoofs = useRecoilValue(addedRoofsState)
const loginUserState = useRecoilValue(loginUserStore)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const canvas = useRecoilValue(canvasState)
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
const [isClosePopup, setIsClosePopup] = useState({ close: false, id: 0 })
const [checkedModules, setCheckedModules] = useRecoilState(checkedModuleState)
const [roofs, setRoofs] = useState(addedRoofs)
const [manualSetupMode, setManualSetupMode] = useRecoilState(toggleManualSetupModeState)
const [layoutSetup, setLayoutSetup] = useState([{}])
const {
selectedModules,
roughnessCodes,
windSpeedCodes,
managementState,
setManagementState,
moduleList,
setSelectedModules,
selectedSurfaceType,
setSelectedSurfaceType,
installHeight,
setInstallHeight,
standardWindSpeed,
setStandardWindSpeed,
verticalSnowCover,
setVerticalSnowCover,
handleChangeModule,
handleChangeSurfaceType,
handleChangeWindSpeed,
handleChangeInstallHeight,
handleChangeVerticalSnowCover,
} = useModuleSelection({ addedRoofs })
const { nextStep, compasDeg, setCompasDeg } = useOrientation()
const { trigger: orientationTrigger } = useCanvasPopupStatusController(1)
const { trigger: trestleTrigger } = useCanvasPopupStatusController(2)
const { trigger: placementTrigger } = useCanvasPopupStatusController(3)
const [roofsStore, setRoofsStore] = useRecoilState(roofsState)
// const { initEvent } = useContext(EventContext)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup, manualModuleLayoutSetup, restoreModuleInstArea } =
useModuleBasicSetting(tabNum)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(tabNum)
const { updateObjectDate } = useMasterController()
useEffect(() => {
const moduleTabNum = basicSetting.roofSizeSet != 3 ? 3 : 2
const handleBtnNextStep = () => {
if (tabNum === 1) {
orientationRef.current.handleNextStep()
} else if (tabNum === 2) {
if (basicSetting.roofSizeSet !== '3') {
if (!isObjectNotEmpty(moduleSelectionData.module)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
return
}
if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) {
Swal.fire({
title: getMessage('construction.length.difference'),
icon: 'warning',
})
return
}
//
updateObjectDataApi({
objectNo: currentCanvasPlan.objectNo, //_no
standardWindSpeedId: moduleSelectionData.common.stdWindSpeed, //
verticalSnowCover: moduleSelectionData.common.stdSnowLd, //
surfaceType: moduleSelectionData.common.illuminationTpNm, //
installHeight: moduleSelectionData.common.instHt, //
userId: loginUserState.userId, //
})
} else {
if (!isObjectNotEmpty(moduleSelectionData.module)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
return
}
}
}
setTabNum(tabNum + 1)
}
const placementRef = {
isChidori: useRef('false'),
setupLocation: useRef('eaves'),
isMaxSetup: useRef('false'),
}
const placementFlatRef = {
setupLocation: useRef('south'),
}
const handleManualModuleSetup = () => {
setIsManualModuleSetup(!isManualModuleSetup)
}
const updateObjectDataApi = async (params) => {
const res = await updateObjectDate(params)
}
useEffect(() => {
let hasModules = canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
@ -90,42 +111,23 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
if (hasModules) {
orientationRef.current.handleNextStep()
setTabNum(moduleTabNum)
setTabNum(3)
}
}, [])
useEffect(() => {
if (roofsStore && addedRoofs) {
setRoofs(
addedRoofs.map((roof, index) => {
return {
...roof,
...roofsStore[index]?.addRoof,
construction: roofsStore[index]?.construction,
trestle: roofsStore[index]?.trestle,
trestleDetail: roofsStore[index]?.trestleDetail,
}
}),
)
setModuleSelectionData({
...moduleSelectionData,
roofConstructions: roofsStore.map((roof) => {
return {
roofIndex: roof.roofIndex,
addRoof: roof.addRoof,
construction: roof.construction,
trestle: roof.trestle,
trestleDetail: roof.trestleDetail,
}
}),
})
//
const handleClosePopup = (id) => {
if (tabNum == 3) {
if (isManualModuleSetup) {
setIsManualModuleSetup(false)
}
}
}, [roofsStore, addedRoofs])
setIsClosePopup({ close: true, id: id })
}
useEffect(() => {
if (basicSetting.roofSizeSet !== '3') {
manualModuleSetup()
manualModuleSetup(placementRef)
} else {
manualFlatroofModuleSetup(placementFlatRef)
}
@ -138,224 +140,55 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
setIsManualModuleSetup(false)
}, [checkedModules])
useEffect(() => {
if (basicSetting.roofSizeSet !== '3') {
if (manualSetupMode.indexOf('manualSetup') > -1) {
manualModuleSetup()
} else if (manualSetupMode.indexOf('manualLayoutSetup') > -1) {
manualModuleLayoutSetup(layoutSetup)
} else if (manualSetupMode.indexOf('off') > -1) {
manualModuleSetup()
manualModuleLayoutSetup(layoutSetup)
}
} else {
manualFlatroofModuleSetup(placementFlatRef)
}
if (isClosePopup.close) {
closePopup(isClosePopup.id)
}
}, [manualSetupMode, isClosePopup])
useEffect(() => {
if (isManualModuleLayoutSetup) {
manualModuleLayoutSetup(layoutSetup)
}
}, [layoutSetup])
useEffect(() => {
setIsManualModuleSetup(false)
setIsManualModuleLayoutSetup(false)
setManualSetupMode(`off`)
}, [checkedModules])
const handleBtnNextStep = () => {
if (tabNum === 1) {
orientationRef.current.handleNextStep()
setAddedRoofs(roofs)
// setTabNum(tabNum + 1)
return
} else if (tabNum === 2) {
if (basicSetting.roofSizeSet !== '3') {
// if (addedRoofs.length !== moduleSelectionData.roofConstructions.length) {
// Swal.fire({
// title: getMessage('construction.length.difference'),
// icon: 'warning',
// })
// return
// }
trestleRef.current.isComplete().then((res) => {
if (!res) return
})
//
} else {
if (!isObjectNotEmpty(moduleSelectionData.module)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
return
}
setTabNum(tabNum + 1)
}
}
}
const placementFlatRef = {
setupLocation: useRef('south'),
}
const handleManualModuleSetup = () => {
setManualSetupMode(`manualSetup_${!isManualModuleSetup}`)
setIsManualModuleSetup(!isManualModuleSetup)
}
const handleManualModuleLayoutSetup = () => {
setManualSetupMode(`manualLayoutSetup_${!isManualModuleLayoutSetup}`)
setIsManualModuleLayoutSetup(!isManualModuleLayoutSetup)
}
const updateObjectDataApi = async (params) => {
const res = await updateObjectDate(params)
}
//
const handleClosePopup = (id) => {
if (tabNum == 3) {
if (isManualModuleSetup) {
setIsManualModuleSetup(false)
}
if (isManualModuleLayoutSetup) {
setIsManualModuleLayoutSetup(false)
}
}
setIsClosePopup({ close: true, id: id })
}
const orientationProps = {
roofs,
setRoofs,
tabNum,
setTabNum,
compasDeg, //
setCompasDeg,
selectedModules,
moduleSelectionData,
setModuleSelectionData,
roughnessCodes, //
windSpeedCodes, //
managementState,
setManagementState,
moduleList, //
setSelectedModules,
selectedSurfaceType,
setSelectedSurfaceType,
installHeight, //
setInstallHeight,
standardWindSpeed, //
setStandardWindSpeed,
verticalSnowCover, //
setVerticalSnowCover,
currentCanvasPlan,
loginUserState,
handleChangeModule,
handleChangeSurfaceType,
handleChangeWindSpeed,
handleChangeInstallHeight,
handleChangeVerticalSnowCover,
orientationTrigger,
nextStep,
updateObjectDataApi,
}
const trestleProps = {
roofs,
setRoofs,
setRoofsStore,
tabNum,
setTabNum,
moduleSelectionData,
setModuleSelectionData,
trestleTrigger,
}
const placementProps = {}
return (
<WithDraggable isShow={true} pos={pos} className={basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' ? 'll' : 'lx-2'}>
<WithDraggable isShow={true} pos={pos} className="lx-2">
<WithDraggable.Header title={getMessage('plan.menu.module.circuit.setting.default')} onClose={() => handleClosePopup(id)} />
<WithDraggable.Body>
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<span className={`tab-arr ${tabNum !== 1 ? 'act' : ''}`}></span>
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && (
<>
<div className={`module-tab-bx ${tabNum !== 1 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.setting')}</div>
<span className={`tab-arr ${tabNum === 3 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 3 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.placement')}</div>
</>
)}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && (
<>
<div className={`module-tab-bx ${tabNum === 2 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.placement')}</div>
</>
)}
<div className={`module-tab-bx ${tabNum !== 1 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.setting')}</div>
<span className={`tab-arr ${tabNum === 3 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 3 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.placement')}</div>
</div>
{tabNum === 1 && <Orientation ref={orientationRef} {...orientationProps} />}
{tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />}
{/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && <Trestle ref={trestleRef} {...trestleProps} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && (
<Placement setTabNum={setTabNum} layoutSetup={layoutSetup} setLayoutSetup={setLayoutSetup} />
)}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && <Module setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />}
{/*배치면 초기설정 - 입력방법: 육지붕*/}
{/* {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && <PitchModule setTabNum={setTabNum} />} */}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && (
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && (
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
)}
<div className="grid-btn-wrap">
{/* {tabNum === 1 && <button className="btn-frame modal mr5">{getMessage('modal.common.save')}</button>} */}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && (
{tabNum !== 1 && (
<button className="btn-frame modal mr5" onClick={() => setTabNum(tabNum - 1)}>
{getMessage('modal.module.basic.setting.prev')}
</button>
)}
{/*{tabNum !== 3 && <button className="btn-frame modal act mr5">{getMessage('modal.common.save')}</button>}*/}
{tabNum !== 3 && (
<button className="btn-frame modal" onClick={handleBtnNextStep}>
Next
</button>
)}
{tabNum === 3 && (
<>
{tabNum !== 1 && (
<button className="btn-frame modal mr5" onClick={() => setTabNum(tabNum - 1)}>
{getMessage('modal.module.basic.setting.prev')}
</button>
)}
{tabNum !== 3 && (
<button className="btn-frame modal" onClick={handleBtnNextStep}>
Next
</button>
)}
{tabNum === 3 && (
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && (
<>
<button className={`btn-frame modal mr5 ${isManualModuleLayoutSetup ? 'act' : ''}`} onClick={handleManualModuleLayoutSetup}>
{getMessage('modal.module.basic.setting.row.batch')}
</button>
<button className="btn-frame modal mr5" onClick={() => autoModuleSetup(MODULE_SETUP_TYPE.LAYOUT, layoutSetup)}>
{getMessage('modal.module.basic.setting.auto.row.batch')}
</button>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>
<button className="btn-frame modal act mr5" onClick={() => autoModuleSetup(MODULE_SETUP_TYPE.AUTO)}>
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
{getMessage('modal.module.basic.setting.auto.placement')}
</button>
</>
)}
</>
)}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && (
<>
{tabNum === 1 && (
<button className="btn-frame modal" onClick={handleBtnNextStep}>
Next
</button>
)}
{tabNum === 2 && (
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && (
<>
<button className="btn-frame modal mr5" onClick={() => setTabNum(tabNum - 1)}>
{getMessage('modal.module.basic.setting.prev')}
</button>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>

View File

@ -1,465 +1,115 @@
import { forwardRef, use, useContext, useEffect, useImperativeHandle, useState } from 'react'
import { forwardRef, useContext, useEffect, useImperativeHandle, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useOrientation } from '@/hooks/module/useOrientation'
import { getDegreeInOrientation } from '@/util/canvas-util'
import { numberCheck } from '@/util/common-utils'
import { addedRoofsState, basicSettingState } from '@/store/settingAtom'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import QSelectBox from '@/components/common/select/QSelectBox'
import { roofsState } from '@/store/roofAtom'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import Swal from 'sweetalert2'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
export const Orientation = forwardRef((props, ref) => {
export const Orientation = forwardRef(({ tabNum }, ref) => {
const { getMessage } = useMessage()
const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController(1)
const { nextStep, compasDeg, setCompasDeg } = useOrientation()
const [hasAnglePassivity, setHasAnglePassivity] = useState(false)
const basicSetting = useRecoilValue(basicSettingState)
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState) //
const [roofsStore, setRoofsStore] = useRecoilState(roofsState)
const [roofTab, setRoofTab] = useState(0) //
const {
roofs,
setRoofs,
tabNum,
setTabNum,
compasDeg,
setCompasDeg,
selectedModules,
roughnessCodes,
windSpeedCodes,
managementState,
setManagementState,
moduleList,
moduleSelectionData,
setModuleSelectionData,
setSelectedModules,
selectedSurfaceType,
setSelectedSurfaceType,
installHeight,
setInstallHeight,
standardWindSpeed,
setStandardWindSpeed,
verticalSnowCover,
setVerticalSnowCover,
orientationTrigger,
nextStep,
currentCanvasPlan,
loginUserState,
updateObjectDataApi,
} = props
const [inputCompasDeg, setInputCompasDeg] = useState(compasDeg ?? 0)
const [inputInstallHeight, setInputInstallHeight] = useState('0')
const [inputMargin, setInputMargin] = useState('0')
const [inputVerticalSnowCover, setInputVerticalSnowCover] = useState('0')
const [inputRoughness, setInputRoughness] = useState(selectedSurfaceType)
const [inputStandardWindSpeed, setInputStandardWindSpeed] = useState(standardWindSpeed)
const { restoreModuleInstArea } = useModuleBasicSetting()
const moduleData = {
header: [
{ name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' },
{
name: `${getMessage('height')} (mm)`,
prop: 'height',
},
{ name: `${getMessage('width')} (mm)`, prop: 'width' },
{ name: `${getMessage('output')} (W)`, prop: 'output' },
],
}
useEffect(() => {
if (basicSetting.roofSizeSet == '3') {
restoreModuleInstArea()
}
}, [])
useEffect(() => {
if (moduleSelectionData?.common) {
setInputMargin(moduleSelectionData?.common?.margin)
}
}, [moduleSelectionData])
useEffect(() => {
if (selectedModules) {
setSelectedModules(moduleList.find((module) => module.itemId === selectedModules.itemId))
}
}, [selectedModules])
useEffect(() => {
if (selectedSurfaceType) {
setInputRoughness(roughnessCodes.find((code) => code.clCode === managementState?.surfaceTypeValue))
}
}, [selectedSurfaceType])
useEffect(() => {
if (standardWindSpeed) setInputStandardWindSpeed(windSpeedCodes.find((code) => code.clCode === managementState?.standardWindSpeedId))
}, [standardWindSpeed])
useEffect(() => {
if (managementState?.installHeight && managementState?.installHeight) {
setSelectedSurfaceType(roughnessCodes.find((code) => code.clCode === managementState?.surfaceTypeValue))
setInputInstallHeight(managementState?.installHeight)
setStandardWindSpeed(windSpeedCodes.find((code) => code.clCode === managementState?.standardWindSpeedId))
setInputVerticalSnowCover(managementState?.verticalSnowCover)
}
}, [managementState])
useImperativeHandle(ref, () => ({
handleNextStep,
}))
const handleNextStep = () => {
if (isComplete()) {
const common = {
illuminationTp: inputRoughness.clCode,
illuminationTpNm: inputRoughness.clCodeNm,
instHt: inputInstallHeight,
stdWindSpeed: inputStandardWindSpeed?.clCode,
stdSnowLd: inputVerticalSnowCover,
saleStoreNorthFlg: managementState?.saleStoreNorthFlg,
moduleTpCd: selectedModules.itemTp,
moduleItemId: selectedModules.itemId,
margin: inputMargin,
}
setCompasDeg(inputCompasDeg)
setInstallHeight(inputInstallHeight)
setVerticalSnowCover(inputVerticalSnowCover)
setSelectedSurfaceType(inputRoughness)
setStandardWindSpeed(inputStandardWindSpeed)
nextStep(inputCompasDeg)
setManagementState({
...managementState,
installHeight: inputInstallHeight,
verticalSnowCover: inputVerticalSnowCover,
standardWindSpeedId: inputStandardWindSpeed?.clCode,
surfaceType: inputRoughness.clCodeNm,
surfaceTypeValue: inputRoughness.clCode,
})
setModuleSelectionData({
...moduleSelectionData,
module: {
...selectedModules,
},
common,
})
orientationTrigger({
compasDeg: inputCompasDeg,
common: common,
module: {
...selectedModules,
},
margin: inputMargin,
})
updateObjectDataApi({
objectNo: currentCanvasPlan.objectNo, //_no
standardWindSpeedId: inputStandardWindSpeed?.clCode, //
verticalSnowCover: inputVerticalSnowCover, //
surfaceType: inputRoughness.clCodeNm, //
installHeight: inputInstallHeight, //
userId: loginUserState.userId, //
})
setTabNum(2)
} else {
if (!selectedModules || !selectedModules.itemId) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
})
return
}
}
nextStep()
canvasPopupStatusTrigger(compasDeg)
}
useEffect(() => {
checkDegree(compasDeg)
}, [compasDeg])
const checkDegree = (e) => {
if (e === '-0' || e === '-') {
setInputCompasDeg('-')
setCompasDeg('-')
return
}
if (e === '0-') {
setInputCompasDeg('-0')
setCompasDeg('-0')
return
}
if (Number(e) >= -180 && Number(e) <= 180) {
if (numberCheck(Number(e))) {
setInputCompasDeg(Number(e))
setCompasDeg(Number(e))
}
} else {
setInputCompasDeg(compasDeg)
setCompasDeg(compasDeg)
}
}
const isComplete = () => {
if (!selectedModules || !selectedModules.itemId) return false
if (basicSetting && basicSetting.roofSizeSet !== '3') {
if (inputInstallHeight <= 0) {
return false
}
if (+inputVerticalSnowCover <= 0) {
return false
}
if (!inputStandardWindSpeed) return false
if (!inputRoughness) return false
}
return true
}
const handleChangeModule = (e) => {
resetRoofs()
setSelectedModules(e)
}
const handleChangeRoughness = (e) => {
resetRoofs()
setInputRoughness(e)
}
const handleChangeInstallHeight = (e) => {
resetRoofs()
setInputInstallHeight(e)
}
const handleChangeStandardWindSpeed = (e) => {
resetRoofs()
setInputStandardWindSpeed(e)
}
const handleChangeVerticalSnowCover = (e) => {
resetRoofs()
setInputVerticalSnowCover(e)
}
const resetRoofs = () => {
const newRoofs = addedRoofs.map((roof) => {
return {
...roof,
trestle: {
lengthBase: null,
trestleMkrCd: null,
constMthdCd: null,
constTp: null,
roofBaseCd: null,
roofPchBase: null,
},
addRoof: {
...roof.addRoof,
lengthBase: null,
eavesMargin: null,
kerabaMargin: null,
ridgeMargin: null,
},
construction: {
constTp: null,
cvrYn: 'N',
snowGdPossYn: 'N',
cvrChecked: false,
snowGdChecked: false,
},
}
})
// setRoofs(newRoofs)
// setAddedRoofs(newRoofs)
setRoofsStore(newRoofs)
}
return (
<>
<div className="properties-setting-wrap">
<div className="outline-wrap">
<div className="roof-module-inner">
<div className="compas-wrapper">
<div className="guide">{getMessage('modal.module.basic.setting.orientation.setting.info')}</div>
<div className="roof-module-compas">
<div className="compas-box">
<div className="compas-box-inner">
{Array.from({ length: 180 / 15 }).map((dot, index) => (
<div
key={index}
className={`circle ${getDegreeInOrientation(inputCompasDeg) === -1 * (-15 * index + 180) || (index === 0 && inputCompasDeg >= 172 && index === 0 && inputCompasDeg <= 180) || (inputCompasDeg === -180 && index === 0) ? 'act' : ''}`}
onClick={() => {
if (index === 0) {
setInputCompasDeg(180)
return
}
setInputCompasDeg(-1 * (-15 * index + 180))
}}
>
{index === 0 && <i>180°</i>}
{index === 6 && <i>-90°</i>}
</div>
))}
{Array.from({ length: 180 / 15 }).map((dot, index) => (
<div
key={index}
className={`circle ${inputCompasDeg !== 180 && getDegreeInOrientation(inputCompasDeg) === 15 * index ? 'act' : ''}`}
onClick={() => setInputCompasDeg(15 * index)}
>
{index === 0 && <i>0°</i>}
{index === 6 && <i>90°</i>}
</div>
))}
<div className="compas">
<div className="compas-arr" style={{ transform: `rotate(${getDegreeInOrientation(inputCompasDeg)}deg)` }}></div>
</div>
<div className="guide">{getMessage('modal.module.basic.setting.orientation.setting.info')}</div>
<div className="roof-module-compas">
<div className="compas-box">
<div className="compas-box-inner">
{Array.from({ length: 180 / 15 }).map((dot, index) => (
<div
key={index}
className={`circle ${getDegreeInOrientation(compasDeg) === -1 * (-15 * index + 180) || (index === 0 && compasDeg >= 172 && index === 0 && compasDeg <= 180) || (compasDeg === -180 && index === 0) ? 'act' : ''}`}
onClick={() => {
if (index === 0) {
setCompasDeg(180)
return
}
setCompasDeg(-1 * (-15 * index + 180))
}}
>
{index === 0 && <i>180°</i>}
{index === 6 && <i>-90°</i>}
</div>
</div>
</div>
<div className="center-wrap">
<div className="outline-form">
<div className="d-check-box pop mr10">
<input type="checkbox" id="ch99" checked={hasAnglePassivity} onChange={() => setHasAnglePassivity(!hasAnglePassivity)} />
<label htmlFor="ch99">{getMessage('modal.module.basic.setting.orientation.setting.angle.passivity')}</label>
))}
{Array.from({ length: 180 / 15 }).map((dot, index) => (
<div
key={index}
className={`circle ${compasDeg !== 180 && getDegreeInOrientation(compasDeg) === 15 * index ? 'act' : ''}`}
onClick={() => setCompasDeg(15 * index)}
>
{index === 0 && <i>0°</i>}
{index === 6 && <i>90°</i>}
</div>
<div className="input-grid mr10" style={{ width: '60px' }}>
<input
type="text"
className="input-origin block"
value={inputCompasDeg}
readOnly={!hasAnglePassivity}
placeholder={0}
onChange={(e) => checkDegree(e.target.value)}
/>
</div>
<span className="thin">°</span>
<span className="thin"> -180 180 </span>
))}
<div className="compas">
<div className="compas-arr" style={{ transform: `rotate(${getDegreeInOrientation(compasDeg)}deg)` }}></div>
</div>
</div>
</div>
<div className="compas-table-wrap">
<div className="compas-table-box mb10">
<div className="outline-form mb10">
<span>{getMessage('modal.module.basic.setting.module.setting')}</span>
<div className="grid-select">
{moduleList && (
<QSelectBox
options={moduleList}
value={selectedModules}
targetKey={'itemId'}
sourceKey={'itemId'}
showKey={'itemNm'}
onChange={(e) => handleChangeModule(e)}
/>
)}
</div>
</div>
<div className="roof-module-table">
<table>
<thead>
<tr>
{moduleData.header.map((header) => {
return (
<th key={header.prop} style={{ width: header.width ? header.width + 'px' : '' }}>
{header.name}
</th>
)
})}
</tr>
</thead>
<tbody>
{Array.from({ length: 3 }).map((_, index) => {
return selectedModules && selectedModules?.itemList && selectedModules?.itemList?.length >= index + 1 ? (
<tr key={index}>
<td>
<div className="color-wrap">
<span
className="color-box"
style={{
backgroundColor: selectedModules.itemList[index].color,
}}
></span>
<span className="name">{selectedModules.itemList[index].itemNm}</span>
</div>
</td>
<td className="al-r">{Number(selectedModules.itemList[index].shortAxis).toFixed(0)}</td>
<td className="al-r">{Number(selectedModules.itemList[index].longAxis).toFixed(0)}</td>
<td className="al-r">{Number(selectedModules.itemList[index].wpOut).toFixed(0)}</td>
</tr>
) : (
<tr key={index}>
<td>
<div className="color-wrap"></div>
</td>
<td className="al-r"></td>
<td className="al-r"></td>
<td className="al-r"></td>
</tr>
)
})}
</tbody>
</table>
</div>
{basicSetting && basicSetting.roofSizeSet == '3' && (
<div className="outline-form mt15">
<span>{getMessage('modal.module.basic.setting.module.placement.area')}</span>
<div className="input-grid mr10" style={{ width: '60px' }}>
<input type="number" className="input-origin block" value={inputMargin} onChange={(e) => setInputMargin(e.target.value)} />
</div>
<span className="thin">m</span>
</div>
)}
</div>
</div>
<div className="center-wrap">
<div className="d-check-box pop">
<input type="checkbox" id="ch99" checked={hasAnglePassivity} onChange={() => setHasAnglePassivity(!hasAnglePassivity)} />
<label htmlFor="ch99">{getMessage('modal.module.basic.setting.orientation.setting.angle.passivity')}-180 180</label>
</div>
<div className="outline-form">
<div className="input-grid mr10" style={{ width: '160px' }}>
<input
type="text"
className="input-origin block"
value={compasDeg}
readOnly={!hasAnglePassivity}
placeholder={0}
onChange={
(e) => checkDegree(e.target.value)
// setCompasDeg(
{basicSetting && basicSetting.roofSizeSet != '3' && (
<div className="compas-table-box">
<div className="compas-grid-table">
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.surface.type')}</span>
<div className="grid-select">
{roughnessCodes.length > 0 && managementState && (
<QSelectBox
options={roughnessCodes}
value={inputRoughness}
targetKey={'clCode'}
sourceKey={'clCode'}
showKey={'clCodeNm'}
onChange={(e) => handleChangeRoughness(e)}
/>
)}
</div>
</div>
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.fitting.height')}</span>
<div className="input-grid mr10">
<input
type="number"
className="input-origin block"
value={inputInstallHeight}
onChange={(e) => handleChangeInstallHeight(e.target.value)}
/>
</div>
<span className="thin">m</span>
</div>
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.standard.wind.speed')}</span>
<div className="grid-select">
{windSpeedCodes.length > 0 && managementState && (
<QSelectBox
title={''}
options={windSpeedCodes}
value={inputStandardWindSpeed}
targetKey={'clCode'}
sourceKey={'clCode'}
showKey={'clCodeNm'}
onChange={(e) => handleChangeStandardWindSpeed(e)}
/>
)}
</div>
</div>
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.standard.snowfall.amount')}</span>
<div className="input-grid mr10">
<input
type="number"
className="input-origin block"
value={inputVerticalSnowCover}
onChange={(e) => handleChangeVerticalSnowCover(e.target.value)}
/>
</div>
<span className="thin">cm</span>
</div>
</div>
</div>
)}
// e.target.value === '-' || (e.target.value !== '' && parseInt(e.target.value) <= 180 && parseInt(e.target.value) >= -180)
// ? e.target.value
// : 0,
// )
}
/>
</div>
<span className="thin">°</span>
</div>
</div>
</div>

View File

@ -1,45 +1,29 @@
import { forwardRef, useEffect, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import {
checkedModuleState,
isManualModuleLayoutSetupState,
isManualModuleSetupState,
moduleRowColArrayState,
moduleSetupOptionState,
toggleManualSetupModeState,
} from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { checkedModuleState, currentCanvasPlanState, isManualModuleSetupState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
import Image from 'next/image'
const Placement = forwardRef((props, refs) => {
const { getMessage } = useMessage()
const [useTab, setUseTab] = useState(true)
const [guideType, setGuideType] = useState('batch')
const [isChidori, setIsChidori] = useState(false)
const [isChidoriNotAble, setIsChidoriNotAble] = useState(false)
const [setupLocation, setSetupLocation] = useState('eaves')
const [isMaxSetup, setIsMaxSetup] = useState('false')
const [selectedItems, setSelectedItems] = useState({})
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState)
const setCheckedModules = useSetRecoilState(checkedModuleState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const { makeModuleInitArea, roofOutlineColor } = useModuleBasicSetting(3)
const { makeModuleInitArea } = useModuleBasicSetting(3)
const [isMultiModule, setIsMultiModule] = useState(false)
//
const setIsManualModuleSetup = useSetRecoilState(isManualModuleSetupState)
const setIsManualModuleLayoutSetup = useSetRecoilState(isManualModuleLayoutSetupState)
const setManualSetupMode = useSetRecoilState(toggleManualSetupModeState)
const [moduleSetupOption, setModuleSetupOption] = useRecoilState(moduleSetupOptionState) //
const resetModuleSetupOption = useResetRecoilState(moduleSetupOptionState)
const [colspan, setColspan] = useState(1)
const moduleRowColArray = useRecoilValue(moduleRowColArrayState)
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
//
useEffect(() => {
@ -52,24 +36,11 @@ const Placement = forwardRef((props, refs) => {
makeModuleInitArea(moduleSelectionData)
}
if (moduleSelectionData.module.itemList.length > 1) {
setColspan(2)
}
return () => {
// refs.isChidori.current = 'false'
// refs.setupLocation.current = 'eaves'
setIsManualModuleSetup(false)
setIsManualModuleLayoutSetup(false)
setManualSetupMode('off')
resetModuleSetupOption()
}
}, [])
// useEffect(() => {
// console.log('moduleRowColArray', moduleRowColArray)
// }, [moduleRowColArray])
//
useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData)) {
@ -83,10 +54,8 @@ const Placement = forwardRef((props, refs) => {
initCheckedModule = { ...initCheckedModule, [obj.itemId]: true }
}
})
setSelectedItems(initCheckedModule)
setSelectedModules(moduleSelectionData.module)
props.setLayoutSetup(moduleSelectionData.module.itemList.map((item) => ({ moduleId: item.itemId, col: 0, row: 0, checked: true })))
}
//
@ -111,79 +80,63 @@ const Placement = forwardRef((props, refs) => {
header: [
{ type: 'check', name: '', prop: 'check', width: 70 },
{ type: 'color-box', name: getMessage('module'), prop: 'module' },
{ type: 'text', name: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn'), prop: 'mixAsgYn', width: 50 },
{ type: 'text', name: `段数`, prop: 'rows', width: 60 },
{ type: 'text', name: `列数`, prop: 'cols', width: 60 },
{ type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 },
],
rows: [],
}
const handleChangeChidori = (e) => {
const bool = e.target.value === 'true' ? true : false
setModuleSetupOption({ ...moduleSetupOption, isChidori: bool })
//
setIsManualModuleSetup(false)
setIsManualModuleLayoutSetup(false)
setManualSetupMode('off')
setIsChidori(bool)
refs.isChidori.current = e.target.value
}
const handleSetupLocation = (e) => {
setModuleSetupOption({ ...moduleSetupOption, setupLocation: e.target.value })
setSetupLocation(e.target.value)
refs.setupLocation.current = e.target.value
}
//
setIsManualModuleSetup(false)
setIsManualModuleLayoutSetup(false)
setManualSetupMode('off')
const handleMaxSetup = (e) => {
if (e.target.checked) {
setIsMaxSetup('true')
refs.isMaxSetup.current = 'true'
} else {
setIsMaxSetup('false')
refs.isMaxSetup.current = 'false'
}
}
//
const handleSelectedItem = (e, itemId) => {
const handleSelectedItem = (e) => {
setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked })
const newLayoutSetup = [...props.layoutSetup]
props.layoutSetup.forEach((item, index) => {
if (item.moduleId === itemId) {
newLayoutSetup[index] = { ...props.layoutSetup[index], checked: e.target.checked }
}
})
props.setLayoutSetup(newLayoutSetup)
}
const handleLayoutSetup = (e, itemId, index) => {
const newLayoutSetup = [...props.layoutSetup]
newLayoutSetup[index] = {
...newLayoutSetup[index],
moduleId: itemId,
[e.target.name]: Number(e.target.value),
}
props.setLayoutSetup(newLayoutSetup)
}
return (
<>
<div className="module-table-flex-wrap">
<div className="module-table-flex-wrap mb10">
<div className="module-table-box">
<div className="module-table-inner">
<div className="roof-module-table">
<table>
<thead>
{moduleData.header.map((data) => (
<th key={data.prop} style={{ width: data.width ? data.width : '' }}>
{data.type === 'check' ? (
<div className="d-check-box no-text pop">
<input type="checkbox" id="ch01" disabled />
<label htmlFor="ch01"></label>
</div>
) : (
data.name
)}
</th>
))}
<tr>
{moduleData.header.map((data) => (
<th key={data.prop} style={{ width: data.width ? data.width : '' }}>
{data.type === 'check' ? (
<div className="d-check-box no-text pop">
<input type="checkbox" id="ch01" disabled />
<label htmlFor="ch01"></label>
</div>
) : (
data.name
)}
</th>
))}
</tr>
</thead>
<tbody>
{selectedModules?.itemList &&
selectedModules?.itemList?.map((item, index) => (
{selectedModules.itemList &&
selectedModules.itemList.map((item, index) => (
<tr key={index}>
<td className="al-c">
<div className="d-check-box no-text pop">
@ -192,7 +145,7 @@ const Placement = forwardRef((props, refs) => {
id={item.itemId}
name={item.itemId}
checked={selectedItems[item.itemId]}
onChange={(e) => handleSelectedItem(e, item.itemId)}
onChange={handleSelectedItem}
/>
<label htmlFor={item.itemId}></label>
</div>
@ -203,209 +156,93 @@ const Placement = forwardRef((props, refs) => {
<span className="name">{item.itemNm}</span>
</div>
</td>
<td className="al-c">
<div className="color-wrap">
<span className="name">{item.mixAsgYn}</span>
</div>
</td>
<td className="al-r">
<div className="input-grid">
<input
type="text"
className="input-origin block"
name="row"
value={props.layoutSetup[index]?.row ?? 1}
defaultValue={0}
onChange={(e) => handleLayoutSetup(e, item.itemId, index)}
/>
</div>
</td>
<td className="al-r">
<div className="input-grid">
<input
type="text"
className="input-origin block"
name="col"
value={props.layoutSetup[index]?.col ?? 1}
defaultValue={0}
onChange={(e) => handleLayoutSetup(e, item.itemId, index)}
/>
</div>
</td>
<td className="al-r">{item.wpOut}</td>
</tr>
))}
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div className="module-table-box non-flex">
<div className="module-table-box">
<div className="module-table-inner">
<div className="roof-module-table">
<table>
<thead>
<tr>
<th>{getMessage('modal.module.basic.setting.module.placement.waterfowl.arrangement')}</th>
<th>{getMessage('modal.module.basic.setting.module.placement.arrangement.standard')}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="hexagonal-radio-wrap">
<div className="d-check-radio pop mb10">
<input
type="radio"
name="radio02"
id="ra03"
checked={moduleSetupOption.isChidori}
disabled={isChidoriNotAble}
value={'true'}
onChange={(e) => handleChangeChidori(e)}
/>
<label htmlFor="ra03">{getMessage('modal.module.basic.setting.module.placement.do')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio02"
id="ra04"
checked={!moduleSetupOption.isChidori}
value={'false'}
onChange={(e) => handleChangeChidori(e)}
/>
<label htmlFor="ra04">{getMessage('modal.module.basic.setting.module.placement.do.not')}</label>
</div>
</div>
</td>
<td>
<div className="hexagonal-radio-wrap">
<div className="d-check-radio pop mb10">
<input
type="radio"
name="radio03"
id="ra05"
checked={moduleSetupOption.setupLocation === 'eaves'}
value={'eaves'}
onChange={handleSetupLocation}
/>
<label htmlFor="ra05">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard.eaves')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio03"
id="ra06"
checked={moduleSetupOption.setupLocation === 'ridge'}
value={'ridge'}
onChange={handleSetupLocation}
disabled={isMultiModule}
/>
<label htmlFor="ra06">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard.ridge')}</label>
</div>
</div>
</td>
</tr>
</tbody>
</table>
<div className="self-table-tit">{getMessage('modal.module.basic.setting.module.placement.select.fitting.type')}</div>
<div className="module-self-table">
<div className="self-table-item">
<div className="self-item-th">{getMessage('modal.module.basic.setting.module.placement.waterfowl.arrangement')}</div>
<div className="self-item-td">
<div className="pop-form-radio">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
checked={isChidori}
disabled={isChidoriNotAble}
value={'true'}
onChange={(e) => handleChangeChidori(e)}
/>
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.module.placement.do')}</label>
</div>
<div className="d-check-radio pop">
<input type="radio" name="radio02" id="ra02" checked={!isChidori} value={'false'} onChange={(e) => handleChangeChidori(e)} />
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.module.placement.do.not')}</label>
</div>
</div>
</div>
</div>
<div className="self-table-item">
<div className="self-item-th">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard')}</div>
<div className="self-item-td">
<div className="pop-form-radio">
<div className="d-check-radio pop">
<input
type="radio"
name="radio03"
id="ra03"
checked={setupLocation === 'center'}
value={'center'}
onChange={handleSetupLocation}
disabled={isMultiModule}
/>
<label htmlFor="ra03">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard.center')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio04"
id="ra04"
checked={setupLocation === 'eaves'}
value={'eaves'}
onChange={handleSetupLocation}
/>
<label htmlFor="ra04">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard.eaves')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio05"
id="ra05"
checked={setupLocation === 'ridge'}
value={'ridge'}
onChange={handleSetupLocation}
disabled={isMultiModule}
/>
<label htmlFor="ra05">{getMessage('modal.module.basic.setting.module.placement.arrangement.standard.ridge')}</label>
</div>
</div>
</div>
</div>
</div>
<div className="self-table-flx">
{/* <div className="d-check-box pop">
<input type="checkbox" id="ch04" checked={isMaxSetup === 'true'} value={'true'} onChange={handleMaxSetup} />
<label htmlFor="ch04">{getMessage('modal.module.basic.setting.module.placement.maximum')}</label>
</div> */}
</div>
</div>
</div>
</div>
<div className="hide-tab-wrap">
<div className="hide-check-guide">
{getMessage('modal.module.basic.setting.module.placement.info')}
<button className={`arr ${useTab ? 'act' : ''}`} onClick={() => setUseTab(!useTab)}></button>
</div>
<div className={`hide-tab-contents ${!useTab ? 'hide' : ''}`}>
<div className="roof-content-tab-wrap">
<button className={`btn-frame block modal mr5 ${guideType === 'batch' ? 'act' : ''} `} onClick={() => setGuideType('batch')}>
{getMessage('modal.module.basic.setting.module.placement.info.batch')}
</button>
<button className={`btn-frame block modal mr5 ${guideType === 'module' ? 'act' : ''}`} onClick={() => setGuideType('module')}>
{getMessage('modal.module.basic.setting.module.placement.info.module')}
</button>
</div>
{guideType === 'batch' && (
<div className={`roof-warning-wrap mt10`}>
<div className="guide">
{getMessage('modal.module.basic.setting.module.placement.info.batch.content1')}
<br />
{getMessage('modal.module.basic.setting.module.placement.info.batch.content2')}
</div>
<div className="roof-warning-img-wrap">
<div className="roof-warning-img">
<Image src={'/static/images/canvas/roof_warning_correct.png'} width={350} height={198} alt="" />
</div>
<div className="roof-warning-img">
<Image src={'/static/images/canvas/roof_warning_wrong.png'} width={350} height={198} alt="" />
</div>
</div>
</div>
)}
{guideType === 'module' && (
<div className={`module-table-box mt10 ${!useTab ? 'hide' : ''}`}>
<div className="module-table-inner">
<div className="roof-module-table">
<table className="">
<thead>
<tr>
<th rowSpan={2} style={{ width: '22%' }}></th>
{selectedModules &&
selectedModules.itemList?.map((item) => (
// <th colSpan={colspan}>
<th>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: item.color }}></span>
<span className="name">{item.itemNm}</span>
</div>
</th>
))}
{colspan > 1 && <th rowSpan={2}>{getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}</th>}
</tr>
<tr>
{selectedModules &&
selectedModules.itemList?.map((item) => (
<>
<th>{getMessage('modal.module.basic.setting.module.placement.max.row')}</th>
{/* {colspan > 1 && <th>{getMessage('modal.module.basic.setting.module.placement.max.rows.multiple')}</th>} */}
</>
))}
</tr>
</thead>
<tbody>
{moduleSelectionData.roofConstructions.map((item, index) => (
<tr>
<td>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: roofOutlineColor(item.addRoof?.index) }}></span>
<span className="name">{item.addRoof?.roofMatlNmJp}</span>
</div>
</td>
{moduleRowColArray[index]?.map((item, index2) => (
<>
<td className="al-c">{item.moduleMaxRows}</td>
{/* {colspan > 1 && <td className="al-c">{item.mixModuleMaxRows}</td>} */}
{colspan > 1 && index2 === moduleRowColArray[index].length - 1 && <td className="al-c">{item.maxRow}</td>}
</>
))}
</tr>
))}
</tbody>
</table>
</div>
</div>
</div>
)}
</div>
</div>
</>
)
})

View File

@ -1,770 +0,0 @@
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useModuleTrestle } from '@/hooks/module/useModuleTrestle'
import { useMessage } from '@/hooks/useMessage'
import { currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom'
import { roofsState } from '@/store/roofAtom'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import Swal from 'sweetalert2'
const Trestle = forwardRef((props, ref) => {
const { tabNum, setTabNum, trestleTrigger, roofs, setRoofs, moduleSelectionData, setModuleSelectionData, setRoofsStore } = props
const { getMessage } = useMessage()
// const [selectedTrestle, setSelectedTrestle] = useState()
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const pitchText = useRecoilValue(pitchTextSelector)
const [selectedRoof, setSelectedRoof] = useState(null)
const {
trestleState,
trestleDetail,
dispatch,
raftBaseList,
trestleList,
constMthdList,
roofBaseList,
constructionList,
eavesMargin,
ridgeMargin,
kerabaMargin,
setEavesMargin,
setRidgeMargin,
setKerabaMargin,
lengthBase,
setLengthBase,
hajebichi,
setHajebichi,
cvrYn,
cvrChecked,
snowGdPossYn,
snowGdChecked,
setCvrYn,
setCvrChecked,
setSnowGdPossYn,
setSnowGdChecked,
} = useModuleTrestle({
selectedRoof,
})
const selectedModules = useRecoilValue(selectedModuleState) //
// const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const [selectedRaftBase, setSelectedRaftBase] = useState(null)
const [selectedTrestle, setSelectedTrestle] = useState(null)
const [selectedConstMthd, setSelectedConstMthd] = useState(null)
const [selectedConstruction, setSelectedConstruction] = useState(null)
const [selectedRoofBase, setSelectedRoofBase] = useState(null)
const { managementState } = useContext(GlobalDataContext)
const { restoreModuleInstArea } = useModuleBasicSetting()
const [flag, setFlag] = useState(false)
const tempModuleSelectionData = useRef(null)
useEffect(() => {
if (roofs && !selectedRoof) {
setSelectedRoof(roofs[0])
}
//
restoreModuleInstArea()
}, [roofs])
useEffect(() => {
if (flag && moduleSelectionData) {
if (JSON.stringify(tempModuleSelectionData.current) === JSON.stringify(moduleSelectionData)) {
setTabNum(tabNum + 1)
}
}
}, [flag, moduleSelectionData])
useEffect(() => {
if (selectedRoof) {
if (moduleSelectionData?.roofConstructions?.length >= selectedRoof.index + 1) {
const { construction, trestle, trestleDetail } = moduleSelectionData?.roofConstructions[selectedRoof.index]
dispatch({
type: 'SET_INITIALIZE',
roof: { common: moduleSelectionData.common, module: moduleSelectionData.module, construction, trestle, trestleDetail, ...selectedRoof },
})
} else {
dispatch({ type: 'SET_INITIALIZE', roof: { ...selectedRoof, common: moduleSelectionData.common, module: moduleSelectionData.module } })
}
}
}, [selectedRoof])
useEffect(() => {
if (raftBaseList.length > 0) {
setSelectedRaftBase(raftBaseList.find((raft) => raft.clCode === selectedRoof?.raft) ?? null)
} else {
setSelectedRaftBase(null)
}
}, [raftBaseList])
useEffect(() => {
if (trestleList.length > 0) {
setSelectedTrestle(trestleList.find((trestle) => trestle.trestleMkrCd === trestleState?.trestleMkrCd) ?? null)
} else {
setSelectedTrestle(null)
}
}, [trestleList])
useEffect(() => {
if (roofBaseList.length > 0) {
setSelectedRoofBase(roofBaseList.find((roofBase) => roofBase.roofBaseCd === trestleState?.roofBaseCd) ?? null)
} else {
setSelectedRoofBase(null)
}
}, [roofBaseList])
useEffect(() => {
if (constMthdList.length > 0) {
setSelectedConstMthd(constMthdList.find((constMthd) => constMthd.constMthdCd === trestleState?.constMthdCd) ?? null)
} else {
setSelectedConstMthd(null)
}
}, [constMthdList])
useEffect(() => {
if (constructionList.length > 0) {
setSelectedConstruction(constructionList.find((construction) => construction.constTp === trestleState?.construction?.constTp) ?? null)
if (constructionList.filter((construction) => construction.constPossYn === 'Y').length === 0) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error4', [selectedRoof?.nameJp]), // .
icon: 'warning',
})
}
} else {
setSelectedConstruction(null)
}
}, [constructionList])
const getConstructionState = (index) => {
if (constructionList && constructionList.length > 0) {
if (constructionList[index].constPossYn === 'Y') {
if (trestleState && trestleState.constTp === constructionList[index].constTp) {
return 'blue'
}
return 'white'
}
return 'no-click'
}
return 'no-click'
}
const onChangeLength = (e) => {
setLengthBase(e)
dispatch({
type: 'SET_LENGTH',
roof: {
length: e,
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: selectedRaftBase?.clCode,
},
})
}
const onChangeRaftBase = (e) => {
setSelectedRaftBase(e)
dispatch({
type: 'SET_RAFT_BASE',
roof: {
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: e.clCode,
},
})
}
const onChangeTrestleMaker = (e) => {
setSelectedTrestle(e)
dispatch({
type: 'SET_TRESTLE_MAKER',
roof: {
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: selectedRaftBase?.clCode,
trestleMkrCd: e.trestleMkrCd,
},
})
}
const onChangeConstMthd = (e) => {
setSelectedConstMthd(e)
dispatch({
type: 'SET_CONST_MTHD',
roof: {
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: selectedRaftBase?.clCode,
trestleMkrCd: selectedTrestle.trestleMkrCd,
constMthdCd: e.constMthdCd,
},
})
}
const onChangeRoofBase = (e) => {
setSelectedRoofBase(e)
dispatch({
type: 'SET_ROOF_BASE',
roof: {
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: selectedRaftBase?.clCode,
trestleMkrCd: selectedTrestle.trestleMkrCd,
constMthdCd: selectedConstMthd.constMthdCd,
roofBaseCd: e.roofBaseCd,
illuminationTp: managementState?.surfaceTypeValue ?? '',
instHt: managementState?.installHeight ?? '',
stdWindSpeed: managementState?.standardWindSpeedId ?? '',
stdSnowLd: managementState?.verticalSnowCover ?? '',
inclCd: selectedRoof?.pitch ?? 0,
roofPitch: Math.round(hajebichi ?? 0),
},
})
}
const handleConstruction = (index) => {
if (constructionList[index]?.constPossYn === 'Y') {
dispatch({
type: 'SET_CONSTRUCTION',
roof: {
moduleTpCd: selectedModules.itemTp ?? '',
roofMatlCd: selectedRoof?.roofMatlCd ?? '',
raft: selectedRaftBase?.clCode,
trestleMkrCd: selectedTrestle.trestleMkrCd,
constMthdCd: selectedConstMthd.constMthdCd,
roofBaseCd: selectedRoofBase.roofBaseCd,
illuminationTp: managementState?.surfaceTypeValue ?? '',
instHt: managementState?.installHeight ?? '',
stdWindSpeed: managementState?.standardWindSpeedId ?? '',
stdSnowLd: managementState?.verticalSnowCover ?? '',
inclCd: selectedRoof?.pitch ?? 0,
roofPitch: Math.round(hajebichi ?? 0),
constTp: constructionList[index].constTp,
snowGdPossYn: constructionList[index].snowGdPossYn,
cvrYn: constructionList[index].cvrYn,
mixMatlNo: selectedModules.mixMatlNo,
// workingWidth: selectedRoof?.length?.toString() ?? '',
workingWidth: lengthBase,
},
})
setCvrYn(constructionList[index].cvrYn)
setSnowGdPossYn(constructionList[index].snowGdPossYn)
setCvrChecked(false)
setSnowGdChecked(false)
}
}
const handleChangeRoofMaterial = (index) => {
const newAddedRoofs = roofs.map((roof, i) => {
if (i === selectedRoof.index) {
return {
...selectedRoof,
hajebichi,
length: lengthBase,
eavesMargin,
ridgeMargin,
kerabaMargin,
roofIndex: selectedRoof.index,
raft: selectedRaftBase?.clCode,
trestle: {
hajebichi: hajebichi,
length: lengthBase,
...selectedRaftBase,
...selectedTrestle,
...selectedConstMthd,
...selectedRoofBase,
},
construction: {
...constructionList.find((data) => data.constTp === trestleState.constTp),
cvrYn: cvrYn,
snowGdPossYn: snowGdPossYn,
cvrChecked: cvrChecked,
snowGdChecked: snowGdChecked,
setupCover: cvrChecked ?? false,
setupSnowCover: snowGdChecked ?? false,
},
trestleDetail: trestleDetail,
}
}
return roof
})
setRoofs(newAddedRoofs)
setSelectedRoof(newAddedRoofs[index])
}
const isComplete = async () => {
const newAddedRoofs = roofs.map((roof, i) => {
if (i === selectedRoof?.index) {
return {
...selectedRoof,
length: lengthBase,
eavesMargin,
ridgeMargin,
kerabaMargin,
roofIndex: roof.index,
raft: selectedRaftBase?.clCode,
hajebichi: hajebichi,
trestle: {
length: lengthBase,
hajebichi: hajebichi,
...selectedRaftBase,
...selectedTrestle,
...selectedConstMthd,
...selectedRoofBase,
},
construction: {
...constructionList.find((data) => data.constTp === trestleState.constTp),
cvrYn,
snowGdPossYn,
cvrChecked,
snowGdChecked,
setupCover: cvrChecked ?? false,
setupSnowCover: snowGdChecked ?? false,
},
trestleDetail: trestleDetail,
}
}
return roof
})
let result = true
for (let i = 0; i < newAddedRoofs.length; i++) {
const roof = newAddedRoofs[i]
if (!roof.trestle?.trestleMkrCd) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error1', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
if (!roof.trestle?.constMthdCd) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error2', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
if (!roof.trestle?.roofBaseCd) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error3', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
if (!roof.construction?.constTp) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error12', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
if (roof.lenAuth === 'C') {
if (!roof.trestle?.length) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error5', [roof.nameJp]), // L .
icon: 'warning',
})
result = false
return false
}
}
if (['C', 'R'].includes(roof.raftAuth)) {
if (!roof?.raft) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error6', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
}
if (['C', 'R'].includes(roof.roofPchAuth)) {
if (!roof?.roofPchBase) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error7', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
}
if (!roof?.eavesMargin || !roof?.ridgeMargin || !roof?.kerabaMargin) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error8', [roof.nameJp]), // .
icon: 'warning',
})
result = false
return false
}
if (roof.trestle.trestleMkrCd !== 'NO_DATA') {
//
if (roof.trestleDetail?.eaveIntvl > roof.eavesMargin) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error9', [roof.trestleDetail?.eaveIntvl, roof.nameJp]), // {0}mm .
icon: 'warning',
})
result = false
return false
}
if (roof.trestleDetail?.ridgeIntvl > roof.ridgeMargin) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error10', [roof.trestleDetail?.ridgeIntvl, roof.nameJp]), // {0}mm .
icon: 'warning',
})
result = false
return false
}
if (roof.trestleDetail?.kerabaIntvl > roof.kerabaMargin) {
Swal.fire({
title: getMessage('modal.module.basic.settting.module.error11', [roof.trestleDetail?.kerabaIntvl, roof.nameJp]), // {0}mm .
icon: 'warning',
})
result = false
return false
}
}
}
if (result) {
const newRoofs = newAddedRoofs.map((roof) => {
const { addRoof, construction, trestle, trestleDetail, roofConstructions, ...rest } = roof
return rest
})
setModuleSelectionData({
...moduleSelectionData,
roofConstructions: newAddedRoofs.map((roof, index) => ({
roofIndex: newRoofs[index].index,
trestle: roof.trestle,
addRoof: newRoofs[index],
construction: roof.construction,
trestleDetail: roof.trestleDetail,
})),
})
setFlag(true)
tempModuleSelectionData.current = {
...moduleSelectionData,
roofConstructions: newAddedRoofs.map((roof, index) => ({
roofIndex: newRoofs[index].index,
trestle: roof.trestle,
addRoof: newRoofs[index],
construction: roof.construction,
trestleDetail: roof.trestleDetail,
})),
}
const updatePromises = [
// new Promise((resolve) => {
// resolve()
// }),
new Promise((resolve) => {
setRoofs(newRoofs)
resolve()
}),
new Promise((resolve) => {
const roofConstructions = newAddedRoofs.map((roof, index) => ({
roofIndex: newRoofs[index].index,
addRoof: newRoofs[index],
trestle: {
...roof.trestle,
raft: roof.raftBaseCd,
},
construction: {
// ...constructionList.find((construction) => newAddedRoofs[index].construction.constTp === construction.constTp),
...roof.construction,
roofIndex: roof.index,
selectedIndex: roof.index,
},
trestleDetail: roof.trestleDetail,
}))
trestleTrigger({
roofConstructions,
})
setRoofsStore(roofConstructions)
resolve()
}),
]
await Promise.all(updatePromises)
return true
}
return false
}
useImperativeHandle(ref, () => ({
isComplete,
}))
return (
<div className="roof-module-tab2-overflow">
<div className="module-table-box mb10">
<div className="module-box-tab">
{roofs &&
roofs.map((roof, index) => (
<button
key={index}
className={`module-btn ${selectedRoof?.index === index ? 'act' : ''}`}
onClick={() => (roof ? handleChangeRoofMaterial(index) : null)}
>
{roof !== undefined ? `${roof.nameJp} (${currentAngleType === 'slope' ? roof.pitch : roof.angle}${pitchText})` : '-'}
</button>
))}
</div>
<div className="module-table-inner">
<div className="module-table-flex-wrap tab2">
<div className="module-flex-item">
<div className="eaves-keraba-table">
{selectedRoof && selectedRoof.lenAuth === 'C' && (
<>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">L</div>
<div className="eaves-keraba-td">
<div className="grid-select">
<input
type="text"
className="input-origin block"
value={lengthBase}
onChange={(e) => onChangeLength(e.target.value)}
disabled={selectedRoof.lenAuth === 'R'}
/>
</div>
</div>
</div>
</>
)}
{selectedRoof && ['C', 'R'].includes(selectedRoof.raftAuth) && (
<>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.rafter.margin')}</div>
<div className="eaves-keraba-td">
<div className="grid-select">
{raftBaseList.length > 0 && (
<QSelectBox
options={raftBaseList}
value={selectedRaftBase}
sourceKey={'clCode'}
targetKey={'clCode'}
showKey={'clCodeNm'}
disabled={selectedRoof.raftAuth === 'R'}
onChange={(e) => onChangeRaftBase(e)}
/>
)}
</div>
</div>
</div>
</>
)}
{selectedRoof && ['C', 'R'].includes(selectedRoof.roofPchAuth) && (
<>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.hajebichi')}</div>
<div className="eaves-keraba-td">
<div className="grid-select">
<input
type="text"
className="input-origin block"
disabled={selectedRoof.roofPchAuth === 'R'}
onChange={(e) => setHajebichi(e.target.value)}
value={hajebichi}
/>
</div>
</div>
</div>
</>
)}
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.trestle.maker')}</div>
<div className="eaves-keraba-td">
<div className="grid-select">
{trestleList && (
<QSelectBox
title={getMessage('selectbox.title')}
options={trestleList}
value={selectedTrestle}
sourceKey={'trestleMkrCd'}
targetKey={'trestleMkrCd'}
showKey={'trestleMkrCdJp'}
onChange={(e) => onChangeTrestleMaker(e)}
/>
)}
</div>
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.construction.method')}</div>
<div className="eaves-keraba-td">
<div className="grid-select">
{constMthdList && (
<QSelectBox
title={getMessage('selectbox.title')}
options={constMthdList}
value={selectedConstMthd}
sourceKey={'constMthdCd'}
targetKey={'constMthdCd'}
showKey={'constMthdCdJp'}
onChange={(e) => onChangeConstMthd(e)}
/>
)}
</div>
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.module.basic.setting.module.under.roof')}</div>
<div className="eaves-keraba-td">
<div className="grid-select">
{roofBaseList && (
<QSelectBox
title={getMessage('selectbox.title')}
options={roofBaseList}
sourceKey={'roofBaseCd'}
targetKey={'roofBaseCd'}
showKey={'roofBaseCdJp'}
value={selectedRoofBase}
onChange={(e) => onChangeRoofBase(e)}
/>
)}
</div>
</div>
</div>
</div>
</div>
<div className="module-flex-item non-flex">
<div className="flex-item-btn-wrap">
<button className={`btn-frame roof ${getConstructionState(0)}`} onClick={() => handleConstruction(0)}>
{getMessage('modal.module.basic.setting.module.standard.construction')}(I)
</button>
<button className={`btn-frame roof ${getConstructionState(3)}`} onClick={() => handleConstruction(3)}>
{getMessage('modal.module.basic.setting.module.multiple.construction')}
</button>
<button className={`btn-frame roof ${getConstructionState(1)}`} onClick={() => handleConstruction(1)}>
{getMessage('modal.module.basic.setting.module.standard.construction')}
</button>
<button className={`btn-frame roof ${getConstructionState(4)}`} onClick={() => handleConstruction(4)}>
{getMessage('modal.module.basic.setting.module.multiple.construction')}(II)
</button>
<button className={`btn-frame roof ${getConstructionState(2)}`} onClick={() => handleConstruction(2)}>
{getMessage('modal.module.basic.setting.module.enforce.construction')}
</button>
</div>
<div className="grid-check-form-flex">
<div className="d-check-box pop">
<input
type="checkbox"
id={`ch01`}
disabled={!cvrYn || cvrYn === 'N'}
checked={cvrChecked || false}
// onChange={() => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, cvrChecked: !trestleState.cvrChecked } })}
onChange={() => setCvrChecked(!cvrChecked)}
/>
<label htmlFor={`ch01`}>{getMessage('modal.module.basic.setting.module.eaves.bar.fitting')}</label>
</div>
<div className="d-check-box pop">
<input
type="checkbox"
id={`ch02`}
disabled={!snowGdPossYn || snowGdPossYn === 'N'}
checked={snowGdChecked || false}
// onChange={() => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, snowGdChecked: !trestleState.snowGdChecked } })}
onChange={() => setSnowGdChecked(!snowGdChecked)}
/>
<label htmlFor={`ch02`}>{getMessage('modal.module.basic.setting.module.blind.metal.fitting')}</label>
</div>
</div>
</div>
</div>
<div className="module-input-area">
<div className="module-area-title">{getMessage('modal.module.basic.setting.module.placement.area')}</div>
<div className="module-input-wrap">
<div className="outline-form mr15">
<span>{getMessage('modal.module.basic.setting.module.placement.area.eaves')}</span>
<div className="input-grid mr10">
<input
type="number"
className="input-origin block"
value={eavesMargin ?? 0}
// onChange={(e) => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, eavesMargin: e.target.value } })}
onChange={(e) => setEavesMargin(+e.target.value)}
/>
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form mr15">
<span>{getMessage('modal.module.basic.setting.module.placement.area.ridge')}</span>
<div className="input-grid mr10">
<input
type="number"
className="input-origin block"
value={ridgeMargin ?? 0}
// onChange={(e) => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, ridgeMargin: e.target.value } })}
onChange={(e) => setRidgeMargin(+e.target.value)}
/>
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form ">
<span>{getMessage('modal.module.basic.setting.module.placement.area.keraba')}</span>
<div className="input-grid mr10">
<input
type="number"
className="input-origin block"
value={kerabaMargin ?? 0}
// onChange={(e) => dispatch({ type: 'SET_TRESTLE_DETAIL', roof: { ...trestleState, kerabaMargin: e.target.value } })}
onChange={(e) => setKerabaMargin(+e.target.value)}
/>
</div>
<span className="thin">mm</span>
</div>
</div>
</div>
<div className="module-input-area">
<div className="module-area-title">{getMessage('modal.module.basic.setting.module.placement.margin')}</div>
<div className="module-input-wrap">
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.placement.margin.horizontal')}</span>
<div className="input-grid mr10">
<input type="text" className="input-origin block" defaultValue={trestleDetail?.moduleIntvlHor} readOnly />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.placement.margin.vertical')}</span>
<div className="input-grid mr10">
<input type="text" className="input-origin block" defaultValue={trestleDetail?.moduleIntvlVer} readOnly />
</div>
<span className="thin">mm</span>
</div>
</div>
</div>
</div>
</div>
<div className="module-bottom">
<div className="module-table-box ">
<div className="warning-guide">
<div className="warning">
{getMessage('modal.module.basic.setting.module.setting.info1')}
<br />
{getMessage('modal.module.basic.setting.module.setting.info2')}
</div>
</div>
</div>
</div>
</div>
)
})
export default Trestle

View File

@ -33,6 +33,14 @@ const PitchPlacement = forwardRef((props, refs) => {
setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked })
}
const moduleData = {
header: [
{ type: 'check', name: '', prop: 'check', width: 70 },
{ type: 'color-box', name: getMessage('module'), prop: 'module' },
{ type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 },
],
}
//
useEffect(() => {
const checkedModuleIds = Object.keys(selectedItems).filter((key) => selectedItems[key])
@ -97,91 +105,87 @@ const PitchPlacement = forwardRef((props, refs) => {
return (
<>
<div className="hexagonal-flex-wrap">
<div className="module-table-box ">
<div className="module-table-inner">
<div className="roof-module-table">
<table>
<thead>
<tr>
<th style={{ width: '70px' }}>
<div className="d-check-box no-text pop">
<input type="checkbox" id="ch01" disabled />
<label htmlFor="ch01"></label>
</div>
<div className="module-table-box mb10">
<div className="module-table-inner">
<div className="roof-module-table">
<table>
<thead>
<tr>
{moduleData.header.map((data) => (
<th key={data.prop} style={{ width: data.width ? data.width : '' }}>
{data.type === 'check' ? (
<div className="d-check-box no-text pop">
<input type="checkbox" id="ch01" disabled />
<label htmlFor="ch01"></label>
</div>
) : (
data.name
)}
</th>
<th>{getMessage('module')}</th>
</tr>
</thead>
<tbody>
{selectedModules.itemList &&
selectedModules.itemList.map((item, index) => (
<tr key={index}>
<td className="al-c">
<div className="d-check-box no-text pop">
<input
type="checkbox"
id={item.itemId}
name={item.itemId}
checked={selectedItems[item.itemId]}
onChange={handleSelectedItem}
/>
<label htmlFor={item.itemId}></label>
</div>
</td>
<td>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: item.color }}></span>
<span className="name">{item.itemNm}</span>
</div>
</td>
</tr>
))}
</tbody>
</table>
</div>
))}
</tr>
</thead>
<tbody>
{selectedModules.itemList &&
selectedModules.itemList.map((item, index) => (
<tr key={index}>
<td className="al-c">
<div className="d-check-box no-text pop">
<input
type="checkbox"
id={item.itemId}
name={item.itemId}
checked={selectedItems[item.itemId]}
onChange={handleSelectedItem}
/>
<label htmlFor={item.itemId}></label>
</div>
</td>
<td>
<div className="color-wrap">
<span className="color-box" style={{ backgroundColor: item.color }}></span>
<span className="name">{item.itemNm}</span>
</div>
</td>
<td className="al-r">{item.wpOut}</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="module-table-box non-flex">
<div className="module-table-inner">
<div className="roof-module-table">
<table>
<thead>
<tr>
<th>{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting')}</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<div className="hexagonal-radio-wrap">
<div className="d-check-radio pop mb10">
<input
type="radio"
name="radio01"
id="ra01"
value={'south'}
defaultChecked={setupLocation === 'south'}
onClick={handleSetupLocation}
/>
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
value={'excreta'}
defaultChecked={setupLocation === 'excreta'}
onClick={handleSetupLocation}
/>
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div className="module-table-box mb10">
<div className="module-table-inner">
<div className="hexagonal-wrap">
<div className="hexagonal-item">
<div className="bold-font">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting')}</div>
</div>
<div className="hexagonal-item">
<div className="pop-form-radio">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
value={'south'}
defaultChecked={setupLocation === 'south'}
onClick={handleSetupLocation}
/>
<label htmlFor="ra01">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.south')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
value={'excreta'}
defaultChecked={setupLocation === 'excreta'}
onClick={handleSetupLocation}
/>
<label htmlFor="ra02">{getMessage('modal.module.basic.setting.pitch.module.placement.standard.setting.select')}</label>
</div>
</div>
</div>
</div>
</div>

View File

@ -13,7 +13,7 @@ import { useRecoilState } from 'recoil'
import { makersState, modelsState, modelState, pcsCheckState, selectedMakerState, selectedModelsState, seriesState } from '@/store/circuitTrestleAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { canvasState, canvasZoomState } from '@/store/canvasAtom'
import { canvasState } from '@/store/canvasAtom'
import { useTrestle } from '@/hooks/module/useTrestle'
import { selectedModuleState } from '@/store/selectedModuleOptions'
@ -25,8 +25,6 @@ import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupSta
import { useImgLoader } from '@/hooks/floorPlan/useImgLoader'
import { usePlan } from '@/hooks/usePlan'
import { QcastContext } from '@/app/QcastProvider'
import { fabric } from 'fabric'
import { fontSelector } from '@/store/fontAtom'
const ALLOCATION_TYPE = {
AUTO: 'auto',
@ -39,16 +37,13 @@ export default function CircuitTrestleSetting({ id }) {
const { swalFire } = useSwal()
const { saveEstimate } = useEstimate()
const canvas = useRecoilValue(canvasState)
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
const [tabNum, setTabNum] = useState(1)
const [allocationType, setAllocationType] = useState(ALLOCATION_TYPE.AUTO)
const [circuitAllocationType, setCircuitAllocationType] = useState(1)
const { managementState, setManagementState } = useContext(GlobalDataContext)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState)
const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList, getPcsManualConfChk } = useMasterController()
const flowText = useRecoilValue(fontSelector('flowText'))
const lengthText = useRecoilValue(fontSelector('lengthText'))
const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText'))
// ()
const [selectedStepUpValues, setSelectedStepUpValues] = useState({})
@ -89,6 +84,7 @@ export default function CircuitTrestleSetting({ id }) {
// const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
useEffect(() => {
if (!managementState) {
setManagementState(managementStateLoaded)
}
// setCircuitData({
// makers,
@ -107,29 +103,6 @@ export default function CircuitTrestleSetting({ id }) {
}
}, [])
//
const beforeCapture = () => {
// setCanvasZoom(100)
const x = canvas.width / 2
const y = canvas.height / 2
canvas.zoomToPoint(new fabric.Point(x, y), 0.5)
changeFontSize('lengthText', '28')
changeFontSize('circuitNumber', '28')
changeFontSize('flowText', '28')
canvas.renderAll()
}
//
const afterCapture = () => {
setCanvasZoom(100)
canvas.set({ zoom: 1 })
canvas.viewportTransform = [1, 0, 0, 1, 0, 0]
changeFontSize('lengthText', lengthText.fontSize.value)
changeFontSize('circuitNumber', circuitNumberText.fontSize.value)
changeFontSize('flowText', flowText.fontSize.value)
canvas.renderAll()
}
//
// PCS
@ -182,7 +155,6 @@ export default function CircuitTrestleSetting({ id }) {
getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
if (res.resultCode === 'S') {
setTabNum(2)
setAllModuleSurfaceIsComplete(false)
} else {
swalFire({
title: res.resultMsg,
@ -216,7 +188,6 @@ export default function CircuitTrestleSetting({ id }) {
}).then((res) => {
if (res?.result.resultCode === 'S' && res?.data) {
setTabNum(2)
setAllModuleSurfaceIsComplete(false)
} else {
swalFire({ text: getMessage('common.message.send.error') })
}
@ -316,8 +287,6 @@ export default function CircuitTrestleSetting({ id }) {
setSelectedModels(pcsItemList)
getPcsVoltageChk(pcsVoltageChkParams).then((res) => {
setAllocationType(ALLOCATION_TYPE.PASSIVITY)
setAllModuleSurfaceIsComplete(false)
clearTrestle()
})
} else {
swalFire({
@ -350,7 +319,6 @@ export default function CircuitTrestleSetting({ id }) {
}
setAllocationType(ALLOCATION_TYPE.PASSIVITY)
clearTrestle()
}
}
@ -371,7 +339,6 @@ export default function CircuitTrestleSetting({ id }) {
// ()
const onApply = async () => {
beforeCapture()
setAllModuleSurfaceIsComplete(false)
setIsGlobalLoading(true)
@ -382,9 +349,12 @@ export default function CircuitTrestleSetting({ id }) {
obj.pcses = getStepUpListData()
})
setViewCircuitNumberTexts(false)
handleCanvasToPng(1)
// result=null
setViewCircuitNumberTexts(true)
//
//
@ -400,7 +370,6 @@ export default function CircuitTrestleSetting({ id }) {
if (result) {
handleCanvasToPng(2)
afterCapture()
//
await saveEstimate(result)
} else {
@ -410,16 +379,6 @@ export default function CircuitTrestleSetting({ id }) {
// removeNotAllocationModules()
}
const changeFontSize = (name, size) => {
const textObjs = canvas?.getObjects().filter((obj) => obj.name === name)
textObjs.forEach((obj) => {
obj.set({
fontSize: size,
})
})
canvas.renderAll()
}
//
const onClickPrev = () => {
// setAllocationType(ALLOCATION_TYPE.AUTO)
@ -520,7 +479,7 @@ export default function CircuitTrestleSetting({ id }) {
console.log(stepUpListData)
stepUpListData[0].pcsItemList.map((item, index) => {
return item.serQtyList
.filter((serQty) => serQty.selected && serQty.paralQty > 0)
.filter((serQty) => serQty.selected)
.forEach((serQty) => {
pcs.push({
pcsMkrCd: item.pcsMkrCd,
@ -696,7 +655,6 @@ export default function CircuitTrestleSetting({ id }) {
return
} else {
setTabNum(2)
setAllModuleSurfaceIsComplete(false)
}
})
}

View File

@ -44,7 +44,7 @@ export default function PowerConditionalSelect(props) {
const { getPcsMakerList, getPcsModelList } = useMasterController()
const selectedModules = useRecoilValue(selectedModuleState)
const { swalFire } = useSwal()
// const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
const modelHeader = [
{ name: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.series'), width: '15%', prop: 'pcsSerNm', type: 'color-box' },
@ -110,7 +110,6 @@ export default function PowerConditionalSelect(props) {
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : false,
}
})
setSelectedModels([])
}
setSeries(copySeries)
handleSetmodels(copySeries.filter((s) => s.selected))

View File

@ -42,6 +42,7 @@ export default function StepUp(props) {
const [arrayLength, setArrayLength] = useState(3) //module-table-inner
const [pcsCheck, setPcsCheck] = useRecoilState(pcsCheckState)
const { getPcsVoltageStepUpList, getPcsAutoRecommendList, getPcsVoltageChk, getPcsConnOptionItemList } = useMasterController()
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState)
const [optCodes, setOptCodes] = useState([])
@ -572,7 +573,7 @@ export default function StepUp(props) {
value={seletedMainOption}
sourceKey="code"
targetKey="code"
showKey={`${globalLocale === 'ja' ? 'nameJp' : 'name'}`}
showKey="name"
onChange={(e) => setSeletedMainOption(e)}
/>
)}
@ -585,7 +586,7 @@ export default function StepUp(props) {
value={seletedSubOption}
sourceKey="code"
targetKey="code"
showKey={`${globalLocale === 'ja' ? 'nameJp' : 'name'}`}
showKey="name"
onChange={(e) => setSeletedSubOption(e)}
/>
)}

View File

@ -25,7 +25,7 @@ export default function PassivityCircuitAllocation(props) {
const { swalFire } = useSwal()
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const { managementState } = useContext(GlobalDataContext)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState)
const [selectedPcs, setSelectedPcs] = useState(selectedModels[0])
const { header, rows, footer } = useRecoilValue(moduleStatisticsState)
@ -38,6 +38,7 @@ export default function PassivityCircuitAllocation(props) {
useEffect(() => {
setModuleStatisticsData()
if (!managementState) {
setManagementState(managementStateLoaded)
}
canvas
.getObjects()
@ -86,26 +87,6 @@ export default function PassivityCircuitAllocation(props) {
.map((obj) => obj.circuitNumber),
),
]
const surfaceList = targetModules.map((module) => {
return canvas.getObjects().filter((obj) => obj.id === canvas.getObjects().filter((obj) => obj.id === module)[0].surfaceId)[0]
})
if (surfaceList.length > 1) {
let surfaceType = {}
surfaceList.forEach((surface) => {
surfaceType[`${surface.direction}-${surface.roofMaterial.pitch}`] = surface
})
if (Object.keys(surfaceType).length > 1) {
swalFire({
text: getMessage('module.circuit.fix.not.same.roof.error'),
type: 'alert',
icon: 'warning',
})
return
}
}
if (!circuitNumber || circuitNumber === 0) {
swalFire({
text: getMessage('module.circuit.minimun.error'),

View File

@ -7,7 +7,6 @@ import { useMessage } from '@/hooks/useMessage'
import { usePopup } from '@/hooks/usePopup'
import { canvasState } from '@/store/canvasAtom'
import { usePolygon } from '@/hooks/usePolygon'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
const FLOW_DIRECTION_TYPE = {
EIGHT_AZIMUTH: 'eightAzimuth',
@ -20,8 +19,6 @@ export default function FlowDirectionSetting(props) {
const canvas = useRecoilValue(canvasState)
const { getMessage } = useMessage()
const { changeSurfaceLineType } = useSurfaceShapeBatch({})
useEffect(() => {
return () => {
canvas?.discardActiveObject()
@ -56,7 +53,6 @@ export default function FlowDirectionSetting(props) {
})
drawDirectionArrow(roof)
canvas?.renderAll()
changeSurfaceLineType(roof)
closePopup(id)
}

View File

@ -4,11 +4,9 @@ import { usePopup } from '@/hooks/usePopup'
import { useRecoilValue } from 'recoil'
import { contextPopupPositionState } from '@/store/popupAtom'
import { useState } from 'react'
import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { currentObjectState } from '@/store/canvasAtom'
import { useGrid } from '@/hooks/common/useGrid'
import { gridColorState } from '@/store/gridAtom'
import { gridDisplaySelector } from '@/store/settingAtom'
const GRID_PADDING = 5
export default function GridCopy(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
const { id, pos = contextPopupPosition } = props
@ -17,39 +15,9 @@ export default function GridCopy(props) {
const [length, setLength] = useState('0')
const [arrow, setArrow] = useState(null)
const currentObject = useRecoilValue(currentObjectState)
const canvas = useRecoilValue(canvasState)
const gridColor = useRecoilValue(gridColorState)
const isGridDisplay = useRecoilValue(gridDisplaySelector)
const { copy } = useGrid()
const handleApply = () => {
copy(currentObject, ['↑', '←'].includes(arrow) ? (+length * -1) / 10 : +length / 10)
}
const copy = (object, length) => {
const lineStartX = object.direction === 'vertical' ? object.x1 + length : 0
const lineEndX = object.direction === 'vertical' ? object.x2 + length : canvas.width
const lineStartY = object.direction === 'vertical' ? 0 : object.y1 + length
const lineEndY = object.direction === 'vertical' ? canvas.width : object.y1 + length
const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], {
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
strokeDashArray: [5, 2],
opacity: 0.3,
padding: GRID_PADDING,
direction: object.direction,
visible: isGridDisplay,
name: object.name,
})
canvas.add(line)
canvas.setActiveObject(line)
canvas.renderAll()
copy(currentObject, ['↑', '←'].includes(arrow) ? +length * -1 : +length)
}
return (
<WithDraggable isShow={true} pos={pos} className="xm">

View File

@ -6,6 +6,7 @@ import { contextPopupPositionState } from '@/store/popupAtom'
import { useCanvas } from '@/hooks/useCanvas'
import { canvasState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useState } from 'react'
import { useGrid } from '@/hooks/common/useGrid'
import { useSwal } from '@/hooks/useSwal'
import { set } from 'react-hook-form'
@ -16,6 +17,7 @@ export default function GridMove(props) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const { swalFire } = useSwal()
const { move } = useGrid()
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
const [isAll, setIsAll] = useState(false)
const [verticalSize, setVerticalSize] = useState('0')
@ -52,31 +54,21 @@ export default function GridMove(props) {
.forEach((grid) => {
move(
grid,
arrow2 === '←' ? (Number(horizonSize) * -1) / 10 : Number(horizonSize) / 10,
arrow1 === '↑' ? (Number(verticalSize) * -1) / 10 : Number(verticalSize) / 10,
arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize),
arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize),
)
})
} else {
move(
currentObject,
arrow2 === '←' ? (Number(horizonSize) * -1) / 10 : Number(horizonSize) / 10,
arrow1 === '↑' ? (Number(verticalSize) * -1) / 10 : Number(verticalSize) / 10,
arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize),
arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize),
)
}
canvas.renderAll()
handleClose()
}
const move = (object, x, y) => {
object.set({
...object,
x1: object.direction === 'vertical' ? object.x1 + x : 0,
x2: object.direction === 'vertical' ? object.x1 + x : canvas.width,
y1: object.direction === 'vertical' ? 0 : object.y1 + y,
y2: object.direction === 'vertical' ? canvas.height : object.y1 + y,
})
}
const handleClose = () => {
closePopup(id)
}

View File

@ -38,11 +38,6 @@ export default function PanelEdit(props) {
const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module') // selectedObj
isSetupModules.forEach((obj) => obj.set({ lockMovementX: false, lockMovementY: false }))
}
//
return () => {
canvas?.discardActiveObject() //
}
}, [])
//
@ -92,7 +87,7 @@ export default function PanelEdit(props) {
moduleMultiCopy('row', length, direction)
break
}
// closePopup(id)
closePopup(id)
}
return (

View File

@ -15,70 +15,73 @@ export default function FlowLine({ FLOW_LINE_REF }) {
const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => {
if (currentObject === null) {
FLOW_LINE_REF.POINTER_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.value = ''
FLOW_LINE_REF.FILLED_INPUT_REF.current.blur()
}
}
const handleInput = (e) => {
const regex = /^-?\d*$/
let value = e.target.value
if (!regex.test(value) && value !== '') return
if (value.startsWith('0') || value === '-0') return
setFilledInput(value.replace(/[^0-9-]/g, ''))
const value = e.target.value.replace(/^0+/, '')
setFilledInput(value.replace(/[^0-9]/g, ''))
}
return (
<>
<div className="outline-wrap">
<div className="guide">{getMessage('modal.movement.flow.line.info')}</div>
<div className="outline-form">
<span>{getMessage('modal.movement.flow.line.position')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={100} readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />
</div>
</div>
<div className="moving-tab-content">
<div className="moving-tab-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
ref={FLOW_LINE_REF.DOWN_LEFT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.DOWN_LEFT)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.bottom.left')}</label>
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
defaultChecked={true}
ref={FLOW_LINE_REF.DOWN_LEFT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.DOWN_LEFT)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.bottom.left')}</label>
</div>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
ref={FLOW_LINE_REF.UP_RIGHT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.UP_RIGHT)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.top.right')}</label>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
{/*<input type="text" className="input-origin block" readOnly={true} ref={FLOW_LINE_REF.POINTER_INPUT_REF} />*/}
</div>
</div>
</div>
</div>
<div className="outline-form">
<span>{getMessage('modal.movement.flow.line.movement')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin block"
defaultValue={100}
ref={FLOW_LINE_REF.FILLED_INPUT_REF}
value={filledInput}
onFocus={handleFocus}
onChange={handleInput}
/>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
ref={FLOW_LINE_REF.UP_RIGHT_RADIO_REF}
onChange={() => {
setType(FLOW_LINE_TYPE.UP_RIGHT)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.top.right')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input
type="text"
className="input-origin block"
ref={FLOW_LINE_REF.FILLED_INPUT_REF}
value={filledInput}
onFocus={handleFocus}
onChange={handleInput}
/>
</div>
<span className="thin">mm</span>
</div>
</div>
<span className="thin">mm</span>
</div>
</div>
</div>

View File

@ -15,7 +15,6 @@ export default function Updown({ UP_DOWN_REF }) {
const currentObject = useRecoilValue(currentObjectState)
const handleFocus = () => {
if (currentObject === null) {
UP_DOWN_REF.POINTER_INPUT_REF.current.value = ''
UP_DOWN_REF.FILLED_INPUT_REF.current.value = ''
UP_DOWN_REF.FILLED_INPUT_REF.current.blur()
}
@ -29,54 +28,61 @@ export default function Updown({ UP_DOWN_REF }) {
<>
<div className="outline-wrap">
<div className="guide">{getMessage('modal.movement.flow.line.updown.info')}</div>
<div className="outline-form">
<span>{getMessage('modal.movement.flow.line.position')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={100} readOnly={true} ref={UP_DOWN_REF.POINTER_INPUT_REF} />
</div>
</div>
<div className="moving-tab-content">
<div className="moving-tab-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
ref={UP_DOWN_REF.UP_RADIO_REF}
defaultChecked={true}
onChange={() => {
setType(UP_DOWN_TYPE.UP)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.updown.up')}</label>
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
ref={UP_DOWN_REF.UP_RADIO_REF}
defaultChecked={true}
onChange={() => {
setType(UP_DOWN_TYPE.UP)
}}
/>
<label htmlFor="ra01">{getMessage('modal.movement.flow.line.updown.up')}</label>
</div>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
ref={UP_DOWN_REF.DOWN_RADIO_REF}
onChange={() => {
setType(UP_DOWN_TYPE.DOWN)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.updown.down')}</label>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
{/*<input type="text" className="input-origin block" readOnly={true} ref={UP_DOWN_REF.UP_INPUT_REF} />*/}
</div>
</div>
</div>
</div>
<div className="outline-form">
<span>{getMessage('modal.movement.flow.line.movement')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin block"
defaultValue={100}
ref={UP_DOWN_REF.FILLED_INPUT_REF}
value={filledInput}
onFocus={handleFocus}
onChange={handleInput}
/>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
ref={UP_DOWN_REF.DOWN_RADIO_REF}
onChange={() => {
setType(UP_DOWN_TYPE.DOWN)
}}
/>
<label htmlFor="ra02">{getMessage('modal.movement.flow.line.updown.down')}</label>
</div>
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input
type="text"
className="input-origin block"
ref={UP_DOWN_REF.FILLED_INPUT_REF}
value={filledInput}
onFocus={handleFocus}
onChange={handleInput}
/>
</div>
<span className="thin">mm</span>
</div>
</div>
<span className="thin">mm</span>
</div>
</div>
</div>

View File

@ -100,7 +100,7 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
]
return (
<WithDraggable isShow={true} pos={pos} className="lrr" isHidden={isHidden}>
<WithDraggable isShow={true} pos={pos} className="lrr" style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
<WithDraggable.Header title={getMessage('plan.menu.placement.surface.object')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">

View File

@ -162,7 +162,6 @@ export default function WallLineSetting(props) {
<></>
)}
</div>
<div className="normal-font mt10">{getMessage('outerLine.property.info')}</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}

View File

@ -19,7 +19,6 @@ import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { usePolygon } from '@/hooks/usePolygon'
import { canvasState } from '@/store/canvasAtom'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePlan } from '@/hooks/usePlan'
/**
* 지붕 레이아웃
@ -54,7 +53,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
rafter: useRef(null),
hajebichi: useRef(null),
}
const { saveCanvas } = usePlan()
/**
* 치수 입력방법(복시도입력/실측값입력/육지붕)
*/
@ -206,7 +205,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
/**
* 배치면초기설정 저장 버튼 클릭
*/
const handleSaveBtn = async () => {
const handleSaveBtn = () => {
const roofInfo = {
...currentRoof,
planNo: basicSetting.planNo,
@ -227,7 +226,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
console.log('save Info', {
...basicSetting,
selectedRoofMaterial: {
...newAddedRoofs[0],
roofInfo,
},
})
@ -240,7 +239,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
* 선택된 지붕재 정보
*/
selectedRoofMaterial: {
...newAddedRoofs[0],
roofInfo,
},
})
@ -255,13 +254,14 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
/* 저장 후 화면 닫기 */
closePopup(id)
await saveCanvas(false)
}
return (
<WithDraggable isShow={true} pos={pos} className="ll">
<WithDraggable.Header title={getMessage('plan.menu.placement.surface.initial.setting')} />
<WithDraggable.Body>
<div className="left-bar modal-handle"></div>
<div className="right-bar modal-handle"></div>
<div className="placement-table">
<table>
<colgroup>
@ -271,11 +271,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
<tbody>
<tr>
<th>{getMessage('modal.placement.initial.setting.plan.drawing')}</th>
<td>
{getMessage('modal.placement.initial.setting.plan.drawing.size.stuff')}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
{getMessage('modal.placement.initial.setting.plan.drawing.only.number')}
</td>
<td>{getMessage('modal.placement.initial.setting.plan.drawing.size.stuff')}</td>
</tr>
<tr>
<th>

View File

@ -105,16 +105,6 @@ export default function GridOption(props) {
initEvent()
}, [gridOptions])
useEffect(() => {
return () => {
setAdsorptionPointAddMode(false)
setTempGridMode(false)
setTimeout(() => {
initEvent()
}, 100)
}
}, [])
const dotLineGridProps = {
id: dotLineId,
setIsShow: setShowDotLineGridModal,

View File

@ -185,7 +185,7 @@ export default function SecondOption(props) {
const onClickOption = async (item) => {
let option4Data = settingModalSecondOptions?.option4
let adsorpPointData = adsorptionPointMode
let adsorpPointData = adsorptionPointMode.adsorptionPoint
// ( )
if (
@ -203,9 +203,11 @@ export default function SecondOption(props) {
//
setAdsorptionRange(item.range)
setAdsorptionPointMode(adsorpPointData)
setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: adsorpPointData })
} else if (item === 'adsorpPoint') {
setAdsorptionPointMode(!adsorpPointData)
setAdsorptionPointMode({ ...adsorptionPointMode, adsorptionPoint: !adsorpPointData })
adsorpPointData = !adsorpPointData
}
setSettingsData({ ...settingsData, option4: [...option4Data], adsorptionPoint: adsorpPointData })
@ -255,7 +257,7 @@ export default function SecondOption(props) {
}}
>
<span>{getMessage('modal.canvas.setting.font.plan.absorption.point')}</span>
<i>{adsorptionPointMode ? 'ON' : 'OFF'}</i>
<i>{adsorptionPointMode.adsorptionPoint ? 'ON' : 'OFF'}</i>
</button>
</div>
</div>

View File

@ -6,22 +6,16 @@ import WithDraggable from '@/components/common/draggable/WithDraggable'
import SecondOption from '@/components/floor-plan/modal/setting01/SecondOption'
import { useMessage } from '@/hooks/useMessage'
import GridOption from '@/components/floor-plan/modal/setting01/GridOption'
import { adsorptionPointAddModeState, canGridOptionSeletor, tempGridModeState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canGridOptionSeletor } from '@/store/canvasAtom'
import { useRecoilValue } from 'recoil'
import { usePopup } from '@/hooks/usePopup'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useTempGrid } from '@/hooks/useTempGrid'
import { settingModalGridOptionsState } from '@/store/settingAtom'
import { useEvent } from '@/hooks/useEvent'
export default function SettingModal01(props) {
const { id } = props
const [buttonAct, setButtonAct] = useState(1)
const { getMessage } = useMessage()
const canGridOptionSeletorValue = useRecoilValue(canGridOptionSeletor)
const [gridOptions, setGridOptions] = useRecoilState(settingModalGridOptionsState)
const [tempGridMode, setTempGridMode] = useRecoilState(tempGridModeState)
const [adsorptionPointAddMode, setAdsorptionPointAddMode] = useRecoilState(adsorptionPointAddModeState)
const { closePopup } = usePopup()
const {
@ -77,22 +71,9 @@ export default function SettingModal01(props) {
setButtonAct(num)
}
const onClose = () => {
setTempGridMode(false)
setAdsorptionPointAddMode(false)
setGridOptions((prev) => {
const newSettingOptions = [...prev]
newSettingOptions[0].selected = false
newSettingOptions[2].selected = false
return [...newSettingOptions]
})
closePopup(id, true)
}
return (
<WithDraggable isShow={true} pos={{ x: 1275, y: 180 }} className="sm">
<WithDraggable.Header title={getMessage('modal.canvas.setting')} onClose={onClose} />
<WithDraggable.Header title={getMessage('modal.canvas.setting')} onClose={() => closePopup(id, true)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
<button className={`btn-frame modal ${buttonAct === 1 ? 'act' : ''}`} onClick={() => handleBtnClick(1)}>

View File

@ -74,7 +74,7 @@ export default function Offset({ length1Ref, arrow1Ref, currentWallLineRef }) {
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" placeholder={0} ref={length1Ref} />
<input type="text" className="input-origin block" defaultValue={0} ref={length1Ref} />
</div>
<span className="thin">mm</span>
</div>

View File

@ -46,7 +46,7 @@ export default forwardRef(function WallLine({ length1Ref, length2Ref, arrow1Ref,
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" placeholder={0} readOnly={type !== 1} ref={length1Ref} />
<input type="text" className="input-origin block" defaultValue={0} readOnly={type !== 1} ref={length1Ref} />
</div>
<span className="thin">mm</span>
</div>
@ -80,7 +80,7 @@ export default forwardRef(function WallLine({ length1Ref, length2Ref, arrow1Ref,
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '100px' }}>
<input type="text" className="input-origin block" placeholder={0} readOnly={type !== 2} ref={length2Ref} />
<input type="text" className="input-origin block" defaultValue={0} readOnly={type !== 2} ref={length2Ref} />
</div>
<span className="thin">mm</span>
</div>

View File

@ -20,11 +20,6 @@ import { stuffSearchState } from '@/store/stuffAtom'
import { QcastContext } from '@/app/QcastProvider'
import { usePopup } from '@/hooks/usePopup'
import { commonCodeState } from '@/store/commonCodeAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import { roofMaterialsAtom } from '@/store/settingAtom'
import { useMasterController } from '@/hooks/common/useMasterController'
import { ROOF_MATERIAL_LAYOUT } from '@/components/floor-plan/modal/placementShape/PlacementShapeSetting'
export const ToggleonMouse = (e, act, target) => {
const listWrap = e.target.closest(target)
@ -72,53 +67,6 @@ export default function Header(props) {
const [SelectOptions, setSelectOptions] = useState([])
const [commonCode, setCommonCode] = useRecoilState(commonCodeState)
const { promiseGet } = useAxios()
/**
* 지붕재 목록 Header에서 조회
*/
const [roofMaterials, setRoofMaterials] = useRecoilState(roofMaterialsAtom)
const { getRoofMaterialList } = useMasterController()
useEffect(() => {
async function initRoofMaterial() {
if (roofMaterials.length !== 0) {
return
}
const { data } = await getRoofMaterialList()
const roofLists = data.map((item, idx) => ({
...item,
id: item.roofMatlCd,
name: item.roofMatlNm,
selected: idx === 0,
index: idx,
nameJp: item.roofMatlNmJp,
length: item.lenBase && parseInt(item.lenBase),
width: item.widBase && parseInt(item.widBase),
raft: item.raftBase && parseInt(item.raftBase),
layout: ['ROOF_ID_SLATE', 'ROOF_ID_SINGLE'].includes(item.roofMatlCd) ? ROOF_MATERIAL_LAYOUT.STAIRS : ROOF_MATERIAL_LAYOUT.PARALLEL,
hajebichi: item.roofPchBase && parseInt(item.roofPchBase),
pitch: item.pitch ? parseInt(item.pitch) : 4,
angle: item.angle ? parseInt(item.angle) : 21.8,
}))
setRoofMaterials(roofLists)
}
initRoofMaterial()
}, [])
useEffect(() => {
const getCommonCode = async () => {
await promiseGet({ url: '/api/commcode/qc-comm-code' }).then((res) => {
setCommonCode(Object.groupBy(res.data, ({ clHeadCd }) => clHeadCd))
})
}
if (!isObjectNotEmpty(commonCode)) {
getCommonCode()
}
}, [])
const getAutoLoginParam = async () => {
await promisePost({ url: '/api/login/v1.0/user/login/autoLoginEncryptData', data: { loginId: userSession.userId } })
.then((res) => {
@ -127,19 +75,19 @@ export default function Header(props) {
userSession.storeId === 'T01'
? [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'HANASYS ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: 'HANASYS Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 1, name: 'Q.ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: 'Q.Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 3, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
]
: userSession.groupId === '60000'
? [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'HANASYS ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 1, name: 'Q.ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
]
: [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'HANASYS Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 1, name: 'Q.Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
],
)
@ -177,7 +125,6 @@ export default function Header(props) {
{ id: 7, name: 'header.menus.community.archive', url: '/community/archive', children: [] },
],
},
{ id: 8, name: 'qna.title', url: '/community/qna', children: [] },
]
const syncSession = useCallback(() => {
@ -235,7 +182,7 @@ export default function Header(props) {
onClick={() => {
// moveHome()
removeStuffRecoil(menu)
if (pathName === '/' && menu.id !== 8) {
if (pathName === '/') {
window.location.reload()
}
}}

View File

@ -203,7 +203,7 @@ export default function Stuff() {
if (event.column.colId === 'objectNo') {
return
} else {
//T S
//T R
if (event.data.objectNo) {
setIsGlobalLoading(true)
if (event.data.tempFlg === '0') {
@ -238,8 +238,6 @@ export default function Stuff() {
schSortType: stuffSearchParams.schSortType,
pageNo: stuffSearchParams?.pageNo ? stuffSearchParams.pageNo : 1,
pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100,
builderNo: session.builderNo,
userId: session.userId
}
if (!params.saleStoreId) {

View File

@ -54,7 +54,7 @@ export default function StuffDetail() {
const { get, promiseGet, del, promisePost, promisePut } = useAxios(globalLocaleState)
//form
const formInitValue = {
// T...() S...()
// T...() R...()
planReqNo: '', //No
receiveUser: session?.userNm, //
objectStatusId: '0', //(:0 : 1)
@ -1033,7 +1033,8 @@ export default function StuffDetail() {
const _saleStoreId = watch('saleStoreId')
// 2
const _otherSaleStoreId = watch('otherSaleStoreId')
// zipNo: '', // #947
// zipNo: '', //
const _zipNo = watch('zipNo')
// prefId: '', //
const _prefId = watch('prefId')
// address: '', //
@ -1070,6 +1071,10 @@ export default function StuffDetail() {
}
}
if (!formData.zipNo) {
errors.zipNo = true
}
if (!formData.prefId) {
errors.prefId = true
}
@ -1110,6 +1115,10 @@ export default function StuffDetail() {
}
}
if (!formData.zipNo) {
errors.zipNo = true
}
if (!formData.prefId || formData.prefId === '0') {
errors.prefId = true
}
@ -1135,6 +1144,7 @@ export default function StuffDetail() {
_objectName,
_saleStoreId,
_otherSaleStoreId,
_zipNo,
_prefId,
_address,
_areaId,
@ -1179,14 +1189,6 @@ export default function StuffDetail() {
}
}, [prefValue])
// / disabled
const onChangePrefCode = (e) => {
setPrefValue(e.prefId)
form.setValue('prefId', e.prefId)
form.setValue('prefName', e.prefName)
}
//
const handleAreaIdOnChange = (e) => {
form.setValue('areaId', e.areaId)
@ -1241,6 +1243,12 @@ export default function StuffDetail() {
errors = fieldNm
}
//
if (!formData.zipNo) {
fieldNm = getMessage('stuff.detail.zipNo')
errors = fieldNm
}
//1
if (!formData.saleStoreId) {
fieldNm = getMessage('stuff.detail.saleStoreId')
@ -1362,11 +1370,10 @@ export default function StuffDetail() {
}
if (params?.receiveUser !== '') {
if (checkLength(params?.receiveUser.trim()) > 40) {
if (checkLength(params?.receiveUser.trim()) > 10) {
return swalFire({ text: getMessage('stuff.detail.tempSave.message2'), type: 'alert', icon: 'warning' })
}
}
// 2 otherSaleStoreId
if (session.storeLvl !== '1') {
if (params.saleStoreLevel === '1') {
@ -1436,15 +1443,20 @@ export default function StuffDetail() {
}
}
/**
* 전각20자 (반각40자)
*/
const checkLength = (value) => {
let fullWidthLength = value.replace(/[^\u3000-\u9FFF\uFF01-\uFF5E]/g, '').length
let halfWidthLength = value.replace(/[\u3000-\u9FFF\uFF01-\uFF5E]/g, '').length
let totalLength = fullWidthLength * 2 + halfWidthLength
return totalLength
let str = new String(value)
let _byte = 0
if (str.length !== 0) {
for (let i = 0; i < str.length; i++) {
let str2 = str.charAt(i)
if (encodeURIComponent(str2).length > 4) {
_byte += 2
} else {
_byte++
}
}
}
return _byte
}
//
const onTempSave = async () => {
@ -1494,7 +1506,7 @@ export default function StuffDetail() {
//
if (params?.receiveUser !== '') {
if (checkLength(params?.receiveUser.trim()) > 40) {
if (checkLength(params?.receiveUser.trim()) > 10) {
return swalFire({ text: getMessage('stuff.detail.tempSave.message2'), type: 'alert', icon: 'warning' })
}
}
@ -1546,7 +1558,7 @@ export default function StuffDetail() {
type: 'alert',
icon: 'error',
})
console.error('error::::::', error)
console.log('error::::::', error)
})
}
}
@ -1992,7 +2004,9 @@ export default function StuffDetail() {
</td>
</tr>
<tr>
<th>{getMessage('stuff.detail.zipNo')}</th>
<th>
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
@ -2024,10 +2038,10 @@ export default function StuffDetail() {
getOptionLabel={(x) => x.prefName}
getOptionValue={(x) => x.prefId}
isSearchable={false}
onChange={onChangePrefCode}
value={prefCodeList.filter(function (option) {
return option.prefId === prefValue
})}
isDisabled={true}
/>
)}
</div>
@ -2557,7 +2571,9 @@ export default function StuffDetail() {
</td>
</tr>
<tr>
<th>{getMessage('stuff.detail.zipNo')}</th>
<th>
{getMessage('stuff.detail.zipNo')} <span className="important">*</span>
</th>
<td>
<div className="flx-box">
<div className="input-wrap mr5" style={{ width: '200px' }}>
@ -2590,10 +2606,10 @@ export default function StuffDetail() {
getOptionLabel={(x) => x.prefName}
getOptionValue={(x) => x.prefId}
isSearchable={false}
onChange={onChangePrefCode}
value={prefCodeList.filter(function (option) {
return option.prefId === prefValue
})}
isDisabled={true}
/>
)}
</div>

View File

@ -56,20 +56,19 @@ export default function StuffSubHeader({ type }) {
*/
const moveFloorPlan = () => {
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
const param = {
pid: managementState?.planList?.length > 0 ? managementState?.planList[0].planNo : '1',
pid: managementState?.planList?.length === 0 ? '1' : managementState?.planList[0].planNo,
objectNo: objectNo,
}
if (managementState?.planList?.length > 0) {
if (managementState?.planList?.length === 0) {
setSelectedMenu('surface')
} else {
if (managementState?.planList[0].estimateDate) {
setSelectedMenu('module')
} else {
setSelectedMenu('surface')
}
} else {
setSelectedMenu('surface')
}
const url = `/floor-plan?${queryStringFormatter(param)}`

View File

@ -66,11 +66,6 @@ export default function FindAddressPop(props) {
zipcode: watch('zipNo'),
}
if (params.zipcode.length < 7) {
swalFire({ text: getMessage('stuff.addressPopup.error.message1'), type: 'alert', icon: 'warning' })
return
}
setIsGlobalLoading(true)
get({ url: `https://zipcloud.ibsnet.co.jp/api/search?${queryStringFormatter(params)}` }).then((res) => {
if (res.status === 200) {
@ -90,20 +85,15 @@ export default function FindAddressPop(props) {
}
//
const applyAddress = () => {
if (!isNotEmptyArray(gridProps.gridData)) {
swalFire({ text: getMessage('stuff.addressPopup.error.message2'), type: 'alert', icon: 'warning' })
return
}
if (gridProps.gridData[0].zipcode == '') {
if (prefId == null) {
swalFire({ text: getMessage('stuff.addressPopup.error.message2'), type: 'alert', icon: 'warning' })
} else {
// 1:1
props.zipInfo({
zipNo: gridProps.gridData[0].zipcode,
address1: gridProps.gridData[0].address1,
address2: gridProps.gridData[0].address2,
address3: gridProps.gridData[0].address3,
prefId: gridProps.gridData[0].prefcode,
zipNo: zipNo,
address1: address1,
address2: address2,
address3: address3,
prefId: prefId,
})
//

View File

@ -114,7 +114,7 @@ export default function Simulator() {
setHatsudenryouPeakcutAllSnow([])
if (objectNo && pid && selectedPlan) {
fetchObjectDetail(objectNo, selectedPlan?.planNo??pid)
fetchObjectDetail(objectNo, selectedPlan.planNo)
fetchSimulatorNotice()
setPwrGnrSimType('D')
setPwrRecoil({ ...pwrRecoil, type: 'D' })

View File

@ -1,11 +0,0 @@
// local, development, production 과 관계없이 동일한 값으로 반환되는 부분은 해당 함수의 return 되는 부분만 수정하면 됩니다. (달라져야 하는 값이 아닌, 같은 값에 대해서는 local, development, production 파일을 모두 수정할 필요가 없어지게 됩니다.)
export default function getConfigs(params) {
// local, development, production 마다 달라지는 값
const { baseUrl, mode } = params
// 공통으로 반환되는 구조
return {
baseUrl,
mode,
}
}

View File

@ -1,13 +0,0 @@
import getConfigs from './config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 development 환경에 맞는 값을 지정합니다.)
const baseUrl = 'https://dev.hanssys.jp'
const mode = 'development'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.
const configDevelopment = getConfigs({
baseUrl,
mode,
})
export default configDevelopment

View File

@ -1,23 +0,0 @@
import configDevelopment from './config.development'
import configLocal from './config.local'
import configLocalDev from './config.local.dev'
import configProduction from './config.production'
// 클라이언트에서는 이 함수를 사용하여 config 값을 참조합니다.
const Config = () => {
console.log('🚀 ~ Config ~ process.env.NEXT_PUBLIC_RUN_MODE:', process.env.NEXT_PUBLIC_RUN_MODE)
switch (process.env.NEXT_PUBLIC_RUN_MODE) {
case 'local':
return configLocal
case 'local.dev':
return configLocalDev
case 'development':
return configDevelopment
case 'production':
return configProduction
default:
return configLocal
}
}
export default Config

View File

@ -1,13 +0,0 @@
import getConfigs from './config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 local 환경에 맞는 값을 지정합니다.)
const baseUrl = 'http://1.248.227.176:5000'
const mode = 'local.dev'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.
const configLocalDev = getConfigs({
baseUrl,
mode,
})
export default configLocalDev

View File

@ -1,13 +0,0 @@
import getConfigs from './config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 local 환경에 맞는 값을 지정합니다.)
const baseUrl = 'http://localhost:3000'
const mode = 'local'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.
const configLocal = getConfigs({
baseUrl,
mode,
})
export default configLocal

View File

@ -1,13 +0,0 @@
import getConfigs from './config.common'
// 환경마다 달라져야 할 변수, 값들을 정의합니다. (여기는 production 환경에 맞는 값을 지정합니다.)
const baseUrl = 'https://www.hanasys.jp'
const mode = 'production'
// 환경마다 달라져야 할 값들을 getConfig 함수에 전달합니다.
const configProduction = getConfigs({
baseUrl,
mode,
})
export default configProduction

View File

@ -9,7 +9,7 @@ import { globalFontAtom } from '@/store/fontAtom'
import { useRoof } from '@/hooks/common/useRoof'
import { usePolygon } from '@/hooks/usePolygon'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { POLYGON_TYPE } from '@/common/common'
export function useCanvasConfigInitialize() {
const canvas = useRecoilValue(canvasState)
@ -64,7 +64,6 @@ export function useCanvasConfigInitialize() {
groupDimensionInit()
reGroupInit() //그룹 객체 재그룹
moduleInit()
innerLinesInit() // innerLines 세팅 추가
}
const gridInit = () => {
@ -229,23 +228,5 @@ export function useCanvasConfigInitialize() {
})
}
const innerLinesInit = () => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
roofs.forEach((roof) => {
roof.innerLines = canvas
.getObjects()
.filter(
(obj) =>
obj.type === 'QLine' &&
obj.attributes?.type !== 'pitchSizeLine' &&
obj.attributes?.roofId === roof.id &&
innerLineTypes.includes(obj.name),
)
})
}
return { canvasLoadInit, gridInit }
}

View File

@ -7,6 +7,8 @@ import { POLYGON_TYPE } from '@/common/common'
export const useCanvasMenu = () => {
const [selectedMenu, setSelectedMenu] = useRecoilState(selectedMenuState)
const canvas = useRecoilValue(canvasState)
const { drawDirectionArrow } = usePolygon()
return {
selectedMenu,

View File

@ -1,6 +1,6 @@
'use client'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import useSWRMutation from 'swr/mutation'
import { useAxios } from '../useAxios'
import { unescapeString } from '@/util/common-utils'
@ -9,10 +9,7 @@ import { compasDegAtom } from '@/store/orientationAtom'
import { canvasState, currentCanvasPlanState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
import { useCircuitTrestle } from '../useCirCuitTrestle'
import { useContext } from 'react'
import { addedRoofsState } from '@/store/settingAtom'
import { roofsState } from '@/store/roofAtom'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useEffect } from 'react'
/**
* 캔버스 팝업 상태 관리
@ -22,22 +19,19 @@ import { GlobalDataContext } from '@/app/GlobalDataProvider'
export function useCanvasPopupStatusController(param = 1) {
const popupType = parseInt(param)
const setCompasDeg = useSetRecoilState(compasDegAtom)
const [compasDeg, setCompasDeg] = useRecoilState(compasDegAtom)
const [moduleSelectionDataStore, setModuleSelectionDataStore] = useRecoilState(moduleSelectionDataState)
const setSelectedModules = useSetRecoilState(selectedModuleState)
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState)
const { get, promiseGet, getFetcher, postFetcher } = useAxios()
const canvas = useRecoilValue(canvasState)
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const [addedRoofs, setAddedRoofs] = useRecoilState(addedRoofsState)
const [roofs, setRoofs] = useRecoilState(roofsState)
const { managementState, setManagementState } = useContext(GlobalDataContext)
/**
* 팝업 상태 조회
* @param {number} popupTypeParam
* @returns
*/
const getModuleSelection = async (popupTypeParam) => {
if (!currentCanvasPlan.objectNo || !currentCanvasPlan.planNo) return
const result = await promiseGet({
url: `/api/v1/canvas-popup-status?objectNo=${currentCanvasPlan.objectNo}&planNo=${currentCanvasPlan.planNo}&popupType=${popupTypeParam}`,
})
@ -49,7 +43,7 @@ export function useCanvasPopupStatusController(param = 1) {
return null
})
return result?.data
return result.data
}
/**
@ -57,36 +51,23 @@ export function useCanvasPopupStatusController(param = 1) {
* 조회 전체 데이터 recoil에 저장
*/
const handleModuleSelectionTotal = async () => {
let resultData = {}
for (let i = 1; i < 3; i++) {
const result = await getModuleSelection(i)
if (!result?.objectNo) return
console.log('🚀 ~ handleModuleSelectionTotal ~ result:', result)
if (!result.objectNo) return
if (i === 1) {
if (result.popupStatus && unescapeString(result.popupStatus)) {
const data = JSON.parse(unescapeString(result.popupStatus))
if (data?.compasDeg) setCompasDeg(data.compasDeg)
if (data?.module) setSelectedModules(data.module)
// setModuleSelectionDataStore(data)
resultData = { ...data }
}
setCompasDeg(result.popupStatus)
} else if (i === 2) {
const data = JSON.parse(unescapeString(result.popupStatus))
setModuleSelectionDataStore(data)
const roofSurfaceList = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
roofSurfaceList.forEach((surface) => {
surface.modules = modules.filter((module) => module.surfaceId === surface.id)
})
if (data.roofConstructions) {
setRoofs(data.roofConstructions)
// setManagementState({ ...managementState, roofs: data.roofConstructions.map((roof) => roof.construction.managementState) })
// setModuleSelectionDataStore({ ...moduleSelectionDataStore, roofConstructions: data.roofConstruction })
resultData = { ...resultData, roofConstructions: data.roofConstructions }
}
// if (data?.module) setManagementState(data.common.managementState)
if (data.module) setSelectedModules(data.module)
}
}
setModuleSelectionDataStore(resultData)
}
/**
@ -99,8 +80,7 @@ export function useCanvasPopupStatusController(param = 1) {
objectNo: currentCanvasPlan.objectNo,
planNo: parseInt(currentCanvasPlan.planNo),
popupType: popupType.toString(),
// popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'),
popupStatus: JSON.stringify(arg).replace(/"/g, '\"'),
popupStatus: popupType === 1 ? arg : JSON.stringify(arg).replace(/"/g, '\"'),
}
postFetcher(`/api/v1/canvas-popup-status`, params)
},

View File

@ -22,8 +22,9 @@ import { useAxios } from '../useAxios'
* const honorificCodes = findCommonCode(200800);
*/
export const useCommonCode = () => {
const globalLocale = useRecoilValue(globalLocaleStore)
const [commonCode, setCommonCode] = useRecoilState(commonCodeState)
const globalLocale = useRecoilValue(globalLocaleStore)
const { promiseGet } = useAxios()
const findCommonCode = (key) => {
const resultCodes = commonCode[key]?.map((code) => {
@ -40,6 +41,18 @@ export const useCommonCode = () => {
return resultCodes
}
useEffect(() => {
const getCommonCode = async () => {
await promiseGet({ url: '/api/commcode/qc-comm-code' }).then((res) => {
setCommonCode(Object.groupBy(res.data, ({ clHeadCd }) => clHeadCd))
})
}
if (!isObjectNotEmpty(commonCode)) {
getCommonCode()
}
}, [])
return {
commonCode,
findCommonCode,

View File

@ -1,11 +1,11 @@
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { useRecoilState, useRecoilValue } from 'recoil'
import { wordDisplaySelector } from '@/store/settingAtom'
import { useEvent } from '@/hooks/useEvent'
import { checkLineOrientation, getDistance } from '@/util/canvas-util'
import { commonUtilsState, dimensionLineSettingsState } from '@/store/commonUtilsAtom'
import { fontSelector } from '@/store/fontAtom'
import { canvasState, currentMenuState } from '@/store/canvasAtom'
import { canvasState } from '@/store/canvasAtom'
import { v4 as uuidv4 } from 'uuid'
import { usePopup } from '@/hooks/usePopup'
import Distance from '@/components/floor-plan/modal/distance/Distance'
@ -16,91 +16,57 @@ import { BATCH_TYPE } from '@/common/common'
export function useCommonUtils() {
const canvas = useRecoilValue(canvasState)
const wordDisplay = useRecoilValue(wordDisplaySelector)
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent, removeMouseEvent } = useEvent()
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent()
const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup, closeAll, targetClose } = usePopup()
const { addPopup } = usePopup()
const { drawDirectionArrow, addLengthText } = usePolygon()
const { applyDormers } = useObjectBatch({})
useEffect(() => {
commonTextMode()
if (commonUtils.dimension) {
if (commonUtils.text) {
commonTextMode()
} else if (commonUtils.dimension) {
commonDimensionMode()
return
}
if (commonUtils.distance) {
} else if (commonUtils.distance) {
commonDistanceMode()
return
}
}, [commonUtils, dimensionSettings, commonTextFont, dimensionLineTextFont])
const commonTextMode = () => {
let textbox
if (commonUtils.text) {
targetClose('other')
setTimeout(() => {
commonTextKeyEvent()
addCanvasMouseEventListener('mouse:down', (event) => {
const pointer = canvas?.getPointer(event.e)
commonTextKeyEvent()
addCanvasMouseEventListener('mouse:down', (event) => {
const pointer = canvas?.getPointer(event.e)
textbox = new fabric.Textbox('', {
left: pointer.x,
top: pointer.y,
width: 200,
editable: true,
name: 'commonText',
visible: wordDisplay,
fill: commonTextFont.fontColor.value,
fontFamily: commonTextFont.fontFamily.value,
fontSize: commonTextFont.fontSize.value,
fontStyle: commonTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: commonTextFont.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
selectable: true,
lockMovementX: true,
lockMovementY: true,
originX: 'center',
originY: 'center',
})
canvas?.add(textbox)
canvas.setActiveObject(textbox)
textbox.enterEditing()
textbox.selectAll()
textbox = new fabric.Textbox('', {
left: pointer.x,
top: pointer.y,
width: 200,
editable: true,
name: 'commonText',
visible: wordDisplay,
fill: commonTextFont.fontColor.value,
fontFamily: commonTextFont.fontFamily.value,
fontSize: commonTextFont.fontSize.value,
fontStyle: commonTextFont.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontWeight: commonTextFont.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
selectable: true,
lockMovementX: true,
lockMovementY: true,
originX: 'center',
originY: 'center',
})
}, 100)
} else {
removeMouseEvent('mouse:down')
const activeObject = canvas?.getActiveObject()
const commonTexts = canvas?.getObjects().filter((obj) => obj.name === 'commonText')
if (commonTexts) {
commonTexts.forEach((text) => {
if (text.text === '') {
canvas?.remove(text)
}
})
}
/*if (activeObject && activeObject.name === 'commonText') {
if (activeObject && activeObject.isEditing) {
if (activeObject.text === '') {
canvas?.remove(activeObject)
} else {
activeObject.exitEditing()
}
//정책 협의
const texts = canvas.getObjects().filter((obj) => obj.name === 'commonText')
texts.forEach((text) => {
text.set({ editable: false })
})
canvas.renderAll()
}
}*/
initEvent()
canvas?.add(textbox)
canvas.setActiveObject(textbox)
textbox.enterEditing()
textbox.selectAll()
})
}
}

View File

@ -153,18 +153,18 @@ export function useGrid() {
const move = (object, x, y) => {
object.set({
...object,
x1: object.direction === 'vertical' ? object.x1 + x : -1500,
x2: object.direction === 'vertical' ? object.x1 + x : 2500,
y1: object.direction === 'vertical' ? -1500 : object.y1 + y,
y2: object.direction === 'vertical' ? 2500 : object.y1 + y,
x1: object.direction === 'vertical' ? object.x1 + x : 0,
x2: object.direction === 'vertical' ? object.x1 + x : canvas.width,
y1: object.direction === 'vertical' ? 0 : object.y1 + y,
y2: object.direction === 'vertical' ? canvas.height : object.y1 + y,
})
}
const copy = (object, length) => {
const lineStartX = object.direction === 'vertical' ? object.x1 + length : -1500
const lineEndX = object.direction === 'vertical' ? object.x2 + length : 2500
const lineStartY = object.direction === 'vertical' ? -1500 : object.y1 + length
const lineEndY = object.direction === 'vertical' ? 2500 : object.y1 + length
const lineStartX = object.direction === 'vertical' ? object.x1 + length : 0
const lineEndX = object.direction === 'vertical' ? object.x2 + length : canvas.width
const lineStartY = object.direction === 'vertical' ? 0 : object.y1 + length
const lineEndY = object.direction === 'vertical' ? canvas.width : object.y1 + length
const line = new fabric.Line([lineStartX, lineStartY, lineEndX, lineEndY], {
stroke: gridColor,

View File

@ -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
})
}

View File

@ -16,13 +16,12 @@ import { usePopup } from '@/hooks/usePopup'
import { useState } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useSurfaceShapeBatch } from '@/hooks/surface/useSurfaceShapeBatch'
import { useRecoilState, useRecoilValue } from 'recoil'
import { useRecoilValue } from 'recoil'
import { canvasState, currentMenuState } from '@/store/canvasAtom'
import { MENU } from '@/common/common'
import { useTrestle } from '@/hooks/module/useTrestle'
import { usePolygon } from '@/hooks/usePolygon'
import { useOrientation } from '@/hooks/module/useOrientation'
import { corridorDimensionSelector, settingModalFirstOptionsState } from '@/store/settingAtom'
/**
* 메뉴 처리
@ -37,11 +36,8 @@ export default function useMenu() {
const { deleteAllSurfacesAndObjects } = useSurfaceShapeBatch({})
const { clear: trestleClear, setAllModuleSurfaceIsComplete } = useTrestle()
const { nextStep } = useOrientation()
const [corridorDimension, setCorridorDimension] = useRecoilState(corridorDimensionSelector)
const handleMenu = (type) => {
if (type === 'outline') {
// 지붕 덮개 메뉴의 경우는 복도치수로 적용한다.
setCorridorDimension(0)
switch (currentMenu) {
case MENU.ROOF_COVERING.EXTERIOR_WALL_LINE:
addPopup(popupId, 1, <WallLineSetting id={popupId} />)
@ -71,8 +67,6 @@ export default function useMenu() {
}
if (type === 'surface') {
// 배치면 메뉴의 경우는 실치수로 적용한다.
setCorridorDimension(1)
switch (currentMenu) {
// case MENU.BATCH_CANVAS.SLOPE_SETTING:
// addPopup(popupId, 1, <Slope id={popupId} />)
@ -93,8 +87,6 @@ export default function useMenu() {
}
if (type === 'module') {
// 모듈,회로 구성 메뉴의 경우는 실치수로 적용한다.
setCorridorDimension(1)
switch (currentMenu) {
case MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING:
trestleClear()

View File

@ -1,5 +1,5 @@
import { useEffect, useRef, useState } from 'react'
import { useRecoilState, useSetRecoilState } from 'recoil'
import { useRecoilState } from 'recoil'
import { useSwal } from '@/hooks/useSwal'
import { useAxios } from '../useAxios'
@ -7,8 +7,6 @@ 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'
import Config from '@/config/config.export'
/**
* 배경 이미지 관리
@ -17,9 +15,6 @@ import Config from '@/config/config.export'
* 이미지 -> 캔버스 배경에 이미지 로드
* 주소 -> 구글 맵에서 주소 검색 이미지로 다운로드 받아서 캔버스 배경에 이미지 로드
* .dwg -> api를 통해서 .png로 변환 캔버스 배경에 이미지 로드
*
* setCurrentBgImage 이미지를 세팅하면 도면에 배경으로 로딩된다.
* 다만 S3 Response에 aws 고유 주소가 나오는데 여기서는 cloudfront 사용을 위해서 NEXT_PUBLIC_AWS_S3_BASE_URL 도메인을 사용한다.
* @returns {object}
*/
export function useRefFiles() {
@ -33,8 +28,7 @@ export function useRefFiles() {
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const { handleBackImageLoadToCanvas } = useCanvas()
const { swalFire } = useSwal()
const { get, post, del } = useAxios()
const setPopSpinnerStore = useSetRecoilState(popSpinnerState)
const { get, post } = useAxios()
useEffect(() => {
if (refFileMethod === '1') {
@ -45,7 +39,6 @@ export function useRefFiles() {
}, [refFileMethod])
/**
* 최초 input type="file" 대한 이벤트
* 파일 불러오기 버튼 컨트롤
* @param {*} file
*/
@ -66,10 +59,6 @@ export function useRefFiles() {
}
}
/**
* 허용하는 파일인지 체크한다
* @param {File} file
*/
const refFileSetting = (file) => {
console.log('🚀 ~ refFileSetting ~ file:', file)
if (file.name.split('.').pop() === 'dwg') {
@ -88,40 +77,34 @@ export function useRefFiles() {
}
/**
* 이미지 파일 삭제
* 파일 삭제
*/
const handleFileDelete = async () => {
swalFire({
text: '삭제하시겠습니까?',
type: 'confirm',
confirmFn: async () => {
setPopSpinnerStore(true)
console.log('🚀 ~ handleFileDelete ~ handleFileDelete:', refImage)
console.log('🚀 ~ handleFileDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName)
await del({ url: `${Config().baseUrl}/api/image/upload?fileName=${currentCanvasPlan.bgImageName}` })
setCurrentBgImage(null)
setRefImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null }))
await deleteBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
})
setPopSpinnerStore(false)
},
})
}
/**
* 주소 이미지 삭제
* 주소 삭제
*/
const handleAddressDelete = async () => {
swalFire({
text: '삭제하시겠습니까?',
type: 'confirm',
confirmFn: async () => {
console.log('🚀 ~ handleAddressDelete ~ handleAddressDelete:', refImage)
console.log('🚀 ~ handleAddressDelete ~ currentCanvasPlan.bgImageName:', currentCanvasPlan.bgImageName)
await del({ url: `${Config().baseUrl}/api/image/map?fileName=${currentCanvasPlan.bgImageName}` })
setMapPositionAddress('')
setCurrentBgImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null }))
await deleteBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
@ -131,7 +114,7 @@ export function useRefFiles() {
}
/**
* 주소로 구글 이미지 다운로드하여 캔버스 배경으로 로드
* 주소로 구글 이미지 다운로드
*/
const handleMapImageDown = async () => {
console.log('🚀 ~ handleMapImageDown ~ handleMapImageDown:')
@ -150,16 +133,15 @@ export function useRefFiles() {
}))
const res = await get({
url: `${Config().baseUrl}/api/image/map?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`,
url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?q=${queryRef.current.value}&fileNm=${currentCanvasPlan.id}&zoom=20`,
})
console.log('🚀 ~ handleMapImageDown ~ res:', res)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_AWS_S3_BASE_URL}/${res.fileName}`)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
await setBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
// imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
imagePath: `${res.filePath}`,
imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
})
}
@ -167,26 +149,16 @@ export function useRefFiles() {
* 배경 이미지 로드를 위한 세팅
*/
useEffect(() => {
// if (!currentBgImage) {
// return
// }
console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage)
if (currentBgImage) {
handleBackImageLoadToCanvas(currentBgImage)
setCurrentCanvasPlan((prev) => ({
...prev,
// bgImageName: refImage?.name ?? null,
bgImageName: currentBgImage.split('/').pop(),
mapPositionAddress: queryRef.current.value,
}))
} else {
setRefImage(null)
setCurrentCanvasPlan((prev) => ({
...prev,
bgImageName: null,
mapPositionAddress: null,
}))
if (!currentBgImage) {
return
}
console.log('🚀 ~ useEffect ~ currentBgImage:', currentBgImage)
handleBackImageLoadToCanvas(currentBgImage)
setCurrentCanvasPlan((prev) => ({
...prev,
bgImageName: refImage?.name ?? null,
mapPositionAddress: queryRef.current.value,
}))
}, [currentBgImage])
/**
@ -194,7 +166,6 @@ 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,
@ -209,22 +180,20 @@ export function useRefFiles() {
formData.append('file', file)
const res = await post({
url: `${Config().baseUrl}/api/image/upload`,
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/upload`,
data: formData,
})
console.log('🚀 ~ handleUploadImageRefFile ~ res:', res)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_AWS_S3_BASE_URL}/${res.fileName}`)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
setRefImage(file)
const params = {
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
// imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
imagePath: `${res.filePath}`,
imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
}
console.log('🚀 ~ handleUploadImageRefFile ~ params:', params)
await setBackGroundImage(params)
setPopSpinnerStore(false)
}
/**
@ -235,54 +204,15 @@ export function useRefFiles() {
const formData = new FormData()
formData.append('file', file)
/** 캐드 도면 파일 변환 */
const res = await post({ url: converterUrl, data: formData })
console.log('🚀 ~ handleUploadConvertRefFile ~ res:', res)
// Convert Base64 to Blob
const base64Data = res.Files[0].FileData
const byteCharacters = atob(base64Data)
const byteArrays = []
for (let offset = 0; offset < byteCharacters.length; offset += 512) {
const slice = byteCharacters.slice(offset, offset + 512)
const byteNumbers = new Array(slice.length)
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i)
}
const byteArray = new Uint8Array(byteNumbers)
byteArrays.push(byteArray)
}
const blob = new Blob(byteArrays, { type: 'image/png' })
// Create File object from Blob
const convertImg = new File([blob], res.Files[0].FileName, { type: 'image/png' })
const newFormData = new FormData()
newFormData.append('file', convertImg)
/** 캐드 도면 파일 업로드 */
const result = await post({
url: `${Config().baseUrl}/api/image/cad`,
data: newFormData,
url: `${process.env.NEXT_PUBLIC_HOST_URL}/cad/convert`,
data: res,
})
console.log('🚀 ~ handleUploadConvertRefFile ~ result:', result)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_AWS_S3_BASE_URL}/${result.fileName}`)
// 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)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${result.filePath}`)
setRefImage(res.Files[0].FileData)
}
/**

View File

@ -23,65 +23,102 @@ export function useRoofFn() {
//면형상 선택 클릭시 지붕 패턴 입히기
function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) {
try {
if (!polygon) {
return
}
if (polygon.points.length < 3) {
return
}
if (isForceChange && !isDisplay) {
/*if (polygon.roofMaterial) {
if (!polygon) {
return
}
if (polygon.points.length < 3) {
return
}
if (isForceChange && !isDisplay) {
/*if (polygon.roofMaterial) {
polygon.roofMaterial = null
}*/
}
if (!roofMaterial) {
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
}
const ratio = window.devicePixelRatio || 1
const layout = roofMaterial.layout
let width = (roofMaterial.width || 226) / 10
let height = (roofMaterial.length || 158) / 10
const index = roofMaterial.index ?? 0
let roofStyle = 2
const inputPatternSize = { width: width, height: height } //임시 사이즈
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
if (polygon.direction === 'east' || polygon.direction === 'west') {
//세로형이면 width height를 바꿈
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
}
// 패턴 소스를 위한 임시 캔버스 생성
const patternSourceCanvas = document.createElement('canvas')
patternSourceCanvas.width = polygon.width * ratio
patternSourceCanvas.height = polygon.height * ratio
const ctx = patternSourceCanvas.getContext('2d')
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
ctx.lineWidth = 2
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
if (trestleMode) {
ctx.strokeStyle = 'black'
ctx.lineWidth = 0.2
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
} else {
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
}
if (polygon.direction === 'east' || polygon.direction === 'west') {
offset = roofStyle === 1 ? 0 : patternSize.height / 2
for (let col = 0; col <= cols; col++) {
const x = col * patternSize.width
const yStart = 0
const yEnd = patternSourceCanvas.height
ctx.beginPath()
ctx.moveTo(x, yStart) // 선 시작점
ctx.lineTo(x, yEnd) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
}
for (let row = 0; row <= rows; row++) {
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
const xStart = col * patternSize.width
const xEnd = xStart + patternSize.width
ctx.beginPath()
ctx.moveTo(xStart, y) // 선 시작점
ctx.lineTo(xEnd, y) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
}
}
}
if (!roofMaterial) {
roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial
}
} else {
for (let row = 0; row <= rows; row++) {
const y = row * patternSize.height
const ratio = window.devicePixelRatio || 1
const layout = roofMaterial.layout
ctx.beginPath()
ctx.moveTo(0, y) // 선 시작점
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
}
let width = (roofMaterial.width || 226) / 10
let height = (roofMaterial.length || 158) / 10
const index = roofMaterial.index ?? 0
let roofStyle = 2
const inputPatternSize = { width: width, height: height } //임시 사이즈
const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해
if (polygon.direction === 'east' || polygon.direction === 'west') {
//세로형이면 width height를 바꿈
;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width]
}
// 패턴 소스를 위한 임시 캔버스 생성
const patternSourceCanvas = document.createElement('canvas')
patternSourceCanvas.width = polygon.width * ratio
patternSourceCanvas.height = polygon.height * ratio
const ctx = patternSourceCanvas.getContext('2d')
let offset = roofStyle === 1 ? 0 : patternSize.width / 2
const rows = Math.floor(patternSourceCanvas.height / patternSize.height)
const cols = Math.floor(patternSourceCanvas.width / patternSize.width)
ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index]
ctx.lineWidth = 2
ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white'
if (trestleMode) {
ctx.strokeStyle = 'black'
ctx.lineWidth = 0.2
ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'
} else {
ctx.fillStyle = 'rgba(255, 255, 255, 1)'
}
if (polygon.direction === 'east' || polygon.direction === 'west') {
offset = roofStyle === 1 ? 0 : patternSize.height / 2
for (let col = 0; col <= cols; col++) {
const x = col * patternSize.width
const yStart = 0
const yEnd = patternSourceCanvas.height
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
const yStart = row * patternSize.height
const yEnd = yStart + patternSize.height
ctx.beginPath()
ctx.moveTo(x, yStart) // 선 시작점
ctx.lineTo(x, yEnd) // 선 끝점
@ -89,90 +126,49 @@ export function useRoofFn() {
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
}
for (let row = 0; row <= rows; row++) {
const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height
const xStart = col * patternSize.width
const xEnd = xStart + patternSize.width
ctx.beginPath()
ctx.moveTo(xStart, y) // 선 시작점
ctx.lineTo(xEnd, y) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height)
}
}
}
} else {
for (let row = 0; row <= rows; row++) {
const y = row * patternSize.height
ctx.beginPath()
ctx.moveTo(0, y) // 선 시작점
ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height)
}
for (let col = 0; col <= cols; col++) {
const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width
const yStart = row * patternSize.height
const yEnd = yStart + patternSize.height
ctx.beginPath()
ctx.moveTo(x, yStart) // 선 시작점
ctx.lineTo(x, yEnd) // 선 끝점
ctx.stroke()
if (mode === 'allPainted' || trestleMode) {
ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart)
}
}
}
}
const hachingPatternSourceCanvas = document.createElement('canvas')
if (mode === 'lineHatch') {
hachingPatternSourceCanvas.width = polygon.width * ratio
hachingPatternSourceCanvas.height = polygon.height * ratio
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
const gap = 10
ctx1.strokeStyle = 'green' // 선 색상
ctx1.lineWidth = 0.3 // 선 두께
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
ctx1.beginPath()
ctx1.moveTo(x, 0) // 선 시작점
ctx1.lineTo(0, x) // 선 끝점
ctx1.stroke()
}
}
const combinedPatternCanvas = document.createElement('canvas')
combinedPatternCanvas.width = polygon.width * ratio
combinedPatternCanvas.height = polygon.height * ratio
const combinedCtx = combinedPatternCanvas.getContext('2d')
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
// 패턴 생성
const pattern = new fabric.Pattern({
source: combinedPatternCanvas,
repeat: 'repeat',
})
polygon.set('fill', null)
polygon.set('fill', pattern)
polygon.roofMaterial = roofMaterial
polygon.canvas?.renderAll()
} catch (e) {
console.log(e)
}
const hachingPatternSourceCanvas = document.createElement('canvas')
if (mode === 'lineHatch') {
hachingPatternSourceCanvas.width = polygon.width * ratio
hachingPatternSourceCanvas.height = polygon.height * ratio
const ctx1 = hachingPatternSourceCanvas.getContext('2d')
const gap = 10
ctx1.strokeStyle = 'green' // 선 색상
ctx1.lineWidth = 0.3 // 선 두께
for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) {
ctx1.beginPath()
ctx1.moveTo(x, 0) // 선 시작점
ctx1.lineTo(0, x) // 선 끝점
ctx1.stroke()
}
}
const combinedPatternCanvas = document.createElement('canvas')
combinedPatternCanvas.width = polygon.width * ratio
combinedPatternCanvas.height = polygon.height * ratio
const combinedCtx = combinedPatternCanvas.getContext('2d')
// 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘
combinedCtx.drawImage(patternSourceCanvas, 0, 0)
combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0)
// 패턴 생성
const pattern = new fabric.Pattern({
source: combinedPatternCanvas,
repeat: 'repeat',
})
polygon.set('fill', null)
polygon.set('fill', pattern)
polygon.roofMaterial = roofMaterial
polygon.canvas?.renderAll()
}
function removeRoofMaterial(roof = currentObject) {

View File

@ -13,8 +13,6 @@ import { useSwal } from '@/hooks/useSwal'
// Constants
const ESTIMATE_API_ENDPOINT = '/api/estimate' // API 엔드포인트 정의
import Config from '@/config/config.export'
// Helper functions
const updateItemInList = (itemList, dispOrder, updates) => {
return itemList.map((item) => (item.dispOrder === dispOrder ? { ...item, ...updates } : item))
@ -132,14 +130,13 @@ export const useEstimateController = (planNo, flag) => {
addFlg: true,
paDispOrder: null,
dispCableFlg: '0',
itemTpCd: '',
},
],
})
}
useEffect(() => {
setEstimateData({ ...estimateContextState, userId: session.userId })
setEstimateData({ ...estimateContextState, userId: session.userId, sapSalesStoreCd: session.custCd })
}, [estimateContextState])
// 첨부파일 다운로드
@ -312,7 +309,6 @@ export const useEstimateController = (planNo, flag) => {
//봄 컴포넌트 제품은 0으로
item.openFlg = '0'
item.unitOpenFlg = '0'
}
}
})
@ -325,7 +321,6 @@ export const useEstimateController = (planNo, flag) => {
}
})
if (delCnt === estimateData.itemList.length) {
itemFlg = false
setIsGlobalLoading(false)
return swalFire({ text: getMessage('estimate.detail.save.requiredItem'), type: 'alert', icon: 'warning' })
}
@ -451,12 +446,14 @@ export const useEstimateController = (planNo, flag) => {
icon: 'warning',
})
} else {
if (checkLength(copyReceiveUser.trim()) > 40) {
if (checkLength(copyReceiveUser.trim()) > 10) {
return swalFire({ text: getMessage('stuff.detail.tempSave.message2'), type: 'alert', icon: 'warning' })
}
}
const params = {
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
objectNo: estimateData.objectNo,
planNo: sendPlanNo,
copySaleStoreId: otherSaleStoreId ? otherSaleStoreId : saleStoreId,
@ -465,64 +462,40 @@ export const useEstimateController = (planNo, flag) => {
}
setIsGlobalLoading(true)
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params })
.then(async (res) => {
setIsGlobalLoading(false)
if (res.status === 201) {
if (isObjectNotEmpty(res.data)) {
let newObjectNo = res.data.objectNo
const copyImage = await handleEstimateImageCopy(params.objectNo, params.planNo, newObjectNo, '1')
swalFire({
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
type: 'alert',
confirmFn: () => {
setEstimateCopyPopupOpen(false) //팝업닫고
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
},
})
}
} else {
setIsGlobalLoading(false)
await promisePost({ url: '/api/estimate/save-estimate-copy', data: params }).then((res) => {
setIsGlobalLoading(false)
if (res.status === 201) {
if (isObjectNotEmpty(res.data)) {
let newObjectNo = res.data.objectNo
swalFire({
text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessage'),
type: 'alert',
confirmFn: () => {
setEstimateCopyPopupOpen(false) //팝업닫고
router.push(`/management/stuff/detail?objectNo=${newObjectNo.toString()}`, { scroll: false })
},
})
}
})
.catch((e) => {
console.error('캔버스 복사 중 오류 발생')
swalFire({ text: getMessage('estimate.detail.estimateCopyPopup.copy.alertMessageError'), type: 'alert', icon: 'error' })
} else {
setIsGlobalLoading(false)
})
}
})
}
const handleEstimateImageCopy = async (objectNo, planNo, newObjectNo, newPlanNo) => {
await promisePost({ url: `${Config().baseUrl}/api/image/estimate-image-copy`, data: { objectNo, planNo, newObjectNo, newPlanNo } }).then(
(res) => {
return res
},
)
}
const handleDeleteEstimate = async (canvasStatus) => {
try {
setIsGlobalLoading(true)
await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/delete-estimate`, data: canvasStatus }).then((res) => {
if (res.status === 201) {
}
})
} catch (e) {
console.error('error::::::::::::', e.response.data.message)
}
setIsGlobalLoading(false)
}
/**
* 전각20자 (반각40자)
*/
const checkLength = (value) => {
let fullWidthLength = value.replace(/[^\u3000-\u9FFF\uFF01-\uFF5E]/g, '').length
let halfWidthLength = value.replace(/[\u3000-\u9FFF\uFF01-\uFF5E]/g, '').length
let totalLength = fullWidthLength * 2 + halfWidthLength
return totalLength
let str = new String(value)
let _byte = 0
if (str.length !== 0) {
for (let i = 0; i < str.length; i++) {
let str2 = str.charAt(i)
if (encodeURIComponent(str2).length > 4) {
_byte += 2
} else {
_byte++
}
}
}
return _byte
}
return {
@ -534,7 +507,5 @@ export const useEstimateController = (planNo, flag) => {
fetchSetting,
handleEstimateFileDownload,
handleEstimateCopy,
handleDeleteEstimate,
handleEstimateImageCopy,
}
}

View File

@ -5,7 +5,6 @@ import { usePlan } from '../usePlan'
import { POLYGON_TYPE } from '@/common/common'
import { QcastContext } from '@/app/QcastProvider'
import { useContext } from 'react'
import Config from '@/config/config.export'
/**
* 이미지 로더 hook
@ -80,8 +79,7 @@ export function useImgLoader() {
/** 이미지 크롭 요청 */
const result = await post({
// url: `${process.env.NEXT_PUBLIC_API_HOST_URL}/image/canvas`,
url: `${Config().baseUrl}/api/image/canvas`,
url: `${process.env.NEXT_PUBLIC_HOST_URL}/image/canvas`,
data: formData,
})
console.log('🚀 ~ handleCanvasToPng ~ result:', result)

View File

@ -27,7 +27,7 @@ export const useMainContentsController = () => {
*/
const fetchObjectList = async () => {
try {
const apiUrl = `/api/main-page/object/${session?.storeId}/${session?.userId}/${session?.builderNo}/list`
const apiUrl = `/api/main-page/object/${session?.storeId}/list`
await promiseGet({
url: apiUrl,
}).then((res) => {

View File

@ -54,7 +54,7 @@ export function useModule() {
})
return
}
// canvas.discardActiveObject() //선택해제
canvas.discardActiveObject() //선택해제
const isSetupModules = getOtherModules(selectedObj)
const selectedModules = canvas.getObjects().filter((obj) => selectedIds.includes(obj.id) && obj.name === 'module') //선택했던 객체들만 가져옴
@ -991,14 +991,14 @@ export function useModule() {
const getRowModules = (target) => {
return canvas
.getObjects()
.filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && Math.abs(obj.top - target.top) < 1)
.filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top)
.sort((a, b) => a.left - b.left)
}
const getColumnModules = (target) => {
return canvas
.getObjects()
.filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && Math.abs(obj.left - target.left) < 1)
.filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.left === target.left)
.sort((a, b) => a.top - b.top)
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,35 @@
import { useEffect, useState } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { useMasterController } from '@/hooks/common/useMasterController'
import { canvasSettingState, canvasState, currentCanvasPlanState, moduleSetupSurfaceState } from '@/store/canvasAtom'
import { POLYGON_TYPE, BATCH_TYPE } from '@/common/common'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { roofDisplaySelector } from '@/store/settingAtom'
import offsetPolygon from '@/util/qpolygon-utils'
import { v4 as uuidv4 } from 'uuid'
import { QPolygon } from '@/components/fabric/QPolygon'
import { useEvent } from '@/hooks/useEvent'
import { useSwal } from '@/hooks/useSwal'
import { useMessage } from '@/hooks/useMessage'
export function useModulePlace() {
const canvas = useRecoilValue(canvasState)
const moduleSelectionData = useRecoilValue(moduleSelectionDataState)
const [trestleDetailParams, setTrestleDetailParams] = useState([])
const [trestleDetailList, setTrestleDetailList] = useState([])
const selectedModules = useRecoilValue(selectedModuleState)
const { getTrestleDetailList } = useMasterController()
const canvasSetting = useRecoilValue(canvasSettingState)
const { setSurfaceShapePattern } = useRoofFn()
const roofDisplay = useRecoilValue(roofDisplaySelector)
const { addTargetMouseEventListener } = useEvent()
const setModuleSetupSurface = useSetRecoilState(moduleSetupSurfaceState)
const [saleStoreNorthFlg, setSaleStoreNorthFlg] = useState(false)
const { swalFire } = useSwal()
const { getMessage } = useMessage()
return {
selectedModules,
}
}

View File

@ -3,7 +3,7 @@ import { useContext, useEffect, useState } from 'react'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { selectedModuleState, moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { selectedModuleState, moduleSelectionInitParamsState, moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
import { canvasState } from '@/store/canvasAtom'
import { POLYGON_TYPE } from '@/common/common'
@ -12,20 +12,23 @@ import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
export function useModuleSelection(props) {
const canvas = useRecoilValue(canvasState)
const { managementState, setManagementState } = useContext(GlobalDataContext)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const [roughnessCodes, setRoughnessCodes] = useState([]) //면조도 목록
const [windSpeedCodes, setWindSpeedCodes] = useState([]) //기준풍속 목록
const [moduleList, setModuleList] = useState([{}]) //모듈 목록
const [selectedSurfaceType, setSelectedSurfaceType] = useState({}) //선택된 면조도
const [installHeight, setInstallHeight] = useState(managementState?.installHeight) //설치 높이
const [standardWindSpeed, setStandardWindSpeed] = useState() //기준풍속
const [verticalSnowCover, setVerticalSnowCover] = useState(managementState?.verticalSnowCover) //수직적설량
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈
// const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const [selectedSurfaceType, setSelectedSurfaceType] = useState({}) //선택된 면조도
const [installHeight, setInstallHeight] = useState() //설치 높이
const [standardWindSpeed, setStandardWindSpeed] = useState({}) //기준풍속
const [verticalSnowCover, setVerticalSnowCover] = useState() //수직적설량
const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈
const [moduleSelectionInitParams, setModuleSelectionInitParams] = useRecoilState(moduleSelectionInitParamsState) //모듈 기본 데이터 ex) 면조도, 높이등등
const { getModuleTypeItemList } = useMasterController()
const { findCommonCode } = useCommonCode()
const resetStatisticsData = useResetRecoilState(moduleStatisticsState)
const { restoreModuleInstArea } = useModuleBasicSetting()
const bindInitData = () => {
@ -40,21 +43,21 @@ export function useModuleSelection(props) {
//탭별 파라메터 초기화
useEffect(() => {
bindInitData()
// const initParams = {
// illuminationTp: managementState?.surfaceTypeValue, //면조도
// illuminationTpNm: managementState?.surfaceType, //면조도명
// instHt: managementState?.installHeight, //설치높이
// stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속
// stdSnowLd: managementState?.verticalSnowCover, //기준적설량
// saleStoreNorthFlg: managementState?.saleStoreNorthFlg, //북쪽 설치 여부
// }
const initParams = {
illuminationTp: managementState?.surfaceTypeValue, //면조도
illuminationTpNm: managementState?.surfaceType, //면조도명
instHt: managementState?.installHeight, //설치높이
stdWindSpeed: managementState?.standardWindSpeedId, //기준풍속
stdSnowLd: managementState?.verticalSnowCover, //기준적설량
saleStoreNorthFlg: managementState?.saleStoreNorthFlg, //북쪽 설치 여부
}
// if (selectedModules) {
// initParams.moduleTpCd = selectedModules.itemTp
// initParams.moduleItemId = selectedModules.itemId
// }
if (selectedModules) {
initParams.moduleTpCd = selectedModules.itemTp
initParams.moduleItemId = selectedModules.itemId
}
// setModuleSelectionInitParams(initParams)
setModuleSelectionInitParams(initParams)
}, [managementState])
useEffect(() => {
@ -84,7 +87,7 @@ export function useModuleSelection(props) {
//새로고침시 데이터 날아가는거 방지
if (managementState === null) {
setManagementState(managementState)
setManagementState(managementStateLoaded)
} else {
bindInitData()
}
@ -92,7 +95,7 @@ export function useModuleSelection(props) {
getModuleData(roofsIds)
//모듈설치면 초기화
// restoreModuleInstArea()
restoreModuleInstArea()
resetStatisticsData()
}, [])
@ -122,19 +125,19 @@ export function useModuleSelection(props) {
setSelectedModules(option) //선택값 저장
//init 데이터에 선택된 모듈 추가
// setModuleSelectionInitParams({
// ...moduleSelectionInitParams,
// moduleTpCd: option.itemTp,
// moduleItemId: option.itemId,
// })
setModuleSelectionInitParams({
...moduleSelectionInitParams,
moduleTpCd: option.itemTp,
moduleItemId: option.itemId,
})
}
const handleChangeSurfaceType = (option) => {
// setModuleSelectionInitParams({
// ...moduleSelectionInitParams,
// illuminationTp: option.clCode,
// illuminationTpNm: option.clCodeNm,
// })
setModuleSelectionInitParams({
...moduleSelectionInitParams,
illuminationTp: option.clCode,
illuminationTpNm: option.clCodeNm,
})
setManagementState({
...managementState,
@ -144,10 +147,10 @@ export function useModuleSelection(props) {
}
const handleChangeWindSpeed = (option) => {
// setModuleSelectionInitParams({
// ...moduleSelectionInitParams,
// stdWindSpeed: option.clCode,
// })
setModuleSelectionInitParams({
...moduleSelectionInitParams,
stdWindSpeed: option.clCode,
})
setManagementState({
...managementState,
@ -157,10 +160,10 @@ export function useModuleSelection(props) {
const handleChangeInstallHeight = (option) => {
setInstallHeight(option)
// setModuleSelectionInitParams({
// ...moduleSelectionInitParams,
// instHt: option,
// })
setModuleSelectionInitParams({
...moduleSelectionInitParams,
instHt: option,
})
setManagementState({
...managementState,
@ -170,10 +173,10 @@ export function useModuleSelection(props) {
const handleChangeVerticalSnowCover = (option) => {
setVerticalSnowCover(option)
// setModuleSelectionInitParams({
// ...moduleSelectionInitParams,
// stdSnowLd: option,
// })
setModuleSelectionInitParams({
...moduleSelectionInitParams,
stdSnowLd: option,
})
setManagementState({
...managementState,
@ -181,23 +184,53 @@ export function useModuleSelection(props) {
})
}
useEffect(() => {
// console.log('installHeight', installHeight)
}, [installHeight])
useEffect(() => {
// console.log('verticalSnowCover', verticalSnowCover)
}, [verticalSnowCover])
//TODO: 설치높이, 기준적설량 debounce 적용해서 추가해야됨
// useEffect(() => {
// getConstructionListData(constructionListParams)
// }, [constructionListParams])
// const getConstructionListData = async (params) => {
// if (params.trestleMkrCd && params.constMthdCd && params.roofBaseCd) {
// const optionsList = await getConstructionList(params)
// console.log('optionsList', optionsList)
// setConstructionList(optionsList.data)
// }
// }
//state 배열에 데이터 추가 함수
// const addRoofTabParams = (key, value, excludeArray = []) => {
// const index = roofTabParams.findIndex((obj) => obj.roofTab === roofTab)
// if (index !== -1) {
// roofTabParams[index][key] = value
// if (excludeArray.length > 0) {
// excludeArray.forEach((exclude) => {
// roofTabParams[index][exclude] = ''
// })
// }
// setRoofTabParams((prev) => [...prev.slice(0, index), roofTabParams[index], ...prev.slice(index + 1)])
// }
// }
return {
// moduleSelectionInitParams,
moduleSelectionInitParams,
selectedModules,
roughnessCodes,
windSpeedCodes,
managementState,
setManagementState,
moduleList,
setSelectedModules,
selectedSurfaceType,
setSelectedSurfaceType,
installHeight,
setInstallHeight,
standardWindSpeed,
setStandardWindSpeed,
verticalSnowCover,
setVerticalSnowCover,
handleChangeModule,
handleChangeSurfaceType,
handleChangeWindSpeed,

View File

@ -1,302 +0,0 @@
import { use, useContext, useEffect, useReducer, useState } from 'react'
import { useCommonCode } from '../common/useCommonCode'
import { useMasterController } from '../common/useMasterController'
import { selectedModuleState } from '@/store/selectedModuleOptions'
import { useRecoilState, useRecoilValue } from 'recoil'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import { popSpinnerState } from '@/store/popupAtom'
const RAFT_BASE_CODE = '203800'
const trestleReducer = (state, action) => {
switch (action.type) {
case 'SET_LENGTH':
case 'SET_RAFT_BASE':
case 'SET_TRESTLE_MAKER':
case 'SET_CONST_MTHD':
case 'SET_ROOF_BASE':
case 'SET_CONSTRUCTION':
case 'SET_TRESTLE_DETAIL':
return {
...action.roof,
}
case 'SET_INITIALIZE':
return {
moduleTpCd: action.roof.module?.itemTp ?? '',
roofMatlCd: action.roof?.roofMatlCd ?? '',
hajebichi: action.roof?.hajebichi ?? 0,
raft: action.roof?.raft ?? null,
trestleMkrCd: action.roof.trestle?.trestleMkrCd ?? null,
constMthdCd: action.roof.trestle?.constMthdCd ?? null,
constTp: action.roof.construction?.constTp ?? null,
roofBaseCd: action.roof.trestle?.roofBaseCd ?? null,
workingWidth: action.roof.workingWidth ?? 0,
lengthBase: action.roof?.length ?? 0,
illuminationTp: action.roof.common?.illuminationTp ?? null,
instHt: action.roof.common?.instHt ?? null,
stdWindSpeed: action.roof.common?.stdWindSpeed ?? null,
stdSnowLd: action.roof.common?.stdSnowLd ?? null,
inclCd: action.roof?.pitch ?? null,
roofPitch: action.roof?.roofPchBase ?? 0,
eavesMargin: action.roof?.eavesMargin ?? null,
ridgeMargin: action.roof?.ridgeMargin ?? null,
kerabaMargin: action.roof?.kerabaMargin ?? null,
}
default:
return state
}
}
export function useModuleTrestle(props) {
const { selectedRoof } = props
const { findCommonCode } = useCommonCode()
const [raftBaseList, setRaftBaseList] = useState([])
const [trestleList, setTrestleList] = useState([])
const [constMthdList, setConstMthdList] = useState([])
const [roofBaseList, setRoofBaseList] = useState([])
const [constructionList, setConstructionList] = useState([])
const { getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController()
const [lengthBase, setLengthBase] = useState(0)
const [hajebichi, setHajebichi] = useState(0)
const [cvrYn, setCvrYn] = useState('N')
const [cvrChecked, setCvrChecked] = useState(false)
const [snowGdPossYn, setSnowGdPossYn] = useState('N')
const [snowGdChecked, setSnowGdChecked] = useState(false)
const [eavesMargin, setEavesMargin] = useState(0)
const [ridgeMargin, setRidgeMargin] = useState(0)
const [kerabaMargin, setKerabaMargin] = useState(0)
const [trestleState, dispatch] = useReducer(trestleReducer, null)
const [trestleDetail, setTrestleDetail] = useState(null)
const [popSpinnerStore, setPopSpinnerStore] = useRecoilState(popSpinnerState)
useEffect(() => {
const raftCodeList = findCommonCode(RAFT_BASE_CODE)
setRaftBaseList(raftCodeList)
setTrestleList([])
setConstMthdList([])
setRoofBaseList([])
setConstructionList([])
// setEavesMargin(selectedRoof?.addRoof?.eavesMargin ?? 0)
// setRidgeMargin(selectedRoof?.addRoof?.ridgeMargin ?? 0)
// setKerabaMargin(selectedRoof?.addRoof?.kerabaMargin ?? 0)
setHajebichi(selectedRoof?.hajebichi ?? 0)
setEavesMargin(selectedRoof?.eavesMargin ?? 0)
setRidgeMargin(selectedRoof?.ridgeMargin ?? 0)
setKerabaMargin(selectedRoof?.kerabaMargin ?? 0)
setLengthBase(Math.round(selectedRoof?.length ?? 0))
setCvrYn(selectedRoof?.construction?.cvrYn ?? 'N')
setCvrChecked(selectedRoof?.construction?.cvrChecked ?? false)
setSnowGdPossYn(selectedRoof?.construction?.snowGdPossYn ?? 'N')
setSnowGdChecked(selectedRoof?.construction?.snowGdChecked ?? false)
setTrestleDetail(selectedRoof?.trestleDetail)
}, [selectedRoof])
useEffect(() => {
if (trestleState) {
handleSetTrestleList()
if (!trestleState?.trestleMkrCd) {
setConstMthdList([])
setRoofBaseList([])
setConstructionList([])
setTrestleDetail(null)
setEavesMargin(0)
setRidgeMargin(0)
setKerabaMargin(0)
return
}
handleSetConstMthdList()
if (!trestleState?.constMthdCd) {
setRoofBaseList([])
setConstructionList([])
setTrestleDetail(null)
setEavesMargin(0)
setRidgeMargin(0)
setKerabaMargin(0)
return
}
handleSetRoofBaseList()
if (!trestleState?.roofBaseCd) {
setConstructionList([])
setTrestleDetail(null)
setEavesMargin(0)
setRidgeMargin(0)
setKerabaMargin(0)
return
}
handleSetConstructionList()
if (!trestleState?.constTp) {
setTrestleDetail(null)
setEavesMargin(0)
setRidgeMargin(0)
setKerabaMargin(0)
return
}
if (!trestleState?.eavesMargin) {
handleSetTrestleDetailData()
}
}
}, [trestleState])
const handleSetTrestleList = () => {
setPopSpinnerStore(true)
getTrestleList({
moduleTpCd: trestleState?.moduleTpCd ?? '',
roofMatlCd: trestleState?.roofMatlCd ?? '',
raftBaseCd: trestleState?.raft ?? '',
})
.then((res) => {
if (res?.data) setTrestleList(res.data)
setPopSpinnerStore(false)
})
.catch((e) => {
setPopSpinnerStore(false)
})
}
const handleSetConstMthdList = () => {
setPopSpinnerStore(true)
getTrestleList({
moduleTpCd: trestleState?.moduleTpCd ?? '',
roofMatlCd: trestleState?.roofMatlCd ?? '',
raftBaseCd: trestleState?.raft ?? '',
trestleMkrCd: trestleState?.trestleMkrCd ?? '',
})
.then((res) => {
if (res?.data) setConstMthdList(res.data)
setPopSpinnerStore(false)
})
.catch((e) => {
setPopSpinnerStore(false)
})
}
const handleSetRoofBaseList = () => {
setPopSpinnerStore(true)
getTrestleList({
moduleTpCd: trestleState?.moduleTpCd ?? '',
roofMatlCd: trestleState?.roofMatlCd ?? '',
raftBaseCd: trestleState?.raft ?? '',
trestleMkrCd: trestleState?.trestleMkrCd ?? '',
constMthdCd: trestleState?.constMthdCd ?? '',
})
.then((res) => {
if (res?.data) setRoofBaseList(res.data)
setPopSpinnerStore(false)
})
.catch((e) => {
setPopSpinnerStore(false)
})
}
const handleSetConstructionList = () => {
setPopSpinnerStore(true)
getConstructionList({
moduleTpCd: trestleState?.moduleTpCd ?? '',
roofMatlCd: trestleState?.roofMatlCd ?? '',
trestleMkrCd: trestleState?.trestleMkrCd ?? '',
constMthdCd: trestleState?.constMthdCd ?? '',
roofBaseCd: trestleState?.roofBaseCd ?? '',
illuminationTp: trestleState.illuminationTp ?? '',
instHt: trestleState.instHt ?? '',
stdWindSpeed: trestleState.stdWindSpeed ?? '',
stdSnowLd: trestleState.stdSnowLd ?? '',
inclCd: trestleState.inclCd ?? '',
raftBaseCd: trestleState.raft ?? '',
roofPitch: trestleState.hajebichi ? trestleState.hajebichi : (trestleState.roofPitch ?? ''),
})
.then((res) => {
if (res?.data) setConstructionList(res.data)
setPopSpinnerStore(false)
})
.catch((e) => {
setPopSpinnerStore(false)
})
}
const handleSetTrestleDetailData = () => {
setPopSpinnerStore(true)
getTrestleDetailList([
{
moduleTpCd: trestleState.moduleTpCd ?? '',
roofMatlCd: trestleState.roofMatlCd ?? '',
trestleMkrCd: trestleState.trestleMkrCd ?? '',
constMthdCd: trestleState.constMthdCd ?? '',
roofBaseCd: trestleState.roofBaseCd ?? '',
illuminationTp: trestleState.illuminationTp ?? '',
instHt: trestleState.instHt ?? '',
stdWindSpeed: trestleState.stdWindSpeed ?? '',
stdSnowLd: trestleState.stdSnowLd ?? '',
inclCd: trestleState.inclCd ?? '',
constTp: trestleState.constTp ?? '',
mixMatlNo: trestleState.mixMatlNo ?? '',
roofPitch: trestleState.hajebichi ? trestleState.hajebichi : (trestleState.roofPitch ?? ''),
// workingWidth: trestleState.length ?? '',
workingWidth: lengthBase ?? '',
},
])
.then((res) => {
if (res.length > 0) {
if (!res[0].data) return
setEavesMargin(res[0].data.eaveIntvl)
setRidgeMargin(res[0].data.ridgeIntvl)
setKerabaMargin(res[0].data.kerabaIntvl)
setTrestleDetail(res[0].data)
// dispatch({
// type: 'SET_TRESTLE_DETAIL',
// roof: {
// ...trestleState,
// eavesMargin: res[0].data.eaveIntvl,
// ridgeMargin: res[0].data.ridgeIntvl,
// kerabaMargin: res[0].data.kerabaIntvl,
// },
// })
}
setPopSpinnerStore(false)
})
.catch((e) => {
setPopSpinnerStore(false)
})
}
return {
trestleState,
trestleDetail,
dispatch,
raftBaseList,
trestleList,
constMthdList,
roofBaseList,
constructionList,
handleSetTrestleList,
handleSetConstMthdList,
handleSetRoofBaseList,
handleSetConstructionList,
handleSetTrestleDetailData,
lengthBase,
setLengthBase,
hajebichi,
setHajebichi,
cvrYn,
cvrChecked,
snowGdPossYn,
snowGdChecked,
eavesMargin,
ridgeMargin,
kerabaMargin,
setEavesMargin,
setRidgeMargin,
setKerabaMargin,
setCvrYn,
setCvrChecked,
setSnowGdPossYn,
setSnowGdChecked,
}
}

Some files were not shown because too many files have changed in this diff Show More