Merge pull request '[1423] 설계가져오기 T01 전용 + 2차점 강제 select 반영 — No data/네트워크 에러 분리 + vExt cascade 평행이동' (#886) from dev into prd-deploy

Reviewed-on: #886
This commit is contained in:
ysCha 2026-06-05 11:28:17 +09:00
commit 13a6e7fae9
4 changed files with 73 additions and 44 deletions

View File

@ -1082,39 +1082,49 @@ export default function StuffDetail() {
return return
} }
// T01 / 1 user + 2 ID: firstAgent ( ) // [PLANREQ-FORCE-SELECT 2026-06-05] T01 / 1 user + 2 ID
get({ url: `/api/object/saleStore/${info.saleStoreId}/firstAgent` }).then((res) => { // + 2 + selected
logger.debug('[PLANREQ-DEBUG] firstAgent result', { firstAgentId: res?.firstAgentId }) // 1 (firstAgent) 1
if (!res?.firstAgentId) { // 'No data' (4xx + message) ,
swalFire({ const applyOtherSaleStore = () => {
title: getMessage('stuff.detail.planReq.message.notMatch'),
type: 'alert',
icon: 'warning',
})
return
}
applyFields() applyFields()
setOtherSaleStoreList((prev) => {
const exists = prev.some((o) => o.saleStoreId === info.saleStoreId)
return exists ? prev : [...prev, { saleStoreId: info.saleStoreId, saleStoreName: info.saleStoreName }]
})
setOtherSelOptions(info.saleStoreId) setOtherSelOptions(info.saleStoreId)
form.setValue('otherSaleStoreId', info.saleStoreId) form.setValue('otherSaleStoreId', info.saleStoreId)
form.setValue('otherSaleStoreName', info.saleStoreName) form.setValue('otherSaleStoreName', info.saleStoreName)
form.setValue('otherSaleStoreLevel', info.saleStoreLevel) form.setValue('otherSaleStoreLevel', info.saleStoreLevel)
const firstAgent = { saleStoreId: res.firstAgentId, saleStoreName: res.firstAgentName } }
setSaleStoreList((prev) => { get({ url: `/api/object/saleStore/${info.saleStoreId}/firstAgent` }).then((res) => {
const exists = prev.some((s) => s.saleStoreId === res.firstAgentId) logger.debug('[PLANREQ-DEBUG] firstAgent result', { firstAgentId: res?.firstAgentId })
return exists ? prev : [...prev, firstAgent] applyOtherSaleStore()
}) if (res?.firstAgentId) {
setShowSaleStoreList((prev) => { const firstAgent = { saleStoreId: res.firstAgentId, saleStoreName: res.firstAgentName }
const exists = prev.some((s) => s.saleStoreId === res.firstAgentId) setSaleStoreList((prev) => {
return exists ? prev : [...prev, firstAgent] const exists = prev.some((s) => s.saleStoreId === res.firstAgentId)
}) return exists ? prev : [...prev, firstAgent]
setSelOptions(res.firstAgentId) })
form.setValue('saleStoreId', res.firstAgentId) setShowSaleStoreList((prev) => {
form.setValue('saleStoreName', res.firstAgentName) const exists = prev.some((s) => s.saleStoreId === res.firstAgentId)
form.setValue('saleStoreLevel', '1') return exists ? prev : [...prev, firstAgent]
}).catch(() => { })
// + setSelOptions(res.firstAgentId)
form.setValue('saleStoreId', res.firstAgentId)
form.setValue('saleStoreName', res.firstAgentName)
form.setValue('saleStoreLevel', '1')
}
}).catch((error) => {
// 'No data' 1 2 +select
const message = error?.response?.data?.message
if (message === 'No data') {
applyOtherSaleStore()
return
}
// /
swalFire({ swalFire({
title: getMessage('stuff.detail.planReq.message.notMatch'), title: getMessage('stuff.detail.planReq.message.networkError'),
type: 'alert', type: 'alert',
icon: 'warning', icon: 'warning',
}) })
@ -1878,16 +1888,18 @@ export default function StuffDetail() {
)) || )) ||
null} null}
</div> </div>
<button {session?.storeId === 'T01' && (
type="button" <button
className="btn-origin grey" type="button"
onClick={() => { className="btn-origin grey"
onSearchDesignRequestPopOpen() onClick={() => {
}} onSearchDesignRequestPopOpen()
style={{ display: showButton }} }}
> style={{ display: showButton }}
{getMessage('stuff.planReqPopup.title')} >
</button> {getMessage('stuff.planReqPopup.title')}
</button>
)}
</div> </div>
</td> </td>
</tr> </tr>
@ -2468,7 +2480,7 @@ export default function StuffDetail() {
></button> ></button>
) : null} ) : null}
</div> </div>
{managementState?.tempFlg === '1' ? ( {managementState?.tempFlg === '1' && session?.storeId === 'T01' ? (
<> <>
<button <button
type="button" type="button"

View File

@ -810,6 +810,7 @@
"stuff.detail.tempSave.message3": "二次販売店を選択してください。", "stuff.detail.tempSave.message3": "二次販売店を選択してください。",
"stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?", "stuff.detail.confirm.message1": "販売店情報を変更すると、設計依頼文書番号が削除されます。変更しますか?",
"stuff.detail.planReq.message.notMatch": "設計依頼の販売店情報が一致しないため、インポートできません。", "stuff.detail.planReq.message.notMatch": "設計依頼の販売店情報が一致しないため、インポートできません。",
"stuff.detail.planReq.message.networkError": "設計依頼情報の照会中にネットワークエラーが発生しました。しばらくしてから再度お試しください。",
"stuff.detail.delete.message1": "仕様が確定したものは削除できません。", "stuff.detail.delete.message1": "仕様が確定したものは削除できません。",
"stuff.detail.planList.title": "プランリスト", "stuff.detail.planList.title": "プランリスト",
"stuff.detail.planList.cnt": "全体", "stuff.detail.planList.cnt": "全体",

View File

@ -810,6 +810,7 @@
"stuff.detail.tempSave.message3": "2차 판매점을 선택해주세요.", "stuff.detail.tempSave.message3": "2차 판매점을 선택해주세요.",
"stuff.detail.confirm.message1": "판매점 정보를 변경하면 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?", "stuff.detail.confirm.message1": "판매점 정보를 변경하면 설계의뢰 문서번호가 삭제됩니다. 변경하시겠습니까?",
"stuff.detail.planReq.message.notMatch": "설계의뢰의 판매점 정보가 일치하지 않아 가져올 수 없습니다.", "stuff.detail.planReq.message.notMatch": "설계의뢰의 판매점 정보가 일치하지 않아 가져올 수 없습니다.",
"stuff.detail.planReq.message.networkError": "설계의뢰 정보 조회 중 네트워크 오류가 발생했습니다. 잠시 후 다시 시도해주세요.",
"stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.", "stuff.detail.delete.message1": "사양이 확정된 물건은 삭제할 수 없습니다.",
"stuff.detail.planList.title": "플랜목록", "stuff.detail.planList.title": "플랜목록",
"stuff.detail.planList.cnt": "전체", "stuff.detail.planList.cnt": "전체",

View File

@ -210,13 +210,28 @@ export const applyKerabOffsetSurgical = (canvas, target, newOffset) => {
for (const other of cascadeTargets) { for (const other of cascadeTargets) {
if (!other || other === il) continue if (!other || other === il) continue
let moved = false let moved = false
if (pointOnOldSeg(other.x1, other.y1)) { const hit1 = pointOnOldSeg(other.x1, other.y1)
other.set({ x1: other.x1 + dxVExt, y1: other.y1 + dyVExt }) const hit2 = pointOnOldSeg(other.x2, other.y2)
moved = true // [KERAB-VALLEY-EXT-PARALLEL 2026-06-05] vExt(골짜기 확장라인)는 self-extension
} // 수직/수평 라인이라 한 끝만 cascade 로 끌면 대각선이 된다 (사용자 룰: 대각선은 hip뿐).
if (pointOnOldSeg(other.x2, other.y2)) { // split 된 vExt 세그먼트는 한 끝만 옛 segment 에 닿아도 양 끝을 같은 변위로 평행이동.
other.set({ x2: other.x2 + dxVExt, y2: other.y2 + dyVExt }) if (other.lineName === 'kerabPatternValleyExt' && (hit1 || hit2)) {
other.set({
x1: other.x1 + dxVExt,
y1: other.y1 + dyVExt,
x2: other.x2 + dxVExt,
y2: other.y2 + dyVExt,
})
moved = true moved = true
} else {
if (hit1) {
other.set({ x1: other.x1 + dxVExt, y1: other.y1 + dyVExt })
moved = true
}
if (hit2) {
other.set({ x2: other.x2 + dxVExt, y2: other.y2 + dyVExt })
moved = true
}
} }
if (moved) { if (moved) {
if (typeof other.setCoords === 'function') other.setCoords() if (typeof other.setCoords === 'function') other.setCoords()