feat(est-test): 수량산출 누계 계산과 넣기
- 원본 누계 표지(F·a)를 읽어 계산마다 소계로 다시 구함 - 산출 줄 커서 자리에 누계 넣기, 표지 반올림 방식·자리 반영 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,16 +26,19 @@ const EstQuantity = (() => {
|
||||
if (name) tags.set(match[1], name);
|
||||
}
|
||||
for (const match of text.matchAll(/<div\b[^>]*>([\s\S]*?)<\/div>/gi)) {
|
||||
const markers = [];
|
||||
const markers = [],
|
||||
totals = [];
|
||||
let raised = false;
|
||||
const tag = (name) =>
|
||||
/^r\d+$/.test(name) || /^L\d+$/.test(name)
|
||||
? "\x12"
|
||||
: /^N\d+$/.test(name)
|
||||
? "\x0e"
|
||||
: /^S\d+$/.test(name)
|
||||
? "\x13"
|
||||
: "";
|
||||
: /^[Fa]\d+$/.test(name)
|
||||
? "\x16"
|
||||
: /^N\d+$/.test(name)
|
||||
? "\x0e"
|
||||
: /^S\d+$/.test(name)
|
||||
? "\x13"
|
||||
: "";
|
||||
let body = match[1].replace(/<c\s+nr=(\d+)\s*\/>/gi, (_, id) => {
|
||||
const next = superscripts.has(id),
|
||||
value = next && !raised ? "^(" : !next && raised ? ")" : "";
|
||||
@@ -47,11 +50,12 @@ const EstQuantity = (() => {
|
||||
.replace(/<begin\b[^>]*\bTag=(\d+)[^>]*>/gi, (_, id) => {
|
||||
const name = tags.get(id) || "";
|
||||
if (tag(name) === "\x12") markers.push(name);
|
||||
if (tag(name) === "\x16") totals.push(name);
|
||||
return tag(name);
|
||||
})
|
||||
.replace(/<end\b[^>]*\bTag=(\d+)[^>]*>/gi, (_, id) => tag(tags.get(id) || ""));
|
||||
body = entities(body.replace(/<[^>]*>/g, "").replace(/\r?\n/g, ""));
|
||||
if (body.trim()) rows.push({ LineData: body, markers });
|
||||
if (body.trim()) rows.push({ LineData: body, markers, ...(totals.length && { totals }) });
|
||||
}
|
||||
return { Code: code, Name: name, rows, items, options };
|
||||
}
|
||||
@@ -78,7 +82,7 @@ const EstQuantity = (() => {
|
||||
};
|
||||
return {
|
||||
...row,
|
||||
LineData: row.LineData.replace(/\*개소당|\bPIPE\b|소\s*계|∴/g, ""),
|
||||
LineData: row.LineData.replace(/\*개소당|\bPIPE\b|소\s*계|∴|\x16[^\x16]*\x16/g, ""),
|
||||
Index: 0,
|
||||
SCheck: 0,
|
||||
LinkIndex: 0,
|
||||
@@ -112,6 +116,8 @@ const EstQuantity = (() => {
|
||||
(whole) => actual[part++]?.[0] || whole,
|
||||
);
|
||||
});
|
||||
if (typeof EstQuantityTotal !== "undefined")
|
||||
EstQuantityTotal.apply(sheet, result.rows.slice(1));
|
||||
return {
|
||||
rows: result.rows.slice(1),
|
||||
items: sheet.items.map((item) => ({ ...item, GN: values.get(item.Code) ?? item.GN })),
|
||||
@@ -315,7 +321,7 @@ const EstQuantity = (() => {
|
||||
{ esc, number, byId } = EstApp;
|
||||
byId("work-content").innerHTML =
|
||||
selector(state) +
|
||||
`<div class="business-tools"><label>산출서명 <input data-quantity-name value="${esc(sheet.Name)}"></label><button data-quantity-add-item>수량 항목 추가</button><button data-quantity-add>산출 행 추가</button><button data-quantity-apply>내역 수량 반영</button><button data-action="quantity-sheet-copy">산출서 복사</button><button data-action="quantity-sheet-up">산출서 위로</button><button data-action="quantity-sheet-down">산출서 아래로</button><button data-quantity-delete-sheet>산출서 삭제</button></div><table class="sheet"><thead><tr><th>산출코드</th><th>품명</th><th>규격</th><th>단위</th><th>저장 수량</th><th>재계산 수량</th><th>연결 내역코드</th><th>끝수 처리</th><th>작업</th></tr></thead><tbody>${output.items.map((item, index) => `<tr><td>${esc(item.Code)}</td><td><input data-quantity-item="Name" data-index="${index}" value="${esc(item.Name || "")}" aria-label="품명"></td><td><input data-quantity-item="Size" data-index="${index}" value="${esc(item.Size || "")}" aria-label="규격"></td><td><input data-quantity-item="Unite" data-index="${index}" value="${esc(item.Unite || "")}" aria-label="단위"></td><td>${number(sheet.items[index]?.GN ?? 0)}</td><td>${number(item.GN)}</td><td style="white-space:normal"><input data-quantity-target="${index}" value="${esc(item.TargetCode ?? item.LinkCode ?? "")}" aria-label="연결 내역코드">${targetSelect(state.project, item, "sheet", index)}</td><td>${formatSelect(sheet.items[index], index)}</td><td><button data-quantity-delete-item="${index}">삭제</button></td></tr>`).join("")}</tbody></table>${typeof EstQuantitySheets !== "undefined" ? EstQuantitySheets.excelView(sheet) : ""}<p class="business-note">${esc(output.errors.join(" / "))} 산출 행의 결과 표지로 수량 항목을 연결합니다. 신규 산출서와 지원되지 않는 원본 구조 변경은 JSON으로 저장합니다.</p><table class="sheet"><thead><tr><th>줄</th><th>산출근거 편집</th><th>작업</th></tr></thead><tbody>${sheet.rows.map((row, index) => `<tr><td>${index + 1}</td><td><textarea data-quantity-line="${index}" rows="1" style="min-width:750px" aria-label="산출근거 ${index + 1}">${esc(EstText.display(output.rows[index].LineData))}</textarea></td><td><button data-quantity-add data-index="${index}">아래 추가</button><button data-quantity-move="-1" data-index="${index}" ${index === 0 ? "disabled" : ""}>↑</button><button data-quantity-move="1" data-index="${index}" ${index === sheet.rows.length - 1 ? "disabled" : ""}>↓</button><button data-action="quantity-mark" data-index="${index}">수량 지정</button><button data-action="quantity-free" data-index="${index}">지정 해제</button><button data-quantity-delete-row="${index}">삭제</button></td></tr>`).join("")}</tbody></table>`;
|
||||
`<div class="business-tools"><label>산출서명 <input data-quantity-name value="${esc(sheet.Name)}"></label><button data-quantity-add-item>수량 항목 추가</button><button data-quantity-add>산출 행 추가</button><button data-quantity-apply>내역 수량 반영</button><button data-action="quantity-sheet-copy">산출서 복사</button><button data-action="quantity-sheet-up">산출서 위로</button><button data-action="quantity-sheet-down">산출서 아래로</button><button data-quantity-delete-sheet>산출서 삭제</button></div><table class="sheet"><thead><tr><th>산출코드</th><th>품명</th><th>규격</th><th>단위</th><th>저장 수량</th><th>재계산 수량</th><th>연결 내역코드</th><th>끝수 처리</th><th>작업</th></tr></thead><tbody>${output.items.map((item, index) => `<tr><td>${esc(item.Code)}</td><td><input data-quantity-item="Name" data-index="${index}" value="${esc(item.Name || "")}" aria-label="품명"></td><td><input data-quantity-item="Size" data-index="${index}" value="${esc(item.Size || "")}" aria-label="규격"></td><td><input data-quantity-item="Unite" data-index="${index}" value="${esc(item.Unite || "")}" aria-label="단위"></td><td>${number(sheet.items[index]?.GN ?? 0)}</td><td>${number(item.GN)}</td><td style="white-space:normal"><input data-quantity-target="${index}" value="${esc(item.TargetCode ?? item.LinkCode ?? "")}" aria-label="연결 내역코드">${targetSelect(state.project, item, "sheet", index)}</td><td>${formatSelect(sheet.items[index], index)}</td><td><button data-quantity-delete-item="${index}">삭제</button></td></tr>`).join("")}</tbody></table>${typeof EstQuantitySheets !== "undefined" ? EstQuantitySheets.excelView(sheet) : ""}<p class="business-note">${esc(output.errors.join(" / "))} 산출 행의 결과 표지로 수량 항목을 연결합니다. 신규 산출서와 지원되지 않는 원본 구조 변경은 JSON으로 저장합니다.</p><table class="sheet"><thead><tr><th>줄</th><th>산출근거 편집</th><th>작업</th></tr></thead><tbody>${sheet.rows.map((row, index) => `<tr><td>${index + 1}</td><td><textarea data-quantity-line="${index}" rows="1" style="min-width:750px" aria-label="산출근거 ${index + 1}">${esc(EstText.display(output.rows[index].LineData))}</textarea></td><td><button data-quantity-add data-index="${index}">아래 추가</button><button data-quantity-move="-1" data-index="${index}" ${index === 0 ? "disabled" : ""}>↑</button><button data-quantity-move="1" data-index="${index}" ${index === sheet.rows.length - 1 ? "disabled" : ""}>↓</button><button data-action="quantity-mark" data-index="${index}">수량 지정</button><button data-action="quantity-free" data-index="${index}">지정 해제</button><button data-action="quantity-total" data-index="${index}">누계</button><button data-quantity-delete-row="${index}">삭제</button></td></tr>`).join("")}</tbody></table>`;
|
||||
}
|
||||
// 원본 수량목록 자리수 메뉴(mnuAuto·mnuTrunc·mnuUp·mnuRound): 결과 코드 뒤 방식(1 반올림·2 절사·3 올림)+자리수.
|
||||
function resultFormat(code) {
|
||||
|
||||
Reference in New Issue
Block a user