fix(B07): 편집이 사라지지 않게 하고 확정한 도면을 잠근다
사용자 편의성 점검 15건 중 반영 확정분 12건. 편집 손실 방지 - CAD에 미저장 표시(drawingDirty)를 두고, 도면을 바꾸기 전에 묻는다. 전에는 그은 선이 경고 없이 사라졌다(실측: 캔버스 서명이 원본과 동일). - 도면 전환을 겹쳐 눌러도 늦게 온 응답이 화면을 덮지 않게 가드를 뒀다. - 도면층 삭제·객체 이동을 되돌리기에 실어 Ctrl+Z로 돌아오게 했다. 확정한 도면은 읽기 전용 - runCommand 한 곳에서 보는 명령만 통과시킨다(허용 명시 방식). - 도면을 실을 때 앞 도면의 그리기 도구를 내린다 — 켜 둔 도구가 확정본에도 계속 그렸다. - 확정 버튼 자리를 [현재 도면 확정] / [수정]으로 가른다. 확정 해제는 [수정] 한 곳뿐 — 되돌리기·색 고르기로 확정이 풀리던 경로를 없앴다. 그 밖 - 잠금 도면층(도각·등고선·계류)은 마우스가 스쳐도 하이라이트하지 않는다. - 준비 중 도면 7종도 빈 도각으로 열린다(눌리지 않는 회색 버튼 제거). - 도면층 행이 잘리지 않게 패널을 300px로 넓히고 이름을 줄여 담는다. - 기본 그리기 색을 검정으로 — 흰 종이에 흰 선이라 안 보였다. - 색 고르는 동안 변경 통지가 연발하지 않는다. - 수량표는 앞 단계 산출물이라 도면에서 고치지 못하게 막고 안내한다. - 자동백업 칸을 도면별로 나눈다 — 되살리면 다른 도면에 붙었다. - 횡단 장 id를 시작 측점 기준으로 바꿔 구간이 달라져도 옛 확정이 안 붙는다. - 회사 도각 저장 전에 좌표를 검사하고, 기본 도각으로 되돌리기를 연다. - 횡단 파일이 없어도 나머지 도면 목록은 남는다. - 불러오는 중·실패를 화면에 표시한다. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -5,17 +5,23 @@ import type { JsonDrawingFileSerialized } from '../helpers/import-export-handler
|
||||
import { exportEntitiesAndLayersToJsonString } from '../helpers/import-export-handlers/export-entities-to-json.ts';
|
||||
import { getEntitiesAndLayersFromJsonObject } from '../helpers/import-export-handlers/import-entities-from-json.ts';
|
||||
import {
|
||||
clearDrawingDirty,
|
||||
getCanvas,
|
||||
getDesignMeta,
|
||||
getEntities,
|
||||
getLayers,
|
||||
getScreenCanvasDrawController,
|
||||
isDrawingDirty,
|
||||
isDrawingReadOnly,
|
||||
resetUndoBaseline,
|
||||
setActiveLayerId,
|
||||
setDesignMeta,
|
||||
setEntities,
|
||||
setLayers,
|
||||
} from '../state.ts';
|
||||
import { toast } from 'react-toastify';
|
||||
import { runCommandInput } from '../commands/run-command.ts';
|
||||
import { setRecoveryScope } from '../helpers/autosave.ts';
|
||||
|
||||
export const AISLO_DRAWING_LOAD_MESSAGE = 'aislo:b08:load-drawing';
|
||||
export const AISLO_DRAWING_READY_MESSAGE = 'aislo:b08:drawing-ready';
|
||||
@@ -52,19 +58,25 @@ export function requestDrawingNavigation(direction: 'prev' | 'next') {
|
||||
notifyParent(AISLO_DRAWING_NAVIGATE_MESSAGE, { direction });
|
||||
}
|
||||
|
||||
/** 수량표 값 편집을 부모에 알린다 (확정 상태 롤백 연동). */
|
||||
export function notifyDrawingChangedByTable() {
|
||||
notifyParent(AISLO_DRAWING_CHANGED_MESSAGE);
|
||||
}
|
||||
/**
|
||||
* 수량 산출표 도면층 — 여기 글자는 앞 단계(B05·B06) 산출값이라 B07에서 고치지 않는다
|
||||
* (2026-09-01 사용자 확정). 고치면 그림 글자만 바뀌고 저장되는 수량표는 그대로여서
|
||||
* 화면과 저장값이 어긋났다.
|
||||
*/
|
||||
const QUANTITY_TABLE_LAYER_ID = 'b08-cross-table';
|
||||
|
||||
/**
|
||||
* 더블클릭한 위치의 텍스트(잠금 해제 레이어)를 찾아 내용을 즉시 편집한다.
|
||||
* CAD 테이블(측점 테이블·수량 산출표) 값 셀 수정 수단 — 잠금 레이어는 제외.
|
||||
* CAD 측점 테이블 값 셀 수정 수단 — 잠금 레이어와 수량 산출표는 제외.
|
||||
*/
|
||||
function registerTextDoubleClickEdit() {
|
||||
const canvas = getCanvas();
|
||||
if (!canvas) return;
|
||||
canvas.addEventListener('dblclick', (event: MouseEvent) => {
|
||||
if (isDrawingReadOnly()) {
|
||||
toast.info('확정한 도면입니다. 고치려면 [수정]을 먼저 누르세요.');
|
||||
return;
|
||||
}
|
||||
const drawController = getScreenCanvasDrawController();
|
||||
const bounds = canvas.getBoundingClientRect();
|
||||
const screenPoint = new Point(event.clientX - bounds.left, bounds.bottom - event.clientY);
|
||||
@@ -76,18 +88,24 @@ function registerTextDoubleClickEdit() {
|
||||
);
|
||||
let closest: TextEntity | null = null;
|
||||
let closestDistance = Number.MAX_SAFE_INTEGER;
|
||||
let closestOnQuantityTable = false;
|
||||
for (const entity of getEntities()) {
|
||||
if (!(entity instanceof TextEntity) || lockedLayerIds.has(entity.layerId)) continue;
|
||||
const distanceInfo = entity.distanceTo(worldPoint);
|
||||
if (distanceInfo && distanceInfo[0] < closestDistance) {
|
||||
closestDistance = distanceInfo[0];
|
||||
closest = entity;
|
||||
closestOnQuantityTable = entity.layerId === QUANTITY_TABLE_LAYER_ID;
|
||||
}
|
||||
}
|
||||
if (!closest) return;
|
||||
const fontSize = closest.getTextOptions().fontSize;
|
||||
const tolerance = Math.max((closest.getLabel().length + 2) * fontSize * 0.5, fontSize * 2);
|
||||
if (closestDistance > tolerance) return;
|
||||
if (closestOnQuantityTable) {
|
||||
toast.info('수량표는 횡단설계(B06)에서 고칩니다. 고치고 돌아오면 반영됩니다.');
|
||||
return;
|
||||
}
|
||||
const nextLabel = window.prompt('값 수정', closest.getLabel());
|
||||
if (nextLabel === null || nextLabel === closest.getLabel()) return;
|
||||
closest.setLabel(nextLabel);
|
||||
@@ -108,8 +126,9 @@ export function registerAisloDrawingBridge() {
|
||||
const drawing = JSON.parse(
|
||||
await exportEntitiesAndLayersToJsonString()
|
||||
) as JsonDrawingFileSerialized;
|
||||
// 편집된 수량표 값을 도면과 함께 부모로 돌려준다.
|
||||
// 수량표는 앞 단계 산출값을 그대로 돌려준다 — B07에서는 고치지 않는다.
|
||||
const quantityTable = getDesignMeta()?.quantityTable ?? null;
|
||||
clearDrawingDirty(); // 부모가 받아 저장한다 — 미저장 경고 대상이 아니다
|
||||
notifyParent(AISLO_DRAWING_SAVE_RESPONSE_MESSAGE, { drawing, quantityTable });
|
||||
} catch (error) {
|
||||
const detail = error instanceof Error ? error.message : 'Unable to serialize drawing';
|
||||
@@ -125,9 +144,17 @@ export function registerAisloDrawingBridge() {
|
||||
setLayers(drawing.layers);
|
||||
setActiveLayerId(drawing.layers[0].id);
|
||||
// 실은 도면이 되돌리기의 바닥 — 첫 Ctrl+Z가 백지로 가지 않게 한다.
|
||||
// (미저장 표시도 여기서 내려간다 — 방금 서버 도면을 실었으니 고친 것이 없다.)
|
||||
resetUndoBaseline();
|
||||
// 설계 컨텍스트(제목·측점정보·확정상태·수량표)를 수량 패널에 반영
|
||||
setDesignMeta(event.data.meta ?? null);
|
||||
// 앞 도면에서 켜 둔 그리기 도구를 내린다. 안 내리면 **확정한 도면 위에도**
|
||||
// 그 도구가 계속 그린다 — 읽기 전용은 새 명령만 막기 때문이다(2026-09-01 실측:
|
||||
// 확정본에서 클릭 두 번에 선 2개가 늘었다). 새 도면에서 앞 도면의 작도 도중
|
||||
// 상태를 이어 갈 이유도 없다.
|
||||
runCommandInput('SELECT');
|
||||
// 자동백업을 이 도면 칸으로 옮긴다 — 안 옮기면 백업 한 칸을 서로 덮는다.
|
||||
setRecoveryScope(event.data.meta?.drawingId ?? null);
|
||||
getScreenCanvasDrawController().zoomToFitScreen();
|
||||
notifyParent(AISLO_DRAWING_LOADED_MESSAGE);
|
||||
} catch (error) {
|
||||
@@ -135,8 +162,10 @@ export function registerAisloDrawingBridge() {
|
||||
notifyParent(AISLO_DRAWING_ERROR_MESSAGE, { detail });
|
||||
}
|
||||
});
|
||||
// 부모는 이 통지로 **미저장 여부만** 안다. 확정을 푸는 것은 [수정] 버튼 한 곳뿐이다
|
||||
// (2026-09-01 사용자 확정) — 예전에는 되돌리기·색 고르기까지 확정을 풀었다.
|
||||
window.addEventListener(HtmlEvent.DRAWING_CHANGED, () => {
|
||||
notifyParent(AISLO_DRAWING_CHANGED_MESSAGE);
|
||||
notifyParent(AISLO_DRAWING_CHANGED_MESSAGE, { dirty: isDrawingDirty() });
|
||||
});
|
||||
registerTextDoubleClickEdit();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user