Merge branch 'dev' into feature/jaeyoung

# Conflicts:
#	src/util/qpolygon-utils.js
This commit is contained in:
Jaeyoung Lee 2025-03-17 17:39:17 +09:00
commit 9f76fa97c5
195 changed files with 8978 additions and 9891 deletions

View File

@ -1,4 +1,4 @@
NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080"
NEXT_PUBLIC_API_SERVER_PATH="https://api.hanasys.jp/"
NEXT_PUBLIC_HOST_URL="http://1.248.227.176:4000"
@ -7,5 +7,7 @@ SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y="
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3"
NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin"
# NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/login/autoLogin"
# NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin"
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/login/autoLogin"
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"

View File

@ -0,0 +1,36 @@
1. 회로할당 ->
수동 할당시 와트수 소수점 노출
2. 모듈 ->
멀티 모듈일시 모듈 순번에 따라 배치면 그리기 적용해야됨
멀티 모듈시 모듈 간격 붙여서 조정
3. contextMenu ->
한번 클릭 후 contextMenu 호출 재호출시 화면에 안나옴
4. 수치 입력시 ->
반각?전각? 입력 처리 필요????????????????
5. 지도 호출 ->
최초 호출 후 삭제, 재호출 안됨
6. 도면 화면 ->
redo, undo 제거
7. 모든 배치면 ->
배치면 외각선 굵기 조절
8. 패브릭 캔버스 ->
줌, 확대 기능 선택 오류 수정 필요
9. 모듈선택 ->
모듈 선택 페이지 단계 변경 예정정(현업 화면에 너무 크게 적용)
10. 외벽선 삭제시 수치 삭제 처리 필요
11. 모듈 삭제 후 재 설치시 모듈이 겹친다고 오류남
12. 모듈 수동시 첫번째는 아무데나 놓을 수 있고 두번째 부터는 무조건 주변에 모듈이 있어야 한다는 조건이 있어야 한다고 함
13. 견적서 다운로드 이미지 정비율이 아님

View File

@ -0,0 +1,10 @@
1. 오픈 예정일정 -> 신상품 7월에 오픈 그와 같이 하는게 어떻냐?
2. 웹 상에서 단축키 모드 추가
3. 형이동 동선이동 작업 해보겠다.
4. 모듈 작업 확정 (좌하, 우상)
5. 발전 시뮬레이션 qsp에 이관 작업(유지보수)

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"id":-1,"name":"Onboarding diagram","userId":-1,"createdAt":"","updatedAt":"","content":{"items":[{"uid":"HduNR37Az-","position":{"x":690,"y":-270},"sizes":{"width":400,"height":168},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"type":"text","text":"배치면 초기설정 "},{"type":"text","marks":[{"type":"bold"}],"text":"☀️"}]},{"type":"bulletList","content":[{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"플랜당 필수 설정"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"필수로 설정이 저장되어야 하기 때문에 닫기 버튼 없음"}]}]},{"type":"listItem","content":[{"type":"paragraph","content":[{"type":"text","text":"저장 버튼으로 update 처리"}]}]}]}]},"color":{"bgColor":"hsla(211, 33%, 22%, 1)","bgName":"blue"},"nodeType":"block"},{"uid":"eB4rr9xOVw","position":{"x":500,"y":-40},"sizes":{"width":810,"height":182.5},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/components/floor-plan/modal/placementShape/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"PlacementShapeSetting.jsx"}]},{"type":"paragraph","content":[{"type":"text","marks":[{"type":"bold"}],"text":"배치면 초기 설정 팝업"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, planNo, openPoint }) {"}]}]},"nodeType":"block"},{"uid":"dzN8hw1chO","position":{"x":990,"y":310},"sizes":{"width":550,"height":361},"autoheight":true,"blockContent":{"type":"doc","content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/option/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"useCanvasSetting.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 조회 및 초기화\n */\nconst fetchBasicSettings = async (planNo, openPoint) => {"}]},{"type":"paragraph"},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":false},"content":[{"type":"text","text":"/**\n * 기본설정(PlacementShapeSetting) 저장\n */\nconst basicSettingSave = async (params) => {"}]}]},"nodeType":"block"},{"uid":"YX7IHZIiqg","position":{"x":330,"y":310},"sizes":{"width":590,"height":259.5},"autoheight":true,"blockContent":{"content":[{"type":"filePathNode","attrs":{"pathToFile":"src/hooks/","version":1},"content":[{"type":"text","marks":[{"type":"bold"}],"text":"usePlan.js"}]},{"type":"codeBlock","attrs":{"language":"javascript","wrapCode":true},"content":[{"type":"text","text":"/**\n * 플랜 삭제 시 배치면 초기설정 데이터 삭제\n *\n * @param {string} objectNo - 물건번호\n * @param {string} planNo - 플랜번호\n */\nconst deleteBasicSettings = async (objectNo, planNo) => {"}]}]},"nodeType":"block"}],"configs":{"centerX":47.05904869941878,"centerY":349.9825354968084,"zoomLevel":1.017264811197917},"arrowData":{"arrowsMap":{"arrow-point-bI0wBh3Ufk-bottom-point-PSPLIYKa9J-top":{"to":"point-PSPLIYKa9J-top","from":"point-bI0wBh3Ufk-bottom","label":"Normal Box","direction":"ft","selectable":true},"arrow-point-bI0wBh3Ufk-bottom-point-ytXK_ayIc1-top":{"to":"point-ytXK_ayIc1-top","from":"point-bI0wBh3Ufk-bottom","label":"Code Box","direction":"ft","selectable":true},"arrow-point-hyyRZE3E8u-right-point-6ZopTaEaDZ-left":{"to":"point-6ZopTaEaDZ-left","from":"point-hyyRZE3E8u-right","label":"call","direction":"ft","selectable":true}},"pointsMap":{"point-PSPLIYKa9J-top":{"x":805.9999797489683,"y":60,"id":"point-PSPLIYKa9J-top","direction":"top"},"point-ytXK_ayIc1-top":{"x":205.99999493724206,"y":60,"id":"point-ytXK_ayIc1-top","direction":"top"},"point-6ZopTaEaDZ-left":{"x":220,"y":605.9999898744841,"id":"point-6ZopTaEaDZ-left","direction":"left"},"point-hyyRZE3E8u-right":{"x":100,"y":606,"id":"point-hyyRZE3E8u-right","direction":"right"},"point-bI0wBh3Ufk-bottom":{"x":515.9999797489683,"y":-40,"id":"point-bI0wBh3Ufk-bottom","direction":"bottom"}},"edgesMap":{"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-YX7IHZIiqg-YX7IHZIiqg-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"YX7IHZIiqg","toHandleId":"YX7IHZIiqg-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}},"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top":{"uid":"edge-eB4rr9xOVw-eB4rr9xOVw-bottom-dzN8hw1chO-dzN8hw1chO-top","fromNodeId":"eB4rr9xOVw","fromHandleId":"eB4rr9xOVw-bottom","toNodeId":"dzN8hw1chO","toHandleId":"dzN8hw1chO-top","direction":"ft","selectable":true,"type":"solid","content":{"label":""}}}}}}

View File

@ -15,6 +15,13 @@ const nextConfig = {
sassOptions: {
includePaths: ['./src/styles'],
},
experimental: {
staleTimes: {
dynamic: 0,
dynamicSWR: 0,
dynamicSSR: 0,
},
},
}
export default nextConfig

View File

@ -5,12 +5,12 @@
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"start": "next start -p 3000",
"start:dev": "next start -p 3001",
"lint": "next lint",
"serve": "node server.js"
},
"dependencies": {
"@nextui-org/react": "^2.4.2",
"ag-grid-react": "^32.0.2",
"axios": "^1.7.8",
"big.js": "^6.2.2",
@ -37,6 +37,8 @@
"react-responsive-modal": "^6.4.2",
"react-select": "^5.8.1",
"recoil": "^0.7.7",
"sqlite": "^5.1.1",
"sqlite3": "^5.1.7",
"sweetalert2": "^11.14.1",
"sweetalert2-react-content": "^5.0.7",
"swr": "^2.3.0",

View File

@ -1,16 +1,14 @@
<svg width="154" height="140" viewBox="0 0 154 140" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_24_15)">
<svg width="140" height="140" viewBox="0 0 140 140" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4103_3971)">
<path d="M1.65636 139L70 9.14709L138.344 139H1.65636Z" stroke="black" stroke-width="2"/>
<rect x="69" y="11" width="2" height="127" fill="black"/>
<rect x="62.5" y="74.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="62.5" y="74.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M67.7331 85.5V84.06H69.3131V79.83H67.9431V78.73C68.3431 78.6567 68.6831 78.5667 68.9631 78.46C69.2498 78.3533 69.5231 78.2167 69.7831 78.05H71.0931V84.06H72.4331V85.5H67.7331Z" fill="#101010"/>
<circle cx="70" cy="8" r="7.5" stroke="#FF0000"/>
</g>
<rect x="148" y="2" width="1" height="136" fill="black"/>
<path d="M144 6L148.5 2L153 6" stroke="black"/>
<path d="M144 134L148.5 138L153 134" stroke="black"/>
<rect x="144" width="9" height="1" fill="#FF0000"/>
<rect x="144" y="139" width="9" height="1" fill="#FF0000"/>
<defs>
<clipPath id="clip0_24_15">
<clipPath id="clip0_4103_3971">
<rect width="140" height="140" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 716 B

After

Width:  |  Height:  |  Size: 801 B

View File

@ -1,21 +1,22 @@
<svg width="154" height="155" viewBox="0 0 154 155" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_4103_3998)">
<svg width="140" height="158" viewBox="0 0 140 158" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_118_40)">
<rect x="69" y="9" width="2" height="129" fill="black"/>
<rect x="62.5" y="73.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="62.5" y="73.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M67.7331 84.5V83.06H69.3131V78.83H67.9431V77.73C68.3431 77.6567 68.6831 77.5667 68.9631 77.46C69.2498 77.3533 69.5231 77.2167 69.7831 77.05H71.0931V83.06H72.4331V84.5H67.7331Z" fill="#101010"/>
<circle cx="70" cy="8" r="7.5" stroke="#FF0000"/>
<path d="M1 139V61.4915L70 8.26297L139 61.4916V139H1Z" stroke="black" stroke-width="2"/>
<path d="M70 8.26297L139 61.4916V139H1V61.4915L70 8.26297Z" stroke="black" stroke-width="2"/>
</g>
<rect x="148" y="2" width="1" height="136" fill="black"/>
<path d="M144 6L148.5 2L153 6" stroke="black"/>
<path d="M144 134L148.5 138L153 134" stroke="black"/>
<rect x="144" width="9" height="1" fill="#FF0000"/>
<rect x="144" y="139" width="9" height="1" fill="#FF0000"/>
<rect x="2" y="150" width="1" height="136" transform="rotate(-90 2 150)" fill="black"/>
<rect x="62.5" y="142.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="62.5" y="142.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M67.3731 153.5V152.48C67.9931 151.913 68.5365 151.387 69.0031 150.9C69.4698 150.413 69.8331 149.96 70.0931 149.54C70.3531 149.113 70.4831 148.72 70.4831 148.36C70.4831 148.133 70.4431 147.943 70.3631 147.79C70.2898 147.63 70.1798 147.51 70.0331 147.43C69.8865 147.35 69.7131 147.31 69.5131 147.31C69.2598 147.31 69.0298 147.383 68.8231 147.53C68.6231 147.67 68.4331 147.837 68.2531 148.03L67.2831 147.07C67.6498 146.677 68.0198 146.387 68.3931 146.2C68.7731 146.013 69.2265 145.92 69.7531 145.92C70.2331 145.92 70.6565 146.017 71.0231 146.21C71.3898 146.403 71.6765 146.677 71.8831 147.03C72.0898 147.377 72.1931 147.787 72.1931 148.26C72.1931 148.687 72.0831 149.123 71.8631 149.57C71.6498 150.01 71.3731 150.447 71.0331 150.88C70.6931 151.307 70.3331 151.713 69.9531 152.1C70.1398 152.073 70.3465 152.05 70.5731 152.03C70.8065 152.01 71.0065 152 71.1731 152H72.5331V153.5H67.3731Z" fill="#101010"/>
<path d="M6 154L2 149.5L6 145" stroke="black"/>
<path d="M134 154L138 149.5L134 145" stroke="black"/>
<rect y="154" width="9" height="1" transform="rotate(-90 0 154)" fill="#FF0000"/>
<rect x="139" y="154" width="9" height="1" transform="rotate(-90 139 154)" fill="#FF0000"/>
<defs>
<clipPath id="clip0_4103_3998">
<clipPath id="clip0_118_40">
<rect width="140" height="140" fill="white"/>
</clipPath>
</defs>

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -1,12 +1,16 @@
<svg width="110" height="108" viewBox="0 0 110 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 21L55.5 106L109 21" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(1 0 0 -1 0 21.5)" fill="#101010"/>
<path d="M55 100L55 24" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M1 8L110 8" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="0.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="0.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.7331 11.5V10.06H54.3131V5.83L52.9431 5.83V4.73C53.3431 4.65667 53.6831 4.56667 53.9631 4.46C54.2498 4.35333 54.5231 4.21667 54.7831 4.05H56.0931V10.06H57.4331V11.5H52.7331Z" fill="#101010"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.3731 58.5V57.48C52.9931 56.9133 53.5365 56.3867 54.0031 55.9C54.4698 55.4133 54.8331 54.96 55.0931 54.54C55.3531 54.1133 55.4831 53.72 55.4831 53.36C55.4831 53.1333 55.4431 52.9433 55.3631 52.79C55.2898 52.63 55.1798 52.51 55.0331 52.43C54.8865 52.35 54.7131 52.31 54.5131 52.31C54.2598 52.31 54.0298 52.3833 53.8231 52.53C53.6231 52.67 53.4331 52.8367 53.2531 53.03L52.2831 52.07C52.6498 51.6767 53.0198 51.3867 53.3931 51.2C53.7731 51.0133 54.2265 50.92 54.7531 50.92C55.2331 50.92 55.6565 51.0167 56.0231 51.21C56.3898 51.4033 56.6765 51.6767 56.8831 52.03C57.0898 52.3767 57.1931 52.7867 57.1931 53.26C57.1931 53.6867 57.0831 54.1233 56.8631 54.57C56.6498 55.01 56.3731 55.4467 56.0331 55.88C55.6931 56.3067 55.3331 56.7133 54.9531 57.1C55.1398 57.0733 55.3465 57.05 55.5731 57.03C55.8065 57.01 56.0065 57 56.1731 57H57.5331V58.5H52.3731Z" fill="#101010"/>
<svg width="119" height="115" viewBox="0 0 119 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M109 21.8171L54.5 106.817L1 21.8171" stroke="#45CD7D" stroke-width="2"/>
<rect x="110" y="22.3171" width="110" height="2" transform="rotate(180 110 22.3171)" fill="#101010"/>
<path d="M55 100.817V24.8171" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M109 8.81714L-1.90735e-06 8.81714" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M66.5 108.317L118.5 26.8172" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="48.3171" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="48.3171" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 59.3171V58.2971C52.9931 57.7305 53.5365 57.2038 54.0031 56.7171C54.4698 56.2305 54.8331 55.7771 55.0931 55.3571C55.3531 54.9305 55.4831 54.5371 55.4831 54.1771C55.4831 53.9505 55.4431 53.7605 55.3631 53.6071C55.2898 53.4471 55.1798 53.3271 55.0331 53.2471C54.8865 53.1671 54.7131 53.1271 54.5131 53.1271C54.2598 53.1271 54.0298 53.2005 53.8231 53.3471C53.6231 53.4871 53.4331 53.6538 53.2531 53.8471L52.2831 52.8871C52.6498 52.4938 53.0198 52.2038 53.3931 52.0171C53.7731 51.8305 54.2265 51.7371 54.7531 51.7371C55.2331 51.7371 55.6565 51.8338 56.0231 52.0271C56.3898 52.2205 56.6765 52.4938 56.8831 52.8471C57.0898 53.1938 57.1931 53.6038 57.1931 54.0771C57.1931 54.5038 57.0831 54.9405 56.8631 55.3871C56.6498 55.8271 56.3731 56.2638 56.0331 56.6971C55.6931 57.1238 55.3331 57.5305 54.9531 57.9171C55.1398 57.8905 55.3465 57.8671 55.5731 57.8471C55.8065 57.8271 56.0065 57.8171 56.1731 57.8171H57.5331V59.3171H52.3731Z" fill="#101010"/>
<rect x="47.5" y="1.31714" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="1.31714" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.7331 12.3171V10.8771H54.3131V6.64714H52.9431V5.54714C53.3431 5.47381 53.6831 5.3838 53.9631 5.27714C54.2498 5.17047 54.5231 5.0338 54.7831 4.86714H56.0931V10.8771H57.4331V12.3171H52.7331Z" fill="#101010"/>
<rect x="86.5" y="59.3171" width="15" height="15" rx="7.5" fill="white"/>
<rect x="86.5" y="59.3171" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M93.7431 70.4571C93.3498 70.4571 92.9931 70.4138 92.6731 70.3271C92.3598 70.2405 92.0798 70.1205 91.8331 69.9671C91.5865 69.8071 91.3731 69.6238 91.1931 69.4171L92.0131 68.2971C92.2398 68.5038 92.4831 68.6771 92.7431 68.8171C93.0031 68.9505 93.2765 69.0171 93.5631 69.0171C93.7965 69.0171 93.9965 68.9871 94.1631 68.9271C94.3365 68.8605 94.4698 68.7638 94.5631 68.6371C94.6565 68.5105 94.7031 68.3538 94.7031 68.1671C94.7031 67.9538 94.6531 67.7705 94.5531 67.6171C94.4531 67.4638 94.2665 67.3471 93.9931 67.2671C93.7198 67.1871 93.3231 67.1471 92.8031 67.1471V65.8871C93.2298 65.8871 93.5631 65.8471 93.8031 65.7671C94.0431 65.6871 94.2131 65.5738 94.3131 65.4271C94.4198 65.2805 94.4731 65.1105 94.4731 64.9171C94.4731 64.6638 94.3998 64.4705 94.2531 64.3371C94.1065 64.1971 93.8965 64.1271 93.6231 64.1271C93.3765 64.1271 93.1498 64.1805 92.9431 64.2871C92.7365 64.3938 92.5198 64.5471 92.2931 64.7471L91.3931 63.6571C91.7398 63.3638 92.0998 63.1371 92.4731 62.9771C92.8531 62.8171 93.2631 62.7371 93.7031 62.7371C94.2165 62.7371 94.6631 62.8171 95.0431 62.9771C95.4298 63.1305 95.7265 63.3605 95.9331 63.6671C96.1465 63.9671 96.2531 64.3405 96.2531 64.7871C96.2531 65.1538 96.1531 65.4805 95.9531 65.7671C95.7531 66.0471 95.4565 66.2671 95.0631 66.4271V66.4771C95.3365 66.5571 95.5798 66.6805 95.7931 66.8471C96.0131 67.0071 96.1831 67.2071 96.3031 67.4471C96.4298 67.6871 96.4931 67.9671 96.4931 68.2871C96.4931 68.7471 96.3665 69.1405 96.1131 69.4671C95.8598 69.7871 95.5231 70.0338 95.1031 70.2071C94.6898 70.3738 94.2365 70.4571 93.7431 70.4571Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -1,12 +1,16 @@
<svg width="108" height="110" viewBox="0 0 108 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M87 109L2 54.5L87 1" stroke="#45CD7D" stroke-width="2"/>
<rect x="86.5" y="110" width="110" height="2" transform="rotate(-90 86.5 110)" fill="#101010"/>
<path d="M8 55L84 55" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M100 109L100 -1.90735e-06" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="45.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="45.5" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M50.3731 58.5V57.48C50.9931 56.9133 51.5365 56.3867 52.0031 55.9C52.4698 55.4133 52.8331 54.96 53.0931 54.54C53.3531 54.1133 53.4831 53.72 53.4831 53.36C53.4831 53.1333 53.4431 52.9433 53.3631 52.79C53.2898 52.63 53.1798 52.51 53.0331 52.43C52.8865 52.35 52.7131 52.31 52.5131 52.31C52.2598 52.31 52.0298 52.3833 51.8231 52.53C51.6231 52.67 51.4331 52.8367 51.2531 53.03L50.2831 52.07C50.6498 51.6767 51.0198 51.3867 51.3931 51.2C51.7731 51.0133 52.2265 50.92 52.7531 50.92C53.2331 50.92 53.6565 51.0167 54.0231 51.21C54.3898 51.4033 54.6765 51.6767 54.8831 52.03C55.0898 52.3767 55.1931 52.7867 55.1931 53.26C55.1931 53.6867 55.0831 54.1233 54.8631 54.57C54.6498 55.01 54.3731 55.4467 54.0331 55.88C53.6931 56.3067 53.3331 56.7133 52.9531 57.1C53.1398 57.0733 53.3465 57.05 53.5731 57.03C53.8065 57.01 54.0065 57 54.1731 57H55.5331V58.5H50.3731Z" fill="#101010"/>
<rect x="92.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="92.5" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M97.7331 58.5V57.06H99.3131V52.83H97.9431V51.73C98.3431 51.6567 98.6831 51.5667 98.9631 51.46C99.2498 51.3533 99.5231 51.2167 99.7831 51.05H101.093V57.06H102.433V58.5H97.7331Z" fill="#101010"/>
<svg width="115" height="119" viewBox="0 0 115 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M93.1826 109L8.18262 54.5L93.1826 1" stroke="#45CD7D" stroke-width="2"/>
<rect x="92.1826" y="110" width="110" height="2" transform="rotate(-90 92.1826 110)" fill="#101010"/>
<path d="M14.1826 55H90.1826" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M106.183 109V-1.90735e-06" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M6.68276 66.5L88.1828 118.5" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="51.6826" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="51.6826" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M56.5557 58.5V57.48C57.1757 56.9133 57.7191 56.3867 58.1857 55.9C58.6524 55.4133 59.0157 54.96 59.2757 54.54C59.5357 54.1133 59.6657 53.72 59.6657 53.36C59.6657 53.1333 59.6257 52.9433 59.5457 52.79C59.4724 52.63 59.3624 52.51 59.2157 52.43C59.0691 52.35 58.8957 52.31 58.6957 52.31C58.4424 52.31 58.2124 52.3833 58.0057 52.53C57.8057 52.67 57.6157 52.8367 57.4357 53.03L56.4657 52.07C56.8324 51.6767 57.2024 51.3867 57.5757 51.2C57.9557 51.0133 58.4091 50.92 58.9357 50.92C59.4157 50.92 59.8391 51.0167 60.2057 51.21C60.5724 51.4033 60.8591 51.6767 61.0657 52.03C61.2724 52.3767 61.3757 52.7867 61.3757 53.26C61.3757 53.6867 61.2657 54.1233 61.0457 54.57C60.8324 55.01 60.5557 55.4467 60.2157 55.88C59.8757 56.3067 59.5157 56.7133 59.1357 57.1C59.3224 57.0733 59.5291 57.05 59.7557 57.03C59.9891 57.01 60.1891 57 60.3557 57H61.7157V58.5H56.5557Z" fill="#101010"/>
<rect x="98.6826" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="98.6826" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M103.916 58.5V57.06H105.496V52.83H104.126V51.73C104.526 51.6567 104.866 51.5667 105.146 51.46C105.432 51.3533 105.706 51.2167 105.966 51.05H107.276V57.06H108.616V58.5H103.916Z" fill="#101010"/>
<rect x="40.6826" y="86.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="40.6826" y="86.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M47.9257 97.64C47.5324 97.64 47.1757 97.5967 46.8557 97.51C46.5424 97.4233 46.2624 97.3033 46.0157 97.15C45.7691 96.99 45.5557 96.8067 45.3757 96.6L46.1957 95.48C46.4224 95.6867 46.6657 95.86 46.9257 96C47.1857 96.1333 47.4591 96.2 47.7457 96.2C47.9791 96.2 48.1791 96.17 48.3457 96.11C48.5191 96.0433 48.6524 95.9467 48.7457 95.82C48.8391 95.6933 48.8857 95.5367 48.8857 95.35C48.8857 95.1367 48.8357 94.9533 48.7357 94.8C48.6357 94.6467 48.4491 94.53 48.1757 94.45C47.9024 94.37 47.5057 94.33 46.9857 94.33V93.07C47.4124 93.07 47.7457 93.03 47.9857 92.95C48.2257 92.87 48.3957 92.7567 48.4957 92.61C48.6024 92.4633 48.6557 92.2933 48.6557 92.1C48.6557 91.8467 48.5824 91.6533 48.4357 91.52C48.2891 91.38 48.0791 91.31 47.8057 91.31C47.5591 91.31 47.3324 91.3633 47.1257 91.47C46.9191 91.5767 46.7024 91.73 46.4757 91.93L45.5757 90.84C45.9224 90.5467 46.2824 90.32 46.6557 90.16C47.0357 90 47.4457 89.92 47.8857 89.92C48.3991 89.92 48.8457 90 49.2257 90.16C49.6124 90.3133 49.9091 90.5433 50.1157 90.85C50.3291 91.15 50.4357 91.5233 50.4357 91.97C50.4357 92.3367 50.3357 92.6633 50.1357 92.95C49.9357 93.23 49.6391 93.45 49.2457 93.61V93.66C49.5191 93.74 49.7624 93.8633 49.9757 94.03C50.1957 94.19 50.3657 94.39 50.4857 94.63C50.6124 94.87 50.6757 95.15 50.6757 95.47C50.6757 95.93 50.5491 96.3233 50.2957 96.65C50.0424 96.97 49.7057 97.2167 49.2857 97.39C48.8724 97.5567 48.4191 97.64 47.9257 97.64Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,12 +1,16 @@
<svg width="108" height="110" viewBox="0 0 108 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 1L106 55.5L21 109" stroke="#45CD7D" stroke-width="2"/>
<rect x="21.5" width="110" height="2" transform="rotate(90 21.5 0)" fill="#101010"/>
<path d="M100 55L24 55" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M8 1V110" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 58.5V57.48C52.9931 56.9133 53.5365 56.3867 54.0031 55.9C54.4698 55.4133 54.8331 54.96 55.0931 54.54C55.3531 54.1133 55.4831 53.72 55.4831 53.36C55.4831 53.1333 55.4431 52.9433 55.3631 52.79C55.2898 52.63 55.1798 52.51 55.0331 52.43C54.8865 52.35 54.7131 52.31 54.5131 52.31C54.2598 52.31 54.0298 52.3833 53.8231 52.53C53.6231 52.67 53.4331 52.8367 53.2531 53.03L52.2831 52.07C52.6498 51.6767 53.0198 51.3867 53.3931 51.2C53.7731 51.0133 54.2265 50.92 54.7531 50.92C55.2331 50.92 55.6565 51.0167 56.0231 51.21C56.3898 51.4033 56.6765 51.6767 56.8831 52.03C57.0898 52.3767 57.1931 52.7867 57.1931 53.26C57.1931 53.6867 57.0831 54.1233 56.8631 54.57C56.6498 55.01 56.3731 55.4467 56.0331 55.88C55.6931 56.3067 55.3331 56.7133 54.9531 57.1C55.1398 57.0733 55.3465 57.05 55.5731 57.03C55.8065 57.01 56.0065 57 56.1731 57H57.5331V58.5H52.3731Z" fill="#101010"/>
<rect x="0.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="0.5" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M5.73313 58.5V57.06H7.31313V52.83H5.94313V51.73C6.34313 51.6567 6.68313 51.5667 6.96313 51.46C7.24979 51.3533 7.52313 51.2167 7.78313 51.05H9.09313V57.06H10.4331V58.5H5.73313Z" fill="#101010"/>
<svg width="115" height="119" viewBox="0 0 115 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.8171 10L106.817 64.5L21.8171 118" stroke="#45CD7D" stroke-width="2"/>
<rect x="22.3171" y="9" width="110" height="2" transform="rotate(90 22.3171 9)" fill="#101010"/>
<path d="M100.817 64H24.8171" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M8.81714 10L8.81714 119" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M108.317 52.5L26.8172 0.500029" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="48.3171" y="56.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="48.3171" y="56.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M53.1903 67.5V66.48C53.8103 65.9133 54.3536 65.3867 54.8203 64.9C55.2869 64.4133 55.6503 63.96 55.9103 63.54C56.1703 63.1133 56.3003 62.72 56.3003 62.36C56.3003 62.1333 56.2603 61.9433 56.1803 61.79C56.1069 61.63 55.9969 61.51 55.8503 61.43C55.7036 61.35 55.5303 61.31 55.3303 61.31C55.0769 61.31 54.8469 61.3833 54.6403 61.53C54.4403 61.67 54.2503 61.8367 54.0703 62.03L53.1003 61.07C53.4669 60.6767 53.8369 60.3867 54.2103 60.2C54.5903 60.0133 55.0436 59.92 55.5703 59.92C56.0503 59.92 56.4736 60.0167 56.8403 60.21C57.2069 60.4033 57.4936 60.6767 57.7003 61.03C57.9069 61.3767 58.0103 61.7867 58.0103 62.26C58.0103 62.6867 57.9003 63.1233 57.6803 63.57C57.4669 64.01 57.1903 64.4467 56.8503 64.88C56.5103 65.3067 56.1503 65.7133 55.7703 66.1C55.9569 66.0733 56.1636 66.05 56.3903 66.03C56.6236 66.01 56.8236 66 56.9903 66H58.3503V67.5H53.1903Z" fill="#101010"/>
<rect x="1.31714" y="56.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="1.31714" y="56.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M6.55026 67.5V66.06H8.13026V61.83H6.76026V60.73C7.16026 60.6567 7.50026 60.5667 7.78026 60.46C8.06693 60.3533 8.34026 60.2167 8.60026 60.05H9.91026V66.06H11.2503V67.5H6.55026Z" fill="#101010"/>
<rect x="59.3171" y="17.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="59.3171" y="17.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M66.5603 28.64C66.1669 28.64 65.8103 28.5967 65.4903 28.51C65.1769 28.4233 64.8969 28.3033 64.6503 28.15C64.4036 27.99 64.1903 27.8067 64.0103 27.6L64.8303 26.48C65.0569 26.6867 65.3003 26.86 65.5603 27C65.8203 27.1333 66.0936 27.2 66.3803 27.2C66.6136 27.2 66.8136 27.17 66.9803 27.11C67.1536 27.0433 67.2869 26.9467 67.3803 26.82C67.4736 26.6933 67.5203 26.5367 67.5203 26.35C67.5203 26.1367 67.4703 25.9533 67.3703 25.8C67.2703 25.6467 67.0836 25.53 66.8103 25.45C66.5369 25.37 66.1403 25.33 65.6203 25.33V24.07C66.0469 24.07 66.3803 24.03 66.6203 23.95C66.8603 23.87 67.0303 23.7567 67.1303 23.61C67.2369 23.4633 67.2903 23.2933 67.2903 23.1C67.2903 22.8467 67.2169 22.6533 67.0703 22.52C66.9236 22.38 66.7136 22.31 66.4403 22.31C66.1936 22.31 65.9669 22.3633 65.7603 22.47C65.5536 22.5767 65.3369 22.73 65.1103 22.93L64.2103 21.84C64.5569 21.5467 64.9169 21.32 65.2903 21.16C65.6703 21 66.0803 20.92 66.5203 20.92C67.0336 20.92 67.4803 21 67.8603 21.16C68.2469 21.3133 68.5436 21.5433 68.7503 21.85C68.9636 22.15 69.0703 22.5233 69.0703 22.97C69.0703 23.3367 68.9703 23.6633 68.7703 23.95C68.5703 24.23 68.2736 24.45 67.8803 24.61V24.66C68.1536 24.74 68.3969 24.8633 68.6103 25.03C68.8303 25.19 69.0003 25.39 69.1203 25.63C69.2469 25.87 69.3103 26.15 69.3103 26.47C69.3103 26.93 69.1836 27.3233 68.9303 27.65C68.6769 27.97 68.3403 28.2167 67.9203 28.39C67.5069 28.5567 67.0536 28.64 66.5603 28.64Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,12 +1,16 @@
<svg width="110" height="108" viewBox="0 0 110 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 87L55.5 2L109 87" stroke="#45CD7D" stroke-width="2"/>
<rect y="86.5" width="110" height="2" fill="#101010"/>
<path d="M55 8V84" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M1 100H110" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="45.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="45.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 56.5V55.48C52.9931 54.9133 53.5365 54.3867 54.0031 53.9C54.4698 53.4133 54.8331 52.96 55.0931 52.54C55.3531 52.1133 55.4831 51.72 55.4831 51.36C55.4831 51.1333 55.4431 50.9433 55.3631 50.79C55.2898 50.63 55.1798 50.51 55.0331 50.43C54.8865 50.35 54.7131 50.31 54.5131 50.31C54.2598 50.31 54.0298 50.3833 53.8231 50.53C53.6231 50.67 53.4331 50.8367 53.2531 51.03L52.2831 50.07C52.6498 49.6767 53.0198 49.3867 53.3931 49.2C53.7731 49.0133 54.2265 48.92 54.7531 48.92C55.2331 48.92 55.6565 49.0167 56.0231 49.21C56.3898 49.4033 56.6765 49.6767 56.8831 50.03C57.0898 50.3767 57.1931 50.7867 57.1931 51.26C57.1931 51.6867 57.0831 52.1233 56.8631 52.57C56.6498 53.01 56.3731 53.4467 56.0331 53.88C55.6931 54.3067 55.3331 54.7133 54.9531 55.1C55.1398 55.0733 55.3465 55.05 55.5731 55.03C55.8065 55.01 56.0065 55 56.1731 55H57.5331V56.5H52.3731Z" fill="#101010"/>
<rect x="47.5" y="92.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="92.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.7331 103.5V102.06H54.3131V97.83H52.9431V96.73C53.3431 96.6567 53.6831 96.5667 53.9631 96.46C54.2498 96.3533 54.5231 96.2167 54.7831 96.05H56.0931V102.06H57.4331V103.5H52.7331Z" fill="#101010"/>
<svg width="119" height="115" viewBox="0 0 119 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 93.1829L64.5 8.18286L118 93.1829" stroke="#45CD7D" stroke-width="2"/>
<rect x="9" y="92.1829" width="110" height="2" fill="#101010"/>
<path d="M64 14.1829V90.1829" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M10 106.183H119" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M52.5 6.68276L0.500029 88.1828" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="56.5" y="51.6829" width="15" height="15" rx="7.5" fill="white"/>
<rect x="56.5" y="51.6829" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M61.3731 62.6829V61.6629C61.9931 61.0962 62.5365 60.5695 63.0031 60.0829C63.4698 59.5962 63.8331 59.1429 64.0931 58.7229C64.3531 58.2962 64.4831 57.9029 64.4831 57.5429C64.4831 57.3162 64.4431 57.1262 64.3631 56.9729C64.2898 56.8129 64.1798 56.6929 64.0331 56.6129C63.8865 56.5329 63.7131 56.4929 63.5131 56.4929C63.2598 56.4929 63.0298 56.5662 62.8231 56.7129C62.6231 56.8529 62.4331 57.0195 62.2531 57.2129L61.2831 56.2529C61.6498 55.8595 62.0198 55.5695 62.3931 55.3829C62.7731 55.1962 63.2265 55.1029 63.7531 55.1029C64.2331 55.1029 64.6565 55.1995 65.0231 55.3929C65.3898 55.5862 65.6765 55.8595 65.8831 56.2129C66.0898 56.5595 66.1931 56.9695 66.1931 57.4429C66.1931 57.8695 66.0831 58.3062 65.8631 58.7529C65.6498 59.1929 65.3731 59.6295 65.0331 60.0629C64.6931 60.4895 64.3331 60.8962 63.9531 61.2829C64.1398 61.2562 64.3465 61.2329 64.5731 61.2129C64.8065 61.1929 65.0065 61.1829 65.1731 61.1829H66.5331V62.6829H61.3731Z" fill="#101010"/>
<rect x="56.5" y="98.6829" width="15" height="15" rx="7.5" fill="white"/>
<rect x="56.5" y="98.6829" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M61.7331 109.683V108.243H63.3131V104.013H61.9431V102.913C62.3431 102.84 62.6831 102.75 62.9631 102.643C63.2498 102.536 63.5231 102.4 63.7831 102.233H65.0931V108.243H66.4331V109.683H61.7331Z" fill="#101010"/>
<rect x="17.5" y="40.6829" width="15" height="15" rx="7.5" fill="white"/>
<rect x="17.5" y="40.6829" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M24.7431 51.8229C24.3498 51.8229 23.9931 51.7795 23.6731 51.6929C23.3598 51.6062 23.0798 51.4862 22.8331 51.3329C22.5865 51.1729 22.3731 50.9895 22.1931 50.7829L23.0131 49.6629C23.2398 49.8695 23.4831 50.0429 23.7431 50.1829C24.0031 50.3162 24.2765 50.3829 24.5631 50.3829C24.7965 50.3829 24.9965 50.3529 25.1631 50.2929C25.3365 50.2262 25.4698 50.1295 25.5631 50.0029C25.6565 49.8762 25.7031 49.7195 25.7031 49.5329C25.7031 49.3195 25.6531 49.1362 25.5531 48.9829C25.4531 48.8295 25.2665 48.7129 24.9931 48.6329C24.7198 48.5529 24.3231 48.5129 23.8031 48.5129V47.2529C24.2298 47.2529 24.5631 47.2129 24.8031 47.1329C25.0431 47.0529 25.2131 46.9395 25.3131 46.7929C25.4198 46.6462 25.4731 46.4762 25.4731 46.2829C25.4731 46.0295 25.3998 45.8362 25.2531 45.7029C25.1065 45.5629 24.8965 45.4929 24.6231 45.4929C24.3765 45.4929 24.1498 45.5462 23.9431 45.6529C23.7365 45.7595 23.5198 45.9129 23.2931 46.1129L22.3931 45.0229C22.7398 44.7295 23.0998 44.5029 23.4731 44.3429C23.8531 44.1829 24.2631 44.1029 24.7031 44.1029C25.2165 44.1029 25.6631 44.1829 26.0431 44.3429C26.4298 44.4962 26.7265 44.7262 26.9331 45.0329C27.1465 45.3329 27.2531 45.7062 27.2531 46.1529C27.2531 46.5195 27.1531 46.8462 26.9531 47.1329C26.7531 47.4129 26.4565 47.6329 26.0631 47.7929V47.8429C26.3365 47.9229 26.5798 48.0462 26.7931 48.2129C27.0131 48.3729 27.1831 48.5729 27.3031 48.8129C27.4298 49.0529 27.4931 49.3329 27.4931 49.6529C27.4931 50.1129 27.3665 50.5062 27.1131 50.8329C26.8598 51.1529 26.5231 51.3995 26.1031 51.5729C25.6898 51.7395 25.2365 51.8229 24.7431 51.8229Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,12 +1,16 @@
<svg width="110" height="108" viewBox="0 0 110 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 21L55.5 106L109 21" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(1 0 0 -1 0 21.5)" fill="#101010"/>
<path d="M55 100V24" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M1 8L110 8" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 58.5V57.48C52.9931 56.9133 53.5365 56.3867 54.0031 55.9C54.4698 55.4133 54.8331 54.96 55.0931 54.54C55.3531 54.1133 55.4831 53.72 55.4831 53.36C55.4831 53.1333 55.4431 52.9433 55.3631 52.79C55.2898 52.63 55.1798 52.51 55.0331 52.43C54.8865 52.35 54.7131 52.31 54.5131 52.31C54.2598 52.31 54.0298 52.3833 53.8231 52.53C53.6231 52.67 53.4331 52.8367 53.2531 53.03L52.2831 52.07C52.6498 51.6767 53.0198 51.3867 53.3931 51.2C53.7731 51.0133 54.2265 50.92 54.7531 50.92C55.2331 50.92 55.6565 51.0167 56.0231 51.21C56.3898 51.4033 56.6765 51.6767 56.8831 52.03C57.0898 52.3767 57.1931 52.7867 57.1931 53.26C57.1931 53.6867 57.0831 54.1233 56.8631 54.57C56.6498 55.01 56.3731 55.4467 56.0331 55.88C55.6931 56.3067 55.3331 56.7133 54.9531 57.1C55.1398 57.0733 55.3465 57.05 55.5731 57.03C55.8065 57.01 56.0065 57 56.1731 57H57.5331V58.5H52.3731Z" fill="#101010"/>
<rect x="47.5" y="0.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="0.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.7331 11.5V10.06H54.3131V5.83H52.9431V4.73C53.3431 4.65667 53.6831 4.56667 53.9631 4.46C54.2498 4.35333 54.5231 4.21667 54.7831 4.05H56.0931V10.06H57.4331V11.5H52.7331Z" fill="#101010"/>
<svg width="119" height="115" viewBox="0 0 119 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 21.8171L64.5 106.817L118 21.8171" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(1 0 0 -1 9 22.3171)" fill="#101010"/>
<path d="M64 100.817V24.8171" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M10 8.81714L119 8.81714" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M52.5005 108.317L0.500517 26.8172" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="56.5" y="48.3174" width="15" height="15" rx="7.5" fill="white"/>
<rect x="56.5" y="48.3174" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M61.3731 59.3174V58.2974C61.9931 57.7307 62.5365 57.204 63.0031 56.7174C63.4698 56.2307 63.8331 55.7774 64.0931 55.3574C64.3531 54.9307 64.4831 54.5374 64.4831 54.1774C64.4831 53.9507 64.4431 53.7607 64.3631 53.6074C64.2898 53.4474 64.1798 53.3274 64.0331 53.2474C63.8865 53.1674 63.7131 53.1274 63.5131 53.1274C63.2598 53.1274 63.0298 53.2007 62.8231 53.3474C62.6231 53.4874 62.4331 53.654 62.2531 53.8474L61.2831 52.8874C61.6498 52.494 62.0198 52.204 62.3931 52.0174C62.7731 51.8307 63.2265 51.7374 63.7531 51.7374C64.2331 51.7374 64.6565 51.834 65.0231 52.0274C65.3898 52.2207 65.6765 52.494 65.8831 52.8474C66.0898 53.194 66.1931 53.604 66.1931 54.0774C66.1931 54.504 66.0831 54.9407 65.8631 55.3874C65.6498 55.8274 65.3731 56.264 65.0331 56.6974C64.6931 57.124 64.3331 57.5307 63.9531 57.9174C64.1398 57.8907 64.3465 57.8674 64.5731 57.8474C64.8065 57.8274 65.0065 57.8174 65.1731 57.8174H66.5331V59.3174H61.3731Z" fill="#101010"/>
<rect x="56.5" y="1.31738" width="15" height="15" rx="7.5" fill="white"/>
<rect x="56.5" y="1.31738" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M61.7331 12.3174V10.8774H63.3131V6.64738H61.9431V5.54738C62.3431 5.47405 62.6831 5.38405 62.9631 5.27738C63.2498 5.17072 63.5231 5.03405 63.7831 4.86738H65.0931V10.8774H66.4331V12.3174H61.7331Z" fill="#101010"/>
<rect x="17.5" y="59.3174" width="15" height="15" rx="7.5" fill="white"/>
<rect x="17.5" y="59.3174" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M24.7431 70.4574C24.3498 70.4574 23.9931 70.414 23.6731 70.3274C23.3598 70.2407 23.0798 70.1207 22.8331 69.9674C22.5865 69.8074 22.3731 69.624 22.1931 69.4174L23.0131 68.2974C23.2398 68.504 23.4831 68.6774 23.7431 68.8174C24.0031 68.9507 24.2765 69.0174 24.5631 69.0174C24.7965 69.0174 24.9965 68.9874 25.1631 68.9274C25.3365 68.8607 25.4698 68.764 25.5631 68.6374C25.6565 68.5107 25.7031 68.354 25.7031 68.1674C25.7031 67.954 25.6531 67.7707 25.5531 67.6174C25.4531 67.464 25.2665 67.3474 24.9931 67.2674C24.7198 67.1874 24.3231 67.1474 23.8031 67.1474V65.8874C24.2298 65.8874 24.5631 65.8474 24.8031 65.7674C25.0431 65.6874 25.2131 65.574 25.3131 65.4274C25.4198 65.2807 25.4731 65.1107 25.4731 64.9174C25.4731 64.664 25.3998 64.4707 25.2531 64.3374C25.1065 64.1974 24.8965 64.1274 24.6231 64.1274C24.3765 64.1274 24.1498 64.1807 23.9431 64.2874C23.7365 64.394 23.5198 64.5474 23.2931 64.7474L22.3931 63.6574C22.7398 63.364 23.0998 63.1374 23.4731 62.9774C23.8531 62.8174 24.2631 62.7374 24.7031 62.7374C25.2165 62.7374 25.6631 62.8174 26.0431 62.9774C26.4298 63.1307 26.7265 63.3607 26.9331 63.6674C27.1465 63.9674 27.2531 64.3407 27.2531 64.7874C27.2531 65.154 27.1531 65.4807 26.9531 65.7674C26.7531 66.0474 26.4565 66.2674 26.0631 66.4274V66.4774C26.3365 66.5574 26.5798 66.6807 26.7931 66.8474C27.0131 67.0074 27.1831 67.2074 27.3031 67.4474C27.4298 67.6874 27.4931 67.9674 27.4931 68.2874C27.4931 68.7474 27.3665 69.1407 27.1131 69.4674C26.8598 69.7874 26.5231 70.034 26.1031 70.2074C25.6898 70.374 25.2365 70.4574 24.7431 70.4574Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

View File

@ -1,12 +1,16 @@
<svg width="108" height="110" viewBox="0 0 108 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M87 1L2 55.5L87 109" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(0 1 1 0 86.5 0)" fill="#101010"/>
<path d="M8 55L84 55" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M100 1L100 110" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="45.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="45.5" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M50.3731 58.5V57.48C50.9931 56.9133 51.5365 56.3867 52.0031 55.9C52.4698 55.4133 52.8331 54.96 53.0931 54.54C53.3531 54.1133 53.4831 53.72 53.4831 53.36C53.4831 53.1333 53.4431 52.9433 53.3631 52.79C53.2898 52.63 53.1798 52.51 53.0331 52.43C52.8865 52.35 52.7131 52.31 52.5131 52.31C52.2598 52.31 52.0298 52.3833 51.8231 52.53C51.6231 52.67 51.4331 52.8367 51.2531 53.03L50.2831 52.07C50.6498 51.6767 51.0198 51.3867 51.3931 51.2C51.7731 51.0133 52.2265 50.92 52.7531 50.92C53.2331 50.92 53.6565 51.0167 54.0231 51.21C54.3898 51.4033 54.6765 51.6767 54.8831 52.03C55.0898 52.3767 55.1931 52.7867 55.1931 53.26C55.1931 53.6867 55.0831 54.1233 54.8631 54.57C54.6498 55.01 54.3731 55.4467 54.0331 55.88C53.6931 56.3067 53.3331 56.7133 52.9531 57.1C53.1398 57.0733 53.3465 57.05 53.5731 57.03C53.8065 57.01 54.0065 57 54.1731 57H55.5331V58.5H50.3731Z" fill="#101010"/>
<rect x="92.5" y="62.5" width="15" height="15" rx="7.5" transform="rotate(-90 92.5 62.5)" fill="white"/>
<rect x="92.5" y="62.5" width="15" height="15" rx="7.5" transform="rotate(-90 92.5 62.5)" stroke="#101010"/>
<path d="M97.7331 58.5V57.06H99.3131V52.83H97.9431V51.73C98.3431 51.6567 98.6831 51.5667 98.9631 51.46C99.2498 51.3533 99.5231 51.2167 99.7831 51.05H101.093V57.06H102.433V58.5H97.7331Z" fill="#101010"/>
<svg width="115" height="119" viewBox="0 0 115 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M93.1826 10L8.18262 64.5L93.1826 118" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(0 1 1 0 92.1826 9)" fill="#101010"/>
<path d="M14.1826 64H90.1826" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M106.183 10V119" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M6.68276 52.5L88.1828 0.500029" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="51.6826" y="56.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="51.6826" y="56.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M56.5557 67.5V66.48C57.1757 65.9133 57.7191 65.3867 58.1857 64.9C58.6524 64.4133 59.0157 63.96 59.2757 63.54C59.5357 63.1133 59.6657 62.72 59.6657 62.36C59.6657 62.1333 59.6257 61.9433 59.5457 61.79C59.4724 61.63 59.3624 61.51 59.2157 61.43C59.0691 61.35 58.8957 61.31 58.6957 61.31C58.4424 61.31 58.2124 61.3833 58.0057 61.53C57.8057 61.67 57.6157 61.8367 57.4357 62.03L56.4657 61.07C56.8324 60.6767 57.2024 60.3867 57.5757 60.2C57.9557 60.0133 58.4091 59.92 58.9357 59.92C59.4157 59.92 59.8391 60.0167 60.2057 60.21C60.5724 60.4033 60.8591 60.6767 61.0657 61.03C61.2724 61.3767 61.3757 61.7867 61.3757 62.26C61.3757 62.6867 61.2657 63.1233 61.0457 63.57C60.8324 64.01 60.5557 64.4467 60.2157 64.88C59.8757 65.3067 59.5157 65.7133 59.1357 66.1C59.3224 66.0733 59.5291 66.05 59.7557 66.03C59.9891 66.01 60.1891 66 60.3557 66H61.7157V67.5H56.5557Z" fill="#101010"/>
<rect x="98.6826" y="56.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="98.6826" y="56.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M103.916 67.5V66.06H105.496V61.83H104.126V60.73C104.526 60.6567 104.866 60.5667 105.146 60.46C105.432 60.3533 105.706 60.2167 105.966 60.05H107.276V66.06H108.616V67.5H103.916Z" fill="#101010"/>
<rect x="40.6826" y="17.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="40.6826" y="17.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M47.9257 28.64C47.5324 28.64 47.1757 28.5967 46.8557 28.51C46.5424 28.4233 46.2624 28.3033 46.0157 28.15C45.7691 27.99 45.5557 27.8067 45.3757 27.6L46.1957 26.48C46.4224 26.6867 46.6657 26.86 46.9257 27C47.1857 27.1333 47.4591 27.2 47.7457 27.2C47.9791 27.2 48.1791 27.17 48.3457 27.11C48.5191 27.0433 48.6524 26.9467 48.7457 26.82C48.8391 26.6933 48.8857 26.5367 48.8857 26.35C48.8857 26.1367 48.8357 25.9533 48.7357 25.8C48.6357 25.6467 48.4491 25.53 48.1757 25.45C47.9024 25.37 47.5057 25.33 46.9857 25.33V24.07C47.4124 24.07 47.7457 24.03 47.9857 23.95C48.2257 23.87 48.3957 23.7567 48.4957 23.61C48.6024 23.4633 48.6557 23.2933 48.6557 23.1C48.6557 22.8467 48.5824 22.6533 48.4357 22.52C48.2891 22.38 48.0791 22.31 47.8057 22.31C47.5591 22.31 47.3324 22.3633 47.1257 22.47C46.9191 22.5767 46.7024 22.73 46.4757 22.93L45.5757 21.84C45.9224 21.5467 46.2824 21.32 46.6557 21.16C47.0357 21 47.4457 20.92 47.8857 20.92C48.3991 20.92 48.8457 21 49.2257 21.16C49.6124 21.3133 49.9091 21.5433 50.1157 21.85C50.3291 22.15 50.4357 22.5233 50.4357 22.97C50.4357 23.3367 50.3357 23.6633 50.1357 23.95C49.9357 24.23 49.6391 24.45 49.2457 24.61V24.66C49.5191 24.74 49.7624 24.8633 49.9757 25.03C50.1957 25.19 50.3657 25.39 50.4857 25.63C50.6124 25.87 50.6757 26.15 50.6757 26.47C50.6757 26.93 50.5491 27.3233 50.2957 27.65C50.0424 27.97 49.7057 28.2167 49.2857 28.39C48.8724 28.5567 48.4191 28.64 47.9257 28.64Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,12 +1,16 @@
<svg width="108" height="110" viewBox="0 0 108 110" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21 109L106 54.5L21 1" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(0 -1 -1 0 21.5 110)" fill="#101010"/>
<path d="M100 55L24 55" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M8 109L8 -1.90735e-06" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 58.5V57.48C52.9931 56.9133 53.5365 56.3867 54.0031 55.9C54.4698 55.4133 54.8331 54.96 55.0931 54.54C55.3531 54.1133 55.4831 53.72 55.4831 53.36C55.4831 53.1333 55.4431 52.9433 55.3631 52.79C55.2898 52.63 55.1798 52.51 55.0331 52.43C54.8865 52.35 54.7131 52.31 54.5131 52.31C54.2598 52.31 54.0298 52.3833 53.8231 52.53C53.6231 52.67 53.4331 52.8367 53.2531 53.03L52.2831 52.07C52.6498 51.6767 53.0198 51.3867 53.3931 51.2C53.7731 51.0133 54.2265 50.92 54.7531 50.92C55.2331 50.92 55.6565 51.0167 56.0231 51.21C56.3898 51.4033 56.6765 51.6767 56.8831 52.03C57.0898 52.3767 57.1931 52.7867 57.1931 53.26C57.1931 53.6867 57.0831 54.1233 56.8631 54.57C56.6498 55.01 56.3731 55.4467 56.0331 55.88C55.6931 56.3067 55.3331 56.7133 54.9531 57.1C55.1398 57.0733 55.3465 57.05 55.5731 57.03C55.8065 57.01 56.0065 57 56.1731 57H57.5331V58.5H52.3731Z" fill="#101010"/>
<rect x="0.5" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="0.5" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M5.73313 58.5L5.73313 57.06H7.31313V52.83H5.94313V51.73C6.34313 51.6567 6.68313 51.5667 6.96313 51.46C7.24979 51.3533 7.52313 51.2167 7.78313 51.05H9.09313V57.06H10.4331V58.5H5.73313Z" fill="#101010"/>
<svg width="115" height="119" viewBox="0 0 115 119" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.8174 109L106.817 54.5L21.8174 1" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(0 -1 -1 0 22.3174 110)" fill="#101010"/>
<path d="M100.817 55H24.8174" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M8.81738 109L8.81738 -1.90735e-06" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M108.317 66.5L26.8172 118.5" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="48.3174" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="48.3174" y="47.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M53.1905 58.5V57.48C53.8105 56.9133 54.3538 56.3867 54.8205 55.9C55.2872 55.4133 55.6505 54.96 55.9105 54.54C56.1705 54.1133 56.3005 53.72 56.3005 53.36C56.3005 53.1333 56.2605 52.9433 56.1805 52.79C56.1072 52.63 55.9972 52.51 55.8505 52.43C55.7038 52.35 55.5305 52.31 55.3305 52.31C55.0772 52.31 54.8472 52.3833 54.6405 52.53C54.4405 52.67 54.2505 52.8367 54.0705 53.03L53.1005 52.07C53.4672 51.6767 53.8372 51.3867 54.2105 51.2C54.5905 51.0133 55.0438 50.92 55.5705 50.92C56.0505 50.92 56.4738 51.0167 56.8405 51.21C57.2072 51.4033 57.4938 51.6767 57.7005 52.03C57.9072 52.3767 58.0105 52.7867 58.0105 53.26C58.0105 53.6867 57.9005 54.1233 57.6805 54.57C57.4672 55.01 57.1905 55.4467 56.8505 55.88C56.5105 56.3067 56.1505 56.7133 55.7705 57.1C55.9572 57.0733 56.1638 57.05 56.3905 57.03C56.6238 57.01 56.8238 57 56.9905 57H58.3505V58.5H53.1905Z" fill="#101010"/>
<rect x="1.31738" y="47.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="1.31738" y="47.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M6.55051 58.5V57.06H8.13051V52.83H6.76051V51.73C7.16051 51.6567 7.50051 51.5667 7.78051 51.46C8.06717 51.3533 8.34051 51.2167 8.60051 51.05H9.91051V57.06H11.2505V58.5H6.55051Z" fill="#101010"/>
<rect x="59.3174" y="86.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="59.3174" y="86.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M66.5605 97.64C66.1672 97.64 65.8105 97.5967 65.4905 97.51C65.1772 97.4233 64.8972 97.3033 64.6505 97.15C64.4038 96.99 64.1905 96.8067 64.0105 96.6L64.8305 95.48C65.0572 95.6867 65.3005 95.86 65.5605 96C65.8205 96.1333 66.0938 96.2 66.3805 96.2C66.6138 96.2 66.8138 96.17 66.9805 96.11C67.1538 96.0433 67.2872 95.9467 67.3805 95.82C67.4738 95.6933 67.5205 95.5367 67.5205 95.35C67.5205 95.1367 67.4705 94.9533 67.3705 94.8C67.2705 94.6467 67.0838 94.53 66.8105 94.45C66.5372 94.37 66.1405 94.33 65.6205 94.33V93.07C66.0472 93.07 66.3805 93.03 66.6205 92.95C66.8605 92.87 67.0305 92.7567 67.1305 92.61C67.2372 92.4633 67.2905 92.2933 67.2905 92.1C67.2905 91.8467 67.2172 91.6533 67.0705 91.52C66.9238 91.38 66.7138 91.31 66.4405 91.31C66.1938 91.31 65.9672 91.3633 65.7605 91.47C65.5538 91.5767 65.3372 91.73 65.1105 91.93L64.2105 90.84C64.5572 90.5467 64.9172 90.32 65.2905 90.16C65.6705 90 66.0805 89.92 66.5205 89.92C67.0338 89.92 67.4805 90 67.8605 90.16C68.2472 90.3133 68.5438 90.5433 68.7505 90.85C68.9638 91.15 69.0705 91.5233 69.0705 91.97C69.0705 92.3367 68.9705 92.6633 68.7705 92.95C68.5705 93.23 68.2738 93.45 67.8805 93.61V93.66C68.1538 93.74 68.3972 93.8633 68.6105 94.03C68.8305 94.19 69.0005 94.39 69.1205 94.63C69.2472 94.87 69.3105 95.15 69.3105 95.47C69.3105 95.93 69.1838 96.3233 68.9305 96.65C68.6772 96.97 68.3405 97.2167 67.9205 97.39C67.5072 97.5567 67.0538 97.64 66.5605 97.64Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,14 +1,16 @@
<svg width="110" height="108" viewBox="0 0 110 108" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1 87L55.5 2L109 87" stroke="#45CD7D" stroke-width="2"/>
<rect y="86.5" width="110" height="2" fill="#101010"/>
<path d="M55 8V84" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M1 100H110" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="45.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="45.5" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 56.5V55.48C52.9931 54.9133 53.5365 54.3867 54.0031 53.9C54.4698 53.4133 54.8331 52.96 55.0931 52.54C55.3531 52.1133 55.4831 51.72 55.4831 51.36C55.4831 51.1333 55.4431 50.9433 55.3631 50.79C55.2898 50.63 55.1798 50.51 55.0331 50.43C54.8865 50.35 54.7131 50.31 54.5131 50.31C54.2598 50.31 54.0298 50.3833 53.8231 50.53C53.6231 50.67 53.4331 50.8367 53.2531 51.03L52.2831 50.07C52.6498 49.6767 53.0198 49.3867 53.3931 49.2C53.7731 49.0133 54.2265 48.92 54.7531 48.92C55.2331 48.92 55.6565 49.0167 56.0231 49.21C56.3898 49.4033 56.6765 49.6767 56.8831 50.03C57.0898 50.3767 57.1931 50.7867 57.1931 51.26C57.1931 51.6867 57.0831 52.1233 56.8631 52.57C56.6498 53.01 56.3731 53.4467 56.0331 53.88C55.6931 54.3067 55.3331 54.7133 54.9531 55.1C55.1398 55.0733 55.3465 55.05 55.5731 55.03C55.8065 55.01 56.0065 55 56.1731 55H57.5331V56.5H52.3731Z"
fill="#101010"/>
<rect x="47.5" y="92.5" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="92.5" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.7331 103.5V102.06H54.3131V97.83H52.9431V96.73C53.3431 96.6567 53.6831 96.5667 53.9631 96.46C54.2498 96.3533 54.5231 96.2167 54.7831 96.05H56.0931V102.06H57.4331V103.5H52.7331Z"
fill="#101010"/>
<svg width="119" height="115" viewBox="0 0 119 115" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M109 93.1829L54.5 8.18286L1 93.1829" stroke="#45CD7D" stroke-width="2"/>
<rect width="110" height="2" transform="matrix(-1 0 0 1 110 92.1829)" fill="#101010"/>
<path d="M55 14.1829V90.1829" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M109 106.183H-1.90735e-06" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<path d="M66.5 6.68276L118.5 88.1828" stroke="#9F9F9F" stroke-dasharray="4 4"/>
<rect x="47.5" y="51.6826" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="51.6826" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M52.3731 62.6826V61.6626C52.9931 61.096 53.5365 60.5693 54.0031 60.0826C54.4698 59.596 54.8331 59.1426 55.0931 58.7226C55.3531 58.296 55.4831 57.9026 55.4831 57.5426C55.4831 57.316 55.4431 57.126 55.3631 56.9726C55.2898 56.8126 55.1798 56.6926 55.0331 56.6126C54.8865 56.5326 54.7131 56.4926 54.5131 56.4926C54.2598 56.4926 54.0298 56.566 53.8231 56.7126C53.6231 56.8526 53.4331 57.0193 53.2531 57.2126L52.2831 56.2526C52.6498 55.8593 53.0198 55.5693 53.3931 55.3826C53.7731 55.196 54.2265 55.1026 54.7531 55.1026C55.2331 55.1026 55.6565 55.1993 56.0231 55.3926C56.3898 55.586 56.6765 55.8593 56.8831 56.2126C57.0898 56.5593 57.1931 56.9693 57.1931 57.4426C57.1931 57.8693 57.0831 58.306 56.8631 58.7526C56.6498 59.1926 56.3731 59.6293 56.0331 60.0626C55.6931 60.4893 55.3331 60.896 54.9531 61.2826C55.1398 61.256 55.3465 61.2326 55.5731 61.2126C55.8065 61.1926 56.0065 61.1826 56.1731 61.1826H57.5331V62.6826H52.3731Z" fill="#101010"/>
<rect x="47.5" y="98.6826" width="15" height="15" rx="7.5" fill="white"/>
<rect x="47.5" y="98.6826" width="15" height="15" rx="7.5" stroke="#101010"/>
<path d="M52.7331 109.683V108.243H54.3131V104.013H52.9431V102.913C53.3431 102.839 53.6831 102.749 53.9631 102.643C54.2498 102.536 54.5231 102.399 54.7831 102.233H56.0931V108.243H57.4331V109.683H52.7331Z" fill="#101010"/>
<rect x="86.5" y="40.6826" width="15" height="15" rx="7.5" fill="white"/>
<rect x="86.5" y="40.6826" width="15" height="15" rx="7.5" stroke="black"/>
<path d="M93.7431 51.8226C93.3498 51.8226 92.9931 51.7793 92.6731 51.6926C92.3598 51.606 92.0798 51.486 91.8331 51.3326C91.5865 51.1726 91.3731 50.9893 91.1931 50.7826L92.0131 49.6626C92.2398 49.8693 92.4831 50.0426 92.7431 50.1826C93.0031 50.316 93.2765 50.3826 93.5631 50.3826C93.7965 50.3826 93.9965 50.3526 94.1631 50.2926C94.3365 50.226 94.4698 50.1293 94.5631 50.0026C94.6565 49.876 94.7031 49.7193 94.7031 49.5326C94.7031 49.3193 94.6531 49.136 94.5531 48.9826C94.4531 48.8293 94.2665 48.7126 93.9931 48.6326C93.7198 48.5526 93.3231 48.5126 92.8031 48.5126V47.2526C93.2298 47.2526 93.5631 47.2126 93.8031 47.1326C94.0431 47.0526 94.2131 46.9393 94.3131 46.7926C94.4198 46.646 94.4731 46.476 94.4731 46.2826C94.4731 46.0293 94.3998 45.836 94.2531 45.7026C94.1065 45.5626 93.8965 45.4926 93.6231 45.4926C93.3765 45.4926 93.1498 45.546 92.9431 45.6526C92.7365 45.7593 92.5198 45.9126 92.2931 46.1126L91.3931 45.0226C91.7398 44.7293 92.0998 44.5026 92.4731 44.3426C92.8531 44.1826 93.2631 44.1026 93.7031 44.1026C94.2165 44.1026 94.6631 44.1826 95.0431 44.3426C95.4298 44.496 95.7265 44.726 95.9331 45.0326C96.1465 45.3326 96.2531 45.706 96.2531 46.1526C96.2531 46.5193 96.1531 46.846 95.9531 47.1326C95.7531 47.4126 95.4565 47.6326 95.0631 47.7926V47.8426C95.3365 47.9226 95.5798 48.046 95.7931 48.2126C96.0131 48.3726 96.1831 48.5726 96.3031 48.8126C96.4298 49.0526 96.4931 49.3326 96.4931 49.6526C96.4931 50.1126 96.3665 50.506 96.1131 50.8326C95.8598 51.1526 95.5231 51.3993 95.1031 51.5726C94.6898 51.7393 94.2365 51.8226 93.7431 51.8226Z" fill="#101010"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
qcast3.database.sqlite Normal file

Binary file not shown.

View File

@ -3,32 +3,12 @@
import { createContext, useEffect, useState } from 'react'
import { useLocalStorage } from 'usehooks-ts'
// export const GlobalDataContext = createContext({
// managementState: {},
// setManagementState: () => {},
// managementStateLoaded: null,
// })
export const GlobalDataContext = createContext(null)
const GlobalDataProvider = ({ children }) => {
const [managementState, setManagementState] = useState(null)
// TODO: 임시 조치이며 개발 완료시 삭제 예정 -> 잊지말기...
const [managementStateLoaded, setManagementStateLoaded] = useLocalStorage('managementStateLoaded', null)
// const pathname = usePathname()
// const setCorrentObjectNo = useSetRecoilState(correntObjectNoState)
// const searchParams = useSearchParams()
// const objectNo = searchParams.get('objectNo')
// const pid = searchParams.get('pid')
// useEffect(() => {
// if (pathname === '/floor-plan') {
// if (pid === undefined || pid === '' || pid === null || objectNo === undefined || objectNo === '' || objectNo === null) {
// notFound()
// }
// setCorrentObjectNo(objectNo)
// }
// }, [pathname])
useEffect(() => {
if (managementState !== null) {
setManagementStateLoaded(managementState)

View File

@ -15,9 +15,7 @@ export const QcastContext = createContext({
})
export const QcastProvider = ({ children }) => {
const [planSave, setPlanSave] = useState(false)
const [isGlobalLoading, setIsGlobalLoading] = useState(true)
const { commonCode, findCommonCode } = useCommonCode()
const [qcastState, setQcastState] = useState({
saleStoreId: '',
@ -27,11 +25,6 @@ export const QcastProvider = ({ children }) => {
businessChargerMail: null,
})
// useEffect(() => {
// console.log('commonCode', commonCode)
// console.log(findCommonCode(113600))
// }, [commonCode, findCommonCode])
return (
<>
<QcastContext.Provider value={{ qcastState, setQcastState, isGlobalLoading, setIsGlobalLoading }}>

View File

@ -1,5 +0,0 @@
import { NextUIProvider } from '@nextui-org/react'
export default function UIProvider({ children }) {
return <NextUIProvider>{children}</NextUIProvider>
}

View File

@ -1,22 +0,0 @@
'use server'
import fs from 'fs/promises'
import { NextResponse } from 'next/server'
import { writeImage, writeImageBuffer } from '@/lib/fileAction'
export async function GET(req) {
const path = 'public/plan-map-images'
const q = req.nextUrl.searchParams.get('q')
const fileNm = req.nextUrl.searchParams.get('fileNm')
const zoom = req.nextUrl.searchParams.get('zoom')
const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=${zoom}&maptype=satellite&size=640x640&scale=1&key=AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc`
const decodeUrl = decodeURIComponent(targetUrl)
const response = await fetch(decodeUrl)
const data = await response.arrayBuffer()
const buffer = Buffer.from(data)
await writeImage(fileNm, buffer)
return NextResponse.json({ fileNm: `${fileNm}.png` })
}

View File

@ -1,15 +0,0 @@
'use server'
import { NextResponse } from 'next/server'
import { writeImage } from '@/lib/fileAction'
export async function POST(req) {
const formData = await req.formData()
const file = formData.get('file')
const fileName = formData.get('fileName')
const arrayBuffer = await file.arrayBuffer()
const buffer = Buffer.from(arrayBuffer)
await writeImage(fileName, buffer)
return NextResponse.json({ fileNm: `${fileName}.png` })
}

View File

@ -1,25 +0,0 @@
import { NextResponse } from 'next/server'
const defaultData = [
{
id: 1,
name: 'John Doe',
email: 'john.doe@example.com',
},
{
id: 2,
name: 'Jane Lee',
email: 'jane.lee@example.com',
},
]
export async function GET(req, res) {
return NextResponse.json(defaultData)
}
export const POST = async (req, res) => {
const { id, name, email } = await req.json()
const newData = { id, name, email }
console.log('🚀 ~ POST ~ newData:', newData)
return NextResponse.json([...defaultData, newData])
}

View File

@ -1,4 +1,3 @@
import Hero from '@/components/Hero'
import Archive from '@/components/community/Archive'
export default async function CommunityArchivePage() {

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import InitSettingsModal from '@/components/InitSettingsModal'
export default async function InitSettingsModalPage() {
return (
<>
<Hero title="Basic Settings" />
<div className="flex flex-col justify-center my-8">
<InitSettingsModal />
</div>
</>
)
}

View File

@ -16,11 +16,20 @@ import '../styles/contents.scss'
import Footer from '@/components/footer/Footer'
import GlobalLoadingProvider from './GlobalLoadingProvider'
/**
* 어플리케이션 메타데이터
* 서버 컴포넌트에 한해서 개별로 설정할 있음
*/
export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
title: 'HANASYS設計',
description: 'HANASYS設計',
}
/**
* 어플리케이션 전체 레이아웃 컴포넌트
* @param {*} param0
* @returns
*/
export default async function RootLayout({ children }) {
const headersList = headers()
const headerPathname = headersList.get('x-pathname') || ''

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import Plan from '@/components/management/Plan'
export default async function ManagementPlanPage() {
return (
<>
<Hero title="도면관리" />
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
<Plan />
</div>
</>
)
}

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import Company from '@/components/master/Company'
export default async function MasterCompanyPage() {
return (
<>
<Hero title="회사정보 조회" />
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
<Company />
</div>
</>
)
}

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import Price from '@/components/master/Price'
export default async function MasterPricePage() {
return (
<>
<Hero title="가격 마스터 조회" />
<div className="container flex flex-wrap items-center justify-between mx-auto p-4 m-4 border">
<Price />
</div>
</>
)
}

View File

@ -1,9 +0,0 @@
import Playground from '@/components/Playground'
export default async function PlaygroundPage() {
return (
<>
<Playground />
</>
)
}

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import Roof from '@/components/Roof'
export default async function RoofPage() {
return (
<>
<Hero title="Drawing on canvas 2D Roof" />
<div className="flex flex-col justify-center my-8">
<Roof />
</div>
</>
)
}

View File

@ -1,11 +0,0 @@
import Roof2 from '@/components/Roof2'
export default async function Roof2Page() {
return (
<>
<div className="flex flex-col justify-center my-8 pt-20">
<Roof2 />
</div>
</>
)
}

View File

@ -1,13 +0,0 @@
import Hero from '@/components/Hero'
import Settings from '@/components/Settings'
export default async function SettingsPage() {
return (
<>
<Hero title="Canvas Setting" />
<div className="flex flex-col justify-center my-8">
<Settings />
</div>
</>
)
}

View File

@ -116,6 +116,15 @@ export const POLYGON_TYPE = {
OBJECT_SURFACE: 'objectOffset',
}
// 가대 관련 상수
export const TRESTLE_MATERIAL = {
EAVE_BAR: 'eaveBar',
HALF_EAVE_BAR: 'halfEaveBar',
RACK: 'rack',
SMART_RACK: 'smartRack',
BRACKET: 'bracket',
}
export const SAVE_KEY = [
'selectable',
'name',
@ -187,6 +196,13 @@ export const SAVE_KEY = [
'circuit',
'onlyOffset',
'isChidory',
'textVisible',
'groupPoints',
'fontSize',
'fontStyle',
'fontWeight',
'dormerAttributes',
'toFixed',
]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype, fabric.Group.prototype]

View File

@ -1,273 +0,0 @@
import { useEffect, useRef, useState } from 'react'
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input } from '@nextui-org/react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { modalContent, modalState } from '@/store/modalAtom'
import { guideLineState, horiGuideLinesState, vertGuideLinesState } from '@/store/canvasAtom'
import { fabric } from 'fabric'
import { ColorPicker, useColor } from 'react-color-palette'
import 'react-color-palette/css'
import { gridColorState } from '@/store/gridAtom'
export default function GridSettingsModal(props) {
const { canvasProps } = props
const [isCustomGridSetting, setIsCustomGridSetting] = useState(true)
const [gridCheckedValue, setGridCheckValue] = useState([])
const [ratioValue, setRatioValue] = useState('1')
const moduleLength = useRef(null) // mm
const customModuleHoriLength = useRef(null)
const customModuleVertLength = useRef(null)
const [open, setOpen] = useRecoilState(modalState)
const [guideLine, setGuideLine] = useRecoilState(guideLineState)
const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState)
const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState)
const gridSettingArray = []
const gridColor = useRecoilValue(gridColorState)
const [colorPickerShow, setColorPickerShow] = useState(false)
const boxStyle = {
width: '50px',
height: '30px',
border: '1px solid black',
backgroundColor: guideColor.hex,
}
useEffect(() => {
moduleLength.current.value = 90
customModuleHoriLength.current.value = 90
customModuleVertLength.current.value = 90
}, [])
useEffect(() => {
setIsCustomGridSetting(ratioValue !== 'custom')
}, [ratioValue])
const drawGridSettings = () => {
//
if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) {
gridSettingArray.push(...guideLine)
}
let moduleHoriLength = moduleLength.current.value //
let moduleVertLength = moduleLength.current.value //
if (ratioValue === 'custom') {
moduleHoriLength = customModuleHoriLength.current.value
moduleVertLength = customModuleVertLength.current.value
} else {
moduleHoriLength = moduleHoriLength / ratioValue
moduleVertLength = moduleVertLength / ratioValue
}
if (gridCheckedValue.includes('line')) {
const horizontalLineArray = []
const verticalLineArray = []
for (let i = 0; i < canvasProps.height / moduleVertLength + 1; i++) {
const horizontalLine = new fabric.Line(
[0, i * moduleVertLength - moduleVertLength / 2, canvasProps.width, i * moduleVertLength - moduleVertLength / 2],
{
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: 'guideLine',
strokeDashArray: [5, 2],
opacity: 0.3,
direction: 'horizontal',
},
)
canvasProps.add(horizontalLine)
horizontalLineArray.push(horizontalLine)
}
for (let i = 0; i < canvasProps.width / moduleHoriLength + 1; i++) {
const verticalLine = new fabric.Line(
[i * moduleHoriLength - moduleHoriLength / 2, 0, i * moduleHoriLength - moduleHoriLength / 2, canvasProps.height],
{
stroke: gridColor,
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: 'guideLine',
strokeDashArray: [5, 2],
opacity: 0.3,
direction: 'vertical',
},
)
canvasProps.add(verticalLine)
verticalLineArray.push(verticalLine)
}
canvasProps.renderAll()
const snapDistance = 10
const recoilObj = {
guideMode: 'guideLine',
horizontalLineArray,
verticalLineArray,
moduleVertLength: moduleVertLength,
moduleHoriLength: moduleHoriLength,
}
gridSettingArray.push(recoilObj)
const newHoriGuideLines = [...horiGuideLines]
horizontalLineArray.forEach((line) => {
newHoriGuideLines.push(line)
})
const newVertGuideLines = [...vertGuideLines]
verticalLineArray.forEach((line) => {
newVertGuideLines.push(line)
})
setHoriGuideLines(newHoriGuideLines)
setVertGuideLines(newVertGuideLines)
}
if (gridCheckedValue.includes('dot')) {
const circle = new fabric.Circle({
radius: 2,
fill: 'white',
stroke: guideColor.hex,
strokeWidth: 0.7,
originX: 'center',
originY: 'center',
selectable: false,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
})
const patternSourceCanvas = new fabric.StaticCanvas(null, {
width: moduleHoriLength,
height: moduleVertLength,
})
patternSourceCanvas.add(circle)
circle.set({
left: patternSourceCanvas.width / 2,
top: patternSourceCanvas.height / 2,
})
patternSourceCanvas.renderAll()
const pattern = new fabric.Pattern({
source: patternSourceCanvas.getElement(),
repeat: 'repeat',
})
const backgroundPolygon = new fabric.Polygon(
[
{ x: 0, y: 0 },
{ x: canvasProps.width, y: 0 },
{ x: canvasProps.width, y: canvasProps.height },
{ x: 0, y: canvasProps.height },
],
{
fill: pattern,
selectable: false,
name: 'guideDot',
},
)
canvasProps.add(backgroundPolygon)
backgroundPolygon.sendToBack()
canvasProps.renderAll()
const recoilObj = {
guideMode: 'guideDot',
moduleVertLength: moduleVertLength,
moduleHoriLength: moduleHoriLength,
}
gridSettingArray.push(recoilObj)
}
canvasProps.renderAll()
setGuideLine(gridSettingArray)
}
const removeGuideLines = () => {
if (!(Object.keys(guideLine).length === 0 && guideLine.constructor === Object)) {
const guideLines = canvasProps._objects.filter((obj) => obj.name === 'guideLine' || obj.name === 'guideDot')
guideLines?.forEach((item) => canvasProps.remove(item))
canvasProps.renderAll()
setGuideLine([])
setHoriGuideLines([])
setVertGuideLines([])
} else {
alert('그리드가 없습니다.')
return
}
}
return (
<>
<div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<label style={{ display: 'block', marginBottom: '5px' }}>
<CheckboxGroup label="그리드 설정" value={gridCheckedValue} defaultChecked={gridCheckedValue} onValueChange={setGridCheckValue}>
<Checkbox value="dot"> 그리드</Checkbox>
<Checkbox value="line">점선 그리드</Checkbox>
</CheckboxGroup>
</label>
</div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<Input type="number" label="모듈" ref={moduleLength} />
mm
</div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<RadioGroup label="비율 설정" value={ratioValue} defaultValue={ratioValue} onValueChange={setRatioValue}>
<Radio value="1">원치수</Radio>
<Radio value="2">1/2</Radio>
<Radio value="4">1/4</Radio>
<Radio value="10">1/10</Radio>
<Radio value="custom">임의간격</Radio>
</RadioGroup>
</div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
가이드컬러 <div style={boxStyle} onClick={() => setColorPickerShow(!colorPickerShow)}></div>
</div>
{colorPickerShow && (
<ColorPicker color={guideColor} onChange={setGuideColor} hideInput={['hsv', 'rgb', 'hex']} height={100} hideAlpha={true} />
)}
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<Checkbox value="linked" isDisabled={isCustomGridSetting}>
종횡연동
</Checkbox>
</div>
</div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<Input type="number" label="가로간격" ref={customModuleHoriLength} min={0} isDisabled={isCustomGridSetting} />
mm
</div>
<div className="flex w-full flex-wrap md:flex-nowrap gap-4">
<Input type="number" label="세로간격" ref={customModuleVertLength} min={0} isDisabled={isCustomGridSetting} />
mm
</div>
<div className="flex gap-4 items-center">
<Button size="sm">초기화</Button>
<Button size="sm" color="secondary" onClick={drawGridSettings} isDisabled={gridCheckedValue.length === 0}>
저장
</Button>
<Button size="sm" onClick={() => setOpen(!open)}>
취소
</Button>
<Button size="sm" onClick={() => removeGuideLines()}>
그리드 삭제
</Button>
</div>
</>
)
}

View File

@ -1,21 +0,0 @@
import Link from 'next/link'
export default function Headers() {
return (
<div className="w-full">
<nav className="container relative flex flex-wrap items-center justify-between mx-auto p-8">
<Link href="/" className="font-bold text-3xl">
Home
</Link>
<div className="space-x-4 text-xl">
<Link href="/intro">Intro</Link>
<Link href="/playground">Playground</Link>
<Link href="/initSettingsModal">Basic Settings</Link>
<Link href="/settings">Canvas Settings</Link>
<Link href="/roof">Roof</Link>
<Link href="/roof2">Roof2</Link>
</div>
</nav>
</div>
)
}

View File

@ -1,7 +0,0 @@
export default function Hero(props) {
return (
<div className="pt-48 flex justify-center">
<h1 className="text-4xl archivo-black-regular">{props.title}</h1>
</div>
)
}

View File

@ -1,255 +0,0 @@
'use client'
import { useEffect, useState, memo, useCallback } from 'react'
import { Button, Checkbox, CheckboxGroup, RadioGroup, Radio, Input, Select, SelectItem } from '@nextui-org/react'
import { useRecoilState, useRecoilValue } from 'recoil'
import { modalContent, modalState } from '@/store/modalAtom'
import { canvasSettingState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios'
export default function InitSettingsModal(props) {
const [objectNo, setObjectNo] = useState('test123240909003') //
const [open, setOpen] = useRecoilState(modalState)
const [canvasSetting, setCanvasSetting] = useRecoilState(canvasSettingState)
const [roofMaterials, setRoofMaterials] = useState([])
const [basicSetting, setBasicSettings] = useState({
roofDrawingSet: '1',
roofSizeSet: '1',
roofAngleSet: 'slope',
roofs: [{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }],
})
const modelProps = {
open,
setOpen,
}
const { get, post } = useAxios()
//const { get, post } = useAxios()
useEffect(() => {
get({ url: `/api/canvas-management/canvas-basic-settings/by-object/${objectNo}` }).then((res) => {
if (res.length == 0) return
// 'roofs'
const roofsRow = res.map((item) => {
return {
roofDrawingSet: String(item.roofDrawingSet),
roofSizeSet: String(item.roofSizeSet),
roofAngleSet: item.roofAngleSet,
}
})
const roofsArray = res.some((item) => !item.roofSeq)
? // roofsArray
[{ roofSeq: '1', roofType: '3', roofWidth: '200', roofHeight: '200', roofGap: '0', roofLayout: 'parallel' }]
: res.map((item) => ({
roofSeq: String(item.roofSeq),
roofType: String(item.roofType),
roofWidth: String(item.roofWidth),
roofHeight: String(item.roofHeight),
roofGap: String(item.roofGap),
roofLayout: item.roofLayout,
}))
// 'roofs' patternData
const patternData = {
roofDrawingSet: roofsRow[0].roofDrawingSet, //
roofSizeSet: roofsRow[0].roofSizeSet, //
roofAngleSet: roofsRow[0].roofAngleSet, //
roofs: roofsArray, // roofs
}
//
setBasicSettings({ ...patternData })
})
if (!(Object.keys(canvasSetting).length === 0 && canvasSetting.constructor === Object)) {
setBasicSettings({ ...canvasSetting })
}
}, [])
//
const handleBasicSetting = (event) => {
const newBasicSetting = { ...basicSetting, [event.target.name]: event.target.value }
setBasicSettings(newBasicSetting)
}
//
const handleRoofSettings = (id, event) => {
// roofs
const updatedRoofs = [...basicSetting.roofs]
// roofSeq id
const index = updatedRoofs.findIndex((roof) => roof.roofSeq === id)
if (index !== -1) {
//
updatedRoofs[index] = {
...updatedRoofs[index],
[event.target.name]: event.target.value,
}
//
setBasicSettings((prevState) => ({
...prevState,
roofs: updatedRoofs,
}))
}
}
//
const submitCanvasConfig = async () => {
if (!objectNo) {
alert('object_no를 입력하세요.')
return
}
const patternData = {
objectNo,
roofDrawingSet: basicSetting.roofDrawingSet,
roofSizeSet: basicSetting.roofSizeSet,
roofAngleSet: basicSetting.roofAngleSet,
roofMaterialsAddList: basicSetting.roofs,
}
await post({ url: `/api/canvas-management/canvas-basic-settings`, data: patternData })
//Recoil
setCanvasSetting({ ...basicSetting })
//
//await handleSelect()
}
return (
<>
<div className="container mx-auto mt-10 p-6 bg-white shadow-lg rounded-lg">
<div className="text-lg font-semibold mb-4">배치면 초기설정</div>
<div className="mb-6">
<div className="flex space-x-4">
<RadioGroup
label="도면 작성방법"
name="roofDrawingSet"
orientation="horizontal"
value={basicSetting.roofDrawingSet}
onChange={handleBasicSetting}
>
<Radio value="1">치수 입력에 의한 물건작성</Radio>
</RadioGroup>
</div>
</div>
<div className="mb-6">
<div className="flex space-x-4">
<RadioGroup
label="치수 입력방법"
name="roofSizeSet"
orientation="horizontal"
value={basicSetting.roofSizeSet}
onChange={handleBasicSetting}
>
<Radio value="1">복사도 입력</Radio>
<Radio value="2">실측값 입력</Radio>
<Radio value="3">육지붕</Radio>
</RadioGroup>
</div>
</div>
<div className="mb-6">
<div className="flex space-x-4">
<RadioGroup
label="지붕각도 설정"
name="roofAngleSet"
orientation="horizontal"
value={basicSetting.roofAngleSet}
onChange={handleBasicSetting}
>
<Radio value="slope">경사</Radio>
<Radio value="angle">각도</Radio>
</RadioGroup>
</div>
</div>
<RadioGroup label="지붕재 추가(단위 : mm)" />
{/* Roofs Array Rendering */}
{basicSetting.roofs &&
basicSetting.roofs.map((roof, index) => {
return (
<div key={index} className="mb-4 flex flex-wrap items-center space-x-4" style={{ border: '1px solid black' }}>
<span> 타입 : </span>
<Select
aria-label="roofMaterial"
className={'w-52'}
name="roofType"
onChange={(e) => handleRoofSettings(roof.roofSeq, e)}
items={roofMaterials}
defaultSelectedKeys={roof.roofType ? [roof.roofType] : []}
selectedKeys={roof.roofType}
value={roof.roofType}
>
{(roofMaterial) => (
<SelectItem key={roofMaterial.id} value={roofMaterial.id}>
{roofMaterial.name}
</SelectItem>
)}
</Select>
<span> 너비 : </span>
<Input
type="text"
name="roofWidth"
placeholder="너비"
value={roof.roofWidth}
className="w-24"
onChange={(e) => handleRoofSettings(roof.roofSeq, e)}
/>
mm
<span> 높이 : </span>
<Input
type="text"
name="roofHeight"
placeholder="높이"
value={roof.roofHeight}
className="w-24"
onChange={(e) => handleRoofSettings(roof.roofSeq, e)}
/>
mm
<span> 서까래 간격 : </span>
<Input
type="text"
name="roofGap"
placeholder="간격"
value={roof.roofGap}
className="w-24"
onChange={(e) => handleRoofSettings(roof.roofSeq, e)}
/>
mm
<div className="flex space-x-4">
<RadioGroup
orientation="horizontal"
name="roofLayout"
value={roof.roofLayout}
defaultValue="parallel"
onChange={(e) => handleRoofSettings(roof.roofSeq, e)}
>
<Radio value="parallel">병렬식</Radio>
<Radio value="cascade">계단식</Radio>
</RadioGroup>
</div>
</div>
)
})}
<div className="flex gap-4 items-right">
<Button size="sm" color="secondary" onClick={submitCanvasConfig}>
저장
</Button>
<Button size="sm" onClick={() => setOpen(!open)}>
취소
</Button>
<input type="text" placeholder="Object No 입력" value={objectNo} onChange={(e) => setObjectNo(e.target.value)} />
</div>
</div>
</>
)
}

View File

@ -1,919 +0,0 @@
'use client'
import { useRef, useState, useEffect, useContext } from 'react'
import Image from 'next/image'
import { useRecoilState } from 'recoil'
import { v4 as uuidv4 } from 'uuid'
import { FaAnglesUp } from 'react-icons/fa6'
import { FaAnglesDown } from 'react-icons/fa6'
import { Button } from '@nextui-org/react'
import ColorPicker from './common/color-picker/ColorPicker'
import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom'
import { useAxios } from '@/hooks/useAxios'
import { useMessage } from '@/hooks/useMessage'
import { useMasterController } from '@/hooks/common/useMasterController'
import { useSwal } from '@/hooks/useSwal'
import { convertDwgToPng } from '@/lib/cadAction'
import { GlobalDataContext } from '@/app/GlobalDataProvider'
import QInput from './common/input/Qinput'
import QSelect from './common/select/QSelect'
import QPagination from './common/pagination/QPagination'
import QSelectBox from './common/select/QSelectBox'
import SampleReducer from './sample/SampleReducer'
import styles from './playground.module.css'
import useSWR from 'swr'
import useSWRMutation from 'swr/mutation'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { canvasPopupStatusStore } from '@/store/canvasPopupStatusAtom'
import { moduleSelectionDataPlanListState } from '@/store/selectedModuleOptions'
import { useRouter } from 'next/navigation'
import { QcastContext } from '@/app/QcastProvider'
export default function Playground() {
const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState)
const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState)
const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState)
const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState)
const fileRef = useRef(null)
const queryRef = useRef(null)
const [zoom, setZoom] = useState(20)
const { get, promiseGet, post, promisePost, getFetcher, postFetcher } = useAxios()
const testVar = process.env.NEXT_PUBLIC_TEST
const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const { getRoofMaterialList, getModuleTypeItemList, getTrestleList, getConstructionList, getTrestleDetailList } = useMasterController()
const [color, setColor] = useState('#ff0000')
const [textInput, setTextInput] = useState('')
const [numberInput, setNumberInput] = useState('')
const [radioInput, setRadioInput] = useState('')
const [checkboxInput, setCheckboxInput] = useState([])
const [selectedValue, setSelectedValue] = useState('')
const [users, setUsers] = useState([])
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const router = useRouter()
const { setIsGlobalLoading } = useContext(QcastContext)
useEffect(() => {
setIsGlobalLoading(false)
}, [])
useEffect(() => {
console.log('textInput:', textInput)
}, [textInput])
useEffect(() => {
console.log('numberInput:', numberInput)
}, [numberInput])
useEffect(() => {
console.log('radioInput:', radioInput)
}, [radioInput])
useEffect(() => {
console.log('checkboxInput:', checkboxInput)
}, [checkboxInput])
useEffect(() => {
console.log('selectedValue:', selectedValue)
}, [selectedValue])
const handleUsers = async () => {
// const users = await get('/api/user/find-all')
const params = {
url: '/api/user/find-all',
}
const users = await get(params)
console.log('users', users)
}
const handleConvert = async () => {
console.log('file', fileRef.current.files[0])
const formData = new FormData()
formData.append('file', fileRef.current.files[0])
await promisePost({ url: converterUrl, data: formData })
.then((res) => {
console.log('response: ', res)
convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData)
setUseCadFile(true)
setCadFileName(res.data.Files[0].FileName)
swalFire({ text: '파일 변환 완료' })
})
.catch((err) => {
console.error(err)
swalFire({ text: '파일 변환 실패' })
})
}
const handleDownImage = async (fileName = '') => {
const fileNm = fileName === '' ? uuidv4() : fileName
const queryString = queryRef.current.value === '' ? '서울시 서대문구 연세로5다길 22-3 발리빌라 3층' : queryRef.current.value
const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryString}&fileNm=${fileNm}&zoom=${zoom}` })
console.log('res', res)
setGoogleMapFileName(res.fileNm)
swalFire({ text: '이미지 저장 완료' })
setUseGoogleMapFile(true)
}
const handleZoom = async (type) => {
if (type === 'up') {
setZoom((prevState) => prevState + 1)
} else {
setZoom((prevState) => prevState - 1)
}
await handleDownImage()
}
const data = [
{
id: 1,
author: 'SWYOO',
contents: '버튼 정리(템플릿 적용)',
date: '2024.07.16',
},
{
id: 2,
author: 'SWYOO',
contents: 'README.md 파일 이미지 경로 수정',
date: '2024.07.17',
},
{
id: 3,
author: 'SWYOO',
contents: '',
date: '',
},
]
const handleSwalAlert = () => {
swalFire({
text: '알림 테스트입니다.',
})
}
const paginationProps = {
pageNo: 1,
pageSize: 10,
pagePerBlock: 10,
totalCount: 26,
handleChangePage: (page) => {
console.log('page', page)
},
}
useEffect(() => {
console.log('users:', users)
}, [users])
const codes = [
{
clHeadCd: '203800',
clCode: 'HEI_455',
clCodeNm: '세로 455mm이하',
clPriority: 1,
name: '세로 455mm이하',
id: 'HEI_455',
},
{
clHeadCd: '203800',
clCode: 'HEI_500',
clCodeNm: '세로 500mm이하',
clPriority: 2,
name: '세로 500mm이하',
id: 'HEI_500',
},
{
clHeadCd: '203800',
clCode: 'HEI_606',
clCodeNm: '세로 606mm이하',
clPriority: 3,
name: '세로 606mm이하',
id: 'HEI_606',
},
{
clHeadCd: '203800',
clCode: 'WID_606',
clCodeNm: '가로 606mm이하',
clPriority: 4,
name: '가로 606mm이하',
id: 'WID_606',
},
{
clHeadCd: '203800',
clCode: 'ETC',
clCodeNm: '기타',
clPriority: 5,
name: '기타',
id: 'ETC',
},
]
const [myData, setMyData] = useState({
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlNm: '화와 A',
roofMatlNmJp: '和瓦A',
widAuth: 'R',
widBase: '265.000',
lenAuth: 'R',
lenBase: '235.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53A',
name: '화와 A',
selected: true,
nameJp: '和瓦A',
length: 235,
width: 265,
layout: 'P',
hajebichi: null,
})
const handleChangeMyData = () => {
setMyData({ ...myData, raftBaseCd: 'HEI_500' })
}
const [myData2, setMyData2] = useState({})
const handleChangeMyData2 = () => {
setMyData2({
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlNm: '화와 A',
roofMatlNmJp: '和瓦A',
widAuth: 'R',
widBase: '265.000',
lenAuth: 'R',
lenBase: '235.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53A',
name: '화와 A',
selected: true,
nameJp: '和瓦A',
length: 235,
width: 265,
layout: 'P',
hajebichi: null,
})
}
// const [callFlag, setCallFlag] = useState(false)
// const { data: tutoData, error, isLoading } = useSWR('http://localhost:8080/api/tutorial', getFetcher)
// const { data: tutoData, error, isLoading } = useSWR(callFlag ? 'http://localhost:8080/api/tutorial' : null, getFetcher)
// const { trigger, isMutating } = useSWRMutation('http://localhost:8080/api/tutorial', postFetcher)
// if (isLoading) {
// return <div>Loading...</div>
// }
// if (error) {
// return <div>Error...</div>
// }
// const [moduleSelectionDataPlanListStore, setModuleSelectionDataPlanListStore] = useRecoilState(moduleSelectionDataPlanListState)
// useEffect(() => {
// console.log('🚀 ~ Playground ~ moduleSelectionDataPlanListStore:', moduleSelectionDataPlanListStore)
// }, [moduleSelectionDataPlanListStore])
// const { trigger: canvasPopupStatusTrigger } = useCanvasPopupStatusController({ objectNo: 'R201T01241120001', planNo: 2, popupType: 2 })
return (
<>
<div className="container mx-auto p-4 m-4 border">
<div className={styles.test}> 영역은 테스트입니다.</div>
<div className="my-2">
<button
className="btn-frame deepgray"
onClick={() => {
getRoofMaterialList()
}}
>
지붕재 목록 조회 API 호출
</button>{' '}
<button
className="btn-frame deepgray"
onClick={() => {
getModuleTypeItemList(['ROOF_ID_HIRA_SEME', 'ROOF_ID_ROOGA'])
}}
>
모듈 타입별 아이템 목록 조회 API 호출
</button>{' '}
<button
className="btn-frame deepgray"
onClick={() => {
getTrestleList({ moduleTpCd: '', roofMatlCd: '', raftBaseCd: '', trestleMkrCd: '', constMthdCd: '', roofBaseCd: '' }) //
}}
>
가대 목록 조회 API 호출
</button>{' '}
<button
className="btn-frame deepgray"
onClick={() => {
getConstructionList({
//
moduleTpCd: 'testData_1',
roofMatlCd: 'testData_2',
trestleMkrCd: 'testData_3',
constMthdCd: 'testData_4',
roofBaseCd: 'testData_5',
illuminationTp: 'testData_6',
instHt: 'testData_7',
stdWindSpeed: 'testData_8',
stdSnowLd: 'testData_9',
inclCd: 'testData_10',
raftBaseCd: '',
roofPitch: 30,
})
}}
>
시공법 목록 조회 API 호출
</button>{' '}
<button
className="btn-frame deepgray"
onClick={() => {
getTrestleDetailList({
//
moduleTpCd: 'testData_1',
roofMatlCd: 'testData_2',
trestleMkrCd: 'testData_3',
constMthdCd: 'testData_4',
roofBaseCd: 'testData_5',
illuminationTp: 'testData_6',
instHt: 'testData_7',
stdWindSpeed: 'testData_8',
stdSnowLd: 'testData_9',
inclCd: 'testData_10',
constTp: 'testData_11',
mixMatlNo: 30,
roofPitch: 0,
})
}}
>
가대 상세 조회 API 호출
</button>
</div>
<div className="m-2">
<button
className="btn-frame deepgray"
onClick={() => {
setTextInput('')
}}
>
QInput TextInput DATA RESET
</button>
<QInput type="text" placeholder="placeholder" value={textInput} onChange={setTextInput} />
<QInput type="text" placeholder="read only" value={textInput} onChange={setTextInput} readOnly="true" />
<br />
<button
className="btn-frame deepgray"
onClick={() => {
setNumberInput('')
}}
>
QInput NumberInput DATA RESET
</button>
<QInput type="number" placeholder="placeholder" value={numberInput} onChange={setNumberInput} />
<QInput type="number" placeholder="read only" value={numberInput} onChange={setNumberInput} readOnly="true" />
<br />
<button
className="btn-frame deepgray"
onClick={() => {
setRadioInput('')
}}
>
QInput Radio DATA RESET
</button>
<QInput
type="radio"
value={radioInput}
onChange={setRadioInput}
options={[
{ id: 'r01', value: 'option1', name: 'Option 1' },
{ id: 'r02', value: 'option2', name: 'Option 2' },
]}
/>
<br />
<button
className="btn-frame deepgray"
onClick={() => {
setCheckboxInput([])
}}
>
QInput Checkbox DATA RESET
</button>
<QInput
type="checkbox"
value={checkboxInput}
onChange={setCheckboxInput}
options={[
{ id: 'c01', value: 'checkbox1', name: 'Checkbox 1' },
{ id: 'c02', value: 'checkbox2', name: 'Checkbox 2' },
]}
/>
</div>
<div className="m-2">
<br />
<button
className="btn-frame deepgray"
onClick={() => {
setSelectedValue([])
}}
>
QSelect DATA RESET
</button>
<QSelect
value={selectedValue}
onChange={setSelectedValue}
// placeholder=" "
options={[
{ id: 's01', value: 'cat', name: '고양이' },
{ id: 's02', value: 'dog', name: '개' },
{ id: 's03', value: 'lion', name: '사자' },
{ id: 's04', value: 'tiger', name: '호랑이' },
]}
/>
<QSelect
value={selectedValue}
onChange={setSelectedValue}
placeholder="동물을 선택하세요"
options={[
{ id: 's01', value: 'cat', name: '고양이' },
{ id: 's02', value: 'dog', name: '개' },
{ id: 's03', value: 'lion', name: '사자' },
{ id: 's04', value: 'tiger', name: '호랑이' },
]}
disabled="true"
/>
<QSelect
value={selectedValue}
onChange={setSelectedValue}
placeholder="동물을 선택하세요"
options={[
{ id: 's01', value: 'cat', name: '고양이' },
{ id: 's02', value: 'dog', name: '개' },
{ id: 's03', value: 'lion', name: '사자' },
{ id: 's04', value: 'tiger', name: '호랑이' },
]}
dark="true"
/>
</div>
<div className="w-full bg-orange-300 m-2">{testVar}</div>
<div>
<div className="m-2">
<Button onClick={handleUsers}>Button</Button>
</div>
</div>
<div className="test">
<p className="text-white">Sass 테스트입니다.</p>
</div>
<div dangerouslySetInnerHTML={{ __html: getMessage('welcome', ['<span style="color: red">test</span>']) }}></div>
<div>
<h1>React ColorPicker</h1>
<ColorPicker color={color} setColor={setColor} />
<div className="p-4">{color}</div>
</div>
<div>
<h1 className="text-2xl">캐드 파일 이미지 사용</h1>
<input type="file" name="file" ref={fileRef} />
<div>
<Button onClick={handleConvert}>Convert</Button>
</div>
</div>
<div>
<h1 className="text-2xl">구글 이미지 사용</h1>
<input type="text" ref={queryRef} className="w-80 border-medium my-2" />
<div>
<Button onClick={handleDownImage}>Google map Download to Image</Button>
</div>
{useGoogleMapFile && (
<>
<div className="my-2">
<p className="text-lg">Zoom Controller : {zoom}</p>
<Button startContent={<FaAnglesUp />} className="mx-2" onClick={() => handleZoom('up')}></Button>
<Button startContent={<FaAnglesDown />} className="mx-2" onClick={() => handleZoom('down')}></Button>
</div>
<div className="my-2">
<Image src={`/mapImages/${googleMapFileName}`} width={640} height={640} />
</div>
</>
)}
</div>
<div className="my-2">
<Button onClick={() => swalFire({ text: 'alert 테스트입니다.' })}>Sweetalert - alert</Button>
</div>
<div className="my-2">
<Button onClick={() => swalFire({ text: 'alert 아이콘 테스트입니다.', icon: 'error' })}>Sweetalert - alert - error</Button>
</div>
<div className="my-2">
<Button
onClick={() =>
swalFire({
html: `confirm 테스트입니다.<br />당신은 바보입니까?`,
type: 'confirm',
confirmFn: () => {
alert('test')
},
})
}
>
Sweetalert - confirm
</Button>
</div>
<div className="my-2">
<QPagination {...paginationProps} />
</div>
<div className="my-2">
<Button
onClick={() => {
promiseGet({ url: 'http://localhost:8080/api/user' }).then((res) => setUsers(res.data))
}}
>
axios get test
</Button>
</div>
<div className="my-2">
<Button
onClick={() => {
const result = promisePost({
url: 'http://localhost:8080/api/user',
data: {
firstName: 'Yoo',
lastName: 'Sangwook',
email: 'yoo1757@naver.com',
age: 46,
},
}).then((res) => console.log('res', res))
}}
>
axios post test
</Button>
</div>
<div className="my-2">
<QSelectBox options={codes} value={myData} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
</div>
<div className="my-2">
<Button onClick={handleChangeMyData}>QSelectBox value change!!</Button>
</div>
<div className="my-2">
<QSelectBox options={codes} value={myData2} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
</div>
<div className="my-2">
<Button onClick={handleChangeMyData2}>QSelectBox dynamic data bind change!!</Button>
</div>
<div className="my-2">
<QSelectBox title="초기값 테스트" options={[]} value={{}} sourceKey="id" targetKey="raftBaseCd" showKey="clCodeNm" />
</div>
<div className="my-2">
<SampleReducer />
</div>
<div className="my-2">
<Button onClick={() => setManagementState({ ...managementState, objectNo: '1234567890' })}>GlobalDataProvider 테스트</Button>
</div>
<div className="my-2">
<Button onClick={() => setManagementState({})}>GlobalDataProvider 초기화</Button>
</div>
{/* <div className="my-2">
<p>{managementStateLoaded?.objectNo}</p>
</div> */}
<div className="my-2">
<Button onClick={() => swalFire({ text: 'alert 테스트입니다.', type: 'alert', confirmFn: () => console.log('Alert!!!') })}>
Sweetalert - alert
</Button>
</div>
{/* <div className="my-2">
{tutoData &&
tutoData.map((item) => (
<div key={item.id}>
{item.name} / {item.email}
</div>
))}
</div>
<div className="my-2">
<Button onClick={() => setCallFlag(true)}>getFetcher call</Button>
</div>
<div className="my-2">
<Button disabled={isMutating} onClick={() => trigger({ id: 3, name: 'seulda kim', email: 'seulda.kim@interplug.co.kr' })}>
insert data
</Button>
</div> */}
<div className="my-2">
<Button
onClick={() => {
canvasPopupStatusTrigger({
common: {
illuminationTp: '3',
instHt: '10',
stdWindSpeed: 'WL_32',
stdSnowLd: '5',
moduleTpCd: 'A1',
moduleItemId: '106796',
},
roofConstructions: [
{
roofIndex: 0,
addRoof: {
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlNm: '일본기와 A',
roofMatlNmJp: '和瓦A',
widAuth: 'R',
widBase: '265.000',
lenAuth: 'R',
lenBase: '235.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53A',
name: '일본기와 A',
selected: true,
index: 0,
nameJp: '和瓦A',
length: 235,
width: 265,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 7,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_WA_53A',
roofMatlCdNm: '일본기와 A',
roofMatlCdJp: '和瓦A',
trestleMkrCd: 'ROOF_TECHRI',
trestleMkrCdNm: '지붕 기술 연구소',
trestleMkrCdJp: '屋根技術研究所',
constMthdCd: 'CST026',
constMthdCdNm: 'YG 앵커 랙 있음',
constMthdCdJp: 'YGアンカー ラック有り',
roofBaseCd: 'RFB001',
roofBaseCdNm: '구조용 합판 9mm 이상',
roofBaseCdJp: '構造用合板9mm以上',
rackYn: null,
priority: 1,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 0,
setupCover: true,
setupSnowCover: true,
selectedIndex: 1,
},
},
{
roofIndex: 1,
addRoof: {
roofMatlCd: 'ROOF_ID_WA_53B',
roofMatlNm: '일본기와 B',
roofMatlNmJp: '和瓦B',
widAuth: 'R',
widBase: '275.000',
lenAuth: 'R',
lenBase: '225.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_WA_53B',
name: '일본기와 B',
selected: true,
index: 1,
nameJp: '和瓦B',
length: 225,
width: 275,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 5,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_WA_53B',
roofMatlCdNm: '일본기와 B',
roofMatlCdJp: '和瓦B',
trestleMkrCd: 'DAIDO HUNT',
trestleMkrCdNm: '다이도 헌트',
trestleMkrCdJp: 'ダイドーハント',
constMthdCd: 'CST016',
constMthdCdNm: '지지 기와Ⅱ-B 랙 있음',
constMthdCdJp: '支持瓦Ⅱ-B ラック有り',
roofBaseCd: 'RFB002',
roofBaseCdNm: 'OSB12mm 이상',
roofBaseCdJp: 'OSB12mm以上',
rackYn: null,
priority: 95,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 1,
setupCover: false,
setupSnowCover: true,
selectedIndex: 1,
},
},
{
roofIndex: 2,
addRoof: {
roofMatlCd: 'ROOF_ID_HIRA_C',
roofMatlNm: '평판기와 C',
roofMatlNmJp: '平板瓦C',
widAuth: 'R',
widBase: '305.000',
lenAuth: 'R',
lenBase: '280.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_HIRA_C',
name: '평판기와 C',
selected: true,
index: 2,
nameJp: '平板瓦C',
length: 280,
width: 305,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 4,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_HIRA_C',
roofMatlCdNm: '평판기와 C',
roofMatlCdJp: '平板瓦C',
trestleMkrCd: 'ROOF_TECHRI',
trestleMkrCdNm: '지붕 기술 연구소',
trestleMkrCdJp: '屋根技術研究所',
constMthdCd: 'CST034',
constMthdCdNm: '지지 기와 C 랙 있음',
constMthdCdJp: '支持瓦C ラック有り',
roofBaseCd: 'RFB001',
roofBaseCdNm: '구조용 합판 9mm 이상',
roofBaseCdJp: '構造用合板9mm以上',
rackYn: null,
priority: 122,
},
construction: {
constTp: 'WORK_LV_ID_1',
constTpNm: '표준 시공',
constTpJp: '標準施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 2,
setupCover: false,
setupSnowCover: false,
selectedIndex: 1,
},
},
{
roofIndex: 3,
addRoof: {
roofMatlCd: 'ROOF_ID_HIRA_D',
roofMatlNm: '평판기와 D',
roofMatlNmJp: '平板瓦D',
widAuth: 'R',
widBase: '305.000',
lenAuth: 'R',
lenBase: '280.000',
roofPchAuth: null,
roofPchBase: null,
raftAuth: 'C',
raftBaseCd: 'HEI_455',
id: 'ROOF_ID_HIRA_D',
name: '평판기와 D',
selected: true,
index: 3,
nameJp: '平板瓦D',
length: 280,
width: 305,
raft: 'HEI_455',
layout: 'P',
hajebichi: 0,
pitch: 8,
angle: 21.8,
roofSizeSet: '1',
roofAngleSet: 'slope',
},
trestle: {
moduleTpCd: 'A1',
moduleTpCdNm: 'A1type',
moduleTpCdJp: 'A1type',
roofMatlCd: 'ROOF_ID_HIRA_D',
roofMatlCdNm: '평판기와 D',
roofMatlCdJp: '平板瓦D',
trestleMkrCd: 'DAIDO HUNT',
trestleMkrCdNm: '다이도 헌트',
trestleMkrCdJp: 'ダイドーハント',
constMthdCd: 'CST018',
constMthdCdNm: '지지 기와Ⅱ-D 랙 있음',
constMthdCdJp: '支持瓦Ⅱ-D ラック有り',
roofBaseCd: 'RFB002',
roofBaseCdNm: 'OSB12mm 이상',
roofBaseCdJp: 'OSB12mm以上',
rackYn: null,
priority: 203,
},
construction: {
constTp: 'WORK_LV_ID_3',
constTpNm: '강화 시공',
constTpJp: '強化施工',
constPossYn: 'Y',
plvrYn: 'Y',
cvrYn: 'Y',
cvrLmtRow: 9999,
snowGdPossYn: 'Y',
roofIndex: 3,
setupCover: false,
setupSnowCover: false,
selectedIndex: 2,
},
},
],
module: {
itemId: '106796',
itemNm: 'Q.TRON M-G2.4+ 430',
goodsNo: 'Q.TRON M-G2.4+ 430',
itemTp: 'A1',
mixMatlNo: null,
mixItemTpYn: 'N',
itemList: [
{
itemId: '106796',
itemNm: 'Q.TRON M-G2.4+ 430',
goodsNo: 'Q.TRON M-G2.4+ 430',
itemTp: 'A1',
color: '#BEF781',
longAxis: '1722.000',
shortAxis: '1134.000',
thickness: '30.000',
wpOut: '430',
mixMatlNo: null,
},
],
name: 'Q.TRON M-G2.4+ 430',
},
})
}}
>
Test Data insert
</Button>
</div>
<div className="my-2">
<Button
onClick={() => {
const params = {
pid: 1,
objectNo: 'RT01250131002',
}
router.push(`/floor-plan/estimate/5?pid=${params.pid}&objectNo=${params.objectNo}`)
}}
>
견적서 페이지 이동
</Button>
</div>
</div>
</>
)
}

View File

@ -1,351 +0,0 @@
'use client'
import { useEffect } from 'react'
import { addDistanceTextToPolygon, getDistance } from '@/util/canvas-util'
import { useCanvas } from '@/hooks/useCanvas'
import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid'
export default function Roof() {
const {
canvas,
addShape,
handleUndo,
handleRedo,
handleClear,
handleCopy,
handleDelete,
handleSave,
handlePaste,
handleRotate,
attachCustomControlOnPolygon,
saveImage,
handleFlip,
} = useCanvas('canvas')
useEffect(() => {
let circle = new fabric.Circle({
radius: 40,
fill: 'rgba(200, 0, 0, 0.3)',
originX: 'center',
originY: 'center',
})
let text = new fabric.Textbox('AJLoveChina', {
originX: 'center',
originY: 'center',
textAlign: 'center',
fontSize: 12,
})
let group = new fabric.Group([circle, text], {
left: 100,
top: 100,
originX: 'center',
originY: 'center',
})
group.on('mousedblclick', () => {
// textForEditing is temporary obj,
// and will be removed after editing
console.log(text.type)
let textForEditing = new fabric.Textbox(text.text, {
originX: 'center',
originY: 'center',
textAlign: text.textAlign,
fontSize: text.fontSize,
left: group.left,
top: group.top,
})
// hide group inside text
text.visible = false
// note important, text cannot be hidden without this
group.addWithUpdate()
textForEditing.visible = true
// do not give controls, do not allow move/resize/rotation on this
textForEditing.hasConstrols = false
// now add this temporary obj to canvas
canvas.add(textForEditing)
canvas.setActiveObject(textForEditing)
// make the cursor showing
textForEditing.enterEditing()
textForEditing.selectAll()
// editing:exited means you click outside of the textForEditing
textForEditing.on('editing:exited', () => {
let newVal = textForEditing.text
let oldVal = text.text
// then we check if text is changed
if (newVal !== oldVal) {
text.set({
text: newVal,
visible: true,
})
// comment before, you must call this
group.addWithUpdate()
// we do not need textForEditing anymore
textForEditing.visible = false
canvas?.remove(textForEditing)
// optional, buf for better user experience
canvas?.setActiveObject(group)
}
})
})
canvas?.add(group)
}, [canvas])
const addRect = () => {
const rect = new fabric.Rect({
height: 200,
width: 200,
top: 10,
left: 10,
opacity: 0.4,
fill: randomColor(),
stroke: 'red',
name: uuidv4(),
})
addShape(rect)
}
const addHorizontalLine = () => {
const { x1, y1, x2, y2 } = { x1: 20, y1: 100, x2: 220, y2: 100 }
/**
* 시작X,시작Y,도착X,도착Y 좌표
*/
const horizontalLine = new fabric.Line([x1, y1, x2, y2], {
name: uuidv4(),
stroke: 'red',
strokeWidth: 3,
selectable: true,
})
const text = new fabric.Text(getDistance(x1, y1, x2, y2).toString(), {
fontSize: 20,
left: (x2 - x1) / 2,
top: y1 - 20,
})
const group = new fabric.Group([horizontalLine, text], {
left: 20,
top: 20,
})
// addShape(horizontalLine)
addShape(group)
console.log(JSON.stringify(canvas))
}
const addVerticalLine = () => {
const verticalLine = new fabric.Line([10, 10, 10, 100], {
name: uuidv4(),
stroke: 'red',
strokeWidth: 3,
selectable: true,
})
addShape(verticalLine)
}
const addTriangle = () => {
const triangle = new fabric.Triangle({
name: uuidv4(),
top: 50,
left: 50,
width: 100,
stroke: randomColor(),
strokeWidth: 3,
})
addShape(triangle)
}
const addTrapezoid = () => {
const trapezoid = new fabric.Polygon(
[
{ x: 100, y: 100 }, //
{ x: 500, y: 100 }, //
{ x: 750, y: 700 }, //
{ x: 250, y: 400 }, //
],
{
name: uuidv4(),
stroke: 'red',
opacity: 0.4,
strokeWidth: 3,
selectable: true,
objectCaching: false,
},
)
attachCustomControlOnPolygon(trapezoid)
const group = addDistanceTextToPolygon(trapezoid)
addGroupClickEvent(group)
canvas?.add(group)
canvas?.renderAll()
}
// group group object
function addGroupClickEvent(group) {
group.on('selected', (e) => {
console.log(e)
})
group.on('mousedblclick', (e) => {
// textForEditing is temporary obj,
// and will be removed after editing
const pointer = canvas?.getPointer(e.e) //
let minDistance = Infinity
let closestTextbox = null
const groupPoint = group.getCenterPoint()
group.getObjects().forEach(function (object) {
if (object.type === 'textbox') {
// TextBox
const objectCenter = object.getCenterPoint() // TextBox
const dx = objectCenter.x + groupPoint.x - pointer.x
const dy = objectCenter.y + groupPoint.y - pointer.y
const distance = Math.sqrt(dx * dx + dy * dy) // TextBox
if (distance < minDistance) {
// TextBox
minDistance = distance
closestTextbox = object
}
}
})
let textForEditing = new fabric.Textbox(closestTextbox.text, {
originX: 'center',
originY: 'center',
textAlign: closestTextbox.textAlign,
fontSize: closestTextbox.fontSize,
left: closestTextbox.left + groupPoint.x,
top: closestTextbox.top + groupPoint.y,
})
// hide group inside text
closestTextbox.visible = false
// note important, text cannot be hidden without this
group.addWithUpdate()
textForEditing.visible = true
// do not give controls, do not allow move/resize/rotation on this
textForEditing.hasConstrols = false
// now add this temporary obj to canvas
canvas?.add(textForEditing)
canvas?.setActiveObject(textForEditing)
// make the cursor showing
textForEditing?.enterEditing()
textForEditing?.selectAll()
// editing:exited means you click outside of the textForEditing
textForEditing?.on('editing:exited', () => {
let newVal = textForEditing.text
// then we check if text is changed
closestTextbox.set({
text: newVal,
visible: true,
})
// comment before, you must call this
group.addWithUpdate()
// we do not need textForEditing anymore
textForEditing.visible = false
canvas?.remove(textForEditing)
// optional, buf for better user experience
canvas?.setActiveObject(group)
})
})
}
// IText polygon
function addTextModifiedEvent(text, polygon, index) {
text.on('editing:exited', function () {})
}
const randomColor = () => {
return '#' + Math.round(Math.random() * 0xffffff).toString(16)
}
return (
<>
<div className="flex justify-center my-8 w-full">
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white" onClick={addRect}>
ADD RECTANGLE
</button>
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white" onClick={addHorizontalLine}>
ADD HORIZONTAL LINE
</button>
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white" onClick={addVerticalLine}>
ADD VERTICALITY LINE
</button>
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white" onClick={addTriangle}>
ADD TRIANGLE
</button>
<button className="w-30 mx-2 p-2 rounded bg-blue-500 text-white" onClick={addTrapezoid}>
ADD TRAPEZOID
</button>
<button className="w-30 mx-2 p-2 rounded bg-black text-white" onClick={handleCopy}>
COPY shape
</button>
<button className="w-30 mx-2 p-2 rounded bg-red-500 text-white" onClick={handleDelete}>
DELETE
</button>
<button className="w-30 mx-2 p-2 rounded bg-red-500 text-white" onClick={handleClear}>
CLEAR
</button>
<button className="w-30 mx-2 p-2 rounded bg-green-500 text-white" onClick={handleUndo}>
UNDO
</button>
<button className="w-30 mx-2 p-2 rounded bg-green-300 text-white" onClick={handleRedo}>
REDO
</button>
<button className="w-30 mx-2 p-2 rounded bg-black text-white" onClick={handleSave}>
저장
</button>
<button className="w-30 mx-2 p-2 rounded bg-black text-white" onClick={handlePaste}>
붙여넣기
</button>
<button className="w-30 mx-2 p-2 rounded bg-black text-white" onClick={() => handleRotate()}>
45 회전
</button>
<button
className="w-30 mx-2 p-2 rounded bg-black text-white"
onClick={() => {
saveImage('제목')
}}
>
이미지 저장
</button>
<button className="w-30 mx-2 p-2 rounded bg-black text-white" onClick={handleFlip}>
도형반전
</button>
</div>
<div
className="flex justify-center"
style={{
border: '1px solid',
width: 1000,
height: 1000,
margin: 'auto',
}}
>
<canvas id="canvas" />
</div>
</>
)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,324 +0,0 @@
'use client'
import React, { useEffect, useState } from 'react'
import { Button } from '@nextui-org/react'
import { useAxios } from '@/hooks/useAxios'
import { useRecoilState } from 'recoil'
import { customSettingsState } from '@/store/canvasAtom'
import { modalContent, modalState } from '@/store/modalAtom'
import ColorPicker from './common/color-picker/ColorPicker'
export default function Settings() {
const [objectNo, setObjectNo] = useState('test123240829010')
const [error, setError] = useState(null)
const [customSettings, setCustomSettings] = useRecoilState(customSettingsState)
const [color, setColor] = useState('#ff0000')
const [open, setOpen] = useRecoilState(modalState)
const [contents, setContent] = useRecoilState(modalContent)
const { get, post } = useAxios()
const handleSavePopup = () => {
console.log('color ', color)
}
const handleClosePopup = () => {
setContent('')
setOpen(false)
console.log('colorSetting ', color)
}
const colorSetting = (
<>
<br />
<h1>React ColorPicker</h1>
<ColorPicker color={color} setColor={setColor} />
<div className="p-4">{color}</div>
<div>
<button onClick={handleSavePopup}>저장</button> <p />
<button onClick={handleClosePopup}>취소</button>
</div>
</>
)
const customStyles = {
overlay: {
backgroundColor: 'rgba(0,0,0,0.5)',
},
content: {
width: '300px',
height: '400px',
margin: 'auto',
borderRadius: '4px',
boxShadow: '0 2px 4px rgba(0,0,0,0.2)',
padding: '20px',
},
}
//
const [settings, setSettings] = useState({
display1: Array(11).fill(false), // 1
display2: Array(3).fill(false), // 2
rangeSetting: 0, //
gridSettings: Array(5).fill(false), //
})
const gridItems = {
display1: [
'할당 표시',
'도면 표시',
'그리드 표시',
'문자 표시',
'흐름방향 표시',
'복도치수 표시',
'실제치수 표시',
'치수 표시 없음',
'가대 표시',
'좌표 표시',
'도면전환 표시',
],
display2: ['테두리만', '라인해치', 'All Painted'],
rangeSetting: ['극소', '소', '중', '대'],
gridSettings: ['임의 그리드', '실선 그리드', '점 그리드', '그리드 색 설정', '흡착점 추가'],
}
//
useEffect(() => {
if (!objectNo) {
alert('object_no를 입력하세요.')
}
}, [])
//
const handleToggle = (type, index) => {
// ' '
if (type === 'gridSettings' && gridItems.gridSettings[index] === '실선 그리드') {
//openGridPopup()
}
// ' '
if (type === 'gridSettings' && gridItems.gridSettings[index] === '그리드 색 설정') {
//setSelectedGridSetting(gridItems.gridSettings[index])
//setIsPopupOpen(true)
//return prevSettings //
setOpen(true)
setContent({ ...colorSetting })
}
setSettings((prevSettings) => {
// prevSettings[type] ,
let updated = Array.isArray(prevSettings[type]) ? [...prevSettings[type]] : []
if (type === 'rangeSetting') {
return { ...prevSettings, [type]: index }
}
updated[index] = updated[index] === false ? true : false
return { ...prevSettings, [type]: updated }
})
}
// ' '
const openGridPopup = () => {
const popupWidth = 500
const popupHeight = 300
//
const left = window.innerWidth / 2 - popupWidth / 2
const top = window.innerHeight / 2 - popupHeight / 2
//
window
.open
//'./components/intro', // URL
//'_blank', //
//`width=${popupWidth},height=${popupHeight},top=${top},left=${left}`, //
()
}
// Canvas Setting
const handleSelect = async () => {
try {
if (!objectNo) {
alert('object_no를 입력하세요.')
return
}
const res = await get({ url: `/api/canvas-management/canvas-settings/by-object/${objectNo}` })
//
if (!res) {
console.warn('조회 결과가 없습니다.')
//
setSettings({
display1: Array(11).fill(false), // 1
display2: Array(3).fill(false), // 2
rangeSetting: 0, //
gridSettings: Array(5).fill(false), //
})
alert('조회된 데이터가 없습니다. 기본 설정이 적용됩니다.')
return //
}
const data = {
display1: [
res.assignDisplay,
res.drawDisplay,
res.gridDisplay,
res.charDisplay,
res.flowDisplay,
res.hallwayDimenDisplay,
res.actualDimenDisplay,
res.noDimenDisplay,
res.trestleDisplay,
res.coordiDisplay,
res.drawConverDisplay,
],
display2: [res.onlyBorder, res.lineHatch, res.allPainted],
rangeSetting: res.adsorpRangeSetting,
gridSettings: [res.randomGrid, res.solidGrid, res.dotGrid, res.gridColorSet, res.adsorpPointAdd],
}
//
setSettings({
display1: data.display1,
display2: data.display2,
rangeSetting: data.rangeSetting,
gridSettings: data.gridSettings,
})
} catch (error) {
console.error('Data fetching error:', error)
}
}
// Canvas Setting
const handleSubmit = async () => {
if (!objectNo) {
alert('object_no를 입력하세요.')
return
}
const patternData = {
objectNo,
assignDisplay: settings.display1[0],
drawDisplay: settings.display1[1],
gridDisplay: settings.display1[2],
charDisplay: settings.display1[3],
flowDisplay: settings.display1[4],
hallwayDimenDisplay: settings.display1[5],
actualDimenDisplay: settings.display1[6],
noDimenDisplay: settings.display1[7],
trestleDisplay: settings.display1[8],
coordiDisplay: settings.display1[9],
drawConverDisplay: settings.display1[10],
onlyBorder: settings.display2[0],
lineHatch: settings.display2[1],
allPainted: settings.display2[2],
adsorpRangeSetting: settings.rangeSetting,
randomGrid: settings.gridSettings[0],
solidGrid: settings.gridSettings[1],
dotGrid: settings.gridSettings[2],
gridColorSet: settings.gridSettings[3],
adsorpPointAdd: settings.gridSettings[4],
}
console.log('patternData', patternData)
await post({ url: `/api/canvas-management/canvas-settings`, data: patternData })
//Recoil
setCustomSettings({ ...patternData })
//
await handleSelect()
}
return (
<>
<div className="container mx-auto p-4 m-4 border">
<div align="right">
<input type="text" placeholder="Object No 입력" value={objectNo} onChange={(e) => setObjectNo(e.target.value)} />
<Button onClick={handleSelect}>조회</Button>
<Button onClick={handleSubmit}>저장</Button>
</div>
<div className="container mx-auto p-4 m-4 border">
<h1>[디스플레이 설정]</h1>
<h1>* 도면에 표시할 항목을 클릭하면 적용 됩니다.</h1>
<div className="grid-container2">
{gridItems.display1.map((item, index) => (
<div
key={index}
className={`grid-item ${settings.display1[index] === true ? 'selected' : 'unselected'}`}
onClick={() => handleToggle('display1', index)}
>
{settings.display1[index]} {item}
</div>
))}
</div>
<br />
<h1>* 화면 표시</h1>
<div className="grid-container3">
{gridItems.display2.map((item, index) => (
<div
key={index}
className={`grid-item ${settings.display2[index] === true ? 'selected' : 'unselected'}`}
onClick={() => handleToggle('display2', index)}
>
{settings.display2[index]} {item}
</div>
))}
</div>
<h1>[글꼴/도면크기 설정]</h1>
<h1>* 글꼴 크기 변경</h1>
<div className="grid-container2">
<div className="grid-item">문자 글꼴 변경</div>
<div className="grid-item">흐름방향 글꼴 변경</div>
<div className="grid-item">치수 글꼴 변경</div>
<div className="grid-item">회로번호 글꼴 변경</div>
</div>
``
<h1>* 흡착 범위 설정</h1>
<div className="grid-container4">
{gridItems.rangeSetting.map((item, index) => (
<div
key={index}
className={`grid-item ${settings.rangeSetting === index ? 'selected' : 'unselected'}`}
onClick={() => handleToggle('rangeSetting', index)}
>
{item}
</div>
))}
</div>
<div className="grid-container3">
<div className="grid-item">치수선 설정</div>
<div className="grid-item">도면 크기 설정</div>
<div className="grid-item">흡착점 ON</div>
</div>
<h1>[그리드 설정]</h1>
<div>
<ColorPicker color={color} setColor={setColor} />
<div className="p-4">{color}</div>
</div>
<div className="grid-container2">
{gridItems.gridSettings.map((item, index) => (
<div
key={index}
className={`grid-item ${settings.gridSettings[index] === true ? 'selected' : 'unselected'}`}
onClick={() => handleToggle('gridSettings', index)}
>
{settings.gridSettings[index]} {item}
</div>
))}
</div>
</div>
</div>
</>
)
}

View File

@ -9,7 +9,7 @@ import { setSession, login, checkSession } from '@/lib/authActions'
import { useMessage } from '@/hooks/useMessage'
import { globalLocaleStore } from '@/store/localeAtom'
import { sessionStore } from '@/store/commonAtom'
import { useRouter } from 'next/navigation'
import { redirect, useRouter } from 'next/navigation'
import { useSearchParams } from 'next/navigation'
import GlobalSpinner from '@/components/common/spinner/GlobalSpinner'
@ -28,11 +28,13 @@ export default function Login() {
autoLoginProcess(autoLoginParam)
}
checkSession().then((res) => {
if (res) {
login()
}
})
// console.log('🚀 ~ checkSession ~ checkSession():', checkSession())
// checkSession().then((res) => {
// console.log('🚀 ~ checkSession ~ res:', res)
// if (res) {
// login()
// }
// })
}, [])
const autoLoginProcess = async (autoLoginParam) => {
@ -49,7 +51,7 @@ export default function Login() {
setSessionState(result)
login()
} else {
router.push('/login')
router.push('/login', undefined, { shallow: true })
}
})
}

View File

@ -33,53 +33,43 @@ export default function ColorPickerModal(props) {
}, [isShow])
return (
<WithDraggable isShow={true} pos={pos ?? ''} handle=".modal-handle">
<div className={`modal-pop-wrap lr mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.color.picker.title')}</h1>
<WithDraggable isShow={true} pos={pos ?? ''} handle=".modal-handle" className="lr">
<WithDraggable.Header
title={getMessage('modal.color.picker.title')}
onClose={() => {
if (setIsShow) {
setIsShow(false)
}
closePopup(id, isConfig)
}}
/>
<WithDraggable.Body>
<div className="color-setting-wrap">
<div className="color-picker">
<ColorPicker color={originColor} setColor={setOriginColor} />
</div>
</div>
<div className="grid-btn-wrap">
<button
className="modal-close"
className="btn-frame modal act"
onClick={() => {
if (setIsShow) {
setIsShow(false)
}
console.log(id)
if (setColor) setColor(originColor)
if (setIsShow) setIsShow(false)
//
if (name !== 'DimensionLineColor')
setSettingsDataSave({
...settingsData,
color: originColor,
})
closePopup(id, isConfig)
}}
>
닫기
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="color-setting-wrap">
<div className="color-tit">COLOR PICKER</div>
<div className="color-picker">
<ColorPicker color={originColor} setColor={setOriginColor} />
</div>
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
if (setColor) setColor(originColor)
if (setIsShow) setIsShow(false)
//
if (name !== 'DimensionLineColor')
setSettingsDataSave({
...settingsData,
color: originColor,
})
closePopup(id, isConfig)
}}
>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -40,7 +40,7 @@ export default function QContextMenu(props) {
if (!contextRef.current) return
const handleContextMenu = (e) => {
// e.preventDefault() // contextmenu
e.preventDefault() // contextmenu
if (tempGridMode) return
const position = {
x: window.innerWidth / 2 < e.pageX ? e.pageX - 240 : e.pageX,
@ -113,7 +113,7 @@ export default function QContextMenu(props) {
return (
<>
{contextMenu.visible && (
<div className="context-menu-wrap" style={{ position: 'fixed', top: contextMenu.y, left: contextMenu.x, zIndex: 2000 }}>
<div className="context-menu-wrap" style={{ position: 'fixed', top: contextMenu.y, left: contextMenu.x }}>
{/*<ul>*/}
{/*<li style={{ padding: '8px 12px', cursor: 'pointer' }} onClick={() => handleObjectMove()}>*/}
{/* 이동*/}

View File

@ -2,9 +2,13 @@
import { useState } from 'react'
import Draggable from 'react-draggable'
import PopSpinner from '../spinner/PopSpinner'
import { popSpinnerState } from '@/store/popupAtom'
import { useRecoilState } from 'recoil'
export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 }, handle = '' }) {
export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 }, handle = '', className = '', hasFooter = true, isHidden = false }) {
const [position, setPosition] = useState(pos)
const [popSpinnerStore, setPopSpinnerStore] = useRecoilState(popSpinnerState)
const handleOnDrag = (e, data) => {
e.stopPropagation()
@ -22,9 +26,44 @@ export default function WithDraggable({ isShow, children, pos = { x: 0, y: 0 },
onDrag={(e, data) => handleOnDrag(e, data)}
handle={handle === '' ? '.modal-handle' : handle}
>
{children}
<div className={`modal-pop-wrap ${className}`} style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
{children}
{hasFooter && <WithDraggableFooter />}
{popSpinnerStore && <PopSpinner />}
</div>
</Draggable>
)}
</>
)
}
function WithDraggableHeader({ title, onClose, children }) {
return (
<div className="modal-head modal-handle">
<h1 className="title">{title}</h1>
{onClose && (
<button className="modal-close" onClick={() => onClose()}>
닫기
</button>
)}
</div>
)
}
function WithDraggableBody({ children }) {
return (
<div className="modal-body">
<div className="left-bar modal-handle"></div>
<div className="right-bar modal-handle"></div>
<>{children}</>
</div>
)
}
function WithDraggableFooter() {
return <div className="modal-foot modal-handle"></div>
}
WithDraggable.Header = WithDraggableHeader
WithDraggable.Body = WithDraggableBody
WithDraggable.Footer = WithDraggableFooter

View File

@ -67,109 +67,101 @@ export default function FontSetting(props) {
}
return (
<WithDraggable isShow={true} pos={pos} handle=".modal-handle">
<div className={`modal-pop-wrap lrr mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.font')}</h1>
<button
className="modal-close"
onClick={() => {
if (setIsShow) setIsShow(false)
closePopup(id, isConfig)
}}
>
닫기
<WithDraggable isShow={true} pos={pos} handle=".modal-handle" className="lrr">
<WithDraggable.Header
title={getMessage('modal.font')}
onClose={() => {
if (setIsShow) setIsShow(false)
closePopup(id, isConfig)
}}
/>
<WithDraggable.Body>
<div className="slope-wrap">
<div className="font-option-warp">
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font')}(F)</div>
<div className="grid-select">
<QSelectBox
options={fonts}
value={selectedFont}
onChange={(e) => {
setSelectedFont(e)
}}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.style')}(Y)</div>
<div className="grid-select">
<QSelectBox
options={fontOptions}
value={selectedFontWeight}
onChange={(e) => {
setSelectedFontWeight(e)
}}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.size')}(S)</div>
<div className="grid-select">
<QSelectBox
options={fontSizes}
value={selectedFontSize}
onChange={(e) => setSelectedFontSize(e)}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.color')}</div>
<div className="grid-select">
<QSelectBox
title={''}
options={fontColors}
showKey={'name'}
sourceKey={'id'}
targetKey={'id'}
value={selectedFontColor}
onChange={(e) => {
setSelectedFontColor(e)
}}
/>
</div>
</div>
</div>
<div className="font-ex-wrap">
<div className="font-ex-tit">{getMessage('modal.font.setting.display')}</div>
<div className="font-ex-box">
<span
style={{
fontFamily: selectedFont?.value ?? 'MS PGothic',
fontWeight: selectedFontWeight?.value?.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: selectedFontWeight?.value?.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: selectedFontSize?.value ?? 16,
color: selectedFontColor?.value ?? 'black',
}}
>
Aaあぁアァ
</span>
</div>
</div>
<div className="normal-font">{getMessage('modal.font.setting.info')}</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSaveBtn}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="font-option-warp">
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font')}(F)</div>
<div className="grid-select">
<QSelectBox
options={fonts}
value={selectedFont}
onChange={(e) => {
setSelectedFont(e)
}}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.style')}(Y)</div>
<div className="grid-select">
<QSelectBox
options={fontOptions}
value={selectedFontWeight}
onChange={(e) => {
setSelectedFontWeight(e)
}}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.size')}(S)</div>
<div className="grid-select">
<QSelectBox
options={fontSizes}
value={selectedFontSize}
onChange={(e) => setSelectedFontSize(e)}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
</div>
<div className="font-option-item">
<div className="option-item-tit">{getMessage('modal.font.color')}</div>
<div className="grid-select">
<QSelectBox
title={''}
options={fontColors}
showKey={'name'}
sourceKey={'id'}
targetKey={'id'}
value={selectedFontColor}
onChange={(e) => {
setSelectedFontColor(e)
}}
/>
</div>
</div>
</div>
<div className="font-ex-wrap">
<div className="font-ex-tit">{getMessage('modal.font.setting.display')}</div>
<div className="font-ex-box">
<span
style={{
fontFamily: selectedFont?.value ?? 'MS PGothic',
fontWeight: selectedFontWeight?.value?.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: selectedFontWeight?.value?.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: selectedFontSize?.value ?? 16,
color: selectedFontColor?.value ?? 'black',
}}
>
Aaあぁアァ
</span>
</div>
</div>
<div className="normal-font">{getMessage('modal.font.setting.info')}</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSaveBtn}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

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

View File

@ -2,6 +2,11 @@
import '@/styles/spinner.scss'
/**
* 전역 스피너
* 전역 로딩 스피너
* @returns
*/
export default function GlobalSpinner() {
return (
<>

View File

@ -0,0 +1,7 @@
export default function PopSpinner() {
return (
<div className="pop-spinner">
<span className="loader"></span>
</div>
)
}

View File

@ -1,10 +1,9 @@
'use client'
import { useEffect, useState, useContext } from 'react'
import { useRecoilValue, useSetRecoilState } from 'recoil'
import { useRecoilValue } from 'recoil'
import { floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { useMessage } from '@/hooks/useMessage'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import SingleDatePicker from '../common/datepicker/SingleDatePicker'
import EstimateFileUploader from './EstimateFileUploader'
import { useAxios } from '@/hooks/useAxios'
@ -14,17 +13,16 @@ import dayjs from 'dayjs'
import { useCommonCode } from '@/hooks/common/useCommonCode'
import { useEstimateController } from '@/hooks/floorPlan/estimate/useEstimateController'
import { SessionContext } from '@/app/SessionProvider'
import Select, { components } from 'react-select'
import Select from 'react-select'
import { convertNumberToPriceDecimal, convertNumberToPriceDecimalToFixed } from '@/util/common-utils'
import ProductFeaturesPop from './popup/ProductFeaturesPop'
import { v4 as uuidv4 } from 'uuid'
import { correntObjectNoState } from '@/store/settingAtom'
import { useSearchParams } from 'next/navigation'
import { usePlan } from '@/hooks/usePlan'
import { usePopup } from '@/hooks/usePopup'
import { useSwal } from '@/hooks/useSwal'
import { QcastContext } from '@/app/QcastProvider'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
export default function Estimate({}) {
const [uniqueData, setUniqueData] = useState([])
const [handlePricingFlag, setHandlePricingFlag] = useState(false)
@ -48,10 +46,10 @@ export default function Estimate({}) {
const [selection, setSelection] = useState(new Set())
//
// const [hidden, setHidden] = useState(false)
const [hidden, setHidden] = useState(true)
//
const [originDisplayItemList, setOriginDisplayItemList] = useState([])
const [displayItemList, setDisplayItemList] = useState([])
//
@ -60,6 +58,9 @@ export default function Estimate({}) {
const [storePriceList, setStorePriceList] = useState([]) // option
const [cableItemList, setCableItemList] = useState([]) //
const [cableItem, setCableItem] = useState('') //
const [startDate, setStartDate] = useState(new Date())
const singleDatePickerProps = {
startDate,
@ -69,9 +70,9 @@ export default function Estimate({}) {
* objectNo 셋팅
* url로 넘어온 objectNo을 리코일에 세팅
*/
const setCurrentObjectNo = useSetRecoilState(correntObjectNoState)
const searchParams = useSearchParams()
const objectRecoil = useRecoilValue(floorPlanObjectState)
const currentObjectNo = searchParams.get('objectNo')
const currentPid = searchParams.get('pid')
//
const { estimateContextState, setEstimateContextState, addItem, handleEstimateFileDownload } = useEstimateController(currentPid, false)
@ -88,13 +89,8 @@ export default function Estimate({}) {
const { getMessage } = useMessage()
const { setMenuNumber } = useCanvasMenu()
const { closeAll } = usePopup()
const currentObjectNo = searchParams.get('objectNo')
setCurrentObjectNo(currentObjectNo)
const { setSelectedMenu } = useCanvasMenu()
// props
const fileUploadProps = {
uploadFiles: files,
@ -104,8 +100,6 @@ export default function Estimate({}) {
const initEstimate = (currPid = currentPid) => {
console.log('🚀 ~ initEstimate ~ currPid:', currPid)
closeAll()
setMenuNumber(5)
setObjectNo(objectRecoil.floorPlanObjectNo)
setPlanNo(currPid)
@ -116,6 +110,16 @@ export default function Estimate({}) {
setHonorificCodeList(code1)
}
//
const code2 = findCommonCode(117900)
if (code2 != null) {
code2.map((item) => {
item.value = item.clRefChr1
item.label = item.clRefChr2
})
setCableItemList(code2)
}
//
const param = {
saleStoreId: session.storeId,
@ -123,7 +127,17 @@ export default function Estimate({}) {
const apiUrl = `/api/display-item/item-list?${queryStringFormatter(param)}`
post({ url: apiUrl, data: param }).then((res) => {
if (res.length > 0) {
setDisplayItemList(res)
let tempList = []
let updatedRes = []
if (estimateContextState?.itemList.length > 0) {
tempList = estimateContextState.itemList.filter((item) => !res.some((resItem) => resItem.itemId === item.itemId))
updatedRes = [...res, ...tempList]
} else {
updatedRes = [...res]
}
setOriginDisplayItemList(res)
setDisplayItemList(updatedRes)
}
})
// API
@ -143,6 +157,7 @@ export default function Estimate({}) {
}, [selectedPlan])
useEffect(() => {
setSelectedMenu('estimate')
initEstimate()
}, [])
@ -465,10 +480,6 @@ export default function Estimate({}) {
//Pricing
const handlePricing = async (showPriceCd) => {
//todo: YJSS swalFire
if (estimateContextState.estimateType === 'YJSS') {
return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' })
}
const param = {
saleStoreId: session.storeId,
sapSalesStoreCd: session.custCd,
@ -549,7 +560,7 @@ export default function Estimate({}) {
}
const getAbledItems = (items) => {
return items.filter((items) => items.paDispOrder === null)
return items.filter((items) => items.dispCableFlg !== '1' && items.paDispOrder === null)
}
const onChangeSelectAll = (e) => {
@ -566,7 +577,7 @@ export default function Estimate({}) {
return selection.size === getAbledItems(estimateContextState.itemList).length
}
//row
//row
const onChangeSelect = (dispOrder) => {
const newSelection = new Set(selection)
if (newSelection.has(dispOrder)) {
@ -578,10 +589,6 @@ export default function Estimate({}) {
setSelection(newSelection)
}
function formatNumberWithComma(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',')
}
//PKG input
const onChangePkgAsp = (value) => {
if (estimateContextState.estimateType === 'YJSS') {
@ -686,12 +693,20 @@ export default function Estimate({}) {
setItemChangeYn(true)
}
/* 케이블 select 변경시 */
const onChangeDisplayCableItem = (value, itemList) => {
itemList.map((item, index) => {
if (item.dispCableFlg === '1') {
if (value !== '') {
onChangeDisplayItem(value, item.dispOrder, index, true)
}
}
})
setCableItem(value)
}
// /
const onChangeDisplayItem = (itemId, dispOrder, index) => {
//todo: YJSS swalFire
if (estimateContextState.estimateType === 'YJSS') {
return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' })
}
const onChangeDisplayItem = (itemId, dispOrder, index, flag) => {
const param = {
itemId: itemId,
coldZoneFlg: estimateContextState?.coldRegionFlg,
@ -721,7 +736,7 @@ export default function Estimate({}) {
updates.itemGroup = res.itemGroup
updates.delFlg = '0' // 0
updates.saleTotPrice = (res.salePrice * estimateContextState.itemList[index].amount).toString()
updates.amount = ''
updates.amount = flag ? estimateContextState.itemList[index].amount : ''
updates.openFlg = res.openFlg
if (estimateContextState.estimateType === 'YJSS') {
@ -784,6 +799,7 @@ export default function Estimate({}) {
bomItem.objectNo = objectNo
bomItem.planNo = planNo
bomItem.addFlg = true // addFlg
bomItem.openFlg = '0' // 0
})
updateList = updateList.filter((item) => item.delFlg === '0')
@ -1002,7 +1018,7 @@ export default function Estimate({}) {
item.showSaleTotPrice = '0'
}
})
let dispCableFlgCnt = 0
estimateContextState.itemList.forEach((item) => {
if (item.delFlg === '0') {
let amount = Number(item.amount?.replace(/[^0-9]/g, '').replaceAll(',', '')) || 0
@ -1037,8 +1053,18 @@ export default function Estimate({}) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (item.dispCableFlg === '1') {
dispCableFlgCnt++
setCableItem(item.itemId)
}
}
})
if (dispCableFlgCnt === 0) {
setCableItem('100038')
}
let pkgAsp = estimateContextState.pkgAsp ? Number(estimateContextState.pkgAsp.replaceAll(',', '')) : 0
totals.pkgTotPrice = pkgAsp * totals.totVolKw * 1000
@ -1066,6 +1092,7 @@ export default function Estimate({}) {
}
})
let dispCableFlgCnt = 0
estimateContextState.itemList.forEach((item) => {
delete item.showSalePrice
delete item.showSaleTotPrice
@ -1093,9 +1120,21 @@ export default function Estimate({}) {
item.showSalePrice = '0'
item.showSaleTotPrice = '0'
}
if (item.dispCableFlg === '1') {
dispCableFlgCnt++
}
if (item.dispCableFlg === '1') {
setCableItem(item.itemId)
}
}
})
if (dispCableFlgCnt === 0) {
setCableItem('100038')
}
totals.vatPrice = totals.supplyPrice * 0.1
totals.totPrice = totals.supplyPrice + totals.vatPrice
@ -1129,6 +1168,35 @@ export default function Estimate({}) {
setSpecialNoteFirstFlg(false)
}, [estimateContextState.resetFlag])
useEffect(() => {
if (estimateContextState?.itemList.length > 0) {
const tempList = estimateContextState.itemList.filter((item) => !displayItemList.some((resItem) => resItem.itemId === item.itemId))
if (tempList.length > 0) {
setDisplayItemList((prevList) => [...prevList, ...tempList])
}
}
}, [estimateContextState])
useEffect(() => {
if (cableItemList.lenght > 0 || estimateContextState?.itemList.length > 0) {
let dispCableFlgCnt = 0
estimateContextState.itemList.map((item) => {
if (item.dispCableFlg === '1') {
dispCableFlgCnt++
cableItemList.map((cable) => {
if (item.itemId === cable.clRefChr1) {
cable.clRefChr3 = item.itemName
}
})
}
})
if (dispCableFlgCnt === 0) {
setCableItem('100038')
}
}
}, [estimateContextState?.itemList, cableItemList])
return (
<div className="sub-content estimate">
<div className="sub-content-inner">
@ -1139,7 +1207,6 @@ export default function Estimate({}) {
<div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.objectNo')}</div>
<div className="estimate-name">
{/* {objectNo} (Plan No: {estimateContextState.planNo}) */}
{currentObjectNo} (Plan No: {planNo})
</div>
</div>
@ -1253,7 +1320,7 @@ export default function Estimate({}) {
}}
getOptionLabel={(x) => x.clCodeNm}
getOptionValue={(x) => x.clCode}
isClearable={false}
isClearable={true}
isSearchable={false}
value={honorificCodeList.filter(function (option) {
return option.clCodeNm === estimateContextState.objectNameOmit
@ -1275,7 +1342,7 @@ export default function Estimate({}) {
</th>
<td colSpan={3}>
<div className="radio-wrap">
{/* <div className="d-check-radio light mr10">
<div className="d-check-radio light mr10">
<input
type="radio"
name="estimateType"
@ -1289,7 +1356,7 @@ export default function Estimate({}) {
}}
/>
<label htmlFor="YJSS">{getMessage('estimate.detail.estimateType.yjss')}</label>
</div> */}
</div>
<div className="d-check-radio light">
<input
type="radio"
@ -1298,8 +1365,7 @@ export default function Estimate({}) {
value={'YJOD'}
checked={estimateContextState?.estimateType === 'YJOD' ? true : false}
onChange={(e) => {
//todo: YJSS
// setHandlePricingFlag(true)
setHandlePricingFlag(true)
setEstimateContextState({ estimateType: e.target.value })
}}
/>
@ -1568,9 +1634,7 @@ export default function Estimate({}) {
{/* 견적특이사항 선택한 내용 영역끝 */}
</div>
</div>
{/* 견적 특이사항 코드영역 끝 */}
{/* 견적특이사항 영역끝 */}
{/* 제품정보 시작 */}
<div className="table-box-title-wrap">
@ -1580,10 +1644,6 @@ export default function Estimate({}) {
</div>
<div className="esimate-wrap">
<div className="estimate-list-wrap one">
{/* <div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totAmount')}</div>
<div className="estimate-name blue">{convertNumberToPriceDecimal(estimateContextState?.totAmount)}</div>
</div> */}
<div className="estimate-box">
<div className="estimate-tit">{getMessage('estimate.detail.sepcialEstimateProductInfo.totVolKw')}</div>
<div className="estimate-name blue">{convertNumberToPriceDecimalToFixed(estimateContextState?.totVolKw, 2)}</div>
@ -1603,7 +1663,7 @@ export default function Estimate({}) {
</div>
</div>
{/* YJOD면 아래영역 숨김 */}
{/* <div className="common-table bt-able" style={{ display: estimateContextState?.estimateType === 'YJSS' ? '' : 'none' }}>
<div className="common-table bt-able" style={{ display: estimateContextState?.estimateType === 'YJSS' ? '' : 'none' }}>
<table>
<colgroup>
<col style={{ width: '160px' }} />
@ -1638,7 +1698,7 @@ export default function Estimate({}) {
</tr>
</tbody>
</table>
</div> */}
</div>
{/* 제품정보 끝 */}
{/* 가격표시영역시작 */}
<div className="estimate-product-option">
@ -1677,6 +1737,24 @@ export default function Estimate({}) {
{getMessage('estimate.detail.showPrice.pricingBtn')}
</button>
</div>
<div className="product-price-wrap ml10">
<div className="select-wrap">
<select
className="select-light"
onChange={(e) => {
onChangeDisplayCableItem(e.target.value, estimateContextState.itemList)
}}
value={cableItem}
>
{cableItemList.length > 0 &&
cableItemList.map((row) => (
<option key={row.clRefChr1} value={row.clRefChr1}>
{row.clRefChr2}
</option>
))}
</select>
</div>
</div>
<div className="product-edit-wrap">
<ul className="product-edit-explane">
<li className="explane-item item01">
@ -1720,7 +1798,7 @@ export default function Estimate({}) {
<table>
<colgroup>
<col width={50} />
<col width={60} />
<col width={70} />
<col />
<col width={300} />
<col width={90} />
@ -1756,7 +1834,7 @@ export default function Estimate({}) {
<input
type="checkbox"
id={item?.dispOrder}
disabled={!!item?.paDispOrder}
disabled={!!item?.paDispOrder || item.dispCableFlg === '1'}
onChange={() => onChangeSelect(item.dispOrder)}
checked={!!selection.has(item.dispOrder)}
/>
@ -1767,27 +1845,50 @@ export default function Estimate({}) {
<td>
<div className="form-flex-wrap">
<div className="select-wrap mr5">
<Select
name="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={displayItemList}
onChange={(e) => {
if (isObjectNotEmpty(e)) {
onChangeDisplayItem(e.itemId, item.dispOrder, index)
}
}}
defaultInputValue={item.itemName}
getOptionLabel={(x) => x.itemName}
getOptionValue={(x) => x.itemId}
isClearable={false}
isDisabled={!!item?.paDispOrder}
value={displayItemList.filter(function (option) {
return option.itemId === item.itemId
})}
/>
{item.dispCableFlg !== '1' ? (
<Select
name="long-value-select1"
instanceId="long-value-select1"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={originDisplayItemList}
onChange={(e) => {
if (isObjectNotEmpty(e)) {
onChangeDisplayItem(e.itemId, item.dispOrder, index, false)
}
}}
menuPlacement={'auto'}
getOptionLabel={(x) => x.itemName}
getOptionValue={(x) => x.itemNo}
isClearable={false}
isDisabled={!!item?.paDispOrder}
value={displayItemList.filter(function (option) {
if (item.itemNo === '') {
return false
} else {
return option.itemId === item.itemId
}
})}
/>
) : (
<Select
name="long-value-select11"
instanceId="long-value-select11"
className="react-select-custom"
classNamePrefix="custom"
placeholder="Select"
options={cableItemList}
menuPlacement={'auto'}
getOptionLabel={(x) => x.clRefChr3}
getOptionValue={(x) => x.clRefChr1}
isClearable={false}
isDisabled={true}
value={cableItemList.filter(function (option) {
return option.clRefChr1 === item.itemId
})}
/>
)}
</div>
{item?.itemChangeFlg === '1' && (
<div className="btn-area">
@ -1882,7 +1983,6 @@ export default function Estimate({}) {
</tbody>
</table>
</div>
{/* html테이블끝 */}
</div>
</div>

View File

@ -3,11 +3,14 @@
import { useRef } from 'react'
import { v4 as uuidv4 } from 'uuid'
import { useMessage } from '@/hooks/useMessage'
import { useSwal } from '@/hooks/useSwal'
export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
const fileInputRef = useRef(null)
const { getMessage } = useMessage()
const { swalFire } = useSwal()
const handleButtonClick = (e) => {
e.preventDefault()
fileInputRef.current.click()
@ -20,9 +23,18 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
const fileList = []
let passFlag = true
const allowedFileTypes = [
'image/',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
]
Array.from(e.target.files).forEach((file) => {
let fileType = file.type
if (!fileType.includes('image')) {
//, pdf,
const fileType = file.type
if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
@ -30,30 +42,11 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
})
if (!passFlag) {
alert(getMessage('estimate.detail.fileList.extCheck'))
swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
// const { files } = e.target
// const file = files[0]
// const fileType = file.type
// if (!fileType.includes('image')) {
// return alert(getMessage('estimate.detail.fileList.extCheck'))
// }
// setUploadFiles([...uploadFiles, { data: e.target.files[0], id: uuidv4() }])
//
setUploadFiles([...uploadFiles, ...fileList])
e.target.value = ''
// const formData = new FormData()
// formData.append('file', e.target.files[0])
// formData.append('objectNo', objectNo) //
// formData.append('planNo', planNo) //
// formData.append('category', category) //
// formData.append('userId', session.userId)
// await promisePost({ url: '/api/file/fileUpload', data: formData }).then((res) => {
// if (res.data > 0) setUploadFiles([...files, { name: e.target.files[0].name, id: uuidv4() }])
// })
}
const deleteFile = (id) => {
@ -65,10 +58,19 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
e.stopPropagation()
const fileList = []
let passFlag = true
const allowedFileTypes = [
'image/',
'application/pdf',
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
'application/vnd.ms-excel',
'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PPTX
'application/vnd.ms-powerpoint', // PPT
]
Array.from(e.dataTransfer.files).forEach((file) => {
//, pdf,
let fileType = file.type
if (!fileType.includes('image')) {
if (!allowedFileTypes.some((type) => fileType.includes(type))) {
passFlag = false
} else {
fileList.push({ data: file, id: uuidv4() })
@ -76,7 +78,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
})
if (!passFlag) {
alert(getMessage('estimate.detail.fileList.extCheck'))
swalFire({ text: getMessage('estimate.detail.fileList.extCheck'), type: 'alert', icon: 'error' })
}
setUploadFiles([...uploadFiles, ...fileList])
@ -103,16 +105,7 @@ export default function EstimateFileUploader({ uploadFiles, setUploadFiles }) {
<label className="file-upload" htmlFor="img" onClick={handleButtonClick}>
{getMessage('estimate.detail.fileList.btn')}
</label>
<input
type="file"
multiple
name="file"
id="img"
accept="image/*"
ref={fileInputRef}
style={{ display: 'none' }}
onChange={(e) => onChangeFiles(e)}
/>
<input type="file" multiple name="file" ref={fileInputRef} style={{ display: 'none' }} onChange={(e) => onChangeFiles(e)} />
</div>
<div
className="drag-file-area"

View File

@ -1,12 +1,15 @@
'use client'
import { useState } from 'react'
import { useState, useContext } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useAxios } from '@/hooks/useAxios'
import { useRecoilValue } from 'recoil'
import { floorPlanObjectState, estimateState } from '@/store/floorPlanObjectAtom'
import { usePathname, useSearchParams } from 'next/navigation'
import { QcastContext } from '@/app/QcastProvider'
export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDownPopLockFlg }) {
const { setIsGlobalLoading } = useContext(QcastContext)
const { getMessage } = useMessage()
const { promisePost } = useAxios()
@ -68,8 +71,10 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
const options = { responseType: 'blob' }
setIsGlobalLoading(true)
await promisePost({ url: url, data: params, option: options })
.then((resultData) => {
setIsGlobalLoading(false)
if (resultData) {
let fileName = 'unknow'
const blob = new Blob([resultData.data], { type: resultData.headers['content-type'] || 'application/octet-stream' })
@ -97,6 +102,7 @@ export default function DocDownOptionPop({ planNo, setEstimatePopupOpen, docDown
}
})
.catch((error) => {
setIsGlobalLoading(false)
console.log('::FileDownLoad Error::', error)
alert('File does not exist.')
})

View File

@ -106,7 +106,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
useEffect(() => {
if (estimateContextState?.charger) {
setCopyReceiveUser(estimateContextState.charger)
setCopyReceiveUser(session?.userNm)
}
}, [estimateContextState?.charger])
@ -296,7 +296,7 @@ export default function EstimateCopyPop({ planNo, setEstimateCopyPopupOpen }) {
type="button"
className="btn-origin navy mr5"
onClick={() => {
handleEstimateCopy(sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId)
handleEstimateCopy(sendPlanNo, copyReceiveUser, saleStoreId, otherSaleStoreId, setEstimateCopyPopupOpen)
}}
>
{getMessage('estimate.detail.estimateCopyPopup.copyBtn')}

View File

@ -13,6 +13,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
area: 0,
children: [],
padding: 5,
textVisible: true,
initialize: function (points, options, length = 0) {
// 소수점 전부 제거
@ -29,6 +30,7 @@ export const QLine = fabric.util.createClass(fabric.Line, {
this.idx = options.idx ?? 0
this.direction = options.direction ?? getDirectionByPoint({ x: this.x1, y: this.y1 }, { x: this.x2, y: this.y2 })
this.textMode = options.textMode ?? 'plane' // plane:복시도, actual:실측, none:표시안함
this.textVisible = options.textVisible ?? true
if (length !== 0) {
this.length = length
} else {
@ -40,6 +42,9 @@ export const QLine = fabric.util.createClass(fabric.Line, {
},
init: function () {
if (!this.textVisible) {
return
}
this.addLengthText()
this.on('moving', () => {

View File

@ -23,6 +23,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
initOptions: null,
direction: null,
arrow: null,
toFixed: 1,
initialize: function (points, options, canvas) {
this.lines = []
this.texts = []
@ -33,11 +34,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.innerLines = []
this.children = []
this.separatePolygon = []
this.toFixed = options.toFixed ?? 1
// 소수점 전부 제거
points.forEach((point) => {
point.x = Number(point.x.toFixed(1))
point.y = Number(point.y.toFixed(1))
point.x = Number(point.x.toFixed(this.toFixed))
point.y = Number(point.y.toFixed(this.toFixed))
})
options.selectable = options.selectable ?? true
options.sort = options.sort ?? true
@ -77,8 +79,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.initOptions = options
this.init()
this.initLines()
this.init()
this.setShape()
},
@ -134,8 +136,20 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
this.on('removed', () => {
// const children = getAllRelatedObjects(this.id, this.canvas)
const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id)
children.forEach((child) => {
this.canvas.remove(child)
//그룹일때
if (child.hasOwnProperty('_objects')) {
child._objects.forEach((obj) => {
if (obj.hasOwnProperty('texts')) {
obj.texts.forEach((text) => {
this.canvas?.remove(text)
})
}
})
}
})
})
@ -162,9 +176,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
},
initLines() {
// if (this.lines.length > 0) {
// return
// }
let attributes = null
if (this.lines.length > 0) {
attributes = this.lines.map((line) => line.attributes)
}
this.lines = []
@ -174,9 +189,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
stroke: this.stroke,
strokeWidth: this.strokeWidth,
fontSize: this.fontSize,
attributes: {
offset: 0,
},
attributes: attributes
? attributes[i]
: {
offset: 0,
},
textVisible: false,
parent: this,
parentId: this.id,
direction: getDirectionByPoint(point, nextPoint),
@ -272,6 +290,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
if ([POLYGON_TYPE.MODULE, 'arrow', POLYGON_TYPE.MODULE_SETUP_SURFACE, POLYGON_TYPE.OBJECT_SURFACE].includes(this.name)) {
return
}
if (!this.fontSize) {
return
}
this.canvas
?.getObjects()
.filter((obj) => obj.name === 'lengthText' && obj.parentId === this.id)
@ -282,6 +304,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
let points = this.getCurrentPoints()
this.texts = []
points.forEach((start, i) => {
const end = points[(i + 1) % points.length]
const dx = Big(end.x).minus(Big(start.x))
@ -313,6 +336,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
lockScalingX: true,
lockScalingY: true,
idx: i,
actualSize: this.lines[i].attributes?.actualSize,
planeSize: this.lines[i].attributes?.planeSize,
name: 'lengthText',
parent: this,
})

View File

@ -13,7 +13,7 @@ import { useContextMenu } from '@/hooks/useContextMenu'
import { useCanvasConfigInitialize } from '@/hooks/common/useCanvasConfigInitialize'
import { currentMenuState } from '@/store/canvasAtom'
import { totalDisplaySelector } from '@/store/settingAtom'
import { MENU } from '@/common/common'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { FloorPlanContext } from '@/app/floor-plan/FloorPlanProvider'
import { QcastContext } from '@/app/QcastProvider'
import {
@ -26,6 +26,10 @@ import {
seriesState,
} from '@/store/circuitTrestleAtom'
import { useCanvasPopupStatusController } from '@/hooks/common/useCanvasPopupStatusController'
import { useCanvasSetting } from '@/hooks/option/useCanvasSetting'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
import { useEvent } from '@/hooks/useEvent'
import { compasDegAtom } from '@/store/orientationAtom'
export default function CanvasFrame() {
const canvasRef = useRef(null)
@ -42,10 +46,13 @@ export default function CanvasFrame() {
const resetSelectedMakerState = useResetRecoilState(selectedMakerState)
const resetSeriesState = useResetRecoilState(seriesState)
const resetModelsState = useResetRecoilState(modelsState)
const resetCompasDeg = useResetRecoilState(compasDegAtom)
const resetSelectedModelsState = useResetRecoilState(selectedModelsState)
const resetPcsCheckState = useResetRecoilState(pcsCheckState)
const { handleModuleSelectionTotal } = useCanvasPopupStatusController()
const { basicSetting, fetchBasicSettings } = useCanvasSetting()
const { selectedMenu, setSelectedMenu } = useCanvasMenu()
const { initEvent } = useEvent()
const loadCanvas = () => {
if (!canvas) return
@ -56,8 +63,16 @@ export default function CanvasFrame() {
canvas?.loadFromJSON(JSON.parse(plan.canvasStatus), function () {
canvasLoadInit() //config
canvas?.renderAll() // .
if (canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE).length > 0) {
setSelectedMenu('module')
} else {
setSelectedMenu('surface')
}
initEvent()
})
}
Object.keys(currentCanvasPlan).length > 0 && canvas && handleModuleSelectionTotal()
}
gridInit()
}
@ -65,7 +80,14 @@ export default function CanvasFrame() {
useEffect(() => {
loadCanvas()
resetRecoilData()
Object.keys(currentCanvasPlan).length > 0 && handleModuleSelectionTotal()
/* 플랜번호가 있으면 베이직세팅 팝업 데이터 로드 */
if (currentCanvasPlan.planNo) {
/* 약간의 지연을 줘서 roofMaterials가 로드될 시간을 확보 */
setTimeout(() => {
fetchBasicSettings(Number(currentCanvasPlan.planNo), null)
}, 100)
}
}, [currentCanvasPlan, canvas])
useEffect(() => {
@ -78,11 +100,12 @@ export default function CanvasFrame() {
}, [])
const resetRecoilData = () => {
resetModuleStatisticsState()
// resetModuleStatisticsState()
resetMakersState()
resetSelectedMakerState()
resetSeriesState()
resetModelsState()
resetCompasDeg()
resetSelectedModelsState()
resetPcsCheckState()
}
@ -102,12 +125,7 @@ export default function CanvasFrame() {
</ul>
))}
</QContextMenu>
{[
MENU.MODULE_CIRCUIT_SETTING.BASIC_SETTING,
MENU.MODULE_CIRCUIT_SETTING.CIRCUIT_TRESTLE_SETTING,
MENU.MODULE_CIRCUIT_SETTING.PLAN_ORIENTATION,
].includes(currentMenu) &&
totalDisplay && <PanelBatchStatistics />}
{selectedMenu === 'module' && totalDisplay && <PanelBatchStatistics />}
{/* 이미지 로드 팝업 */}
<ImgLoad />
</div>

View File

@ -14,7 +14,7 @@ import { globalLocaleStore } from '@/store/localeAtom'
export default function CanvasLayout({ children }) {
// const { menuNumber } = props
const pathname = usePathname()
const { menuNumber } = useCanvasMenu()
const { selectedMenu } = useCanvasMenu()
const { session } = useContext(SessionContext)
const { floorPlanState } = useContext(FloorPlanContext)
const { objectNo, pid } = floorPlanState
@ -30,7 +30,7 @@ export default function CanvasLayout({ children }) {
return (
<div className="canvas-layout">
<div className={`canvas-page-list ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>
<div className={`canvas-page-list ${['outline', 'surface', 'module'].includes(selectedMenu) ? 'active' : ''}`}>
<div className="canvas-plane-wrap">
{plans.map((plan, index) => (
<button
@ -39,7 +39,7 @@ export default function CanvasLayout({ children }) {
onClick={() => handleCurrentPlan(plan.id)}
>
<span>{`Plan ${plan.planNo}`}</span>
{index !== 0 && !pathname.includes('/estimate') && !pathname.includes('/simulator') && (
{plans.length > 1 && !pathname.includes('/estimate') && !pathname.includes('/simulator') && (
<i
className="close"
onClick={(e) => {

View File

@ -38,7 +38,7 @@ import {
} from '@/store/settingAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
import { commonUtilsState } from '@/store/commonUtilsAtom'
import { menusState, menuTypeState } from '@/store/menuAtom'
import { menusState } from '@/store/menuAtom'
import { estimateState, floorPlanObjectState } from '@/store/floorPlanObjectAtom'
import { pwrGnrSimTypeState } from '@/store/simulatorAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
@ -48,13 +48,14 @@ import KO from '@/locales/ko.json'
import JA from '@/locales/ja.json'
import { QcastContext } from '@/app/QcastProvider'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { usePolygon } from '@/hooks/usePolygon'
export default function CanvasMenu(props) {
const { menuNumber, setMenuNumber } = props
const { selectedMenu, setSelectedMenu } = props
const pathname = usePathname()
const router = useRouter()
const { addPopup } = usePopup()
const canvasMenus = useRecoilValue(menusState)
const [type, setType] = useRecoilState(menuTypeState)
const [verticalHorizontalMode, setVerticalHorizontalMode] = useRecoilState(verticalHorizontalModeState)
const setAppMessageState = useSetRecoilState(appMessageStore)
const setCurrentMenu = useSetRecoilState(currentMenuState)
@ -88,11 +89,11 @@ export default function CanvasMenu(props) {
const selectedRoofMaterial = useRecoilValue(selectedRoofMaterialSelector)
//
const [buttonStyle1, setButtonStyle1] = useState('') //
const [buttonStyle2, setButtonStyle2] = useState('') //
const [buttonStyle3, setButtonStyle3] = useState('') //
const [buttonStyle4, setButtonStyle4] = useState('') //
const [buttonStyle5, setButtonStyle5] = useState('') //
const [docDownButtonStyle, setDocDownButtonStyle] = useState('') //
const [saveButtonStyle, setSaveButtonStyle] = useState('') //
const [resetButtonStyle, setResetButtonStyle] = useState('') //
const [copyButtonStyle, setCopyButtonStyle] = useState('') //
const [lockButtonStyle, setLockButtonStyle] = useState('') //
const setFloorPlanObjectNo = useSetRecoilState(floorPlanObjectState) //
@ -104,11 +105,13 @@ export default function CanvasMenu(props) {
const pwrGnrSimTypeRecoil = useRecoilValue(pwrGnrSimTypeState)
const { setIsGlobalLoading } = useContext(QcastContext)
const { setSurfaceShapePattern } = useRoofFn()
const { drawDirectionArrow } = usePolygon()
//
const { selectedPlan } = usePlan()
const handleExcelPdfFileDown = async (donwloadType, drawingFlg) => {
const url = '/api/estimate/excel-download'
const url = '/api/pwrGnrSimulation/excel-download'
const params = {
objectNo: objectNo,
@ -149,9 +152,20 @@ export default function CanvasMenu(props) {
setIsGlobalLoading(false)
}
// roof
const initRoofs = () => {
const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
roofs.forEach((roof) => {
roof.set({ selectable: true })
setSurfaceShapePattern(roof, null, false, roof.roofMaterial)
delete roof.moduleCompass
drawDirectionArrow(roof, false)
})
}
const onClickNav = async (menu) => {
switch (menu.index) {
case 0:
switch (menu.type) {
case 'drawing':
swalFire({
text: getMessage('stuff.detail.move.confirmMsg'),
type: 'confirm',
@ -161,77 +175,77 @@ export default function CanvasMenu(props) {
},
})
break
case 1:
setType('placementShape')
case 'placement':
onClickPlacementInitialMenu()
await reloadCanvasStatus(objectNo, pid)
break
case 2:
setType('outline')
case 'outline':
await reloadCanvasStatus(objectNo, pid)
break
case 3:
console.log('🚀 ~ onClickNav ~ menu:', menu)
console.log('🚀 ~ onClickNav ~ menuNumber:', menuNumber)
if (menuNumber > menu.index) {
const modules = canvas.getObjects().filter((module) => module.name === POLYGON_TYPE.MODULE)
if (modules.length > 0) {
swalFire({
text: getMessage('module.delete.confirm'),
type: 'confirm',
confirmFn: () => {
//
const moduleSurfacesArray = canvas
.getObjects()
.filter(
(obj) =>
obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE || obj.name === POLYGON_TYPE.MODULE || obj.name === POLYGON_TYPE.OBJECT_SURFACE,
)
if (moduleSurfacesArray.length > 0) {
moduleSurfacesArray.forEach((moduleSurface) => {
canvas.remove(moduleSurface)
})
canvas.renderAll()
}
setType('surface')
},
denyFn: () => {
return
},
})
} else {
setType('surface')
}
} else {
setType('surface')
case 'surface':
const modules = canvas
.getObjects()
.filter((obj) => [POLYGON_TYPE.MODULE_SETUP_SURFACE, POLYGON_TYPE.MODULE, POLYGON_TYPE.OBJECT_SURFACE].includes(obj.name))
if (modules.length > 0) {
swalFire({
text: getMessage('module.delete.confirm'),
type: 'confirm',
confirmFn: () => {
//
const moduleSurfacesArray = canvas
.getObjects()
.filter((obj) => [POLYGON_TYPE.MODULE_SETUP_SURFACE, POLYGON_TYPE.MODULE, POLYGON_TYPE.OBJECT_SURFACE].includes(obj.name))
if (moduleSurfacesArray.length > 0) {
//
moduleSurfacesArray.forEach((moduleSurface) => {
canvas.remove(moduleSurface)
})
initRoofs()
canvas.renderAll()
onClickNav(menu)
}
},
denyFn: () => {
return
},
})
return
}
setSelectedMenu(menu.type)
await reloadCanvasStatus(objectNo, pid)
break
case 4:
if (menuNumber < menu.index) {
case 'module':
if (['placement', 'outline', 'surface'].some((menu) => menu === selectedMenu)) {
if (!checkMenuAndCanvasState()) {
swalFire({ text: getMessage('menu.validation.canvas.roof') })
return
} else {
setType('module')
setSelectedMenu('module')
}
} else {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
setSelectedMenu('module')
}
await reloadCanvasStatus(objectNo, pid)
break
case 5:
case 'estimate':
setIsGlobalLoading(true)
// (useEstimateController.js) setIsGlobalLoading(false)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
// if (estimateDetail.tempFlg === '0' && estimateDetail.estimateDate !== null) {
if (estimateDetail.estimateDate !== null) {
setMenuNumber(menu.index)
setSelectedMenu(menu.type)
setCurrentMenu(menu.title)
setFloorPlanObjectNo({ floorPlanObjectNo: objectNo })
router.push(`/floor-plan/estimate/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
setIsGlobalLoading(false)
router.push(`/floor-plan/estimate/5?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
if (pathname === '/floor-plan/estimate/5') {
setIsGlobalLoading(false)
}
} else {
setIsGlobalLoading(false)
swalFire({ text: getMessage('estimate.menu.move.valid1') })
@ -239,16 +253,18 @@ export default function CanvasMenu(props) {
}
})
break
case 6:
case 'simulation':
setIsGlobalLoading(true)
// (Simulator.jsx) setIsGlobalLoading(false)
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan.planNo}/detail` }).then((res) => {
if (res.status === 200) {
const estimateDetail = res.data
if (estimateDetail.estimateDate !== null) {
setMenuNumber(menu.index)
if (estimateDetail.estimateDate !== null && estimateDetail.docNo) {
setSelectedMenu(menu.type)
setCurrentMenu(menu.title)
router.push(`/floor-plan/simulator/${menu.index}?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
router.push(`/floor-plan/simulator/6?pid=${selectedPlan.planNo}&objectNo=${objectNo}`)
if (pathname === '/floor-plan/simulator/6') {
setIsGlobalLoading(false)
}
} else {
setIsGlobalLoading(false)
swalFire({ text: getMessage('simulator.menu.move.valid1') })
@ -258,14 +274,13 @@ export default function CanvasMenu(props) {
break
}
if (menu.index !== 6 && menu.index !== 0 && menu.index !== 5) {
setMenuNumber(menu.index)
if (menu.type !== 'simulation' && menu.type !== 'estimate' && menu.type !== 'drawing') {
setSelectedMenu(menu.type)
setCurrentMenu(menu.title)
}
if (pathname !== '/floor-plan') {
// if (menu.index !== 0 ) {
// or ..
if (menu.index !== 0 && menu.index !== 5 && menu.index !== 6) {
if (menu.type !== 'drawing' && menu.type !== 'estimate' && menu.type !== 'simulation') {
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
}
}
@ -288,20 +303,11 @@ export default function CanvasMenu(props) {
const settingsModalOptions = useRecoilState(settingModalFirstOptionsState)
useEffect(() => {
if (menuNumber === 1) {
console.log(selectedMenu)
if (selectedMenu === 'placement') {
onClickPlacementInitialMenu()
}
if (menuNumber === 3) {
const moduleSurfacesArray = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
if (moduleSurfacesArray.length > 0) {
moduleSurfacesArray.forEach((moduleSurface) => {
moduleSurface.modules = []
canvas.remove(moduleSurface)
})
canvas.renderAll()
}
}
}, [menuNumber, type])
}, [selectedMenu])
// (btn08)
const handleSaveCanvas = async () => {
@ -329,7 +335,12 @@ export default function CanvasMenu(props) {
x: 50,
y: 180,
},
planNo: selectedPlan?.planNo ? selectedPlan.planNo : pid,
openPoint: 'canvasMenus',
}
/**
* 배치면 초기설정 팝업 열기
*/
const onClickPlacementInitialMenu = () => {
addPopup(placementInitialId, 1, <PlacementShapeSetting {...placementInitialProps} />)
}
@ -354,11 +365,6 @@ export default function CanvasMenu(props) {
//
const handleEstimateReset = () => {
//todo: YJSS swalFire
if (estimateRecoilState.estimateType === 'YJSS') {
return swalFire({ text: getMessage('estimate.detail.save.requiredEstimateType'), type: 'alert', icon: 'warning' })
}
swalFire({
text: getMessage('estimate.detail.reset.confirmMsg'),
type: 'confirm',
@ -393,26 +399,20 @@ export default function CanvasMenu(props) {
} else {
setAppMessageState(JA)
}
}, [type, globalLocale])
/*useEffect(() => {
if (menuNumber === 1) {
return
}
setMenuNumber(1)
// if ([2, 3].some((num) => num === canvasSetting?.roofSizeSet)) {
// setMenuNumber(3)
// setType('surface')
// setCurrentMenu(MENU.BATCH_CANVAS.BATCH_DRAWING)
// } else {
// setMenuNumber(2)
// setType('outline')
// setCurrentMenu(MENU.ROOF_COVERING.EXTERIOR_WALL_LINE)
// }
}, [basicSetting])*/
}, [globalLocale])
const checkMenuState = (menu) => {
return (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) || (menuNumber === 4 && [1, 2].includes(menu.index))
return (
(['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.type === 'outline') ||
(selectedMenu === 'module' && ['placement', 'outline'].includes(menu.type)) ||
(isExistModule() && ['placement', 'outline'].some((num) => num === menu.type)) ||
(['estimate', 'simulation'].includes(selectedMenu) && ['placement', 'outline', 'surface'].includes(menu.type))
)
}
const isExistModule = () => {
const modules = canvas?.getObjects().filter((module) => module.name === POLYGON_TYPE.MODULE) ?? []
return modules.length > 0
}
/**
@ -430,42 +430,40 @@ export default function CanvasMenu(props) {
useEffect(() => {
if (isObjectNotEmpty(estimateContextState)) {
const { createUser, tempFlg, lockFlg } = estimateContextState
const { createUser, tempFlg, lockFlg, docNo } = estimateContextState
if (createUser && tempFlg && lockFlg) {
if (createUser === 'T01') {
if (sessionState.storeId !== 'T01') {
setAllButtonStyles('none')
} else {
handleButtonStyles(tempFlg, lockFlg)
}
if (createUser === 'T01' && sessionState.storeId !== 'T01') {
setAllButtonStyles('none')
} else {
handleButtonStyles(tempFlg, lockFlg)
handleButtonStyles(tempFlg, lockFlg, docNo)
}
}
}
}, [estimateContextState?.createUser, estimateContextState?.tempFlg, estimateContextState?.lockFlg])
}, [estimateContextState?.createUser, estimateContextState?.tempFlg, estimateContextState?.lockFlg, estimateContextState.docNo])
const setAllButtonStyles = (style) => {
setButtonStyle1(style)
setButtonStyle2(style)
setButtonStyle3(style)
setButtonStyle4(style)
setButtonStyle5(style)
setDocDownButtonStyle(style)
setSaveButtonStyle(style)
setResetButtonStyle(style)
setCopyButtonStyle(style)
setLockButtonStyle(style)
}
const handleButtonStyles = (tempFlg, lockFlg) => {
const handleButtonStyles = (tempFlg, lockFlg, docNo) => {
if (tempFlg === '1') {
setAllButtonStyles('none')
setButtonStyle2('')
setSaveButtonStyle('')
} else if (tempFlg === '0' && lockFlg === '0') {
setAllButtonStyles('')
} else {
setButtonStyle1('')
setButtonStyle2('none')
setButtonStyle3('none')
setButtonStyle4('')
setButtonStyle5('')
setDocDownButtonStyle('')
setSaveButtonStyle('none')
setResetButtonStyle('none')
setCopyButtonStyle('')
setLockButtonStyle('')
}
if (!docNo) {
setDocDownButtonStyle('none')
}
}
@ -495,16 +493,11 @@ export default function CanvasMenu(props) {
estimateRecoilState.lockFlg = estimateRecoilState.lockFlg === '0' ? '1' : '0'
const { createUser, tempFlg, lockFlg } = estimateRecoilState
if (createUser && tempFlg && lockFlg) {
if (createUser === 'T01') {
if (sessionState.storeId !== 'T01') {
setAllButtonStyles('none')
} else {
setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg })
handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg)
}
if (createUser === 'T01' && sessionState.storeId !== 'T01') {
setAllButtonStyles('none')
} else {
setEstimateContextState({ tempFlg: estimateRecoilState.tempFlg, lockFlg: estimateRecoilState.lockFlg })
handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg)
handleButtonStyles(estimateRecoilState.tempFlg, estimateRecoilState.lockFlg, estimateContextState.docNo)
}
}
}
@ -520,25 +513,24 @@ export default function CanvasMenu(props) {
//
const docDownPopLockFlg = () => {
setButtonStyle1('')
setButtonStyle2('none')
setButtonStyle3('none')
setButtonStyle4('')
setButtonStyle5('')
setDocDownButtonStyle('')
setSaveButtonStyle('none')
setResetButtonStyle('none')
setCopyButtonStyle('')
setLockButtonStyle('')
}
return (
<div className={`canvas-menu-wrap ${[2, 3, 4].some((num) => num === menuNumber) ? 'active' : ''}`}>
<div className={`canvas-menu-wrap ${['outline', 'surface', 'module'].some((num) => num === selectedMenu) ? 'active' : ''}`}>
<div className="canvas-menu-inner">
<ul className="canvas-menu-list">
{canvasMenus.map((menu) => {
return (
<li
key={`canvas-menu-${menu.index}`}
className={`canvas-menu-item ${menuNumber === menu.index ? 'active' : ''}`}
key={`canvas-menu-${menu.type}`}
className={`canvas-menu-item ${selectedMenu === menu.type ? 'active' : ''}`}
onClick={async () => {
if (['2', '3'].includes(canvasSetting?.roofSizeSet) && menu.index === 2) return
if (menuNumber === 4 && [1, 2].includes(menu.index)) return
if (checkMenuState(menu)) return
await onClickNav(menu)
}}
>
@ -551,7 +543,7 @@ export default function CanvasMenu(props) {
})}
</ul>
<div className="canvas-side-btn-wrap">
{![5, 6].some((num) => num === menuNumber) && (
{!['estimate', 'simulation'].some((num) => num === selectedMenu) && (
<>
{
<div className={`vertical-horizontal ${verticalHorizontalMode ? 'on' : ''}`}>
@ -568,16 +560,26 @@ export default function CanvasMenu(props) {
<div className="select-box">
{
<QSelectBox
//options={addedRoofs}
options={addedRoofs.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp }
})}
//showKey={'roofMatlNm'}
title={
+basicSetting.roofSizeSet === 3
? getMessage('modal.placement.initial.setting.size.none.pitch')
: globalLocale === 'ko'
? selectedRoofMaterial?.roofMatlNm
: selectedRoofMaterial?.roofMatlNmJp
}
options={
+basicSetting.roofSizeSet === 3
? []
: addedRoofs.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.roofMatlNm : roof.roofMatlNmJp }
})
}
showKey={'name'}
value={selectedRoofMaterial}
onChange={changeSelectedRoofMaterial}
sourceKey={'index'}
targetKey={'index'}
disabled={+basicSetting.roofSizeSet === 3}
/>
}
</div>
@ -612,20 +614,35 @@ export default function CanvasMenu(props) {
</>
)}
{menuNumber === 5 && (
{selectedMenu === 'estimate' && (
<>
<div className="ico-btn-from">
<button type="button" style={{ display: buttonStyle1 }} className="btn-frame gray ico-flx" onClick={() => setEstimatePopupOpen(true)}>
<button
type="button"
className="btn-frame gray ico-fix"
onClick={() => {
setIsGlobalLoading(true)
router.push(`/management/stuff/tempReg`, { scroll: false })
}}
>
<span className="name">{getMessage('stuff.search.btn.register')}</span>
</button>
<button
type="button"
style={{ display: docDownButtonStyle }}
className="btn-frame gray ico-flx"
onClick={() => setEstimatePopupOpen(true)}
>
<span className="ico ico01"></span>
<span className="name">{getMessage('plan.menu.estimate.docDown')}</span>
</button>
<button type="button" style={{ display: buttonStyle2 }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
<button type="button" style={{ display: saveButtonStyle }} className="btn-frame gray ico-flx" onClick={handleEstimateSubmit}>
<span className="ico ico02"></span>
<span className="name">{getMessage('plan.menu.estimate.save')}</span>
</button>
<button
type="button"
style={{ display: buttonStyle3 }}
style={{ display: resetButtonStyle }}
className="btn-frame gray ico-flx"
onClick={() => {
handleEstimateReset()
@ -638,7 +655,7 @@ export default function CanvasMenu(props) {
{estimateRecoilState?.docNo !== null && (sessionState.storeId === 'T01' || sessionState.storeLvl === '1') && (
<button
type="button"
style={{ display: buttonStyle4 }}
style={{ display: copyButtonStyle }}
className="btn-frame gray ico-flx"
onClick={() => {
setEstimateCopyPopupOpen(true)
@ -650,7 +667,7 @@ export default function CanvasMenu(props) {
)}
<button
type="button"
style={{ display: buttonStyle5 }}
style={{ display: lockButtonStyle }}
className="btn-frame gray ico-flx"
onClick={() => {
handleEstimateLockController(estimateRecoilState)
@ -664,7 +681,7 @@ export default function CanvasMenu(props) {
</div>
</>
)}
{menuNumber === 6 && (
{selectedMenu === 'simulation' && (
<>
<div className="ico-btn-from">
<button type="button" className="btn-frame gray ico-flx" onClick={() => handleExcelPdfFileDown('EXCEL', '2')}>
@ -680,8 +697,8 @@ export default function CanvasMenu(props) {
)}
</div>
</div>
<div className={`canvas-depth2-wrap ${[2, 3, 4].some((num) => num === menuNumber) ? 'active' : ''}`}>
{[2, 3, 4].some((num) => num === menuNumber) && <MenuDepth01 />}
<div className={`canvas-depth2-wrap ${['outline', 'surface', 'module'].some((num) => num === selectedMenu) ? 'active' : ''}`}>
{['outline', 'surface', 'module'].some((num) => num === selectedMenu) && <MenuDepth01 />}
</div>
{/* 견적서(menuNumber=== 5) 상세화면인경우 문서다운로드 팝업 */}
{estimatePopupOpen && (

View File

@ -15,11 +15,10 @@ export default function FloorPlan({ children }) {
const [correntObjectNo, setCurrentObjectNo] = useRecoilState(correntObjectNoState)
const searchParams = useSearchParams()
const objectNo = searchParams.get('objectNo')
const pid = searchParams.get('pid')
const { closeAll } = usePopup()
const { menuNumber, setMenuNumber } = useCanvasMenu()
const { fetchSettings, fetchBasicSettings } = useCanvasSetting()
const { selectedMenu, setSelectedMenu } = useCanvasMenu()
const { fetchSettings } = useCanvasSetting()
const resetCurrentMenu = useResetRecoilState(currentMenuState)
useEffect(() => {
return () => {
@ -27,7 +26,9 @@ export default function FloorPlan({ children }) {
}
}, [])
// URL objectNo
/**
* URL 파라미터에서 objectNo 설정
*/
useEffect(() => {
if (!objectNo) {
notFound()
@ -35,15 +36,15 @@ export default function FloorPlan({ children }) {
setCurrentObjectNo(objectNo)
}, [objectNo, setCurrentObjectNo])
// fetch
/**
* 설정 데이터 fetch
*/
useEffect(() => {
if (!correntObjectNo) return // correntObjectNo
/** correntObjectNo가 없으면 실행하지 않음 */
if (!correntObjectNo) return
if (menuNumber === null) {
//setMenuNumber(1)
}
/** CanvasSetting 데이터 fetch */
fetchSettings()
fetchBasicSettings()
return () => {
closeAll()
@ -51,15 +52,17 @@ export default function FloorPlan({ children }) {
}, [correntObjectNo])
const modalProps = {
menuNumber,
setMenuNumber,
selectedMenu,
setSelectedMenu,
}
return (
<>
<div className="canvas-wrap">
<CanvasMenu {...modalProps} />
<div className={`canvas-content ${menuNumber === 2 || menuNumber === 3 || menuNumber === 4 ? 'active' : ''}`}>{children}</div>
<div className={`canvas-content ${selectedMenu === 'outline' || selectedMenu === 'surface' || selectedMenu === 'module' ? 'active' : ''}`}>
{children}
</div>
</div>
</>
)

View File

@ -6,32 +6,33 @@ import { useMessage } from '@/hooks/useMessage'
import useMenu from '@/hooks/common/useMenu'
import { canvasState, currentMenuState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue } from 'recoil'
import { menuTypeState, subMenusState } from '@/store/menuAtom'
import { subMenusState } from '@/store/menuAtom'
import { useCanvasMenu } from '@/hooks/common/useCanvasMenu'
export default function MenuDepth01() {
const type = useRecoilValue(menuTypeState)
const canvas = useRecoilValue(canvasState)
const { getMessage } = useMessage()
const { handleMenu } = useMenu()
const { selectedMenu, setSelectedMenu } = useCanvasMenu()
const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState)
const subMenus = useRecoilValue(subMenusState)
const onClickMenu = ({ id, menu }) => {
if (menu === currentMenu) {
handleMenu(type)
handleMenu(selectedMenu)
} else {
setCurrentMenu(menu)
}
}
useEffect(() => {
handleMenu(type)
handleMenu(selectedMenu)
canvas?.discardActiveObject()
}, [currentMenu])
return (
<div className="canvas-depth2-inner">
<ul className="canvas-depth2-list">
{subMenus[type]?.map((menu) => {
{subMenus[selectedMenu]?.map((menu) => {
return (
<li key={menu.id} className={`canvas-depth2-item ${menu.menu === currentMenu ? 'active' : ''}`}>
<button onClick={() => onClickMenu(menu)}>{getMessage(menu.name)}</button>

View File

@ -12,6 +12,10 @@ import { useCanvas } from '@/hooks/useCanvas'
import { useImgLoader } from '@/hooks/floorPlan/useImgLoader'
// import { initImageLoaderPopup } from '@/lib/planAction'
/**
* 이미지 로드 모달
* @returns
*/
export default function ImgLoad() {
const { currentCanvasPlan, setCurrentCanvasPlan } = usePlan()
const { getMessage } = useMessage()
@ -72,97 +76,88 @@ export default function ImgLoad() {
}, [currentCanvasPlan])
return (
<WithDraggable isShow={floorPlanState.refFileModalOpen} pos={{ x: 1000, y: 200 }}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('common.input.file')}</h1>
<button
className="modal-close"
onClick={() => {
setFloorPlanState({ ...floorPlanState, refFileModalOpen: false })
}}
>
닫기
</button>
<WithDraggable isShow={floorPlanState.refFileModalOpen} pos={{ x: 1000, y: 200 }} className="r">
<WithDraggable.Header
title={getMessage('common.input.file')}
onClose={() => setFloorPlanState({ ...floorPlanState, refFileModalOpen: false })}
/>
<WithDraggable.Body>
<div className="img-flex-box">
<span className="normal-font mr10">{getMessage('modal.image.load.size.rotate')}</span>
<label className="toggle-btn">
<input
type="checkbox"
checked={floorPlanState.toggleRotate}
onChange={(e) => setFloorPlanState({ ...floorPlanState, toggleRotate: e.target.checked })}
/>
<span className="slider"></span>
</label>
</div>
<div className="modal-body">
<div className="img-flex-box">
<span className="normal-font mr10">{getMessage('modal.image.load.size.rotate')}</span>
<label className="toggle-btn">
<input
type="checkbox"
checked={floorPlanState.toggleRotate}
onChange={(e) => setFloorPlanState({ ...floorPlanState, toggleRotate: e.target.checked })}
/>
<span className="slider"></span>
</label>
</div>
<div className="img-load-from">
<div className="img-load-item">
<div className="d-check-radio pop">
<input type="radio" name="radio03" id="ra06" value={'1'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '1'} />
<label htmlFor="ra06">{getMessage('common.input.file')}</label>
</div>
<div className="img-flex-box">
<div className="img-edit-wrap">
<label className="img-edit-btn" htmlFor="img_file">
<span className="img-edit"></span>
{getMessage('common.load')}
</label>
<input
type="file"
id="img_file"
style={{ display: 'none' }}
onChange={refFileMethod === '1' ? (e) => handleRefFile(e.target.files[0]) : () => {}}
/>
</div>
<div className="img-name-wrap">
<input
type="text"
className="input-origin al-l"
value={refImage ? (refImage?.name ?? '') : (currentCanvasPlan?.bgImageName ?? '')}
readOnly
/>
{refImage && <button className="img-check" onClick={handleFileDelete}></button>}
</div>
</div>
<div className="img-load-from">
<div className="img-load-item">
<div className="d-check-radio pop">
<input type="radio" name="radio03" id="ra06" value={'1'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '1'} />
<label htmlFor="ra06">{getMessage('common.input.file')}</label>
</div>
<div className="img-load-item">
<div className="d-check-radio pop">
<input type="radio" name="radio03" id="ra07" value={'2'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '2'} />
<label htmlFor="ra07">{getMessage('common.input.address.load')}</label>
<div className="img-flex-box">
<div className="img-edit-wrap">
<label className="img-edit-btn" htmlFor="img_file">
<span className="img-edit"></span>
{getMessage('common.load')}
</label>
<input
type="file"
id="img_file"
style={{ display: 'none' }}
onChange={refFileMethod === '1' ? (e) => handleRefFile(e.target.files[0]) : () => {}}
/>
</div>
<div className="img-flex-box for-address">
<div className="img-name-wrap">
<input
type="text"
ref={queryRef}
className="input-origin al-l mr10"
placeholder={'住所入力'}
value={mapPositionAddress}
onChange={(e) => setMapPositionAddress(e.target.value)}
className="input-origin al-l"
value={refImage ? (refImage?.name ?? '') : (currentCanvasPlan?.bgImageName ?? '')}
readOnly
/>
<div className="img-edit-wrap">
<button
className={`img-edit-btn ${mapPositionAddress.trim().length === 0 ? 'no-click' : ''}`}
onClick={refFileMethod === '2' ? handleMapImageDown : () => {}}
>
{getMessage('common.finish')}
</button>
</div>
{mapPositionAddress && <button className="check-address fail" onClick={handleAddressDelete}></button>}
{/* <span className="check-address success"></span> */}
{refImage && <button className="img-check" onClick={handleFileDelete}></button>}
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleModal}>
{getMessage('common.finish')}
</button>
{/* <button className="btn-frame modal act" onClick={() => handleCanvasToPng(2)}></button> */}
<div className="img-load-item">
<div className="d-check-radio pop">
<input type="radio" name="radio03" id="ra07" value={'2'} onChange={(e) => handleRefFileMethod(e)} checked={refFileMethod === '2'} />
<label htmlFor="ra07">{getMessage('common.input.address.load')}</label>
</div>
<div className="img-flex-box for-address">
<input
type="text"
ref={queryRef}
className="input-origin al-l mr10"
placeholder={'住所入力'}
value={mapPositionAddress}
onChange={(e) => setMapPositionAddress(e.target.value)}
/>
<div className="img-edit-wrap">
<button
className={`img-edit-btn ${mapPositionAddress.trim().length === 0 ? 'no-click' : ''}`}
onClick={refFileMethod === '2' ? handleMapImageDown : () => {}}
>
{getMessage('common.finish')}
</button>
</div>
{mapPositionAddress && <button className="check-address fail" onClick={handleAddressDelete}></button>}
{/* <span className="check-address success"></span> */}
</div>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleModal}>
{getMessage('common.finish')}
</button>
{/* <button className="btn-frame modal act" onClick={() => handleCanvasToPng(2)}></button> */}
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -13,40 +13,32 @@ export default function Slope({ id, pos = { x: 50, y: 230 } }) {
const inputRef = useRef()
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.slope.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="xxxm">
<WithDraggable.Header title={getMessage('plan.menu.placement.surface.slope.setting')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="slope-wrap">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('slope')}
</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={globalPitch} ref={inputRef} />
</div>
<span className="thin">{pitchText}</span>
</div>
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
setGlobalPitch(inputRef.current.value)
closePopup(id)
}}
>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('slope')}
</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" defaultValue={globalPitch} ref={inputRef} />
</div>
<span className="thin">{pitchText}</span>
</div>
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
setGlobalPitch(inputRef.current.value)
closePopup(id)
}}
>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -124,44 +124,36 @@ export default function AuxiliaryDrawing({ id, pos = { x: 50, y: 230 } }) {
setType(button.type)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.auxiliary.drawing')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.auxiliary.drawing')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
{types.map((type, idx) => (
<button key={idx} className={`btn-frame modal ${buttonAct === type.id ? 'act' : ''}`} onClick={() => onClickButton(type)}>
{type.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{buttonAct === 1 && <OuterLineWall props={outerLineProps} />}
{buttonAct === 2 && <RightAngle props={rightAngleProps} />}
{buttonAct === 3 && <DoublePitch props={doublePitchProps} />}
{buttonAct === 4 && <Angle props={angleProps} />}
{buttonAct === 5 && <Diagonal props={diagonalLineProps} />}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal mr5" onClick={cutAuxiliary}>
{getMessage('contextmenu.auxiliary.cut')}
</button>
<button className="btn-frame modal act" onClick={() => handleFix(id)}>
{getMessage('apply')}
</button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
{types.map((type, idx) => (
<button key={idx} className={`btn-frame modal ${buttonAct === type.id ? 'act' : ''}`} onClick={() => onClickButton(type)}>
{type.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{buttonAct === 1 && <OuterLineWall props={outerLineProps} />}
{buttonAct === 2 && <RightAngle props={rightAngleProps} />}
{buttonAct === 3 && <DoublePitch props={doublePitchProps} />}
{buttonAct === 4 && <Angle props={angleProps} />}
{buttonAct === 5 && <Diagonal props={diagonalLineProps} />}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal mr5" onClick={cutAuxiliary}>
{getMessage('contextmenu.auxiliary.cut')}
</button>
<button className="btn-frame modal act" onClick={() => handleFix(id)}>
{getMessage('apply')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -26,12 +26,12 @@ export default function AuxiliaryEdit(props) {
return
}
if ((verticalSize && +verticalSize === 0) || !arrow1) {
if (verticalSize && +verticalSize !== 0 && !arrow1) {
swalFire({ title: getMessage('length.direction.is.required'), type: 'alert' })
return
}
if ((horizonSize && +horizonSize === 0) || !arrow2) {
if (horizonSize && +horizonSize !== 0 && !arrow2) {
swalFire({ title: getMessage('length.direction.is.required'), type: 'alert' })
return
}
@ -55,75 +55,67 @@ export default function AuxiliaryEdit(props) {
closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage(type === 'copy' ? 'modal.auxiliary.copy' : 'modal.auxiliary.move')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="grid-option-tit">{getMessage(type === 'copy' ? 'modal.auxiliary.copy.info' : 'modal.auxiliary.move.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input type="text" className="input-origin" value={verticalSize} onChange={(e) => setVerticalSize(e.target.value)} />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
onClick={() => {
setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
</div>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage(type === 'copy' ? 'modal.auxiliary.copy' : 'modal.auxiliary.move')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="grid-option-tit">{getMessage(type === 'copy' ? 'modal.auxiliary.copy.info' : 'modal.auxiliary.move.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input type="text" className="input-origin" value={verticalSize} onChange={(e) => setVerticalSize(e.target.value)} />
</div>
<div className="input-move-wrap">
<div className="input-move">
<input type="text" className="input-origin" value={horizonSize} onChange={(e) => setHorizonSize(e.target.value)} />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === '↑' ? 'act' : ''}`}
onClick={() => {
setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
</div>
</div>
<div className="input-move-wrap">
<div className="input-move">
<input type="text" className="input-origin" value={horizonSize} onChange={(e) => setHorizonSize(e.target.value)} />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -111,61 +111,53 @@ export default function AuxiliarySize(props) {
closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.auxiliary.size.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage('modal.auxiliary.size.edit')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="discrimination-box mb10">
<div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra01" onClick={(e) => setCheckedRadio(1)} />
<label htmlFor="ra01">1{getMessage('modal.auxiliary.size.edit.point')}</label>
</div>
<div className="outline-form mb15">
<div className="input-grid mr5" style={{ flex: '1 1 auto' }}>
<input type="text" className="input-origin block" defaultValue={currentObject?.attributes.planeSize} readOnly={true} />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span style={{ width: 'auto' }}>{getMessage('length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={value1} readOnly={checkedRadio !== 1} onChange={handleInput} />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="discrimination-box ">
<div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra02" onClick={(e) => setCheckedRadio(2)} />
<label htmlFor="ra02">2{getMessage('modal.auxiliary.size.edit.point')}</label>
</div>
<div className="outline-form mb15">
<div className="input-grid mr5" style={{ flex: '1 1 auto' }}>
<input type="text" className="input-origin block" defaultValue={currentObject?.attributes.planeSize} readOnly={true} />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span style={{ width: 'auto' }}>{getMessage('length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={value2} readOnly={checkedRadio !== 2} onChange={handleInput} />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="discrimination-box mb10">
<div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra01" onClick={(e) => setCheckedRadio(1)} />
<label htmlFor="ra01">1{getMessage('modal.auxiliary.size.edit.point')}</label>
</div>
<div className="outline-form mb15">
<div className="input-grid mr5" style={{ flex: '1 1 auto' }}>
<input type="text" className="input-origin block" defaultValue={currentObject?.attributes.planeSize} readOnly={true} />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span style={{ width: 'auto' }}>{getMessage('length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={value1} readOnly={checkedRadio !== 1} onChange={handleInput} />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="discrimination-box ">
<div className="d-check-radio pop mb10">
<input type="radio" name="radio01" id="ra02" onClick={(e) => setCheckedRadio(2)} />
<label htmlFor="ra02">2{getMessage('modal.auxiliary.size.edit.point')}</label>
</div>
<div className="outline-form mb15">
<div className="input-grid mr5" style={{ flex: '1 1 auto' }}>
<input type="text" className="input-origin block" defaultValue={currentObject?.attributes.planeSize} readOnly={true} />
</div>
<span className="thin">mm</span>
</div>
<div className="outline-form">
<span style={{ width: 'auto' }}>{getMessage('length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={value2} readOnly={checkedRadio !== 2} onChange={handleInput} />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -6,12 +6,12 @@ import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchMod
import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement'
import Placement from '@/components/floor-plan/modal/basic/step/Placement'
import { useRecoilValue, useRecoilState } from 'recoil'
import { canvasSettingState, canvasState, isManualModuleSetupState } from '@/store/canvasAtom'
import { canvasSettingState, canvasState, checkedModuleState, isManualModuleSetupState } from '@/store/canvasAtom'
import { usePopup } from '@/hooks/usePopup'
import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { useEvent } from '@/hooks/useEvent'
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { addedRoofsState, corridorDimensionSelector, basicSettingState } from '@/store/settingAtom'
import { isObjectNotEmpty } from '@/util/common-utils'
import Swal from 'sweetalert2'
@ -36,10 +36,12 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
const canvas = useRecoilValue(canvasState)
const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState)
const [isClosePopup, setIsClosePopup] = useState({ close: false, id: 0 })
const [checkedModules, setCheckedModules] = useRecoilState(checkedModuleState)
// const { initEvent } = useContext(EventContext)
const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(tabNum)
const { updateObjectDate } = useMasterController()
const handleBtnNextStep = () => {
if (tabNum === 1) {
orientationRef.current.handleNextStep()
@ -70,7 +72,7 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
userId: loginUserState.userId, //
})
} else {
if (!isObjectNotEmpty(moduleSelectionData.flatModule)) {
if (!isObjectNotEmpty(moduleSelectionData.module)) {
Swal.fire({
title: getMessage('module.not.found'),
icon: 'warning',
@ -134,75 +136,71 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) {
}
}, [isManualModuleSetup, isClosePopup])
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lx-2`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.module.circuit.setting.default')}</h1>
<button className="modal-close" onClick={() => handleClosePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<span className={`tab-arr ${tabNum !== 1 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum !== 1 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.setting')}</div>
<span className={`tab-arr ${tabNum === 3 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 3 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.placement')}</div>
</div>
{tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />}
{/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && <Module setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />}
useEffect(() => {
setIsManualModuleSetup(false)
}, [checkedModules])
{/*배치면 초기설정 - 입력방법: 육지붕*/}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && (
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
return (
<WithDraggable isShow={true} pos={pos} className="lx-2">
<WithDraggable.Header title={getMessage('plan.menu.module.circuit.setting.default')} onClose={() => handleClosePopup(id)} />
<WithDraggable.Body>
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<span className={`tab-arr ${tabNum !== 1 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum !== 1 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.setting')}</div>
<span className={`tab-arr ${tabNum === 3 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 3 ? 'act' : ''}`}>{getMessage('modal.module.basic.setting.module.placement')}</div>
</div>
{tabNum === 1 && <Orientation ref={orientationRef} tabNum={tabNum} setTabNum={setTabNum} />}
{/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && <Module setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && <Placement setTabNum={setTabNum} ref={placementRef} />}
{/*배치면 초기설정 - 입력방법: 육지붕*/}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && <PitchModule setTabNum={setTabNum} />}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 3 && (
<PitchPlacement setTabNum={setTabNum} ref={placementFlatRef} />
)}
<div className="grid-btn-wrap">
{tabNum !== 1 && (
<button className="btn-frame modal mr5" onClick={() => setTabNum(tabNum - 1)}>
{getMessage('modal.module.basic.setting.prev')}
</button>
)}
{/*{tabNum !== 3 && <button className="btn-frame modal act mr5">{getMessage('modal.common.save')}</button>}*/}
{tabNum !== 3 && (
<button className="btn-frame modal" onClick={handleBtnNextStep}>
Next
</button>
)}
<div className="grid-btn-wrap">
{tabNum !== 1 && (
<button className="btn-frame modal mr5" onClick={() => setTabNum(tabNum - 1)}>
{getMessage('modal.module.basic.setting.prev')}
</button>
)}
{/*{tabNum !== 3 && <button className="btn-frame modal act mr5">{getMessage('modal.common.save')}</button>}*/}
{tabNum !== 3 && (
<button className="btn-frame modal" onClick={handleBtnNextStep}>
Next
</button>
)}
{tabNum === 3 && (
<>
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && (
<>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
{getMessage('modal.module.basic.setting.auto.placement')}
</button>
</>
)}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && (
<>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>
<button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}>
{getMessage('modal.module.basic.setting.auto.placement')}
</button>
</>
)}
</>
)}
</div>
{tabNum === 3 && (
<>
{basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && (
<>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>
<button className="btn-frame modal act" onClick={() => autoModuleSetup(placementRef)}>
{getMessage('modal.module.basic.setting.auto.placement')}
</button>
</>
)}
{basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && (
<>
<button className={`btn-frame modal mr5 ${isManualModuleSetup ? 'act' : ''}`} onClick={handleManualModuleSetup}>
{getMessage('modal.module.basic.setting.passivity.placement')}
</button>
<button className="btn-frame modal act" onClick={() => autoFlatroofModuleSetup(placementFlatRef)}>
{getMessage('modal.module.basic.setting.auto.placement')}
</button>
</>
)}
</>
)}
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -3,10 +3,13 @@ import { useMessage } from '@/hooks/useMessage'
import { isObjectNotEmpty } from '@/util/common-utils'
import QSelectBox from '@/components/common/select/QSelectBox'
import { useModuleTabContents } from '@/hooks/module/useModuleTabContents'
import { useRecoilValue } from 'recoil'
import { ANGLE_TYPE, currentAngleTypeSelector } from '@/store/canvasAtom'
export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, roofTab, tempModuleSelectionData, setTempModuleSelectionData }) {
const { getMessage } = useMessage()
const [roofMaterial, setRoofMaterial] = useState(addRoof) //`
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
const {
raftCodes,
@ -45,7 +48,7 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
<div className="module-flex-item">
<div className="module-flex-item-tit">
{getMessage('modal.module.basic.setting.module.roof.material')}{roofMaterial.nameJp}
{addRoof.roofAngleSet === 'slope' ? roofMaterial.pitch : roofMaterial.angle}
{currentAngleType === ANGLE_TYPE.SLOPE ? roofMaterial.pitch : roofMaterial.angle}
{globalPitchText}
</div>
<div className="eaves-keraba-table">

View File

@ -1,7 +1,7 @@
import { forwardRef, useEffect, useState } from 'react'
import { useMessage } from '@/hooks/useMessage'
import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting'
import { checkedModuleState, currentCanvasPlanState } from '@/store/canvasAtom'
import { checkedModuleState, currentCanvasPlanState, isManualModuleSetupState } from '@/store/canvasAtom'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { moduleSelectionDataState, selectedModuleState } from '@/store/selectedModuleOptions'
import { isObjectNotEmpty } from '@/util/common-utils'
@ -23,6 +23,8 @@ const Placement = forwardRef((props, refs) => {
const [isMultiModule, setIsMultiModule] = useState(false)
const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState)
//
useEffect(() => {
if (moduleSelectionData) {
@ -33,6 +35,10 @@ const Placement = forwardRef((props, refs) => {
}
makeModuleInitArea(moduleSelectionData)
}
return () => {
setIsManualModuleSetup(false)
}
}, [])
//
@ -53,7 +59,7 @@ const Placement = forwardRef((props, refs) => {
}
//
if (moduleSelectionData.module.itemList.length > 1) {
if (isObjectNotEmpty(moduleSelectionData.module) && moduleSelectionData.module.itemList.length > 1) {
setIsMultiModule(true)
}
}

View File

@ -47,17 +47,17 @@ export default function PitchModule({}) {
setSelectedModules(option) //
setModuleSelectionData({
...moduleSelectionData,
flatModule: option,
module: option,
})
moduleSelectedDataTrigger({
...moduleSelectionData,
flatModule: option,
module: option,
})
}
useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData.flatModule) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.flatModule)
if (isObjectNotEmpty(moduleSelectionData.module) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.module)
}
}, [moduleList])

View File

@ -69,7 +69,7 @@ const PitchPlacement = forwardRef((props, refs) => {
excretaLine.forEach((line) => {
line.set({
stroke: '#642EFB',
strokeWidth: 5,
strokeWidth: 3,
surfaceId: surface.surfaceId,
name: 'flatExcretaLine',
})
@ -89,10 +89,10 @@ const PitchPlacement = forwardRef((props, refs) => {
}
useEffect(() => {
if (!moduleSelectionData.flatModule) return // null
if (moduleSelectionData && moduleSelectionData.flatModule.itemList.length > 0) {
if (!moduleSelectionData.module) return // null
if (moduleSelectionData && moduleSelectionData.module.itemList.length > 0) {
let initCheckedModule = {}
moduleSelectionData.flatModule.itemList.forEach((obj, index) => {
moduleSelectionData.module.itemList.forEach((obj, index) => {
if (index === 0) {
initCheckedModule = { [obj.itemId]: true }
} else {

View File

@ -1,5 +1,5 @@
import WithDraggable from '@/components/common/draggable/WithDraggable'
import { useState, useEffect, useContext } from 'react'
import { useState, useEffect, useContext, useRef } from 'react'
import PowerConditionalSelect from '@/components/floor-plan/modal/circuitTrestle/step/PowerConditionalSelect'
import StepUp from '@/components/floor-plan/modal/circuitTrestle/step/StepUp'
import { useMessage } from '@/hooks/useMessage'
@ -33,7 +33,7 @@ const ALLOCATION_TYPE = {
export default function CircuitTrestleSetting({ id }) {
const { getMessage } = useMessage()
const { closePopup } = usePopup()
const { apply, setViewCircuitNumberTexts } = useTrestle()
const { apply, setViewCircuitNumberTexts, getEstimateData, clear: clearTrestle, setAllModuleSurfaceIsComplete } = useTrestle()
const { swalFire } = useSwal()
const { saveEstimate } = useEstimate()
const canvas = useRecoilValue(canvasState)
@ -43,7 +43,7 @@ export default function CircuitTrestleSetting({ id }) {
const [circuitAllocationType, setCircuitAllocationType] = useState(1)
const { managementState, setManagementState, managementStateLoaded } = useContext(GlobalDataContext)
const selectedModules = useRecoilValue(selectedModuleState)
const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList } = useMasterController()
const { getPcsAutoRecommendList, getPcsVoltageChk, getPcsVoltageStepUpList, getPcsManualConfChk } = useMasterController()
// ()
const [selectedStepUpValues, setSelectedStepUpValues] = useState({})
@ -51,12 +51,12 @@ export default function CircuitTrestleSetting({ id }) {
// const { trigger: setCircuitData } = useCanvasPopupStatusController(4)
// const [stepUpListData, setStepUpListData] = useRecoilState(stepUpListDataState)
const [stepUpListData, setStepUpListData] = useState([])
const [seletedOption, setSeletedOption] = useState(null)
const [seletedMainOption, setSeletedMainOption] = useState(null)
const [seletedSubOption, setSeletedSubOption] = useState(null)
const { setModuleStatisticsData } = useCircuitTrestle()
const { handleCanvasToPng } = useImgLoader()
const { saveCanvas } = usePlan()
const passivityCircuitAllocationRef = useRef()
const { setIsGlobalLoading } = useContext(QcastContext)
const {
@ -79,6 +79,7 @@ export default function CircuitTrestleSetting({ id }) {
getRoofSurfaceList,
getModuleList,
removeNotAllocationModules,
resetCircuits,
} = useCircuitTrestle()
// const { trigger: moduleSelectedDataTrigger } = useCanvasPopupStatusController(2)
useEffect(() => {
@ -93,6 +94,13 @@ export default function CircuitTrestleSetting({ id }) {
// selectedModels,
// pcsCheck,
// })
return () => {
const moduleSetupSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
if (moduleSetupSurfaces.some((surface) => !surface.isComplete)) {
resetCircuits()
}
}
}, [])
//
@ -331,6 +339,8 @@ export default function CircuitTrestleSetting({ id }) {
// ()
const onApply = async () => {
setAllModuleSurfaceIsComplete(false)
setIsGlobalLoading(true)
canvas
.getObjects()
@ -343,19 +353,29 @@ export default function CircuitTrestleSetting({ id }) {
handleCanvasToPng(1)
//
const result = await apply()
// result=null
setViewCircuitNumberTexts(true)
//
//
// apply()
// apply() null
const applyResult = apply()
if (!applyResult) {
setIsGlobalLoading(false)
return
}
const result = await getEstimateData()
if (result) {
handleCanvasToPng(2)
//
await saveCanvas(false)
//
await saveEstimate(result)
} else {
setIsGlobalLoading(false)
}
// removeNotAllocationModules()
}
@ -374,6 +394,12 @@ export default function CircuitTrestleSetting({ id }) {
obj.pcsItemId = null
obj.circuitNumber = null
})
setSelectedModels(
JSON.parse(JSON.stringify(selectedModels)).map((model) => {
model.isUsed = false
return model
}),
)
if (allocationType === ALLOCATION_TYPE.PASSIVITY) {
setAllocationType(ALLOCATION_TYPE.AUTO)
@ -381,6 +407,7 @@ export default function CircuitTrestleSetting({ id }) {
} else {
setTabNum(1)
}
clearTrestle()
canvas.renderAll()
setModuleStatisticsData()
@ -427,6 +454,7 @@ export default function CircuitTrestleSetting({ id }) {
allocationType,
circuitAllocationType,
setCircuitAllocationType,
selectedMaker,
selectedModels,
setSelectedModels,
getSelectedPcsItemList,
@ -437,23 +465,27 @@ export default function CircuitTrestleSetting({ id }) {
onValuesSelected: handleStepUpValuesSelected, //
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
seletedMainOption,
setSeletedMainOption,
seletedSubOption,
setSeletedSubOption,
getModuleList,
setModuleStatisticsData,
}
//
const getStepUpListData = () => {
return stepUpListData[0].pcsItemList.map((item) => {
const pcs = []
console.log(stepUpListData)
stepUpListData[0].pcsItemList.map((item, index) => {
return item.serQtyList
.filter((serQty) => serQty.selected)
.map((serQty) => {
return {
.forEach((serQty) => {
pcs.push({
pcsMkrCd: item.pcsMkrCd,
pcsSerCd: item.pcsSerCd,
pcsItemId: item.itemId,
pscOptCd: seletedOption.code,
pscOptCd: getPcsOptCd(index),
paralQty: serQty.paralQty,
connections: item.connList?.length
? [
@ -462,97 +494,219 @@ export default function CircuitTrestleSetting({ id }) {
},
]
: [],
}
})[0]
})
// return {
// pcsMkrCd: item.pcsMkrCd,
// pcsSerCd: item.pcsSerCd,
// pcsItemId: item.itemId,
// pscOptCd: getPcsOptCd(index),
// paralQty: serQty.paralQty,
// connections: item.connList?.length
// ? [
// {
// connItemId: item.connList[0].itemId,
// },
// ]
// : [],
// }
})
})
return pcs
}
const getPcsOptCd = (index) => {
console.log(selectedModels)
console.log(seletedMainOption)
console.log(seletedSubOption)
if (selectedModels.some((model) => model.pcsSerParallelYn === 'Y')) {
if (selectedModels.length > 1) {
if (index === 0) {
return seletedMainOption.code
} else {
return seletedSubOption.code
}
} else {
return seletedMainOption.code
}
} else {
return seletedMainOption.code
}
}
const handleStepUp = () => {
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) {
swalFire({
title: getMessage('not.allocation.exist.module'),
type: 'alert',
})
return
}
setTabNum(2)
handlePassivityAllocationCkeck()
// const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
// if (notAllocationModules.length > 0) {
// swalFire({
// title: getMessage('not.allocation.exist.module'),
// type: 'alert',
// })
// return
// } else {
// passivityCircuitAllocationRef.current.onApply()
// setTabNum(2)
// }
}
//
const handleClose = () => {
// //
// const circuitTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
// canvas.remove(...circuitTexts)
// //
// canvas
// .getObjects()
// .filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// .forEach((obj) => {
// obj.circuit = null
// obj.pcsItemId = null
// obj.circuitNumber = null
// })
if (
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
.some((surface) => !surface.isComplete)
) {
canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'circuitNumber'))
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
obj.circuitNumber = null
})
canvas.renderAll()
}
// canvas.renderAll()
closePopup(id)
}
const handlePassivityAllocationCkeck = () => {
let pcsCount = {}
let result = {}
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
if (notAllocationModules.length > 0) {
swalFire({
text: getMessage('not.allocation.exist.module'),
type: 'alert',
icon: 'warning',
})
return
}
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((module) => {
const circuitNumber = module.circuitNumber.replace(/[()]/g, '')
pcsCount[circuitNumber] = (pcsCount[circuitNumber] || 0) + 1
})
for (const key in pcsCount) {
const firstPart = key.split('-')[0] // '-'
const value = pcsCount[key]
//
if (!result[firstPart]) {
result[firstPart] = { maxValue: value, count: 1 }
} else {
// , count
result[firstPart].maxValue = Math.max(result[firstPart].maxValue, value)
result[firstPart].count += 1
}
}
const params = {
...getOptYn(),
useModuleItemList: getUseModuleItemList(),
roofSurfaceList: getRoofSurfaceList(),
pcsItemList: selectedModels.map((model, index) => {
return {
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
itemId: model.itemId,
itemNm: model.itemNm,
goodsNo: model.goodsNo,
serQtyList: [
{
serQty: result[(index + 1).toString()] ? result[(index + 1).toString()].maxValue : 0,
paralQty: result[(index + 1).toString()] ? result[(index + 1).toString()].count : 0,
rmdYn: 'Y',
usePossYn: 'Y',
roofSurfaceList: canvas
.getObjects()
.filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0)
.map((surface) => {
return {
roofSurfaceId: surface.id,
roofSurface: surface.direction,
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
moduleList: surface.modules.map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber,
pcsItemId: module.pcsItemId,
}
}),
}
}),
},
],
}
}),
}
getPcsManualConfChk(params).then((res) => {
if (res?.resultCode === 'E') {
swalFire({
text: res.resultMsg,
type: 'alert',
icon: 'warning',
})
return
} else {
setTabNum(2)
}
})
}
return (
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
<div className={`modal-pop-wrap l-2`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.circuit.trestle.setting')} </h1>
{/* <button className="modal-close" onClick={() => closePopup(id)}> */}
<button className="modal-close" onClick={handleClose}>
닫기
</button>
</div>
<div className="modal-body">
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.circuit.trestle.setting.power.conditional.select')}</div>
<span className={`tab-arr ${tabNum === 2 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 2 ? 'act' : ''}`}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</div>
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }} className="l-2">
<WithDraggable.Header title={getMessage('modal.circuit.trestle.setting')} onClose={() => handleClose()} />
<WithDraggable.Body>
<div className="roof-module-tab">
<div className={`module-tab-bx act`}>{getMessage('modal.circuit.trestle.setting.power.conditional.select')}</div>
<span className={`tab-arr ${tabNum === 2 ? 'act' : ''}`}></span>
<div className={`module-tab-bx ${tabNum === 2 ? 'act' : ''}`}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</div>
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && <PassivityCircuitAllocation {...passivityProps} />}
{tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5 act" onClick={() => onAutoRecommend()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className="btn-frame modal act" onClick={() => onPassivityAllocation()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div>
)}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5 " onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')}
</button>
<button className="btn-frame modal act" onClick={() => handleStepUp()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</button>
</div>
)}
{tabNum === 2 && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')}
</button>
{/* <button className="btn-frame modal act" onClick={() => apply()}> */}
<button className="btn-frame modal act" onClick={onApply}>
{getMessage('modal.common.save')}({getMessage('modal.circuit.trestle.setting.circuit.allocation')})
</button>
</div>
)}
</div>
<div className="modal-foot modal-handle"></div>
</div>
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && <PowerConditionalSelect {...powerConditionalSelectProps} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && (
<PassivityCircuitAllocation {...passivityProps} ref={passivityCircuitAllocationRef} />
)}
{tabNum === 2 && <StepUp {...stepUpProps} onInitialize={handleStepUpInitialize} />}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.AUTO && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5 act" onClick={() => onAutoRecommend()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className="btn-frame modal act" onClick={() => onPassivityAllocation()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div>
)}
{tabNum === 1 && allocationType === ALLOCATION_TYPE.PASSIVITY && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5 " onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')}
</button>
<button className="btn-frame modal act" onClick={() => handleStepUp()}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation')}({getMessage('modal.circuit.trestle.setting.step.up.allocation')})
</button>
</div>
)}
{tabNum === 2 && (
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => onClickPrev()}>
{getMessage('modal.common.prev')}
</button>
{/* <button className="btn-frame modal act" onClick={() => apply()}> */}
<button className="btn-frame modal act" onClick={onApply}>
{getMessage('modal.common.save')}({getMessage('modal.circuit.trestle.setting.circuit.allocation')})
</button>
</div>
)}
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -13,6 +13,12 @@ import { useRecoilState } from 'recoil'
import { useRecoilValue } from 'recoil'
import { v4 as uuidv4 } from 'uuid'
export const PCS_MKR_MULTI_TYPE = {
MULTI: 'MULTI',
SINGLE_P: 'SINGLE-P',
SINGLE_N: 'SINGLE-N',
}
export default function PowerConditionalSelect(props) {
let {
tabNum,
@ -75,18 +81,26 @@ export default function PowerConditionalSelect(props) {
const onCheckSeries = (data) => {
let copySeries = []
if (data.pcsMkrMultiType === 'MULTI') {
if (data.pcsMkrMultiType === PCS_MKR_MULTI_TYPE.MULTI) {
copySeries = series.map((s) => {
return {
...s,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.selected,
}
})
} else if (data.pcsMkrMultiType === 'SINGLE-P') {
} else if (data.pcsMkrMultiType === PCS_MKR_MULTI_TYPE.SINGLE_P) {
if (series.filter((s) => s.selected).length === 0 && data.pcsSerParallelYn === 'Y') {
swalFire({
title: getMessage('modal.module.pcs.error1'),
icon: 'warning',
})
return
}
copySeries = series.map((s) => {
return {
...s,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : s.pcsMkrMultiType === 'MULTI' ? s.selected : false,
selected: s.pcsSerCd === data.pcsSerCd ? !s.selected : data.pcsSerParallelYn === 'Y' ? s.selected : false,
}
})
} else {
@ -107,7 +121,6 @@ export default function PowerConditionalSelect(props) {
setSelectedModels([])
return
}
console.log('moduleSelectionData', moduleSelectionData)
const pcsMkrCd = selectedSeries[0]?.pcsMkrCd
const pcsSerList = selectedSeries.map((series) => {
return { pcsSerCd: series.pcsSerCd }
@ -147,15 +160,34 @@ export default function PowerConditionalSelect(props) {
return
}
if (selectedMaker.pcsMkrMultiType === 'MULTI') {
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4(), isUsed: false }])
if (selectedModels.find((m) => m.pcsSerParallelYn === 'Y') && selectedRow.pcsSerParallelYn === 'Y') {
return
}
if (selectedRow.pcsSerParallelYn === 'Y' && selectedModels.length === 0 && selectedMaker.pcsMkrMultiType === PCS_MKR_MULTI_TYPE.SINGLE_P) {
swalFire({
title: getMessage('modal.module.pcs.error1'),
icon: 'warning',
})
return
}
if (selectedMaker.pcsMkrMultiType === PCS_MKR_MULTI_TYPE.MULTI) {
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4() }])
} else if (!selectedModels.find((m) => m.itemId === selectedRow.itemId)) {
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4(), isUsed: false }])
setSelectedModels([...selectedModels, { ...selectedRow, id: uuidv4() }])
}
setSelectedRow(null)
}
const onRemoveSelectedModel = (model) => {
const tempModels = selectedModels.filter((m) => m.id !== model.id)
if (tempModels.length === 1 && tempModels[0].pcsSerParallelYn === 'Y') {
setSelectedModels([])
return
}
setSelectedModels(selectedModels.filter((m) => m.id !== model.id))
}
@ -264,14 +296,6 @@ export default function PowerConditionalSelect(props) {
</label>
</div>
</div>
{/* <div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={() => setTabNum(2)}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.auto')}
</button>
<button className="btn-frame modal act" onClick={() => setTabNum(tabNum + 1)}>
{getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity')}
</button>
</div> */}
</>
)
}

View File

@ -15,6 +15,7 @@ import { POLYGON_TYPE } from '@/common/common'
import { useSwal } from '@/hooks/useSwal'
import { circuitNumDisplaySelector } from '@/store/settingAtom'
import { fontSelector } from '@/store/fontAtom'
import { PCS_MKR_MULTI_TYPE } from './PowerConditionalSelect'
export default function StepUp(props) {
const {
@ -22,8 +23,11 @@ export default function StepUp(props) {
allocationType,
stepUpListData,
setStepUpListData,
seletedOption,
setSeletedOption,
seletedMainOption,
setSeletedMainOption,
seletedSubOption,
setSeletedSubOption,
selectedMaker,
selectedModels,
setSelectedModels,
getSelectedPcsItemList,
@ -42,23 +46,18 @@ export default function StepUp(props) {
const canvas = useRecoilValue(canvasState)
const selectedModules = useRecoilValue(selectedModuleState)
const [optCodes, setOptCodes] = useState([])
const [mainOptions, setMainOptions] = useState([])
const [subOptions, setSubOptions] = useState([])
const [selectedRows, setSelectedRows] = useState({})
const [isManualSelection, setIsManualSelection] = useState({})
//
const [selectedValues, setSelectedValues] = useState({})
const isDisplayCircuitNumber = useRecoilValue(circuitNumDisplaySelector)
const circuitNumberText = useRecoilValue(fontSelector('circuitNumberText'))
// useCanvasPopupStatusController(6)
// const canvasPopupStatusState = useRecoilValue(canvasPopupStatusStore)
// if (Object.keys(canvasPopupStatusState[6]).length !== 0) {
// console.log('🚀 ~ useEffect ~ canvasPopupStatusState :', canvasPopupStatusState)
// }
useEffect(() => {
if (allocationType === 'auto') {
//
/** 자동일 때 모듈의 회로 정보 초기화 */
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
@ -70,79 +69,103 @@ export default function StepUp(props) {
canvas.renderAll()
// PCS
/** PCS 자동 승압설정 정보 조회 */
fetchAutoStepUpData()
} else {
// PCS
/** PCS 수동 승압설정 정보 조회 */
fetchPassiStepUpData()
}
}, [])
// PCS
/**
* PCS 자동 승압설정 정보 조회
*/
const isMultiOptions = () => {
return selectedModels.some((model) => model.pcsSerParallelYn === 'Y')
}
const fetchAutoStepUpData = async () => {
try {
const params = {
...props.getOptYn(), // Y/N
useModuleItemList: props.getUseModuleItemList(), // List
roofSurfaceList: props.getRoofSurfaceList(), //
pcsItemList: props.getSelectedPcsItemList(), // PCS
...props.getOptYn() /** 옵션 Y/N */,
useModuleItemList: props.getUseModuleItemList() /** 사용된 모듈아이템 List */,
roofSurfaceList: props.getRoofSurfaceList() /** 지붕면 목록 */,
pcsItemList: props.getSelectedPcsItemList() /** PCS 아이템 목록 */,
}
//
/** 회로 구성 가능 여부 체크 통과 시 승압설정 정보 조회 */
getPcsVoltageStepUpList(params).then((res) => {
if (res?.result.resultCode === 'S' && res?.data) {
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
/** PCS 승압설정 정보 SET */
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
/** PCS 옵션 조회 */
// const formattedOptCodes = formatOptionCodes(res.data.optionList)
// setOptCodes(formattedOptCodes)
// setSeletedOption(formattedOptCodes[0])
//
//stepUpListData[0].pcsItemList.forEach((pcsItem) => {
stepUpListData[0].pcsItemList.forEach((pcsItem) => {
/** 캔버스에 회로 정보 적용 */
// pcs setSubOpsions, setMainOptions
console.log('stepUpListData', stepUpListData)
stepUpListData[0].pcsItemList.forEach((pcsItem, index) => {
const optionList = formatOptionCodes(pcsItem.optionList)
if (isMultiOptions()) {
if (index === 0) {
setMainOptions(optionList)
setSeletedMainOption(optionList[0])
} else {
setSubOptions(optionList)
setSeletedSubOption(optionList[0])
}
} else {
if (index === 0) {
setMainOptions(optionList)
setSeletedMainOption(optionList[0])
}
}
const selectedSerQty = pcsItem.serQtyList.find((serQty) => serQty.selected)
if (selectedSerQty) {
selectedSerQty.roofSurfaceList.forEach((roofSurface) => {
const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0]
const moduleIds = targetSurface.modules.map((module) => module.id)
//
/** 기존 모듈 텍스트 삭제 */
canvas
.getObjects()
.filter((obj) => moduleIds.includes(obj.parentId))
.forEach((text) => canvas.remove(text))
//
/** 새로운 모듈 회로 정보 추가 */
roofSurface.moduleList.forEach((module) => {
const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0]
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
selectable: false,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
const targetModule = canvas.getObjects().find((obj) => obj.id === module.uniqueId)
if (targetModule && module.circuit !== '' && module.circuit) {
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
selectable: false,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
}
})
})
}
@ -152,10 +175,6 @@ export default function StepUp(props) {
setModuleStatisticsData()
} else {
swalFire({ text: getMessage('common.message.send.error') })
// swalFire({
// title: res.result.resultMsg,
// type: 'alert',
// })
}
})
} catch (error) {
@ -163,38 +182,34 @@ export default function StepUp(props) {
}
}
// PCS
/**
* PCS 수동 승압설정 정보 조회
*/
const fetchPassiStepUpData = async () => {
try {
// 1-1 2-2
// canvas
// .getObjects()
// .filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuit)
// .map((module) => module.circuitNumber)
//
/** 모듈 데이터 가져오기 */
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
// PCS
/** PCS별 회로 정보를 저장할 객체 */
const pcsSummary = {}
// PCS
/** 각 모듈을 순회하며 PCS별 회로 정보 수집 */
modules.forEach((module) => {
if (!module.circuit || !module.pcsItemId) return
if (!pcsSummary[module.pcsItemId]) {
pcsSummary[module.pcsItemId] = {
if (!pcsSummary[module.circuit.circuitInfo.id]) {
pcsSummary[module.circuit.circuitInfo.id] = {
circuits: {},
totalModules: 0,
}
}
const circuitNumber = module.circuitNumber
if (!pcsSummary[module.pcsItemId].circuits[circuitNumber]) {
pcsSummary[module.pcsItemId].circuits[circuitNumber] = 0
if (!pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber]) {
pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber] = 0
}
pcsSummary[module.pcsItemId].circuits[circuitNumber]++
pcsSummary[module.pcsItemId].totalModules++
pcsSummary[module.circuit.circuitInfo.id].circuits[circuitNumber]++
pcsSummary[module.circuit.circuitInfo.id].totalModules++
})
const params = {
@ -202,20 +217,35 @@ export default function StepUp(props) {
pcsItemList: getSelectedPcsItemList(),
}
// PCS
/** PCS 접속함 및 옵션 목록 조회 */
getPcsConnOptionItemList(params).then((res) => {
if (res?.result.code === 200 && res?.data) {
// PCS serQtyList
const pcsItemListWithSerQty = res.data.pcsItemList.map((pcsItem) => {
const pcsData = pcsSummary[pcsItem.itemId] || { circuits: {}, totalModules: 0 }
/** PCS 아이템 리스트에 serQtyList 추가 */
const pcsItemListWithSerQty = res.data.pcsItemList.map((pcsItem, index) => {
const pcsData = pcsSummary[selectedModels[index].id] || { circuits: {}, totalModules: 0 }
const circuitCounts = Object.values(pcsData.circuits)
const optionList = formatOptionCodes(pcsItem.optionList)
if (isMultiOptions()) {
if (index === 0) {
setMainOptions(optionList)
setSeletedMainOption(optionList[0])
} else {
setSubOptions(optionList)
setSeletedSubOption(optionList[0])
}
} else {
if (index === 0) {
setMainOptions(optionList)
setSeletedMainOption(optionList[0])
}
}
return {
...pcsItem,
serQtyList: [
{
//
/** 한 회로당 최대 모듈 수 */
serQty: circuitCounts.length > 0 ? Math.max(...circuitCounts) : 0,
//
/** 회로 개수 */
paralQty: Object.keys(pcsData.circuits).length || 0,
rmdYn: 'Y',
usePossYn: 'Y',
@ -225,19 +255,19 @@ export default function StepUp(props) {
}
})
// Update res.data with modified pcsItemList
/** res.data with modified pcsItemList */
res.data.pcsItemList = pcsItemListWithSerQty
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
/** PCS 승압설정 정보 SET */
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
/** PCS 옵션 조회 */
// const formattedOptCodes = formatOptionCodes(res.data.optionList)
// setOptCodes(formattedOptCodes)
// setSeletedOption(formattedOptCodes[0])
}
})
} catch (error) {
@ -245,16 +275,20 @@ export default function StepUp(props) {
}
}
// PCS
/**
* PCS 옵션 조회
*/
const formatOptionCodes = (optionList = []) => {
return optionList?.map((opt) => ({
code: opt.pcsOptCd ? opt.pcsOptCd : '',
name: opt.pcsOptNm ? opt.pcsOptNm : '',
nameJp: opt.pcsOptNmJp ? opt.pcsOptNmJp : '',
code: opt.pcsOptCd ?? '',
name: opt.pcsOptNm ?? '',
nameJp: opt.pcsOptNmJp ?? '',
}))
}
// PCS
/**
* PCS 승압설정 정보 포맷 추천 저장
*/
const formatStepUpListData = (dataArray = []) => {
const formattedData = dataArray?.map((stepUps) => ({
...stepUps,
@ -266,16 +300,20 @@ export default function StepUp(props) {
return formattedData
}
// PCS
/**
* PCS 옵션 포맷
*/
const formatOptionList = (optionList = []) => {
return optionList?.map((option) => ({
pcsOptCd: option.pcsOptCd ? option.pcsOptCd : '',
pcsOptNm: option.pcsOptNm ? option.pcsOptNm : '',
pcsOptNmJp: option.pcsOptNmJp ? option.pcsOptNmJp : '',
pcsOptCd: option.pcsOptCd ?? '',
pcsOptNm: option.pcsOptNm ?? '',
pcsOptNmJp: option.pcsOptNmJp ?? '',
}))
}
// PCS
/**
* PCS 아이템 포맷
*/
const formatPcsItemList = (pcsItemList = []) => {
return pcsItemList?.map((item, index) => ({
goodsNo: item.goodsNo ? item.goodsNo : '',
@ -286,56 +324,68 @@ export default function StepUp(props) {
uniqueIndex: `${item.itemId}_${index}`, // ( PCS )
connList: formatConnList(item.connList),
serQtyList: formatSerQtyList(item.serQtyList),
optionList: item.optionList ?? [],
}))
}
// PCS
/**
* PCS 연결 포맷
*/
const formatConnList = (connList = []) => {
if (!connList) return [] // null
return connList?.map((conn) => ({
connAllowCur: conn.connAllowCur ? conn.connAllowCur : 0,
connMaxParalCnt: conn.connMaxParalCnt ? conn.connMaxParalCnt : 0,
goodsNo: conn.goodsNo ? conn.goodsNo : '',
itemId: conn.itemId ? conn.itemId : '',
itemNm: conn.itemNm ? conn.itemNm : '',
vstuParalCnt: conn.vstuParalCnt ? conn.vstuParalCnt : 0,
connAllowCur: conn.connAllowCur ?? 0,
connMaxParalCnt: conn.connMaxParalCnt ?? 0,
goodsNo: conn.goodsNo ?? '',
itemId: conn.itemId ?? '',
itemNm: conn.itemNm ?? '',
vstuParalCnt: conn.vstuParalCnt ?? 0,
}))
}
// PCS
/**
* PCS 시리즈 포맷
*/
const formatSerQtyList = (serQtyList = []) => {
return serQtyList?.map((qty) => ({
code: uuidv4(),
serQty: qty.serQty ? qty.serQty : 0,
paralQty: qty.paralQty ? qty.paralQty : 0,
rmdYn: qty.rmdYn ? qty.rmdYn : 'N',
usePossYn: qty.usePossYn ? qty.usePossYn : 'Y',
serQty: qty.serQty ?? 0,
paralQty: qty.paralQty ?? 0,
rmdYn: qty.rmdYn ?? 'N',
usePossYn: qty.usePossYn ?? 'Y',
roofSurfaceList: formatRoofSurfaceList(qty.roofSurfaceList),
selected: qty.rmdYn === 'Y',
}))
}
// PCS RoofSurface
/**
* PCS RoofSurface 포맷
*/
const formatRoofSurfaceList = (roofSurfaceList = []) => {
return roofSurfaceList?.map((rsf) => ({
moduleList: formatModuleList(rsf.moduleList),
roofSurface: rsf.roofSurface ? rsf.roofSurface : '',
roofSurfaceId: rsf.roofSurfaceId ? rsf.roofSurfaceId : '',
roofSurfaceIncl: rsf.roofSurfaceIncl ? rsf.roofSurfaceIncl : '',
}))
}
// PCS MatModule
const formatModuleList = (moduleList = []) => {
return moduleList?.map((module) => ({
circuit: module.circuit ? module.circuit : '',
itemId: module.itemId ? module.itemId : '',
pcsItemId: module.pcsItemId ? module.pcsItemId : '',
uniqueId: module.uniqueId ? module.uniqueId : '',
roofSurface: rsf.roofSurface ?? '',
roofSurfaceId: rsf.roofSurfaceId ?? '',
roofSurfaceIncl: rsf.roofSurfaceIncl ? +rsf.roofSurfaceIncl : '',
}))
}
//
/**
* PCS MatModule 포맷
*/
const formatModuleList = (moduleList = []) => {
return moduleList?.map((module) => ({
circuit: module.circuit ?? '',
itemId: module.itemId ?? '',
pcsItemId: module.pcsItemId ?? '',
uniqueId: module.uniqueId ?? '',
}))
}
/**
* 모듈의 탭을 변경하는 함수
*/
const handleTabChange = (goodsNo, idx, tabNumber) => {
setModuleTabs((prev) => ({
...prev,
@ -343,9 +393,11 @@ export default function StepUp(props) {
}))
}
//
/**
* 선택 핸들러 함수 추가
*/
const handleRowClick = (mainIdx, subIdx) => {
//
/** 자동 승압 설정인 경우만 실행 */
if (allocationType !== 'auto') return
let tempStepUpListData = [...stepUpListData]
@ -357,26 +409,24 @@ export default function StepUp(props) {
}
item.selected = index === subIdx
})
//
/** 선택된 행 정보 저장 */
setStepUpListData(tempStepUpListData)
// console.log('🚀 ~ handleRowClick ~ tempStepUpListData:', tempStepUpListData)
// console.log('🚀 ~ handleRowClick ~ selectedData:', selectedData)
// PCS 2 PCS
if (stepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) {
//
/** PCS 2개 이상 또는 첫번째 PCS 선택 시에만 실행 */
if (tempStepUpListData[0].pcsItemList.length > 1 && mainIdx === 0) {
/** 파워컨디셔너 옵션 조회 요청 파라미터 */
const params = {
...props.getOptYn(), // Y/N
useModuleItemList: props.getUseModuleItemList(), // List
roofSurfaceList: props.getRoofSurfaceList(), //
pcsItemList: props.getSelectedPcsItemList().map((pcsItem, index) => {
// PCS
// tempStepUpListData PCS
// uniqueIndex
/** PCS
* tempStepUpListData에서 해당 PCS 아이템 찾기
* uniqueIndex를 사용하여 매칭
*/
const matchingPcsItem = tempStepUpListData[0].pcsItemList.find((item) => item.uniqueIndex === `${pcsItem.itemId}_${index}`)
// serQty
/** 선택된 serQty 찾기 */
const selectedSerQty = matchingPcsItem?.serQtyList.find((serQty) => serQty.selected)?.serQty || 0
return {
@ -386,34 +436,29 @@ export default function StepUp(props) {
}),
}
// PCS 1 2 3 PCS serQty 0 API
/** PCS가 1개 이고 2번째 또는 3번째 PCS serQty가 0인 경우는 추천 API 실행하지 않음 */
if (params.pcsItemList.length !== 1 && (params.pcsItemList[1]?.applySerQty !== 0 || params.pcsItemList[2]?.applySerQty) !== 0) {
// PCS
//const res = await getPcsVoltageStepUpList(params)
//getPcsManualConfChk(params).then((res) => {
/** PCS 승압설정 정보 조회 */
getPcsVoltageStepUpList(params).then((res) => {
if (res?.result.resultCode === 'S' && res?.data) {
const dataArray = Array.isArray(res.data) ? res.data : [res.data]
const stepUpListData = formatStepUpListData(dataArray)
// PCS SET
/** PCS 승압설정 정보 SET */
setStepUpListData(stepUpListData)
// PCS
const formattedOptCodes = formatOptionCodes(res.data.optionList)
setOptCodes(formattedOptCodes)
setSeletedOption(formattedOptCodes[0])
/** PCS 옵션 조회 */
// const formattedOptCodes = formatOptionCodes(res.data.optionList)
// setOptCodes(formattedOptCodes)
// setSeletedOption(formattedOptCodes[0])
} else {
swalFire({ text: getMessage('common.message.send.error') })
// swalFire({
// title: res.result.resultMsg,
// type: 'alert',
// })
}
})
}
}
/** 모듈 목록 삭제 */
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
@ -423,13 +468,14 @@ export default function StepUp(props) {
module.pcsItemId = null
})
/** 선택된 모듈 목록 추가 */
selectedData.roofSurfaceList.forEach((roofSurface) => {
const targetSurface = canvas.getObjects().filter((obj) => obj.id === roofSurface.roofSurfaceId)[0]
const moduleIds = targetSurface.modules.map((module) => {
return module.id
})
//
/** 모듈 목록 삭제 */
canvas
.getObjects()
.filter((obj) => moduleIds.includes(obj.parentId))
@ -437,34 +483,35 @@ export default function StepUp(props) {
canvas.remove(text)
})
//
/** 모듈 목록 추가 */
canvas.renderAll()
roofSurface.moduleList.forEach((module) => {
const targetModule = canvas.getObjects().filter((obj) => obj.id === module.uniqueId)[0]
if (module.circuit === '') return
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
const targetModule = canvas.getObjects().find((obj) => obj.id === module.uniqueId)
if (targetModule && module.circuit !== '' && module.circuit !== null) {
const moduleCircuitText = new fabric.Text(module.circuit, {
left: targetModule.left + targetModule.width / 2,
top: targetModule.top + targetModule.height / 2,
fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value,
width: targetModule.width,
height: targetModule.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
parentId: targetModule.id,
circuitInfo: module.pcsItemId,
visible: isDisplayCircuitNumber,
})
targetModule.circuit = moduleCircuitText
targetModule.pcsItemId = module.pcsItemId
targetModule.circuitNumber = module.circuit
canvas.add(moduleCircuitText)
}
})
})
@ -472,7 +519,9 @@ export default function StepUp(props) {
setModuleStatisticsData()
}
//
/**
* 현재 선택된 값들을 가져오는 함수 추가
*/
const getCurrentSelections = () => {
const selectedValues = stepUpListData[0].pcsItemList.forEach((item) => {
item.serQtyList.filter((serQty) => serQty.selected)
@ -493,20 +542,20 @@ export default function StepUp(props) {
return selectedValues
}
// props getCurrentSelections
/** props로 getCurrentSelections 함수 전달 */
useEffect(() => {
if (props.onInitialize) {
props.onInitialize(getCurrentSelections)
}
}, [])
// stepUpListData useEffect
/** stepUpListData가 변경될 때마다 업데이트하는 useEffect */
useEffect(() => {
if (props.onInitialize) {
// onInitialize props
/** onInitialize를 props에서 가져옴 */
props.onInitialize(() => ({
...getCurrentSelections(),
stepUpListData, // stepUpListData
stepUpListData /** stepUpListData를 포함하여 반환 */,
}))
}
}, [stepUpListData])
@ -515,15 +564,43 @@ export default function StepUp(props) {
<>
<div className="properties-setting-wrap outer">
<div className="circuit-title-sel">
<div className="outline-form">
<p className="circuit-title">{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}</p>
<div className="circuit-sel-wrap">
<div className="grid-select mr10">
{mainOptions.length > 0 && (
<QSelectBox
options={mainOptions}
value={seletedMainOption}
sourceKey="code"
targetKey="code"
showKey="name"
onChange={(e) => setSeletedMainOption(e)}
/>
)}
</div>
{isMultiOptions() && selectedModels.length === 2 && (
<div className="grid-select ">
{subOptions.length > 0 && (
<QSelectBox
options={subOptions}
value={seletedSubOption}
sourceKey="code"
targetKey="code"
showKey="name"
onChange={(e) => setSeletedSubOption(e)}
/>
)}
</div>
)}
</div>
{/* <div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('modal.circuit.trestle.setting.step.up.allocation.select.monitor')}
</span>
{optCodes.length > 0 && (
<div className="grid-select mr10">
{/* <QSelectBox title={'電力検出ユニット (モニター付き)'} /> */}
<QSelectBox
//options={optCodes}
options={optCodes.map((roof) => {
return { ...roof, name: globalLocale === 'ko' ? roof.name : roof.nameJp }
})}
@ -536,7 +613,7 @@ export default function StepUp(props) {
/>
</div>
)}
</div>
</div> */}
</div>
<div className="slope-wrap">
@ -625,8 +702,6 @@ export default function StepUp(props) {
<table>
<thead>
<tr>
{/* <th></th>
<th>昇圧回路数</th> */}
<th>{getMessage('modal.circuit.trestle.setting.power.conditional.select.name')}</th>
<th>{getMessage('modal.circuit.trestle.setting.step.up.allocation.circuit.amount')}</th>
</tr>

View File

@ -15,6 +15,7 @@ import { useRecoilState, useRecoilValue } from 'recoil'
export default function PassivityCircuitAllocation(props) {
const {
setTabNum,
selectedModels,
setSelectedModels,
getOptYn: getApiProps,
@ -88,14 +89,14 @@ export default function PassivityCircuitAllocation(props) {
]
if (!circuitNumber || circuitNumber === 0) {
swalFire({
text: '회로번호를 1 이상입력해주세요.',
text: getMessage('module.circuit.minimun.error'),
type: 'alert',
icon: 'warning',
})
return
} else if (targetModules.length === 0) {
swalFire({
text: '모듈을 선택해주세요.',
text: getMessage('module.not.found'),
type: 'alert',
icon: 'warning',
})
@ -113,7 +114,7 @@ export default function PassivityCircuitAllocation(props) {
})
if (result) {
swalFire({
text: '회로 번호가 같은 다른 파워 컨디셔너 모듈이 있습니다. 다른 회로 번호를 설정하십시오.',
text: getMessage('module.already.exist.error'),
type: 'alert',
icon: 'warning',
})
@ -156,18 +157,10 @@ export default function PassivityCircuitAllocation(props) {
obj.pcsItemCode = selectedPcs.id
obj.circuit = moduleCircuitText
obj.circuitNumber = getCircuitNumber()
tempSelectedPcs.used = true
setSelectedPcs(tempSelectedPcs)
canvas.add(moduleCircuitText)
})
let pcsList = JSON.parse(JSON.stringify(selectedModels)).map((model) => {
if (model.id === selectedPcs.id) {
model.isUsed = true
}
return model
})
const roofSurfaceList = canvas
.getObjects()
.filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0)
@ -175,7 +168,7 @@ export default function PassivityCircuitAllocation(props) {
return {
roofSurfaceId: surface.id,
roofSurface: surface.direction,
roofSurfaceIncl: canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
moduleList: surface.modules.map((module) => {
return {
itemId: module.moduleInfo.itemId,
@ -185,9 +178,248 @@ export default function PassivityCircuitAllocation(props) {
}),
}
})
let pcsCount = {}
let result = {}
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE)
.forEach((module) => {
if (module.circuitNumber) {
const circuitNumber = module.circuitNumber.replace(/[()]/g, '')
pcsCount[circuitNumber] = (pcsCount[circuitNumber] || 0) + 1
}
})
for (const key in pcsCount) {
const firstPart = key.split('-')[0] // '-'
const value = pcsCount[key]
const usedPcses = pcsList.filter((model) => model.isUsed)
const pcsItemList = usedPcses.map((model, index) => {
//
if (!result[firstPart]) {
result[firstPart] = { maxValue: value, count: 1 }
} else {
// , count
result[firstPart].maxValue = Math.max(result[firstPart].maxValue, value)
result[firstPart].count += 1
}
}
const pcsItemList = selectedModels.map((model, index) => {
return {
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
itemId: model.itemId,
itemNm: model.itemNm,
goodsNo: model.goodsNo,
serQtyList: [
{
serQty: result[(index + 1).toString()] ? result[(index + 1).toString()].maxValue : 0,
paralQty: result[(index + 1).toString()] ? result[(index + 1).toString()].count : 0,
rmdYn: 'Y',
usePossYn: 'Y',
roofSurfaceList: roofSurfaceList,
},
],
}
})
const params = {
...getApiProps(),
useModuleItemList: getSelectedModuleList(),
pcsItemList: pcsItemList,
}
getPcsManualConfChk(params).then((res) => {
if (res?.resultCode === 'E') {
swalFire({
text: res.resultMsg,
type: 'alert',
icon: 'warning',
confirmFn: () => {
const circuitNumbers = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber' && targetModules.includes(obj.parentId))
canvas.remove(...circuitNumbers)
canvas
.getObjects()
.filter((obj) => obj.name === 'module' && targetModules.includes(obj.id))
.forEach((obj) => {
obj.pcsItemId = null
obj.circuit = null
obj.circuitNumber = null
})
canvas.renderAll()
},
})
setTargetModules([])
return
}
setTargetModules([])
setCircuitNumber(+circuitNumber + 1)
setModuleStatisticsData()
})
}
const getCircuitNumber = () => {
if (selectedModels.length === 1) {
return `(${circuitNumber})`
} else {
return `(${selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1}-${circuitNumber})`
}
}
const initSelectedPcsCircuitNumber = () => {
swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset.info'),
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id)
if (circuitModules.length === 0) {
return
}
const circuitNumbers = circuitModules.map((obj) => {
const circuitNumber = obj.circuitNumber.replace(/[()]/g, '').split('-')
return parseInt(circuitNumber[circuitNumber.length - 1])
})
const minCircuitNumber = Math.min(...circuitNumbers)
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.circuitNumber = null
obj.pcsItemId = null
})
setCircuitNumber(minCircuitNumber)
setTargetModules([])
canvas.renderAll()
canvas.discardActiveObject()
setModuleStatisticsData()
},
})
}
const initAllPcsCircuitNumber = () => {
canvas.discardActiveObject()
swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info'),
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.circuitNumber = null
obj.pcsItemId = null
})
canvas.renderAll()
setCircuitNumber(1)
setTargetModules([])
setModuleStatisticsData()
},
})
}
const onApply = () => {
let uniqueCircuitNumbers = [
...new Set(
canvas
.getObjects()
.filter((obj) => obj.name === POLYGON_TYPE.MODULE && obj.circuitNumber)
.map((obj) => obj.circuitNumber),
),
]
if (!circuitNumber || circuitNumber === 0) {
swalFire({
text: getMessage('module.circuit.minimun.error'),
type: 'alert',
icon: 'warning',
})
return
} else if (targetModules.length === 0) {
swalFire({
text: getMessage('module.not.found'),
type: 'alert',
icon: 'warning',
})
return
} else if (selectedModels.length > 1) {
let result = false
uniqueCircuitNumbers.forEach((number) => {
if (
number.split('-')[1] === circuitNumber + ')' &&
number.split('-')[0] !== '(' + (selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1)
) {
result = true
}
})
if (result) {
swalFire({
text: getMessage('module.already.exist.error'),
type: 'alert',
icon: 'warning',
})
return
}
}
let tempSelectedPcs = { ...selectedPcs }
canvas.discardActiveObject()
canvas
.getObjects()
.filter((obj) => targetModules.includes(obj.id))
.forEach((obj) => {
if (obj.circuit) {
canvas.remove(obj.circuit)
}
const moduleCircuitText = new fabric.Text(getCircuitNumber(), {
left: obj.left + obj.width / 2,
top: obj.top + obj.height / 2,
fontFamily: circuitNumberText.fontFamily.value,
fontWeight: circuitNumberText.fontWeight.value.toLowerCase().includes('bold') ? 'bold' : 'normal',
fontStyle: circuitNumberText.fontWeight.value.toLowerCase().includes('italic') ? 'italic' : 'normal',
fontSize: circuitNumberText.fontSize.value,
fill: circuitNumberText.fontColor.value,
width: obj.width,
height: obj.height,
textAlign: 'center',
originX: 'center',
originY: 'center',
name: 'circuitNumber',
selectable: false,
parentId: obj.id,
circuitInfo: selectedPcs,
visible: isDisplayCircuitNumber,
})
obj.set({
strokeWidth: 0.3,
})
obj.pcsItemId = selectedPcs.itemId
obj.pcsItemCode = selectedPcs.id
obj.circuit = moduleCircuitText
obj.circuitNumber = getCircuitNumber()
setSelectedPcs(tempSelectedPcs)
canvas.add(moduleCircuitText)
})
const roofSurfaceList = canvas
.getObjects()
.filter((obj) => POLYGON_TYPE.MODULE_SETUP_SURFACE === obj.name && obj?.modules.length > 0)
.map((surface) => {
return {
roofSurfaceId: surface.id,
roofSurface: surface.direction,
roofSurfaceIncl: +canvas.getObjects().filter((obj) => obj.id === surface.parentId)[0].pitch,
moduleList: surface.modules.map((module) => {
return {
itemId: module.moduleInfo.itemId,
circuit: module.circuitNumber,
pcsItemId: module.pcsItemId,
}
}),
}
})
const pcsItemList = selectedModels.map((model, index) => {
return {
pcsMkrCd: model.pcsMkrCd,
pcsSerCd: model.pcsSerCd,
@ -232,73 +464,13 @@ export default function PassivityCircuitAllocation(props) {
canvas.renderAll()
},
})
setSelectedPcs({ ...selectedPcs, used: false })
setTargetModules([])
return
}
setSelectedModels(pcsList)
setTargetModules([])
setCircuitNumber(+circuitNumber + 1)
setModuleStatisticsData()
})
}
const getCircuitNumber = () => {
if (selectedModels.length === 1) {
return `(${circuitNumber})`
} else {
return `(${selectedModels.findIndex((model) => model.id === selectedPcs.id) + 1}-${circuitNumber})`
}
}
const initSelectedPcsCircuitNumber = () => {
swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.selected.power.conditional.reset.info'),
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas.getObjects().filter((obj) => obj.name === 'module' && obj.circuit?.circuitInfo?.id === selectedPcs.id)
const circuitNumbers = circuitModules.map((obj) => {
const circuitNumber = obj.circuitNumber.replace(/[()]/g, '').split('-')
return parseInt(circuitNumber[circuitNumber.length - 1])
})
const minCircuitNumber = Math.min(...circuitNumbers)
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
setCircuitNumber(minCircuitNumber)
setTargetModules([])
canvas.renderAll()
canvas.discardActiveObject()
setModuleStatisticsData()
},
})
}
const initAllPcsCircuitNumber = () => {
canvas.discardActiveObject()
swalFire({
title: getMessage('modal.circuit.trestle.setting.circuit.allocation.passivity.all.power.conditional.reset.info'),
type: 'confirm',
icon: 'warning',
confirmFn: () => {
const circuitModules = canvas
.getObjects()
.filter((obj) => obj.name === 'module' && selectedModels.map((model) => model.id).includes(obj.circuit?.circuitInfo?.id))
canvas.remove(...circuitModules.map((module) => module.circuit))
circuitModules.forEach((obj) => {
obj.circuit = null
obj.pcsItemId = null
})
canvas.renderAll()
setTargetModules([])
setModuleStatisticsData()
},
setTabNum(2)
})
}
@ -326,8 +498,8 @@ export default function PassivityCircuitAllocation(props) {
{header.map((header, i) => (
<td className="al-c" key={'rowcell' + i}>
{typeof row[header.prop] === 'number'
? row[header.prop].toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: row[header.prop]}
? (row[header.prop] ?? 0).toLocaleString('ko-KR', { maximumFractionDigits: 4 })
: (row[header.prop] ?? 0)}
</td>
))}
</tr>

View File

@ -7,6 +7,9 @@ import { contextPopupPositionState } from '@/store/popupAtom'
import QSelectBox from '@/components/common/select/QSelectBox'
import { canvasState, pitchTextSelector } from '@/store/canvasAtom'
import { defaultSlope } from '@/store/commonAtom'
import { re } from 'mathjs'
import { basicSettingState } from '@/store/settingAtom'
import { getChonByDegree, getDegreeByChon } from '@/util/canvas-util'
export default function DimensionLineSetting(props) {
const contextPopupPosition = useRecoilValue(contextPopupPositionState)
@ -18,131 +21,186 @@ export default function DimensionLineSetting(props) {
const SelectOption01 = defaultSlope
const [basicLength, setBasicLength] = useState(0)
const [slopeAble, setSlopeAble] = useState(false)
const basicSetting = useRecoilValue(basicSettingState)
const changeSlopeRef = useRef()
let slopeInput1, slopeInput2
const [options, setOptions] = useState([])
const [changeLength, setChangeLength] = useState(null)
const [selectedSlope1, setSelectedSlope1] = useState(null)
const [selectedSlope2, setSelectedSlope2] = useState(null)
useEffect(() => {
if (canvas) {
const dimensionObject = canvas.getActiveObject()
console.log(dimensionObject)
const id = dimensionObject.groupId
const textObj = dimensionObject._objects.filter((obj) => obj.name === 'dimensionLineText' && obj.id === id)[0]
setBasicLength(parseInt(textObj.text))
const textObj = dimensionObject._objects.filter((obj) => obj.name === 'dimensionLineText' && obj.group.groupId === id)[0]
if (!textObj) return
// setBasicLength(parseInt(textObj.text))
setBasicLength(+dimensionObject.length)
setSelectedSlope1(dimensionObject.angle1)
setSelectedSlope2(dimensionObject.angle2)
setSlopeAble(dimensionObject.slopeAble)
}
if (basicSetting.roofAngleSet === 'slope') {
setOptions(
Array.from({ length: 21 }).map((_, index) => {
return {
name: index * 0.5,
value: index * 0.5,
}
}),
)
} else {
setOptions(
Array.from({ length: 7 }).map((_, index) => {
return {
name: index * 5,
value: index * 5,
}
}),
)
}
return () => {
setBasicLength(0)
}
}, [])
const handleChangeLength = () => {
const changeLength = changeSlopeRef.current
useEffect(() => {
// if (!slopeAble) {
// const dimensionObject = canvas.getActiveObject()
// dimensionObject.set({
// angle1: null,
// angle2: null,
// })
// }
}, [slopeAble])
const handleChangeLength = () => {
if (canvas) {
const dimensionObject = canvas.getActiveObject()
const id = dimensionObject.groupId
const textObj = dimensionObject._objects.filter((obj) => obj.name === 'dimensionLineText' && obj.id === id)[0]
let resultText = changeLength.value > 0 ? changeLength.value : '0'
const textObj = dimensionObject._objects.filter((obj) => obj.name === 'dimensionLineText' && obj.group.groupId === id)[0]
let resultText = +changeLength > 0 ? +changeLength : dimensionObject.length
if (slopeAble) {
if (slopeInput1) {
resultText = calculateLength(basicLength, slopeInput1.angleValue).toFixed(0)
if (slopeInput2) {
const length = calculateLength(basicLength, slopeInput1.angleValue, slopeInput2.angleValue)
resultText = length.toFixed(0)
}
}
resultText = !selectedSlope2
? calculateLength(resultText, selectedSlope1.value).toFixed(0)
: calculateLength(resultText, selectedSlope1.value, selectedSlope2.value).toFixed(0)
}
textObj.set({
text: String(resultText),
})
dimensionObject.set({
length: +changeLength > 0 ? +changeLength : dimensionObject.length,
slopeAble: slopeAble,
angle1: selectedSlope1,
angle2: selectedSlope2,
})
setBasicLength(resultText)
setChangeLength('')
canvas.renderAll()
}
}
const handleSelectbox = (option, params) => {
const index = params.index
if (index === 1) slopeInput1 = option
if (index === 2) slopeInput2 = option
}
function calculateLength(originalLength, angle) {
const angleInRadians = angle * (Math.PI / 180)
const result = Math.sqrt(Math.pow(originalLength * Math.tan(angleInRadians), 2) + Math.pow(originalLength, 2))
return result
}
function calculateLength(originalLength, angle1, angle2) {
const numerator = Math.sqrt(Math.pow(angle1, 2) + 100 + Math.pow((10 * angle1) / angle2, 2)) * originalLength
const denominator = Math.sqrt(Math.pow((10 * angle1) / angle2, 2) + 100)
const result = numerator / denominator
return result
const calculateLength = (originalLength, angle, angle1) => {
if (!angle1) {
const slope1 = basicSetting.roofAngleSet !== 'slope' ? getDegreeByChon(angle) : angle
const result = Math.sqrt(Math.pow(originalLength * Math.tan((getDegreeByChon(slope1) * Math.PI) / 180), 2) + Math.pow(originalLength, 2))
console.log(result)
return result
} else {
const slope1 = basicSetting.roofAngleSet !== 'slope' ? getChonByDegree(angle) : angle
const slope2 = basicSetting.roofAngleSet !== 'slope' ? getChonByDegree(angle1 ?? 0) : angle1
const numerator = Math.sqrt(Math.pow(slope1, 2) + 100 + Math.pow((10 * slope1) / slope2, 2)) * originalLength
const denominator = Math.sqrt(Math.pow((10 * slope1) / slope2, 2) + 100)
const result = numerator / denominator
return result
}
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('contextmenu.display.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage('contextmenu.display.edit')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="guide">{getMessage('modal.display.edit.info')}</div>
<div className="mb-box">
<div className="slope-wrap">
<div className="outline-form mb15">
<span className="mr10">{getMessage('modal.display.edit.before.length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={basicLength} readOnly />
</div>
</div>
<div className="mb-box">
<div className="outline-form">
<span className="mr10">{getMessage('modal.display.edit.after.length')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin block"
defaultValue={''}
value={changeLength}
onChange={(e) => {
console.log(e.target)
setChangeLength(e.target.value)
}}
/>
</div>
</div>
</div>
<div className="d-check-box pop">
<input type="checkbox" id="ch99" checked={slopeAble} onChange={() => setSlopeAble(!slopeAble)} />
<label htmlFor="ch99">{getMessage('modal.display.edit.input.slope')}</label>
</div>
</div>
</div>
<div className="slope-wrap">
<div className="warning">{getMessage('modal.display.edit.input.slope')}</div>
<div className="display-change-wrap">
<div className="outline-form mb15">
<span className="mr10">{getMessage('slope')}</span>
<div className="grid-select mr10">
<QSelectBox
title={''}
options={options}
disabled={!slopeAble}
value={selectedSlope1}
onChange={(e) => setSelectedSlope1(e)}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
<span className="thin">{pitchText}</span>
</div>
<div className="outline-form">
<span className="mr10">{getMessage('slope')}</span>
<div className="grid-select mr10">
<QSelectBox
title={''}
options={options}
disabled={!slopeAble}
value={selectedSlope2}
onChange={(e) => setSelectedSlope2(e)}
showKey={'name'}
sourceKey={'value'}
targetKey={'value'}
/>
</div>
<span className="thin">{pitchText}</span>
</div>
</div>
<div className="warning">{getMessage('modal.display.edit.input.slope.info')}</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleChangeLength}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="guide">{getMessage('modal.display.edit.info')}</div>
<div className="mb-box">
<div className="slope-wrap">
<div className="outline-form mb15">
<span className="mr10">{getMessage('modal.display.edit.before.length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" value={basicLength} readOnly />
</div>
</div>
<div className="mb-box">
<div className="outline-form">
<span className="mr10">{getMessage('modal.display.edit.after.length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" ref={changeSlopeRef} />
</div>
</div>
</div>
<div className="d-check-box pop">
<input type="checkbox" id="ch99" onChange={() => setSlopeAble(!slopeAble)} />
<label htmlFor="ch99">{getMessage('modal.display.edit.input.slope')}</label>
</div>
</div>
</div>
<div className="slope-wrap">
<div className="warning">{getMessage('modal.display.edit.input.slope')}</div>
<div className="display-change-wrap">
<div className="outline-form mb15">
<span className="mr10">{getMessage('slope')}</span>
<div className="grid-select mr10">
<QSelectBox title={''} options={SelectOption01} disabled={!slopeAble} params={{ index: 1 }} onChange={handleSelectbox} />
</div>
<span className="thin">{pitchText}</span>
</div>
<div className="outline-form">
<span className="mr10">{getMessage('slope')}</span>
<div className="grid-select mr10">
<QSelectBox title={''} options={SelectOption01} disabled={!slopeAble} params={{ index: 2 }} onChange={handleSelectbox} />
</div>
<span className="thin">{pitchText}</span>
</div>
</div>
<div className="warning">{getMessage('modal.display.edit.input.slope.info')}</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleChangeLength}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -16,60 +16,52 @@ export default function Distance(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.distance')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.dual.point')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.diagonal} readOnly />
</div>
<span className="thin">mm</span>
<WithDraggable isShow={true} pos={pos} className="xxxm">
<WithDraggable.Header title={getMessage('modal.distance')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="slope-wrap">
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.dual.point')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.diagonal} readOnly />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.horizon')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.horizon} readOnly />
</div>
<span className="thin">mm</span>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.horizon')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.horizon} readOnly />
</div>
<span className="thin">mm</span>
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.vertical')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.vertical} readOnly />
</div>
<span className="thin">mm</span>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.distance.vertical')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '98px' }}>
<input type="text" className="input-origin block" defaultValue={0} value={distance.vertical} readOnly />
</div>
<span className="thin">mm</span>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleClose}>
{getMessage('common.ok')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleClose}>
{getMessage('common.ok')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -38,32 +38,24 @@ export default function EavesGableEdit({ id, pos = { x: 50, y: 230 } }) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.eaves.gable.edit')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.eaves.gable.edit')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
{buttonMenu.map((item) => (
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
{item.name}
</button>
))}
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
{buttonMenu.map((item) => (
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{type === TYPES.EAVES && <Eaves {...eavesProps} />}
{type === TYPES.GABLE && <Gable {...gableProps} />}
{type === TYPES.WALL_MERGE && <WallMerge {...wallMergeProps} />}
{type === TYPES.SHED && <Shed {...shedProps} />}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
{type === TYPES.EAVES && <Eaves {...eavesProps} />}
{type === TYPES.GABLE && <Gable {...gableProps} />}
{type === TYPES.WALL_MERGE && <WallMerge {...wallMergeProps} />}
{type === TYPES.SHED && <Shed {...shedProps} />}
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -63,121 +63,113 @@ export default function FlowDirectionSetting(props) {
)
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ml mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.shape.flow.direction.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="drawing-flow-wrap">
<div className="discrimination-box">
<div className="discrimination-tit mb15">{getMessage('modal.flow.direction.setting')}</div>
<div className="guide">{getMessage('modal.flow.direction.setting.info')}</div>
<div className="object-direction-wrap">
<div className="plane-direction">
<span className="top">{getMessage('commons.north')}</span>
<button className={`plane-btn up ${flowDirection === 'north' ? 'act' : ''}`} onClick={() => setFlowDirection('north')}></button>
<span className="right">{getMessage('commons.east')}</span>
<button className={`plane-btn right ${flowDirection === 'east' ? 'act' : ''}`} onClick={() => setFlowDirection('east')}></button>
<span className="bottom">{getMessage('commons.south')}</span>
<button className={`plane-btn down ${flowDirection === 'south' ? 'act' : ''}`} onClick={() => setFlowDirection('south')}></button>
<span className="left">{getMessage('commons.west')}</span>
<button className={`plane-btn left ${flowDirection === 'west' ? 'act' : ''}`} onClick={() => setFlowDirection('west')}></button>
</div>
<WithDraggable isShow={true} pos={pos} className="ml">
<WithDraggable.Header title={getMessage('modal.shape.flow.direction.setting')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="drawing-flow-wrap">
<div className="discrimination-box">
<div className="discrimination-tit mb15">{getMessage('modal.flow.direction.setting')}</div>
<div className="guide">{getMessage('modal.flow.direction.setting.info')}</div>
<div className="object-direction-wrap">
<div className="plane-direction">
<span className="top">{getMessage('commons.north')}</span>
<button className={`plane-btn up ${flowDirection === 'north' ? 'act' : ''}`} onClick={() => setFlowDirection('north')}></button>
<span className="right">{getMessage('commons.east')}</span>
<button className={`plane-btn right ${flowDirection === 'east' ? 'act' : ''}`} onClick={() => setFlowDirection('east')}></button>
<span className="bottom">{getMessage('commons.south')}</span>
<button className={`plane-btn down ${flowDirection === 'south' ? 'act' : ''}`} onClick={() => setFlowDirection('south')}></button>
<span className="left">{getMessage('commons.west')}</span>
<button className={`plane-btn left ${flowDirection === 'west' ? 'act' : ''}`} onClick={() => setFlowDirection('west')}></button>
</div>
</div>
<div className="discrimination-box">
<div className="discrimination-tit mb15">{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<div className="guide">{getMessage('modal.shape.flow.direction.setting.orientation.setting.info')}</div>
<div className="mb-box">
<div className="d-check-radio pop mb15">
<input
type="radio"
name="radio01"
id="ra01"
checked={type === FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH}
onChange={(e) => {
setCompasDeg(0)
setType(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH)
}}
/>
<label htmlFor="ra01">{getMessage('modal.shape.flow.direction.setting.orientation.8')}</label>
</div>
<div className="grid-select ">
<QSelectBox
value={selectedOrientation}
options={orientations}
onChange={(e) => {
setType(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH)
setSelectedOrientation(e)
setCompasDeg(e.value)
}}
showKey={'name'}
targetKey={'value'}
sourceKey={'value'}
/>
</div>
</div>
<div className="discrimination-box">
<div className="discrimination-tit mb15">{getMessage('modal.module.basic.setting.orientation.setting')}</div>
<div className="guide">{getMessage('modal.shape.flow.direction.setting.orientation.setting.info')}</div>
<div className="mb-box">
<div className="d-check-radio pop mb15">
<input
type="radio"
name="radio01"
id="ra01"
checked={type === FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH}
onChange={(e) => {
setCompasDeg(0)
setType(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH)
}}
/>
<label htmlFor="ra01">{getMessage('modal.shape.flow.direction.setting.orientation.8')}</label>
</div>
<div className="mb-box">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
value={1}
checked={type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH}
onChange={(e) => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
}}
/>
<label htmlFor="ra02">{getMessage('modal.shape.flow.direction.setting.orientation.24')}</label>
</div>
<div className="grid-select ">
<QSelectBox
value={selectedOrientation}
options={orientations}
onChange={(e) => {
setType(FLOW_DIRECTION_TYPE.EIGHT_AZIMUTH)
setSelectedOrientation(e)
setCompasDeg(e.value)
}}
showKey={'name'}
targetKey={'value'}
sourceKey={'value'}
/>
</div>
<div className="draw-flow-wrap">
<div className="compas-box">
<div className="compas-box-inner">
{Array.from({ length: 180 / 15 + 1 }).map((dot, index) => (
<div
key={index}
className={`circle ${compasDeg === 15 * (12 + index) && type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH ? 'act' : ''}`}
onClick={() => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
setCompasDeg(15 * (12 + index))
}}
></div>
))}
{Array.from({ length: 180 / 15 - 1 }).map((dot, index) => (
<div
key={index}
className={`circle ${compasDeg === 15 * (index + 1) && type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH ? 'act' : ''}`}
onClick={() => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
setCompasDeg(15 * (index + 1))
}}
></div>
))}
<div className="compas">
<div
className="compas-arr"
style={{ transform: `${type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH && `rotate(${compasDeg}deg)`}` }}
></div>
</div>
</div>
<div className="mb-box">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
value={1}
checked={type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH}
onChange={(e) => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
}}
/>
<label htmlFor="ra02">{getMessage('modal.shape.flow.direction.setting.orientation.24')}</label>
</div>
</div>
<div className="draw-flow-wrap">
<div className="compas-box">
<div className="compas-box-inner">
{Array.from({ length: 180 / 15 + 1 }).map((dot, index) => (
<div
key={index}
className={`circle ${compasDeg === 15 * (12 + index) && type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH ? 'act' : ''}`}
onClick={() => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
setCompasDeg(15 * (12 + index))
}}
></div>
))}
{Array.from({ length: 180 / 15 - 1 }).map((dot, index) => (
<div
key={index}
className={`circle ${compasDeg === 15 * (index + 1) && type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH ? 'act' : ''}`}
onClick={() => {
setType(FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH)
setCompasDeg(15 * (index + 1))
}}
></div>
))}
<div className="compas">
<div
className="compas-arr"
style={{ transform: `${type === FLOW_DIRECTION_TYPE.TWENTY_FOUR_AZIMUTH && `rotate(${compasDeg}deg)`}` }}
></div>
</div>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => changeSurfaceFlowDirection(target, flowDirection, compasDeg)}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => changeSurfaceFlowDirection(target, flowDirection, compasDeg)}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -177,123 +177,115 @@ export default function DotLineGrid(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.grid.dot.line.setting')}</h1>
<button
className="modal-close"
onClick={() => {
setIsShow(false)
closePopup(id, isConfig)
}}
>
닫기
<WithDraggable isShow={true} pos={pos} className="ssm">
<WithDraggable.Header
title={getMessage('modal.canvas.setting.grid.dot.line.setting')}
onClose={() => {
setIsShow(false)
closePopup(id, isConfig)
}}
/>
<WithDraggable.Body>
<div className="grid-check-form">
<div className="d-check-box pop">
<input type="checkbox" id="ch01" value={TYPE.DOT} onChange={handleCheckBoxChange} checked={copyCurrentSetting.DOT} />
<label htmlFor="ch01">{getMessage('modal.canvas.setting.grid.dot.line.setting.dot.display')}</label>
</div>
<div className="d-check-box pop">
<input type="checkbox" id="ch02" value={TYPE.LINE} onChange={handleCheckBoxChange} checked={copyCurrentSetting.LINE} />
<label htmlFor="ch02">{getMessage('modal.canvas.setting.grid.dot.line.setting.line.display')}</label>
</div>
</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="d-check-radio pop no-text">
<input
type="radio"
name="radio01"
id="ra01"
value={1}
onChange={handleRadioChange}
checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 1}
readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/>
<label htmlFor="ra01"></label>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.horizon')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`horizontalInterval`}
value={copyCurrentSetting.INTERVAL.horizontalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.vertical')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`verticalInterval`}
value={copyCurrentSetting.INTERVAL.verticalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
</div>
<div className="grid-option-box">
<div className="d-check-radio pop no-text">
<input
type="radio"
name="radio01"
id="ra02"
value={2}
onChange={handleRadioChange}
checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 2}
readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/>
<label htmlFor="ra02"></label>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.ratio')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`ratioInterval`}
value={copyCurrentSetting.INTERVAL.ratioInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
<div className="grid-select">
{selectOption && (
<QSelectBox
options={SelectOptions}
onChange={changeDimension}
value={selectOption}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
)}
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={reset}>
{getMessage('modal.canvas.setting.grid.dot.line.setting.reset')}
</button>
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.canvas.setting.grid.dot.line.setting.save')}
</button>
</div>
<div className="modal-body">
<div className="grid-check-form">
<div className="d-check-box pop">
<input type="checkbox" id="ch01" value={TYPE.DOT} onChange={handleCheckBoxChange} checked={copyCurrentSetting.DOT} />
<label htmlFor="ch01">{getMessage('modal.canvas.setting.grid.dot.line.setting.dot.display')}</label>
</div>
<div className="d-check-box pop">
<input type="checkbox" id="ch02" value={TYPE.LINE} onChange={handleCheckBoxChange} checked={copyCurrentSetting.LINE} />
<label htmlFor="ch02">{getMessage('modal.canvas.setting.grid.dot.line.setting.line.display')}</label>
</div>
</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="d-check-radio pop no-text">
<input
type="radio"
name="radio01"
id="ra01"
value={1}
onChange={handleRadioChange}
checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 1}
readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/>
<label htmlFor="ra01"></label>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.horizon')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`horizontalInterval`}
value={copyCurrentSetting.INTERVAL.horizontalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.vertical')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`verticalInterval`}
value={copyCurrentSetting.INTERVAL.verticalInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
</div>
<div className="grid-option-box">
<div className="d-check-radio pop no-text">
<input
type="radio"
name="radio01"
id="ra02"
value={2}
onChange={handleRadioChange}
checked={(copyCurrentSetting.DOT || copyCurrentSetting.LINE) && copyCurrentSetting.INTERVAL.type === 2}
readOnly={!copyCurrentSetting.DOT && !copyCurrentSetting.LINE}
/>
<label htmlFor="ra02"></label>
</div>
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.canvas.setting.grid.dot.line.setting.ratio')}</span>
<div className="input-grid mr5">
<input
type="text"
className="input-origin"
name={`ratioInterval`}
value={copyCurrentSetting.INTERVAL.ratioInterval}
onChange={(e) => onlyNumberInputChange(e, changeInput)}
/>
</div>
<span>mm</span>
</div>
<div className="grid-select">
{selectOption && (
<QSelectBox
options={SelectOptions}
onChange={changeDimension}
value={selectOption}
showKey={'name'}
targetKey={'id'}
sourceKey={'id'}
/>
)}
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={reset}>
{getMessage('modal.canvas.setting.grid.dot.line.setting.reset')}
</button>
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.canvas.setting.grid.dot.line.setting.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -20,65 +20,57 @@ export default function GridCopy(props) {
copy(currentObject, ['↑', '←'].includes(arrow) ? +length * -1 : +length)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.grid.copy')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="grid-option-tit">{getMessage('modal.grid.copy.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.grid.copy.length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin" value={length} onChange={(e) => setLength(e.target.value)} />
</div>
<span>mm</span>
</div>
<div className="grid-direction">
<button
className={`direction up ${arrow === '↑' ? 'act' : ''} ${currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'vertical') return
setArrow('↑')
}}
></button>
<button
className={`direction down ${arrow === '↓' ? 'act' : ''} ${currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'vertical') return
setArrow('↓')
}}
></button>
<button
className={`direction left ${arrow === '←' ? 'act' : ''} ${currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'horizontal') return
setArrow('←')
}}
></button>
<button
className={`direction right ${arrow === '→' ? 'act' : ''} ${currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'horizontal') return
setArrow('→')
}}
></button>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage('modal.grid.copy')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="grid-option-tit">{getMessage('modal.grid.copy.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="grid-input-form">
<span className="mr10">{getMessage('modal.grid.copy.length')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin" value={length} onChange={(e) => setLength(e.target.value)} />
</div>
<span>mm</span>
</div>
<div className="grid-direction">
<button
className={`direction up ${arrow === '↑' ? 'act' : ''} ${currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'vertical') return
setArrow('↑')
}}
></button>
<button
className={`direction down ${arrow === '↓' ? 'act' : ''} ${currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'vertical') return
setArrow('↓')
}}
></button>
<button
className={`direction left ${arrow === '←' ? 'act' : ''} ${currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'horizontal') return
setArrow('←')
}}
></button>
<button
className={`direction right ${arrow === '→' ? 'act' : ''} ${currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
if (currentObject?.direction === 'horizontal') return
setArrow('→')
}}
></button>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.grid.copy.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.grid.copy.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -73,91 +73,83 @@ export default function GridMove(props) {
closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.grid.move')} </h1>
<button className="modal-close" onClick={handleClose}>
닫기
</button>
</div>
<div className="modal-body">
<div className="grid-option-tit">{getMessage('modal.grid.move.info')}</div>
<div className="grid-option-wrap">
<div className="d-check-box pop mb10">
<input type="checkbox" id="ch99" checked={isAll} onChange={() => setIsAll(!isAll)} />
<label htmlFor="ch99">{getMessage('modal.grid.move.all')}</label>
</div>
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('modal.grid.move.length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input
type="text"
className="input-origin"
value={verticalSize}
onChange={(e) => setVerticalSize(e.target.value)}
readOnly={!isAll && currentObject?.direction === 'vertical'}
/>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === '↑' ? 'act' : ''} ${!isAll && currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''} ${!isAll && currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
</div>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage('modal.grid.move')} onClose={() => handleClose()} />
<WithDraggable.Body>
<div className="grid-option-tit">{getMessage('modal.grid.move.info')}</div>
<div className="grid-option-wrap">
<div className="d-check-box pop mb10">
<input type="checkbox" id="ch99" checked={isAll} onChange={() => setIsAll(!isAll)} />
<label htmlFor="ch99">{getMessage('modal.grid.move.all')}</label>
</div>
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('modal.grid.move.length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input
type="text"
className="input-origin"
value={verticalSize}
onChange={(e) => setVerticalSize(e.target.value)}
readOnly={!isAll && currentObject?.direction === 'vertical'}
/>
</div>
<div className="input-move-wrap">
<div className="input-move">
<input
type="text"
className="input-origin"
value={horizonSize}
onChange={(e) => setHorizonSize(e.target.value)}
readOnly={!isAll && currentObject?.direction === 'horizontal'}
/>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''} ${!isAll && currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''} ${!isAll && currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === '↑' ? 'act' : ''} ${!isAll && currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
setArrow1('↑')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowUp' }))
}}
></button>
<button
className={`direction down ${arrow1 === '↓' ? 'act' : ''} ${!isAll && currentObject?.direction === 'vertical' ? 'no-click' : ''}`}
onClick={() => {
setArrow1('↓')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown' }))
}}
></button>
</div>
</div>
<div className="input-move-wrap">
<div className="input-move">
<input
type="text"
className="input-origin"
value={horizonSize}
onChange={(e) => setHorizonSize(e.target.value)}
readOnly={!isAll && currentObject?.direction === 'horizontal'}
/>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === '←' ? 'act' : ''} ${!isAll && currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
setArrow2('←')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }))
}}
></button>
<button
className={`direction right ${arrow2 === '→' ? 'act' : ''} ${!isAll && currentObject?.direction === 'horizontal' ? 'no-click' : ''}`}
onClick={() => {
setArrow2('→')
document.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowRight' }))
}}
></button>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.grid.move.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.grid.move.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -50,49 +50,41 @@ export default function LinePropertySetting(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('contextmenu.line.property.edit')} </h1>
<button className="modal-close" onClick={() => handleClosePopup()}>
닫기
</button>
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('contextmenu.line.property.edit')} onClose={() => handleClosePopup()} />
<WithDraggable.Body>
<div className="guide">
<span className="mb10">{getMessage('modal.line.property.edit.info')}</span>
<span>
{getMessage('modal.line.property.edit.selected')} [ {selectedProperty?.name} ]
</span>
</div>
<div className="modal-body">
<div className="guide">
<span className="mb10">{getMessage('modal.line.property.edit.info')}</span>
<span>
{getMessage('modal.line.property.edit.selected')} [ {selectedProperty?.name} ]
</span>
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
<div className="outline-wrap">
<div className="radio-grid-wrap">
{properties.map((property, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={'ra' + (index + 1 >= 10 ? index + 1 : `0${index + 1}`)}
onChange={(e) => setSelectedProperty(property)}
/>
<label htmlFor={'ra' + (index + 1 > 10 ? index + 1 : `0${index + 1}`)}>{property.name}</label>
</div>
)
})}
</div>
<div className="properties-setting-wrap outer">
<div className="setting-tit">{getMessage('setting')}</div>
<div className="outline-wrap">
<div className="radio-grid-wrap">
{properties.map((property, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={'ra' + (index + 1 >= 10 ? index + 1 : `0${index + 1}`)}
onChange={(e) => setSelectedProperty(property)}
/>
<label htmlFor={'ra' + (index + 1 > 10 ? index + 1 : `0${index + 1}`)}>{property.name}</label>
</div>
)
})}
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => changeSurfaceLineProperty(selectedProperty, target)}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => changeSurfaceLineProperty(selectedProperty, target)}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -14,36 +14,28 @@ export default function CircuitNumberEdit(props) {
closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title"> {getMessage('modal.module.circuit.number.edit')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="grid-option-tit"> {getMessage('modal.module.circuit.number.edit.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('modal.module.circuit.number')}
</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" />
</div>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={getMessage('modal.module.circuit.number.edit')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="grid-option-tit"> {getMessage('modal.module.circuit.number.edit.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="outline-form">
<span className="mr10" style={{ width: 'auto' }}>
{getMessage('modal.module.circuit.number')}
</span>
<div className="input-grid mr5">
<input type="text" className="input-origin block" />
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -9,7 +9,6 @@ import { deepCopyArray } from '@/util/common-utils'
import { canvasState } from '@/store/canvasAtom'
import * as turf from '@turf/turf'
import { POLYGON_TYPE } from '@/common/common'
import { useModal } from '@nextui-org/react'
import { useModule } from '@/hooks/module/useModule'
import { useSwal } from '@/hooks/useSwal'
@ -34,7 +33,6 @@ export default function PanelEdit(props) {
const canvas = useRecoilValue(canvasState)
const { swalFire } = useSwal()
const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy, moduleMoveAll, moduleCopyAll } = useModule()
useEffect(() => {
if (!canvas) {
const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module') // selectedObj
@ -52,7 +50,6 @@ export default function PanelEdit(props) {
})
return
}
debugger
const completeSurfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.isComplete)
if (completeSurfaces.length > 0) {
@ -94,65 +91,64 @@ export default function PanelEdit(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">
{getMessage([PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting' : 'modal.copy.setting')}{' '}
</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header
title={getMessage(
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting' : 'modal.copy.setting',
)}
onClose={() => closePopup(id)}
/>
<WithDraggable.Body>
<div className="grid-option-tit">
{getMessage(
[PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.MOVE_ALL, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type)
? 'modal.move.setting.info'
: 'modal.copy.setting.info',
)}
</div>
<div className="modal-body">
<div className="grid-option-tit">
{getMessage([PANEL_EDIT_TYPE.MOVE, PANEL_EDIT_TYPE.COLUMN_MOVE].includes(type) ? 'modal.move.setting.info' : 'modal.copy.setting.info')}
</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="grid-input-form">
<span className="mr10">{getMessage('margin')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin" defaultValue={0} onKeyUp={(e) => setLength(e.target.value)} />
</div>
<span>mm</span>
</div>
<div className="grid-direction">
<button
className={`direction up ${direction === 'up' ? 'act' : ''}`}
onClick={() => {
setDirection('up')
}}
></button>
<button
className={`direction down ${direction === 'down' ? 'act' : ''}`}
onClick={() => {
setDirection('down')
}}
></button>
<button
className={`direction left ${direction === 'left' ? 'act' : ''}`}
onClick={() => {
setDirection('left')
}}
></button>
<button
className={`direction right ${direction === 'right' ? 'act' : ''}`}
onClick={() => {
setDirection('right')
}}
></button>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="grid-input-form">
<span className="mr10">{getMessage('margin')}</span>
<div className="input-grid mr5">
<input type="text" className="input-origin" defaultValue={0} onKeyUp={(e) => setLength(e.target.value)} />
</div>
<span>mm</span>
</div>
<div className="grid-direction">
<button
className={`direction up ${direction === 'up' ? 'act' : ''}`}
onClick={() => {
setDirection('up')
}}
></button>
<button
className={`direction down ${direction === 'down' ? 'act' : ''}`}
onClick={() => {
setDirection('down')
}}
></button>
<button
className={`direction left ${direction === 'left' ? 'act' : ''}`}
onClick={() => {
setDirection('left')
}}
></button>
<button
className={`direction right ${direction === 'right' ? 'act' : ''}`}
onClick={() => {
setDirection('right')
}}
></button>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -24,89 +24,69 @@ export default function ColumnInsert(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.panel.column.insert')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.panel.column.insert')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.panel.column.insert.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
onChange={handleRadioChange}
value={MODULE_INSERT_TYPE.LEFT}
checked={selectedType === MODULE_INSERT_TYPE.LEFT}
/>
<label htmlFor="ra01">{getMessage('modal.panel.column.insert.type.left')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
onChange={handleRadioChange}
value={MODULE_INSERT_TYPE.RIGHT}
checked={selectedType === MODULE_INSERT_TYPE.RIGHT}
/>
<label htmlFor="ra02">{getMessage('modal.panel.column.insert.type.right')}</label>
</div>
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_INSERT_TYPE.LEFT && (
<Image src="/static/images/canvas/additional-edit01.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
{selectedType === MODULE_INSERT_TYPE.RIGHT && (
<Image src="/static/images/canvas/additional-edit02.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
</div>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.column')}</span>
</div>
<div className="additional-color-box">
<span className="additional-color white"></span>
<span className="normal-font">{getMessage('modal.panel.insert.column')}</span>
</div>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.panel.column.insert.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
onChange={handleRadioChange}
value={MODULE_INSERT_TYPE.LEFT}
checked={selectedType === MODULE_INSERT_TYPE.LEFT}
/>
<label htmlFor="ra01">{getMessage('modal.panel.column.insert.type.left')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
onChange={handleRadioChange}
value={MODULE_INSERT_TYPE.RIGHT}
checked={selectedType === MODULE_INSERT_TYPE.RIGHT}
/>
<label htmlFor="ra02">{getMessage('modal.panel.column.insert.type.right')}</label>
</div>
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_INSERT_TYPE.LEFT && (
<Image
src="/static/images/canvas/additional-edit01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_INSERT_TYPE.RIGHT && (
<Image
src="/static/images/canvas/additional-edit02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.column')}</span>
</div>
<div className="additional-color-box">
<span className="additional-color white"></span>
<span className="normal-font">{getMessage('modal.panel.insert.column')}</span>
</div>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -21,102 +21,69 @@ export default function ColumnRemove(props) {
{ name: getMessage('modal.panel.column.remove.type.none'), value: MODULE_REMOVE_TYPE.NONE },
]
const handleApply = () => {
// if (apply) apply()
moduleColumnRemove(selectedType)
closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.panel.column.remove')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.panel.column.remove.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={(e) => setSelectedType(e.target.value)}
value={type.value}
checked={selectedType === type.value}
/>
<label htmlFor={`ra0${index + 1}`}>{type.name}</label>
</div>
)
})}
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_REMOVE_TYPE.LEFT && (
<Image
src="/static/images/canvas/additional_del01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.RIGHT && (
<Image
src="/static/images/canvas/additional_del02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE && (
<Image
src="/static/images/canvas/additional_del03.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image
src="/static/images/canvas/additional_del04.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.panel.column.remove')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.panel.column.remove.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={(e) => setSelectedType(e.target.value)}
value={type.value}
checked={selectedType === type.value}
/>
<label htmlFor={`ra0${index + 1}`}>{type.name}</label>
</div>
)
})}
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_REMOVE_TYPE.LEFT && (
<Image src="/static/images/canvas/additional_del01.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
{selectedType === MODULE_REMOVE_TYPE.RIGHT && (
<Image src="/static/images/canvas/additional_del02.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
{selectedType === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE && (
<Image src="/static/images/canvas/additional_del03.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image src="/static/images/canvas/additional_del04.svg" alt="react" width={0} height={0} style={{ width: 'auto', height: 'auto' }} />
)}
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.column')}</span>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.column')}</span>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -24,89 +24,82 @@ export default function RowInsert(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.row.insert')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.row.insert')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.row.insert.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
onChange={HandleRadioChange}
value={MODULE_INSERT_TYPE.TOP}
checked={selectedType === MODULE_INSERT_TYPE.TOP}
/>
<label htmlFor="ra01">{getMessage('modal.row.insert.type.up')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
onChange={HandleRadioChange}
value={MODULE_INSERT_TYPE.BOTTOM}
checked={selectedType === MODULE_INSERT_TYPE.BOTTOM}
/>
<label htmlFor="ra02">{getMessage('modal.row.insert.type.down')}</label>
</div>
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_INSERT_TYPE.TOP && (
<Image
src="/static/images/canvas/additional_bundle-edit01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_INSERT_TYPE.BOTTOM && (
<Image
src="/static/images/canvas/additional_bundle-edit02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.row')}</span>
</div>
<div className="additional-color-box">
<span className="additional-color white"></span>
<span className="normal-font">{getMessage('modal.panel.insert.row')}</span>
</div>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.row.insert.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra01"
onChange={HandleRadioChange}
value={MODULE_INSERT_TYPE.TOP}
checked={selectedType === MODULE_INSERT_TYPE.TOP}
/>
<label htmlFor="ra01">{getMessage('modal.row.insert.type.up')}</label>
</div>
<div className="d-check-radio pop">
<input
type="radio"
name="radio01"
id="ra02"
onChange={HandleRadioChange}
value={MODULE_INSERT_TYPE.BOTTOM}
checked={selectedType === MODULE_INSERT_TYPE.BOTTOM}
/>
<label htmlFor="ra02">{getMessage('modal.row.insert.type.down')}</label>
</div>
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_INSERT_TYPE.TOP && (
<Image
src="/static/images/canvas/additional_bundle-edit01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_INSERT_TYPE.BOTTOM && (
<Image
src="/static/images/canvas/additional_bundle-edit02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.row')}</span>
</div>
<div className="additional-color-box">
<span className="additional-color white"></span>
<span className="normal-font">{getMessage('modal.panel.insert.row')}</span>
</div>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -27,96 +27,88 @@ export default function RowRemove(props) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.row.remove')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.row.remove.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={(e) => setSelectedType(e.target.value)}
value={type.value}
checked={selectedType === type.value}
/>
<label htmlFor={`ra0${index + 1}`}>{type.name}</label>
</div>
)
})}
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_REMOVE_TYPE.TOP && (
<Image
src="/static/images/canvas/additional_bundle-del01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.BOTTOM && (
<Image
src="/static/images/canvas/additional_bundle-del02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.VERTICAL_SIDE && (
<Image
src="/static/images/canvas/additional_bundle-del03.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image
src="/static/images/canvas/additional_bundle-del04.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('modal.row.remove')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('modal.row.remove.info')}</div>
<div className="additional-wrap">
<div className="additional-radio-wrap">
{types.map((type, index) => {
return (
<div className="d-check-radio pop" key={index}>
<input
type="radio"
name="radio01"
id={`ra0${index + 1}`}
onClick={(e) => setSelectedType(e.target.value)}
value={type.value}
checked={selectedType === type.value}
/>
<label htmlFor={`ra0${index + 1}`}>{type.name}</label>
</div>
)
})}
</div>
<div className="additional-img-wrap">
{selectedType === MODULE_REMOVE_TYPE.TOP && (
<Image
src="/static/images/canvas/additional_bundle-del01.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.BOTTOM && (
<Image
src="/static/images/canvas/additional_bundle-del02.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.VERTICAL_SIDE && (
<Image
src="/static/images/canvas/additional_bundle-del03.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
{selectedType === MODULE_REMOVE_TYPE.NONE && (
<Image
src="/static/images/canvas/additional_bundle-del04.svg"
alt="react"
width={0}
height={0}
style={{ width: 'auto', height: 'auto' }}
/>
)}
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.row')}</span>
</div>
</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('legend')}</div>
<div className="module-table-box">
<div className="module-table-inner">
<div className="additional-color-wrap">
<div className="additional-color-box">
<span className="additional-color pink"></span>
<span className="normal-font">{getMessage('modal.panel.select.row')}</span>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleApply}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -16,34 +16,26 @@ export default function MovementSetting({ id, pos = { x: 50, y: 230 } }) {
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap r`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.roof.cover.movement.shape.updown')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="r">
<WithDraggable.Header title={getMessage('plan.menu.roof.cover.movement.shape.updown')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
{buttonType.map((item) => (
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
{type === TYPE.FLOW_LINE && <FlowLine {...flowLineProps} />}
{type === TYPE.UP_DOWN && <Updown {...updownProps} />}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
{buttonType.map((item) => (
<button key={item.id} className={`btn-frame modal ${type === item.type ? 'act' : ''}`} onClick={() => setType(item.type)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
{type === TYPE.FLOW_LINE && <FlowLine {...flowLineProps} />}
{type === TYPE.UP_DOWN && <Updown {...updownProps} />}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleSave}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -32,79 +32,71 @@ export default function DormerOffset(props) {
dormerOffset(arrow1, arrow2, length1, length2)
setArrow1(null)
setArrow2(null)
arrow1LengthRef.current.value = ''
arrow2LengthRef.current.value = ''
// setArrow1(null)
// setArrow2(null)
// arrow1LengthRef.current.value = ''
// arrow2LengthRef.current.value = ''
// closePopup(id)
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{title}</h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="grid-option-tit">{getMessage('modal.dormer.offset.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input type="text" className="input-origin" ref={arrow1LengthRef} placeholder="0" />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === 'up' ? 'act' : ''}`}
onClick={() => {
setArrow1('up')
}}
></button>
<button
className={`direction down ${arrow1 === 'down' ? 'act' : ''}`}
onClick={() => {
setArrow1('down')
}}
></button>
</div>
<WithDraggable isShow={true} pos={pos} className="xm">
<WithDraggable.Header title={title} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="grid-option-tit">{getMessage('modal.dormer.offset.info')}</div>
<div className="grid-option-wrap">
<div className="grid-option-box">
<div className="move-form">
<p className="mb5">{getMessage('length')}</p>
<div className="input-move-wrap mb5">
<div className="input-move">
<input type="text" className="input-origin" ref={arrow1LengthRef} placeholder="0" />
</div>
<div className="input-move-wrap">
<div className="input-move">
<input type="text" className="input-origin" ref={arrow2LengthRef} placeholder="0" />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === 'left' ? 'act' : ''}`}
onClick={() => {
setArrow2('left')
}}
></button>
<button
className={`direction right ${arrow2 === 'right' ? 'act' : ''}`}
onClick={() => {
setArrow2('right')
}}
></button>
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction up ${arrow1 === 'up' ? 'act' : ''}`}
onClick={() => {
setArrow1('up')
}}
></button>
<button
className={`direction down ${arrow1 === 'down' ? 'act' : ''}`}
onClick={() => {
setArrow1('down')
}}
></button>
</div>
</div>
<div className="input-move-wrap">
<div className="input-move">
<input type="text" className="input-origin" ref={arrow2LengthRef} placeholder="0" />
</div>
<span>mm</span>
<div className="direction-move-wrap">
<button
className={`direction left ${arrow2 === 'left' ? 'act' : ''}`}
onClick={() => {
setArrow2('left')
}}
></button>
<button
className={`direction right ${arrow2 === 'right' ? 'act' : ''}`}
onClick={() => {
setArrow2('right')
}}
></button>
</div>
</div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleOffsetDormer}>
{getMessage('modal.common.save')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={handleOffsetDormer}>
{getMessage('modal.common.save')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -24,7 +24,6 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
const { closePopup } = usePopup()
const surfaceShapePolygons = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF)
//
useEffect(() => {
canvas.discardActiveObject()
@ -54,15 +53,41 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
const applyObject = () => {
if (surfaceShapePolygons.length === 0) {
swalFire({ text: '지붕이 없어요 지붕부터 그리세요', icon: 'error' })
swalFire({ text: getMessage('batch.object.outside.roof'), icon: 'error' })
return
}
//,
if (buttonAct === 1 || buttonAct === 2) {
applyOpeningAndShadow(objectPlacement, buttonAct, surfaceShapePolygons)
applyOpeningAndShadow(objectPlacement, buttonAct)
} else {
applyDormers(dormerPlacement, buttonAct, surfaceShapePolygons)
const height = dormerPlacement.heightRef.current !== null ? dormerPlacement.heightRef.current.value / 10 : 0
const width = dormerPlacement.widthRef.current !== null ? dormerPlacement.widthRef.current.value / 10 : 0 //triangle
const pitch = dormerPlacement.pitchRef.current !== null ? Number(dormerPlacement.pitchRef.current.value) : 0
const offsetRef =
dormerPlacement.offsetRef.current !== null
? dormerPlacement.offsetRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetRef.current.value) / 10
: 0
const offsetWidthRef =
dormerPlacement.offsetWidthRef.current !== null
? dormerPlacement.offsetWidthRef.current.value === ''
? 0
: parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
: 0
const directionRef = dormerPlacement.directionRef.current
const dormerParams = {
height: height,
width: width,
pitch: pitch,
offsetRef: offsetRef,
offsetWidthRef: offsetWidthRef,
directionRef: directionRef,
}
applyDormers(dormerParams, buttonAct)
}
setIsHidden(true)
}
@ -75,41 +100,33 @@ export default function ObjectSetting({ id, pos = { x: 50, y: 230 } }) {
]
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap lrr`} style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('plan.menu.placement.surface.object')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="lrr" style={{ visibility: isHidden ? 'hidden' : 'visible' }}>
<WithDraggable.Header title={getMessage('plan.menu.placement.surface.object')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
{buttonMenu.map((item) => (
<button key={item.id} className={`btn-frame modal ${buttonAct === item.id ? 'act' : ''}`} onClick={() => setButtonAct(item.id)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
{buttonAct === 1 && <OpenSpace ref={objectPlacement} />}
{buttonAct === 2 && <Shadow ref={objectPlacement} />}
{buttonAct === 3 && <TriangleDormer ref={dormerPlacement} />}
{buttonAct === 4 && <PentagonDormer ref={dormerPlacement} />}
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
applyObject()
}}
>
{getMessage('write')}
</button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
{buttonMenu.map((item) => (
<button key={item.id} className={`btn-frame modal ${buttonAct === item.id ? 'act' : ''}`} onClick={() => setButtonAct(item.id)}>
{item.name}
</button>
))}
</div>
<div className="properties-setting-wrap outer">
{buttonAct === 1 && <OpenSpace ref={objectPlacement} />}
{buttonAct === 2 && <Shadow ref={objectPlacement} />}
{buttonAct === 3 && <TriangleDormer ref={dormerPlacement} />}
{buttonAct === 4 && <PentagonDormer ref={dormerPlacement} />}
</div>
<div className="grid-btn-wrap">
<button
className="btn-frame modal act"
onClick={() => {
applyObject()
}}
>
{getMessage('write')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -21,26 +21,18 @@ export default function RoofMaterialSetting(props) {
]
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap xxxm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.roof.material.edit')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="grid-select">
<QSelectBox title={'지붕재 선택'} options={roofMaterials} />
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
<WithDraggable isShow={true} pos={pos} className="xxxm">
<WithDraggable.Header title={getMessage('modal.roof.material.edit')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="slope-wrap">
<div className="grid-select">
<QSelectBox title={'지붕재 선택'} options={roofMaterials} />
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act">{getMessage('modal.common.save')}</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -32,71 +32,58 @@ export default function SizeSetting(props) {
const width = widthRef.current.value
const height = heightRef.current.value
if (
target.name === BATCH_TYPE.OPENING ||
target.name === BATCH_TYPE.SHADOW ||
target.name === BATCH_TYPE.TRIANGLE_DORMER ||
target.name === BATCH_TYPE.PENTAGON_DORMER
) {
resizeObjectBatch(settingTarget, target, width, height)
if (target.name === BATCH_TYPE.OPENING || target.name === BATCH_TYPE.SHADOW) {
resizeObjectBatch(settingTarget, target, width, height, id)
} else if (target.name === POLYGON_TYPE.ROOF) {
resizeSurfaceShapeBatch(settingTarget, target, width, height)
resizeSurfaceShapeBatch(settingTarget, target, width, height, id)
}
}
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.size.setting')} </h1>
<button className="modal-close" onClick={() => closePopup(id)}>
닫기
</button>
</div>
<div className="modal-body">
<div className="slope-wrap">
<div className="size-option-top">
<WithDraggable isShow={true} pos={pos} className="ssm">
<WithDraggable.Header title={getMessage('modal.size.setting')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="slope-wrap">
<div className="size-option-top">
<div className="size-option-wrap">
<div className="size-option mb5">
<input type="text" className="input-origin mr5" value={target?.width.toFixed(0) * 10} readOnly={true} />
<span className="normal-font">mm</span>
</div>
<div className="size-option">
<input type="text" className="input-origin mr5" defaultValue={target?.width.toFixed(0) * 10} ref={widthRef} />
<span className="normal-font">mm</span>
</div>
</div>
</div>
<div className="size-inner-warp">
<div className="size-option-side">
<div className="size-option-wrap">
<div className="size-option mb5">
<input type="text" className="input-origin mr5" value={target?.width.toFixed(0) * 10} readOnly={true} />
<input type="text" className="input-origin mr5" value={target?.height.toFixed(0) * 10} readOnly={true} />
<span className="normal-font">mm</span>
</div>
<div className="size-option">
<input type="text" className="input-origin mr5" defaultValue={target?.width.toFixed(0) * 10} ref={widthRef} />
<input type="text" className="input-origin mr5" defaultValue={target?.height.toFixed(0) * 10} ref={heightRef} />
<span className="normal-font">mm</span>
</div>
</div>
</div>
<div className="size-inner-warp">
<div className="size-option-side">
<div className="size-option-wrap">
<div className="size-option mb5">
<input type="text" className="input-origin mr5" value={target?.height.toFixed(0) * 10} readOnly={true} />
<span className="normal-font">mm</span>
</div>
<div className="size-option">
<input type="text" className="input-origin mr5" defaultValue={target?.height.toFixed(0) * 10} ref={heightRef} />
<span className="normal-font">mm</span>
</div>
</div>
</div>
<div className="size-check-wrap">
<button className={`size-btn ${settingTarget === 1 ? 'act' : ''}`} onClick={() => setSettingTarget(1)}></button>
<button className={`size-btn ${settingTarget === 2 ? 'act' : ''}`} onClick={() => setSettingTarget(2)}></button>
<button className={`size-btn ${settingTarget === 3 ? 'act' : ''}`} onClick={() => setSettingTarget(3)}></button>
<button className={`size-btn ${settingTarget === 4 ? 'act' : ''}`} onClick={() => setSettingTarget(4)}></button>
<div className="size-box"></div>
</div>
<div className="size-check-wrap">
<button className={`size-btn ${settingTarget === 1 ? 'act' : ''}`} onClick={() => setSettingTarget(1)}></button>
<button className={`size-btn ${settingTarget === 2 ? 'act' : ''}`} onClick={() => setSettingTarget(2)}></button>
<button className={`size-btn ${settingTarget === 3 ? 'act' : ''}`} onClick={() => setSettingTarget(3)}></button>
<button className={`size-btn ${settingTarget === 4 ? 'act' : ''}`} onClick={() => setSettingTarget(4)}></button>
<div className="size-box"></div>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => handleReSizeObject()}>
{getMessage('write')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal act" onClick={() => handleReSizeObject(id)}>
{getMessage('write')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -23,7 +23,10 @@ const PentagonDormer = forwardRef((props, refs) => {
<div className="object-size-input">
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.object.setting.agreement.depth')}</div>
<div className="eaves-keraba-th">
<span className="object-input-num"></span>
{getMessage('modal.object.setting.agreement.depth')}
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}>
@ -45,7 +48,10 @@ const PentagonDormer = forwardRef((props, refs) => {
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('width')}</div>
<div className="eaves-keraba-th">
<span className="object-input-num"></span>
{getMessage('modal.object.setting.size.width')}
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}>
@ -67,7 +73,7 @@ const PentagonDormer = forwardRef((props, refs) => {
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('slope')}</div>
<div className="eaves-keraba-th">{getMessage('modal.object.setting.offset.slope')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}>

View File

@ -23,7 +23,10 @@ const TriangleDormer = forwardRef((props, refs) => {
<div className="object-size-input">
<div className="eaves-keraba-table">
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('modal.object.setting.agreement.depth')}</div>
<div className="eaves-keraba-th">
<span className="object-input-num"></span>
{getMessage('modal.object.setting.agreement.depth')}
</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}>
@ -45,7 +48,7 @@ const TriangleDormer = forwardRef((props, refs) => {
</div>
</div>
<div className="eaves-keraba-item">
<div className="eaves-keraba-th">{getMessage('slope')}</div>
<div className="eaves-keraba-th">{getMessage('modal.object.setting.offset.slope')}</div>
<div className="eaves-keraba-td">
<div className="outline-form">
<div className="input-grid mr5" style={{ width: '60px' }}>

View File

@ -8,38 +8,30 @@ export default function PropertiesSetting(props) {
const { handleSetEaves, handleSetGable, handleRollback, handleFix, closeModal } = usePropertiesSetting(id)
return (
<WithDraggable isShow={true} pos={pos}>
<div className={`modal-pop-wrap ssm`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.canvas.setting.wallline.properties.setting')}</h1>
<button className="modal-close" onClick={() => closeModal(id)}>
닫기
<WithDraggable isShow={true} pos={pos} className="ssm">
<WithDraggable.Header title={getMessage('modal.canvas.setting.wallline.properties.setting')} onClose={() => closeModal(id)} />
<WithDraggable.Body>
<div className="properties-guide">{getMessage('modal.canvas.setting.wallline.properties.setting.info')}</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('setting')}</div>
<div className="setting-btn-wrap">
<button className="setting-btn green mr5" onClick={handleSetEaves}>
{getMessage('modal.canvas.setting.wallline.properties.setting.eaves')}
</button>
<button className="setting-btn blue" onClick={handleSetGable}>
{getMessage('modal.canvas.setting.wallline.properties.setting.edge')}
</button>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal act" onClick={() => handleFix()}>
{getMessage('modal.cover.outline.finish')}
</button>
</div>
<div className="modal-body">
<div className="properties-guide">{getMessage('modal.canvas.setting.wallline.properties.setting.info')}</div>
<div className="properties-setting-wrap">
<div className="setting-tit">{getMessage('setting')}</div>
<div className="setting-btn-wrap">
<button className="setting-btn green mr5" onClick={handleSetEaves}>
{getMessage('modal.canvas.setting.wallline.properties.setting.eaves')}
</button>
<button className="setting-btn blue" onClick={handleSetGable}>
{getMessage('modal.canvas.setting.wallline.properties.setting.edge')}
</button>
</div>
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button className="btn-frame modal act" onClick={() => handleFix()}>
{getMessage('modal.cover.outline.finish')}
</button>
</div>
</div>
<div className="modal-foot modal-handle"></div>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

View File

@ -114,22 +114,18 @@ export default function WallLineSetting(props) {
}
return (
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }}>
<div className={`modal-pop-wrap r mount`}>
<div className="modal-head modal-handle">
<h1 className="title">{getMessage('modal.cover.outline.drawing')}</h1>
<button className="modal-close" onClick={() => closePopup(id)}></button>
</div>
<div className="modal-body">
<div className="modal-btn-wrap">
<button
<WithDraggable isShow={true} pos={{ x: 50, y: 230 }} className="r">
<WithDraggable.Header title={getMessage('modal.cover.outline.drawing')} onClose={() => closePopup(id)} />
<WithDraggable.Body>
<div className="modal-btn-wrap">
{/*<button
className={`btn-frame modal ${type === OUTER_LINE_TYPE.OUTER_LINE ? 'act' : ''}`}
onClick={() => setType(OUTER_LINE_TYPE.OUTER_LINE)}
>
{getMessage('modal.cover.outline')}
</button>
</button>*/}
<button
{/* <button -- 2025-03-11 #838 . .
className={`btn-frame modal ${type === OUTER_LINE_TYPE.RIGHT_ANGLE ? 'act' : ''}`}
onClick={() => setType(OUTER_LINE_TYPE.RIGHT_ANGLE)}
>
@ -149,42 +145,40 @@ export default function WallLineSetting(props) {
onClick={() => setType(OUTER_LINE_TYPE.DIAGONAL_LINE)}
>
{getMessage('modal.cover.outline.diagonal')}
</button>
</div>
<div className="properties-setting-wrap outer">
{type === OUTER_LINE_TYPE.OUTER_LINE ? (
<OuterLineWall props={outerLineProps} />
) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? (
<RightAngle props={rightAngleProps} />
) : type === OUTER_LINE_TYPE.DOUBLE_PITCH ? (
<DoublePitch props={doublePitchProps} />
) : type === OUTER_LINE_TYPE.ANGLE ? (
<Angle props={angleProps} />
) : type === OUTER_LINE_TYPE.DIAGONAL_LINE ? (
<Diagonal props={diagonalLineProps} />
) : (
<></>
)}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button
className="btn-frame modal act"
onClick={() => {
handleFix()
// closePopup(id)
// setShowPropertiesSettingModal(true)
}}
>
{getMessage('modal.cover.outline.fix')}
</button>
</div>
</button>*/}
</div>
<div className="modal-foot modal-handle"></div>
</div>
<div className="properties-setting-wrap">
{type === OUTER_LINE_TYPE.OUTER_LINE ? (
<OuterLineWall props={outerLineProps} />
) : type === OUTER_LINE_TYPE.RIGHT_ANGLE ? (
<RightAngle props={rightAngleProps} />
) : type === OUTER_LINE_TYPE.DOUBLE_PITCH ? (
<DoublePitch props={doublePitchProps} />
) : type === OUTER_LINE_TYPE.ANGLE ? (
<Angle props={angleProps} />
) : type === OUTER_LINE_TYPE.DIAGONAL_LINE ? (
<Diagonal props={diagonalLineProps} />
) : (
<></>
)}
</div>
<div className="grid-btn-wrap">
<button className="btn-frame modal mr5" onClick={handleRollback}>
{getMessage('modal.cover.outline.rollback')}
</button>
<button
className="btn-frame modal act"
onClick={() => {
handleFix()
// closePopup(id)
// setShowPropertiesSettingModal(true)
}}
>
{getMessage('modal.cover.outline.fix')}
</button>
</div>
</WithDraggable.Body>
</WithDraggable>
)
}

Some files were not shown because too many files have changed in this diff Show More