Merge pull request 'dev' (#549) from dev into dev-deploy

Reviewed-on: #549
This commit is contained in:
ysCha 2026-01-05 19:02:40 +09:00
commit f686789b6a
6 changed files with 149 additions and 7558 deletions

View File

@ -223,6 +223,7 @@ export const SAVE_KEY = [
'skeleton', 'skeleton',
'viewportTransform', 'viewportTransform',
'outerLineFix', 'outerLineFix',
'adjustRoofLines',
] ]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -18,8 +18,9 @@ import Config from '@/config/config.export'
export default function MainPage() { export default function MainPage() {
const [sessionState, setSessionState] = useRecoilState(sessionStore) const [sessionState, setSessionState] = useRecoilState(sessionStore)
const [chagePasswordPopOpen, setChagePasswordPopOpen] = useState(false) const [changePasswordPopOpen, setChangePasswordPopOpen] = useState(false)
//
const [isSessionLoaded, setIsSessionLoaded] = useState(false)
const router = useRouter() const router = useRouter()
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -52,6 +53,14 @@ export default function MainPage() {
} }
} }
useEffect(() => {
if (isObjectNotEmpty(sessionState)) {
if (sessionState?.pwdInitYn !== 'Y') {
setChangePasswordPopOpen(true)
}
}
}, [sessionState])
// //
const handleOnChangeRadio = (e) => { const handleOnChangeRadio = (e) => {
setSearchRadioType(e.target.value) setSearchRadioType(e.target.value)
@ -77,7 +86,7 @@ export default function MainPage() {
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(sessionState)) { if (isObjectNotEmpty(sessionState)) {
if (sessionState?.pwdInitYn !== 'Y') { if (sessionState?.pwdInitYn !== 'Y') {
setChagePasswordPopOpen(true) setChangePasswordPopOpen(true)
} }
} }
}, [sessionState]) }, [sessionState])
@ -86,10 +95,25 @@ export default function MainPage() {
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [modalNoticeNo, setModalNoticeNo] = useState('') const [modalNoticeNo, setModalNoticeNo] = useState('')
useEffect(() => {
if (isObjectNotEmpty(sessionState)) {
if (sessionState?.pwdInitYn !== 'Y') {
setChangePasswordPopOpen(true)
} else {
// pwdInitYn 'Y' (false)
setChangePasswordPopOpen(false)
}
}
}, [sessionState])
//if (!isSessionLoaded) return null
return ( return (
<> <>
{open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />} {open && <BoardDetailModal noticeNo={modalNoticeNo} setOpen={setOpen} />}
{(!chagePasswordPopOpen && ( {changePasswordPopOpen ? (
<ChangePasswordPop setChangePasswordPopOpen={setChangePasswordPopOpen} />
) : (
<> <>
<div className="background-bord"></div> <div className="background-bord"></div>
<div className="main-contents"> <div className="main-contents">
@ -131,11 +155,8 @@ export default function MainPage() {
<MainContents setFaqOpen={setOpen} setFaqModalNoticeNo={setModalNoticeNo} /> <MainContents setFaqOpen={setOpen} setFaqModalNoticeNo={setModalNoticeNo} />
</div> </div>
</> </>
)) || (
<>
<ChangePasswordPop setChagePasswordPopOpen={setChagePasswordPopOpen} />
</>
)} )}
</> </>
) )
} }

View File

@ -36,6 +36,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.separatePolygon = [] this.separatePolygon = []
this.toFixed = options.toFixed ?? 1 this.toFixed = options.toFixed ?? 1
this.baseLines = [] this.baseLines = []
this.adjustRoofLines = []
// this.colorLines = [] // this.colorLines = []
// 소수점 전부 제거 // 소수점 전부 제거
@ -134,7 +135,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.setCoords() this.setCoords()
}) })
this.on('modified', (e) => { this.on('modified', () => {
this.initLines() this.initLines()
this.addLengthText() this.addLengthText()
this.setCoords() this.setCoords()
@ -223,7 +224,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
calculateDegree() { calculateDegree() {
const degrees = [] const degrees = []
// polygon.lines를 순회하며 각도를 구해 출력 // polygon.lines를 순회하며 각도를 구해 출력
this.lines.forEach((line, idx) => { this.lines.forEach((line) => {
const dx = line.x2 - line.x1 const dx = line.x2 - line.x1
const dy = line.y2 - line.y1 const dy = line.y2 - line.y1
const rad = Math.atan2(dy, dx) const rad = Math.atan2(dy, dx)
@ -258,6 +259,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
) )
.forEach((obj) => this.canvas.remove(obj)) .forEach((obj) => this.canvas.remove(obj))
this.innerLines = [] this.innerLines = []
this.adjustRoofLines = []
this.canvas.renderAll() this.canvas.renderAll()
let textMode = 'plane' let textMode = 'plane'
@ -339,18 +341,17 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
if (types.every((type) => type === LINE_TYPE.WALLLINE.EAVES)) { if (types.every((type) => type === LINE_TYPE.WALLLINE.EAVES)) {
// 용마루 -- straight-skeleton // 용마루 -- straight-skeleton
console.log('용마루 지붕') // console.log('용마루 지붕')
///drawRidgeRoof(this.id, this.canvas, textMode)
drawSkeletonRidgeRoof(this.id, this.canvas, textMode) drawSkeletonRidgeRoof(this.id, this.canvas, textMode)
} else if (isGableRoof(types)) { } else if (isGableRoof(types)) {
// A형, B형 박공 지붕 // A형, B형 박공 지붕
console.log('패턴 지붕') // console.log('패턴 지붕')
drawGableRoof(this.id, this.canvas, textMode) drawGableRoof(this.id, this.canvas, textMode)
} else if (isShedRoof(types, this.lines)) { } else if (isShedRoof(types, this.lines)) {
console.log('한쪽흐름 지붕') // console.log('한쪽흐름 지붕')
drawShedRoof(this.id, this.canvas, textMode) drawShedRoof(this.id, this.canvas, textMode)
} else { } else {
console.log('변별로 설정') // console.log('변별로 설정')
drawRoofByAttribute(this.id, this.canvas, textMode) drawRoofByAttribute(this.id, this.canvas, textMode)
} }
}, },
@ -404,7 +405,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
const degree = Big(Math.atan2(dy.toNumber(), dx.toNumber())).times(180).div(Math.PI).toNumber() const degree = Big(Math.atan2(dy.toNumber(), dx.toNumber())).times(180).div(Math.PI).toNumber()
// Create new text object if it doesn't exist // Create a new text object if it doesn't exist
const text = new fabric.Text(length.toString(), { const text = new fabric.Text(length.toString(), {
left: midPoint.x, left: midPoint.x,
top: midPoint.y, top: midPoint.y,

View File

@ -114,7 +114,7 @@ export default function ChangePasswordPop(props) {
const result = { ...sessionState, pwdInitYn: 'Y' } const result = { ...sessionState, pwdInitYn: 'Y' }
setSession(result) setSession(result)
setSessionState(result) setSessionState(result)
props.setChagePasswordPopOpen(false) props.setChangePasswordPopOpen(false)
await login() await login()
}, },
}) })

View File

@ -30,7 +30,6 @@ import { QcastContext } from '@/app/QcastProvider'
import { usePlan } from '@/hooks/usePlan' import { usePlan } from '@/hooks/usePlan'
import { roofsState } from '@/store/roofAtom' import { roofsState } from '@/store/roofAtom'
import { useText } from '@/hooks/useText' import { useText } from '@/hooks/useText'
import { processEaveHelpLines } from '@/util/skeleton-utils'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
export function useRoofAllocationSetting(id) { export function useRoofAllocationSetting(id) {
@ -114,9 +113,9 @@ export function useRoofAllocationSetting(id) {
*/ */
const fetchBasicSettings = async (planNo) => { const fetchBasicSettings = async (planNo) => {
try { try {
const response = await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` }); const response = await get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${correntObjectNo}/${planNo}` })
let roofsArray = []; let roofsArray = []
// API에서 데이터를 성공적으로 가져온 경우 // API에서 데이터를 성공적으로 가져온 경우
if (response && response.length > 0) { if (response && response.length > 0) {
@ -133,15 +132,15 @@ export function useRoofAllocationSetting(id) {
roofPitch: item.roofPitch, roofPitch: item.roofPitch,
roofAngle: item.roofAngle, roofAngle: item.roofAngle,
selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정 selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정
index: index index: index,
})); }))
} }
// API에서 데이터가 없고 기존 roofList가 있는 경우 // API에서 데이터가 없고 기존 roofList가 있는 경우
else if (roofList && roofList.length > 0) { else if (roofList && roofList.length > 0) {
roofsArray = roofList.map((roof, index) => ({ roofsArray = roofList.map((roof, index) => ({
...roof, ...roof,
selected: index === 0 // 첫 번째 항목을 기본 선택으로 설정 selected: index === 0, // 첫 번째 항목을 기본 선택으로 설정
})); }))
} }
// 둘 다 없는 경우 기본값 설정 // 둘 다 없는 경우 기본값 설정
else { else {
@ -156,64 +155,62 @@ export function useRoofAllocationSetting(id) {
roofHajebichi: 0, roofHajebichi: 0,
roofGap: 'HEI_455', roofGap: 'HEI_455',
roofLayout: 'P', roofLayout: 'P',
roofPitch: 4, roofPitch: 4,
roofAngle: 21.8, roofAngle: 21.8,
}, },
] ]
}
/**
* 데이터 설정
*/
const selectRoofs = []
for (let i = 0; i < roofsArray.length; i++) {
roofMaterials?.map((material) => {
if (material.roofMatlCd === roofsArray[i].roofMatlCd) {
selectRoofs.push({
...material,
selected: roofsArray[i].roofApply,
index: roofsArray[i].roofSeq,
id: roofsArray[i].roofMatlCd,
width: roofsArray[i].roofWidth,
length: roofsArray[i].roofHeight,
hajebichi: roofsArray[i].roofHajebichi,
raft: roofsArray[i].roofGap,
layout: roofsArray[i].roofLayout,
pitch: roofsArray[i].roofPitch,
angle: roofsArray[i].roofAngle,
})
} }
/**
* 데이터 설정
*/
const selectRoofs = []
for (let i = 0; i < roofsArray.length; i++) {
roofMaterials?.map((material) => {
if (material.roofMatlCd === roofsArray[i].roofMatlCd) {
selectRoofs.push({
...material,
selected: roofsArray[i].roofApply,
index: roofsArray[i].roofSeq,
id: roofsArray[i].roofMatlCd,
width: roofsArray[i].roofWidth,
length: roofsArray[i].roofHeight,
hajebichi: roofsArray[i].roofHajebichi,
raft: roofsArray[i].roofGap,
layout: roofsArray[i].roofLayout,
pitch: roofsArray[i].roofPitch,
angle: roofsArray[i].roofAngle,
})
}
})
}
const firstRes = Array.isArray(res) && res.length > 0 ? res[0] : null
setBasicSetting({
...basicSetting,
planNo: firstRes?.planNo ?? planNo,
roofSizeSet: firstRes?.roofSizeSet ?? 0,
roofAngleSet: firstRes?.roofAngleSet ?? 0,
roofsData: roofsArray,
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
}) })
}
setBasicInfo({ const firstRes = Array.isArray(res) && res.length > 0 ? res[0] : null
planNo: '' + (firstRes?.planNo ?? planNo),
roofSizeSet: '' + (firstRes?.roofSizeSet ?? 0),
roofAngleSet: '' + (firstRes?.roofAngleSet ?? 0),
})
// 데이터 동기화: 렌더링용 필드 기본값 보정
const normalizedRoofs = selectRoofs.map((roof) => ({
...roof,
width: roof.width ?? '',
length: roof.length ?? '',
hajebichi: roof.hajebichi ?? '',
pitch: roof.pitch ?? '',
angle: roof.angle ?? '',
}))
setCurrentRoofList(normalizedRoofs)
setBasicSetting({
...basicSetting,
planNo: firstRes?.planNo ?? planNo,
roofSizeSet: firstRes?.roofSizeSet ?? 0,
roofAngleSet: firstRes?.roofAngleSet ?? 0,
roofsData: roofsArray,
selectedRoofMaterial: selectRoofs.find((roof) => roof.selected),
})
setBasicInfo({
planNo: '' + (firstRes?.planNo ?? planNo),
roofSizeSet: '' + (firstRes?.roofSizeSet ?? 0),
roofAngleSet: '' + (firstRes?.roofAngleSet ?? 0),
})
// 데이터 동기화: 렌더링용 필드 기본값 보정
const normalizedRoofs = selectRoofs.map((roof) => ({
...roof,
width: roof.width ?? '',
length: roof.length ?? '',
hajebichi: roof.hajebichi ?? '',
pitch: roof.pitch ?? '',
angle: roof.angle ?? '',
}))
setCurrentRoofList(normalizedRoofs)
} catch (error) { } catch (error) {
console.error('Data fetching error:', error) console.error('Data fetching error:', error)
} }
@ -467,7 +464,6 @@ export function useRoofAllocationSetting(id) {
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
roofBases.forEach((roofBase) => { roofBases.forEach((roofBase) => {
try { try {
const roofEaveHelpLines = canvas.getObjects().filter((obj) => obj.lineName === 'eaveHelpLine' && obj.roofId === roofBase.id) const roofEaveHelpLines = canvas.getObjects().filter((obj) => obj.lineName === 'eaveHelpLine' && obj.roofId === roofBase.id)
if (roofEaveHelpLines.length > 0) { if (roofEaveHelpLines.length > 0) {
if (roofBase.lines) { if (roofBase.lines) {
@ -534,6 +530,34 @@ export function useRoofAllocationSetting(id) {
} }
} }
if (roofBase.adjustRoofLines.length > 0) {
const newRoofLines = []
let lineIndex = 1
roofBase.lines.forEach((line, idx) => {
const adjustLines = roofBase.adjustRoofLines.filter((adjustLine) => adjustLine.roofIdx === line.idx)
if (adjustLines.length === 0) {
line.idx = lineIndex
newRoofLines.push(line)
lineIndex++
} else {
adjustLines.forEach(({ point, roofIdx }) => {
const newLine = new QLine(point, {
idx: lineIndex,
selectable: false,
parentId: line.parentId,
parent: line.parent,
fontSize: line.fontSize,
stroke: line.stroke,
strokeWidth: line.strokeWidth,
attributes: line.attributes,
})
newRoofLines.push(newLine)
lineIndex++
})
}
})
roofBase.lines = newRoofLines
}
if (roofBase.separatePolygon.length > 0) { if (roofBase.separatePolygon.length > 0) {
splitPolygonWithSeparate(roofBase.separatePolygon) splitPolygonWithSeparate(roofBase.separatePolygon)
} else { } else {

File diff suppressed because it is too large Load Diff