diff --git a/src/app/management/stuff/detail/page.jsx b/src/app/management/stuff/detail/page.jsx index 8c7dd731..7c5b0b0e 100644 --- a/src/app/management/stuff/detail/page.jsx +++ b/src/app/management/stuff/detail/page.jsx @@ -3,6 +3,8 @@ import '@/styles/contents.scss' import StuffSubHeader from '@/components/management/StuffSubHeader' import StuffHeader from '@/components/management/StuffHeader' import StuffDetail from '@/components/management/StuffDetail' +import '@/styles/contents.scss' +import '@/styles/grid.scss' export default function ManagementStuffDetailPage() { return ( <> diff --git a/src/app/management/stuff/page.jsx b/src/app/management/stuff/page.jsx index eb852712..414f377b 100644 --- a/src/app/management/stuff/page.jsx +++ b/src/app/management/stuff/page.jsx @@ -1,7 +1,7 @@ import StuffSearchCondition from '@/components/management/StuffSearchCondition' import Stuff from '@/components/management/Stuff' import StuffSubHeader from '@/components/management/StuffSubHeader' -import '@/styles/contents.scss' +import '@/styles/grid.scss' export default async function ManagementStuffPage() { return ( <> diff --git a/src/components/common/font/FontSetting.jsx b/src/components/common/font/FontSetting.jsx index d738d016..cbb2de00 100644 --- a/src/components/common/font/FontSetting.jsx +++ b/src/components/common/font/FontSetting.jsx @@ -1,8 +1,11 @@ import WithDraggable from '@/components/common/draggable/WithDraggable' import QSelectBox from '@/components/common/select/QSelectBox' import { usePopup } from '@/hooks/usePopup' -import { useState } from 'react' +import { useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' +import { useRecoilState, useRecoilValue } from 'recoil' +import { fontSelector, globalFontAtom } from '@/store/fontAtom' +import { useFont } from '@/hooks/common/useFont' const fonts = [ { name: 'MS PGothic', value: 'MS PGothic' }, @@ -43,19 +46,38 @@ const fontColors = [ { name: '남색', value: 'darkblue' }, ] export default function FontSetting(props) { - const { id, setIsShow, font, setFont, fontSize, setFontSize, pos = { x: 455, y: 180 } } = props + const { id, setIsShow, pos = { x: 455, y: 180 }, type } = props const { getMessage } = useMessage() const { closePopup } = usePopup() - const [originFont, setOriginFont] = useState(font) - const [originFontSize, setOriginFontSize] = useState(fontSize) - const [selectedFont, setSelectedFont] = useState(font ? font : fonts[0]) - const [selectedFontSize, setSelectedFontSize] = useState(fontSize ? fontSize : fontSizes[0]) - const [selectedFontColor, setSelectedFontColor] = useState(null) + const [globalFont, setGlobalFont] = useRecoilState(globalFontAtom) + const currentFont = useRecoilValue(fontSelector(type)) + + const [selectedFont, setSelectedFont] = useState(currentFont.fontFamily) + const [selectedFontWeight, setSelectedFontWeight] = useState(currentFont.fontWeight) + const [selectedFontSize, setSelectedFontSize] = useState(currentFont.fontSize) + const [selectedFontColor, setSelectedFontColor] = useState(currentFont.fontColor) + + const handleSaveBtn = () => { + setGlobalFont((prev) => { + return { + ...prev, + [type]: { + fontFamily: selectedFont, + fontSize: selectedFontSize, + fontColor: selectedFontColor, + fontWeight: selectedFontWeight, + }, + } + }) + setIsShow(false) + closePopup(id) + } + return (
-

{getMessage('modal.font')}

+

{getMessage('modal.font')}

diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index 7700ae42..7b4e2196 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -57,11 +57,10 @@ export const QLine = fabric.util.createClass(fabric.Line, { }) this.on('removed', () => { - const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id) - if (thisText) { - this.canvas.remove(thisText) - } - this.text = null + const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id) + children.forEach((child) => { + this.canvas.remove(child) + }) }) }, diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index d982a49a..76c8dd6c 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -132,22 +132,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) this.on('removed', () => { - const thisText = this.canvas.getObjects().filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id) - thisText.forEach((text) => { - this.canvas.remove(text) + const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id) + children.forEach((child) => { + this.canvas.remove(child) }) - this.texts = null - - if (this.arrow) { - this.canvas.remove(this.arrow) - this.canvas - .getObjects() - .filter((obj) => obj.name === 'directionText' && obj.parent === this.arrow) - .forEach((text) => { - this.canvas.remove(text) - }) - this.arrow = null - } }) // polygon.fillCell({ width: 50, height: 30, padding: 10 }) diff --git a/src/components/floor-plan/modal/setting01/SecondOption.jsx b/src/components/floor-plan/modal/setting01/SecondOption.jsx index 40463296..ceccce5e 100644 --- a/src/components/floor-plan/modal/setting01/SecondOption.jsx +++ b/src/components/floor-plan/modal/setting01/SecondOption.jsx @@ -1,4 +1,4 @@ -import { useRecoilState, useSetRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { settingModalFirstOptionsState, settingModalSecondOptionsState } from '@/store/settingAtom' import { useMessage } from '@/hooks/useMessage' import React, { useEffect, useState } from 'react' @@ -28,7 +28,6 @@ export default function SecondOption() { const [showFontSettingModal, setShowFontSettingModal] = useState(false) const [showDimensionLineSettingModal, setShowDimensionLineSettingModal] = useState(false) const [showPlanSizeSettingModal, setShowPlanSizeSettingModal] = useState(false) - const dimensionSettings = useRecoilValue(dimensionLineSettingsState) // 데이터를 최초 한 번만 조회 @@ -203,12 +202,34 @@ export default function SecondOption() { } break - case 'font1': //문자 글꼴변경 - case 'font2': //흐름 방향 글꼴 변경 - case 'font3': //치수 글꼴변경 + case 'font1': { + //문자 글꼴변경 + setShowFontSettingModal(true) + fontProps.type = 'commonText' + fontProps.id = fontId + 1 + addPopup(fontId + 1, 2, ) + break + } + case 'font2': { + //흐름 방향 글꼴 변경 + setShowFontSettingModal(true) + fontProps.type = 'flowText' + fontProps.id = fontId + 2 + addPopup(fontId + 2, 2, ) + break + } + case 'font3': { + //치수 글꼴변경 + setShowFontSettingModal(true) + fontProps.type = 'lengthText' + fontProps.id = fontId + 3 + addPopup(fontId + 3, 2, ) + break + } case 'font4': //회로번호 글꼴변경 setShowFontSettingModal(true) - + fontProps.type = 'circuitNumberText' + fontProps.id = fontId addPopup(fontId, 2, ) break case 'planSize': diff --git a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx index aae246dc..2afbd184 100644 --- a/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx +++ b/src/components/floor-plan/modal/setting01/dimensionLine/DimensionLineSetting.jsx @@ -92,6 +92,7 @@ export default function DimensionLineSetting(props) { x: 455, y: 180, }, + type: 'dimensionLineText', } const popupHandle = (type) => { switch (type) { diff --git a/src/components/management/Stuff.jsx b/src/components/management/Stuff.jsx index 07119205..b5297420 100644 --- a/src/components/management/Stuff.jsx +++ b/src/components/management/Stuff.jsx @@ -16,7 +16,6 @@ import { appMessageStore, globalLocaleStore } from '@/store/localeAtom' import KO from '@/locales/ko.json' import JA from '@/locales/ja.json' import QPagination from '../common/pagination/QPagination' -import '@/styles/grid.scss' import { sessionStore } from '@/store/commonAtom' export default function Stuff() { diff --git a/src/components/management/StuffDetail.jsx b/src/components/management/StuffDetail.jsx index fd01fc41..5d49bc06 100644 --- a/src/components/management/StuffDetail.jsx +++ b/src/components/management/StuffDetail.jsx @@ -16,6 +16,7 @@ import FindAddressPop from './popup/FindAddressPop' import PlanRequestPop from './popup/PlanRequestPop' import WindSelectPop from './popup/WindSelectPop' import { useCommonCode } from '@/hooks/common/useCommonCode' +import StuffPlanQGrid from './StuffPlanQGrid' export default function StuffDetail() { //공통코드 @@ -31,12 +32,12 @@ export default function StuffDetail() { const { getMessage } = useMessage() const globalLocaleState = useRecoilValue(globalLocaleStore) const ref = useRef() - const { get, del, promisePost, promisePut } = useAxios(globalLocaleState) + const { get, promiseGet, del, promisePost, promisePut } = useAxios(globalLocaleState) //form const formInitValue = { // 물건번호 T...(임시) R...(진짜) planReqNo: '', //설계의뢰No - dispCompanyName: '', //담당자 + receiveUser: '', //담당자 objectStatusId: '0', //물건구분(신축:0 기축 : 1) objectName: '', //물건명 objectNameOmit: '', //경칭선택 @@ -91,6 +92,173 @@ export default function StuffDetail() { const [editMode, setEditMode] = useState('NEW') const [detailData, setDetailData] = useState({}) + const [planGridProps, setPlanGridProps] = useState({ + planGridData: [], + isPageable: false, + planGridColumns: [ + { + field: 'planNo', + headerName: getMessage('stuff.detail.planGridHeader.planNo'), + width: 100, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'orderFlg', + headerName: getMessage('stuff.detail.planGridHeader.orderFlg'), + width: 80, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + //1일때만 동그라미 + let orderFlg + orderFlg = params.value === '1' ? 'O' : 'X' + return orderFlg + }, + }, + { + field: 'moduleModel', + headerName: getMessage('stuff.detail.planGridHeader.moduleModel'), + flex: 1, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'capacity', + headerName: getMessage('stuff.detail.planGridHeader.capacity'), + width: 120, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + }, + { + field: 'roofMaterialIdMulti', + headerName: getMessage('stuff.detail.planGridHeader.roofMaterialIdMulti'), + width: 140, + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
+ + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'constructSpecification', + headerName: getMessage('stuff.detail.planGridHeader.constructSpecification'), + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
+ + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'supportMethodIdMulti', + headerName: getMessage('stuff.detail.planGridHeader.supportMethodIdMulti'), + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
+ + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'pcTypeNo', + headerName: getMessage('stuff.detail.planGridHeader.pcTypeNo'), + flex: 1, + wrapText: true, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: (params) => { + let origin = params.value + if (origin !== null) { + return ( + <> + {origin?.split(',').map((it) => ( + <> + {it} +
+ + ))} + + ) + } else { + return null + } + }, + }, + { + field: 'management', + headerName: getMessage('stuff.detail.planGridHeader.management'), + width: 200, + autoHeight: true, + cellStyle: { display: 'flex', justifyContent: 'center', alignItems: 'center' }, + cellRenderer: () => { + return ( +
+ + +
+ ) + }, + }, + ], + }) + useEffect(() => { // console.log('objectNo::', objectNo) @@ -101,9 +269,22 @@ export default function StuffDetail() { //진짜 setIsFormValid(true) } - get({ url: `/api/object/${objectNo}/detail` }).then((res) => { - if (res != null) { - setDetailData(res) + promiseGet({ url: `/api/object/${objectNo}/detail` }).then((res) => { + if (res.status === 200) { + if (res.data != null) { + setDetailData(res.data) + } else { + setDetailData({}) + } + if (isNotEmptyArray(res.data.planList)) { + // console.log('플랜RES::::::::', res.data.planList) + setPlanGridProps({ ...planGridProps, planGridData: res.data.planList }) + } else { + setPlanGridProps({ ...planGridProps, planGridData: [] }) + } + } else { + setDetailData({}) + setPlanGridProps({ ...planGridProps, planGridData: [] }) } }) } else { @@ -187,7 +368,7 @@ export default function StuffDetail() { //설계의뢰No. form.setValue('planReqNo', detailData.planReqNo) //담당자 - form.setValue('dispCompanyName', detailData.dispCompanyName) + form.setValue('receiveUser', detailData.receiveUser) //물건구분objectStatusId setSelectObjectStatusId(detailData.objectStatusId) @@ -197,7 +378,6 @@ export default function StuffDetail() { form.setValue('objectName', detailData.objectName) //경칭코드 - setSelHonorificCode(detailData.objectNameOmit) form.setValue('objectNameOmit', detailData.objectNameOmit) @@ -217,7 +397,32 @@ export default function StuffDetail() { // form.setValue('otherSaleStoreId', sessionState?.storeId) // form.setValue('otherSaleStoreLevel', sessionState?.storeLvl) + //우편번호 form.setValue('zipNo', detailData.zipNo) + + //도도부현 / 주소 + setPrefValue(detailData.prefId) + form.setValue('prefId', detailData.prefId) + //prefName ??? + form.setValue('address', detailData.address) + + //수직적설량 + form.setValue('verticalSnowCover', detailData.verticalSnowCover) + //한랭지대책시행 coldRegionFlg 1이면 true + form.setValue('coldRegionFlg', detailData.coldRegionFlg === '1' ? true : false) + + //면조도구분surfaceType + // form.setValue('surfaceType', 'Ⅱ') + // form.setValue('surfaceType', 'III・IV') + form.setValue('surfaceType', detailData.surfaceType) + //염해지역용아이템사용 saltAreaFlg 1이면 true + form.setValue('saltAreaFlg', detailData.saltAreaFlg === '1' ? true : false) + //설치높이 + form.setValue('installHeight', detailData.installHeight) + //계약조건 + form.setValue('conType', detailData.conType) + //메모 + form.setValue('remarks', detailData.remarks) }) } }, [detailData, sessionState]) @@ -414,8 +619,8 @@ export default function StuffDetail() { form.setValue('standardWindSpeedId', info.windSpeed) } - //dispCompanyName: '', //담당자 - const _dispCompanyName = watch('dispCompanyName') + //receiveUser: '', //담당자 + const _receiveUser = watch('receiveUser') //objectName: '', //물건명 const _objectName = watch('objectName') // objectNameOmit: '', //경칭선택 @@ -441,8 +646,8 @@ export default function StuffDetail() { if (editMode === 'NEW') { const formData = form.getValues() let errors = {} - if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { - errors.dispCompanyName = true + if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { + errors.receiveUser = true } if (!formData.objectName || formData.objectName.trim().length === 0) { errors.objectName = true @@ -483,8 +688,8 @@ export default function StuffDetail() { console.log('상세일때 폼체크') const formData = form.getValues() let errors = {} - if (!formData.dispCompanyName || formData.dispCompanyName.trim().length === 0) { - errors.dispCompanyName = true + if (!formData.receiveUser || formData.receiveUser.trim().length === 0) { + errors.receiveUser = true } if (!formData.objectName || formData.objectName.trim().length === 0) { errors.objectName = true @@ -524,7 +729,7 @@ export default function StuffDetail() { setIsFormValid(Object.keys(errors).length === 0 ? true : false) } }, [ - _dispCompanyName, + _receiveUser, _objectName, _objectNameOmit, _saleStoreId, @@ -592,14 +797,14 @@ export default function StuffDetail() { prefName: formData.prefName, address: formData.address, areaId: formData.areaId, - receiveUser: formData.dispCompanyName, + receiveUser: formData.receiveUser, installHeight: formData.installHeight, standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, - coldRegionFlg: formData.coldRegionFlg, - saltAreaFlg: formData.saltAreaFlg, + coldRegionFlg: formData.coldRegionFlg === true ? '1' : '0', + saltAreaFlg: formData.saltAreaFlg === true ? '1' : '0', tempFlg: '0', workNo: null, workName: null, @@ -623,13 +828,6 @@ export default function StuffDetail() { } } - //필수값 안넣었을때 임시저장 form required사용시 - // const onInvalid = (errors) => { - // console.log('22222222222222222222222') - // const formData = form.getValues() - // console.log('임시저장formData::::', formData) - // } - // 임시저장 const onTempSave = async () => { const formData = form.getValues() @@ -646,14 +844,14 @@ export default function StuffDetail() { prefName: formData.prefName, address: formData.address, areaId: formData.areaId, - receiveUser: formData.dispCompanyName, + receiveUser: formData.receiveUser, installHeight: formData.installHeight, standardWindSpeedId: formData.standardWindSpeedId, verticalSnowCover: formData.verticalSnowCover, surfaceType: formData.surfaceType, conType: formData.conType, - coldRegionFlg: formData.coldRegionFlg, - saltAreaFlg: formData.saltAreaFlg, + coldRegionFlg: formData.coldRegionFlg === true ? '1' : '0', + saltAreaFlg: formData.saltAreaFlg === true ? '1' : '0', tempFlg: '1', workNo: null, workName: null, @@ -685,7 +883,7 @@ export default function StuffDetail() { } else { if (confirm(getMessage('common.message.data.delete'))) { del({ url: `/api/object/${objectNo}` }).then((res) => { - console.log('삭제결과:::::::', res) + // console.log('삭제결과:::::::', res) router.push('/management/stuff') }) } @@ -743,7 +941,7 @@ export default function StuffDetail() {
- +
@@ -881,7 +1079,7 @@ export default function StuffDetail() { @@ -968,7 +1166,6 @@ export default function StuffDetail() {
- {/* 기준풍속sel시작 */}
- {/* 기준풍속sel끝 */} {getMessage('stuff.detail.windSpeedSpan')} -
@@ -1007,7 +1203,7 @@ export default function StuffDetail() { type="text" className="input-light" onKeyUp={handleKeyUp} - value={form.watch('verticalSnowCover')} + value={form.watch('verticalSnowCover') || ''} {...register('verticalSnowCover')} />
@@ -1037,7 +1233,9 @@ export default function StuffDetail() { -
+
+ {getMessage('stuff.detail.tooltip.surfaceType')} +
@@ -1052,7 +1250,7 @@ export default function StuffDetail() { type="text" className="input-light" onKeyUp={handleKeyUp} - value={form.watch('installHeight')} + value={form.watch('installHeight') || ''} {...register('installHeight')} /> @@ -1151,12 +1349,7 @@ export default function StuffDetail() {
- +
@@ -1224,7 +1417,9 @@ export default function StuffDetail() { {getMessage('stuff.detail.saleStoreId')} * -
+
+ {getMessage('stuff.detail.tooltip.saleStoreId')} +
@@ -1250,7 +1445,7 @@ export default function StuffDetail() { @@ -1292,7 +1487,7 @@ export default function StuffDetail() { @@ -1317,29 +1512,203 @@ export default function StuffDetail() { {/* 도도부현 /주소 시작*/} + + + {getMessage('stuff.detail.prefId')} + * + + +
+
+ {prefCodeList?.length > 0 && ( + +
+
+ + {/* 도도부현 /주소 끝 */} {/* 발전량시뮬레이션지역시작 */} + + + {getMessage('stuff.detail.areaId')} * + + +
+ x.clCodeNm} + getOptionValue={(x) => x.clCode} + isClearable={true} + isSearchable={false} + value={windSpeedList.filter(function (option) { + return option.clCode === watch('standardWindSpeedId') + })} + > +
+ {getMessage('stuff.detail.windSpeedSpan')} + + + + {/* 기준풍속끝 */} {/* 수직적설량시작 */} + + + {getMessage('stuff.detail.verticalSnowCover')} * + + +
+
+ +
+ cm +
+ + +
+
+ + {/* 수직적설량끝 */} {/* 면조도구분시작 */} + + + {getMessage('stuff.detail.surfaceType')} * + + +
+
+ + +
+
+ + +
+
+ + +
+
+ {getMessage('stuff.detail.tooltip.surfaceType')} +
+
+ + {/* 면조도구분끝 */} - {/* 설치높이싲가 */} + {/* 설치높이시작 */} + + + {getMessage('stuff.detail.installHeight')} * + + +
+
+ +
+ m +
+ + {/* 설치높이끝 */} {/* 계약조건시작 */} + + {getMessage('stuff.detail.conType')} + +
+
+ + +
+
+ + +
+
+ + {/* 계약조건끝 */} {/* 메모시작 */} - {/* 메모끝 */} - + {getMessage('stuff.detail.remarks')} + +
+ +
+ + {/* 메모끝 */} - {objectNo.substring(0, 1) === 'R' ? ( <> {/* 진짜R 플랜시작 */} @@ -1349,7 +1718,7 @@ export default function StuffDetail() { @@ -1367,8 +1736,8 @@ export default function StuffDetail() {
- 그리드영역 -
페이징영역
+ + {/*
페이징영역
*/}
{/* 진짜R 플랜끝 */} diff --git a/src/components/management/StuffPlanQGrid.jsx b/src/components/management/StuffPlanQGrid.jsx new file mode 100644 index 00000000..b4108342 --- /dev/null +++ b/src/components/management/StuffPlanQGrid.jsx @@ -0,0 +1,51 @@ +import { useState, useMemo, useCallback, useEffect } from 'react' +import { AgGridReact } from 'ag-grid-react' +import 'ag-grid-community/styles/ag-grid.css' +import 'ag-grid-community/styles/ag-theme-quartz.css' +export default function StuffPlanQGrid(props) { + const { planGridData, planGridColumns, isPageable = true } = props + + const [rowData, setRowData] = useState(null) + const [gridApi, setGridApi] = useState(null) + const [colDefs, setColDefs] = useState(planGridColumns) + + const defaultColDef = useMemo(() => { + return { + flex: 1, + minWidth: 100, + sortable: false, + suppressMovable: false, + resizable: false, + suppressSizeToFit: false, + } + }, []) + + const rowBuffer = 100 + + useEffect(() => { + planGridData ? setRowData(planGridData) : '' + }, [planGridData]) + + const onGridReady = useCallback( + (params) => { + setGridApi(params.api) + planGridData ? setRowData(planGridData) : '' + }, + [planGridData], + ) + + return ( +
+ +
+ ) +} diff --git a/src/hooks/common/useFont.js b/src/hooks/common/useFont.js new file mode 100644 index 00000000..383997a0 --- /dev/null +++ b/src/hooks/common/useFont.js @@ -0,0 +1,51 @@ +import { useRecoilValue } from 'recoil' +import { canvasState } from '@/store/canvasAtom' +import { fontSelector, globalFontAtom } from '@/store/fontAtom' +import { useEffect } from 'react' + +export function useFont() { + const canvas = useRecoilValue(canvasState) + const commonText = useRecoilValue(fontSelector('commonText')) + const dimensionLineText = useRecoilValue(fontSelector('dimensionLineText')) + const flowText = useRecoilValue(fontSelector('flowText')) + const lengthText = useRecoilValue(fontSelector('lengthText')) + const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText')) + + useEffect(() => {}, [commonText]) + + useEffect(() => {}, [dimensionLineText]) + + useEffect(() => { + if (canvas) { + const textObjs = canvas.getObjects().filter((obj) => obj.name === 'flowText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: flowText.fontFamily.value, + fontWeight: flowText.fontWeight.value, + fontSize: flowText.fontSize.value, + fill: flowText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [flowText]) + + useEffect(() => { + if (canvas) { + const textObjs = canvas.getObjects().filter((obj) => obj.name === 'lengthText') + textObjs.forEach((obj) => { + obj.set({ + fontFamily: lengthText.fontFamily.value, + fontWeight: lengthText.fontWeight.value, + fontSize: lengthText.fontSize.value, + fill: lengthText.fontColor.value, + }) + }) + canvas.renderAll() + } + }, [lengthText]) + + useEffect(() => {}, [circuitNumberText]) + + return {} +} diff --git a/src/hooks/option/useFirstOption.js b/src/hooks/option/useFirstOption.js index 4010b69e..5a4605e9 100644 --- a/src/hooks/option/useFirstOption.js +++ b/src/hooks/option/useFirstOption.js @@ -11,12 +11,67 @@ export function useFirstOption() { useEffect(() => { const option1 = settingModalFirstOptions.option1 - canvas - .getObjects() - .filter((obj) => obj.name === '') - .forEach((obj) => { - obj.set({ visible: !obj.visible }) - }) + // 'allocDisplay' 할당 표시 + // 'outlineDisplay' 외벽선 표시 'outerLine', 'wallLine' + // 'gridDisplay' 그리드 표시 'lindGrid', 'dotGrid' + // 'lineDisplay' 지붕선 표시 'roof', 'roofBase' + // 'wordDisplay' 문자 표시 + // 'circuitNumDisplay' 회로번호 표시 + // 'flowDisplay' 흐름방향 표시 'arrow' + // 'trestleDisplay' 가대 표시 + // 'totalDisplay' 집계표 표시 + + let optionName //옵션명 + let optionSelected //옵션상태 + + for (let i = 0; i < option1.length; i++) { + switch (option1[i].column) { + case 'allocDisplay': //할당 표시 + optionName = ['1'] + break + case 'outlineDisplay': //외벽선 표시 + optionName = ['outerLine', 'wallLine'] + break + case 'gridDisplay': //그리드 표시 + optionName = ['lindGrid', 'dotGrid'] + break + case 'lineDisplay': //지붕선 표시 + optionName = ['roof', 'roofBase'] + break + case 'wordDisplay': //문자 표시 + optionName = ['6'] + break + case 'circuitNumDisplay': //회로번호 표시 + optionName = ['7'] + break + case 'flowDisplay': //흐름방향 표시 + optionName = ['arrow'] + break + case 'trestleDisplay': //가대 표시 + optionName = ['8'] + break + case 'totalDisplay': //집계표 표시 + optionName = ['9'] + break + } + // 표시 선택 상태(true/false) + optionSelected = option1[i].selected + + canvas + .getObjects() + .filter((obj) => optionName.includes(obj.name)) + //.filter((obj) => obj.name === optionName) + .forEach((obj) => { + obj.set({ visible: optionSelected }) + //obj.set({ visible: !obj.visible }) + }) + + // console.log( + // 'optionName', + // optionName, + // canvas.getObjects().filter((obj) => optionName.includes(obj.name)), + // ) + } }, [settingModalFirstOptions]) return { settingModalFirstOptions, setSettingModalFirstOptions } diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index 5ab18a40..39294260 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -241,7 +241,8 @@ export function useAuxiliaryDrawing(id) { const x = lastPoint.x + length * Math.cos(radian) const y = lastPoint.y - length * Math.sin(radian) - return [...prev, { x, y }] + mousePointerArr.current.push({ x, y }) + drawLine() } } }, diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index a33c0de2..17f00eea 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -13,6 +13,7 @@ import { writeImage } from '@/lib/canvas' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { useAxios } from '@/hooks/useAxios' import { v4 as uuidv4 } from 'uuid' +import { useFont } from '@/hooks/common/useFont' export function useCanvas(id) { const [canvas, setCanvas] = useRecoilState(canvasState) @@ -23,6 +24,7 @@ export function useCanvas(id) { const [fontSize] = useRecoilState(fontSizeState) const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() const { post } = useAxios() + const {} = useFont() /** * 처음 셋팅 @@ -92,6 +94,7 @@ export function useCanvas(id) { // settings for all canvas in the app fabric.Object.prototype.transparentCorners = false fabric.Object.prototype.id = uuidv4() + fabric.Object.prototype.uuid = uuidv4() fabric.Object.prototype.selectable = true fabric.Object.prototype.lockMovementX = true fabric.Object.prototype.lockMovementY = true diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 4f041e79..bf878c7b 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,5 +1,6 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' +import { v4 as uuidv4 } from 'uuid' import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' @@ -32,7 +33,9 @@ export function useCanvasEvent() { const objectEvent = { onChange: (e) => { const target = e.target + if (target) { + target.uuid = uuidv4() // settleDown(target) } }, diff --git a/src/hooks/usePlan.js b/src/hooks/usePlan.js index 166ff738..26d26339 100644 --- a/src/hooks/usePlan.js +++ b/src/hooks/usePlan.js @@ -62,6 +62,7 @@ export function usePlan() { 'stickeyPoint', 'text', 'pitch', + 'uuid', ]) const str = JSON.stringify(objs) @@ -108,16 +109,16 @@ export function usePlan() { return JSON.parse(canvasStatus).objects.length > 0 } else { // 저장된 캔버스 - // 각각 object들의 id 목록을 추출하여 비교 - const canvasObjsIds = getObjectIds(JSON.parse(canvasStatus).objects) - const dbObjsIds = getObjectIds(JSON.parse(initPlanData.canvasStatus).objects) - return canvasObjsIds.length !== dbObjsIds.length || !canvasObjsIds.every((id, index) => id === dbObjsIds[index]) + // 각각 object들의 uuid 목록을 추출하여 비교 + const canvasObjsUuids = getObjectUuids(JSON.parse(canvasStatus).objects) + const dbObjsUuids = getObjectUuids(JSON.parse(initPlanData.canvasStatus).objects) + return canvasObjsUuids.length !== dbObjsUuids.length || !canvasObjsUuids.every((id, index) => id === dbObjsUuids[index]) } } - const getObjectIds = (objects) => { + const getObjectUuids = (objects) => { return objects - .filter((obj) => obj.hasOwnProperty('id')) - .map((obj) => obj.id) + .filter((obj) => obj.hasOwnProperty('uuid')) + .map((obj) => obj.uuid) .sort() } /** @@ -201,7 +202,6 @@ export function usePlan() { ), ) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) - swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) @@ -223,7 +223,6 @@ export function usePlan() { ) setPlans((plans) => plans.map((plan) => (plan.id === currentCanvasPlan.id ? { ...plan, canvasStatus: canvasStatus } : plan))) setModifiedPlans((modifiedPlans) => modifiedPlans.filter((planId) => planId !== currentCanvasPlan.id)) - swalFire({ text: getMessage('plan.message.save') }) }) .catch((error) => { swalFire({ text: error.message, icon: 'error' }) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index a976c0aa..71e49408 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -114,7 +114,7 @@ export const usePolygon = () => { polygon.canvas .getObjects() - .filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow) + .filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow) .forEach((obj) => polygon.canvas.remove(obj)) let arrow = null @@ -190,7 +190,7 @@ export const usePolygon = () => { break } - arrow = new fabric.Polygon(points, { + arrow = new QPolygon(points, { selectable: false, name: 'arrow', fill: 'transparent', @@ -200,8 +200,10 @@ export const usePolygon = () => { stickeyPoint: stickeyPoint, visible: isFlowDisplay, pitch: polygon.pitch, + parentId: polygon.id, }) + arrow.setViewLengthText(false) polygon.arrow = arrow polygon.canvas.add(arrow) polygon.canvas.renderAll() @@ -383,7 +385,7 @@ export const usePolygon = () => { westText = '西北西' } - clearDirectionText(canvas) + clearFlowText(canvas) addTextByArrows(eastArrows, eastText, canvas) addTextByArrows(westArrows, westText, canvas) @@ -391,8 +393,8 @@ export const usePolygon = () => { addTextByArrows(southArrows, southText, canvas) } - const clearDirectionText = (canvas) => { - const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') + const clearFlowText = (canvas) => { + const texts = canvas.getObjects().filter((obj) => obj.name === 'flowText') texts.forEach((text) => { canvas.remove(text) }) @@ -405,11 +407,12 @@ export const usePolygon = () => { fill: 'black', originX: 'center', originY: 'center', - name: 'directionText', + name: 'flowText', selectable: false, left: arrow.stickeyPoint.x, top: arrow.stickeyPoint.y, parent: arrow, + parentId: arrow.id, visible: isFlowDisplay, }) canvas.add(text) diff --git a/src/locales/ja.json b/src/locales/ja.json index 359d313e..521f4ac6 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -502,6 +502,7 @@ "stuff.detail.conType1": "全量", "stuff.detail.remarks": "メモ", "stuff.detail.tooltip.saleStoreId": "販売代理店または販売代理店IDを1文字以上入力してください", + "stuff.detail.tooltip.surfaceType": "塩害地域の定義は各メーカーの設置マニュアルをご確認ください", "stuff.detail.tempSave.message1": "一時保存されました。商品番号を取得するには、必須項目をすべて入力してください。", "stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?", "stuff.detail.delete.message1": "仕様が確定したものは削除できません。", @@ -566,6 +567,17 @@ "stuff.windSelectPopup.search.address1": "県", "stuff.windSelectPopup.btn1": "閉じる", "stuff.windSelectPopup.btn2": "選択", + "stuff.detail.planGridHeader.planNo": "プラン番号", + "stuff.detail.planGridHeader.orderFlg": "発注可", + "stuff.detail.planGridHeader.moduleModel": "モジュール", + "stuff.detail.planGridHeader.capacity": "システム容量", + "stuff.detail.planGridHeader.roofMaterialIdMulti": "屋根材", + "stuff.detail.planGridHeader.constructSpecification": "施工方法", + "stuff.detail.planGridHeader.supportMethodIdMulti": "架台", + "stuff.detail.planGridHeader.pcTypeNo": "パワーコンディショナー", + "stuff.detail.planGridHeader.management": "管理", + "stuff.detail.planGrid.btn1": "見積書の照会", + "stuff.detail.planGrid.btn2": "Excel", "length": "長さ", "height": "高さ", "output": "出力", diff --git a/src/locales/ko.json b/src/locales/ko.json index fe228f22..693d94b4 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -507,6 +507,7 @@ "stuff.detail.conType1": "전량", "stuff.detail.remarks": "메모", "stuff.detail.tooltip.saleStoreId": "판매대리점 또는 판매대리점ID를 1자 이상 입력하세요", + "stuff.detail.tooltip.surfaceType": "염해지역 정의는 각 메이커의 설치 메뉴얼을 확인해주십시오", "stuff.detail.tempSave.message1": "임시저장 되었습니다. 물건번호를 획득하려면 필수 항목을 모두 입력해 주십시오.", "stuff.detail.confirm.message1": "판매점 정보를 변경하면, 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", "stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.", @@ -571,6 +572,17 @@ "stuff.windSelectPopup.search.address1": "현", "stuff.windSelectPopup.btn1": "닫기", "stuff.windSelectPopup.btn2": "선택", + "stuff.detail.planGridHeader.planNo": "플랜번호", + "stuff.detail.planGridHeader.orderFlg": "발주여부", + "stuff.detail.planGridHeader.moduleModel": "모듈", + "stuff.detail.planGridHeader.capacity": "시스템용량", + "stuff.detail.planGridHeader.roofMaterialIdMulti": "지붕재", + "stuff.detail.planGridHeader.constructSpecification": "시공방법", + "stuff.detail.planGridHeader.supportMethodIdMulti": "가대", + "stuff.detail.planGridHeader.pcTypeNo": "파워컨디셔너", + "stuff.detail.planGridHeader.management": "관리", + "stuff.detail.planGrid.btn1": "견적서 조회", + "stuff.detail.planGrid.btn2": "Excel", "length": "길이", "height": "높이", "output": "출력", diff --git a/src/store/fontAtom.js b/src/store/fontAtom.js new file mode 100644 index 00000000..1bf0df80 --- /dev/null +++ b/src/store/fontAtom.js @@ -0,0 +1,29 @@ +import { atom, selectorFamily } from 'recoil' + +const defaultFont = { + fontFamily: { name: 'MS PGothic', value: 'MS PGothic' }, + fontWeight: { name: '보통', value: 'normal' }, + fontSize: { name: '16', value: '16' }, + fontColor: { name: '검정색', value: 'black' }, +} + +export const globalFontAtom = atom({ + key: 'fontAtom', + default: { + commonText: defaultFont, + dimensionLineText: defaultFont, + flowText: defaultFont, + lengthText: defaultFont, + circuitNumberText: defaultFont, + }, +}) + +export const fontSelector = selectorFamily({ + key: 'fontSelector', + get: + (type) => + ({ get }) => { + const fontAtom = get(globalFontAtom) + return fontAtom[type] + }, +})