feat(M02): 면적 값 고침이 저장 전 도면 패널 표에 바로 비침 · 이름 · 보내기 취소는 [저장] 때 서버가 기록(112-1·112-2)
- 112-1 면적 표 변환을 공용 파일(spreadsheet_area_table.ts)로 빼 서버 Node 와 브라우저가 한 벌로 씀 · 도면 패널이 칸 고침마다(값 바뀐 표만 · 펼친 동안만) CAD 연결 표 갈기를 보기 전용 갈음(preview)으로 보냄 - 112-2 보낸 범위 이름은 도면 [저장] 요청 안에서 서버가 면적 문서에 둠(놓기만 하고 저장 안 하면 안 생김) · [보내기 취소]는 화면에서만 빼고 면적 [저장] 때 서버가 연결표 줄 · 이름을 뺌 · /name · /unlink 길 삭제 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
@@ -4,10 +4,13 @@
|
||||
* ① 면적 상세 머리 [도면으로 보내기] — 고른 범위 · 저장 안 한 고침은 먼저 저장 물음 · 작은 창 글자 크기(기본 2.5)
|
||||
* → 서버 표 변환 길(`POST /layers/{층}/area/{열}/table` · 41-1)로 표 객체 받음 → 같은 페이지에서 그 열
|
||||
* 도면 상세로 옮기며 넘김(닫힘 변수 · 캐시 · 서버 안 씀) → 도면 손잡이 `placeTable`(놓기 도구 · 41-2)
|
||||
* ② 도면 [저장] — 문서 맨 위 `연결표[]` = {연결(T1…), 시트, 범위, 글자크기, 값(마지막 칸 글 `{시트!A1: 글}`)} ·
|
||||
* 표 style.연결 = 연결 · 도면에서 지운 표는 기록에서 뺌(면적 [저장] 때 서버가 칸 글 · 값을 다시 적음 · 41-1)
|
||||
* ② 도면 [저장] — 문서 맨 위 `연결표[]` = {연결(T1…), 시트, 범위, 이름, 글자크기, 값(마지막 칸 글 `{시트!A1: 글}`)} ·
|
||||
* 표 style.연결 = 연결 · 도면에서 지운 표는 기록에서 뺌(면적 [저장] 때 서버가 칸 글 · 값을 다시 적음 · 41-1) ·
|
||||
* 새 연결 줄의 보낸 범위 이름은 이 [저장] 요청 안에서 서버가 면적 문서에 둠(112-2 · 놓고 저장 안 하면 안 생김)
|
||||
* ③ 도면을 열 때 — 연결표마다 지금 면적 값과 마지막 값이 다르면 알림 한 줄 + [업데이트](`updateTable`)
|
||||
* ④ 표 여러 개 — id 마다 한 줄
|
||||
* ⑥ 이름표 메뉴 [보내기 취소] — 화면에서만 점선 · 이름표를 빼고 면적 화면 「저장 안 한 고침」 ·
|
||||
* 면적 [저장] 문서에 `보내기취소[]` 를 실어 서버가 그 연결표 줄 · 이름을 뺌(도면 표는 남음 · 112-2)
|
||||
* ⑤ 여러 장(82-3) — 놓을 장 = 지금 탭 · 새 T번호 = 모든 장에서 안 쓴 것 · 연결표 줄 `장` = 표가 놓인 장id
|
||||
* (1장 = 빈 값) · 안 실린 장 표 갱신 = 도면 손잡이(받아 둔 장) · 면적 [저장] 때는 서버가 모든 장
|
||||
* ========================================================================== */
|
||||
@@ -117,25 +120,6 @@ async function fetchTable(layer: Layer, column: string, spec: LinkSpec): Promise
|
||||
return data as AreaTable;
|
||||
}
|
||||
|
||||
/** 보낸 범위 이름을 면적 시트에 더함/갱신(104-1 · 처음 놓을 때 1번) — 실패해도 놓기는 이미 끝났으니 토스트만 */
|
||||
async function defineAreaName(
|
||||
layer: Layer,
|
||||
column: string,
|
||||
시트: string,
|
||||
범위: string,
|
||||
이름: string,
|
||||
): Promise<void> {
|
||||
const owner = getActiveOwner();
|
||||
const q = owner && layer !== "system" && layer !== "project" ? `?owner=${enc(owner)}` : "";
|
||||
const res = await fetch(`${API_BASE_URL}/m02/layers/${layer}/area/${enc(column)}/name${q}`, {
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ 시트, 범위, 이름 }),
|
||||
});
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
}
|
||||
|
||||
/** 장마다 `[장id, entities]` — 1장 = 빈 값(서버 `drawing_sheets` 와 같음) */
|
||||
const sheetsOf = (doc: StructureDoc): [string, unknown[]][] => [
|
||||
["", doc.도면?.entities ?? []],
|
||||
@@ -149,29 +133,19 @@ const linkOf = (e: TableEntityJson): string | null => {
|
||||
return typeof id === "string" && id ? id : null;
|
||||
};
|
||||
/** 칸 글 묶음 견줌 — 열쇠 차례와 무관 */
|
||||
const sameValues = (a: Record<string, string> = {}, b: Record<string, string> = {}): boolean => {
|
||||
export const sameValues = (
|
||||
a: Record<string, string> = {},
|
||||
b: Record<string, string> = {},
|
||||
): boolean => {
|
||||
const ka = Object.keys(a);
|
||||
return ka.length === Object.keys(b).length && ka.every((k) => a[k] === b[k]);
|
||||
};
|
||||
|
||||
/** 이름표 메뉴 [보내기 취소](104-3) — 연결표에서 그 줄만 빼고 저장(도면 표는 남음) */
|
||||
async function unlinkTable(at: Selection, 연결: string): Promise<boolean> {
|
||||
const owner = getActiveOwner();
|
||||
const q = owner && at.layer !== "system" && at.layer !== "project" ? `?owner=${enc(owner)}` : "";
|
||||
const res = await fetch(
|
||||
`${API_BASE_URL}/m02/layers/${at.layer}/structures/${enc(at.name)}/unlink${q}`,
|
||||
{
|
||||
method: "POST",
|
||||
credentials: "include",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ 연결 }),
|
||||
},
|
||||
);
|
||||
return res.ok;
|
||||
}
|
||||
|
||||
/** 면적 시트에 겹쳐 보일 「도면으로 보낸 범위」 — 같은 열 도면 `연결표` 에서(받기 실패 = 없음 · 조용히) */
|
||||
export async function sentRanges(at: Selection): Promise<NonNullable<LinkOptions["표시범위"]>> {
|
||||
export async function sentRanges(
|
||||
at: Selection,
|
||||
onCancel: (연결: string) => void,
|
||||
): Promise<NonNullable<LinkOptions["표시범위"]>> {
|
||||
try {
|
||||
const got = await readTemplate(at.layer, "structure", at.name, at.projectId);
|
||||
const rows = (got.문서 as StructureDoc | undefined)?.연결표 ?? [];
|
||||
@@ -181,7 +155,7 @@ export async function sentRanges(at: Selection): Promise<NonNullable<LinkOptions
|
||||
범위이름: row.이름,
|
||||
이름: fill(TEXT.tag, "id", row.연결),
|
||||
설명: fill(fill(fill(TEXT.tip, "id", row.연결), "range", row.범위), "size", row.글자크기),
|
||||
취소: () => unlinkTable(at, row.연결).catch(() => false),
|
||||
취소: async () => (onCancel(row.연결), true), // 화면에서만 — 서버는 면적 [저장] 때
|
||||
}));
|
||||
} catch {
|
||||
return [];
|
||||
@@ -208,8 +182,14 @@ export interface AreaToDrawing {
|
||||
onDrawing: (handle: unknown, at: Selection, doc: StructureDoc) => void;
|
||||
/** 보낸 표 놓기 기다리는 중 — 편집 칸 「저장 안 한 고침」 에 듦 */
|
||||
waiting: () => boolean;
|
||||
/** 떠나기로 함(물음 [확인]) — 기다리던 표 버림 */
|
||||
/** 떠나기로 함(물음 [확인]) · 저장 끝 — 기다리던 표 · 저장 전 보내기 취소를 버림 */
|
||||
drop: () => void;
|
||||
/** 이름표 메뉴 [보내기 취소] — 저장 전 목록에 담음(면적 화면 「저장 안 한 고침」) */
|
||||
cancel: (연결: string) => void;
|
||||
/** 저장 전 보내기 취소한 연결 */
|
||||
cancelled: () => ReadonlySet<string>;
|
||||
/** 면적 저장 문서 — 취소한 연결이 있으면 `보내기취소[]` 를 실음(서버가 줄 · 이름을 뺌) */
|
||||
withCancels: <T extends object>(doc: T) => T;
|
||||
/** 도면에서 Esc 로 놓지 않고 그만둠 — 기다림을 풀고 그 보내기 기록도 뺌 */
|
||||
cancelPlace: () => void;
|
||||
/** 도면 저장 문서 — 맨 위 `연결표` 를 도면의 표에 맞춤 */
|
||||
@@ -227,6 +207,8 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
/** 보낸 표가 도면에 놓이길 기다림 — 떠날 때 「저장 안 한 고침」 물음(`waiting`) */
|
||||
let waiting = false;
|
||||
let waitingId = "";
|
||||
/** 면적 화면에서 [보내기 취소]한 연결 — 면적 [저장] 때 서버가 끊음 */
|
||||
const cancels = new Set<string>();
|
||||
|
||||
/** 글자 크기 작은 창 — 보내기면 크기 · 닫으면 null */
|
||||
const askSize = (spec: { 범위: string }): Promise<number | null> =>
|
||||
@@ -339,14 +321,21 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
|
||||
return {
|
||||
select: (s) => (range = { 시트: s.시트, 범위: s.범위 }),
|
||||
waiting: () => waiting,
|
||||
drop: () => (waiting = false),
|
||||
waiting: () => waiting || cancels.size > 0,
|
||||
drop: () => ((waiting = false), cancels.clear()),
|
||||
cancel: (연결) => void cancels.add(연결),
|
||||
cancelled: () => cancels,
|
||||
withCancels: (doc) => {
|
||||
const { 보내기취소: _old, ...rest } = doc as typeof doc & { 보내기취소?: unknown }; // 앞 저장 것은 떼고
|
||||
return (cancels.size ? { ...rest, 보내기취소: [...cancels] } : rest) as typeof doc;
|
||||
},
|
||||
cancelPlace: () => {
|
||||
waiting = false;
|
||||
fresh.delete(waitingId);
|
||||
},
|
||||
onArea: (at, readOnly, slot) => {
|
||||
waiting = false;
|
||||
cancels.clear();
|
||||
// 범위는 그대로 — 시트가 처음 고름(A1)을 이 갈고리보다 먼저 알림
|
||||
if (readOnly || at.layer === "project") return;
|
||||
const button = createButton({ label: TEXT.send }); // 머리 일반 단추(43-5 · 돌아가기와 같은 높이)
|
||||
@@ -360,6 +349,7 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
const handle = raw as TableHandle;
|
||||
shown = `${at.layer}:${at.name}`;
|
||||
range = null; // 면적 상세를 떠남
|
||||
cancels.clear();
|
||||
fresh = new Map();
|
||||
latest = new Map();
|
||||
const give =
|
||||
@@ -377,11 +367,11 @@ export function createAreaToDrawing(opt: AreaToDrawingOptions): AreaToDrawing {
|
||||
waitingId = id;
|
||||
waiting = true; // 놓기 전 떠나도 물음(놓으면 도면 고침 · [저장] 때 풂)
|
||||
showToast(TEXT.place, "info");
|
||||
// 보낸 범위 이름을 면적 시트에 — 행열 넣기 · 지우기를 따라가게(104-1) · 실패해도 놓기는 그대로
|
||||
void defineAreaName(at.layer, at.name, 시트, 범위, 이름).catch(() => {});
|
||||
// 보낸 범위 이름(104-1)은 도면 [저장] 요청 안에서 서버가 면적 문서에 둠(112-2 · 여기서 안 씀)
|
||||
}
|
||||
}
|
||||
if (doc.지운연결?.length) showToast(fill(TEXT.rangeGone, "ids", doc.지운연결.join(" · ")), "info");
|
||||
if (doc.지운연결?.length)
|
||||
showToast(fill(TEXT.rangeGone, "ids", doc.지운연결.join(" · ")), "info");
|
||||
void checkStale(handle, at, doc);
|
||||
},
|
||||
withLinks: (doc) => {
|
||||
|
||||
Reference in New Issue
Block a user