Merge branch 'dev' into dev-yj

This commit is contained in:
yjnoh 2024-12-03 17:55:01 +09:00
commit e12b3eb8d9
11 changed files with 186 additions and 168 deletions

View File

@ -34,7 +34,7 @@ export const QcastProvider = ({ children }) => {
const targetElement = document.getElementById('canvas') const targetElement = document.getElementById('canvas')
if (!targetElement && currentCanvasPlan?.id && planSave) { if (!targetElement && currentCanvasPlan?.id && planSave) {
setPlanSave((prev) => !prev) setPlanSave((prev) => !prev)
checkUnsavedCanvasPlan(currentCanvasPlan.userId) checkUnsavedCanvasPlan()
} else if (targetElement && currentCanvasPlan?.id) { } else if (targetElement && currentCanvasPlan?.id) {
setPlanSave(true) setPlanSave(true)
} }

View File

@ -191,9 +191,9 @@ export default function Estimate({ params }) {
}, [specialNoteList]) }, [specialNoteList])
// remark // remark
const settingShowContent = (code, event) => { const settingShowContent = (code) => {
setShowContentCode(code) setShowContentCode(code)
event.stopPropagation() // event.stopPropagation()
} }
// estimateContextState // estimateContextState
@ -227,7 +227,15 @@ export default function Estimate({ params }) {
}, [estimateContextState?.fileList]) }, [estimateContextState?.fileList])
// ( ?) // ( ?)
const deleteOriginFile = async (objectNo, no) => { const deleteOriginFile = (objectNo, no) => {
originFiles.map((file) => {
if (file.no === no) {
file.delFlg = '1'
}
})
// console.log('originFiles::', originFiles)
setOriginFiles(originFiles)
const delParams = { const delParams = {
userId: session.userId, userId: session.userId,
objectNo: objectNo, objectNo: objectNo,
@ -407,25 +415,43 @@ export default function Estimate({ params }) {
if (isNotEmptyArray(data.data2)) { if (isNotEmptyArray(data.data2)) {
estimateContextState.itemList.map((item) => { estimateContextState.itemList.map((item) => {
// console.log('::', item)
let checkYn = false let checkYn = false
data.data2.map((item2) => { for (let i = 0; i < data.data2.length; i++) {
if (item2) { // console.log(':::', data.data2[i])
if (item2.itemId === item.itemId) { if (data.data2[i]) {
if (data.data2[i].itemId === item.itemId) {
updateList.push({ updateList.push({
...item, ...item,
openFlg: item2.unitPrice === '0.0' ? '1' : '0', openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
salePrice: item2.unitPrice === null ? '0' : item2.unitPrice, salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
saleTotPrice: (item.amount * item2.unitPrice).toString(), saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
}) })
checkYn = true checkYn = true
break
} }
} }
}) }
// data.data2.map((item2) => {
// if (item2) {
// // console.log('::::', item2)
// if (item2.itemId === item.itemId) {
// updateList.push({
// ...item,
// openFlg: item2.unitPrice === '0.0' ? '1' : '0',
// salePrice: item2.unitPrice === null ? '0' : item2.unitPrice,
// saleTotPrice: (item.amount * item2.unitPrice).toString(),
// })
// checkYn = true
// }
// }
// })
if (!checkYn) { if (!checkYn) {
updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' }) updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' })
} }
}) })
setEstimateContextState({ setEstimateContextState({
priceCd: showPriceCd, priceCd: showPriceCd,
itemList: updateList, itemList: updateList,
@ -472,7 +498,7 @@ export default function Estimate({ params }) {
//PKG input //PKG input
const onChangePkgAsp = (value) => { const onChangePkgAsp = (value) => {
if (estimateContextState.estimateType === 'YJSS') { if (estimateContextState.estimateType === 'YJSS') {
let pkgAsp = Number(value.replace(/[^0-9]/g, '').replaceAll(',', '')) let pkgAsp = Number(value.replace(/[^-\.0-9]/g, '').replaceAll(',', ''))
if (isNaN(pkgAsp)) { if (isNaN(pkgAsp)) {
pkgAsp = 0 pkgAsp = 0
} else { } else {
@ -725,6 +751,7 @@ export default function Estimate({ params }) {
makeUniqueSpecialNoteCd(itemList) makeUniqueSpecialNoteCd(itemList)
itemList.forEach((item) => { itemList.forEach((item) => {
// console.log('YJOD::::::', item)
delete item.showSalePrice delete item.showSalePrice
delete item.showSaleTotPrice delete item.showSaleTotPrice
if (item.delFlg === '0') { if (item.delFlg === '0') {
@ -753,10 +780,10 @@ export default function Estimate({ params }) {
itemList.sort((a, b) => a.dispOrder - b.dispOrder) itemList.sort((a, b) => a.dispOrder - b.dispOrder)
makeUniqueSpecialNoteCd(itemList) makeUniqueSpecialNoteCd(itemList)
itemList.forEach((item) => { itemList.forEach((item) => {
// console.log('YJSSS::', item)
if (item.delFlg === '0') { if (item.delFlg === '0') {
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0 let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
let salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0 let salePrice = Number(item.salePrice?.replaceAll(',', '')) || 0
if (item.moduleFlg === '1') { if (item.moduleFlg === '1') {
const volKw = (item.pnowW * amount) / 1000 const volKw = (item.pnowW * amount) / 1000
totals.totVolKw += volKw totals.totVolKw += volKw
@ -1111,17 +1138,26 @@ export default function Estimate({ params }) {
{originFiles.map((originFile) => { {originFiles.map((originFile) => {
return ( return (
<li className="file-item" key={uuidv4()}> <li className="file-item" key={uuidv4()}>
<span onClick={() => handleEstimateFileDownload(originFile)}> <div className="file-item-wrap">
{originFile.faileName} <span>
<button {originFile.faileName}
type="button" <button
className="delete" type="button"
onClick={(e) => { className="delete"
deleteOriginFile(originFile.objectNo, originFile.no) onClick={(e) => {
e.stopPropagation() deleteOriginFile(originFile.objectNo, originFile.no)
}} e.stopPropagation()
></button> }}
</span> ></button>
</span>
{/* <div className="return-wrap">
<span className="return">{originFile.faileName}</span>
<button type="button" className="return-btn">
<i className="return-ico"></i>
{getMessage('estimate.detail.fileList2.btn.return')}
</button>
</div> */}
</div>
</li> </li>
) )
})} })}
@ -1155,21 +1191,29 @@ export default function Estimate({ params }) {
specialNoteList.map((row) => { specialNoteList.map((row) => {
return ( return (
<div key={uuidv4()} className="special-note-check-item"> <div key={uuidv4()} className="special-note-check-item">
<div className="d-check-box light"> <div className="special-note-check-box">
<input <div className="d-check-box light">
type="checkbox" <input
id={row.code} type="checkbox"
checked={!!row.check} id={row.code}
disabled={row.code === 'ATTR001' ? true : false} checked={!!row.check}
onChange={(event) => { disabled={row.code === 'ATTR001' || row.pkgYn === '1' ? true : false}
setSpecialNoteList((specialNote) => onClick={(event) => {
specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)), setSpecialNoteList((specialNote) =>
) specialNote.map((temp) => (temp.code === row.code ? { ...temp, check: !temp.check } : temp)),
)
settingShowContent(row.code, event) }}
/>
<label htmlFor={row.code}></label>
</div>
<span
className="check-name"
onClick={() => {
settingShowContent(row.code)
}} }}
/> >
<label htmlFor={row.code}>{row.codeNm}</label> {row.codeNm}
</span>
</div> </div>
</div> </div>
) )
@ -1501,7 +1545,9 @@ export default function Estimate({ params }) {
</div> </div>
</td> </td>
<td className="al-r"> <td className="al-r">
{convertNumberToPriceDecimal(item?.showSaleTotPrice === '0' ? null : item?.saleTotPrice?.replaceAll(',', ''))} {convertNumberToPriceDecimal(
item?.showSaleTotPrice === '0' ? null : item?.saleTotPrice === '0' ? null : item?.saleTotPrice?.replaceAll(',', ''),
)}
</td> </td>
</tr> </tr>
) )

View File

@ -20,7 +20,7 @@ export default function CanvasLayout({ children }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { plans, initCanvasPlans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan() const { plans, modifiedPlans, loadCanvasPlanData, handleCurrentPlan, handleAddPlan, handleDeletePlan } = usePlan()
useEffect(() => { useEffect(() => {
loadCanvasPlanData(session.userId, objectNo, pid) loadCanvasPlanData(session.userId, objectNo, pid)
@ -34,10 +34,9 @@ export default function CanvasLayout({ children }) {
<button <button
key={`plan-${plan.id}`} key={`plan-${plan.id}`}
className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`} className={`canvas-page-box ${plan.isCurrent === true ? 'on' : ''}`}
onClick={() => handleCurrentPlan(session.userId, plan.id)} onClick={() => handleCurrentPlan(plan.id)}
> >
<span> <span>
{!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === plan.id) && 'New '}
{`Plan ${plan.ordering}`} {`Plan ${plan.ordering}`}
{modifiedPlans.some((modifiedPlan) => modifiedPlan === plan.id) && ' [ M ]'} {modifiedPlans.some((modifiedPlan) => modifiedPlan === plan.id) && ' [ M ]'}
</span> </span>
@ -45,10 +44,7 @@ export default function CanvasLayout({ children }) {
className="close" className="close"
onClick={(e) => onClick={(e) =>
swalFire({ swalFire({
text: text: `Plan ${plan.ordering} ` + getMessage('plan.message.confirm.delete'),
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === plan.id) ? 'New ' : '') +
`Plan ${plan.ordering} ` +
getMessage('plan.message.confirm.delete'),
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
handleDeletePlan(e, plan.id) handleDeletePlan(e, plan.id)

View File

@ -68,7 +68,7 @@ export default function CanvasMenu(props) {
const [estimateCopyPopupOpen, setEstimateCopyPopupOpen] = useState(false) const [estimateCopyPopupOpen, setEstimateCopyPopupOpen] = useState(false)
const { getMessage } = useMessage() const { getMessage } = useMessage()
const { currentCanvasPlan, saveCanvas } = usePlan() const { saveCanvas } = usePlan()
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent() const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useEvent()
// const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useContext(EventContext) // const { initEvent, addCanvasMouseEventListener, addDocumentEventListener } = useContext(EventContext)
@ -118,13 +118,7 @@ export default function CanvasMenu(props) {
// (btn08) // (btn08)
const handleSaveCanvas = async () => { const handleSaveCanvas = async () => {
// swalFire({ await saveCanvas()
// text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
// type: 'confirm',
// confirmFn: async () => {
await saveCanvas(sessionState.userId)
// },
// })
} }
const [placementInitialId, setPlacementInitialId] = useState(uuidv4()) const [placementInitialId, setPlacementInitialId] = useState(uuidv4())

View File

@ -18,6 +18,9 @@ const updateItemInList = (itemList, dispOrder, updates) => {
} }
export const useEstimateController = (planNo) => { export const useEstimateController = (planNo) => {
const [fileList, setFileList] = useState([])
const [deleteFileList, setDeleteFileList] = useState([])
const router = useRouter() const router = useRouter()
const { session } = useContext(SessionContext) const { session } = useContext(SessionContext)
const globalLocaleState = useRecoilValue(globalLocaleStore) const globalLocaleState = useRecoilValue(globalLocaleStore)
@ -148,8 +151,8 @@ export const useEstimateController = (planNo) => {
//첨부파일을 첨부안했는데 //첨부파일을 첨부안했는데
//아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼 //아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼
console.log('새로추가첨부파일:::', estimateData.newFileList) // console.log('새로추가첨부파일:::', estimateData.newFileList)
console.log('기존첨부파일:::', estimateData.originFiles) // console.log('기존첨부파일:::', estimateData.originFiles)
// return // return
@ -228,13 +231,12 @@ export const useEstimateController = (planNo) => {
formData.append('category', '10') formData.append('category', '10')
formData.append('userId', estimateData.userId) formData.append('userId', estimateData.userId)
await post({ url: '/api/file/fileUpload', data: formData }) await post({ url: '/api/file/fileUpload', data: formData }).then((res) => {
console.log('리턴::::::::::::', res)
})
} }
//첨부파일저장끝 //첨부파일저장끝
//제품라인 추가했는데 아이템 안고르고 저장하면itemId=''은 날리고 나머지 저장하기
// estimateData.itemList = estimateData.itemList.filter((item) => item.itemId !== '')
estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg) estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg)
let delCnt = 0 let delCnt = 0
@ -287,7 +289,8 @@ export const useEstimateController = (planNo) => {
estimateOptions = estimateOptionsArray.join('、') estimateOptions = estimateOptionsArray.join('、')
estimateData.estimateOption = estimateOptions estimateData.estimateOption = estimateOptions
console.log('최종아이템:::', estimateData.itemList) // console.log('첨부파일::::::::', fileList)
// console.log('최종아이템:::', estimateData.itemList)
console.log('최종저장::', estimateData) console.log('최종저장::', estimateData)
//2. 상세데이터 저장 //2. 상세데이터 저장
// return // return

View File

@ -950,16 +950,19 @@ export function useModuleBasicSetting() {
// }) // })
// setModuleIsSetup(moduleArray) // setModuleIsSetup(moduleArray)
}) })
console.log(calculateForApi())
} }
const calculateForApi = (moduleSetupArray) => { const calculateForApi = () => {
// TODO : 현재는 남쪽기준. 동,서,북 분기처리 필요 // TODO : 현재는 남쪽기준. 동,서,북 분기처리 필요
const centerPoints = [] const centerPoints = []
moduleSetupArray.forEach((module, index) => { const modules = canvas.getObjects().filter((obj) => obj.name === 'module')
modules.forEach((module, index) => {
module.tempIndex = index module.tempIndex = index
const { x, y } = module.getCenterPoint() const { x, y } = module.getCenterPoint()
const { width, height } = module const { width, height } = module
centerPoints.push({ x, y, width, height, index }) centerPoints.push({ x, y, width: Math.abs(width), height: Math.abs(height), index })
const circle = new fabric.Circle({ const circle = new fabric.Circle({
radius: 5, radius: 5,
fill: 'red', fill: 'red',
@ -969,7 +972,7 @@ export function useModuleBasicSetting() {
index: index, index: index,
selectable: false, selectable: false,
}) })
canvas.add(circle) // canvas.add(circle)
}) })
//완전 노출 하면 //완전 노출 하면
@ -988,7 +991,7 @@ export function useModuleBasicSetting() {
centerPoints.forEach((centerPoint, index) => { centerPoints.forEach((centerPoint, index) => {
const { x, y, width, height } = centerPoint const { x, y, width, height } = centerPoint
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인 // centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
const bottomCell = centerPoints.filter((centerPoint) => centerPoint.x === x && Math.abs(centerPoint.y - (y + height)) < 2) const bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y + height)) < 2)
if (bottomCell.length === 1) { if (bottomCell.length === 1) {
touchDimension++ touchDimension++
return return
@ -1018,7 +1021,7 @@ export function useModuleBasicSetting() {
centerPoints.forEach((centerPoint, index) => { centerPoints.forEach((centerPoint, index) => {
const { x, y, width, height } = centerPoint const { x, y, width, height } = centerPoint
const topCell = centerPoints.filter((centerPoint) => centerPoint.x === x && Math.abs(centerPoint.y - (y - height)) < 2) const topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y - height)) < 2)
if (topCell.length === 1) { if (topCell.length === 1) {
return return
} }
@ -1048,8 +1051,8 @@ export function useModuleBasicSetting() {
const points = cells.map((cell) => { const points = cells.map((cell) => {
return cell.getCenterPoint() return cell.getCenterPoint()
})*/ })*/
const groupPoints = groupCoordinates(centerPoints) const groupPoints = groupCoordinates(centerPoints, modules[0])
console.log('groupPoints', groupPoints)
groupPoints.forEach((group) => { groupPoints.forEach((group) => {
// 각 그룹에서 y값이 큰 값을 찾는다. // 각 그룹에서 y값이 큰 값을 찾는다.
// 그리고 그 y값과 같은 값을 가지는 centerPoint를 찾는다. // 그리고 그 y값과 같은 값을 가지는 centerPoint를 찾는다.
@ -1069,21 +1072,21 @@ export function useModuleBasicSetting() {
} }
// polygon 내부 cell들의 centerPoint 배열을 그룹화 해서 반환 // polygon 내부 cell들의 centerPoint 배열을 그룹화 해서 반환
const groupCoordinates = (points) => { const groupCoordinates = (points, moduleExample) => {
const groups = [] const groups = []
const visited = new Set() const visited = new Set()
const width = 100 const width = Math.floor(moduleExample.width)
const height = 100 const height = Math.floor(moduleExample.height)
const horizonPadding = 5 // 가로 패딩 const horizonPadding = 0 // 가로 패딩
const verticalPadding = 3 // 세로 패딩 const verticalPadding = 0 // 세로 패딩
function isAdjacent(p1, p2) { function isAdjacent(p1, p2) {
const dx = Math.abs(p1.x - p2.x) const dx = Math.abs(p1.x - p2.x)
const dy = Math.abs(p1.y - p2.y) const dy = Math.abs(p1.y - p2.y)
return ( return (
(dx === width + horizonPadding && dy === 0) || (Math.abs(width + horizonPadding - dx) < 2 && dy < 2) ||
(dx === 0 && dy === height + verticalPadding) || (dx < 2 && Math.abs(dy - height + verticalPadding)) < 2 ||
(dx === width / 2 + horizonPadding / 2 && dy === height + verticalPadding) (Math.abs(dx - width / 2 + horizonPadding / 2) < 2 && Math.abs(dy - height + verticalPadding) < 2)
) )
} }

View File

@ -1,7 +1,7 @@
import { useEffect, useState } from 'react' import { useEffect, useState } from 'react'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { v4 as uuidv4, validate as isValidUUID } from 'uuid' import { v4 as uuidv4, validate as isValidUUID } from 'uuid'
import { canvasState, currentCanvasPlanState, initCanvasPlansState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom' import { canvasState, currentCanvasPlanState, plansState, modifiedPlansState, modifiedPlanFlagState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios' import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage' import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
@ -15,8 +15,7 @@ export function usePlan() {
const [canvas, setCanvas] = useRecoilState(canvasState) const [canvas, setCanvas] = useRecoilState(canvasState)
const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState) const [currentCanvasPlan, setCurrentCanvasPlan] = useRecoilState(currentCanvasPlanState)
const [initCanvasPlans, setInitCanvasPlans] = useRecoilState(initCanvasPlansState) // DB에 저장된 plan const [plans, setPlans] = useRecoilState(plansState) // 전체 plan
const [plans, setPlans] = useRecoilState(plansState) // 전체 plan (DB에 저장된 plan + 저장 안된 새로운 plan)
const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan const [modifiedPlans, setModifiedPlans] = useRecoilState(modifiedPlansState) // 변경된 canvas plan
const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag const [modifiedPlanFlag, setModifiedPlanFlag] = useRecoilState(modifiedPlanFlagState) // 캔버스 실시간 오브젝트 이벤트 감지 flag
@ -109,22 +108,22 @@ export function usePlan() {
setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus })) setCurrentCanvasPlan((prev) => ({ ...prev, canvasStatus: currentCanvasStatus }))
} }
}, [currentCanvasStatus]) }, [currentCanvasStatus])
/** /**
* 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단 * 현재 캔버스 상태와 DB에 저장된 캔버스 상태를 비교하여 수정 여부를 판단
*/ */
const checkModifiedCanvasPlan = (planId) => { const checkModifiedCanvasPlan = (planId) => {
const canvasStatus = currentCanvasData() const planData = plans.find((plan) => plan.id === planId)
if (isValidUUID(planId)) { if (planData.canvasStatus === '') {
// 새로운 캔버스 // 빈 상태로 저장된 캔버스
return JSON.parse(canvasStatus).objects.length > 0 return true
} else {
// 저장된 캔버스
// 각각 object들의 uuid 목록을 추출하여 비교
const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects)
const initPlanData = initCanvasPlans.find((plan) => plan.id === planId)
const dbObjsUuids = getObjectUuids(JSON.parse(initPlanData.canvasStatus).objects)
return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index])
} }
// 각각 object들의 uuid 목록을 추출하여 비교
const canvasStatus = currentCanvasData()
const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects)
const dbObjsUuids = getObjectUuids(JSON.parse(planData.canvasStatus).objects)
return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((uuid, index) => uuid === dbObjsUuids[index])
} }
const getObjectUuids = (objects) => { const getObjectUuids = (objects) => {
return objects return objects
@ -141,16 +140,12 @@ export function usePlan() {
/** /**
* 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 저장 * 캔버스에 저장되지 않은 변경사항이 있을때 저장 여부를 확인 저장
*/ */
const checkUnsavedCanvasPlan = async (userId) => { const checkUnsavedCanvasPlan = async () => {
swalFire({ swalFire({
text: text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.save.modified'),
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === currentCanvasPlan.id) ? 'New ' : '') +
`Plan ${currentCanvasPlan.ordering}의 변경 사항을 저장하시겠습니까?`,
type: 'confirm', type: 'confirm',
confirmFn: async () => { confirmFn: async () => {
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id) await putCanvasStatus(currentCanvasPlan.canvasStatus)
? await putCanvasStatus(currentCanvasPlan.canvasStatus)
: await postCanvasStatus(userId, currentCanvasPlan.canvasStatus)
}, },
}) })
resetModifiedPlans() resetModifiedPlans()
@ -173,11 +168,9 @@ export function usePlan() {
/** /**
* 페이지 캔버스를 저장 * 페이지 캔버스를 저장
*/ */
const saveCanvas = async (userId) => { const saveCanvas = async () => {
const canvasStatus = currentCanvasData('save') const canvasStatus = currentCanvasData('save')
initCanvasPlans.some((plan) => plan.id === currentCanvasPlan.id) await putCanvasStatus(canvasStatus)
? await putCanvasStatus(canvasStatus)
: await postCanvasStatus(userId, canvasStatus)
} }
/** /**
@ -200,29 +193,19 @@ export function usePlan() {
/** /**
* 신규 canvas 데이터를 저장 * 신규 canvas 데이터를 저장
*/ */
const postCanvasStatus = async (userId, canvasStatus) => { const postCanvasStatus = async (userId, objectNo, canvasStatus) => {
const planData = { const planData = {
userId: userId, userId: userId,
imageName: 'image_name', // api 필수항목이여서 임시로 넣음, 이후 삭제 필요 imageName: 'image_name', // api 필수항목이여서 임시로 넣음, 이후 삭제 필요
objectNo: currentCanvasPlan.objectNo, objectNo: objectNo,
mapPositionAddress: currentCanvasPlan.mapPositionAddress, mapPositionAddress: currentCanvasPlan.mapPositionAddress,
canvasStatus: canvasToDbFormat(canvasStatus), canvasStatus: canvasToDbFormat(canvasStatus),
} }
await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData }) await promisePost({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => { .then((res) => {
setInitCanvasPlans((initCanvasPlans) => [...initCanvasPlans, { id: res.data, canvasStatus: canvasStatus }]) setPlans([...plans, { id: res.data, objectNo: objectNo, userId: userId, canvasStatus: canvasStatus, ordering: planNum + 1 }])
setPlans((plans) => handleCurrentPlan(res.data)
plans.map((plan) => setPlanNum(planNum + 1)
plan.id === currentCanvasPlan.id
? {
...plan,
id: res.data,
canvasStatus: canvasStatus,
}
: plan,
),
)
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
}) })
.catch((error) => { .catch((error) => {
swalFire({ text: error.message, icon: 'error' }) swalFire({ text: error.message, icon: 'error' })
@ -240,9 +223,6 @@ export function usePlan() {
} }
await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData }) await promisePut({ url: '/api/canvas-management/canvas-statuses', data: planData })
.then((res) => { .then((res) => {
setInitCanvasPlans((initCanvasPlans) =>
initCanvasPlans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)),
)
setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan)))
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
}) })
@ -269,21 +249,10 @@ export function usePlan() {
* plan 이동 * plan 이동
* 현재 plan의 작업상태를 확인, 저장 이동 * 현재 plan의 작업상태를 확인, 저장 이동
*/ */
const handleCurrentPlan = async (userId, newCurrentId) => { const handleCurrentPlan = async (newCurrentId) => {
if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) { if (!currentCanvasPlan || currentCanvasPlan.id !== newCurrentId) {
if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) { if (currentCanvasPlan?.id && modifiedPlans.some((modifiedPlan) => modifiedPlan === currentCanvasPlan.id)) {
// swalFire({ await saveCanvas()
// text: `${currentCanvasPlan.name} ` + getMessage('plan.message.confirm.save'),
// type: 'confirm',
// confirmFn: async () => {
// await saveCanvas(userId)
// updateCurrentPlan(newCurrentId)
// },
// denyFn: () => {
// updateCurrentPlan(newCurrentId)
// },
// })
await saveCanvas(userId)
} }
updateCurrentPlan(newCurrentId) updateCurrentPlan(newCurrentId)
} }
@ -313,20 +282,21 @@ export function usePlan() {
const handleAddPlan = (userId, objectNo) => { const handleAddPlan = (userId, objectNo) => {
JSON.parse(currentCanvasData()).objects.length > 0 JSON.parse(currentCanvasData()).objects.length > 0
? swalFire({ ? swalFire({
text: text: `Plan ${currentCanvasPlan.ordering} ` + getMessage('plan.message.confirm.copy'),
(!initCanvasPlans.some((initCanvasPlans) => initCanvasPlans.id === currentCanvasPlan.id) ? 'New ' : '') +
`Plan ${currentCanvasPlan.ordering} ` +
getMessage('plan.message.confirm.copy'),
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
addPlan(userId, objectNo, currentCanvasData()) postCanvasStatus(userId, objectNo, currentCanvasData())
}, },
denyFn: () => { denyFn: () => {
addPlan(userId, objectNo, '') postCanvasStatus(userId, objectNo, '')
}, },
}) })
: addPlan(userId, objectNo, '') : postCanvasStatus(userId, objectNo, '')
} }
/**
* DB에 추가하지 않고 화면 상에서 plan을 추가하는 함수
*/
const addPlan = (userId, objectNo, canvasStatus) => { const addPlan = (userId, objectNo, canvasStatus) => {
const id = uuidv4() const id = uuidv4()
const newPlan = { const newPlan = {
@ -337,7 +307,7 @@ export function usePlan() {
ordering: planNum + 1, ordering: planNum + 1,
} }
setPlans([...plans, newPlan]) setPlans([...plans, newPlan])
handleCurrentPlan(userId, id) handleCurrentPlan(id)
setPlanNum(planNum + 1) setPlanNum(planNum + 1)
} }
@ -347,22 +317,15 @@ export function usePlan() {
const handleDeletePlan = (e, id) => { const handleDeletePlan = (e, id) => {
e.stopPropagation() // 이벤트 버블링 방지 e.stopPropagation() // 이벤트 버블링 방지
if (initCanvasPlans.some((plan) => plan.id === id)) { delCanvasById(id)
delCanvasById(id) .then((res) => {
.then((res) => { setPlans((plans) => plans.filter((plan) => plan.id !== id))
setInitCanvasPlans((initCanvasPlans) => initCanvasPlans.filter((plan) => plan.id !== id)) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
setPlans((plans) => plans.filter((plan) => plan.id !== id)) swalFire({ text: getMessage('plan.message.delete') })
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) })
swalFire({ text: getMessage('plan.message.delete') }) .catch((error) => {
}) swalFire({ text: error.message, icon: 'error' })
.catch((error) => { })
swalFire({ text: error.message, icon: 'error' })
})
} else {
setPlans((plans) => plans.filter((plan) => plan.id !== id))
setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id))
swalFire({ text: getMessage('plan.message.delete') })
}
// 삭제 후 last 데이터에 포커싱 // 삭제 후 last 데이터에 포커싱
const lastPlan = plans.filter((plan) => plan.id !== id).at(-1) const lastPlan = plans.filter((plan) => plan.id !== id).at(-1)
@ -381,12 +344,11 @@ export function usePlan() {
getCanvasByObjectNo(userId, objectNo).then((res) => { getCanvasByObjectNo(userId, objectNo).then((res) => {
// console.log('canvas 목록 ', res) // console.log('canvas 목록 ', res)
if (res.length > 0) { if (res.length > 0) {
setInitCanvasPlans(res)
setPlans(res) setPlans(res)
updateCurrentPlan(res[pid - 1].id) updateCurrentPlan(res[pid - 1].id)
setPlanNum(res.length) setPlanNum(res.length)
} else { } else {
addPlan(userId, objectNo, '') postCanvasStatus(userId, objectNo, '')
} }
}) })
} }
@ -394,7 +356,6 @@ export function usePlan() {
return { return {
canvas, canvas,
plans, plans,
initCanvasPlans,
selectedPlan, selectedPlan,
currentCanvasPlan, currentCanvasPlan,
modifiedPlans, modifiedPlans,

View File

@ -294,6 +294,7 @@
"modal.actual.size.setting.plane.size.length": "廊下の寸法の長さ", "modal.actual.size.setting.plane.size.length": "廊下の寸法の長さ",
"modal.actual.size.setting.actual.size.length": "実寸長", "modal.actual.size.setting.actual.size.length": "実寸長",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
"plan.message.save": "저장되었습니다.", "plan.message.save": "저장되었습니다.",
@ -840,6 +841,7 @@
"estimate.detail.fileList.btn": "ファイル選択", "estimate.detail.fileList.btn": "ファイル選択",
"estimate.detail.fileList.extCheck": "そのファイルはイメージファイルではありません", "estimate.detail.fileList.extCheck": "そのファイルはイメージファイルではありません",
"estimate.detail.header.fileList2": "添付ファイル一覧", "estimate.detail.header.fileList2": "添付ファイル一覧",
"estimate.detail.fileList2.btn.return": "復元",
"estimate.detail.header.specialEstimate": "見積もりの具体的な", "estimate.detail.header.specialEstimate": "見積もりの具体的な",
"estimate.detail.header.specialEstimateProductInfo": "製品情報", "estimate.detail.header.specialEstimateProductInfo": "製品情報",
"estimate.detail.sepcialEstimateProductInfo.totAmount": "数量 (PCS)", "estimate.detail.sepcialEstimateProductInfo.totAmount": "数量 (PCS)",

View File

@ -299,6 +299,7 @@
"modal.actual.size.setting.plane.size.length": "복도치수 길이", "modal.actual.size.setting.plane.size.length": "복도치수 길이",
"modal.actual.size.setting.actual.size.length": "실제치수 길이", "modal.actual.size.setting.actual.size.length": "실제치수 길이",
"plan.message.confirm.save": "PLAN을 저장하시겠습니까?", "plan.message.confirm.save": "PLAN을 저장하시겠습니까?",
"plan.message.confirm.save.modified": "PLAN의 변경사항을 저장하시겠습니까?",
"plan.message.confirm.copy": "PLAN을 복사하시겠습니까?", "plan.message.confirm.copy": "PLAN을 복사하시겠습니까?",
"plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?", "plan.message.confirm.delete": "PLAN을 삭제하시겠습니까?",
"plan.message.save": "저장되었습니다.", "plan.message.save": "저장되었습니다.",
@ -850,6 +851,7 @@
"estimate.detail.fileList.btn": "파일선택", "estimate.detail.fileList.btn": "파일선택",
"estimate.detail.fileList.extCheck": "해당 파일은 이미지 파일이 아닙니다", "estimate.detail.fileList.extCheck": "해당 파일은 이미지 파일이 아닙니다",
"estimate.detail.header.fileList2": "첨부파일 목록", "estimate.detail.header.fileList2": "첨부파일 목록",
"estimate.detail.fileList2.btn.return": "복원",
"estimate.detail.header.specialEstimate": "견적특이사항", "estimate.detail.header.specialEstimate": "견적특이사항",
"estimate.detail.header.specialEstimateProductInfo": "제품정보", "estimate.detail.header.specialEstimateProductInfo": "제품정보",
"estimate.detail.sepcialEstimateProductInfo.totAmount": "수량 (PCS)", "estimate.detail.sepcialEstimateProductInfo.totAmount": "수량 (PCS)",

View File

@ -260,12 +260,6 @@ export const dotLineIntervalSelector = selector({
}, },
}) })
// canvas plan 초기 목록
export const initCanvasPlansState = atom({
key: 'initCanvasPlans',
default: [],
})
// 현재 canvas plan // 현재 canvas plan
export const currentCanvasPlanState = atom({ export const currentCanvasPlanState = atom({
key: 'currentCanvasPlan', key: 'currentCanvasPlan',

View File

@ -97,6 +97,23 @@ export const inputNumberCheck = (e) => {
/** /**
* 파이프함수 정의 * 파이프함수 정의
* @param {...any} fns 순수함수들 * @param {...any} fns 순수함수들
* @returns * @returns
*/ */
export const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x) export const pipe =
(...fns) =>
(x) =>
fns.reduce((v, f) => f(v), x)
/**
* 캔버스 각도에 따른 흐름 방향 계산
* @param {number} canvasAngle
* @returns {object} 흐름 방향 객체
*/
export const calculateFlowDirection = (canvasAngle) => {
return {
down: -canvasAngle,
up: 180 - canvasAngle,
left: 90 - canvasAngle,
right: -90 - canvasAngle,
}
}