feat(stmate-test): 3차 화면·데이터 마무리 — 보호표시 · 공종번호 · 직종·노임 · 제비율표 편집 · 차수 칸 저장 · 계약 변환등록 = 울진 계약 STC · 장부 87.6%

- 시험 615 통과 · 브라우저 화면 13개·메뉴 90개 오류 0

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-13 21:00:14 +09:00
co-authored by Claude Opus 5.5
parent e8b76dd65b
commit ffc2401870
36 changed files with 1907 additions and 78 deletions
+19 -1
View File
@@ -4,6 +4,10 @@
* · 22_UI_폼_분석 §3.1 wM_Edt_Hal(적용단가 = 기준단가 × % · 소수 자리 미만 절사/반올림 · 적용단가 0원 제외)
* · STC_필드사전_핵심(AMT_11~51 후보 5칸 · PG_1 = 채택 출처 · PG_11~51 페이지) · Start8x.Ini JMOK1~5·JMK10~50·JEMNM
* 그림코드 = I 코드(DFM uM_ChgCode·uM_DelCode·wM_Boxa 의 Tab_I 「그림코드(Ctrl+I)」 · Act_Sel_I) — 실자료 표본에는 없음
* 보호표시 = wM_Boxa 단가 격자 「보호」 열(√/공란 = True/False · 논리 칸) → 기초·견적단가(M·L·S·W) 행의 COSTN UC 로 읽음
* · 일괄 손질(가격지 채택·기준단가 수정·일괄할증·일괄변경)은 보호 행을 건너뜀(22 §3.1 안내문)
* · 보호해제시 적용단가 자동할증(Chk_Auto_Hal) = 풀 때 그 행에만 일괄할증을 다시 걺
* · B·D 행의 UC 는 산근 편집기 「결과값에 낙찰율적용」(Ck_UC) 자리 — 실무 7건 UC=T ⇔ NAGCD>0 이라 보호로 보지 않음
*/
(function (global) {
"use strict";
@@ -32,6 +36,17 @@
];
const OWN = { M: "MAMT", L: "LAMT", S: "SAMT" };
const isBase = (code) => /^[MLS]/.test(code);
const isProtected = (r) => /^[MLSW]/.test(codeOf(r)) && String(r.UC || "").trim() === "T";
// 보호 켜기·끄기 — 끌 때 autoHal(일괄할증 설정)이 있으면 그 행만 다시 할증(STMATE_UI_CODE_AMT.halAll)
function setProtect(r, on, o) {
if (!/^[MLSW]/.test(codeOf(r))) return null;
r.UC = on ? "T" : "F";
const UA = global.STMATE_UI_CODE_AMT;
if (on || !(o && o.autoHal) || !UA) return { code: codeOf(r), on: Boolean(on), hal: null };
const kind = codeOf(r)[0];
const hal = UA.halAll([r], Object.assign({}, o.autoHal, { kinds: kind, codes: [codeOf(r)] }));
return { code: codeOf(r), on: false, hal: hal[0] || null };
}
// 가격지 이름 — 프로젝트 초기값(JMOK1~5 · 줄임 JMK10~50 · 표시 차례 JEMNM)
function slotNames(ini) {
@@ -109,7 +124,7 @@
function adopt(r, how, o) {
const opt = Object.assign({ skipZero: true }, o || {});
const c = codeOf(r);
if (!isBase(c) || how === "none") return null;
if (!isBase(c) || how === "none" || isProtected(r)) return null;
const cand = candidates(r);
let slot = Number(how),
v = cand[slot - 1];
@@ -168,6 +183,7 @@
rows.forEach((r) => {
const c = codeOf(r);
if (!c || !isBase(c) || !opt.kinds.includes(c[0]) || (only && !only.has(c))) return;
if (isProtected(r)) return;
const cur = appliedPrice(r);
if (!(cur > 0)) return;
const s = adoptedSlot(r),
@@ -216,6 +232,8 @@
num,
codeOf,
isBase,
isProtected,
setProtect,
slotNames,
candidates,
pages,