Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2025-02-20 17:45:28 +09:00
commit 1679351fc1
9 changed files with 173 additions and 38 deletions

View File

@ -37,6 +37,8 @@
"react-responsive-modal": "^6.4.2", "react-responsive-modal": "^6.4.2",
"react-select": "^5.8.1", "react-select": "^5.8.1",
"recoil": "^0.7.7", "recoil": "^0.7.7",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"sweetalert2": "^11.14.1", "sweetalert2": "^11.14.1",
"sweetalert2-react-content": "^5.0.7", "sweetalert2-react-content": "^5.0.7",
"swr": "^2.3.0", "swr": "^2.3.0",

BIN
qcast3.database.sqlite Normal file

Binary file not shown.

View File

@ -384,7 +384,12 @@ export default function CircuitTrestleSetting({ id }) {
obj.pcsItemId = null obj.pcsItemId = null
obj.circuitNumber = null obj.circuitNumber = null
}) })
setSelectedModels(JSON.parse(JSON.stringify(selectedModels)).map((model) => (model.isUsed = false))) setSelectedModels(
JSON.parse(JSON.stringify(selectedModels)).map((model) => {
model.isUsed = false
return model
}),
)
if (allocationType === ALLOCATION_TYPE.PASSIVITY) { if (allocationType === ALLOCATION_TYPE.PASSIVITY) {
setAllocationType(ALLOCATION_TYPE.AUTO) setAllocationType(ALLOCATION_TYPE.AUTO)

View File

@ -364,7 +364,7 @@ export default function StepUp(props) {
// console.log('🚀 ~ handleRowClick ~ selectedData:', selectedData) // console.log('🚀 ~ handleRowClick ~ selectedData:', selectedData)
// PCS 2 PCS // PCS 2 PCS
if (stepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) { if (tempStepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) {
// //
const params = { const params = {
...props.getOptYn(), // Y/N ...props.getOptYn(), // Y/N
@ -442,29 +442,30 @@ export default function StepUp(props) {
roofSurface.moduleList.forEach((module) => { roofSurface.moduleList.forEach((module) => {
const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0] const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0]
if (module.circuit === '') return if (module.circuit !== '' && module.circuit) {
const moduleCircuitText = new fabric.Text(module.circuit, { const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2, left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2, top: targetModule.top + targetModule.height / 2,
fontFamily: circuitNumberText.fontFamily.value, fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal', fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value, fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value, fill: circuitNumberText.fontColor.value,
width: targetModule.width, width: targetModule.width,
height: targetModule.height, height: targetModule.height,
textAlign: 'center', textAlign: 'center',
originX: 'center', originX: 'center',
originY: 'center', originY: 'center',
name: 'circuitNumber', name: 'circuitNumber',
parentId: targetModule.id, parentId: targetModule.id,
circuitInfo: module.pcsItemId, circuitInfo: module.pcsItemId,
visible: isDisplayCircuitNumber, visible: isDisplayCircuitNumber,
}) })
targetModule.circuit = moduleCircuitText targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText) canvas.add(moduleCircuitText)
}
}) })
}) })

View File

@ -24,7 +24,6 @@ export const ROOF_MATERIAL_LAYOUT = {
export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) { export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) {
const [showSizeGuideModal, setShowSizeGuidModal] = useState(false) const [showSizeGuideModal, setShowSizeGuidModal] = useState(false)
const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false) const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false)
const { closePopup } = usePopup()
const { getMessage } = useMessage() const { getMessage } = useMessage()
const roofMaterials = useRecoilValue(roofMaterialsAtom) const roofMaterials = useRecoilValue(roofMaterialsAtom)
@ -221,9 +220,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla
<div className={`modal-pop-wrap ll mount`}> <div className={`modal-pop-wrap ll mount`}>
<div className="modal-head modal-handle"> <div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.initial.setting')}</h1> <h1 className="title">{getMessage('plan.menu.placement.surface.initial.setting')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div> </div>
<div className="modal-body"> <div className="modal-body">
<div className="left-bar modal-handle"></div> <div className="left-bar modal-handle"></div>

View File

@ -5,6 +5,8 @@ import { useSwal } from '@/hooks/useSwal'
import { useAxios } from '../useAxios' import { useAxios } from '../useAxios'
import { currentCanvasPlanState } from '@/store/canvasAtom' import { currentCanvasPlanState } from '@/store/canvasAtom'
import { useCanvas } from '@/hooks/useCanvas' import { useCanvas } from '@/hooks/useCanvas'
import { deleteBackGroundImage, setBackGroundImage } from '@/lib/imageActions'
import { settingModalFirstOptionsState } from '@/store/settingAtom'
/** /**
* 배경 이미지 관리 * 배경 이미지 관리
@ -19,6 +21,7 @@ export function useRefFiles() {
const [currentBgImage, setCurrentBgImage] = useState(null) const [currentBgImage, setCurrentBgImage] = useState(null)
const queryRef = useRef(null) const queryRef = useRef(null)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState)
const { handleBackImageLoadToCanvas } = useCanvas() const { handleBackImageLoadToCanvas } = useCanvas()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { get, post } = useAxios() const { get, post } = useAxios()
@ -72,13 +75,17 @@ export function useRefFiles() {
/** /**
* 파일 삭제 * 파일 삭제
*/ */
const handleFileDelete = () => { const handleFileDelete = async () => {
swalFire({ swalFire({
text: '삭제하시겠습니까?', text: '삭제하시겠습니까?',
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: async () => {
setRefImage(null) setRefImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null })) setCurrentCanvasPlan((prev) => ({ ...prev, bgImageName: null }))
await deleteBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
})
}, },
}) })
} }
@ -86,14 +93,18 @@ export function useRefFiles() {
/** /**
* 주소 삭제 * 주소 삭제
*/ */
const handleAddressDelete = () => { const handleAddressDelete = async () => {
swalFire({ swalFire({
text: '삭제하시겠습니까?', text: '삭제하시겠습니까?',
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: async () => {
setMapPositionAddress('') setMapPositionAddress('')
setCurrentBgImage(null) setCurrentBgImage(null)
setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null })) setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null }))
await deleteBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
})
}, },
}) })
} }
@ -107,11 +118,27 @@ export function useRefFiles() {
return return
} }
const newOption1 = settingModalFirstOptions.option1.map((option) => ({
...option,
selected: option.column === 'imageDisplay' ? true : option.selected,
}))
setSettingModalFirstOptions((prev) => ({
...prev,
option1: newOption1,
}))
const res = await get({ const res = await get({
url: `${process.env.NEXT_PUBLIC_HOST_URL}/map/convert?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) console.log('🚀 ~ handleMapImageDown ~ res:', res)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) 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}`,
})
} }
/** /**
@ -135,6 +162,16 @@ export function useRefFiles() {
* @param {*} file * @param {*} file
*/ */
const handleUploadImageRefFile = async (file) => { const handleUploadImageRefFile = async (file) => {
const newOption1 = settingModalFirstOptions.option1.map((option) => ({
...option,
selected: option.column === 'imageDisplay' ? true : option.selected,
}))
setSettingModalFirstOptions((prev) => ({
...prev,
option1: newOption1,
}))
const formData = new FormData() const formData = new FormData()
formData.append('file', file) formData.append('file', file)
@ -145,6 +182,14 @@ export function useRefFiles() {
console.log('🚀 ~ handleUploadImageRefFile ~ res:', res) console.log('🚀 ~ handleUploadImageRefFile ~ res:', res)
setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`) setCurrentBgImage(`${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`)
setRefImage(file) setRefImage(file)
const params = {
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
imagePath: `${process.env.NEXT_PUBLIC_HOST_URL}${res.filePath}`,
}
console.log('🚀 ~ handleUploadImageRefFile ~ params:', params)
await setBackGroundImage(params)
} }
/** /**

View File

@ -710,7 +710,7 @@ export const useTrestle = () => {
slope, slope,
classType: currentAngleType === 'slope' ? '0' : '1', classType: currentAngleType === 'slope' ? '0' : '1',
angle: getDegreeByChon(slope), angle: getDegreeByChon(slope),
azimuth: getAzimuth(surface), azimuth: getAzimuth(parent),
moduleList, moduleList,
} }
}) })
@ -726,8 +726,8 @@ export const useTrestle = () => {
return { itemList, northArrangement, roofSurfaceList, circuitItemList } return { itemList, northArrangement, roofSurfaceList, circuitItemList }
} }
const getAzimuth = (surface) => { const getAzimuth = (parent) => {
const { moduleCompass, surfaceCompass, direction } = surface const { moduleCompass, surfaceCompass, direction } = parent
if (surfaceCompass) { if (surfaceCompass) {
if (surfaceCompass > 180) { if (surfaceCompass > 180) {

View File

@ -2,7 +2,7 @@
import { useEffect } from 'react' import { useEffect } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil' import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, globalPitchState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState, globalPitchState } from '@/store/canvasAtom'
import { MENU, POLYGON_TYPE } from '@/common/common' import { MENU, POLYGON_TYPE } from '@/common/common'
import { getIntersectionPoint } from '@/util/canvas-util' import { getIntersectionPoint } from '@/util/canvas-util'
import { degreesToRadians } from '@turf/turf' import { degreesToRadians } from '@turf/turf'
@ -19,6 +19,7 @@ import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn' import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outerLinePointsState } from '@/store/outerLineAtom' import { outerLinePointsState } from '@/store/outerLineAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import { getBackGroundImage } from '@/lib/imageActions'
import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
@ -38,6 +39,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext) // const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
const { addPopup, closePopup } = usePopup() const { addPopup, closePopup } = usePopup()
const { setSurfaceShapePattern } = useRoofFn() const { setSurfaceShapePattern } = useRoofFn()
const currentCanvasPlan = useRecoilValue(currentCanvasPlanState)
const applySurfaceShape = (surfaceRefs, selectedType, id) => { const applySurfaceShape = (surfaceRefs, selectedType, id) => {
let length1, length2, length3, length4, length5 let length1, length2, length3, length4, length5
@ -719,12 +721,42 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
return points return points
} }
const deleteAllSurfacesAndObjects = () => { const deleteAllSurfacesAndObjects = async () => {
const backgroundImage = await getBackGroundImage({
objectId: currentCanvasPlan.id,
planNo: currentCanvasPlan.planNo,
})
console.log('🚀 ~ deleteAllSurfacesAndObjects ~ backgroundImage:', backgroundImage)
swalFire({ swalFire({
text: getMessage('batch.canvas.delete.all'), text: getMessage('batch.canvas.delete.all'),
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
canvas.clear() canvas.clear()
fabric.Image.fromURL(`${backgroundImage.path}`, function (img) {
console.log('🚀 ~ img:', img)
img.set({
left: 0,
top: 0,
width: img.width,
height: img.height,
name: 'backGroundImage',
selectable: false,
hasRotatingPoint: false, // 회전 핸들 활성화
lockMovementX: false,
lockMovementY: false,
lockRotation: false,
lockScalingX: false,
lockScalingY: false,
})
// image = img
canvas?.add(img)
canvas?.sendToBack(img)
canvas?.renderAll()
// setBackImg(img)
})
resetOuterLinePoints() resetOuterLinePoints()
resetPlacementShapeDrawingPoints() resetPlacementShapeDrawingPoints()
swalFire({ text: getMessage('plan.message.delete') }) swalFire({ text: getMessage('plan.message.delete') })

54
src/lib/imageActions.js Normal file
View File

@ -0,0 +1,54 @@
'use server'
import sqlite3 from 'sqlite3'
import { open } from 'sqlite'
export const setBackGroundImage = async ({ objectId, planNo, imagePath }) => {
let db = null
if (!db) {
db = await open({
filename: 'qcast3.database.sqlite',
driver: sqlite3.Database,
})
}
const fetchSql = `SELECT * FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
const result = await db.get(fetchSql)
if (result) {
const updateSql = `UPDATE background_image SET path = '${imagePath}' WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
await db.run(updateSql)
} else {
const insertSql = `INSERT INTO background_image (object_id, plan_no, path) VALUES ('${objectId}', '${planNo}', '${imagePath}')`
await db.run(insertSql)
}
}
export const getBackGroundImage = async ({ objectId, planNo }) => {
let db = null
if (!db) {
db = await open({
filename: 'qcast3.database.sqlite',
driver: sqlite3.Database,
})
}
const sql = `SELECT * FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
const result = await db.get(sql)
return result
}
export const deleteBackGroundImage = async ({ objectId, planNo }) => {
let db = null
if (!db) {
db = await open({
filename: 'qcast3.database.sqlite',
driver: sqlite3.Database,
})
}
const sql = `DELETE FROM background_image WHERE object_id = '${objectId}' AND plan_no = '${planNo}'`
await db.run(sql)
}