feat(m02): 면적 아래 알약 막대에 도면 알약 — 범위 · 상태 · 누르면 고름 · × 보내기 취소(114-3)
- 「T1 도면 E7:J17」 + 공용 꼬리표 상태(값 맞음 · 값 다름 · 도면에 표 없음 · 범위 없음) · 테두리 = 시트 위 점선 색 - 상태는 지금 책으로 판정(areaTable → sameValues) · 값이 바뀌면 150ms 모아 다시 - × = 기존 [보내기 취소](화면에서만 · 면적 저장 때 기록) · 시트 위 이름표 그대로 - 보낸 범위 몫을 spreadsheet_link_range.ts 로 나눔(700줄) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
- 114-1 면적 상세를 열 때 화면(`sentRanges` + 책)이 `도면_{연결}` 이름정의를 둠 → 행 넣기 → 면적 [저장]
|
||||
→ 서버 `refresh_drawing` 이 그 이름을 연결표 줄에 적고 도면 표 칸 글 = 옮겨진 칸.
|
||||
- 114-2 셀 밀기 · 당기기(칸 삽입 · 삭제 창)에 이름 따라감 · 카드 도면 저장도 표 없는 연결표 줄 뺌(`fitLinks`).
|
||||
- 114-3 아래 막대 도면 알약(`spreadsheet_link_range.rangePills`) · 상태(표 있음/없음 · 값 맞음/다름 · 범위 없음)
|
||||
· 누르면 범위 고름 · × = 보내기 취소 · 상태는 150ms 모아 한 번.
|
||||
TS 는 Node 로(`AreaToDrawing` 은 그 자리 변환 · 스프레드시트 모듈은 `helper_spreadsheet_d_bundle.cjs`).
|
||||
"""
|
||||
|
||||
@@ -28,6 +30,7 @@ const { load, SS } = require(path.join(ROOT, "resources/tester/spreadsheet/helpe
|
||||
const ts = require(path.join(ROOT, "config/node_modules/typescript"));
|
||||
const input = JSON.parse(fs.readFileSync(0, "utf8"));
|
||||
const ss = (name) => load(path.join(SS, name + ".ts"));
|
||||
let drawingNow = input.drawing;
|
||||
const tsLoad = (file, stubs) => {
|
||||
const src = fs.readFileSync(path.join(ROOT, file), "utf8");
|
||||
const js = ts.transpileModule(src, {
|
||||
@@ -46,7 +49,7 @@ const toDrawing = tsLoad("M02_MasterTemplete/M02_MasterTemplete_AreaToDrawing.ts
|
||||
"@ui/ui_template_modal": {},
|
||||
"./M02_MasterTemplete_Api_Fetch": {
|
||||
getActiveOwner: () => null,
|
||||
readTemplate: async () => ({ 문서: input.drawing }),
|
||||
readTemplate: async () => ({ 문서: drawingNow }),
|
||||
},
|
||||
"../A00_Common/spreadsheet/spreadsheet_address": ss("spreadsheet_address"),
|
||||
"../A00_Common/spreadsheet/spreadsheet_area_table": ss("spreadsheet_area_table"),
|
||||
@@ -96,7 +99,61 @@ const { applyCommand } = ss("spreadsheet_commands");
|
||||
kept: toDrawing.fitLinks({ 도면: { entities: [tbl("T1")] }, 연결표: [row("T1"), row("T2")] }).연결표,
|
||||
plain: "연결표" in toDrawing.fitLinks({ 도면: { entities: [tbl("T9")] } }),
|
||||
};
|
||||
console.log(JSON.stringify({ opened, book, shifted, fit }));
|
||||
// 114-3 — 아래 막대 도면 알약 · 상태(표 있음/없음 · 값 맞음/다름 · 범위 없음)
|
||||
const states = {};
|
||||
const pills = {};
|
||||
if (input.drawing3) {
|
||||
drawingNow = input.drawing3;
|
||||
const book3 = input.book3;
|
||||
const marks3 = await toDrawing.sentRanges(area, () => {}, book3);
|
||||
const st = await Promise.all(marks3.map((m) => m.상태(book3)));
|
||||
states.first = st.map((s) => [s.글, s.종류]);
|
||||
book3.시트[0].칸.B1 = { 값: 99, 서식: 1 }; // 저장 안 한 고침
|
||||
states.edited = [(await marks3[0].상태(book3)).글];
|
||||
const mk = (tag, o = {}) => ({ tag, className: o.className ?? "", text: o.text ?? "",
|
||||
attrs: o.attrs ?? {}, children: [...(o.children ?? [])], title: "", on: {},
|
||||
style: { props: {}, setProperty(k, v) { this.props[k] = v; } },
|
||||
addEventListener(k, f) { this.on[k] = f; }, append(...x) { this.children.push(...x); } });
|
||||
const lr = tsLoad("A00_Common/spreadsheet/spreadsheet_link_range.ts", {
|
||||
"@ui/ui_template_elements": { el: mk, createTag: (l, v) => mk("span", { className: `ui-tag ui-tag--${v}`, text: l }) },
|
||||
"./spreadsheet_address": ss("spreadsheet_address"),
|
||||
"./spreadsheet_link_color": ss("spreadsheet_link_color"),
|
||||
"./spreadsheet_names": ss("spreadsheet_names"),
|
||||
"./spreadsheet_selection": ss("spreadsheet_selection"),
|
||||
});
|
||||
const got = new Map(marks3.map((m, i) => [m, st[i]]));
|
||||
const picked = [];
|
||||
const cancelled = [];
|
||||
let backs = 0;
|
||||
const ctx = { book: book3, readOnly: false, selection: { 시트: "s1" }, sheet: () => book3.시트[0],
|
||||
showSheet: () => {}, select: (s) => picked.push(s) };
|
||||
const made = lr.rangePills(ctx, marks3, (m) => got.get(m), () => (backs += 1),
|
||||
(m) => cancelled.push(m.이름), { pick: "누르면 고름", cancel: "보내기 취소" });
|
||||
made[0].on.click();
|
||||
made[1].children.find((c) => c.className === "ss-link__x").on.click({ stopPropagation() {} });
|
||||
const ro = lr.rangePills({ ...ctx, readOnly: true }, marks3, () => undefined, () => {}, () => {}, { pick: "", cancel: "" });
|
||||
pills.made = made.map((p) => ({
|
||||
text: p.children[0].text,
|
||||
tag: p.children[1] && p.children[1].className.startsWith("ui-tag") ? [p.children[1].className, p.children[1].text] : null,
|
||||
x: p.children.some((c) => c.className === "ss-link__x"),
|
||||
cls: p.className,
|
||||
hue: typeof p.style.props["--ss-link-h"],
|
||||
}));
|
||||
pills.picked = picked.map((s) => s.범위[0]);
|
||||
pills.backs = backs;
|
||||
pills.cancelled = cancelled;
|
||||
pills.roX = ro.map((p) => p.children.some((c) => c.className === "ss-link__x"));
|
||||
// 상태 모음 — 잇단 schedule 은 150ms 뒤 한 번만
|
||||
let calls = 0;
|
||||
let done = 0;
|
||||
const fake = [{ 상태: () => (calls += 1, { 글: "x", 종류: "success" }) }];
|
||||
const rs = lr.createRangeStates(() => fake, () => book3, () => (done += 1));
|
||||
rs.schedule(); rs.schedule(); rs.schedule();
|
||||
const early = calls;
|
||||
await new Promise((r) => setTimeout(r, 250));
|
||||
pills.gather = { early, calls, done, got: rs.get(fake[0]) };
|
||||
}
|
||||
console.log(JSON.stringify({ opened, book, shifted, fit, states, pills }));
|
||||
})().catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
@@ -188,3 +245,43 @@ def test_카드_도면_저장도_표_없는_연결표_줄_뺌_114_2(world): # n
|
||||
fit = _node({"book": area["문서"], "drawing": {"연결표": []}})["fit"]
|
||||
assert fit["kept"] == [{"연결": "T1", "시트": "s1", "범위": "A1", "값": {}, "장": ""}]
|
||||
assert fit["plain"] is False # 기록 없던 도면은 칸을 안 만듦
|
||||
|
||||
|
||||
def test_아래_막대_도면_알약_상태_누르면_고름_x_는_보내기_취소_114_3(world): # noqa: F811
|
||||
with store.at(world["system"]):
|
||||
area = store.read("area", "rv")
|
||||
book = area["문서"]
|
||||
now = sheet_node.area_tables([{"book": book, "시트": "s1", "범위": "A1:B2"}])[0]["값"]
|
||||
drawing3 = {
|
||||
"도면": {"entities": [T1_TABLE, {**T1_TABLE, "shapeData": {"style": {"연결": "T3"}}}]},
|
||||
"연결표": [
|
||||
{**OLD_ROW, "값": now}, # 이름 없는 옛 연결 · 표 있음 · 값 같음
|
||||
{"연결": "T2", "시트": "s1", "범위": "B1", "값": {}}, # 도면에 표 없음
|
||||
{
|
||||
"연결": "T3",
|
||||
"시트": "s1",
|
||||
"범위": "A1",
|
||||
"이름": "도면_없음",
|
||||
"값": {},
|
||||
}, # 이름 지워짐
|
||||
],
|
||||
}
|
||||
out = _node({"book": book, "drawing": {"연결표": []}, "drawing3": drawing3, "book3": book})
|
||||
assert out["states"]["first"] == [
|
||||
["값 맞음", "success"],
|
||||
["도면에 표 없음", "danger"],
|
||||
["범위 없음", "danger"],
|
||||
]
|
||||
assert out["states"]["edited"] == ["값 다름"] # 저장 전 칸 고침 = 지금 책으로 판정
|
||||
p = out["pills"]
|
||||
assert [x["text"] for x in p["made"]] == ["T1 도면 A1:B2", "T2 도면 B1", "T3 도면"]
|
||||
assert p["made"][0]["tag"] == ["ui-tag ui-tag--success", "값 맞음"] # 공용 꼬리표
|
||||
assert p["made"][1]["tag"] == ["ui-tag ui-tag--danger", "도면에 표 없음"]
|
||||
assert all(x["x"] and x["cls"] == "ss-link ss-link--range" for x in p["made"])
|
||||
assert all(x["hue"] == "string" for x in p["made"]) # 색 = 시트 위 테두리 색
|
||||
assert (
|
||||
p["picked"] == [{"r0": 0, "c0": 0, "r1": 1, "c1": 1}] and p["backs"] == 1
|
||||
) # 누르면 범위 고름
|
||||
assert p["cancelled"] == ["T2 도면"] # × = 보내기 취소(화면에서만 · 저장 때 기록)
|
||||
assert p["roX"] == [False, False, False] # 읽기 = × 없음
|
||||
assert p["gather"] == {"early": 0, "calls": 1, "done": 1, "got": {"글": "x", "종류": "success"}}
|
||||
|
||||
Reference in New Issue
Block a user