diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 6b257645..65a24def 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -9,7 +9,7 @@ import SingleDatePicker from '../common/datepicker/SingleDatePicker' import EstimateFileUploader from './EstimateFileUploader' import { useAxios } from '@/hooks/useAxios' import { globalLocaleStore } from '@/store/localeAtom' -import { isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' +import { isEmptyArray, isNotEmptyArray, isObjectNotEmpty, queryStringFormatter } from '@/util/common-utils' import dayjs from 'dayjs' import { useCommonCode } from '@/hooks/common/useCommonCode' import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController' @@ -61,7 +61,7 @@ export default function Estimate({ params }) { const objectRecoil = useRecoilValue(floorPlanObjectState) //견적서 상세데이터 - const { estimateContextState, setEstimateContextState, addItem } = useEstimateController(params.pid) + const { estimateContextState, setEstimateContextState, addItem, handleEstimateFileDownload } = useEstimateController(params.pid) //견적특이사항 List const [specialNoteList, setSpecialNoteList] = useState([]) @@ -209,11 +209,12 @@ export default function Estimate({ params }) { }, [files]) useEffect(() => { - if (originFiles.length > 0) { - setEstimateContextState({ - originFiles: originFiles, - }) - } + // console.log('USEEFFECT originFiles::::::::::', originFiles) + // if (originFiles.length > 0) { + // setEstimateContextState({ + // originFiles: originFiles, + // }) + // } }, [originFiles]) //상세에서 내려온 첨부파일 set 만들기 @@ -232,10 +233,12 @@ export default function Estimate({ params }) { file.delFlg = '0' } }) - setOriginFiles((prev) => { return [...prev] }) + setEstimateContextState({ + originFiles: originFiles, + }) } // 기존첨부파일 삭제 (플래그값 추가?) 저장할때 플래그값에 따라 진짜 삭제 const deleteOriginFile = (no) => { @@ -245,29 +248,13 @@ export default function Estimate({ params }) { } }) - // console.log('originFiles::', originFiles) setOriginFiles((prev) => { return [...prev] }) - // setOriginFiles(originFiles) - // const delParams = { - // userId: session.userId, - // objectNo: objectNo, - // no: no, - // } + setEstimateContextState({ + originFiles: originFiles, + }) alert(getMessage('estimate.detail.alert.delFile')) - // await promisePost({ url: 'api/file/fileDelete', data: delParams }).then((res) => { - // if (res.status === 204) { - // setOriginFiles(originFiles.filter((file) => file.objectNo === objectNo && file.no !== no)) - // setEstimateContextState({ - // fileList: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no), - // originFiles: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no), - // newFileList: originFiles.filter((file) => file.objectNo === objectNo && file.no !== no), - // }) - - // alert(getMessage('plan.message.delete')) - // } - // }) } //가격표시 option 목록 최초세팅 && 주문분류 변경시 @@ -446,20 +433,6 @@ export default function Estimate({ params }) { } } } - // 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) { updateList.push({ ...item, salePrice: '0', saleTotPrice: '0' }) @@ -624,14 +597,12 @@ export default function Estimate({ params }) { updates.pkgMaterialFlg = res.pkgMaterialFlg updates.pnowW = res.pnowW updates.salePrice = res.salePrice - // updates.salePrice = '' updates.specification = res.specification updates.unit = res.unit updates.specialNoteCd = res.spnAttrCds updates.itemGroup = res.itemGroup updates.delFlg = '0' // 삭제플래그 0 updates.saleTotPrice = (res.salePrice * estimateContextState.itemList[index].amount).toString() - // updates.saleTotPrice = '' updates.amount = '' updates.openFlg = res.openFlg @@ -1153,7 +1124,10 @@ export default function Estimate({ params }) { return (
  • - + handleEstimateFileDownload(originFile)} + > {originFile.faileName} {estimateRecoilState?.docNo !== null && (sessionState.storeId === 'T01' || sessionState.storeLvl === '1') && ( @@ -342,9 +342,13 @@ export default function CanvasMenu(props) { }} > - {getMessage('plan.menu.estimate.copy')} + {getMessage('plan.menu.estimate.copy')} )} +
    )} diff --git a/src/hooks/floorPlan/estimate/useEstimateController.js b/src/hooks/floorPlan/estimate/useEstimateController.js index 63f92832..dea8c9aa 100644 --- a/src/hooks/floorPlan/estimate/useEstimateController.js +++ b/src/hooks/floorPlan/estimate/useEstimateController.js @@ -3,7 +3,7 @@ import { useContext, useEffect, useReducer, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { globalLocaleStore } from '@/store/localeAtom' import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom' -import { isObjectNotEmpty } from '@/util/common-utils' +import { isObjectNotEmpty, isEmptyArray } from '@/util/common-utils' import { SessionContext } from '@/app/SessionProvider' import { useMessage } from '@/hooks/useMessage' import { useRouter } from 'next/navigation' @@ -42,6 +42,12 @@ export const useEstimateController = (planNo) => { } }, []) + useEffect(() => { + if (fileList.length > 0) { + realSave(fileList) + } + }, [fileList]) + // 상세 조회 const fetchSetting = async (objectNo, planNo) => { try { @@ -53,6 +59,7 @@ export const useEstimateController = (planNo) => { item.delFlg = '0' }) } + setEstimateContextState(res.data) } } @@ -149,19 +156,16 @@ export const useEstimateController = (planNo) => { return alert(getMessage('estimate.detail.save.requiredEstimateDate')) } - //첨부파일을 첨부안했는데 - //아이템 fileUploadFlg가1(첨부파일 필수)이 1개라도 있는데 후일 자료 제출(fileFlg) 체크안했으면(0) alert 저장안돼 - // console.log('새로추가첨부파일:::', estimateData.newFileList) - // console.log('기존첨부파일:::', estimateData.originFiles) - - // return - + //기존에 첨부된 파일이 있으면 파일첨부관련 통과 if (estimateData?.originFiles?.length > 0) { originFileFlg = true } if (flag) { if (!originFileFlg) { - if (estimateData.newFileList?.length < 1) { + //기존에 첨부된 파일이 없으면 + // if (estimateData.newFileList?.length < 1) { + if (isEmptyArray(estimateData.newFileList)) { + //새로 첨부한 파일이 없으면 if (estimateData.itemList.length > 1) { estimateData.itemList.map((row) => { if (row.delFlg === '0') { @@ -217,26 +221,7 @@ export const useEstimateController = (planNo) => { } } }) - } - if (flag && fileFlg && itemFlg) { - //1. 첨부파일 저장시작 - const formData = new FormData() - if (estimateData?.newFileList?.length > 0) { - estimateData.newFileList.forEach((file) => { - formData.append('files', file) - }) - formData.append('objectNo', estimateData.objectNo) - formData.append('planNo', estimateData.planNo) - formData.append('category', '10') - formData.append('userId', estimateData.userId) - - await post({ url: '/api/file/fileUpload', data: formData }).then((res) => { - console.log('리턴::::::::::::', res) - }) - } - - //첨부파일저장끝 estimateData.itemList = estimateData.itemList.filter((item) => item.delFlg === '0' || !item.addFlg) let delCnt = 0 @@ -248,66 +233,103 @@ export const useEstimateController = (planNo) => { if (delCnt === estimateData.itemList.length) { return alert(getMessage('estimate.detail.save.requiredItem')) } + } - let option = [] - estimateData.itemList.forEach((item) => { - if (item.specialNoteCd) { - let split2 = item.specialNoteCd.split('、') - option = option.concat(split2) - } - }) - - let estimateOptions = '' - let estimateOptionsArray - estimateData.specialNoteList.map((item) => { - if (item.pkgYn === '0') { - if (item.check) { - if (estimateOptions === '') { - estimateOptions = item.code - } else { - estimateOptions += '、' + item.code - } - } - } else { - if (item.check) { - let flg = '0' - for (let i = 0; i < estimateData.uniqueData.length; i++) { - if (item.code.indexOf(estimateData.uniqueData[i]) > -1) { - flg = '1' - } - if (flg === '1') { - estimateOptions += '、' + estimateData.uniqueData[i] - } - } - } - } - }) - - estimateOptionsArray = estimateOptions.split('、').sort() - estimateOptionsArray = Array.from(new Set(estimateOptionsArray)) - - estimateOptions = estimateOptionsArray.join('、') - - estimateData.estimateOption = estimateOptions - // console.log('첨부파일::::::::', fileList) - // console.log('최종아이템:::', estimateData.itemList) - console.log('최종저장::', estimateData) - //2. 상세데이터 저장 - // return - try { - await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => { - if (res.status === 201) { - alert(getMessage('estimate.detail.save.alertMsg')) - //어디로 보낼지 - fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo) - } + if (flag && fileFlg && itemFlg) { + //1. 첨부파일 저장시작 + const formData = new FormData() + if (estimateData?.newFileList?.length > 0) { + // console.log('새로추가한 첨부파일있음:::', estimateData?.newFileList) + estimateData.newFileList.forEach((file) => { + formData.append('files', file) }) - } catch (e) { - console.log('error::::::::::::', e.response.data.message) + formData.append('objectNo', estimateData.objectNo) + formData.append('planNo', estimateData.planNo) + formData.append('category', '10') + formData.append('userId', estimateData.userId) + + await post({ url: '/api/file/fileUpload', data: formData }).then((res) => { + setFileList(res) + }) + } else { + realSave() } } } + const realSave = async (fileList) => { + //첨부파일저장끝 + + let option = [] + estimateData.itemList.forEach((item) => { + if (item.specialNoteCd) { + let split2 = item.specialNoteCd.split('、') + option = option.concat(split2) + } + }) + + let estimateOptions = '' + let estimateOptionsArray + estimateData.specialNoteList.map((item) => { + if (item.pkgYn === '0') { + if (item.check) { + if (estimateOptions === '') { + estimateOptions = item.code + } else { + estimateOptions += '、' + item.code + } + } + } else { + if (item.check) { + let flg = '0' + for (let i = 0; i < estimateData.uniqueData.length; i++) { + if (item.code.indexOf(estimateData.uniqueData[i]) > -1) { + flg = '1' + } + if (flg === '1') { + estimateOptions += '、' + estimateData.uniqueData[i] + } + } + } + } + }) + + estimateOptionsArray = estimateOptions.split('、').sort() + estimateOptionsArray = Array.from(new Set(estimateOptionsArray)) + + estimateOptions = estimateOptionsArray.join('、') + + estimateData.estimateOption = estimateOptions + // console.log('최종아이템:::', estimateData.itemList) + if (fileList?.length > 0) { + estimateData.fileList = fileList + } else { + estimateData.fileList = [] + } + if (estimateData.originFiles?.length > 0) { + estimateData.deleteFileList = estimateData.originFiles?.filter((item) => item.delFlg === '1') + } else { + estimateData.deleteFileList = [] + } + + console.log('최종저장::', estimateData) + //2. 상세데이터 저장 + // return + try { + await promisePost({ url: `${ESTIMATE_API_ENDPOINT}/save-estimate`, data: estimateData }).then((res) => { + if (res.status === 201) { + estimateData.newFileList = [] + estimateData.originFileList = [] + alert(getMessage('estimate.detail.save.alertMsg')) + //어디로 보낼지 + fetchSetting(objectRecoil.floorPlanObjectNo, estimateData.planNo) + } + }) + } catch (e) { + console.log('error::::::::::::', e.response.data.message) + } + } + /** * 견적서 복사버튼 * (견적서 번호(estimateData.docNo)가 생성된 이후 버튼 활성화 ) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 126f064a..02a13a7d 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -958,120 +958,128 @@ export function useModuleBasicSetting() { const calculateForApi = () => { // TODO : 현재는 남쪽기준. 동,서,북 분기처리 필요 - const centerPoints = [] - const modules = canvas.getObjects().filter((obj) => obj.name === 'module') - modules.forEach((module, index) => { - module.tempIndex = index - const { x, y } = module.getCenterPoint() - const { width, height } = module - centerPoints.push({ x, y, width: Math.abs(width), height: Math.abs(height), index }) - const circle = new fabric.Circle({ - radius: 5, - fill: 'red', - name: 'redCircle', - left: x - 5, - top: y - 5, - index: index, - selectable: false, + const moduleSufaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) + const results = [] + + moduleSufaces.forEach((moduleSurface) => { + const centerPoints = [] + const modules = moduleSurface.modules + + modules.forEach((module, index) => { + module.tempIndex = index + const { x, y } = module.getCenterPoint() + const { width, height } = module + centerPoints.push({ x, y, width: Math.abs(width), height: Math.abs(height), index }) + const circle = new fabric.Circle({ + radius: 5, + fill: 'red', + name: 'redCircle', + left: x - 5, + top: y - 5, + index: index, + selectable: false, + }) + // canvas.add(circle) + }) + + //완전 노출 하면 + let exposedBottom = 0 + // 반 노출 하면 + let exposedHalfBottom = 0 + // 완전 노출 상면 + let exposedTop = 0 + //반 노출 상면 + let exposedHalfTop = 0 + // 완전 접면 + let touchDimension = 0 + //반접면 + let halfTouchDimension = 0 + // 노출하면 체크 + centerPoints.forEach((centerPoint, index) => { + const { x, y, width, height } = centerPoint + // centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인 + const bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y + height)) < 2) + if (bottomCell.length === 1) { + touchDimension++ + return + } + + const bottomLeftPoint = { x: x - width / 2, y: y + height } + const bottomRightPoint = { x: x + width / 2, y: y + height } + + // 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다. + const leftBottomCnt = centerPoints.filter( + (centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < 2 && Math.abs(centerPoint.y - bottomLeftPoint.y) < 2, + ).length + const rightBottomCnt = centerPoints.filter( + (centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < 2 && Math.abs(centerPoint.y - bottomRightPoint.y) < 2, + ).length + if (leftBottomCnt + rightBottomCnt === 2) { + touchDimension++ + return + } + if (leftBottomCnt + rightBottomCnt === 1) { + halfTouchDimension++ + exposedHalfBottom++ + return + } + }) + // 노출상면 체크 + + centerPoints.forEach((centerPoint, index) => { + const { x, y, width, height } = centerPoint + const topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y - height)) < 2) + if (topCell.length === 1) { + return + } + + const topLeftPoint = { x: x - width / 2, y: y - height } + const topRightPoint = { x: x + width / 2, y: y - height } + + const leftTopCnt = centerPoints.filter( + (centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2, + ).length + const rightTopCnt = centerPoints.filter( + (centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2, + ).length + + if (leftTopCnt + rightTopCnt === 1) { + exposedHalfTop++ + return + } + if (leftTopCnt + rightTopCnt === 0) { + exposedTop++ + return + } + }) + // 완전 노출 하면 계산 + + /*const cells = canvas.getObjects().filter((obj) => polygon.id === obj.parentId) + const points = cells.map((cell) => { + return cell.getCenterPoint() + })*/ + const groupPoints = groupCoordinates(centerPoints, modules[0]) + console.log('groupPoints', groupPoints) + groupPoints.forEach((group) => { + // 각 그룹에서 y값이 큰 값을 찾는다. + // 그리고 그 y값과 같은 값을 가지는 centerPoint를 찾는다. + const maxY = group.reduce((acc, cur) => (acc.y > cur.y ? acc : cur)).y + const maxYCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.y - maxY) < 2) + exposedBottom += maxYCenterPoint.length + }) + + results.push({ + exposedBottom, + exposedHalfBottom, + exposedTop, + exposedHalfTop, + touchDimension, + halfTouchDimension, }) - // canvas.add(circle) }) - //완전 노출 하면 - let exposedBottom = 0 - // 반 노출 하면 - let exposedHalfBottom = 0 - // 완전 노출 상면 - let exposedTop = 0 - //반 노출 상면 - let exposedHalfTop = 0 - // 완전 접면 - let touchDimension = 0 - //반접면 - let halfTouchDimension = 0 - // 노출하면 체크 - centerPoints.forEach((centerPoint, index) => { - const { x, y, width, height } = centerPoint - // centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인 - const bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y + height)) < 2) - if (bottomCell.length === 1) { - touchDimension++ - return - } - - const bottomLeftPoint = { x: x - width / 2, y: y + height } - const bottomRightPoint = { x: x + width / 2, y: y + height } - - // 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다. - const leftBottomCnt = centerPoints.filter( - (centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < 2 && Math.abs(centerPoint.y - bottomLeftPoint.y) < 2, - ).length - const rightBottomCnt = centerPoints.filter( - (centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < 2 && Math.abs(centerPoint.y - bottomRightPoint.y) < 2, - ).length - if (leftBottomCnt + rightBottomCnt === 2) { - touchDimension++ - return - } - if (leftBottomCnt + rightBottomCnt === 1) { - halfTouchDimension++ - exposedHalfBottom++ - return - } - }) - // 노출상면 체크 - - centerPoints.forEach((centerPoint, index) => { - const { x, y, width, height } = centerPoint - const topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < 2 && Math.abs(centerPoint.y - (y - height)) < 2) - if (topCell.length === 1) { - return - } - - const topLeftPoint = { x: x - width / 2, y: y - height } - const topRightPoint = { x: x + width / 2, y: y - height } - - const leftTopCnt = centerPoints.filter( - (centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2, - ).length - const rightTopCnt = centerPoints.filter( - (centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < 2 && Math.abs(centerPoint.y - topRightPoint.y) < 2, - ).length - - if (leftTopCnt + rightTopCnt === 1) { - exposedHalfTop++ - return - } - if (leftTopCnt + rightTopCnt === 0) { - exposedTop++ - return - } - }) - // 완전 노출 하면 계산 - - /*const cells = canvas.getObjects().filter((obj) => polygon.id === obj.parentId) - const points = cells.map((cell) => { - return cell.getCenterPoint() - })*/ - const groupPoints = groupCoordinates(centerPoints, modules[0]) - console.log('groupPoints', groupPoints) - groupPoints.forEach((group) => { - // 각 그룹에서 y값이 큰 값을 찾는다. - // 그리고 그 y값과 같은 값을 가지는 centerPoint를 찾는다. - const maxY = group.reduce((acc, cur) => (acc.y > cur.y ? acc : cur)).y - const maxYCenterPoint = group.filter((centerPoint) => Math.abs(centerPoint.y - maxY) < 2) - exposedBottom += maxYCenterPoint.length - }) - - return { - exposedBottom, - exposedHalfBottom, - exposedTop, - exposedHalfTop, - touchDimension, - halfTouchDimension, - } + return results } // polygon 내부 cell들의 centerPoint 배열을 그룹화 해서 반환 diff --git a/src/locales/ja.json b/src/locales/ja.json index 8efb602d..1dea67e7 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -164,6 +164,7 @@ "plan.menu.estimate.save": "保存", "plan.menu.estimate.reset": "初期化", "plan.menu.estimate.copy": "見積書のコピー", + "plan.menu.estimate.unLock": "ロック解除", "plan.menu.simulation": "発展シミュレーション", "plan.menu.simulation.excel": "Excel", "plan.menu.simulation.pdf": "PDF", diff --git a/src/locales/ko.json b/src/locales/ko.json index ad437c99..b1d7c7da 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -168,6 +168,7 @@ "plan.menu.estimate.save": "저장", "plan.menu.estimate.reset": "초기화", "plan.menu.estimate.copy": "견적서 복사", + "plan.menu.estimate.unLock": "잠금 해제", "plan.menu.simulation": "발전 시뮬레이션", "plan.menu.simulation.excel": "Excel", "plan.menu.simulation.pdf": "PDF",