fix(M01): 계산 멈춤에도 수량 칸 날식 · 까닭 날글 안 찍음 — 마지막 조각 · 빈칸 · 까닭 걸러냄 (PLAN 6장 셋째 줄)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016WRFJmmhPi4exAzHgPZHMT
This commit is contained in:
@@ -59,6 +59,8 @@ interface Opened extends Draft {
|
||||
reasons: string[];
|
||||
lines: CalcLine[] | null;
|
||||
text: TextAnswer | null;
|
||||
/** 마지막으로 잘 받은 읽는 식 — 멈춘 뒤에도 수량 칸 조각을 이걸로 */
|
||||
lastText?: TextAnswer;
|
||||
ownHost: HTMLElement;
|
||||
values: Record<string, string>;
|
||||
}
|
||||
@@ -170,6 +172,7 @@ export async function mountM01LogicLab(
|
||||
values: current.values,
|
||||
onText: (text) => {
|
||||
current.text = text;
|
||||
if (text.ok) current.lastText = text;
|
||||
drawEditor(); // [계산] 전 미리보기 응답도 왼쪽 이름 식 칸에 바로 비치게 — onLines 와 같은 자리
|
||||
},
|
||||
onLines: (lines) => {
|
||||
@@ -202,6 +205,7 @@ export async function mountM01LogicLab(
|
||||
prices: current.prices,
|
||||
lines: current.lines,
|
||||
text: current.text,
|
||||
lastText: current.lastText,
|
||||
values: current.values,
|
||||
ownHost: current.ownHost,
|
||||
onChange: touch,
|
||||
|
||||
@@ -20,7 +20,7 @@ import type {
|
||||
import { buildEditor, qtyKind } from "./M01_MasterData_UI_Logic_Edit";
|
||||
import { formatMoney, formatPrice } from "./M01_MasterData_UI_Logic_Money";
|
||||
import { openPicker } from "./M01_MasterData_UI_Logic_Pick";
|
||||
import { tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { safeReason, tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { buildFormula } from "./M01_MasterData_UI_LogicLab_Formula";
|
||||
import {
|
||||
condText,
|
||||
@@ -64,6 +64,8 @@ export interface DetailContext {
|
||||
lines: CalcLine[] | null;
|
||||
/** 마지막 시험 계산의 읽는 식 줄(서버가 줌) */
|
||||
text: TextAnswer | null;
|
||||
/** 마지막으로 잘 받은 읽는 식 — `text` 가 멈춤이면 조각을 이걸로 */
|
||||
lastText?: TextAnswer;
|
||||
values: Record<string, string>;
|
||||
/** 자체 로직 편집기 자리 — 다시 그려도 같은 칸을 씀(고치던 값이 안 날아감) */
|
||||
ownHost: HTMLElement;
|
||||
@@ -166,7 +168,7 @@ function infoBox(ctx: DetailContext): HTMLElement {
|
||||
className: "m01-logic__reasons",
|
||||
children: [
|
||||
el("strong", { text: tx("Head_Blocked") }),
|
||||
...ctx.reasons.map((r) => el("div", { text: r })),
|
||||
...ctx.reasons.map((r) => el("div", { text: safeReason(r) })),
|
||||
],
|
||||
}),
|
||||
]
|
||||
@@ -287,14 +289,18 @@ function entries(ctx: DetailContext): Entry[] {
|
||||
* 이름을 차례로 따라가며 줄 차례에 맞춤 · 금액 0 로직 부름 줄처럼 묶음이 달라도 찾음 ·
|
||||
* 끝내 못 찾으면 날식 대신 빈칸(계산 전 · 서버 실패면 식 글자 그대로) */
|
||||
function attachPieces(all: Entry[], ctx: DetailContext): void {
|
||||
if (!ctx.text?.ok) return;
|
||||
const source = ctx.text?.ok ? ctx.text : ctx.lastText;
|
||||
if (!source?.ok) {
|
||||
if (ctx.text) for (const e of all) e.qtyFrag = e.piecesFrag = []; // 멈춤 · 받은 조각 없음 — 날식 대신 빈칸
|
||||
return;
|
||||
}
|
||||
const ho = ctx.row.호표 ?? [];
|
||||
const names = [
|
||||
...ho.map((item) => item.이름 ?? (condOf(item) ? condLabel(condOf(item)!) : item.요소)),
|
||||
...(ctx.row.덧줄 ?? []).map((extra) => extra.이름),
|
||||
];
|
||||
const found = new Map<string, TextLine>();
|
||||
for (const g of ctx.text.groups) {
|
||||
for (const g of source.groups) {
|
||||
let from = 0;
|
||||
for (const line of g.줄) {
|
||||
const at = names.findIndex((n, i) => i >= from && n === line.이름);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import { el } from "@ui/ui_template_elements";
|
||||
import type { TextAnswer } from "./M01_MasterData_UI_Logic_Api";
|
||||
import { formatMoney } from "./M01_MasterData_UI_Logic_Money";
|
||||
import { tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { safeReason, tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { tl } from "./M01_MasterData_UI_LogicLab_Text";
|
||||
import "./M01_MasterData_UI_LogicLab_Formula.css";
|
||||
|
||||
@@ -31,7 +31,10 @@ export function buildFormula(host: HTMLElement, ctx: FormulaContext): void {
|
||||
host.replaceChildren(
|
||||
el("div", {
|
||||
className: "m01-logic__reasons",
|
||||
children: [el("strong", { text: tx("Calc_Stopped") }), el("div", { text: text.reason })],
|
||||
children: [
|
||||
el("strong", { text: tx("Calc_Stopped") }),
|
||||
el("div", { text: safeReason(text.reason) }),
|
||||
],
|
||||
}),
|
||||
);
|
||||
return;
|
||||
@@ -62,7 +65,7 @@ export function buildFormula(host: HTMLElement, ctx: FormulaContext): void {
|
||||
? [
|
||||
el("div", { text: `${line.이름} : ${line.글}` }),
|
||||
...(line.까닭
|
||||
? [el("div", { className: "m01-logic__muted", text: line.까닭 })]
|
||||
? [el("div", { className: "m01-logic__muted", text: safeReason(line.까닭) })]
|
||||
: []),
|
||||
]
|
||||
: [el("div", { className: "m01-logic__muted", text: tl("Formula_Slot") })],
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
} from "./M01_MasterData_UI_Logic_Api";
|
||||
import { formatNumber } from "./M01_MasterData_UI_Logic_Edit";
|
||||
import { formatMoney } from "./M01_MasterData_UI_Logic_Money";
|
||||
import { tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
import { safeReason, tx } from "./M01_MasterData_UI_Logic_Text";
|
||||
|
||||
/** 고르기 값이 마스터 키(자재·기계·직종)면 이름으로 바꿔 보임 — 값 칸은 키 그대로 보냄 */
|
||||
const KEY_RE = /^[A-Z]{2}\d{6}$/;
|
||||
@@ -201,7 +201,10 @@ function answerView(answer: CalcAnswer, draft: boolean, money: boolean): HTMLEle
|
||||
...note,
|
||||
el("div", {
|
||||
className: "m01-logic__reasons",
|
||||
children: [el("strong", { text: tx("Calc_Stopped") }), el("div", { text: answer.reason })],
|
||||
children: [
|
||||
el("strong", { text: tx("Calc_Stopped") }),
|
||||
el("div", { text: safeReason(answer.reason) }),
|
||||
],
|
||||
}),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -138,6 +138,10 @@ const TEXT = {
|
||||
"「{name}」 규격이 여럿이라 정하지 못함 — 위 「쓰이는 재료·기계」에서 하나를 골라 주세요",
|
||||
"「{name}」 has several specs — pick one in the materials list above",
|
||||
],
|
||||
Stop_Generic: [
|
||||
"이 조건으로는 셈하지 못함 — 입력값 · 표에 그 조합이 있는지 확인",
|
||||
"Cannot be calculated with these inputs — check the values and the table",
|
||||
],
|
||||
Stop_NoPrice: [
|
||||
"「{name}」 단가가 자료에 비어 있어 셈하지 못함 — 자료를 채워야 함",
|
||||
"「{name}」 has no price in the data yet",
|
||||
@@ -158,6 +162,12 @@ export function plainReason(reason: string): string {
|
||||
return reason;
|
||||
}
|
||||
|
||||
/** 화면에 찍는 까닭의 마지막 방어 — 중괄호 · 따옴표 · Decimal( 이 섞인 날글은 사람 말 한 줄로 */
|
||||
export function safeReason(reason: string): string {
|
||||
const plain = plainReason(reason);
|
||||
return /[{}"']|Decimal\(/.test(plain) ? tx("Stop_Generic") : plain;
|
||||
}
|
||||
|
||||
/** 흐름 그림 머리 「이렇게 씀」 — 줄 목록 */
|
||||
|
||||
/** 공용 `t()` 와 같은 뜻 — `{n}`·`{v}` 는 채움 */
|
||||
|
||||
Reference in New Issue
Block a user