Merge pull request 'dev' (#927) from dev into prd-deploy
Reviewed-on: #927
This commit is contained in:
commit
c3e2562a19
@ -10,11 +10,14 @@ 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_bV5zuYMyyIYFlOb3"
|
||||||
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
||||||
NEXT_PUBLIC_CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png"
|
||||||
NEXT_PUBLIC_CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png"
|
||||||
|
CONVERTER_API_TOKEN="mcHqQkSZP30vxCRpIWJV62ciBYT887RI"
|
||||||
|
|
||||||
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order-dev.q-cells.jp/eos/login/autoLogin"
|
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order-dev.q-cells.jp/eos/login/autoLogin"
|
||||||
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi-dev.q-cells.jp/qm/login/autoLogin"
|
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="https://q-musubi-dev.q-cells.jp/qm/login/autoLogin"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_URL="https://q-order-dev.q-cells.jp/eos/simulation/list"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_DETAIL_URL="https://q-order-dev.q-cells.jp/eos/simulation/detail"
|
||||||
|
|
||||||
# 테스트용
|
# 테스트용
|
||||||
# AWS_REGION="ap-northeast-2"
|
# AWS_REGION="ap-northeast-2"
|
||||||
|
|||||||
@ -14,6 +14,8 @@ NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secr
|
|||||||
|
|
||||||
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/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"
|
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_URL="http://q-order-stg.q-cells.jp:8120/eos/simulation/list"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_DETAIL_URL="http://q-order-stg.q-cells.jp:8120/eos/simulation/detail"
|
||||||
|
|
||||||
# 테스트용
|
# 테스트용
|
||||||
# AWS_REGION="ap-northeast-2"
|
# AWS_REGION="ap-northeast-2"
|
||||||
|
|||||||
@ -10,11 +10,14 @@ 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_bV5zuYMyyIYFlOb3"
|
||||||
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
||||||
NEXT_PUBLIC_CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png"
|
||||||
NEXT_PUBLIC_CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png"
|
||||||
|
CONVERTER_API_TOKEN="mcHqQkSZP30vxCRpIWJV62ciBYT887RI"
|
||||||
|
|
||||||
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="http://q-order-stg.q-cells.jp:8120/eos/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"
|
NEXT_PUBLIC_Q_MUSUBI_AUTO_LOGIN_URL="http://q-musubi-stg.q-cells.jp:8120/qm/login/autoLogin"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_URL="http://q-order-stg.q-cells.jp:8120/eos/simulation/list"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_DETAIL_URL="http://q-order-stg.q-cells.jp:8120/eos/simulation/detail"
|
||||||
|
|
||||||
# 테스트용
|
# 테스트용
|
||||||
# AWS_REGION="ap-northeast-2"
|
# AWS_REGION="ap-northeast-2"
|
||||||
|
|||||||
@ -10,11 +10,14 @@ 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_bV5zuYMyyIYFlOb3"
|
||||||
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
# NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_yAS4QDalL9jgQ7vS"
|
||||||
NEXT_PUBLIC_CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DWG_API_URL="https://v2.convertapi.com/convert/dwg/to/png"
|
||||||
NEXT_PUBLIC_CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png?Secret=secret_a0FLEK6M2oTpXInK"
|
CONVERTER_DXF_API_URL="https://v2.convertapi.com/convert/dxf/to/png"
|
||||||
|
CONVERTER_API_TOKEN="mcHqQkSZP30vxCRpIWJV62ciBYT887RI"
|
||||||
|
|
||||||
NEXT_PUBLIC_Q_ORDER_AUTO_LOGIN_URL="https://q-order.q-cells.jp/eos/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_MUSUBI_AUTO_LOGIN_URL="https://q-musubi.q-cells.jp/qm/login/autoLogin"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_URL="https://q-order.q-cells.jp/eos/simulation/list"
|
||||||
|
NEXT_PUBLIC_ECONOMIC_SIMULATION_DETAIL_URL="https://q-order.q-cells.jp/eos/simulation/detail"
|
||||||
|
|
||||||
# AWS_REGION="ap-northeast-2"
|
# AWS_REGION="ap-northeast-2"
|
||||||
# AMPLIFY_BUCKET="interplug"
|
# AMPLIFY_BUCKET="interplug"
|
||||||
|
|||||||
36
src/app/api/image/convert/route.js
Normal file
36
src/app/api/image/convert/route.js
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
import { NextResponse } from 'next/server'
|
||||||
|
|
||||||
|
// ConvertAPI 토큰은 서버 전용 env 로만 보관 (NEXT_PUBLIC_ 아님) — 클라이언트 번들에 노출되지 않는다.
|
||||||
|
const CONVERTER_API_TOKEN = process.env.CONVERTER_API_TOKEN
|
||||||
|
const CONVERTER_URLS = {
|
||||||
|
dwg: process.env.CONVERTER_DWG_API_URL,
|
||||||
|
dxf: process.env.CONVERTER_DXF_API_URL,
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function POST(req) {
|
||||||
|
try {
|
||||||
|
const formData = await req.formData()
|
||||||
|
const file = formData.get('file')
|
||||||
|
const type = formData.get('type')
|
||||||
|
|
||||||
|
const convertUrl = CONVERTER_URLS[type]
|
||||||
|
if (!file || !convertUrl) {
|
||||||
|
return NextResponse.json({ error: 'Invalid request' }, { status: 400 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const upstream = new FormData()
|
||||||
|
upstream.append('file', file, file.name)
|
||||||
|
|
||||||
|
const res = await fetch(convertUrl, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { Authorization: `Bearer ${CONVERTER_API_TOKEN}` },
|
||||||
|
body: upstream,
|
||||||
|
})
|
||||||
|
|
||||||
|
const data = await res.json()
|
||||||
|
return NextResponse.json(data, { status: res.status })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('CAD convert proxy error:', error)
|
||||||
|
return NextResponse.json({ Message: error?.message ?? 'Failed to convert CAD file' }, { status: 500 })
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -105,6 +105,20 @@ export default function CanvasMenu(props) {
|
|||||||
// 발전시뮬레이션 메뉴 이동
|
// 발전시뮬레이션 메뉴 이동
|
||||||
const { objectNo, pid } = floorPlanState
|
const { objectNo, pid } = floorPlanState
|
||||||
|
|
||||||
|
const openEconomicSimulation = async (objectNo, planNo) => {
|
||||||
|
const encRes = await promiseGet({
|
||||||
|
url: '/api/pwrGnrSimulation/encData',
|
||||||
|
option: { params: { saleStoreId: sessionState.storeId, userId: sessionState.userId } },
|
||||||
|
})
|
||||||
|
const { encSaleStoreId, encUserId } = encRes.data
|
||||||
|
if (!encSaleStoreId || !encUserId) return
|
||||||
|
window.open(
|
||||||
|
`${process.env.NEXT_PUBLIC_ECONOMIC_SIMULATION_DETAIL_URL}?authYn=Y&encStoreId=${encodeURIComponent(encSaleStoreId)}&encRegId=${encodeURIComponent(encUserId)}&stuffNo=${objectNo}&planNo=${planNo}`,
|
||||||
|
'economicSimulation',
|
||||||
|
`height=${screen.height},width=${screen.width},fullscreen=yes`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// 발전시물레이션 Excel/PDF 다운
|
// 발전시물레이션 Excel/PDF 다운
|
||||||
const { promiseGet, promisePost } = useAxios(globalLocale)
|
const { promiseGet, promisePost } = useAxios(globalLocale)
|
||||||
const pwrGnrSimTypeRecoil = useRecoilValue(pwrGnrSimTypeState)
|
const pwrGnrSimTypeRecoil = useRecoilValue(pwrGnrSimTypeState)
|
||||||
@ -294,15 +308,30 @@ export default function CanvasMenu(props) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
break
|
break
|
||||||
|
case 'economicSimulation':
|
||||||
|
setIsGlobalLoading(true)
|
||||||
|
promiseGet({ url: `/api/estimate/${objectNo}/${selectedPlan?.planNo ?? pid}/detail` }).then(async (res) => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const estimateDetail = res.data
|
||||||
|
if (estimateDetail.estimateDate !== null && estimateDetail.docNo) {
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
await openEconomicSimulation(objectNo, selectedPlan?.planNo ?? pid)
|
||||||
|
} else {
|
||||||
|
setIsGlobalLoading(false)
|
||||||
|
swalFire({ text: getMessage('simulator.menu.move.valid1') })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if (menu.type !== 'simulation' && menu.type !== 'estimate' && menu.type !== 'drawing') {
|
if (menu.type !== 'simulation' && menu.type !== 'estimate' && menu.type !== 'drawing' && menu.type !== 'economicSimulation') {
|
||||||
setSelectedMenu(menu.type)
|
setSelectedMenu(menu.type)
|
||||||
setCurrentMenu(menu.title)
|
setCurrentMenu(menu.title)
|
||||||
}
|
}
|
||||||
if (pathname !== '/floor-plan') {
|
if (pathname !== '/floor-plan') {
|
||||||
//견적서 or 발전시뮬레이션 탭에서 같은 탭 클릭시 화면 이동했다 돌아오지않도록..
|
//견적서 or 발전시뮬레이션 탭에서 같은 탭 클릭시 화면 이동했다 돌아오지않도록..
|
||||||
if (menu.type !== 'drawing' && menu.type !== 'estimate' && menu.type !== 'simulation') {
|
if (menu.type !== 'drawing' && menu.type !== 'estimate' && menu.type !== 'simulation' && menu.type !== 'economicSimulation') {
|
||||||
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
|
router.push(`/floor-plan?pid=${pid}&objectNo=${objectNo}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -171,8 +171,9 @@ export default function ModuleTabContents({ tabIndex, addRoof, setAddedRoofs, ro
|
|||||||
<div className="flex-item-btn-wrap">
|
<div className="flex-item-btn-wrap">
|
||||||
{/* 2026-06-05 공법 버튼을 배열 인덱스 대신 constTp로 매핑 — API 응답 항목 추가/순서변경(예: 標準施工(Ⅱ) WORK_LV_ID_-2) 시 인덱스 밀림 방지. 운영(구 API)엔 -2가 없어 optional 은 데이터 있을 때만 렌더 */}
|
{/* 2026-06-05 공법 버튼을 배열 인덱스 대신 constTp로 매핑 — API 응답 항목 추가/순서변경(예: 標準施工(Ⅱ) WORK_LV_ID_-2) 시 인덱스 밀림 방지. 운영(구 API)엔 -2가 없어 optional 은 데이터 있을 때만 렌더 */}
|
||||||
{[
|
{[
|
||||||
{ constTp: 'WORK_LV_ID_-1', label: '標準施工(Ⅰ)' },
|
// [표시순서변경 2026-06-17] 標準(Ⅱ) 를 標準(Ⅰ) 앞으로 — 사용자 요청
|
||||||
{ constTp: 'WORK_LV_ID_-2', label: '標準施工(Ⅱ)', optional: true },
|
{ constTp: 'WORK_LV_ID_-2', label: '標準施工(Ⅱ)', optional: true },
|
||||||
|
{ constTp: 'WORK_LV_ID_-1', label: '標準施工(Ⅰ)' },
|
||||||
{ constTp: 'WORK_LV_ID_1', label: '標準施工' },
|
{ constTp: 'WORK_LV_ID_1', label: '標準施工' },
|
||||||
{ constTp: 'WORK_LV_ID_3', label: '強化施工' },
|
{ constTp: 'WORK_LV_ID_3', label: '強化施工' },
|
||||||
{ constTp: 'WORK_LV_ID_4', label: '多設施工' },
|
{ constTp: 'WORK_LV_ID_4', label: '多設施工' },
|
||||||
|
|||||||
@ -867,8 +867,9 @@ const Trestle = forwardRef((props, ref) => {
|
|||||||
<div className="flex-item-btn-wrap">
|
<div className="flex-item-btn-wrap">
|
||||||
{/* 2026-06-05 공법 버튼을 배열 인덱스 대신 constTp로 매핑 — API 응답 항목 추가/순서변경(예: 標準施工(II) WORK_LV_ID_-2) 시 인덱스 밀림 방지. 운영(구 API)엔 -2가 없어 optional 은 데이터 있을 때만 렌더 */}
|
{/* 2026-06-05 공법 버튼을 배열 인덱스 대신 constTp로 매핑 — API 응답 항목 추가/순서변경(예: 標準施工(II) WORK_LV_ID_-2) 시 인덱스 밀림 방지. 운영(구 API)엔 -2가 없어 optional 은 데이터 있을 때만 렌더 */}
|
||||||
{[
|
{[
|
||||||
{ constTp: 'WORK_LV_ID_-1', label: `${getMessage('modal.module.basic.setting.module.standard.construction')}(I)` },
|
// [표시순서변경 2026-06-17] 標準(II) 를 標準(I) 앞으로 — 사용자 요청
|
||||||
{ constTp: 'WORK_LV_ID_-2', label: `${getMessage('modal.module.basic.setting.module.standard.construction')}(II)`, optional: true },
|
{ constTp: 'WORK_LV_ID_-2', label: `${getMessage('modal.module.basic.setting.module.standard.construction')}(II)`, optional: true },
|
||||||
|
{ constTp: 'WORK_LV_ID_-1', label: `${getMessage('modal.module.basic.setting.module.standard.construction')}(I)` },
|
||||||
{ constTp: 'WORK_LV_ID_1', label: getMessage('modal.module.basic.setting.module.standard.construction') },
|
{ constTp: 'WORK_LV_ID_1', label: getMessage('modal.module.basic.setting.module.standard.construction') },
|
||||||
{ constTp: 'WORK_LV_ID_3', label: getMessage('modal.module.basic.setting.module.enforce.construction') },
|
{ constTp: 'WORK_LV_ID_3', label: getMessage('modal.module.basic.setting.module.enforce.construction') },
|
||||||
{ constTp: 'WORK_LV_ID_4', label: getMessage('modal.module.basic.setting.module.multiple.construction') },
|
{ constTp: 'WORK_LV_ID_4', label: getMessage('modal.module.basic.setting.module.multiple.construction') },
|
||||||
|
|||||||
@ -164,6 +164,23 @@ export default function Header(props) {
|
|||||||
getAutoLoginParam()
|
getAutoLoginParam()
|
||||||
}, [userSession])
|
}, [userSession])
|
||||||
|
|
||||||
|
const openEconomicSimulation = async () => {
|
||||||
|
const encRes = await promiseGet({
|
||||||
|
url: '/api/pwrGnrSimulation/encData',
|
||||||
|
option: { params: { saleStoreId: sessionState.storeId, userId: sessionState.userId } },
|
||||||
|
})
|
||||||
|
|
||||||
|
const { encSaleStoreId, encUserId } = encRes.data
|
||||||
|
|
||||||
|
if (!encSaleStoreId || !encUserId) return
|
||||||
|
|
||||||
|
window.open(
|
||||||
|
`${process.env.NEXT_PUBLIC_ECONOMIC_SIMULATION_URL}?authYn=Y&encStoreId=${encodeURIComponent(encSaleStoreId)}&encRegId=${encodeURIComponent(encUserId)}`,
|
||||||
|
'economicSimulation',
|
||||||
|
`height=${screen.height},width=${screen.width},fullscreen=yes`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const menus = [
|
const menus = [
|
||||||
{ id: 0, name: 'header.menus.home', url: '/', children: [] },
|
{ id: 0, name: 'header.menus.home', url: '/', children: [] },
|
||||||
{
|
{
|
||||||
@ -187,7 +204,10 @@ export default function Header(props) {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{ id: 8, name: 'qna.title', url: '/community/qna', children: [] },
|
{ id: 8, name: 'qna.title', url: '/community/qna', children: [] },
|
||||||
]
|
process.env.NEXT_PUBLIC_RUN_MODE !== 'production'
|
||||||
|
? { id: 9, name: 'header.menus.economic.simulation', action: openEconomicSimulation, children: [] }
|
||||||
|
: null,
|
||||||
|
].filter(Boolean)
|
||||||
|
|
||||||
const syncSession = useCallback(() => {
|
const syncSession = useCallback(() => {
|
||||||
setSessionState({ ...userSession })
|
setSessionState({ ...userSession })
|
||||||
@ -237,6 +257,11 @@ export default function Header(props) {
|
|||||||
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
onMouseLeave={(e) => ToggleonMouse(e, 'remove', 'nav > ul')}
|
||||||
>
|
>
|
||||||
{menu.children.length === 0 ? (
|
{menu.children.length === 0 ? (
|
||||||
|
menu.action ? (
|
||||||
|
<button key={`${menu.id}`} className="no-arrow" onClick={() => menu.action()}>
|
||||||
|
{getMessage(menu.name)}
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
<Link
|
<Link
|
||||||
key={`${menu.id}`}
|
key={`${menu.id}`}
|
||||||
href={menu.url}
|
href={menu.url}
|
||||||
@ -272,6 +297,7 @@ export default function Header(props) {
|
|||||||
>
|
>
|
||||||
{getMessage(menu.name)}
|
{getMessage(menu.name)}
|
||||||
</Link>
|
</Link>
|
||||||
|
)
|
||||||
) : (
|
) : (
|
||||||
<Fragment key={`${menu.id}`}>
|
<Fragment key={`${menu.id}`}>
|
||||||
<button>{getMessage(menu.name)}</button>
|
<button>{getMessage(menu.name)}</button>
|
||||||
|
|||||||
@ -25,8 +25,6 @@ import { logger } from '@/util/logger'
|
|||||||
* @returns {object}
|
* @returns {object}
|
||||||
*/
|
*/
|
||||||
export function useRefFiles() {
|
export function useRefFiles() {
|
||||||
const converterDwgUrl = process.env.NEXT_PUBLIC_CONVERTER_DWG_API_URL
|
|
||||||
const converterDxfUrl = process.env.NEXT_PUBLIC_CONVERTER_DXF_API_URL
|
|
||||||
const { getMessage } = useMessage()
|
const { getMessage } = useMessage()
|
||||||
const [refImage, setRefImage] = useState(null)
|
const [refImage, setRefImage] = useState(null)
|
||||||
const [refFileMethod, setRefFileMethod] = useState('1')
|
const [refFileMethod, setRefFileMethod] = useState('1')
|
||||||
@ -89,9 +87,9 @@ export function useRefFiles() {
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
if (file.name.split('.').pop() === 'dwg') {
|
if (file.name.split('.').pop() === 'dwg') {
|
||||||
handleUploadConvertRefFile(file, converterDwgUrl);
|
handleUploadConvertRefFile(file, 'dwg');
|
||||||
} else if (file.name.split('.').pop() === 'dxf') {
|
} else if (file.name.split('.').pop() === 'dxf') {
|
||||||
handleUploadConvertRefFile(file, converterDxfUrl);
|
handleUploadConvertRefFile(file, 'dxf');
|
||||||
} else {
|
} else {
|
||||||
if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) {
|
if (file && ['image/png', 'image/jpg', 'image/jpeg', 'image/bmp', 'image/gif'].includes(file.type)) {
|
||||||
handleUploadImageRefFile(file)
|
handleUploadImageRefFile(file)
|
||||||
@ -152,7 +150,7 @@ export function useRefFiles() {
|
|||||||
* 주소로 구글 맵 이미지 다운로드하여 캔버스 배경으로 로드
|
* 주소로 구글 맵 이미지 다운로드하여 캔버스 배경으로 로드
|
||||||
*/
|
*/
|
||||||
const handleMapImageDown = async () => {
|
const handleMapImageDown = async () => {
|
||||||
debugger; logger.log('🚀 ~ handleMapImageDown ~ handleMapImageDown:')
|
logger.log('🚀 ~ handleMapImageDown ~ handleMapImageDown:')
|
||||||
if (queryRef.current.value === '' || queryRef.current.value === null) {
|
if (queryRef.current.value === '' || queryRef.current.value === null) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -250,16 +248,23 @@ export function useRefFiles() {
|
|||||||
/**
|
/**
|
||||||
* RefFile이 캐드 도면 파일일 경우 변환하여 이미지로 저장
|
* RefFile이 캐드 도면 파일일 경우 변환하여 이미지로 저장
|
||||||
* @param {*} file
|
* @param {*} file
|
||||||
* @param converterUrl
|
* @param {'dwg'|'dxf'} cadType
|
||||||
*/
|
*/
|
||||||
const handleUploadConvertRefFile = async (file, converterUrl) => {
|
const handleUploadConvertRefFile = async (file, cadType) => {
|
||||||
|
try {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
|
formData.append('type', cadType)
|
||||||
|
|
||||||
/** 캐드 도면 파일 변환 */
|
/** 캐드 도면 변환은 서버 프록시 경유 — ConvertAPI 토큰을 클라이언트에 노출하지 않는다 */
|
||||||
const res = await post({ url: converterUrl, data: formData })
|
const res = await post({ url: `${Config().baseUrl}/api/image/convert`, data: formData })
|
||||||
logger.log('🚀 ~ handleUploadConvertRefFile ~ res:', res)
|
logger.log('🚀 ~ handleUploadConvertRefFile ~ res:', res)
|
||||||
|
|
||||||
|
// 변환 API 가 정상 변환 대신 에러 본문(Code/Message)을 반환한 경우 그대로 throw [DXF-CONVERT-FAIL 2026-06-15]
|
||||||
|
if (!res?.Files?.[0]?.FileData) {
|
||||||
|
throw new Error(res?.Message || getMessage('common.message.ref.file.convertFail'))
|
||||||
|
}
|
||||||
|
|
||||||
// Convert Base64 to Blob
|
// Convert Base64 to Blob
|
||||||
const base64Data = res.Files[0].FileData
|
const base64Data = res.Files[0].FileData
|
||||||
const byteCharacters = atob(base64Data)
|
const byteCharacters = atob(base64Data)
|
||||||
@ -304,8 +309,15 @@ export function useRefFiles() {
|
|||||||
}
|
}
|
||||||
logger.log('🚀 ~ handleUploadImageRefFile ~ params:', params)
|
logger.log('🚀 ~ handleUploadImageRefFile ~ params:', params)
|
||||||
await setBackGroundImage(params)
|
await setBackGroundImage(params)
|
||||||
|
} catch (error) {
|
||||||
|
// 변환/업로드 실패 시 API 응답 메시지를 그대로 노출 (없으면 기본 안내) [DXF-CONVERT-FAIL 2026-06-15]
|
||||||
|
logger.error('🚨 handleUploadConvertRefFile error:', error)
|
||||||
|
const apiMessage = error?.response?.data?.Message || error?.message || getMessage('common.message.ref.file.convertFail')
|
||||||
|
swalFire({ text: apiMessage, type: 'alert', icon: 'error' })
|
||||||
|
} finally {
|
||||||
setPopSpinnerStore(false)
|
setPopSpinnerStore(false)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 라디오 버튼 컨트롤
|
* 라디오 버튼 컨트롤
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1228,6 +1228,17 @@ export function useRoofAllocationSetting(id) {
|
|||||||
roofBase.innerLines.push(...made)
|
roofBase.innerLines.push(...made)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [KERAB-TYPE-EAVES-SK-HELPER-PURGE 2026-06-12] kerabPatternHip 이 있을 때
|
||||||
|
// name='hip', lineName 미설정 인 SK 격자 반-엣지를 innerLines 에서 제거한다.
|
||||||
|
// 이 선들은 외곽 gable 변과 동일직선상에서 더 짧은 경로를 제공하여 Dijkstra 가
|
||||||
|
// degenerate collinear face 를 먼저 선택 → 진짜 top/bottom 사다리꼴 면의 start 가
|
||||||
|
// 소진돼 미생성된다. kerab 케이스에서만 purge — 일반 SK hip 에서는 건드리지 않음.
|
||||||
|
if (roofBase.innerLines.some((l) => l?.lineName === 'kerabPatternHip')) {
|
||||||
|
const skHelpers = roofBase.innerLines.filter((l) => !l?.lineName && l?.name === 'hip')
|
||||||
|
skHelpers.forEach((l) => canvas.remove(l))
|
||||||
|
roofBase.innerLines = roofBase.innerLines.filter((l) => !(!l?.lineName && l?.name === 'hip'))
|
||||||
|
}
|
||||||
|
|
||||||
if (roofBase.separatePolygon.length > 0) {
|
if (roofBase.separatePolygon.length > 0) {
|
||||||
splitPolygonWithSeparate(roofBase.separatePolygon)
|
splitPolygonWithSeparate(roofBase.separatePolygon)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"header.menus.community.notice": "お知らせ",
|
"header.menus.community.notice": "お知らせ",
|
||||||
"header.menus.community.faq": "FAQ",
|
"header.menus.community.faq": "FAQ",
|
||||||
"header.menus.community.archive": "各種資料ダウンロード",
|
"header.menus.community.archive": "各種資料ダウンロード",
|
||||||
|
"header.menus.economic.simulation": "経済シミュレーション管理",
|
||||||
"header.logout": "ログアウト",
|
"header.logout": "ログアウト",
|
||||||
"header.go": "移動",
|
"header.go": "移動",
|
||||||
"header.online.warranty.system": "オンライン保証システム",
|
"header.online.warranty.system": "オンライン保証システム",
|
||||||
@ -248,6 +249,7 @@
|
|||||||
"plan.menu.estimate.unLock": "ロック解除",
|
"plan.menu.estimate.unLock": "ロック解除",
|
||||||
"plan.menu.estimate.lock": "ロック",
|
"plan.menu.estimate.lock": "ロック",
|
||||||
"plan.menu.simulation": "発電シミュレーション",
|
"plan.menu.simulation": "発電シミュレーション",
|
||||||
|
"plan.menu.economic.simulation": "経済シミュレーション",
|
||||||
"plan.menu.simulation.excel": "Excel",
|
"plan.menu.simulation.excel": "Excel",
|
||||||
"plan.menu.simulation.pdf": "PDF",
|
"plan.menu.simulation.pdf": "PDF",
|
||||||
"plan.mode.vertical.horizontal": "垂直水平モード",
|
"plan.mode.vertical.horizontal": "垂直水平モード",
|
||||||
@ -589,6 +591,7 @@
|
|||||||
"common.message.no.edit.save": "このドキュメントは変更できません。",
|
"common.message.no.edit.save": "このドキュメントは変更できません。",
|
||||||
"common.message.ref.file.change": "ファイルを変更しますか?",
|
"common.message.ref.file.change": "ファイルを変更しますか?",
|
||||||
"common.message.ref.file.noImage": "画像ではありません。",
|
"common.message.ref.file.noImage": "画像ではありません。",
|
||||||
|
"common.message.ref.file.convertFail": "図面の変換に失敗しました。時間をおいて再度お試しください。",
|
||||||
"common.load": "読込",
|
"common.load": "読込",
|
||||||
"common.input.file": "ファイルを読み込む",
|
"common.input.file": "ファイルを読み込む",
|
||||||
"common.input.file.load": "読込",
|
"common.input.file.load": "読込",
|
||||||
|
|||||||
@ -10,6 +10,7 @@
|
|||||||
"header.menus.community.notice": "공지사항",
|
"header.menus.community.notice": "공지사항",
|
||||||
"header.menus.community.faq": "FAQ",
|
"header.menus.community.faq": "FAQ",
|
||||||
"header.menus.community.archive": "각종 자료 다운로드",
|
"header.menus.community.archive": "각종 자료 다운로드",
|
||||||
|
"header.menus.economic.simulation": "경제시뮬레이션 관리",
|
||||||
"header.logout": "로그아웃",
|
"header.logout": "로그아웃",
|
||||||
"header.go": "이동",
|
"header.go": "이동",
|
||||||
"header.online.warranty.system": "온라인보증시스템",
|
"header.online.warranty.system": "온라인보증시스템",
|
||||||
@ -248,6 +249,7 @@
|
|||||||
"plan.menu.estimate.unLock": "잠금 해제",
|
"plan.menu.estimate.unLock": "잠금 해제",
|
||||||
"plan.menu.estimate.lock": "잠금",
|
"plan.menu.estimate.lock": "잠금",
|
||||||
"plan.menu.simulation": "발전 시뮬레이션",
|
"plan.menu.simulation": "발전 시뮬레이션",
|
||||||
|
"plan.menu.economic.simulation": "경제 시뮬레이션",
|
||||||
"plan.menu.simulation.excel": "Excel",
|
"plan.menu.simulation.excel": "Excel",
|
||||||
"plan.menu.simulation.pdf": "PDF",
|
"plan.menu.simulation.pdf": "PDF",
|
||||||
"plan.mode.vertical.horizontal": "수직 수평 모드",
|
"plan.mode.vertical.horizontal": "수직 수평 모드",
|
||||||
@ -328,7 +330,7 @@
|
|||||||
"modal.canvas.setting.first.option.display": "화면 표시",
|
"modal.canvas.setting.first.option.display": "화면 표시",
|
||||||
"modal.canvas.setting.first.option.border": "테두리만",
|
"modal.canvas.setting.first.option.border": "테두리만",
|
||||||
"modal.canvas.setting.first.option.line": "라인해치",
|
"modal.canvas.setting.first.option.line": "라인해치",
|
||||||
"modal.canvas.setting.first.option.all": "All painted",
|
"modal.canvas.setting.first.option.all": "전체 칠하기",
|
||||||
"modal.canvas.setting.wallline.properties.setting": "외벽선 속성 설정",
|
"modal.canvas.setting.wallline.properties.setting": "외벽선 속성 설정",
|
||||||
"modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
|
"modal.canvas.setting.wallline.properties.setting.info": "※ 속성을 변경할 외벽선을 선택하고 처마로 설정 또는 케라바로 설정\n 버튼을 클릭하여 설정값을 적용하십시오.\n",
|
||||||
"modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정",
|
"modal.canvas.setting.wallline.properties.setting.eaves": "처마로 설정",
|
||||||
@ -534,12 +536,12 @@
|
|||||||
"common.message.file.template.validation03": "Non-registerable extension",
|
"common.message.file.template.validation03": "Non-registerable extension",
|
||||||
"common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity ",
|
"common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity ",
|
||||||
"common.message.file.template.validation05": "업로드 파일을 선택해주세요. {0} MB",
|
"common.message.file.template.validation05": "업로드 파일을 선택해주세요. {0} MB",
|
||||||
"common.message.multi.insert": "Total {0} cases ({1} successes {2} failures {3})",
|
"common.message.multi.insert": "총 {0}건 (성공 {1} 실패 {2} {3})",
|
||||||
"common.message.error": "Error occurred please contact site administrator.",
|
"common.message.error": "Error occurred please contact site administrator.",
|
||||||
"common.message.data.save": "Do you want to save it?",
|
"common.message.data.save": "Do you want to save it?",
|
||||||
"common.message.data.delete": "정말로 삭제하시겠습니까?",
|
"common.message.data.delete": "정말로 삭제하시겠습니까?",
|
||||||
"common.message.data.exists": "{0} is data that already exists.",
|
"common.message.data.exists": "{0}은(는) 이미 존재하는 데이터입니다.",
|
||||||
"common.message.data.no.exists": "{0} is data that does not exist.",
|
"common.message.data.no.exists": "{0}은(는) 존재하지 않는 데이터입니다.",
|
||||||
"common.message.all": "All",
|
"common.message.all": "All",
|
||||||
"common.message.tab.close.all": "Close all tabs?",
|
"common.message.tab.close.all": "Close all tabs?",
|
||||||
"common.message.transfer.save": "Want to {0} transfer it?",
|
"common.message.transfer.save": "Want to {0} transfer it?",
|
||||||
@ -570,18 +572,18 @@
|
|||||||
"common.message.menu.validation01": "There is no menu to save the order.",
|
"common.message.menu.validation01": "There is no menu to save the order.",
|
||||||
"common.message.menu.validation02": "The same sort order exists.",
|
"common.message.menu.validation02": "The same sort order exists.",
|
||||||
"common.message.menuCode.check01": "Registerable",
|
"common.message.menuCode.check01": "Registerable",
|
||||||
"common.message.menuCode.check02": "Unable to register",
|
"common.message.menuCode.check02": "등록할 수 없습니다.",
|
||||||
"common.message.pleaseSelect": "Please Select {0}",
|
"common.message.pleaseSelect": "{0}을(를) 선택해 주세요.",
|
||||||
"common.message.pleaseInput": "Please Input a {0}.",
|
"common.message.pleaseInput": "{0}을(를) 입력해 주세요.",
|
||||||
"common.message.pleaseInputOr": "Please Input a {0} or {1}.",
|
"common.message.pleaseInputOr": "{0} 또는 {1}을(를) 입력해 주세요.",
|
||||||
"common.message.please.input.over": "{0} 이상 값을 입력해주세요.",
|
"common.message.please.input.over": "{0} 이상 값을 입력해주세요.",
|
||||||
"common.message.approved ": "Approved.",
|
"common.message.approved ": "Approved.",
|
||||||
"common.message.errorFieldExist": "Error Field Exist",
|
"common.message.errorFieldExist": "Error Field Exist",
|
||||||
"common.message.storeIdExist ": "이미 사용하고 있는 판매점 ID 입니다.",
|
"common.message.storeIdExist ": "이미 사용하고 있는 판매점 ID 입니다.",
|
||||||
"common.message.userIdExist ": "이미 사용하고 있는 사용자 ID 입니다.",
|
"common.message.userIdExist ": "이미 사용하고 있는 사용자 ID 입니다.",
|
||||||
"common.message.noExists ": "삭제된 게시물 입니다.",
|
"common.message.noExists ": "삭제된 게시물 입니다.",
|
||||||
"common.message.emailReqTo": "Email To is required",
|
"common.message.emailReqTo": "받는 사람(Email To)은 필수입니다.",
|
||||||
"common.message.downloadPeriod": "Please select the download search period within {0} days.",
|
"common.message.downloadPeriod": "다운로드 조회 기간을 {0}일 이내로 선택해 주세요.",
|
||||||
"common.message.backToSubmit": "판매점 블록 해제를 실행하시겠습니까?",
|
"common.message.backToSubmit": "판매점 블록 해제를 실행하시겠습니까?",
|
||||||
"common.message.backToG3": "Back to G3 처리를 실행하시겠습니까?",
|
"common.message.backToG3": "Back to G3 처리를 실행하시겠습니까?",
|
||||||
"common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?",
|
"common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?",
|
||||||
@ -589,6 +591,7 @@
|
|||||||
"common.message.no.edit.save": "This document cannot be changed.",
|
"common.message.no.edit.save": "This document cannot be changed.",
|
||||||
"common.message.ref.file.change": "파일을 변경하시겠습니까?",
|
"common.message.ref.file.change": "파일을 변경하시겠습니까?",
|
||||||
"common.message.ref.file.noImage": "이미지가 아닙니다.",
|
"common.message.ref.file.noImage": "이미지가 아닙니다.",
|
||||||
|
"common.message.ref.file.convertFail": "도면 변환에 실패했습니다. 잠시 후 다시 시도해 주세요.",
|
||||||
"common.load": "불러오기",
|
"common.load": "불러오기",
|
||||||
"common.input.file": "파일 불러오기",
|
"common.input.file": "파일 불러오기",
|
||||||
"common.input.file.load": "불러오기",
|
"common.input.file.load": "불러오기",
|
||||||
@ -911,7 +914,7 @@
|
|||||||
"offset": "출폭",
|
"offset": "출폭",
|
||||||
"width": "폭",
|
"width": "폭",
|
||||||
"size": "치수",
|
"size": "치수",
|
||||||
"size.angle": "寸(度)",
|
"size.angle": "치(도)",
|
||||||
"eaves": "처마",
|
"eaves": "처마",
|
||||||
"eaves.line": "처마선",
|
"eaves.line": "처마선",
|
||||||
"gable": "케라바",
|
"gable": "케라바",
|
||||||
@ -999,10 +1002,10 @@
|
|||||||
"estimate.detail.objectName": "안건명",
|
"estimate.detail.objectName": "안건명",
|
||||||
"estimate.detail.objectRemarks": "메모",
|
"estimate.detail.objectRemarks": "메모",
|
||||||
"estimate.detail.estimateType": "주문분류",
|
"estimate.detail.estimateType": "주문분류",
|
||||||
"estimate.detail.estimateType.yjss": "住宅PKG",
|
"estimate.detail.estimateType.yjss": "주택PKG",
|
||||||
"estimate.detail.estimateType.yjod": "積上げ( YJOD )",
|
"estimate.detail.estimateType.yjod": "적산(YJOD)",
|
||||||
"estimate.detail.agency": "2차점명",
|
"estimate.detail.agency": "2차점명",
|
||||||
"estimate.detail.roofCns": "지붕재・사양시공",
|
"estimate.detail.roofCns": "지붕재·시공구분",
|
||||||
"estimate.detail.remarks": "비고",
|
"estimate.detail.remarks": "비고",
|
||||||
"estimate.detail.fileFlg": "후일자료제출",
|
"estimate.detail.fileFlg": "후일자료제출",
|
||||||
"estimate.detail.dragFileGuide": "(※ 북면설치인 경우, 파일 첨부가 필수입니다.)",
|
"estimate.detail.dragFileGuide": "(※ 북면설치인 경우, 파일 첨부가 필수입니다.)",
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import { atom } from 'recoil'
|
import { atom } from 'recoil'
|
||||||
|
|
||||||
|
// localhost(yarn dev, RUN_MODE=local) 에서만 기본 한국어, 그 외(dev/prd)는 일본어
|
||||||
|
const DEFAULT_LOCALE = process.env.NEXT_PUBLIC_RUN_MODE === 'local' ? 'ko' : 'ja'
|
||||||
|
|
||||||
export const globalLocaleStore = atom({
|
export const globalLocaleStore = atom({
|
||||||
key: 'globalLocaleState',
|
key: 'globalLocaleState',
|
||||||
default: 'ja',
|
default: DEFAULT_LOCALE,
|
||||||
})
|
})
|
||||||
|
|
||||||
export const appMessageStore = atom({
|
export const appMessageStore = atom({
|
||||||
|
|||||||
@ -36,7 +36,10 @@ export const menusState = atom({
|
|||||||
icon: 'con05',
|
icon: 'con05',
|
||||||
title: MENU.POWER_GENERATION_SIMULATION.DEFAULT,
|
title: MENU.POWER_GENERATION_SIMULATION.DEFAULT,
|
||||||
},
|
},
|
||||||
],
|
process.env.NEXT_PUBLIC_RUN_MODE !== 'production'
|
||||||
|
? { type: 'economicSimulation', name: 'plan.menu.economic.simulation', icon: 'con05', title: '' }
|
||||||
|
: null,
|
||||||
|
].filter(Boolean),
|
||||||
})
|
})
|
||||||
|
|
||||||
export const subMenusState = atom({
|
export const subMenusState = atom({
|
||||||
|
|||||||
@ -79,6 +79,9 @@ header{
|
|||||||
background: url(/static/images/common/nav-arr.svg)no-repeat center;
|
background: url(/static/images/common/nav-arr.svg)no-repeat center;
|
||||||
transition: all .17s ease-in-out;
|
transition: all .17s ease-in-out;
|
||||||
}
|
}
|
||||||
|
&.no-arrow:after{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&:last-child{
|
&:last-child{
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
|||||||
@ -29,7 +29,7 @@ const lineLineIntersection = (p1, p2, p3, p4) => {
|
|||||||
* @returns true=적용됨 / false=조건 미달 또는 변경 없음
|
* @returns true=적용됨 / false=조건 미달 또는 변경 없음
|
||||||
*/
|
*/
|
||||||
export const applyKerabOffsetSurgical = (canvas, target, newOffset, options = {}) => {
|
export const applyKerabOffsetSurgical = (canvas, target, newOffset, options = {}) => {
|
||||||
const { skipInnerLines = false } = options
|
const { skipInnerLines = false, skipKerabHips = false } = options
|
||||||
const roof = canvas
|
const roof = canvas
|
||||||
.getObjects()
|
.getObjects()
|
||||||
.find((o) => o.name === POLYGON_TYPE.ROOF && !o.isFixed && o.id === target.attributes?.roofId)
|
.find((o) => o.name === POLYGON_TYPE.ROOF && !o.isFixed && o.id === target.attributes?.roofId)
|
||||||
@ -363,6 +363,10 @@ export const applyKerabOffsetSurgical = (canvas, target, newOffset, options = {}
|
|||||||
// 골짜기(케라바 패턴) 라인과 일반 라인은 각자 독립 핸들러로 처리되어 서로 간섭하지 않는다.
|
// 골짜기(케라바 패턴) 라인과 일반 라인은 각자 독립 핸들러로 처리되어 서로 간섭하지 않는다.
|
||||||
for (const il of roof.innerLines || []) {
|
for (const il of roof.innerLines || []) {
|
||||||
if (!il) continue
|
if (!il) continue
|
||||||
|
// [KERAB-HIP-45-PROTECT 2026-06-15] 케라바 hip(확장라인)은 CORNER-SNAP 금지 —
|
||||||
|
// 호출자(reclick 45° 블록)가 wall 코너에서 45° ray-cast 로 roofLine 까지 뻗는다.
|
||||||
|
// 여기서 recomputeKerabPatternLine 의 t-ratio 매핑을 타면 roofLine 코너로 스냅돼 룰 위반.
|
||||||
|
if (skipKerabHips && il.lineName === 'kerabPatternHip') continue
|
||||||
if (isKerabPatternLine(il)) recomputeKerabPatternLine(il)
|
if (isKerabPatternLine(il)) recomputeKerabPatternLine(il)
|
||||||
else recomputeNormalLine(il)
|
else recomputeNormalLine(il)
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user