feat(807-1): 엑셀 불러오기 = 수식 문서 · 단가산출 · 일위대가 하나씩 개인 층으로 · 원문 패널 기초 찾기 + 「어디서 왔나」 카드

- 임도품셈 판 대응표 CSV 새 자리(STmate/old/30_원자료) — 불러오기 시험 26 실패 → 0
- 가져온 식 SK = 수식 문서(멈춘 wip/802-4b-1 M02_Doc_Import 를 메인 판에 다시 얹음 · 빈 산근 = 엑셀 0 원 줄) —
  줄 쌓기 「수식」 탭 길 열림 · 셈 = 단가기준(엑셀 값 기억 | 연결 값) · 화면 캐시 기록 · 수식 길 저장 `단가기준`
- 1,021 블록 전수(실무 여덟 + 표본 밖 셋) 엑셀 검산 · 엑셀 전후 · 우리 전후 모두 같음 · 셈됨 줄지 않음
- 옮기기 도구 「가져온식」 상태 걷음(가져온 줄 문서로 대조)
- [내 일위대가로] = 호표 하나 + 하위 → 개인 층 SC · 부르는 단산 = 가져온 식 SK(같은 내용 = 있는 것 · 못 이은 줄 = 고정)
- [내 단가산출로] = 단산 블록 판 → 개인 층 가져온 식 SK(개인 층이면 [가져온 식으로 열기] 숨김)
- 원문 패널(M01 로직 · M02 단가산출) 맨 위 「단가산출 기초 찾기」 · 가져온 식 SK 첫 화면 = 「어디서 왔나」 카드
  (프로그램 · 파일 · 블록 · 행 · 가져온 때 · 표지 · 엑셀 글의 품셈 절 글만)
- 수식 탭 [엑셀 단가 그대로 | 우리 단가로](단가산출 화면 · 저장 뒤 페이지 문서 단가기준 맞춤)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-11-08 17:11:09 +09:00
co-authored by Claude Opus 5.5
parent 5a0144004d
commit 9c803024e0
25 changed files with 1465 additions and 58 deletions
+3
View File
@@ -11,6 +11,7 @@ import { createBadge } from "@ui/ui_template_badge";
import { createButton } from "@ui/ui_template_button";
import { eqText } from "@ui/ui_template_equation";
import { showConfirmDialog } from "@ui/ui_template_elements";
import type { Basis } from "../common_util/common_util_formula_doc_import";
import { ft } from "./formula_doc_text";
export type CopyJob = "단가갱신" | "재생성";
@@ -22,6 +23,8 @@ export interface CopyMark {
단가새값?: boolean;
문서새판?: string[];
따로?: boolean;
/** 가져온 식(엑셀 불러오기 · 807-1) 단가기준 — 엑셀 = 엑셀 값 기억 · 우리 = 연결 값 */
단가기준?: Basis;
}
export interface CopyOptions {
+2
View File
@@ -72,6 +72,8 @@ const TEXT = {
Changed: ["바뀐 자원", "Changed resources"],
Before_After: ["계", "Sum"],
Job_Done: ["적용함", "Applied"],
Basis_Excel: ["엑셀 단가 그대로", "Excel prices"],
Basis_Ours: ["우리 단가로", "Our prices"],
Dirty_First: [
"저장 안 한 고침이 있음 — [저장] 또는 [되돌림] 먼저",
"Save or discard edits first",
+27 -1
View File
@@ -25,6 +25,8 @@ import {
} from "@ui/ui_template_elements";
import { blankDoc, type FormulaDoc } from "../common_util/common_util_formula_doc";
import { calcDoc, type DocAnswer } from "../common_util/common_util_formula_doc_calc";
import { importView, type Basis } from "../common_util/common_util_formula_doc_import";
import { createSegment } from "@ui/ui_template_segment";
import type { DocTable } from "../common_util/common_util_formula_doc_table";
import { createDocCache, type DocRecord } from "../common_util/common_util_formula_doc_cache";
import { lineMap } from "../common_util/common_util_formula_doc_view";
@@ -170,7 +172,8 @@ export function createStackScreen(opt: StackScreenOptions) {
};
const recalc = (): void => {
if (!doc) return;
answer = calcDoc(doc, cache.links, usable());
const basis = mark?.단가기준; // 가져온 식(807-1) — 서버 셈과 같은 보기
answer = calcDoc(basis ? importView(doc, basis) : doc, cache.links, usable());
if (cache.takeMissing()) ask();
};
/** 캐시에 없는 연결 — 뒤에서 서버 기록을 받아 더함 */
@@ -275,6 +278,7 @@ export function createStackScreen(opt: StackScreenOptions) {
});
const busy = dirty();
const tools = [
...(mark?.단가기준 && opt.page ? [basisPick(mark.단가기준)] : []), // 모달 = 머리 판 단추(793-3b)
...(cp && edit() && key ? copyTools(true, (job) => void runJob(job)) : []),
...(edit() && key && !opt.page
? [
@@ -380,6 +384,28 @@ export function createStackScreen(opt: StackScreenOptions) {
if (await askJob(job, got, cache.names)) await save({ 할일: job, 판: version }, ft("Job_Done"));
};
/** 가져온 식 [엑셀 단가 그대로] · [우리 단가로](807-1) — 저장(서버가 그 기준으로 다시 셈) */
const basisPick = (now: Basis): HTMLElement => {
const seg = createSegment({
options: [
{ value: "엑셀", label: ft("Basis_Excel") },
{ value: "우리", label: ft("Basis_Ours") },
],
value: now,
size: 28,
onChange: (v) => {
if (v === now) return;
if (!edit() || dirty()) {
seg.set(now);
return void showToast(ft("Dirty_First"), "warning");
}
void save({ 단가기준: v, 판: version }, ft("Job_Done")).then((ok) => ok || seg.set(now));
},
});
seg.root.dataset.importBasis = now;
return seg.root;
};
let loading: Promise<void> = Promise.resolve();
const save = async (job?: Record<string, unknown>, done = ft("Saved")): Promise<boolean> => {
await loading; // 새 로직 저장 뒤 여는 중이면 다 읽고(캐시 이어 받음)