Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1
This commit is contained in:
@@ -275,6 +275,8 @@ export function putStandardSheetSpec(
|
|||||||
back_len_cm: string | null;
|
back_len_cm: string | null;
|
||||||
face_slope_ratio: string | null;
|
face_slope_ratio: string | null;
|
||||||
foundation: string | null;
|
foundation: string | null;
|
||||||
|
stone_coeff_basis: string | null;
|
||||||
|
fill_concrete_mpa: string | null;
|
||||||
},
|
},
|
||||||
): Promise<{ status: string; revision: number; changed: number; notes: string[] }> {
|
): Promise<{ status: string; revision: number; changed: number; notes: string[] }> {
|
||||||
return requestJson(`/projects/${projectId}/standard-sheets/spec`, {
|
return requestJson(`/projects/${projectId}/standard-sheets/spec`, {
|
||||||
|
|||||||
@@ -12,7 +12,10 @@
|
|||||||
직접 읽는다. 치수를 여기서 다시 적으면 **그림과 표가 갈린다**(CLAUDE.md 5장).
|
직접 읽는다. 치수를 여기서 다시 적으면 **그림과 표가 갈린다**(CLAUDE.md 5장).
|
||||||
|
|
||||||
상부 두께 = 뒷길이 + 0.30 하부 두께 = 상부 + 0.30 × (H − 1.0)
|
상부 두께 = 뒷길이 + 0.30 하부 두께 = 상부 + 0.30 × (H − 1.0)
|
||||||
터파기 폭 = 평균두께 + 0.2 되메우기 두께 = 0.2
|
터파기 폭 = 평균두께 + 0.2 기초 0.5×0.9 (기초유) · 0.1×0.7 (기초버림)
|
||||||
|
|
||||||
|
⚠ 터파기 치수는 **`common_util_excavation` 한 벌**을 읽는다 — 횡단도가 쓰는 그 상수다.
|
||||||
|
여기서 다시 적으면 두 도면이 다른 터파기를 그린다.
|
||||||
|
|
||||||
⚠ **뒷길이가 두께에 들어간다**(확정 2차 ②, 실무 구조물도 식). 뒷길이가 다르면 벽이
|
⚠ **뒷길이가 두께에 들어간다**(확정 2차 ②, 실무 구조물도 식). 뒷길이가 다르면 벽이
|
||||||
두꺼워지고 그림도 그만큼 넓어진다 — 예전 식(0.45+0.10H / 0.45+0.40H)은 뒷길이를
|
두꺼워지고 그림도 그만큼 넓어진다 — 예전 식(0.45+0.10H / 0.45+0.40H)은 뒷길이를
|
||||||
@@ -35,6 +38,13 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
|
|||||||
polyline_entity,
|
polyline_entity,
|
||||||
)
|
)
|
||||||
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import STONE_MASONRY, face_slope_ratio
|
from B08_Quantity.B08_Quantity_Engine_UnitQuantity import STONE_MASONRY, face_slope_ratio
|
||||||
|
from common_util.common_util_excavation import (
|
||||||
|
WALL_BLINDING_DEPTH_M,
|
||||||
|
WALL_BLINDING_WIDTH_M,
|
||||||
|
WALL_FOUNDATION_DEPTH_M,
|
||||||
|
WALL_FOUNDATION_WIDTH_M,
|
||||||
|
WALL_TRENCH_CLEARANCE_M,
|
||||||
|
)
|
||||||
|
|
||||||
#: 그림 축척 — 1/25(1m = 40㎜). 표(줄 높이 9㎜) 위에 얹어도 한 면에 드는 크기다.
|
#: 그림 축척 — 1/25(1m = 40㎜). 표(줄 높이 9㎜) 위에 얹어도 한 면에 드는 크기다.
|
||||||
SCALE_MM_PER_M = 40.0
|
SCALE_MM_PER_M = 40.0
|
||||||
@@ -135,8 +145,15 @@ def build_figure(
|
|||||||
points = section_points(height_m, slope, back_cm)
|
points = section_points(height_m, slope, back_cm)
|
||||||
top_t, bottom_t = wall_thickness(height_m, back_cm)
|
top_t, bottom_t = wall_thickness(height_m, back_cm)
|
||||||
average_t = (top_t + bottom_t) / 2.0
|
average_t = (top_t + bottom_t) / 2.0
|
||||||
dig_width = average_t + STONE_MASONRY["excavation_extra_m"]
|
dig_width = average_t + WALL_TRENCH_CLEARANCE_M
|
||||||
backfill_t = STONE_MASONRY["backfill_thickness_m"]
|
# 기초 몫 — 「기초유 / 기초버림」이 폭·깊이를 가른다(정본 탭 제목).
|
||||||
|
foundation = str((sheet.get("options") or {}).get("foundation") or "")
|
||||||
|
if foundation == "기초유":
|
||||||
|
base_w, base_d = WALL_FOUNDATION_WIDTH_M, WALL_FOUNDATION_DEPTH_M
|
||||||
|
elif foundation == "기초버림":
|
||||||
|
base_w, base_d = WALL_BLINDING_WIDTH_M, WALL_BLINDING_DEPTH_M
|
||||||
|
else:
|
||||||
|
base_w = base_d = 0.0 # 안 정한 장은 기초를 안 그린다 — 지어내지 않는다.
|
||||||
|
|
||||||
entities: list[dict[str, Any]] = []
|
entities: list[dict[str, Any]] = []
|
||||||
wall = polyline_entity(
|
wall = polyline_entity(
|
||||||
@@ -156,16 +173,16 @@ def build_figure(
|
|||||||
if dig is not None:
|
if dig is not None:
|
||||||
entities.append(dig)
|
entities.append(dig)
|
||||||
|
|
||||||
# 되메우기 두께 선 — 밑면에서 0.2m 위. 값이 어디서 오는지 눈에 보이게.
|
# 기초 — 벽 밑에 놓이는 칸. 「안 정함」이면 안 그린다.
|
||||||
entities.append(
|
if base_d > 0:
|
||||||
_line_entity(
|
base = polyline_entity(
|
||||||
f"{drawing_id}:fig:backfill",
|
f"{drawing_id}:fig:base",
|
||||||
mm((0.0, backfill_t)),
|
[mm(p) for p in ((0.0, 0.0), (0.0, -base_d), (base_w, -base_d), (base_w, 0.0))],
|
||||||
mm((dig_width, backfill_t)),
|
|
||||||
layer_id,
|
layer_id,
|
||||||
guide_color,
|
guide_color,
|
||||||
)
|
)
|
||||||
)
|
if base is not None:
|
||||||
|
entities.append(base)
|
||||||
|
|
||||||
# 물구멍 — 벽을 가로지르는 짧은 선 하나. 개소 간격은 글자로 적는다(면적당이라 그림에 못 씀).
|
# 물구멍 — 벽을 가로지르는 짧은 선 하나. 개소 간격은 글자로 적는다(면적당이라 그림에 못 씀).
|
||||||
weep_y = height_m * 0.5
|
weep_y = height_m * 0.5
|
||||||
@@ -189,7 +206,13 @@ def build_figure(
|
|||||||
(dig_width + 0.16, height_m * 0.92),
|
(dig_width + 0.16, height_m * 0.92),
|
||||||
"left",
|
"left",
|
||||||
),
|
),
|
||||||
(f"되메우기 {backfill_t:g} m", (dig_width + 0.16, backfill_t), "left"),
|
(
|
||||||
|
f"기초 {base_w:g} × {base_d:g} m ({foundation})"
|
||||||
|
if base_d > 0
|
||||||
|
else "기초 — 안 정함(기초유/기초버림)",
|
||||||
|
(dig_width + 0.16, -base_d / 2.0 if base_d else 0.0),
|
||||||
|
"left",
|
||||||
|
),
|
||||||
(
|
(
|
||||||
f"물구멍 — {STONE_MASONRY['weep_hole_area_m2']:g}㎡당 1개소",
|
f"물구멍 — {STONE_MASONRY['weep_hole_area_m2']:g}㎡당 1개소",
|
||||||
(slope * weep_y + top_t + 0.16, weep_y),
|
(slope * weep_y + top_t + 0.16, weep_y),
|
||||||
@@ -243,5 +266,5 @@ def build_figure(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
used_mm = (height_m + 0.95) * scale
|
used_mm = (height_m + 0.95 + base_d) * scale
|
||||||
return entities, used_mm
|
return entities, used_mm
|
||||||
|
|||||||
@@ -31,6 +31,8 @@ EDITABLE_KEYS: tuple[str, ...] = (
|
|||||||
"back_len_cm",
|
"back_len_cm",
|
||||||
"face_slope_ratio",
|
"face_slope_ratio",
|
||||||
"foundation",
|
"foundation",
|
||||||
|
"stone_coeff_basis",
|
||||||
|
"fill_concrete_mpa",
|
||||||
)
|
)
|
||||||
|
|
||||||
#: 기초 갈래 — 정본 xls 탭 제목 그대로(`04.구조도(기슭막이).xls`).
|
#: 기초 갈래 — 정본 xls 탭 제목 그대로(`04.구조도(기슭막이).xls`).
|
||||||
@@ -51,8 +53,17 @@ FIELD_LABELS: dict[str, str] = {
|
|||||||
"back_len_cm": "뒷길이",
|
"back_len_cm": "뒷길이",
|
||||||
"face_slope_ratio": "전면 기울기",
|
"face_slope_ratio": "전면 기울기",
|
||||||
"foundation": "기초",
|
"foundation": "기초",
|
||||||
|
"stone_coeff_basis": "야면석 계수",
|
||||||
|
"fill_concrete_mpa": "채움 강도",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#: 야면석 계수를 어느 열에서 읽나 — 확정 ⑨ 「품셈 열이 기본, 사용자가 고를 수 있게」.
|
||||||
|
STONE_COEFF_CHOICES: tuple[str, ...] = ("품셈", "실무 관행")
|
||||||
|
|
||||||
|
#: 채움 콘크리트 강도(MPa) — 확정 2차 ⑩ 「기본 210, 고를 수 있게」.
|
||||||
|
#: 180 은 국가기준 하한(돌쌓기 전용), 210 은 콘크리트 구조물 몸체 쪽 기준.
|
||||||
|
FILL_CONCRETE_CHOICES: tuple[str, ...] = ("180", "210")
|
||||||
|
|
||||||
|
|
||||||
def _clean_slope(value: Any) -> tuple[float | None, str | None]:
|
def _clean_slope(value: Any) -> tuple[float | None, str | None]:
|
||||||
"""전면 기울기 — `(값, 안내)`. 비면 `(None, None)` 이고 그것이 「자동」의 뜻이다."""
|
"""전면 기울기 — `(값, 안내)`. 비면 `(None, None)` 이고 그것이 「자동」의 뜻이다."""
|
||||||
@@ -116,6 +127,20 @@ def clean_spec(spec: dict[str, Any]) -> tuple[dict[str, Any], list[str]]:
|
|||||||
f"(있는 것: {' · '.join(FOUNDATION_CHOICES)})."
|
f"(있는 것: {' · '.join(FOUNDATION_CHOICES)})."
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for key, choices in (
|
||||||
|
("stone_coeff_basis", STONE_COEFF_CHOICES),
|
||||||
|
("fill_concrete_mpa", FILL_CONCRETE_CHOICES),
|
||||||
|
):
|
||||||
|
if key not in spec:
|
||||||
|
continue
|
||||||
|
raw = spec.get(key)
|
||||||
|
cleaned[key] = str(raw) if raw not in (None, "") else None
|
||||||
|
if cleaned[key] and cleaned[key] not in choices:
|
||||||
|
notes.append(
|
||||||
|
f"{FIELD_LABELS[key]} 「{cleaned[key]}」는 없는 갈래입니다 "
|
||||||
|
f"(있는 것: {' · '.join(choices)})."
|
||||||
|
)
|
||||||
|
|
||||||
if "face_slope_ratio" in spec:
|
if "face_slope_ratio" in spec:
|
||||||
ratio, note = _clean_slope(spec.get("face_slope_ratio"))
|
ratio, note = _clean_slope(spec.get("face_slope_ratio"))
|
||||||
cleaned["face_slope_ratio"] = ratio
|
cleaned["face_slope_ratio"] = ratio
|
||||||
|
|||||||
@@ -71,6 +71,8 @@ class StandardSheetSpecRequest(BaseModel):
|
|||||||
back_len_cm: int | str | None = None
|
back_len_cm: int | str | None = None
|
||||||
face_slope_ratio: float | str | None = None
|
face_slope_ratio: float | str | None = None
|
||||||
foundation: str | None = None
|
foundation: str | None = None
|
||||||
|
stone_coeff_basis: str | None = None
|
||||||
|
fill_concrete_mpa: str | None = None
|
||||||
|
|
||||||
|
|
||||||
@router.put("/{project_id}/standard-sheets/spec")
|
@router.put("/{project_id}/standard-sheets/spec")
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ const SUPPLIES = ["채집", "구입"] as const;
|
|||||||
const BACK_LENGTHS = ["25", "30", "35", "45", "55", "60", "75"] as const;
|
const BACK_LENGTHS = ["25", "30", "35", "45", "55", "60", "75"] as const;
|
||||||
/** 정본 xls 탭 제목 그대로 — 터파기 기초 몫 0.45 대 0.07 을 가르는 축. */
|
/** 정본 xls 탭 제목 그대로 — 터파기 기초 몫 0.45 대 0.07 을 가르는 축. */
|
||||||
const FOUNDATIONS = ["기초유", "기초버림"] as const;
|
const FOUNDATIONS = ["기초유", "기초버림"] as const;
|
||||||
|
/** 확정 ⑨ — 품셈 열이 기본, 실무 관행(깬돌 열)으로 바꿀 수 있게. */
|
||||||
|
const COEFF_BASES = ["품셈", "실무 관행"] as const;
|
||||||
|
/** 확정 2차 ⑩ — 기본 210. 180 은 국가기준 하한(돌쌓기 전용). */
|
||||||
|
const FILL_MPA = ["180", "210"] as const;
|
||||||
|
|
||||||
/** 표준도 장 하나 — 서버가 낸 것 중 이 폼이 쓰는 것만. */
|
/** 표준도 장 하나 — 서버가 낸 것 중 이 폼이 쓰는 것만. */
|
||||||
export interface StandardSheetSpec {
|
export interface StandardSheetSpec {
|
||||||
@@ -34,6 +38,8 @@ export interface StandardSpecResult {
|
|||||||
back_len_cm: string | null;
|
back_len_cm: string | null;
|
||||||
face_slope_ratio: string | null;
|
face_slope_ratio: string | null;
|
||||||
foundation: string | null;
|
foundation: string | null;
|
||||||
|
stone_coeff_basis: string | null;
|
||||||
|
fill_concrete_mpa: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 이 종류가 돌쌓기 계열인가 — 옹벽·집수정에는 이 칸들이 뜻이 없다. */
|
/** 이 종류가 돌쌓기 계열인가 — 옹벽·집수정에는 이 칸들이 뜻이 없다. */
|
||||||
@@ -110,6 +116,8 @@ export function buildStandardSpecPanel(
|
|||||||
const supply = select(SUPPLIES, options.stone_supply, "— 안 정함(기본 채집) —");
|
const supply = select(SUPPLIES, options.stone_supply, "— 안 정함(기본 채집) —");
|
||||||
const back = select(BACK_LENGTHS, options.back_len_cm, "— 안 정함 —");
|
const back = select(BACK_LENGTHS, options.back_len_cm, "— 안 정함 —");
|
||||||
const foundation = select(FOUNDATIONS, options.foundation, "— 안 정함 —");
|
const foundation = select(FOUNDATIONS, options.foundation, "— 안 정함 —");
|
||||||
|
const coeff = select(COEFF_BASES, options.stone_coeff_basis, "— 안 정함(품셈) —");
|
||||||
|
const mpa = select(FILL_MPA, options.fill_concrete_mpa, "— 안 정함(210) —");
|
||||||
|
|
||||||
const slope = document.createElement("input");
|
const slope = document.createElement("input");
|
||||||
slope.className = "b07-spec__input";
|
slope.className = "b07-spec__input";
|
||||||
@@ -128,6 +136,8 @@ export function buildStandardSpecPanel(
|
|||||||
slope,
|
slope,
|
||||||
judgedSlope ? `비우면 자동 — 지금 판정값 1:${judgedSlope}` : "비우면 자동으로 판정합니다.",
|
judgedSlope ? `비우면 자동 — 지금 판정값 1:${judgedSlope}` : "비우면 자동으로 판정합니다.",
|
||||||
),
|
),
|
||||||
|
field("야면석 계수", coeff, "비우면 품셈 열을 씁니다."),
|
||||||
|
field("채움 강도 (MPa)", mpa, "비우면 210. 180 은 국가기준 하한입니다."),
|
||||||
);
|
);
|
||||||
|
|
||||||
const notes = document.createElement("ul");
|
const notes = document.createElement("ul");
|
||||||
@@ -163,6 +173,8 @@ export function buildStandardSpecPanel(
|
|||||||
back_len_cm: back.value || null,
|
back_len_cm: back.value || null,
|
||||||
face_slope_ratio: slope.value.trim() || null,
|
face_slope_ratio: slope.value.trim() || null,
|
||||||
foundation: foundation.value || null,
|
foundation: foundation.value || null,
|
||||||
|
stone_coeff_basis: coeff.value || null,
|
||||||
|
fill_concrete_mpa: mpa.value || null,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Reference in New Issue
Block a user