feat(B01,B07): 설계일자 사용자 지정 입력 + 도면번호 자동 부여
사용자 확정(2026-09-02): 설계일자는 확정일 자동이 아니라 **사용자가 넣는다**. 도면번호는 Claude 판단으로 목록 순번을 쓴다. 설계일자 - `013_company_assets.sql` 로 `projects.design_date DATE` 추가(같은 마이그레이션에 로고·서명 공유 테이블 자리도 함께 만들었음 — 배선은 다음 커밋). - B01 프로젝트 수정 모달에 날짜 칸. 공용 `createInputField` 가 `type="date"` 를 받게 넓힘. - 표제란에는 도면 표기 관행대로 `2026. 09. 02.` 꼴로 적는다. 도면번호 - 단건 조회는 목록 순서를 모른다 — 알려면 횡단 장 계획을 다시 계산해야 하고 도면을 열 때마다 그러면 비싸다. **목록이 매긴 번호를 manifest 에 적어 두고** 단건 조회가 읽는다. 목록은 화면 진입 때 늘 먼저 뜨므로 성립하고, 목록이 바뀌면 다음 조회에서 다시 적힌다. - `add_title_fields()` 신설 — 도면을 읽는 도중에 아는 값을 문맥에 얹는 창구. 검증: `pytest tmp/tests/ -q` 139 passed / 0 failed, 루트 `tsc --noEmit` 통과. 실사용자 경로(5174, wdw) — 대시보드 [수정] 모달 라벨 10개(설계일자 칸 추가 확인) → `2026-09-02` 입력 → [확인] → 종단면도 표제란에 `2026. 09. 02.`. 도면번호는 목록 13건 기준 종단 1 · 유역도 6 · 용지도 13 이 도각에 그대로 실림 (표지는 도각을 두르지 않아 번호 칸이 없다). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,15 @@ def use_title_fields(fields: dict[str, str] | None) -> None:
|
||||
_title_fields.set(fields or {})
|
||||
|
||||
|
||||
def add_title_fields(extra: dict[str, str]) -> None:
|
||||
"""이미 세운 표제란 값에 몇 개를 덧붙인다.
|
||||
|
||||
도면번호처럼 **도면을 읽는 도중에야 아는 값**을 위해서다. 라우터가 DB 값을 먼저 세우고,
|
||||
작도 스레드가 여기서 나머지를 얹는다(`asyncio.to_thread` 가 문맥을 복사한다).
|
||||
"""
|
||||
_title_fields.set({**_title_fields.get(), **(extra or {})})
|
||||
|
||||
|
||||
def company_template_path(company_dir: Path, name: str = A1_TEMPLATE) -> Path:
|
||||
"""회사 도각 파일 경로(없을 수도 있다)."""
|
||||
return Path(company_dir) / COMPANY_TEMPLATE_SUBDIR / f"{name}.json"
|
||||
|
||||
@@ -123,17 +123,16 @@ async def _title_block_fields(project_id: UUID) -> dict[str, str]:
|
||||
|
||||
아직 못 채우는 자리와 이유:
|
||||
- 사업량·연도기번은 사람이 넣는 값이다(B01 프로젝트 수정 화면). 비어 있으면 빈칸.
|
||||
- 설계일자 — "확정일"인데 도각은 **확정 전**에 그려져 저장본에 굳는다.
|
||||
채울 시점 정의가 미결이라 비워 둔다.
|
||||
- 도면번호 — 단건 조회가 목록 순서를 모른다(목록을 다시 만들면 도면을 열 때마다
|
||||
횡단 장 계획을 재계산하게 된다).
|
||||
- 설계일자·도면번호는 여기서 담지 않는다 — 설계일자는 사용자가 넣은 `design_date`
|
||||
를 그대로 쓰고(확정일 자동이 아니다), 도면번호는 도면을 읽는 쪽이 manifest 에
|
||||
적힌 목록 순번을 얹는다.
|
||||
"""
|
||||
pool = get_db_pool()
|
||||
async with pool.acquire() as connection, connection.cursor() as cursor:
|
||||
await cursor.execute(
|
||||
"""
|
||||
SELECT p.name, p.region, p.client_org, p.project_number, p.work_amount,
|
||||
c.name, c.logo_path,
|
||||
p.design_date, c.name, c.logo_path,
|
||||
COALESCE(designer.name, owner.name),
|
||||
COALESCE(designer.signature_path, owner.signature_path),
|
||||
pm.name, lead.name
|
||||
@@ -156,6 +155,7 @@ async def _title_block_fields(project_id: UUID) -> dict[str, str]:
|
||||
client_org,
|
||||
project_number,
|
||||
work_amount,
|
||||
design_date,
|
||||
company,
|
||||
logo_path,
|
||||
designer,
|
||||
@@ -169,6 +169,8 @@ async def _title_block_fields(project_id: UUID) -> dict[str, str]:
|
||||
"시행청": client_org,
|
||||
"연도기번": project_number,
|
||||
"사업량": work_amount,
|
||||
# 도면 표기 관행대로 "2026. 09. 02." 꼴로 적는다.
|
||||
"설계일자": f"{design_date:%Y. %m. %d.}" if design_date else None,
|
||||
"용역회사": company,
|
||||
"설계자": designer,
|
||||
"과업책임자": pm,
|
||||
|
||||
@@ -40,6 +40,7 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Table import (
|
||||
QUANTITY_VALUE_KEYS,
|
||||
)
|
||||
from B07_DesignDetail.B07_DesignDetail_Engine_Template import add_title_fields
|
||||
from B07_DesignDetail.B07_DesignDetail_Schema import (
|
||||
DesignDrawingItem,
|
||||
)
|
||||
@@ -417,9 +418,29 @@ def _drawing_list(
|
||||
# 목록의 절반이 눌리지 않는 회색 버튼이면 고장난 것처럼 보인다.
|
||||
for drawing_id, label in BLANK_DRAWINGS:
|
||||
drawings.append(DesignDrawingItem(id=drawing_id, kind="blank", label=label))
|
||||
_store_drawing_numbers(project_root, drawings)
|
||||
return drawings
|
||||
|
||||
|
||||
def _store_drawing_numbers(project_root: Path, drawings: list[DesignDrawingItem]) -> None:
|
||||
"""도면번호(목록 순번)를 manifest 에 적어 둔다.
|
||||
|
||||
단건 조회는 목록 순서를 모른다 — 알려면 횡단 장 계획을 다시 계산해야 하고, 그것을 도면
|
||||
열 때마다 하면 비싸다. 목록은 화면에 들어올 때 늘 먼저 뜨므로, 그때 매긴 번호를 적어
|
||||
두고 단건 조회는 그것을 읽는다. 목록이 바뀌면 다음 조회에서 다시 적힌다.
|
||||
"""
|
||||
manifest = _read_manifest(project_root)
|
||||
entries = manifest["drawings"]
|
||||
changed = False
|
||||
for number, item in enumerate(drawings, start=1):
|
||||
entry = entries.setdefault(item.id, {})
|
||||
if entry.get("number") != number:
|
||||
entry["number"] = number
|
||||
changed = True
|
||||
if changed:
|
||||
_write_manifest(project_root, manifest)
|
||||
|
||||
|
||||
def _cross_sheet_plan(
|
||||
project_root: Path,
|
||||
longitudinal_path: Path,
|
||||
@@ -590,6 +611,9 @@ def _read_drawing(
|
||||
stored_design(없으면 기본값)에서 만든다.
|
||||
"""
|
||||
manifest_entry = _read_manifest(project_root)["drawings"].get(drawing_id, {})
|
||||
number = manifest_entry.get("number")
|
||||
if isinstance(number, int):
|
||||
add_title_fields({"도면번호": str(number)})
|
||||
saved_path = _design_root(project_root) / "drawings" / f"{drawing_id}.json"
|
||||
if manifest_entry.get("confirmed") and saved_path.is_file():
|
||||
saved = _read_json(saved_path)
|
||||
|
||||
Reference in New Issue
Block a user