diff --git a/package.json b/package.json index c2b9e6cf..a9b977ce 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,8 @@ "react-responsive-modal": "^6.4.2", "react-select": "^5.8.1", "recoil": "^0.7.7", + "sqlite": "^5.1.1", + "sqlite3": "^5.1.7", "sweetalert2": "^11.14.1", "sweetalert2-react-content": "^5.0.7", "swr": "^2.3.0", diff --git a/qcast3.database.sqlite b/qcast3.database.sqlite new file mode 100644 index 00000000..c0c43e6f Binary files /dev/null and b/qcast3.database.sqlite differ diff --git a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx index 5cc8b7ba..681a425d 100644 --- a/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/CircuitTrestleSetting.jsx @@ -384,7 +384,12 @@ export default function CircuitTrestleSetting({ id }) { obj.pcsItemId = 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) { setAllocationType(ALLOCATION_TYPE.AUTO) diff --git a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx index 239487e9..f3536bc9 100644 --- a/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx +++ b/src/components/floor-plan/modal/circuitTrestle/step/StepUp.jsx @@ -364,7 +364,7 @@ export default function StepUp(props) { // console.log('πŸš€ ~ handleRowClick ~ selectedData:', selectedData) // PCS 2개 이상 λ˜λŠ” 첫번째 PCS 선택 μ‹œμ—λ§Œ μ‹€ν–‰ - if (stepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) { + if (tempStepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) { // νŒŒμ›Œμ»¨λ””μ…”λ„ˆ μ˜΅μ…˜ 쑰회 μš”μ²­ νŒŒλΌλ―Έν„° const params = { ...props.getOptYn(), // μ˜΅μ…˜ Y/N @@ -442,29 +442,30 @@ export default function StepUp(props) { roofSurface.moduleList.forEach((module) => { const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0] - if (module.circuit === '') return - const moduleCircuitText = new fabric.Text(module.circuit, { - left: targetModule.left + targetModule.width / 2, - top: targetModule.top + targetModule.height / 2, - fontFamily: circuitNumberText.fontFamily.value, - fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal', - fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', - fontSize: circuitNumberText.fontSize.value, - fill: circuitNumberText.fontColor.value, - width: targetModule.width, - height: targetModule.height, - textAlign: 'center', - originX: 'center', - originY: 'center', - name: 'circuitNumber', - parentId: targetModule.id, - circuitInfo: module.pcsItemId, - visible: isDisplayCircuitNumber, - }) - targetModule.circuit = moduleCircuitText - targetModule.pcsItemId = module.pcsItemId - targetModule.circuitNumber = module.circuit - canvas.add(moduleCircuitText) + if (module.circuit !== '' && module.circuit) { + const moduleCircuitText = new fabric.Text(module.circuit, { + left: targetModule.left + targetModule.width / 2, + top: targetModule.top + targetModule.height / 2, + fontFamily: circuitNumberText.fontFamily.value, + fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal', + fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', + fontSize: circuitNumberText.fontSize.value, + fill: circuitNumberText.fontColor.value, + width: targetModule.width, + height: targetModule.height, + textAlign: 'center', + originX: 'center', + originY: 'center', + name: 'circuitNumber', + parentId: targetModule.id, + circuitInfo: module.pcsItemId, + visible: isDisplayCircuitNumber, + }) + targetModule.circuit = moduleCircuitText + targetModule.pcsItemId = module.pcsItemId + targetModule.circuitNumber = module.circuit + canvas.add(moduleCircuitText) + } }) }) diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 140c9abd..05880782 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -24,7 +24,6 @@ export const ROOF_MATERIAL_LAYOUT = { export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) { const [showSizeGuideModal, setShowSizeGuidModal] = useState(false) const [showMaterialGuideModal, setShowMaterialGuidModal] = useState(false) - const { closePopup } = usePopup() const { getMessage } = useMessage() const roofMaterials = useRecoilValue(roofMaterialsAtom) @@ -221,9 +220,6 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla

{getMessage('plan.menu.placement.surface.initial.setting')}

-
diff --git a/src/hooks/common/useRefFiles.js b/src/hooks/common/useRefFiles.js index 992c1319..52f8ef47 100644 --- a/src/hooks/common/useRefFiles.js +++ b/src/hooks/common/useRefFiles.js @@ -5,6 +5,8 @@ import { useSwal } from '@/hooks/useSwal' import { useAxios } from '../useAxios' import { currentCanvasPlanState } from '@/store/canvasAtom' 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 queryRef = useRef(null) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) + const [settingModalFirstOptions, setSettingModalFirstOptions] = useRecoilState(settingModalFirstOptionsState) const { handleBackImageLoadToCanvas } = useCanvas() const { swalFire } = useSwal() const { get, post } = useAxios() @@ -72,13 +75,17 @@ export function useRefFiles() { /** * 파일 μ‚­μ œ */ - const handleFileDelete = () => { + const handleFileDelete = async () => { swalFire({ text: 'μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?', type: 'confirm', - confirmFn: () => { + confirmFn: async () => { setRefImage(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({ text: 'μ‚­μ œν•˜μ‹œκ² μŠ΅λ‹ˆκΉŒ?', type: 'confirm', - confirmFn: () => { + confirmFn: async () => { setMapPositionAddress('') setCurrentBgImage(null) setCurrentCanvasPlan((prev) => ({ ...prev, mapPositionAddress: null })) + await deleteBackGroundImage({ + objectId: currentCanvasPlan.id, + planNo: currentCanvasPlan.planNo, + }) }, }) } @@ -107,11 +118,27 @@ export function useRefFiles() { return } + const newOption1 = settingModalFirstOptions.option1.map((option) => ({ + ...option, + selected: option.column === 'imageDisplay' ? true : option.selected, + })) + + setSettingModalFirstOptions((prev) => ({ + ...prev, + option1: newOption1, + })) + const res = await get({ 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_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 */ 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() formData.append('file', file) @@ -145,6 +182,14 @@ export function useRefFiles() { console.log('πŸš€ ~ handleUploadImageRefFile ~ res:', res) 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}`, + } + console.log('πŸš€ ~ handleUploadImageRefFile ~ params:', params) + await setBackGroundImage(params) } /** diff --git a/src/hooks/module/useTrestle.js b/src/hooks/module/useTrestle.js index 17f58814..3304d180 100644 --- a/src/hooks/module/useTrestle.js +++ b/src/hooks/module/useTrestle.js @@ -710,7 +710,7 @@ export const useTrestle = () => { slope, classType: currentAngleType === 'slope' ? '0' : '1', angle: getDegreeByChon(slope), - azimuth: getAzimuth(surface), + azimuth: getAzimuth(parent), moduleList, } }) @@ -726,8 +726,8 @@ export const useTrestle = () => { return { itemList, northArrangement, roofSurfaceList, circuitItemList } } - const getAzimuth = (surface) => { - const { moduleCompass, surfaceCompass, direction } = surface + const getAzimuth = (parent) => { + const { moduleCompass, surfaceCompass, direction } = parent if (surfaceCompass) { if (surfaceCompass > 180) { diff --git a/src/hooks/surface/useSurfaceShapeBatch.js b/src/hooks/surface/useSurfaceShapeBatch.js index dd0ae21f..abb3688b 100644 --- a/src/hooks/surface/useSurfaceShapeBatch.js +++ b/src/hooks/surface/useSurfaceShapeBatch.js @@ -2,7 +2,7 @@ import { useEffect } from 'react' 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 { getIntersectionPoint } from '@/util/canvas-util' import { degreesToRadians } from '@turf/turf' @@ -19,6 +19,7 @@ import { QLine } from '@/components/fabric/QLine' import { useRoofFn } from '@/hooks/common/useRoofFn' import { outerLinePointsState } from '@/store/outerLineAtom' import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom' +import { getBackGroundImage } from '@/lib/imageActions' import PlacementSurfaceLineProperty from '@/components/floor-plan/modal/placementShape/PlacementSurfaceLineProperty' import { v4 as uuidv4 } from 'uuid' @@ -38,6 +39,7 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { // const { addCanvasMouseEventListener, initEvent } = useContext(EventContext) const { addPopup, closePopup } = usePopup() const { setSurfaceShapePattern } = useRoofFn() + const currentCanvasPlan = useRecoilValue(currentCanvasPlanState) const applySurfaceShape = (surfaceRefs, selectedType, id) => { let length1, length2, length3, length4, length5 @@ -719,12 +721,42 @@ export function useSurfaceShapeBatch({ isHidden, setIsHidden }) { return points } - const deleteAllSurfacesAndObjects = () => { + const deleteAllSurfacesAndObjects = async () => { + const backgroundImage = await getBackGroundImage({ + objectId: currentCanvasPlan.id, + planNo: currentCanvasPlan.planNo, + }) + console.log('πŸš€ ~ deleteAllSurfacesAndObjects ~ backgroundImage:', backgroundImage) + swalFire({ text: getMessage('batch.canvas.delete.all'), type: 'confirm', confirmFn: () => { 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() resetPlacementShapeDrawingPoints() swalFire({ text: getMessage('plan.message.delete') }) diff --git a/src/lib/imageActions.js b/src/lib/imageActions.js new file mode 100644 index 00000000..f3276d64 --- /dev/null +++ b/src/lib/imageActions.js @@ -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) +}