feat(M02): 일위대가 수량산출 모달 하나 — 지금 수량 · 손 입력 · 연결 풀기 + 면적산출 시트를 모달 안에 바로(칸 누름 = 이음) · 넣을 값 모달에서 수량 칸 뺌(43-1 · 43-2)
- 새 Labor_QtyModal.ts(로직 줄 수량산출 칸 · 자재 줄 같음 · [확인] = 손 · 고른 칸 · 풀기 · [닫기] = 그대로) · 두 단계 모달([엑셀에서 고르기]) 없앰 - AreaCellPick: 시트 부분을 mountAreaSheet 로 뗌(읽기만 · 실제 값 · 이은 칸 색 · 함께 잇기 · 바꾸기 물음 그대로) · 모달 pickAreaCell 지움 - Labor_Detail: openQty · openMat → openQtyFor · linkCell · Labor_Input: 수량 칸 · openQtyModal 지움(입력값 · 메모만) - 화면 판정 시나리오 resources/tester/ui_checks/43-1_수량산출_모달.js · 시험 test_m02_area_panel 부품 기대값 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
@@ -94,12 +94,15 @@ def test_카드_알약_취향은_계정_받은_뒤_올림():
|
||||
|
||||
|
||||
def test_엑셀_칸_고르기_모달_부품():
|
||||
"""40-3 ① — 읽기만 시트 · 칸 누름 = 주소 · 풀기 = {칸: null} · 그만둠 = null · 저장 안 함."""
|
||||
"""40-3 ① · 43-1 — 읽기만 시트(수량산출 모달 안에 바로 · `mountAreaSheet`) · 칸 누름 = 주소 ·
|
||||
풀기 · 손 · 확인 · 닫기는 일위대가 수량산출 모달(`Labor_QtyModal`) · 저장 안 함."""
|
||||
pick = _text("M02_MasterTemplete_AreaCellPick.ts")
|
||||
assert 'export { linkAreaCell } from "../A00_Common/spreadsheet/spreadsheet_link_set";' in pick
|
||||
assert "readOnly: true," in pick and "beforeClose: () => (finish(null), true)," in pick
|
||||
assert "finish({ 칸: null })" in pick
|
||||
assert 'finish(choice === "바꾸기" ? { 칸: at, 바꾸기: true } : { 칸: at });' in pick
|
||||
assert "export function mountAreaSheet(" in pick and "readOnly: true," in pick
|
||||
assert 'opts.onPick(choice === "바꾸기" ? { 칸: at, 바꾸기: true } : { 칸: at });' in pick
|
||||
qty = _text("M02_MasterTemplete_Labor_QtyModal.ts")
|
||||
assert "sheet = mountAreaSheet(host, {" in qty and 'pending = { kind: "unlink" };' in qty
|
||||
assert "엑셀에서 고르기" not in qty # 두 단계 모달 없앰(43-1)
|
||||
assert "linksAt(book, sheetId, at, opts.pill)" in pick and "askShare(" in pick
|
||||
assert "if ((e as MouseEvent).button === 0 && moved) void choose();" in pick
|
||||
assert "handle?.destroy();" in pick
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
/* 43-1 · 43-2 일위대가 수량산출 모달 — `orca eval --expression "$(cat 이 파일)"` 한 번에 돎 · JSON 돌려줌.
|
||||
*
|
||||
* 시작 화면: M02 마스터 템플릿(시스템 관리자) · 좌측 일위대가 줄 「SU-000003」 이 보이는 상태 ·
|
||||
* 그 열 면적산출(SA-000003) B6 = 12.5(검증 전 넣고 끝나면 마스터 사본으로 되씀) · 저장은 안 함(끝에 다시 열기 → 버림).
|
||||
* 기대 수치:
|
||||
* qtyModal.sheetCells > 0 · qtyModal.twoStepButton = false(「엑셀에서 고르기」 없음) · qtyModal.hasHand = true
|
||||
* hand.applied = round(기준 × 5) · hand.qty = "손 5 ㎡"
|
||||
* cell.qty = "B6 = 12.5" · cell.applied = round(기준 × 12.5)(배 1)
|
||||
* follow.qty = "B6 = 12.5"(손 지움 = 칸 따름 · 연결은 남음) · unlink.qty = "—"
|
||||
* matRow.opens = true(자재 줄이 있으면 같은 모달) · inputModal.hasQty = false(43-2 · 입력값 · 메모만)
|
||||
* discarded = true(다시 열기 → 확인 → 처음 수량 글과 같음)
|
||||
*/
|
||||
(async () => {
|
||||
const W = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const $ = (s, root = document) => root.querySelector(s);
|
||||
const $$ = (s, root = document) => [...root.querySelectorAll(s)];
|
||||
const btn = (root, text) => $$("button", root).find((b) => b.innerText.trim() === text);
|
||||
const num = (t) => Number(String(t).replace(/[^0-9.-]/g, ""));
|
||||
const LOGIC = "GF000219";
|
||||
const row = () => $(`[data-labor-logic="${LOGIC}"]`);
|
||||
const qtyText = () =>
|
||||
row().querySelector(".m02-labrow__qty .m02-labrow__applied").innerText.trim();
|
||||
const money = () =>
|
||||
$$(".m02-labrow__money", row()).map((c) => [
|
||||
num(c.querySelector(".m02-labrow__base").innerText),
|
||||
c.querySelector(".m02-labrow__applied").innerText.trim(),
|
||||
]);
|
||||
const out = {};
|
||||
const side = $$(".m02-side__item").find((b) => b.innerText.startsWith("SU-000003"));
|
||||
if (!side) return JSON.stringify({ error: "SU-000003 줄 없음" });
|
||||
side.click();
|
||||
await W(5000);
|
||||
const base = money()[3][0]; // 합계 기준
|
||||
out.initial = qtyText();
|
||||
const openQty = async () => {
|
||||
row().querySelector("[data-labor-qty-open]").click();
|
||||
await W(2500);
|
||||
return $(".m02-labqty");
|
||||
};
|
||||
// ① 모달 모양 + 손 5
|
||||
let m = await openQty();
|
||||
out.qtyModal = {
|
||||
open: !!m,
|
||||
sheetCells: $$("[data-labor-qty-sheet] .aislo-cell", m).length,
|
||||
twoStepButton: !!btn(m, "엑셀에서 고르기"),
|
||||
hasHand: !!$("[data-labor-qty]", m),
|
||||
now: $("[data-labor-qty-now]", m)?.innerText,
|
||||
};
|
||||
const hand = $("[data-labor-qty]", m);
|
||||
hand.value = "5";
|
||||
hand.dispatchEvent(new Event("input"));
|
||||
btn(m, "확인").click();
|
||||
await W(600);
|
||||
out.hand = { qty: qtyText(), applied: num(money()[3][1]), expect: Math.round(base * 5) };
|
||||
out.hand.ok = Math.abs(out.hand.applied - out.hand.expect) <= 5; // 기준은 화면 반올림 값
|
||||
// ② 칸 B6 고름 → 확인
|
||||
m = await openQty();
|
||||
const c = $('[data-labor-qty-sheet] [data-addr="B6"]', m);
|
||||
const r = c.getBoundingClientRect();
|
||||
const o = {
|
||||
bubbles: true,
|
||||
cancelable: true,
|
||||
clientX: r.x + 10,
|
||||
clientY: r.y + 8,
|
||||
button: 0,
|
||||
pointerId: 1,
|
||||
pointerType: "mouse",
|
||||
};
|
||||
c.dispatchEvent(new PointerEvent("pointerdown", o));
|
||||
c.dispatchEvent(new MouseEvent("mousedown", o));
|
||||
await W(80);
|
||||
c.dispatchEvent(new PointerEvent("pointerup", o));
|
||||
c.dispatchEvent(new MouseEvent("mouseup", o));
|
||||
c.dispatchEvent(new MouseEvent("click", o));
|
||||
await W(600);
|
||||
const share = btn(document, "함께 잇기"); // 그 칸에 다른 알약이 있으면 물음
|
||||
if (share) {
|
||||
share.click();
|
||||
await W(300);
|
||||
}
|
||||
out.cell = {
|
||||
state: $("[data-labor-qty-state]", m)?.innerText,
|
||||
handCleared: $("[data-labor-qty]", m).value === "",
|
||||
};
|
||||
btn(m, "확인").click();
|
||||
await W(800);
|
||||
Object.assign(out.cell, {
|
||||
qty: qtyText(),
|
||||
applied: num(money()[3][1]),
|
||||
expect: Math.round(base * 12.5),
|
||||
});
|
||||
// ③ 손 넣었다 지우고 확인 = 칸 따름 · ④ 연결 풀기
|
||||
m = await openQty();
|
||||
$("[data-labor-qty]", m).value = "";
|
||||
btn(m, "확인").click();
|
||||
await W(500);
|
||||
out.follow = { qty: qtyText() };
|
||||
m = await openQty();
|
||||
const unlink = btn(m, "연결 풀기");
|
||||
out.unlink = { button: !!unlink };
|
||||
if (unlink) {
|
||||
unlink.click();
|
||||
btn(m, "확인").click();
|
||||
await W(500);
|
||||
out.unlink.qty = qtyText();
|
||||
} else btn(m, "닫기").click();
|
||||
// ⑤ 자재 줄 · ⑥ 입력 모달(43-2)
|
||||
const mat = $("[data-labor-mat]");
|
||||
if (mat) {
|
||||
mat.click();
|
||||
await W(2500);
|
||||
out.matRow = { opens: !!$(".m02-labqty") };
|
||||
btn($(".m02-labqty"), "닫기")?.click();
|
||||
await W(300);
|
||||
} else out.matRow = { opens: "자재 없음" };
|
||||
row().querySelector(".m02-labrow__name").click();
|
||||
await W(400);
|
||||
const im = $(".m02-labin:not(.m02-labqty)");
|
||||
out.inputModal = {
|
||||
open: !!im,
|
||||
hasQty: !!$("[data-labor-qty]", im) || !!btn(im, "엑셀에서 고르기"),
|
||||
hasMemo: !!$("[data-labor-memo]", im),
|
||||
};
|
||||
btn(im, "취소")?.click();
|
||||
await W(300);
|
||||
// ⑦ 버림
|
||||
btn($(".m02-main__head"), "다시 열기").click();
|
||||
await W(600);
|
||||
btn($(".ui-confirm"), "확인")?.click();
|
||||
await W(4500);
|
||||
out.afterDiscard = qtyText();
|
||||
out.discarded = out.afterDiscard === out.initial;
|
||||
return JSON.stringify(out);
|
||||
})();
|
||||
Reference in New Issue
Block a user