Compare commits

...

24 Commits

Author SHA1 Message Date
김민식
f846644145 모듈 간격 영역 추가 2025-05-07 11:34:22 +09:00
김민식
655f0781a2 🚨chore: Sync Sass 2025-05-07 11:34:03 +09:00
김민식
76dd1aaa43 Merge remote-tracking branch 'origin/qcast-pub' into dev 2025-05-02 16:43:15 +09:00
e3df21f827 http://1.248.227.176:43333/issues/1022 상단 유틸리티 title 추가 2025-05-02 16:16:23 +09:00
김민식
7f1ef1ace4 Merge remote-tracking branch 'origin/qcast-pub' into dev 2025-05-02 10:01:59 +09:00
c40ba2586f Merge pull request '886 - 견적서 정가 다운로드 : 0 => "open"' (#33) from feature/ysCha into dev
Reviewed-on: #33
2025-04-29 15:04:53 +09:00
fc8e85b76c 886 - 견적서 정가 다운로드 : 0 => "open" 2025-04-29 15:02:19 +09:00
034bfb374e Merge pull request '1019 - ja, ko 변경' (#32) from feature/ysCha into dev
Reviewed-on: #32
2025-04-25 14:47:44 +09:00
71d3a33bf4 1019 - ja, ko 변경 2025-04-25 14:46:00 +09:00
0f079080a1 Merge pull request '1018 - 캔버스팝업상태 복사저장, 조회 : unescapeString() if => while 변경' (#31) from feature/ysCha into dev
Reviewed-on: #31
2025-04-25 14:05:14 +09:00
9bf961441b 1018 - 캔버스팝업상태 복사저장, 조회 : unescapeString() if => while 변경 2025-04-25 14:02:35 +09:00
3b96344943 index 세팅 추가 2025-04-24 13:30:58 +09:00
4be94e41a2 Merge pull request '1006 - ja 추가변경' (#30) from feature/ysCha into dev
Reviewed-on: #30
2025-04-24 11:36:19 +09:00
bd62bf7028 1006 - ja 추가변경 2025-04-24 11:34:59 +09:00
93c8bad986 Merge pull request '1012 - top select box link name 변경' (#29) from feature/ysCha into dev
Reviewed-on: #29
2025-04-24 10:48:54 +09:00
203ddfbdf3 1012 - top select box link name 변경 2025-04-24 10:39:47 +09:00
b11424e70e 육지붕일 경우 값 고정 2025-04-24 10:29:36 +09:00
88e2c8ed05 Merge pull request '1003 - calcLineActualSize() degree가 undefined => 0 처리' (#28) from feature/ysCha into dev
Reviewed-on: #28
2025-04-24 09:51:20 +09:00
6b56af6119 1003 - calcLineActualSize() degree가 undefined => 0 처리
showLine 함수의 canvas.getObjects().find()가 undefined => Optional chaining (?.) 처리
2025-04-24 09:45:36 +09:00
287ce5c85a 보조선 이동, 복사 시 나누기 10 적용 2025-04-23 17:09:33 +09:00
737fcf0b30 Merge pull request '986 - 시공사번호 추가, 시공사(userId) 데이터만 조회' (#27) from feature/ysCha into dev
Reviewed-on: #27
2025-04-23 16:16:42 +09:00
f3dfc50f6e 986 - 시공사번호 추가, 시공사(userId) 데이터만 조회 2025-04-23 16:13:07 +09:00
김민식
77e34d849d Merge remote-tracking branch 'origin/qcast-pub' into dev 2025-04-23 15:44:32 +09:00
4a8428f9f7 #1008 보조선 관련 오류 수정 2025-04-23 13:39:32 +09:00
27 changed files with 465 additions and 171 deletions

View File

@ -0,0 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="12" cy="12" r="8.25" stroke="#101010" stroke-width="1.5"/>
<path d="M7.94995 16.5C10.0485 14.302 13.9289 14.1986 16.05 16.5M14.2455 9.75C14.2455 10.9926 13.2367 12 11.9923 12C10.7479 12 9.73912 10.9926 9.73912 9.75C9.73912 8.50736 10.7479 7.5 11.9923 7.5C13.2367 7.5 14.2455 8.50736 14.2455 9.75Z" stroke="#101010" stroke-width="1.5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 474 B

View File

@ -58,6 +58,7 @@ export default async function RootLayout({ children }) {
pwdInitYn: session.pwdInitYn, pwdInitYn: session.pwdInitYn,
custCd: session.custCd, custCd: session.custCd,
isLoggedIn: session.isLoggedIn, isLoggedIn: session.isLoggedIn,
builderNo: session.builderNo
} }
} }
if (!headerPathname.includes('/login') && !session.isLoggedIn) { if (!headerPathname.includes('/login') && !session.isLoggedIn) {

View File

@ -26,6 +26,7 @@ export default function QSelectBox({
targetKey = '', targetKey = '',
showKey = '', showKey = '',
params = {}, params = {},
tagTitle = '',
}) { }) {
const { getMessage } = useMessage() const { getMessage } = useMessage()
@ -82,6 +83,7 @@ export default function QSelectBox({
className={`sort-select ${openSelect ? 'active' : ''} ${disabled ? 'disabled' : ''}`} className={`sort-select ${openSelect ? 'active' : ''} ${disabled ? 'disabled' : ''}`}
ref={ref} ref={ref}
onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)} onClick={disabled ? () => {} : () => setOpenSelect(!openSelect)}
title={tagTitle}
> >
<p>{selected}</p> <p>{selected}</p>
<ul className="select-item-wrap"> <ul className="select-item-wrap">

View File

@ -564,6 +564,7 @@ export default function Estimate({}) {
updateList.push({ updateList.push({
...item, ...item,
openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0', openFlg: data.data2[i].unitPrice === '0.0' ? '1' : '0',
unitOpenFlg: (showPriceCd === 'QSP_PRICE' && item.openFlg === '1') ? '1' : '0',
salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice, salePrice: data.data2[i].unitPrice === null ? '0' : data.data2[i].unitPrice,
saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(), saleTotPrice: (item.amount * data.data2[i].unitPrice).toString(),
}) })

View File

@ -548,13 +548,26 @@ export default function CanvasMenu(props) {
{ {
<div className={`vertical-horizontal ${verticalHorizontalMode ? 'on' : ''}`}> <div className={`vertical-horizontal ${verticalHorizontalMode ? 'on' : ''}`}>
<span>{getMessage('plan.mode.vertical.horizontal')}</span> <span>{getMessage('plan.mode.vertical.horizontal')}</span>
<button onClick={() => setVerticalHorizontalMode(!verticalHorizontalMode)}>{verticalHorizontalMode ? 'ON' : 'OFF'}</button> <button
title={`${getMessage('plan.mode.vertical.horizontal')} ${verticalHorizontalMode ? 'ON' : 'OFF'}`}
onClick={() => setVerticalHorizontalMode(!verticalHorizontalMode)}
>
{verticalHorizontalMode ? 'ON' : 'OFF'}
</button>
</div> </div>
} }
<div className="btn-from"> <div className="btn-from">
<button className={`btn01 ${commonUtils.text ? 'active' : ''}`} onClick={() => commonFunctions('text')}></button> <button className={`btn01 ${commonUtils.text ? 'active' : ''}`} onClick={() => commonFunctions('text')} title="文字作成"></button>
<button className={`btn02 ${commonUtils.dimension ? 'active' : ''} `} onClick={() => commonFunctions('dimension')}></button> <button
<button className={`btn03 ${commonUtils.distance ? 'active' : ''} `} onClick={() => commonFunctions('distance')}></button> className={`btn02 ${commonUtils.dimension ? 'active' : ''} `}
onClick={() => commonFunctions('dimension')}
title="寸法作成"
></button>
<button
className={`btn03 ${commonUtils.distance ? 'active' : ''} `}
onClick={() => commonFunctions('distance')}
title="定規"
></button>
</div> </div>
{isObjectNotEmpty(selectedRoofMaterial) && addedRoofs.length > 0 && ( {isObjectNotEmpty(selectedRoofMaterial) && addedRoofs.length > 0 && (
<div className="select-box"> <div className="select-box">
@ -580,6 +593,7 @@ export default function CanvasMenu(props) {
sourceKey={'index'} sourceKey={'index'}
targetKey={'index'} targetKey={'index'}
disabled={+basicSetting.roofSizeSet === 3} disabled={+basicSetting.roofSizeSet === 3}
tagTitle={'屋根材変更'}
/> />
} }
</div> </div>
@ -588,9 +602,10 @@ export default function CanvasMenu(props) {
<button <button
className={`btn10 ${floorPlanState.refFileModalOpen && 'active'}`} className={`btn10 ${floorPlanState.refFileModalOpen && 'active'}`}
onClick={() => setFloorPlanState({ ...floorPlanState, refFileModalOpen: true })} onClick={() => setFloorPlanState({ ...floorPlanState, refFileModalOpen: true })}
title="読込"
></button> ></button>
{/*<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>*/} {/*<button className="btn04" onClick={() => setShowCanvasSettingModal(true)}></button>*/}
<button className="btn04" onClick={handlePopup}></button> <button className="btn04" onClick={handlePopup} title="設定"></button>
</div> </div>
<div className="size-control"> <div className="size-control">
<button <button
@ -599,7 +614,9 @@ export default function CanvasMenu(props) {
handleZoom(false) handleZoom(false)
}} }}
></button> ></button>
<span onClick={handleZoomClear}>{canvasZoom}%</span> <span onClick={handleZoomClear} title="拡大・縮小">
{canvasZoom}%
</span>
<button <button
className="control-btn plus" className="control-btn plus"
onClick={() => { onClick={() => {
@ -608,8 +625,8 @@ export default function CanvasMenu(props) {
></button> ></button>
</div> </div>
<div className="btn-from"> <div className="btn-from">
<button className="btn08" onClick={handleSaveCanvas}></button> <button className="btn08" onClick={handleSaveCanvas} title="保存"></button>
<button className="btn09" onClick={handleLeaveCanvas}></button> <button className="btn09" onClick={handleLeaveCanvas} title="物件検索画面へ移動"></button>
</div> </div>
</> </>
)} )}

View File

@ -40,15 +40,15 @@ export default function AuxiliaryEdit(props) {
if (currentObject) { if (currentObject) {
copy( copy(
currentObject, currentObject,
arrow2 ? (arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize)) : 0, arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize)) : 0, arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
) )
} }
} else { } else {
move( move(
currentObject, currentObject,
arrow2 ? (arrow2 === '←' ? Number(horizonSize) * -1 : Number(horizonSize)) : 0, arrow2 ? (arrow2 === '←' ? Number(+horizonSize / 10) * -1 : Number(+horizonSize / 10)) : 0,
arrow1 ? (arrow1 === '↑' ? Number(verticalSize) * -1 : Number(verticalSize)) : 0, arrow1 ? (arrow1 === '↑' ? Number(+verticalSize / 10) * -1 : Number(+verticalSize / 10)) : 0,
) )
} }

View File

@ -110,8 +110,8 @@ const Placement = forwardRef((props, refs) => {
{ type: 'check', name: '', prop: 'check', width: 70 }, { type: 'check', name: '', prop: 'check', width: 70 },
{ type: 'color-box', name: getMessage('module'), prop: 'module' }, { type: 'color-box', name: getMessage('module'), prop: 'module' },
{ type: 'text', name: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn'), prop: 'mixAsgYn', width: 50 }, { type: 'text', name: getMessage('modal.module.basic.setting.module.placement.mix.asg.yn'), prop: 'mixAsgYn', width: 50 },
{ type: 'text', name: ``, prop: 'rows', width: 60 }, { type: 'text', name: ``, prop: 'rows', width: 60 },
{ type: 'text', name: `熱水`, prop: 'cols', width: 60 }, { type: 'text', name: `列数`, prop: 'cols', width: 60 },
], ],
rows: [], rows: [],
} }

View File

@ -667,8 +667,9 @@ const Trestle = forwardRef((props, ref) => {
</div> </div>
</div> </div>
<div className="module-area mt10"> <div className="module-input-area">
<div className="module-area-title">{getMessage('modal.module.basic.setting.module.placement.area')}</div> <div className="module-area-title">{getMessage('modal.module.basic.setting.module.placement.area')}</div>
<div className="module-input-wrap">
<div className="outline-form mr15"> <div className="outline-form mr15">
<span>{getMessage('modal.module.basic.setting.module.placement.area.eaves')}</span> <span>{getMessage('modal.module.basic.setting.module.placement.area.eaves')}</span>
<div className="input-grid mr10"> <div className="input-grid mr10">
@ -710,6 +711,26 @@ const Trestle = forwardRef((props, ref) => {
</div> </div>
</div> </div>
</div> </div>
<div className="module-input-area">
<div className="module-area-title">{getMessage('modal.module.basic.setting.module.placement.margin')}</div>
<div className="module-input-wrap">
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.placement.margin.horizontal')}</span>
<div className="input-grid mr10">
<input type="text" className="input-origin block" defaultValue={trestleDetail?.moduleIntvlHor} readOnly />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span>{getMessage('modal.module.basic.setting.module.placement.margin.vertical')}</span>
<div className="input-grid mr10">
<input type="text" className="input-origin block" defaultValue={trestleDetail?.moduleIntvlVer} readOnly />
</div>
<span className="thin">mm</span>
</div>
</div>
</div>
</div>
</div> </div>
<div className="module-bottom"> <div className="module-bottom">
<div className="module-table-box "> <div className="module-table-box ">

View File

@ -75,19 +75,19 @@ export default function Header(props) {
userSession.storeId === 'T01' userSession.storeId === 'T01'
? [ ? [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' }, { id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'Q.ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' }, { id: 1, name: 'HANASYS ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: 'Q.Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' }, { id: 2, name: 'HANASYS Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 3, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' }, { id: 3, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
] ]
: userSession.groupId === '60000' : userSession.groupId === '60000'
? [ ? [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' }, { id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'Q.ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' }, { id: 1, name: 'HANASYS ORDER', link: `${qOrderUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' }, { id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
] ]
: [ : [
{ id: 0, name: getMessage('site.header.link1'), target: '_blank' }, { id: 0, name: getMessage('site.header.link1'), target: '_blank' },
{ id: 1, name: 'Q.Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' }, { id: 1, name: 'HANASYS Musubi', link: `${qMusubiUrl}?autoLoginParam1=${encodeURIComponent(res.data)}`, target: '_blank' },
{ id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' }, { id: 2, name: getMessage('site.header.link2'), link: `https://q-warranty.q-cells.jp/seller_login`, target: '_blank' },
], ],
) )

View File

@ -238,6 +238,8 @@ export default function Stuff() {
schSortType: stuffSearchParams.schSortType, schSortType: stuffSearchParams.schSortType,
pageNo: stuffSearchParams?.pageNo ? stuffSearchParams.pageNo : 1, pageNo: stuffSearchParams?.pageNo ? stuffSearchParams.pageNo : 1,
pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100, pageSize: stuffSearchParams?.pageSize ? stuffSearchParams.pageSize : 100,
builderNo: session.builderNo,
userId: session.userId
} }
if (!params.saleStoreId) { if (!params.saleStoreId) {

View File

@ -310,6 +310,7 @@ export const useEstimateController = (planNo, flag) => {
//봄 컴포넌트 제품은 0으로 //봄 컴포넌트 제품은 0으로
item.openFlg = '0' item.openFlg = '0'
item.unitOpenFlg = '0'
} }
} }
}) })

View File

@ -27,7 +27,7 @@ export const useMainContentsController = () => {
*/ */
const fetchObjectList = async () => { const fetchObjectList = async () => {
try { try {
const apiUrl = `/api/main-page/object/${session?.storeId}/list` const apiUrl = `/api/main-page/object/${session?.storeId}/${session?.userId}/${session?.builderNo}/list`
await promiseGet({ await promiseGet({
url: apiUrl, url: apiUrl,
}).then((res) => { }).then((res) => {

View File

@ -2251,7 +2251,15 @@ export const useTrestle = () => {
let halfMaxX let halfMaxX
let halfMaxY let halfMaxY
const { direction, trestleDetail } = surface const { direction, trestleDetail } = surface
const { moduleIntvlHor, moduleIntvlVer } = trestleDetail let moduleIntvlHor, moduleIntvlVer
if (+roofSizeSet === 3) {
//육지붕의 경우 값 고정
moduleIntvlHor = 300
moduleIntvlVer = 100
} else {
moduleIntvlHor = trestleDetail.moduleIntvlHor
moduleIntvlVer = trestleDetail.moduleIntvlVer
}
if (direction === 'south' || direction === 'north') { if (direction === 'south' || direction === 'north') {
maxX = width + moduleIntvlHor / 10 maxX = width + moduleIntvlHor / 10

View File

@ -5,16 +5,6 @@ import { useEvent } from '@/hooks/useEvent'
import { useMouse } from '@/hooks/useMouse' import { useMouse } from '@/hooks/useMouse'
import { useLine } from '@/hooks/useLine' import { useLine } from '@/hooks/useLine'
import { useTempGrid } from '@/hooks/useTempGrid' import { useTempGrid } from '@/hooks/useTempGrid'
import {
outerLineAngle1State,
outerLineAngle2State,
outerLineArrow1State,
outerLineArrow2State,
outerLineDiagonalState,
outerLineLength1State,
outerLineLength2State,
outerLineTypeState,
} from '@/store/outerLineAtom'
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine } from '@/util/canvas-util' import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine } from '@/util/canvas-util'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint'
@ -23,6 +13,16 @@ import { usePopup } from '@/hooks/usePopup'
import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils' import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils'
import { POLYGON_TYPE } from '@/common/common' import { POLYGON_TYPE } from '@/common/common'
import { useMessage } from '../useMessage' import { useMessage } from '../useMessage'
import {
auxiliaryLineAngle1State,
auxiliaryLineAngle2State,
auxiliaryLineArrow1State,
auxiliaryLineArrow2State,
auxiliaryLineDiagonalState,
auxiliaryLineLength1State,
auxiliaryLineLength2State,
auxiliaryLineTypeState,
} from '@/store/auxiliaryLineAtom'
// 보조선 작성 // 보조선 작성
export function useAuxiliaryDrawing(id, isUseEffect = true) { export function useAuxiliaryDrawing(id, isUseEffect = true) {
@ -49,20 +49,20 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
const length2Ref = useRef(0) const length2Ref = useRef(0)
const angle1Ref = useRef('') const angle1Ref = useRef('')
const angle2Ref = useRef('') const angle2Ref = useRef('')
const [length1, setLength1] = useRecoilState(outerLineLength1State) const [length1, setLength1] = useRecoilState(auxiliaryLineLength1State)
const [length2, setLength2] = useRecoilState(outerLineLength2State) const [length2, setLength2] = useRecoilState(auxiliaryLineLength2State)
const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State) const [arrow1, setArrow1] = useRecoilState(auxiliaryLineArrow1State)
const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State) const [arrow2, setArrow2] = useRecoilState(auxiliaryLineArrow2State)
const [type, setType] = useRecoilState(outerLineTypeState) const [type, setType] = useRecoilState(auxiliaryLineTypeState)
const [angle1, setAngle1] = useRecoilState(outerLineAngle1State) const [angle1, setAngle1] = useRecoilState(auxiliaryLineAngle1State)
const [angle2, setAngle2] = useRecoilState(outerLineAngle2State) const [angle2, setAngle2] = useRecoilState(auxiliaryLineAngle2State)
const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(outerLineDiagonalState) const [auxiliaryLineDiagonalLength, setAuxiliaryLineDiagonalLength] = useRecoilState(auxiliaryLineDiagonalState)
const arrow1Ref = useRef(arrow1) const arrow1Ref = useRef(arrow1)
const arrow2Ref = useRef(arrow2) const arrow2Ref = useRef(arrow2)
const typeRef = useRef(type) const typeRef = useRef(type)
const outerLineDiagonalLengthRef = useRef(0) const auxiliaryLineDiagonalLengthRef = useRef(0)
const intersectionPoints = useRef([]) const intersectionPoints = useRef([])
const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState)
@ -124,7 +124,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
setAngle1(0) setAngle1(0)
setAngle2(0) setAngle2(0)
setOuterLineDiagonalLength(0) setAuxiliaryLineDiagonalLength(0)
} }
const move = (object, x, y) => { const move = (object, x, y) => {
@ -408,7 +408,7 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
//대각선 완료될 경우 확인 //대각선 완료될 경우 확인
const checkDiagonal = (direction) => { const checkDiagonal = (direction) => {
const activeElem = document.activeElement const activeElem = document.activeElement
const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이 const diagonalLength = auxiliaryLineDiagonalLengthRef.current.value // 대각선 길이
const length1Value = length1Ref.current.value const length1Value = length1Ref.current.value
@ -913,9 +913,9 @@ export function useAuxiliaryDrawing(id, isUseEffect = true) {
angle2, angle2,
setAngle2, setAngle2,
angle2Ref, angle2Ref,
outerLineDiagonalLength, auxiliaryLineDiagonalLength,
setOuterLineDiagonalLength, setAuxiliaryLineDiagonalLength,
outerLineDiagonalLengthRef, auxiliaryLineDiagonalLengthRef,
type, type,
setType, setType,
handleFix, handleFix,

View File

@ -469,7 +469,7 @@ export function useRoofAllocationSetting(id) {
const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id) const selectedRoofMaterial = roofMaterials.find((roof) => roof.roofMatlCd === value.id)
const newRoofList = currentRoofList.map((roof, idx) => { const newRoofList = currentRoofList.map((roof, idx) => {
if (idx === index) { if (idx === index) {
return { ...selectedRoofMaterial, selected: roof.selected } return { ...selectedRoofMaterial, selected: roof.selected, index }
} }
return roof return roof
}) })

View File

@ -53,8 +53,8 @@ export const useLine = () => {
}) })
canvas canvas
?.getObjects() ?.getObjects()
.find((obj) => obj.parentId === line.id) ?.find((obj) => obj.parentId === line.id)
.set({ ?.set({
visible: true, visible: true,
}) })
canvas?.renderAll() canvas?.renderAll()

View File

@ -21,6 +21,7 @@ import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedM
import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController' import { useCanvasPopupStatusController } from './common/useCanvasPopupStatusController'
import { useCanvasMenu } from './common/useCanvasMenu' import { useCanvasMenu } from './common/useCanvasMenu'
import { QcastContext } from '@/app/QcastProvider' import { QcastContext } from '@/app/QcastProvider'
import { unescapeString } from '@/util/common-utils'
/** /**
* 플랜 처리 * 플랜 처리
@ -264,7 +265,7 @@ export function usePlan(params = {}) {
objectNo, objectNo,
planNo: parseInt(newPlan.planNo), planNo: parseInt(newPlan.planNo),
popupType: 1, popupType: 1,
popupStatus: sourceDegree.popupStatus, popupStatus: unescapeString(sourceDegree.popupStatus),
} }
console.log('🚀 ~ postObjectPlan ~ degreeData:', degreeData) console.log('🚀 ~ postObjectPlan ~ degreeData:', degreeData)
await post({ url: `/api/v1/canvas-popup-status`, data: degreeData }) await post({ url: `/api/v1/canvas-popup-status`, data: degreeData })

View File

@ -48,6 +48,7 @@ export async function setSession(data) {
session.pwdInitYn = data.pwdInitYn session.pwdInitYn = data.pwdInitYn
session.custCd = data.custCd session.custCd = data.custCd
session.isLoggedIn = true session.isLoggedIn = true
session.builderNo = data.builderNo
await session.save() await session.save()
} }

View File

@ -97,9 +97,12 @@
"modal.module.basic.setting.module.under.roof": "屋根下地", "modal.module.basic.setting.module.under.roof": "屋根下地",
"modal.module.basic.setting.module.setting": "モジュールの選択", "modal.module.basic.setting.module.setting": "モジュールの選択",
"modal.module.basic.setting.module.placement.area": "モジュール配置領域", "modal.module.basic.setting.module.placement.area": "モジュール配置領域",
"modal.module.basic.setting.module.placement.margin": "モジュール間の間隙",
"modal.module.basic.setting.module.placement.area.eaves": "軒側", "modal.module.basic.setting.module.placement.area.eaves": "軒側",
"modal.module.basic.setting.module.placement.area.ridge": "棟側", "modal.module.basic.setting.module.placement.area.ridge": "棟側",
"modal.module.basic.setting.module.placement.area.keraba": "けらぱ", "modal.module.basic.setting.module.placement.area.keraba": "けらぱ",
"modal.module.basic.setting.module.placement.margin.horizontal": "左右",
"modal.module.basic.setting.module.placement.margin.vertical": "上下",
"modal.module.basic.setting.module.hajebichi": "ハゼピッチ", "modal.module.basic.setting.module.hajebichi": "ハゼピッチ",
"modal.module.basic.setting.module.setting.info1": "※勾配の範囲には制限があります。屋根傾斜が2.5値未満10値を超える場合は、施工が可能かどうか施工マニュアルを確認してください。", "modal.module.basic.setting.module.setting.info1": "※勾配の範囲には制限があります。屋根傾斜が2.5値未満10値を超える場合は、施工が可能かどうか施工マニュアルを確認してください。",
"modal.module.basic.setting.module.setting.info2": "※モジュール配置時は、施工マニュアルに記載されている<モジュール配置条件>を必ずご確認ください。", "modal.module.basic.setting.module.setting.info2": "※モジュール配置時は、施工マニュアルに記載されている<モジュール配置条件>を必ずご確認ください。",
@ -117,7 +120,7 @@
"modal.module.basic.settting.module.error1": "架台メーカーを選択してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error1": "架台メーカーを選択してください。\n(屋根材: {0})(JA)",
"modal.module.basic.settting.module.error2": "工法を選択してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error2": "工法を選択してください。\n(屋根材: {0})(JA)",
"modal.module.basic.settting.module.error3": "屋根の下を選択してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error3": "屋根の下を選択してください。\n(屋根材: {0})(JA)",
"modal.module.basic.settting.module.error4": "施工法を選択してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error4": "設置可能な施工条件がないので設置条件を変更してください。\n(屋根材: {0})",
"modal.module.basic.settting.module.error5": "L を選択してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error5": "L を選択してください。\n(屋根材: {0})(JA)",
"modal.module.basic.settting.module.error6": "垂木の間隔を入力してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error6": "垂木の間隔を入力してください。\n(屋根材: {0})(JA)",
"modal.module.basic.settting.module.error7": "下在ビーチを入力してください。\n(屋根材: {0})(JA)", "modal.module.basic.settting.module.error7": "下在ビーチを入力してください。\n(屋根材: {0})(JA)",
@ -128,8 +131,8 @@
"modal.module.basic.setting.module.placement": "モジュールの配置", "modal.module.basic.setting.module.placement": "モジュールの配置",
"modal.module.basic.setting.module.placement.select.fitting.type": "設置形態を選択してください。", "modal.module.basic.setting.module.placement.select.fitting.type": "設置形態を選択してください。",
"modal.module.basic.setting.module.placement.waterfowl.arrangement": "千鳥配置", "modal.module.basic.setting.module.placement.waterfowl.arrangement": "千鳥配置",
"modal.module.basic.setting.module.placement.max.row.amount": "Max数", "modal.module.basic.setting.module.placement.max.row.amount": "Max数",
"modal.module.basic.setting.module.placement.mix.max.row.amount": "混合Max数", "modal.module.basic.setting.module.placement.mix.max.row.amount": "混合Max数",
"modal.module.basic.setting.module.placement.row.amount": "段数", "modal.module.basic.setting.module.placement.row.amount": "段数",
"modal.module.basic.setting.module.placement.column.amount": "列数", "modal.module.basic.setting.module.placement.column.amount": "列数",
"modal.module.basic.setting.module.placement.do": "する", "modal.module.basic.setting.module.placement.do": "する",
@ -320,7 +323,7 @@
"modal.object.setting.offset.width": "幅の出幅", "modal.object.setting.offset.width": "幅の出幅",
"modal.object.setting.offset.slope": "勾配", "modal.object.setting.offset.slope": "勾配",
"modal.object.setting.direction.select": "方向の選択", "modal.object.setting.direction.select": "方向の選択",
"modal.placement.surface.setting.info": "ⓘ①の長さ入力後、対角線長を入力すると②の長さを自動計算します。", "modal.placement.surface.setting.info": "①の長さを入力後、③の長さを入力すると②の長さを自動計算します。",
"modal.placement.surface.setting.diagonal.length": "斜めの長さ", "modal.placement.surface.setting.diagonal.length": "斜めの長さ",
"modal.color.picker.title": "色設定", "modal.color.picker.title": "色設定",
"modal.color.picker.default.color": "基本色", "modal.color.picker.default.color": "基本色",
@ -1066,12 +1069,12 @@
"roof.line.not.found": "屋根形状がありません", "roof.line.not.found": "屋根形状がありません",
"roof.material.can.not.delete": "割り当てられた配置面があります。", "roof.material.can.not.delete": "割り当てられた配置面があります。",
"chidory.can.not.install": "千鳥配置できない工法です。", "chidory.can.not.install": "千鳥配置できない工法です。",
"module.layout.setup.max.count": "モジュールの最大段数は{0}、最大列数は{1}です。 (JA)", "module.layout.setup.max.count": "モジュールの単体での最大段数は{0}、最大列数は{1}です。 (JA)",
"module.layout.setup.max.count.multiple": "モジュール{0}の最大段数は{1}、最大列数は{2}です。 (JA)", "module.layout.setup.max.count.multiple": "モジュール{0}の単体での最大段数は{1}、最大列数は{2}です。 (JA)",
"roofAllocation.not.found": "割り当てる屋根がありません。 (JA)", "roofAllocation.not.found": "割り当てる屋根がありません。 (JA)",
"modal.module.basic.setting.module.placement.max.size.check": "屋根材別モジュールの単体の最大段数、2種混合の段数を確認して下さい", "modal.module.basic.setting.module.placement.max.size.check": "屋根材別モジュールの単体の単体での最大段数、2種混合の段数を確認して下さい",
"modal.module.basic.setting.module.placement.max.row": "最大段数", "modal.module.basic.setting.module.placement.max.row": "単体での最大段数",
"modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合最大段数", "modal.module.basic.setting.module.placement.max.rows.multiple": "2種混合時の最大段数",
"modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)", "modal.module.basic.setting.module.placement.mix.asg.yn.error": "混合インストール不可能なモジュールです。 (JA)",
"modal.module.basic.setting.module.placement.mix.asg.yn": "混合", "modal.module.basic.setting.module.placement.mix.asg.yn": "混合",
"modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)" "modal.module.basic.setting.layoutpassivity.placement": "layout配置 (JA)"

View File

@ -97,9 +97,12 @@
"modal.module.basic.setting.module.under.roof": "지붕밑바탕", "modal.module.basic.setting.module.under.roof": "지붕밑바탕",
"modal.module.basic.setting.module.setting": "모듈 선택", "modal.module.basic.setting.module.setting": "모듈 선택",
"modal.module.basic.setting.module.placement.area": "모듈 배치 영역", "modal.module.basic.setting.module.placement.area": "모듈 배치 영역",
"modal.module.basic.setting.module.placement.margin": "모듈 배치 간격",
"modal.module.basic.setting.module.placement.area.eaves": "처마쪽", "modal.module.basic.setting.module.placement.area.eaves": "처마쪽",
"modal.module.basic.setting.module.placement.area.ridge": "용마루쪽", "modal.module.basic.setting.module.placement.area.ridge": "용마루쪽",
"modal.module.basic.setting.module.placement.area.keraba": "케라바쪽", "modal.module.basic.setting.module.placement.area.keraba": "케라바쪽",
"modal.module.basic.setting.module.placement.margin.horizontal": "좌우",
"modal.module.basic.setting.module.placement.margin.vertical": "상하",
"modal.module.basic.setting.module.hajebichi": "망둥어 피치", "modal.module.basic.setting.module.hajebichi": "망둥어 피치",
"modal.module.basic.setting.module.setting.info1": "※ 구배의 범위에는 제한이 있습니다. 지붕경사가 2.5치 미만 10치를 초과하는 경우에는 시공이 가능한지 시공 매뉴얼을 확인해주십시오.", "modal.module.basic.setting.module.setting.info1": "※ 구배의 범위에는 제한이 있습니다. 지붕경사가 2.5치 미만 10치를 초과하는 경우에는 시공이 가능한지 시공 매뉴얼을 확인해주십시오.",
"modal.module.basic.setting.module.setting.info2": "※ 모듈 배치 시에는 시공 매뉴얼에 기재된 <모듈 배치 조건>을 반드시 확인해주십시오.", "modal.module.basic.setting.module.setting.info2": "※ 모듈 배치 시에는 시공 매뉴얼에 기재된 <모듈 배치 조건>을 반드시 확인해주십시오.",
@ -117,7 +120,7 @@
"modal.module.basic.settting.module.error1": "가대메이커를 선택해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error1": "가대메이커를 선택해주세요.\n(지붕재: {0})",
"modal.module.basic.settting.module.error2": "공법를 선택해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error2": "공법를 선택해주세요.\n(지붕재: {0})",
"modal.module.basic.settting.module.error3": "지붕밑바탕을 선택해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error3": "지붕밑바탕을 선택해주세요.\n(지붕재: {0})",
"modal.module.basic.settting.module.error4": "시공법을 선택해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error4": "설치 조건이 없으므로 설치 조건을 변경하십시오.\n(지붕재: {0})",
"modal.module.basic.settting.module.error5": "L 을 입력해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error5": "L 을 입력해주세요.\n(지붕재: {0})",
"modal.module.basic.settting.module.error6": "서까래 간격을 입력해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error6": "서까래 간격을 입력해주세요.\n(지붕재: {0})",
"modal.module.basic.settting.module.error7": "하제비치를 입력해주세요.\n(지붕재: {0})", "modal.module.basic.settting.module.error7": "하제비치를 입력해주세요.\n(지붕재: {0})",

View File

@ -0,0 +1,71 @@
import { atom } from 'recoil'
// 보조선 타입
export const AUXILIARY_LINE_TYPE = {
OUTER_LINE: 'outerLine', // 외벽선
RIGHT_ANGLE: 'rightAngle', // 직각
DOUBLE_PITCH: 'doublePitch',
ANGLE: 'angle', // 각도
DIAGONAL_LINE: 'diagonalLine', // 대각선
}
/**
* 보조선 작성에서 사용하는 recoilState
*/
export const auxiliaryLineLength1State = atom({
//길이1
key: 'auxiliaryLineLength1State',
default: 0,
})
export const auxiliaryLineLength2State = atom({
// 길이2
key: 'auxiliaryLineLength2State',
default: 0,
})
export const auxiliaryLineArrow1State = atom({
// 방향1
key: 'auxiliaryLineArrow1State',
default: '',
})
export const auxiliaryLineArrow2State = atom({
// 방향2
key: 'auxiliaryLineArrow2State',
default: '',
})
export const auxiliaryLineAngle1State = atom({
// 각도1
key: 'auxiliaryLineAngle1State',
default: 0,
})
export const auxiliaryLineAngle2State = atom({
// 각도2
key: 'auxiliaryLineAngle2State',
default: 0,
})
export const auxiliaryLineDiagonalState = atom({
// 대각선
key: 'auxiliaryLineDiagonalState',
default: 0,
})
export const auxiliaryLineTypeState = atom({
key: 'auxiliaryLineTypeState',
default: AUXILIARY_LINE_TYPE.OUTER_LINE,
})
export const auxiliaryLinePointsState = atom({
key: 'auxiliaryLinePointsState',
default: [],
})
export const auxiliaryLineFixState = atom({
key: 'auxiliaryLineFixState',
default: false,
})

View File

@ -806,8 +806,6 @@
color: #45576F; color: #45576F;
margin-left: 5px; margin-left: 5px;
} }
.drag-file-box{
padding: 10px;
.btn-area{ .btn-area{
padding-bottom: 15px; padding-bottom: 15px;
border-bottom: 1px solid #ECF0F4; border-bottom: 1px solid #ECF0F4;
@ -828,6 +826,8 @@
} }
} }
} }
.drag-file-box{
padding: 10px;
.drag-file-area{ .drag-file-area{
position: relative; position: relative;
margin-top: 15px; margin-top: 15px;

View File

@ -2363,20 +2363,6 @@ $alert-color: #101010;
} }
} }
.module-area{
display: flex;
align-items: center;
.module-area-title{
flex: none;
font-size: 12px;
color: #fff;
font-weight: 500;
margin-right: 20px;
}
.outline-form{
flex: 1;
}
}
.placement-name-guide{ .placement-name-guide{
font-size: 11px; font-size: 11px;
@ -2423,3 +2409,31 @@ $alert-color: #101010;
height: 0; height: 0;
} }
} }
// 2025-05-07 지붕모듈
.module-input-area{
display: flex;
align-items: center;
margin-top: 10px;
.module-area-title{
flex: none;
font-size: 12px;
color: #fff;
font-weight: 500;
margin-right: 20px;
}
.module-input-wrap{
width: 100%;
display: flex;
.outline-form{
width: calc(33.333% - 10px);
margin-right: 15px;
&:last-child{
margin-right: 0;
}
.input-grid{
width: 100%;
}
}
}
}

View File

@ -377,6 +377,7 @@ button{
font-size: 12px; font-size: 12px;
color: #fff; color: #fff;
line-height: 1.4; line-height: 1.4;
text-align: left;
} }
&:hover{ &:hover{
background-color: #2C2C2C; background-color: #2C2C2C;
@ -1024,3 +1025,22 @@ input:checked + .slider {
.swal2-container{ .swal2-container{
z-index: 120000; z-index: 120000;
} }
// textarea
.textarea-form{
width: 100%;
outline: none;
resize: none;
border: none;
border: 1px solid #eee;
min-height: 150px;
padding: 10px;
font-size: 13px;
color: #45576F;
border-radius: 2px;
font-family: "Noto Sans JP", sans-serif;
transition: border .15s ease-in-out;
&:focus{
border-color: #94a0ad;
}
}

View File

@ -288,7 +288,6 @@
} }
// 커뮤니티 // 커뮤니티
.community_detail{
.community_detail-tit{ .community_detail-tit{
font-size: 16px; font-size: 16px;
color: #101010; color: #101010;
@ -303,13 +302,15 @@
font-size: 13px; font-size: 13px;
color: #101010; color: #101010;
font-weight: 500; font-weight: 500;
margin-bottom: 15px;
} }
dd{ dd{
font-size: 12px; font-size: 12px;
font-weight: 400; font-weight: 400;
margin-bottom: 3px; margin-bottom: 3px;
color: #344356; color: #344356;
&:nth-child(2){
margin-top: 15px;
}
&:last-child{ &:last-child{
margin-bottom: 0; margin-bottom: 0;
} }
@ -336,7 +337,7 @@
background-color: transparent; background-color: transparent;
} }
} }
}
// 견적 복사 // 견적 복사
.estimate-copy-info-item{ .estimate-copy-info-item{
@ -369,3 +370,116 @@
} }
} }
} }
// 1:1문의
.one-on-one{
.select-wrap{
width: 250px;
}
.input-wrap{
flex: 1 1 auto;
}
&.btn-area{
padding-bottom: 0;
border: none;
margin-left: 10px;
}
&.drag-file-box{
border: 1px solid #eee;
.drag-file-area{
margin-top: 0;
}
}
}
.oneonone-header-wrap{
padding-bottom: 14px;
border-bottom: 2px solid #101010;
.oneonone-title{
font-size: 16px;
color: #101010;
font-weight: 600;
margin-bottom: 14px;
}
}
.oneonone-infor{
display: flex;
align-items: center;
.profile{
position: relative;
padding-left: 26px;
padding-right: 8px;
font-size: 13px;
font-weight: 400;
color: #101010;
&::before{
content: '';
position: absolute;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 24px;
height: 24px;
background: url(./../../public/static/images/sub/oneonone_profile_icon.svg)no-repeat center;
}
&::after{
content: '';
position: absolute;
top: 50%;
right: 0;
transform: translateY(-50%);
width: 1px;
height: 8px;
background-color: #CCCCCC;
}
}
.date{
padding-left: 8px;
font-size: 13px;
font-weight: 400;
color: #101010;
}
}
.oneonone-detail{
padding: 20px;
border: 1px solid #101010;
border-top: none;
.community_detail-file-wrap{
padding-top: 0;
}
.community_detail-inner{
max-height: 110px;
margin-top: 24px;
margin-bottom: 0;
}
}
.oneonone-answer{
margin-top: 8px;
padding: 20px;
border: 1px solid #101010;
.community_detail-inner{
max-height: 110px;
}
.community_detail-file-wrap{
border-top: 1px solid #D4DCE7;
padding: 16px 0 0 0;
border-bottom: none;
}
}
.answer-title-wrap{
display: flex;
align-items: center;
padding-bottom: 14px;
border-bottom: 1px solid #D4DCE7;
.answer-title{
font-size: 14px;
color: #101010;
font-weight: 600;
}
.oneonone-infor{
margin-left: auto;
}
}

View File

@ -145,9 +145,19 @@ export const unescapeString = (str) => {
'&#39;': "'", '&#39;': "'",
} }
/*
1. 한번 변환은 {&quot; 변환됨 : 에러 발생 => while 변경
2. 변환할 내용이 없으면 리턴값이 undefined
if (regex.test(str)) { if (regex.test(str)) {
return str.replace(regex, (matched) => chars[matched] || matched) return str.replace(regex, (matched) => chars[matched] || matched)
} }
*/
while (regex.test(str)) {
str = str.replace(regex, (matched) => chars[matched] || matched);
}
return str
} }
export const isNullOrUndefined = (value) => { export const isNullOrUndefined = (value) => {

View File

@ -3527,7 +3527,7 @@ export const calcLinePlaneSize = (points) => {
* @param degree * @param degree
* @returns number * @returns number
*/ */
export const calcLineActualSize = (points, degree) => { export const calcLineActualSize = (points, degree = 0) => {
const { x1, y1, x2, y2 } = points const { x1, y1, x2, y2 } = points
const planeSize = calcLinePlaneSize(points) const planeSize = calcLinePlaneSize(points)
let height = Big(Math.tan(Big(degree).times(Math.PI / 180))).times(planeSize) let height = Big(Math.tan(Big(degree).times(Math.PI / 180))).times(planeSize)