fix(M02 실무자료): 339 덧고침 — 확인 창 표 꼴 · 만들기 뒤 사전조합 목록 갱신 · 엑셀 보기 창 제안 수 다시 읽음

- 확인 창 줄 표: 한글 낱말 단위 줄바꿈 · 품명 · 규격 최소 폭 · 옵션 · 품 비교 항목마다 한 줄 · 단추 칸 세로 쌓음(좁게)
- 별칭 장부 표: 품명 · 규격 같은 손질
- 만들기(확인 창 · 엑셀 보기 창 일괄) 뒤 document 알림 → 좌측 「일위대가 사전조합」 목록 다시 읽음
- 엑셀 보기 창: 뒤 셈 중이면 3 초마다 목록 「제안 n/m」 다시 읽음 · 펼침 표 숫자 판정 칸 = 맞음 n · 다른 점 n
- 품 비교 판정 함수 · 서버 그대로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWh5wNNycMkbwMpACz1rte
This commit is contained in:
2026-10-16 01:09:47 +09:00
co-authored by Claude Opus 5.5
parent 933c4c5d71
commit 7f33ffe2bd
7 changed files with 110 additions and 22 deletions
@@ -1,9 +1,10 @@
/* =============================================================================
* M02_MasterTemplete_Hopyo_Sheet.ts
* 일위대가 실무자료 엑셀 보기 창(PLAN 329 · 338-3) — 큰 모달 · 왼쪽 = 올린 엑셀을 연 것처럼 읽기 전용 시트(A00 산출근거
* 스프레드시트 · 탭 일위대가 · 단가산출) · 오른쪽 = 호표 목록(체크 · 찾기 · 제안 n/m) + [고른 n개 확인하고 만들기].
* 스프레드시트 · 탭 일위대가 · 단가산출) · 오른쪽 = 호표 목록(체크 · 찾기 · 제안 n/m — 뒤 셈 중이면 3 초마다 다시)
* + [고른 n개 확인하고 만들기].
* · 목록 누름 → 시트에서 그 호표 영역(B열 ~ 끝 열) 고름 · 칸 누름 → 그 행 호표를 목록에서 강조 · 영역 고름
* · ① [고른 n개 확인하고 만들기] = 고른 호표마다 서버 보기 → 펼침 표(넣을 줄 = 체크 제안 · 빠질 줄 · 셈 중 ·
* · ① [고른 n개 확인하고 만들기] = 고른 호표마다 서버 보기 → 펼침 표(넣을 줄 = 체크 제안 · 빠질 줄 · 셈 중 또는 맞음 · 다른 점 수 ·
* [확인 창 열기]) ② [이대로 n개 만들기] = 하위 호표부터 차례로 `/hopyo-build`(몸 = 그 호표 체크 줄) —
* 펼쳐 보이고 한 번 누름 = 사용자 확인 · 결과 표(사전조합 키 · 빠진 줄 · 값 차이) ·
* `onImport` 가 있으면 호표마다 알림([로직 추가] 참조 줄)
@@ -32,14 +33,17 @@ import {
type HopyoOne,
type HopyoScope,
type HopyoSpan,
type HopyoView,
} from "./M02_MasterTemplete_Hopyo_Api";
import {
bodyOf,
draftKey,
HOPYO_BUILT,
leftOut,
loadDraft,
openHopyoCheck,
partsOf,
POLL_MS,
toTarget,
} from "./M02_MasterTemplete_Hopyo_Check";
import { builtWord } from "./M02_MasterTemplete_Hopyo_Choose";
@@ -239,6 +243,18 @@ export function openHopyoSheet(opt: HopyoSheetOptions): void {
});
}
/** 뒤 숫자 판정 셈 중이면 3 초 뒤 목록 「제안 n/m」 다시 읽음 — 셈 끝 · 창 닫음 · 못 읽음이면 멈춤 */
function poll(file: HopyoView): void {
if (!file.셈 || file.셈.끝) return;
window.setTimeout(async () => {
const next = closed ? null : await readHopyo(opt.scope, opt.key).catch(() => null);
if (!next || closed) return;
briefs = next.호표;
paintList();
poll(next);
}, POLL_MS);
}
async function load(): Promise<void> {
try {
const [file, grid] = await Promise.all([
@@ -249,6 +265,7 @@ export function openHopyoSheet(opt: HopyoSheetOptions): void {
briefs = file.호표;
spans = grid instanceof Error ? [] : grid.호표;
paintList();
poll(file);
if (grid instanceof Error) return void left.replaceChildren(note(grid.message));
await mountSheet(grid);
if (opt.단산행 !== undefined) sheet?.select(rowsText(opt.단산행), DANSAN);
@@ -300,7 +317,11 @@ export function openHopyoSheet(opt: HopyoSheetOptions): void {
const h = one.호표;
const d = loadDraft(draftKey(opt.scope, opt.key, h.번));
const out = Object.entries(leftOut(h.줄, d));
const calc = h.셈 && !h.셈.끝 ? `셈 중 ${h.셈.한}/${h.셈.모두}` : "";
const tally = (s: string): number => h.줄.filter((l) => l.맞춤.상태 === s).length;
const calc =
h.셈 && !h.셈.끝
? `셈 중 ${h.셈.한}/${h.셈.모두}`
: `맞음 ${tally("맞음")} · 다른 점 ${tally("다른 점")}`;
const brief = briefs.find((x) => x.번 === h.번) ?? h;
return el("tr", {
attrs: { "data-review": String(h.번) },
@@ -395,6 +416,7 @@ export function openHopyoSheet(opt: HopyoSheetOptions): void {
} finally {
hideLoadingOverlay();
}
if (ok) document.dispatchEvent(new Event(HOPYO_BUILT));
result.replaceChildren(table(["호표", "사전조합", "빠진 줄", "값 차이(참고)"], rows));
showToast(`만듦 ${ok} / ${order.length}`, ok === order.length ? "success" : "warning");
}