Merge branch 'dev' of ssh://git.jetbrains.space/nalpari/q-cast-iii/qcast-front into qcast-pub

# Conflicts:
#	src/components/floor-plan/CanvasMenu.jsx
This commit is contained in:
김민식 2025-03-05 14:10:58 +09:00
commit ad37a2465d
15 changed files with 104 additions and 49 deletions

View File

@ -12,10 +12,12 @@ export default function QPagination(props) {
return ( return (
<ol className="pagination"> <ol className="pagination">
<li className="page-item first"> <li className="page-item first">
<button onClick={() => handlePage(1)}></button> <button type="button" disabled={currentPage === 1} onClick={() => handlePage(1)}></button>
</li> </li>
<li className="page-item prev"> <li className="page-item prev">
<button <button
type="button"
disabled={currentPage <= 1}
onClick={() => { onClick={() => {
if (currentPage === 1) return if (currentPage === 1) return
handlePage(Math.max(1, (pageGroup - 2) * pagePerBlock + 1)) handlePage(Math.max(1, (pageGroup - 2) * pagePerBlock + 1))
@ -24,11 +26,15 @@ export default function QPagination(props) {
</li> </li>
{pageRange.map((page) => ( {pageRange.map((page) => (
<li className={page === currentPage ? `page-item on` : `page-item`} key={page}> <li className={page === currentPage ? `page-item on` : `page-item`} key={page}>
<button onClick={() => handlePage(page)}>{page}</button> <button type="button" onClick={() => handlePage(page)}>
{page}
</button>
</li> </li>
))} ))}
<li className="page-item next"> <li className="page-item next">
<button <button
type="button"
disabled={currentPage >= totalPages}
onClick={() => { onClick={() => {
if (currentPage === totalPages) return if (currentPage === totalPages) return
if (pageGroup * pagePerBlock + 1 <= totalPages) handlePage(Math.max(1, pageGroup * pagePerBlock + 1)) if (pageGroup * pagePerBlock + 1 <= totalPages) handlePage(Math.max(1, pageGroup * pagePerBlock + 1))
@ -36,7 +42,7 @@ export default function QPagination(props) {
></button> ></button>
</li> </li>
<li className="page-item last"> <li className="page-item last">
<button onClick={() => handlePage(totalPages)}></button> <button type="button" disabled={currentPage === totalPages} onClick={() => handlePage(totalPages)}></button>
</li> </li>
</ol> </ol>
) )

View File

@ -1263,7 +1263,7 @@ export default function Estimate({}) {
}} }}
getOptionLabel={(x) => x.clCodeNm} getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode} getOptionValue={(x) => x.clCode}
isClearable={false} isClearable={true}
isSearchable={false} isSearchable={false}
value={honorificCodeList.filter(function (option) { value={honorificCodeList.filter(function (option) {
return option.clCodeNm === estimateContextState.objectNameOmit return option.clCodeNm === estimateContextState.objectNameOmit

View File

@ -28,6 +28,8 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
'application/pdf', 'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel', 'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
] ]
Array.from(e.target.files).forEach((file) => { Array.from(e.target.files).forEach((file) => {
//, pdf, //, pdf,
@ -61,6 +63,8 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
'application/pdf', 'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel', 'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
] ]
Array.from(e.dataTransfer.files).forEach((file) => { Array.from(e.dataTransfer.files).forEach((file) => {

View File

@ -106,7 +106,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
useEffect(() => { useEffect(() => {
if (estimateContextState?.charger) { if (estimateContextState?.charger) {
setCopyReceiveUser(estimateContextState.charger) setCopyReceiveUser(session?.userNm)
} }
}, [estimateContextState?.charger]) }, [estimateContextState?.charger])

View File

@ -159,7 +159,7 @@ export default function CanvasMenu(props) {
roof.set({ selectable: true }) roof.set({ selectable: true })
setSurfaceShapePattern(roof, null, false, roof.roofMaterial) setSurfaceShapePattern(roof, null, false, roof.roofMaterial)
delete roof.moduleCompass delete roof.moduleCompass
drawDirectionArrow(roof) drawDirectionArrow(roof, false)
}) })
} }
@ -193,7 +193,6 @@ export default function CanvasMenu(props) {
type: 'confirm', type: 'confirm',
confirmFn: () => { confirmFn: () => {
// //
initRoofs()
const moduleSurfacesArray = canvas const moduleSurfacesArray = canvas
.getObjects() .getObjects()
@ -204,6 +203,7 @@ export default function CanvasMenu(props) {
moduleSurfacesArray.forEach((moduleSurface) => { moduleSurfacesArray.forEach((moduleSurface) => {
canvas.remove(moduleSurface) canvas.remove(moduleSurface)
}) })
canvas.renderAll() canvas.renderAll()
onClickNav(menu) onClickNav(menu)
} }
@ -302,6 +302,7 @@ export default function CanvasMenu(props) {
const settingsModalOptions = useRecoilState(settingModalFirstOptionsState) const settingsModalOptions = useRecoilState(settingModalFirstOptionsState)
useEffect(() => { useEffect(() => {
console.log(selectedMenu)
if (selectedMenu === 'placement') { if (selectedMenu === 'placement') {
onClickPlacementInitialMenu() onClickPlacementInitialMenu()
} }

View File

@ -563,8 +563,8 @@ export default function CircuitTrestleSetting({ id }) {
goodsNo: model.goodsNo, goodsNo: model.goodsNo,
serQtyList: [ serQtyList: [
{ {
serQty: result[index + 1].maxValue, serQty: result[(index + 1).toString()] ? result[(index + 1).toString()].maxValue : 0,
paralQty: result[index + 1].count, paralQty: result[(index + 1).toString()] ? result[(index + 1).toString()].count : 0,
rmdYn: 'Y', rmdYn: 'Y',
usePossYn: 'Y', usePossYn: 'Y',
roofSurfaceList: canvas roofSurfaceList: canvas

View File

@ -23,7 +23,7 @@ export default function StuffSubHeader({ type }) {
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState)
const { managementState } = useContext(GlobalDataContext) const { managementState, setManagementState } = useContext(GlobalDataContext)
const [buttonStyle, setButtonStyle] = useState('') const [buttonStyle, setButtonStyle] = useState('')
@ -31,17 +31,20 @@ export default function StuffSubHeader({ type }) {
useEffect(() => { useEffect(() => {
window.scrollTo(0, 0) window.scrollTo(0, 0)
setManagementState({})
}, []) }, [])
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(managementState)) { if (type === 'detail') {
if (managementState?.createSaleStoreId === 'T01') { if (isObjectNotEmpty(managementState)) {
if (session?.storeId !== 'T01') { if (managementState?.createSaleStoreId === 'T01') {
setButtonStyle('none') if (session?.storeId !== 'T01') {
setButtonStyle('none')
}
} }
} }
} }
}, [managementState?.createSaleStoreId]) }, [type, managementState])
const searchParams = useSearchParams() const searchParams = useSearchParams()
const objectNo = searchParams.get('objectNo') //url set const objectNo = searchParams.get('objectNo') //url set

View File

@ -17,6 +17,7 @@ export function useCommonUtils() {
const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent() const { addCanvasMouseEventListener, addDocumentEventListener, initEvent } = useEvent()
const dimensionSettings = useRecoilValue(dimensionLineSettingsState) const dimensionSettings = useRecoilValue(dimensionLineSettingsState)
const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText')) const dimensionLineTextFont = useRecoilValue(fontSelector('dimensionLineText'))
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const commonTextFont = useRecoilValue(fontSelector('commonText')) const commonTextFont = useRecoilValue(fontSelector('commonText'))
const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState) const [commonUtils, setCommonUtilsState] = useRecoilState(commonUtilsState)
const { addPopup } = usePopup() const { addPopup } = usePopup()
@ -561,6 +562,7 @@ export function useCommonUtils() {
obj.clone((cloned) => { obj.clone((cloned) => {
clonedObj = cloned clonedObj = cloned
clonedObj.fontSize = lengthTextFont.fontSize.value
}) })
addCanvasMouseEventListener('mouse:move', (e) => { addCanvasMouseEventListener('mouse:move', (e) => {
@ -595,6 +597,7 @@ export function useCommonUtils() {
//배치면일 경우 //배치면일 경우
if (obj.name === 'roof') { if (obj.name === 'roof') {
clonedObj.setCoords() clonedObj.setCoords()
clonedObj.fire('modified')
clonedObj.fire('polygonMoved') clonedObj.fire('polygonMoved')
clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial }) clonedObj.set({ direction: obj.direction, directionText: obj.directionText, roofMaterial: obj.roofMaterial })

View File

@ -412,6 +412,9 @@ export function useModule() {
} }
const moduleColumnRemove = (type) => { const moduleColumnRemove = (type) => {
if (isFixedModule()) {
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
if (activeModule.circuit) { if (activeModule.circuit) {
swalFire({ swalFire({
@ -535,6 +538,9 @@ export function useModule() {
} }
const moduleRowRemove = (type) => { const moduleRowRemove = (type) => {
if (isFixedModule()) {
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const rowModules = getRowModules(activeModule) const rowModules = getRowModules(activeModule)
const otherModules = getOtherModules(rowModules) const otherModules = getOtherModules(rowModules)
@ -651,6 +657,9 @@ export function useModule() {
} }
const moduleColumnInsert = (type) => { const moduleColumnInsert = (type) => {
if (isFixedModule()) {
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const columnModules = getColumnModules(activeModule) const columnModules = getColumnModules(activeModule)
let otherModules = getOtherModules(columnModules) let otherModules = getOtherModules(columnModules)
@ -750,7 +759,25 @@ export function useModule() {
setModuleStatisticsData() setModuleStatisticsData()
} }
const isFixedModule = () => {
const completeSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.isComplete)
if (completeSurfaces.length > 0) {
swalFire({
title: getMessage('modal.module.can.not.edit'),
type: 'alert',
icon: 'error',
})
return true
}
return false
}
const muduleRowInsert = (type) => { const muduleRowInsert = (type) => {
if (isFixedModule()) {
return
}
const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0]
const rowModules = getRowModules(activeModule) const rowModules = getRowModules(activeModule)
let otherModules = getOtherModules(rowModules) let otherModules = getOtherModules(rowModules)

View File

@ -27,6 +27,13 @@ export function useOrientation() {
setCompasDeg(0) setCompasDeg(0)
} }
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
const hasModules = canvas.getObjects().some((obj) => obj.name === 'module')
if (!hasModules) {
roofs.forEach((roof) => {
delete roof.directionText
})
}
roofs.forEach((roof) => { roofs.forEach((roof) => {
roof.set({ roof.set({
moduleCompass: isNaN(compasDeg) ? 0 : compasDeg, moduleCompass: isNaN(compasDeg) ? 0 : compasDeg,

View File

@ -9,6 +9,7 @@ import { basicSettingState, trestleDisplaySelector } from '@/store/settingAtom'
import { useSwal } from '@/hooks/useSwal' import { useSwal } from '@/hooks/useSwal'
import { useContext } from 'react' import { useContext } from 'react'
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
// 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주 // 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주
const MODULE_MARGIN = 10 const MODULE_MARGIN = 10
@ -22,6 +23,9 @@ export const useTrestle = () => {
const isTrestleDisplay = useRecoilValue(trestleDisplaySelector) const isTrestleDisplay = useRecoilValue(trestleDisplaySelector)
const { swalFire } = useSwal() const { swalFire } = useSwal()
const { setIsGlobalLoading } = useContext(QcastContext) const { setIsGlobalLoading } = useContext(QcastContext)
const { getSelectedPcsItemList } = useCircuitTrestle()
const apply = () => { const apply = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit) const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) { if (notAllocationModules.length > 0) {
@ -723,11 +727,7 @@ export const useTrestle = () => {
// circuitItemList 중복제거 // circuitItemList 중복제거
circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index) circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index)
circuitItemList = circuitItemList.map((circuitId) => { circuitItemList = getSelectedPcsItemList()
return {
itemId: circuitId,
}
})
return { itemList, northArrangement, roofSurfaceList, circuitItemList } return { itemList, northArrangement, roofSurfaceList, circuitItemList }
} }

View File

@ -239,7 +239,7 @@ export function useRoofAllocationSetting(id) {
*/ */
const onAddRoofMaterial = () => { const onAddRoofMaterial = () => {
if (currentRoofList.length >= 4) { if (currentRoofList.length >= 4) {
swalFire({ type: 'alert', icon: 'error', text: getMessage('지붕재는 4개까지 선택 가능합니다.') }) swalFire({ type: 'alert', icon: 'error', text: getMessage('roof.exceed.count') })
return return
} }
setCurrentRoofList([ setCurrentRoofList([

View File

@ -172,8 +172,9 @@ export const usePolygon = () => {
/** /**
* poolygon의 방향에 따라 화살표를 추가한다. * poolygon의 방향에 따라 화살표를 추가한다.
* @param polygon * @param polygon
* @param showDirectionText
*/ */
const drawDirectionArrow = (polygon) => { const drawDirectionArrow = (polygon, showDirectionText = true) => {
if (polygon.points.length < 3) { if (polygon.points.length < 3) {
return return
} }
@ -319,17 +320,16 @@ export const usePolygon = () => {
pitch: polygon.roofMaterial?.pitch ?? 4, pitch: polygon.roofMaterial?.pitch ?? 4,
parentId: polygon.id, parentId: polygon.id,
}) })
arrow.setViewLengthText(false) arrow.setViewLengthText(false)
polygon.arrow = arrow polygon.arrow = arrow
polygon.canvas.add(arrow) polygon.canvas.add(arrow)
polygon.canvas.renderAll() polygon.canvas.renderAll()
drawDirectionStringToArrow2(polygon) drawDirectionStringToArrow2(polygon, showDirectionText)
// drawDirectionStringToArrow() // drawDirectionStringToArrow()
} }
//arrow의 compass 값으로 방향 글자 설정 필요 //arrow의 compass 값으로 방향 글자 설정 필요
const drawDirectionStringToArrow2 = (polygon) => { const drawDirectionStringToArrow2 = (polygon, showDirectionText) => {
const { direction, surfaceCompass, moduleCompass, arrow } = polygon const { direction, surfaceCompass, moduleCompass, arrow } = polygon
if (moduleCompass === null || moduleCompass === undefined) { if (moduleCompass === null || moduleCompass === undefined) {
const textObj = new fabric.Text(`${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText}`, { const textObj = new fabric.Text(`${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText}`, {
@ -510,24 +510,27 @@ export const usePolygon = () => {
text = text + (sameDirectionCnt.length + 1) text = text + (sameDirectionCnt.length + 1)
polygon.set('directionText', text) polygon.set('directionText', text)
const textObj = new fabric.Text(`${text} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})`, { const textObj = new fabric.Text(
fontFamily: flowFontOptions.fontFamily.value, `${showDirectionText && text} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})`,
fontWeight: flowFontOptions.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal', {
fontStyle: flowFontOptions.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal', fontFamily: flowFontOptions.fontFamily.value,
fontSize: flowFontOptions.fontSize.value, fontWeight: flowFontOptions.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fill: flowFontOptions.fontColor.value, fontStyle: flowFontOptions.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
pitch: arrow.pitch, fontSize: flowFontOptions.fontSize.value,
originX: 'center', fill: flowFontOptions.fontColor.value,
originY: 'center', pitch: arrow.pitch,
name: 'flowText', originX: 'center',
originText: text, originY: 'center',
selectable: false, name: 'flowText',
left: arrow.stickeyPoint.x, originText: text,
top: arrow.stickeyPoint.y, selectable: false,
parent: arrow, left: arrow.stickeyPoint.x,
parentId: arrow.id, top: arrow.stickeyPoint.y,
visible: isFlowDisplay, parent: arrow,
}) parentId: arrow.id,
visible: isFlowDisplay,
},
)
polygon.canvas.add(textObj) polygon.canvas.add(textObj)
} }
@ -755,10 +758,7 @@ export const usePolygon = () => {
// innerLine이 세팅이 안되어있는경우 찾아서 세팅한다. // innerLine이 세팅이 안되어있는경우 찾아서 세팅한다.
if (!innerLines || innerLines.length === 0) { if (!innerLines || innerLines.length === 0) {
let innerLineTypes = [] let innerLineTypes = Object.keys(LINE_TYPE.SUBLINE).map((key, value) => LINE_TYPE.SUBLINE[key])
Object.keys(LINE_TYPE.SUBLINE).forEach((key, value) => {
innerLineTypes.push(LINE_TYPE.SUBLINE[key])
})
polygon.innerLines = canvas polygon.innerLines = canvas
.getObjects() .getObjects()
.filter( .filter(
@ -1102,6 +1102,8 @@ export const usePolygon = () => {
} }
}) })
// blue로 생성된 것들은 대표라인이 될 수 없음.
representLines = representLines.filter((line) => line.stroke !== 'blue')
// representLines중 가장 긴 line을 찾는다. // representLines중 가장 긴 line을 찾는다.
representLines.forEach((line) => { representLines.forEach((line) => {
if (!representLine) { if (!representLine) {

View File

@ -1028,5 +1028,6 @@
"not.allocation.exist.module": "回路を割り当てていないモジュールがあります。", "not.allocation.exist.module": "回路を割り当てていないモジュールがあります。",
"roof.is.not.selected": "屋根の選択をお願いします。", "roof.is.not.selected": "屋根の選択をお願いします。",
"length.direction.is.required": "長さと方向を入力します。", "length.direction.is.required": "長さと方向を入力します。",
"canvas.infomation.text": "数字は [半角] 入力のみ可能です。" "canvas.infomation.text": "数字は [半角] 入力のみ可能です。",
"roof.exceed.count": "屋根材は4つまで選択可能です。"
} }

View File

@ -1028,5 +1028,6 @@
"not.allocation.exist.module": "회로를 할당하지 않은 모듈이 있습니다.", "not.allocation.exist.module": "회로를 할당하지 않은 모듈이 있습니다.",
"roof.is.not.selected": "지붕을 선택해주세요.", "roof.is.not.selected": "지붕을 선택해주세요.",
"length.direction.is.required": "길이와 방향을 입력하세요.", "length.direction.is.required": "길이와 방향을 입력하세요.",
"canvas.infomation.text": "숫자는 [반각] 입력만 가능합니다." "canvas.infomation.text": "숫자는 [반각] 입력만 가능합니다.",
"roof.exceed.count": "지붕재는 4개까지 선택 가능합니다."
} }