Merge remote-tracking branches 'origin/sub_laptop_5' and 'origin/sub_laptop_8' into sub_laptop_6
This commit is contained in:
@@ -30,7 +30,7 @@ export interface CheckItem {
|
||||
why: string;
|
||||
}
|
||||
|
||||
const BLANK_WHY = "금액 모름 — 단가연결 칸 램프 · 이은 호표의 빈 줄을 확인";
|
||||
const BLANK_WHY = "금액 모름 — 단가연결 칸 ● · 이은 호표의 빈 줄을 확인";
|
||||
|
||||
/** 빈 줄(설계내역서 줄마다 하나 · 까닭 모음) · 그 밖 확인 줄(탭 · 키마다 하나) · 알림 글 */
|
||||
export function checkItems(
|
||||
@@ -175,7 +175,7 @@ export function createCheckPanel(refresh: HTMLElement, goto: (link: Link) => voi
|
||||
const made = checkItems(sheets, next);
|
||||
items = [...made.items, ...made.others];
|
||||
const blank = [
|
||||
head(`빈 줄 ${made.items.length}`),
|
||||
head(`금액 빈 줄 ${made.items.length}`),
|
||||
...(made.items.length ? [list(made.items, 0)] : []),
|
||||
];
|
||||
const others = made.others.length
|
||||
|
||||
@@ -21,7 +21,7 @@ import {
|
||||
|
||||
export type LinkMode = "popup" | "link";
|
||||
|
||||
const LINK_LABEL: Record<LinkMode, string> = { link: "하이퍼링크", popup: "팝업" };
|
||||
const LINK_LABEL: Record<LinkMode, string> = { link: "탭 이동", popup: "곁 창" };
|
||||
|
||||
/** 행 누름 길 — 모르는 값 · 못 읽음 = 팝업 */
|
||||
export function linkMode(): LinkMode {
|
||||
|
||||
@@ -86,7 +86,7 @@ async function preview(code: string, given: Row, rate: unknown, picks: unknown):
|
||||
const label = (text: string, unit: string): string => (unit ? `${text} (${unit})` : text);
|
||||
const KIND_TEXT: Record<string, string> = {
|
||||
logic: "단가산출",
|
||||
precombo: "일위대가 사전조합",
|
||||
precombo: "일위대가(자료집)",
|
||||
combo: "구조물 조합",
|
||||
dg: "일위대가 호표",
|
||||
sg: "단가산출 호표",
|
||||
|
||||
@@ -97,7 +97,10 @@ export function createLiveCalc(
|
||||
if (mine !== seq || me.signal.aborted) return;
|
||||
ctrl = null;
|
||||
failedSig = sig;
|
||||
showToast(`새 산근 단가를 못 받음 — [저장] 때 다시 셈 · ${String(error)}`, "warning");
|
||||
showToast(
|
||||
`새 단가산출 단가를 못 받음 — [저장] 때 다시 셈 · ${String(error)}`,
|
||||
"warning",
|
||||
);
|
||||
settle(null, user);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import "@ui/ui_template_general_layout.css";
|
||||
import "./B09_Estimation_UI_Page.css";
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import { API_BASE_URL, ROUTES } from "@config/config_frontend";
|
||||
import { createWorkflowLayout } from "@ui/ui_template_workflow_layout";
|
||||
import { createText } from "@ui/ui_template_text";
|
||||
import { createBanner } from "@ui/ui_template_banner";
|
||||
@@ -32,6 +32,7 @@ import { ui_locales, currentLanguageIndex } from "@ui/ui_template_locale";
|
||||
import { clearState, readState, writeState } from "../A00_Common/b_page_state";
|
||||
import { workflowSteps } from "../A00_Common/b_page_scaffold";
|
||||
import { moveStage, WORKFLOW_STEP_ROUTES } from "../A00_Common/b_workflow_nav";
|
||||
import { navigateTo } from "../A00_Common/router";
|
||||
import { computeBase, type Row } from "./B09_Estimation_Calc_Base";
|
||||
import { computeEstimation } from "./B09_Estimation_Calc_Bill";
|
||||
import { computeLabor, daegaPrice } from "./B09_Estimation_Calc_Labor";
|
||||
@@ -381,7 +382,7 @@ export function renderB09Estimation(root: HTMLElement): void {
|
||||
});
|
||||
save.dataset.b09Save = "";
|
||||
// 카드 = 좌측 패널 공용 카드(269 · 「구조물 배치」 양식)
|
||||
const section = createPanelCard("데이터 점검", true); // 311 기본 접힘
|
||||
const section = createPanelCard("내역 점검", true); // 311 기본 접힘
|
||||
section.append(refresh, check.list);
|
||||
// 303-1 · 304-1 하단 고정 줄 — [박스보기|호표보기] · [하이퍼링크|팝업] · 초안 단추 · [?][<][>][초기화]
|
||||
const actions = createDock([save, reset], () => isGroupTab(current) && show(current));
|
||||
@@ -420,6 +421,18 @@ export function renderB09Estimation(root: HTMLElement): void {
|
||||
if (go) void moveStage(projectId, goNext, [{ name: "원가 계산 단계 완료", run: complete }]);
|
||||
});
|
||||
});
|
||||
// 703-4 진행 판 · ☰ 서랍(같은 단계 막대) 끝 = M02 「내 자료집」(일위대가 · 구조물 조합) 길
|
||||
layout.root.querySelector(".ui-workflow-layout__steps.is-vertical")?.append(
|
||||
createButton({
|
||||
label: "내 자료집(일위대가 · 구조물 조합)",
|
||||
variant: "pill",
|
||||
onClick: () =>
|
||||
void askProjectLeave().then((go) => {
|
||||
if (go)
|
||||
navigateTo(ROUTES.M02_MASTER_TEMPLATE, { open: "일위대가조합", root: "personal" });
|
||||
}),
|
||||
}),
|
||||
);
|
||||
root.append(layout.root);
|
||||
show(current);
|
||||
// 572-2 떠남 물음 — 고침 = 세션 칸(불러온 뒤) · 저장 = 단계 이동과 같은 길
|
||||
|
||||
@@ -65,7 +65,7 @@ export const blankRows = (sheets: Row): Row[] =>
|
||||
/** 「빈 줄 n · 미완성」 띠 글(701-3) — 빈 줄 0 = null */
|
||||
export const unfinished = (sheets: Row): string | null => {
|
||||
const n = blankRows(sheets).length;
|
||||
return n ? `빈 줄 ${n} · 미완성 — 금액은 아는 줄까지 · 인쇄 · 확정은 빈 줄 0 일 때만` : null;
|
||||
return n ? `금액 빈 줄 ${n} · 미완성 — 금액은 아는 줄까지 · 인쇄 · 확정은 빈 줄 0 일 때만` : null;
|
||||
};
|
||||
|
||||
/** 위 탭(181-1) — [위 탭 이름, 아래 탭들] · 아래 탭 하나뿐 = 위 탭 단독 · 첫 아래 탭 = 위 탭 키 */
|
||||
|
||||
@@ -54,18 +54,18 @@ export const buildLabor: TabBuild = ({ sheets, payload }) =>
|
||||
priceList(
|
||||
sheets.labor || [],
|
||||
"단가(원/인)",
|
||||
`굳힌 단가(${madeText(payload)}) 기준 · 바꾸려면 [업데이트]`,
|
||||
`이 공사 단가 책(${madeText(payload)}) 기준 · 새 노임은 [업데이트]`,
|
||||
);
|
||||
|
||||
export const buildExpense: TabBuild = ({ sheets, payload }) =>
|
||||
priceList(
|
||||
sheets.expense || [],
|
||||
"기준가(천원)",
|
||||
`굳힌 단가(${madeText(payload)}) 기준 · 바꾸려면 [업데이트]`,
|
||||
`이 공사 단가 책(${madeText(payload)}) 기준 · 새 노임은 [업데이트]`,
|
||||
);
|
||||
|
||||
function madeText(payload: Row): string {
|
||||
return payload.book?.made ? `${dateText(String(payload.book.made))} 굳힘` : "아직 안 굳힘";
|
||||
return payload.book?.made ? `${dateText(String(payload.book.made))} 정함` : "아직 안 정함";
|
||||
}
|
||||
|
||||
export const buildBasis: TabBuild = ({ sheets }): TabTable => {
|
||||
|
||||
@@ -69,9 +69,9 @@ export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
total: { name: "순공사비 계(관급 제외)", ...direct },
|
||||
frozen: 1,
|
||||
hint:
|
||||
"줄을 우클릭하면 항목 추가 · 줄 삭제 · 옮김 · 단가연결 칸 램프를 누르면 일위대가 · 단가산출 연결" +
|
||||
"줄을 우클릭하면 항목 추가 · 줄 삭제 · 옮김 · 단가연결 칸 ● 을 누르면 일위대가 · 단가산출 연결" +
|
||||
(direct.blank
|
||||
? ` · 빈 줄 ${direct.blank} — 계는 아는 금액만 · 원가계산서도 아는 금액까지 · 인쇄 · 확정은 빈 줄 0 일 때만`
|
||||
? ` · 금액 빈 줄 ${direct.blank} — 계는 아는 금액만 · 원가계산서도 아는 금액까지 · 인쇄 · 확정은 빈 줄 0 일 때만`
|
||||
: ""),
|
||||
editOnDouble: true,
|
||||
editable: (i, key) => {
|
||||
|
||||
@@ -91,7 +91,7 @@ async function postPersonal(body: Row): Promise<{ ok: boolean; status: number; g
|
||||
async function savePersonal(ctx: TabContext, block: Row): Promise<void> {
|
||||
let name = await askText({
|
||||
title: "내 자료집에 저장",
|
||||
message: "개인 층 일위대가 사전조합으로 — 넣을 값 · 고른 자재 · 줄 수량 고친 칸까지",
|
||||
message: "내 자료집 일위대가로 — 옵션 값 · 고른 자재 · 줄 수량 고친 칸까지",
|
||||
value: block.name || "",
|
||||
okLabel: "저장",
|
||||
});
|
||||
|
||||
@@ -41,21 +41,21 @@ export function askInputs(apply: ApplyRef, code: string, name: string, old?: Row
|
||||
(got) => {
|
||||
const logic = got.로직[0] ?? null;
|
||||
openLaborInput({
|
||||
title: `${code} ${name}`.trim(),
|
||||
title: name || code, // 703-4 번호 = 알림 글 끝(자세히)
|
||||
logic,
|
||||
values: old?.given || {},
|
||||
memo: null,
|
||||
rate: old?.rate ?? null,
|
||||
readOnly: false,
|
||||
okLabel: "연결",
|
||||
notice: "새 산근 = 단가산출근거 뒤 번호 · 단가는 연결 뒤 서버가 바로 셈",
|
||||
notice: `새 단가산출(산근) = 단가산출근거 끝 호표 · 금액은 연결 뒤 바로 셈 · 번호 ${code}`,
|
||||
done: (next) => {
|
||||
const unit = String(logic?.결과단위 || "")
|
||||
.replace(/^원\//, "")
|
||||
.replace(/^[\d.]+/, "");
|
||||
const ref = { tab: "logic", code, name, given: next.입력값, rate: next.켜쌓기율 };
|
||||
apply({ ...ref, picks: old?.picks ?? null }, { name, unit });
|
||||
showToast("연결함 — 새 산근 단가 셈 중", "success");
|
||||
showToast("연결함 — 단가 셈 중", "success");
|
||||
},
|
||||
});
|
||||
},
|
||||
@@ -194,7 +194,7 @@ export async function openPriceLink(o: PriceLinkOpts): Promise<void> {
|
||||
((tab === "dg" ? o.hopyo?.dg : o.hopyo?.sg) ?? []).map((r) => ({
|
||||
kind: tab,
|
||||
key: String(r.key),
|
||||
tag: tab === "dg" ? `대가${r.no}` : `산근 ${r.no}호표`,
|
||||
tag: tab === "dg" ? `일위대가 ${r.no}호` : `단가산출 ${r.no}호`,
|
||||
name: String(r.name || ""),
|
||||
sub: String(r.spec || ""),
|
||||
unit: String(r.unit || ""),
|
||||
@@ -206,7 +206,7 @@ export async function openPriceLink(o: PriceLinkOpts): Promise<void> {
|
||||
key: `${r.layer}:${r.owner ?? ""}:${r.key}`,
|
||||
tag: "구조물 조합",
|
||||
name: itemName(r),
|
||||
sub: `${LAYER_TEXT[r.layer ?? "system"]} · ${r.key}`,
|
||||
sub: LAYER_TEXT[r.layer ?? "system"], // 703-4 번호 숨김
|
||||
unit: String(r.단위 || ""),
|
||||
onPick: () =>
|
||||
pick({
|
||||
@@ -225,12 +225,12 @@ export async function openPriceLink(o: PriceLinkOpts): Promise<void> {
|
||||
extra: [...combos, ...hop("dg"), ...hop("sg")],
|
||||
kindFilter: [
|
||||
{ value: "logic", text: "단가산출" },
|
||||
{ value: "precombo", text: "일위대가 사전조합" },
|
||||
{ value: "precombo", text: "일위대가(자료집)" },
|
||||
{ value: "combo", text: "구조물 조합" },
|
||||
...(o.hopyo
|
||||
? [
|
||||
{ value: "dg", text: "일위대가 호표" },
|
||||
{ value: "sg", text: "단가산출 호표" },
|
||||
{ value: "dg", text: "이 공사 일위대가" },
|
||||
{ value: "sg", text: "이 공사 단가산출" },
|
||||
]
|
||||
: []),
|
||||
],
|
||||
|
||||
@@ -39,7 +39,7 @@ export const GROUP_TABS: TabId[] = ["dg", "machine_blocks", "sg"];
|
||||
export const isGroupTab = (tab: TabId): boolean => GROUP_TABS.includes(tab);
|
||||
|
||||
/** 단추 글 = 그 보기 이름(304-1 좌측 스위치) */
|
||||
export const viewLabel = (view: GroupView): string => (view === "cards" ? "박스보기" : "호표보기");
|
||||
export const viewLabel = (view: GroupView): string => (view === "cards" ? "카드 보기" : "표 보기");
|
||||
|
||||
type Saved = Record<string, unknown> | null;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ import { raw } from "./B09_Estimation_UI_Tabs_Sangeun";
|
||||
import { HOPYO_TAG, hopyoCellClass, hopyoGrid } from "@ui/ui_template_hopyo_grid";
|
||||
|
||||
const EMPTY =
|
||||
"연결 없음 — 연결된 구조물 조합 사본(일위대가)이 없음 · B05 · B06 에서 조합을 고르고 [저장]";
|
||||
"일위대가 없음 — 이 공사에 고른 구조물 조합이 없음 · B05 · B06 에서 구조물 조합을 고르고 [저장] · 또는 설계내역서 오른쪽 재료 창고";
|
||||
const BLANK = "빈 줄은 금액을 모르는 줄(합계는 아는 줄만)";
|
||||
/** 「빈 줄 n」 작은 글 · 풍선 = 빈 줄 이름 */
|
||||
const blankNote = (b: Row): string => (b.blank ? `빈 줄 ${b.blank}` : "");
|
||||
|
||||
@@ -28,7 +28,7 @@ const hint = (sheets: Row, payload: Row): string => {
|
||||
const fixed = Number((payload.summary || {}).fixed) || 0;
|
||||
return [
|
||||
HINT,
|
||||
...(n ? [`빈 줄 ${n} — 집계에서 빠짐(좌측 데이터 점검)`] : []),
|
||||
...(n ? [`금액 빈 줄 ${n} — 집계에서 빠짐(왼쪽 내역 점검)`] : []),
|
||||
...(fixed ? [`고정 줄 ${fixed} — 이은 단가 없어 집계에서 빠짐`] : []),
|
||||
].join(" · ");
|
||||
};
|
||||
|
||||
@@ -100,7 +100,7 @@ function billRows(bill: Row | undefined): DataRow[] {
|
||||
material: r.material ?? null,
|
||||
expense: r.expense ?? null,
|
||||
});
|
||||
const blank = direct.blank ? ` · 빈 줄 ${direct.blank} — 아는 금액만` : "";
|
||||
const blank = direct.blank ? ` · 금액 빈 줄 ${direct.blank} — 아는 금액만` : "";
|
||||
return [
|
||||
...top.map((r: Row) => ({
|
||||
key: `bill:${r.key}`,
|
||||
@@ -243,8 +243,8 @@ export const buildTotal: TabBuild = (ctx): TabTable => {
|
||||
money("expense", "경비"),
|
||||
qty("rate", "요율(%)", 5),
|
||||
money("hand", "수기 입력", undefined, 2),
|
||||
text("note", "산식", 320),
|
||||
text("candidate", "요율 출처", 260),
|
||||
text("note", "계산식", 320),
|
||||
text("candidate", "요율 근거", 260),
|
||||
],
|
||||
rows,
|
||||
total: grand,
|
||||
@@ -253,7 +253,7 @@ export const buildTotal: TabBuild = (ctx): TabTable => {
|
||||
level: nameLevel(rows),
|
||||
mergeSame: ["part"],
|
||||
banner: unfinished(ctx.sheets) ?? undefined,
|
||||
hint: "맨 위 내역 줄을 누르면 설계내역서 그 줄로 · 요율 칸에 적으면 사용자 값 · 지우거나 출처 칸을 누르면 자동 값",
|
||||
hint: "맨 위 내역 줄을 누르면 설계내역서 그 줄로 · 요율 칸에 적으면 사용자 값 · 지우거나 근거 칸을 누르면 자동 값",
|
||||
editable: (i, key) =>
|
||||
(key === "rate" && RATE_KEYS.has(String(rows[i]?.key))) ||
|
||||
(key === "hand" && String(rows[i]?.key) in HAND),
|
||||
|
||||
@@ -160,7 +160,7 @@ export function createSchedulePanel(user: () => Row, setUser: (next: Row) => voi
|
||||
holidayCaption.textContent = "공휴일 넣기(그 밖 법정공휴일은 늘 넣음)";
|
||||
holidayBox.append(holidayCaption, ...checks);
|
||||
|
||||
const section = createPanelCard("공기 옵션", true); // 311 기본 접힘
|
||||
const section = createPanelCard("공사기간 조건", true); // 311 기본 접힘
|
||||
section.dataset.b09SchedulePanel = "";
|
||||
section.style.display = "none"; // 원천(서버 공기 자료)이 오면 보임 · hidden 은 공용 카드 flex 가 덮음
|
||||
section.append(
|
||||
|
||||
@@ -263,7 +263,7 @@ export function buildScheduleSum(ctx: TabContext): TabTable | string {
|
||||
frozen: 2,
|
||||
mergeSame: ["label"],
|
||||
rowClass: (i) => (rows[i].key === "span" || rows[i].key === "start" ? "is-title" : null),
|
||||
hint: "공사기간 = 준비기간 + 작업일수 + 비작업일수 + 정리기간 · 착공 = 「연.월」 또는 「연.월.일」(왼쪽 「공기 옵션」과 같은 값) · 강수 · 혹서 · 공휴일 칸은 더블클릭으로 고침(빈칸 = 기본값)",
|
||||
hint: "공사기간 = 준비기간 + 작업일수 + 비작업일수 + 정리기간 · 착공 = 「연.월」 또는 「연.월.일」(왼쪽 「공사기간 조건」과 같은 값) · 강수 · 혹서 · 공휴일 칸은 더블클릭으로 고침(빈칸 = 기본값)",
|
||||
tip: (i, key) => {
|
||||
const m = months[monthOf(key)];
|
||||
if (!m || rows[i].key !== "b") return null;
|
||||
|
||||
Reference in New Issue
Block a user