Merge branch 'dev' into dev-yj-layoutSetup

# Conflicts:
#	src/hooks/module/useModuleBasicSetting.js
#	src/locales/ja.json
#	src/locales/ko.json
This commit is contained in:
yjnoh 2025-03-19 13:38:16 +09:00
commit 8ea6f43ddb
17 changed files with 60 additions and 24 deletions

10
ecosystem.config.js Normal file
View File

@ -0,0 +1,10 @@
module.exports = {
apps: [
{
name: 'qcast-front-production',
script: 'npm run start',
instance: 2,
exec_mode: 'cluster',
},
],
}

View File

@ -5,8 +5,9 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start -p 3000",
"start:dev": "next start -p 3001",
"start:cluster1": "next start -p 5000",
"start:cluster2": "next start -p 5001",
"start:dev": "next start -p 5010",
"lint": "next lint",
"serve": "node server.js"
},

View File

@ -87,7 +87,7 @@ export default function QSelectBox({
<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

@ -271,7 +271,11 @@ 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')}</td>
<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>
</tr>
<tr>
<th>

View File

@ -301,7 +301,6 @@ export default function Stuff() {
} else if (stuffSearchParams?.code === 'E') {
stuffSearchParams.startRow = (stuffSearch.pageNo - 1) * stuffSearchParams.pageSize + 1
stuffSearchParams.endRow = stuffSearchParams.pageNo * stuffSearchParams.pageSize
stuffSearchParams.schSortType = defaultSortType
stuffSearchParams.pageNo = stuffSearchParams.pageNo
if (!stuffSearchParams.saleStoreId) {

View File

@ -574,6 +574,7 @@ export function useModuleBasicSetting(tabNum) {
/**
* 스냅기능
*/
let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 50 : 50
let sideSnapDistance = 15
let trestleSnapDistance = 15

View File

@ -84,7 +84,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
// innerLines가 있을경우 삭제
const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
if (roofs.length === 0) {
swalFire({ text: '지붕형상이 없습니다.' })
swalFire({ text: getMessage('roof.line.not.found') })
closePopup(id)
return
}

View File

@ -52,7 +52,7 @@ export function useEavesGableEdit(id) {
useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (!outerLineFix || outerLines.length === 0) {
swalFire({ text: '외벽선이 없습니다.' })
swalFire({ text: getMessage('wall.line.not.found') })
closePopup(id)
}
}, [])

View File

@ -1,6 +1,6 @@
import { useRecoilState, useRecoilValue, useResetRecoilState, useSetRecoilState } from 'recoil'
import { canvasState, currentAngleTypeSelector, currentMenuState, currentObjectState } from '@/store/canvasAtom'
import { useEffect, useRef, useState } from 'react'
import { useContext, useEffect, useRef, useState } from 'react'
import { useAxios } from '@/hooks/useAxios'
import { useSwal } from '@/hooks/useSwal'
import { usePolygon } from '@/hooks/usePolygon'
@ -26,6 +26,7 @@ import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { QcastContext } from '@/app/QcastProvider'
export function useRoofAllocationSetting(id) {
const canvas = useRecoilValue(canvasState)
@ -49,7 +50,7 @@ export function useRoofAllocationSetting(id) {
const { get, post } = useAxios(globalLocaleState)
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const { setIsGlobalLoading } = useContext(QcastContext)
const { setSurfaceShapePattern } = useRoofFn()
const [moduleSelectionData, setModuleSelectionData] = useRecoilState(moduleSelectionDataState)
@ -200,6 +201,7 @@ export function useRoofAllocationSetting(id) {
*/
const basicSettingSave = async () => {
try {
setIsGlobalLoading(true)
const patternData = {
objectNo: correntObjectNo,
planNo: Number(basicSetting.planNo),
@ -222,6 +224,7 @@ export function useRoofAllocationSetting(id) {
await post({ url: `/api/canvas-management/roof-allocation-settings`, data: patternData }).then((res) => {
swalFire({ text: getMessage(res.returnMessage) })
setIsGlobalLoading(false)
})
//Recoil 설정
@ -270,8 +273,6 @@ export function useRoofAllocationSetting(id) {
* 선택한 지붕재로 할당
*/
const handleSave = () => {
basicSettingSave()
/**
* 모두 actualSize 있으면 바로 적용 없으면 actualSize 설정
*/
@ -280,6 +281,7 @@ export function useRoofAllocationSetting(id) {
} else {
apply()
resetPoints()
basicSettingSave()
}
}
@ -287,7 +289,6 @@ export function useRoofAllocationSetting(id) {
* 지붕재 오른쪽 마우스 클릭 단일로 지붕재 변경 필요한 경우
*/
const handleSaveContext = () => {
basicSettingSave()
const newRoofList = currentRoofList.map((roof, idx) => {
return { ...roof, index: idx, raft: roof.raft ? roof.raft : roof.raftBaseCd }
})
@ -304,6 +305,7 @@ export function useRoofAllocationSetting(id) {
drawDirectionArrow(currentObject)
modifyModuleSelectionData()
closeAll()
basicSettingSave()
}
/**
@ -361,6 +363,7 @@ export function useRoofAllocationSetting(id) {
splitPolygonWithLines(roofBase)
}
} catch (e) {
console.log(e)
return
}

View File

@ -51,7 +51,7 @@ export function useRoofShapePassivitySetting(id) {
useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (!outerLineFix || outerLines.length === 0) {
swalFire({ text: '외벽선이 없습니다.' })
swalFire({ text: getMessage('wall.line.not.found') })
closePopup(id)
return
}

View File

@ -191,7 +191,7 @@ export function useRoofShapeSetting(id) {
let direction
if (outerLines.length < 2) {
swalFire({ text: '외벽선이 없습니다.', icon: 'error' })
swalFire({ text: getMessage('wall.line.not.found') })
return
}

View File

@ -60,7 +60,7 @@ export function useWallLineOffsetSetting(id) {
useEffect(() => {
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine')
if (outerLines.length === 0) {
swalFire({ text: '외벽선이 없습니다.' })
swalFire({ text: getMessage('wall.line.not.found') })
closePopup(id)
return
}

View File

@ -767,7 +767,7 @@ export const usePolygon = () => {
obj.type === 'QLine' &&
obj.attributes?.type !== 'pitchSizeLine' &&
obj.attributes?.roofId === polygon.id &&
(innerLineTypes.includes(obj.name) || !obj.name),
innerLineTypes.includes(obj.name),
)
innerLines = [...polygon.innerLines]

View File

@ -37,7 +37,7 @@
"modal.roof.shape.setting.patten.a": "Aパターン",
"modal.roof.shape.setting.patten.b": "Bパターン",
"modal.roof.shape.setting.side": "別に設定",
"plan.menu.roof.cover": "屋根作図",
"plan.menu.roof.cover": "伏せ図入力",
"plan.menu.roof.cover.outline.drawing": "外壁線を描く",
"plan.menu.roof.cover.roof.shape.setting": "屋根形状の設定",
"plan.menu.roof.cover.roof.shape.passivity.setting": "屋根形状の手動設定",
@ -72,7 +72,7 @@
"common.setting.rollback": "前に戻る",
"modal.cover.outline.remove": "外壁の取り外し",
"modal.cover.outline.select.move": "外壁選択の移動",
"plan.menu.placement.surface": "配置面",
"plan.menu.placement.surface": "実測値入力",
"plan.menu.placement.surface.slope.setting": "傾斜設定",
"plan.menu.placement.surface.drawing": "配置面の描画",
"modal.placement.surface.drawing.straight.line": "直線",
@ -558,7 +558,7 @@
"board.faq.title": "FAQ",
"board.faq.sub.title": "FAQリスト",
"board.archive.title": "各種資料ダウンロード",
"board.archive.sub.title": "見積書一覧",
"board.archive.sub.title": "掲載資料一覧",
"board.list.header.rownum": "番号",
"board.list.header.title": "タイトル",
"board.list.header.regDt": "登録日",
@ -1035,5 +1035,8 @@
"outerLine.property.fix": "外壁線の属性設定 を完了しますか?",
"outerLine.property.close": "外壁線の属性設定 を終了しますか?",
"want.to.complete.auxiliary.creation": "보補助線の作成を完了しますか?",
"module.layout.setup.has.zero.value": "モジュールの列、行を入力してください."
"module.layout.setup.has.zero.value": "モジュールの列、行を入力してください.",
"modal.placement.initial.setting.plan.drawing.only.number": "(※数字は[半角]入力のみ可能です。)",
"wall.line.not.found": "外壁がありません",
"roof.line.not.found": "屋根形状がありません"
}

View File

@ -1035,5 +1035,8 @@
"outerLine.property.fix": "외벽선 속성 설정을 완료하시겠습니까?",
"outerLine.property.close": "외벽선 속성 설정을 종료하시겠습니까?",
"want.to.complete.auxiliary.creation": "보조선 작성을 완료하시겠습니까?",
"module.layout.setup.has.zero.value": "모듈의 열, 행을 입력해 주세요."
"module.layout.setup.has.zero.value": "모듈의 열, 행을 입력해 주세요.",
"modal.placement.initial.setting.plan.drawing.only.number": "(※ 숫자는 [반각]입력만 가능합니다.)",
"wall.line.not.found": "외벽선이 없습니다.",
"roof.line.not.found": "지붕형상이 없습니다."
}

View File

@ -518,14 +518,23 @@ export const sortedPointLessEightPoint = (points) => {
*/
// 직선의 방정식.
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
export function isPointOnLine(line, point) {
const a = line.y2 - line.y1
export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }) {
/*const a = line.y2 - line.y1
const b = line.x1 - line.x2
const c = line.x2 * line.y1 - line.x1 * line.y2
const result = Math.abs(a * point.x + b * point.y + c) / 100
// 점이 선 위에 있는지 확인
return result <= 10
return result <= 10*/
// 직선 방정식 만족 여부 확인
const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1)
if (Math.abs(crossProduct) > 5) return false // 작은 오차 허용
// 점이 선분의 범위 내에 있는지 확인
const withinXRange = Math.min(x1, x2) <= x && x <= Math.max(x1, x2)
const withinYRange = Math.min(y1, y2) <= y && y <= Math.max(y1, y2)
return withinXRange && withinYRange
}
/**
* 점과 가까운 line 찾기

View File

@ -305,6 +305,9 @@ export function removeDuplicatePolygons(polygons) {
}
export const isSamePoint = (a, b) => {
if (!a || !b) {
return false
}
return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2
}